drydock

Authentication

drydock runs Claude Code (Anthropic), OpenAI Codex (OpenAI), and Gemini (Google), each with a vendor API key or, for Claude and Codex, your existing subscription, and opencode for any OpenAI-compatible endpoint (see Bring your own model).

Whichever you choose, the real credential stays host-side and never enters the VM: the sandbox only ever sees a per-task token.

Pick the agent per task with --agent claude|codex|gemini|opencode, or set default_agent in config.yaml.

The matrix

Agent API key Subscription (no key)
Claude Code export ANTHROPIC_API_KEY=… drydock auth claude + anthropic_auth: subscription
OpenAI Codex export OPENAI_API_KEY=… drydock auth codex + openai_auth: subscription
Gemini export GEMINI_API_KEY=… API key only, no subscription mode

An API key is the quickest path for the three agents in the table above (opencode is configured separately; see Bring your own model). The subscription path lets you reuse a plan you already pay for (Claude and Codex only; macOS only; needs the vendor's claude / codex CLI).

Gemini: API key only

Gemini (--agent gemini) is API-key auth only: there is no OAuth / subscription lane. Set GEMINI_API_KEY in your shell env or store it at ~/.drydock/api-keys.env. See Models: Gemini (native) for model choices and the comparison with the OpenAI-compat Gemini route.

Bring your own model

opencode reaches any OpenAI-compatible endpoint (OpenRouter, a local server, or Gemini via its compat lane). It's API-key-only (no OAuth) and configured by the openai_compat block, not the matrix above. See Bring your own model.

API key

Set at least one vendor key. Keep it in your shell env, or let the drydock setup wizard store it at ~/.drydock/api-keys.env (mode 0600, read host-side). Either way it never crosses the VM boundary.

export ANTHROPIC_API_KEY=sk-ant-...   # Claude Code tasks
export OPENAI_API_KEY=sk-...          # OpenAI Codex tasks
export GEMINI_API_KEY=...             # Gemini tasks (native --agent gemini)
drydock start

Subscription (Claude Pro/Max or ChatGPT)

# Claude
claude login            # log in to your Claude account (opens a browser)
drydock auth claude     # copy the credential into ~/.drydock/claude-oauth.json (0600)
export DRYDOCK_ANTHROPIC_AUTH=subscription   # or set anthropic_auth: subscription in config.yaml

# Codex
codex login             # log in to your ChatGPT account
drydock auth codex      # copy into ~/.drydock/codex-oauth.json (0600)
export DRYDOCK_OPENAI_AUTH=subscription      # or set openai_auth: subscription in config.yaml

drydock start
Important: subscription-mode limits and terms-of-service risk

Budget vs. request cap. The USD budget (task_budget_usd) does not apply in subscription mode; there's no spend to meter. To stop a runaway task from burning your subscription's rate limit, set task_max_requests in config.yaml. task_timeout still applies as a wall-clock backstop. The cap stops inference the moment it's hit (the gateway returns HTTP 429), but the agent retries with backoff before giving up, so a capped task can spin for a minute or two before erroring out. Concurrent side calls (e.g. parallel subagents) also serialize against task_max_inflight (default 1) and retry on 429; if a task stalls on repeated 429s, raise task_max_inflight in config.yaml, at the cost of a wider worst-case budget overshoot.

Credential blast radius. The stored OAuth credential (~/.drydock/claude-oauth.json or codex-oauth.json) is a full-account token, broader than a scoped API key, and not per-task revocable. It never enters the VM, but keep it protected. See SECURITY.md for the full blast-radius note.

Terms of service. Headless use of a personal subscription may brush against the provider's terms and hit rate limits sooner than interactive use. drydock makes no claim that automating a personal Claude or ChatGPT subscription headlessly is sanctioned by Anthropic or OpenAI; the operator assumes that risk.

Verify

drydock auth claude --status   # or: drydock auth codex --status
drydock status