Skip to content

fix(docker): bootstrap Claude auth for containerized phantom#2

Merged
electronicBlacksmith merged 1 commit intomainfrom
fix/docker-credentials-bootstrap
Apr 5, 2026
Merged

fix(docker): bootstrap Claude auth for containerized phantom#2
electronicBlacksmith merged 1 commit intomainfrom
fix/docker-credentials-bootstrap

Conversation

@electronicBlacksmith
Copy link
Copy Markdown
Owner

Summary

The Docker entrypoint never installed Claude authentication credentials, so every container recreate booted without them and phantom responded with "please /login" to any Slack message. Additionally, the original bind-mount approach documented in `docker-compose.override.yml` shared a rotating OAuth session between host and container, which the Anthropic auth backend rejects as concurrent use — the CLI then deletes its own credentials file to force a re-login, breaking phantom a second time.

Two paths in the entrypoint

  1. Preferred: `CLAUDE_CODE_OAUTH_TOKEN` in `.env`, generated once via `claude setup-token` inside the container. Long-lived (1 year), its own session, never rotates, never conflicts with a Claude Code session on the host. Skips the mount entirely.
  2. Fallback: bind-mount the host's `~/.claude/.credentials.json` to `/tmp/.credentials-mount.json`. Entrypoint installs it into `/home/phantom/.claude/` with 600 perms and starts a background loop that re-copies when the host file changes. The comment in the script warns that this path is only safe when nothing else on the host is running Claude Code.

Auth priority: token env var > credentials mount > neither (prints a message that `ANTHROPIC_API_KEY` is expected).

Root cause diagnostic

Before this fix, phantom was asking for `/login` in Slack. Investigation timeline:

  • `/home/phantom/.claude/.credentials.json` was missing despite the container being up for 53 minutes with no restart
  • Host credentials file unchanged, token valid for 4+ more hours
  • Parent dir mtime confirmed deletion at 03:41:37, 3 minutes after a successful SDK call
  • Diagnosis: the container's `claude` CLI subprocess got a 401 from the auth backend (concurrent use rejection) and its error-handling path deleted the credentials file

Restoring the file manually would just replay the same failure on the next SDK call while the host's Claude Code was active. The env-var path sidesteps it entirely.

Test plan

  • `bash -n scripts/docker-entrypoint.sh` syntax clean
  • Rebuild phantom image and recreate container with `CLAUDE_CODE_OAUTH_TOKEN` in `.env` — startup log shows `Using CLAUDE_CODE_OAUTH_TOKEN from environment (skipping credentials mount)`
  • No credentials file written under `/home/phantom/.claude/`
  • SDK sanity call succeeds: `bun -e 'query({prompt:...})'` returns result with `subtype: success`
  • Slack connection establishes cleanly
  • Confirm long-term: token still works after 24h of Slack activity (pending real-world soak)

The entrypoint never installed authentication credentials, so every
container recreate booted without them and phantom responded with
"please /login" to any Slack message.

Two paths:

1. Preferred: CLAUDE_CODE_OAUTH_TOKEN in .env, generated once via
   `claude setup-token` inside the container. This is a long-lived
   (1 year) token with its own session, so it never rotates and
   will never conflict with a Claude Code session running on the
   host. Skips the credentials mount entirely.

2. Fallback: docker-compose.override.yml can bind-mount the host's
   ~/.claude/.credentials.json to /tmp/.credentials-mount.json.
   On boot we install it into /home/phantom/.claude/ with 600 perms
   and start a background loop that re-copies when the host file
   changes, so host-side token refreshes propagate without a
   restart.

   WARNING in the entrypoint comment: this path shares a rotating
   OAuth session between the host and the container, which the auth
   backend rejects as concurrent use and which will eventually cause
   the CLI to delete its own credentials to force re-login. Only
   safe when nothing else on the host is running Claude Code.

Auth priority is token env var > credentials mount > neither (the
latter prints a message that ANTHROPIC_API_KEY is expected).
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.

1 participant