dev-base: non-root agents can't install their repo's required Python (root-owned UV_PYTHON_INSTALL_DIR) #327
Labels
No labels
burndown-2026-06
coherence-core
consult
headless
interactive
P0
P1
P2
P3
P4
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
coilyco-flight-deck/agentic-os#327
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
A non-root agent in a dev-base container cannot install the Python its repo requires, so
uv rundies and every headless run on that repo fails its test/smoke gate before it can land.docker/dev-base/Dockerfileenv-setsUV_PYTHON_INSTALL_DIR=/opt/uv/python(line ~38) and later runschmod -R a+rX /opt/uv(line ~68). That grants read and traverse, not write. No managed Python is pre-installed, and the base image ships only systempython3(3.12 on bookworm, line ~47). So when a repo requires a newer Python (for example eco-app'srequires-python = ">=3.13", product imageFROM python:3.13), uv must download 3.13 into/opt/uv/python, which the non-root agent cannot create:Impact
Every
wardedengineer run on any repo whose required Python is not the system 3.12 dies on its firstuv run(test, lint, smoke). It surfaced on coilyco-gaming/eco-app: three dispatched runs left zero commits and zero branches, killed silently at the smoke gate. Local workaround filed as coilyco-gaming/eco-app#56 (redirectUV_PYTHON_INSTALL_DIRto a HOME-writable dir in that repo's Makefile), but that is a per-repo bandage - the fleet needs the image fixed.Fix options (pick one or both)
uv python install 3.13 3.12before thechmod -R a+rX /opt/uv. Consumers then find 3.13 already present, no runtime download, offline-safe. Add versions as the fleet adopts them./opt/uv/pythonand grant group/world write (or chown to the agent uid), so uv can download any version on demand at run time.Option 1 is the more deterministic fix (no network at run time). Option 2 is the flexible fallback for versions not pre-baked. Doing both is reasonable: pre-bake the common versions and leave the dir writable for the rest.
Acceptance
uv run --python 3.13 python -Vsucceeds with no writable-path workaround.Origin
Diagnosed from the coilyco-gaming/eco-app read-only director session, 2026-07-05. Motivating incident and local workaround: coilyco-gaming/eco-app#56. This is the root-cause fix that #56 bandages, and the reason CI-in-pinned-dev-base parity is worth adopting fleet-wide (companion umbrella issue).
🔒 Reserved by
ward agent --driver claude— containerengineer-claude-agentic-os-327on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T02:13:16Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).
— Claude (she/her), via
ward agent🔓 Reservation released by
ward container reap— containeragentic-os(--driver claude) exited without launching the agent (smoke-test death, ward#222/#264), so the hold it took is retracted. A plainward agentretry no longer needs--force.— Claude (she/her), via
ward agent🔒 Reserved by
ward agent --driver claude— containerengineer-claude-agentic-os-327on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T02:35:52Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).
— Claude (she/her), via
ward agentWARD-OUTCOME: done - dev-base now pre-installs Python 3.13 + 3.12 and leaves UV_PYTHON_INSTALL_DIR world-writable, so non-root agents can
uv runwithout the Permission-denied wall.Straightforward root-cause fix once I traced it: the
chmod -R a+rX /opt/uvreally did grant read+traverse but never write, and nothing pre-seeded a managed interpreter. I took both options the issue offered - pre-bake the common versions as root for the offline/deterministic path, and ana+rwXon the install dir for on-demand downloads of anything not baked. The one ordering gotcha was making sure thea+rwXruns after the pre-commit block'sa+rXso the write bit isn't a no-op.No real fights, but two rough edges. First, I couldn't build the image here (no docker daemon in the container), so I validated the mechanism directly with the same uv 0.11.26:
uv python install 3.13 3.12lands both under UV_PYTHON_INSTALL_DIR anduv run --python 3.13/3.12resolves the pre-baked interpreter with zero download - the interpreter layer #327 is about. Full end-to-end proof waits on the publish-image rebuild. Second, the docs cap fought back: the managed-Pythons bullet tipped dev-base-image.md past the 4000-char documentation-layout cap, so I had to tighten several neighboring bullets to fit rather than split the doc.Fairly confident in the result. Follow-up worth considering: fold the version list into dep-bump so new fleet Pythons ride the auto-bump instead of a hand edit, and eco-app#56's per-repo Makefile bandage can now be reverted.