Relationships
#2093 agent-runner: allow using the Claude CLI's stored login instead of requiring an API key
Opened by hmcrum · 9/10/2026· Shipped 9/28/2026
The gap
run and review cannot use the Claude Code CLI's own stored login. Auth resolution ends in an unconditional throw, so an API key is mandatory even when the machine already has an authenticated CLI:
// models/_lib/auth.ts — resolveApiKey()
// globalArgs.apiKey -> Deno.env.get(envVar) -> throwFor interactive or human-gated workflows this is the difference between "works with what the operator already has" and "provision and store a secret first".
Why it looks close to free
models/_lib/runner.ts already forwards HOME in FORWARDED_ENV_VARS, so the spawned binary can see the CLI's credential store. The CLI authenticates happily in exactly the stripped environment buildSubprocessEnv constructs, with no key present:
env -i PATH=... HOME=... TMPDIR=... USER=... LANG=... SHELL=... TERM=dumb \
claude -p 'Reply with exactly: OK' --allowedTools ''
# -> OK, exit 0The only thing preventing it is that resolveApiKey runs at runner.ts:32, before ensureBinary and before the spawn.
Why it cannot be configured around
Setting apiKeyEnvVar to any populated variable does not help, because the resolved value is then injected as ANTHROPIC_API_KEY, and a set key takes precedence over the stored login:
⚠ claude.ai connectors are disabled because ANTHROPIC_API_KEY or another
auth source is set and takes precedence over your claude.ai login
Failed to authenticate. API Error: 401 API key is invalid.An empty value is falsy and re-throws. So the key must be genuinely absent from the subprocess environment, which means the spawn has to be owned by whoever wants CLI auth — there is no configuration that reaches it.
Suggested change
Let auth be selectable rather than assumed, e.g. a global argument:
auth: "apiKey" | "cli" # default "apiKey", preserving current behaviourUnder cli, skip resolveApiKey and omit the key variable from buildSubprocessEnv entirely (rather than setting it empty). A softer variant: when no apiKey/apiKeyEnvVar is configured and no env var is present, fall through to a keyless spawn instead of throwing — though an explicit switch is easier to reason about, and keeps a missing-key typo from silently changing how a CI run bills.
Codex would need its own answer; this request is only about the claude provider.
Current workaround
A local export const extension on @swamp/agent-runner adding a run_local method that re-implements the spawn: same buildArgs translation, same env allowlist, minus the key. Roughly 150 lines, and it duplicates provider logic that will drift. Happy to send a PR against the real thing instead if the auth switch above is the shape you would accept.
Upstream repository: https://github.com/swamp-club/swamp-extensions
Environment
- Extension:
@swamp/agent-runner@2026.08.23.1 - swamp:
20260820.072114.0-sha.05d20b6a - OS:
darwin(aarch64) - Deno:
2.8.3 - Shell:
/bin/zsh
Shipped
Click a lifecycle step above to view its details.
stack72 commented 9/28/2026, 6:57:31 PM
Thanks @hmcrum for reporting this! We shipped: Add an opt-in auth global argument (apiKey default, cli opt-in) to @swamp/agent-runner so the claude provider can run on the Claude CLI's stored login. Under cli, skip API key resolution and leave the key variable out of the subprocess environment entirely. Default apiKey keeps existing users unchanged.. The fix has been merged and a release is on its way. We appreciate your contribution to swamp.
Sign in to post a ripple.