Skip to content

codex-shell: chown global agent CLI to uid 10001 for auto-update - #23

Merged
nprodromou merged 1 commit into
mainfrom
fix/agent-npm-ownership
May 11, 2026
Merged

codex-shell: chown global agent CLI to uid 10001 for auto-update#23
nprodromou merged 1 commit into
mainfrom
fix/agent-npm-ownership

Conversation

@nprodromou

Copy link
Copy Markdown
Owner

Summary

  • After npm install -g (which runs as root), chown the global agent CLI install + entrypoint symlink to the agent uid/gid (10001) so the agent user can auto-update.
  • Same pattern for both variants: claude → @anthropic-ai + /usr/bin/claude, codex → @openai + /usr/bin/codex.

Why

The pod runtime user is 10001, but /usr/lib/node_modules/@anthropic-ai/ was being installed root-owned, so npm install -g @anthropic-ai/claude-code at runtime fails with EACCES on the rename inside the @scope/ parent. Surfaces in pods as the "Auto-update failed" warning at the bottom of the Claude Code TUI.

Test plan

  • Dockerfile diff is +12/-2, scoped to the install RUN block
  • CI build green
  • Merge → main image build tags new sha
  • apk8s tag bump PR follows, restart pods
  • Verify in pod: npm install -g @anthropic-ai/claude-code succeeds as uid 10001, Claude Code banner no longer shows the auto-update warning, version is 2.1.139 (latest)

Risk

  • chown is idempotent and runs at image build time only — zero runtime overhead.
  • numeric chown to 10001 before the agent user exists is fine (numeric ids don't require a passwd entry); the user is created at L282-283 with matching uid/gid.

🤖 Generated with Claude Code

`npm install -g` at L261-264 runs as root (before the USER directive
at L318), so /usr/lib/node_modules/@anthropic-ai/ and the matching
/usr/bin/claude symlink land owned by root:root. When the agent user
(uid 10001) later tries `npm install -g @anthropic-ai/claude-code` to
auto-update, npm's reify step renames within /usr/lib/node_modules/
@anthropic-ai/ → EACCES.

Fix: after each `npm install -g`, chown the scope directory and the
entrypoint symlink to 10001:10001. The agent user is created later in
the Dockerfile but the uid/gid 10001 are pinned constants (with an
explicit "DO NOT bump uid/gid casually" comment at L266-282), so
numeric chown here is safe and order-independent.

Same pattern applied to both variants: claude → @Anthropic-AI +
/usr/bin/claude, codex → @openai + /usr/bin/codex.

After this lands and apk8s bumps to the resulting sha, in-pod
`npm install -g @anthropic-ai/claude-code` should succeed for the
agent user, and claude-code's startup auto-update check should stop
showing the "Auto-update failed" banner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nprodromou
nprodromou merged commit 1bdf598 into main May 11, 2026
2 checks passed
@nprodromou
nprodromou deleted the fix/agent-npm-ownership branch May 11, 2026 21:50
nprodromou added a commit that referenced this pull request May 11, 2026
#24)

Three coupled changes that together make the agent containers boot
into a usable, current-version state without manual intervention.

1. Bump pinned CLI versions to current npm latest:
     CLAUDE_CODE_VERSION: 2.1.133 → 2.1.139
     OPENAI_CODEX_VERSION: 0.129.0 → 0.130.0
   This is what runtime auto-update was trying (and failing) to do.
   Letting Renovate own ongoing bumps via PRs matches the rest of
   the codex-shell pinning model.

2. ENV DISABLE_AUTOUPDATER=true. Runtime auto-update can't succeed
   inside the container anyway — npm rename within /usr/bin/ requires
   root, and the agent user is uid 10001. The chown patch (PR #23)
   covered /usr/lib/node_modules/@Anthropic-AI and the symlink itself
   but couldn't cover write-perms on the /usr/bin/ parent. With the
   ARG-pinned versions, suppressing the updater removes a noisy TUI
   banner without losing any actual version-update capability.

3. Add --dangerously-skip-permissions to the claude launch command.
   Without this, every restart drops the agent back into per-tool
   approval mode and unattended task execution stalls waiting for a
   human. The pod IS the sandbox boundary; the per-tool approval
   gate isn't load-bearing inside it.

Co-authored-by: claude-prodromou <claude@prodromou.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codex-prodromou

Copy link
Copy Markdown
Collaborator

Retroactive Codex review: blessed after merge.

The diff is limited to chowning the global npm scope directories and entrypoint symlinks to uid/gid 10001 after root-owned npm install -g. That matches the pinned agent user and the apk8s runtime UID alignment in nprodromou/apk8s#36. build (codex) and build (claude) were green. No follow-up from this pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants