# PRD prd-new: Claude forward_host_credentials - **Status:** Draft - **Author:** claude - **Created:** 2026-07-01 - **Issue:** #325 ## Summary Add `agent_provider.forward_host_credentials: true` support for the `claude` template, mirroring the existing Codex flow. When enabled, bot-bottle reads the host's Claude OAuth session key from `~/.claude.json` at launch, forwards it only to the egress sidecar, and injects a placeholder `CLAUDE_CODE_OAUTH_TOKEN` into the agent so Claude Code starts without ever seeing the real credential. ## Problem Running a Claude agent in a container today requires the operator to manually extract a long-lived OAuth token (`claude setup-token`), export it as `BOT_BOTTLE_CLAUDE_OAUTH_TOKEN`, and reference it explicitly in the manifest with `agent_provider.auth_token: "BOT_BOTTLE_CLAUDE_OAUTH_TOKEN"`. This is a two-step manual ceremony that is easy to skip or do incorrectly. The host already stores a valid Claude session in `~/.claude.json` after `claude login` or `claude setup-token`. Codex already automates an equivalent extraction from `~/.codex/auth.json`. There is no reason Claude bottles cannot do the same. ## Goals / Success Criteria - A Claude bottle with `forward_host_credentials: true` in the manifest uses the host's `~/.claude.json` session key at launch with no additional operator steps. - The agent container receives only `CLAUDE_CODE_OAUTH_TOKEN=egress-placeholder` — never the real token. - The real session key lives only in the egress sidecar's environment. - Missing, malformed, or expired host Claude auth fails launch with a clear operator-facing message. - Existing `auth_token` behavior is unchanged. - `forward_host_credentials: true` is rejected in the manifest when both `auth_token` and `forward_host_credentials` are set, since they serve the same purpose. ## Non-goals - Refreshing Claude OAuth tokens in the sidecar. - Writing a dummy `~/.claude.json` auth state to the agent (unlike the Codex flow, Claude Code reads its credential from `CLAUDE_CODE_OAUTH_TOKEN` in env, not from an auth file — no guest-side auth marker is needed). - Supporting `forward_host_credentials` for providers other than `codex` and `claude`. ## Design ### Manifest schema ```yaml agent_provider: template: claude forward_host_credentials: true ``` Rejects in manifest validation when: - Template is not `codex` or `claude`. - Both `auth_token` and `forward_host_credentials` are set. ### Host auth extraction (`contrib/claude/claude_auth.py`) At prepare/launch time, when `forward_host_credentials: true`: 1. Resolve `~/.claude.json` (falling back to `$HOME/.claude.json`). 2. Parse the JSON object. 3. Require an `oauthAccount` dict. 4. Require a non-empty `oauthAccount.sessionKey` string. 5. If `oauthAccount.expiresAt` is present as a number, require it to be in the future. 6. Return only the session key to the launch path. Errors name the missing or invalid condition and point the operator at `claude login`, without printing token values. ### Egress route When `forward_host_credentials: true`: - Provision the session key in `provisioned_env` under `BOT_BOTTLE_CLAUDE_HOST_ACCESS_TOKEN` (new constant in `egress.py`). - Set up the `api.anthropic.com` egress route with `auth_scheme: Bearer` and `token_ref: BOT_BOTTLE_CLAUDE_HOST_ACCESS_TOKEN`. - Set `CLAUDE_CODE_OAUTH_TOKEN=egress-placeholder` in the agent env and add it to `hidden_env_names`. No dummy auth file and no `verify` step are needed — Claude Code reads the credential from the env var, not from a file. ### Constants - `CLAUDE_HOST_CREDENTIAL_TOKEN_REF = "BOT_BOTTLE_CLAUDE_HOST_ACCESS_TOKEN"` in `egress.py` (alongside the existing `CODEX_HOST_CREDENTIAL_TOKEN_REF`). - `CLAUDE_HOST_CREDENTIAL_HOSTS = ("api.anthropic.com",)` in `agent_provider.py` (alongside the existing `CODEX_HOST_CREDENTIAL_HOSTS`). ### Data flow ``` Host ~/.claude.json → bot-bottle launch │ ├──► egress sidecar env (real token only) │ └──► agent env: CLAUDE_CODE_OAUTH_TOKEN=egress-placeholder Agent → HTTPS to api.anthropic.com (via egress) Egress → injects Authorization: Bearer Egress → forwards to api.anthropic.com ``` ## Open questions None — the Codex precedent makes the design clear.