Skip to content

plain-route spawns inherit the gateway's transport env (ANTHROPIC_BASE_URL et al) from a gateway session #38

Description

@SSFSKIM

Problem & intent

Clearing DAEMON_CLAUDE_SETTINGS / DAEMON_CLAUDE_EFFORT on a plain spawn (PR
#35, commit d27fbcc, and its review/land companion #37) stops the dispatcher
from recording the gateway — it does not stop the spawned worker from using
it. When a dispatcher runs inside a gateway-routed daemon, the clodex settings
file has already placed the gateway's transport variables into that session's
environment, and every Bash subprocess inherits them, including the
claude --bg that daemon-spawn launches for a "plain" worker.

Verified on this machine: ~/.claude/clodex-settings.json is a settings file
whose only top-level key is env, carrying

ANTHROPIC_BASE_URL=http://localhost:8317
ANTHROPIC_AUTH_TOKEN=<redacted>
ANTHROPIC_DEFAULT_FABLE_MODEL / _OPUS_MODEL / _SONNET_MODEL / _HAIKU_MODEL
CLAUDE_CODE_SUBAGENT_MODEL, CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY,
CLAUDE_CODE_ALWAYS_ENABLE_EFFORT, CLAUDE_CODE_MAX_OUTPUT_TOKENS,
CLAUDE_CODE_AUTO_COMPACT_WINDOW, ENABLE_TOOL_SEARCH,
CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY

Consequence: a plain-route worker spawned from inside a gateway session routes
its first turn through localhost:8317 while no gateway metadata is
persisted in the registry meta — so when the sweep later resumes it,
daemon-resume.sh restores nothing and the same daemon silently changes model
provider mid-life
. That is strictly more confusing than the #35/#37 leak, which
at least stayed on the gateway consistently.

Found by the review engine on PR #35 (round 2, P1) and confirmed by the reviewer
against the real settings file. Not fixed in #35: the fix is a design decision,
not a mechanical edit (see below), and #35's ticket was scoped to a one-line
default flip.

Constraints

  • The gateway's variable set is not repo-owned. It lives in a user-local
    settings file ($CLODEX_SETTINGS, default ~/.claude/clodex-settings.json)
    whose env keys can change without any repo change. A hardcoded unset-list in
    the dispatchers would be wrong the moment that file gains a key — so
    "just add env -u ANTHROPIC_BASE_URL …" is not an acceptable fix on its own.
  • Whatever lands must keep the gateway route working unchanged, and must not
    require a dispatcher to parse secrets out of the settings file into its own
    argv or logs (ANTHROPIC_AUTH_TOKEN is in there).
  • Affects all three dispatchers (implement, review, land) and any future
    daemon-spawn.sh caller, so a per-dispatcher fix repeats the bug by
    construction. Prefer one place.

Success criteria

  • A plain-route worker spawned from inside a gateway-routed session talks to the
    normal Anthropic endpoint, not the gateway — demonstrated, not argued.
  • A gateway-route worker still reaches the gateway, and still survives a resume
    on it (the existing persistence contract in daemon-spawn.sh /
    daemon-resume.sh keeps working).
  • No daemon can silently change model provider between its first turn and a
    later resumed turn.
  • A test pins the plain case against an ambient gateway environment.

Open questions

  • Where does "route" become explicit? Recommended direction, carried over
    from the PR feat(implement): default model route flips clodex → claude (C6) #35 fixer's own out-of-scope note: give daemon-spawn.sh an
    explicit route input (a --no-gateway flag, or a required route argument)
    instead of inferring "plain" from the absence of env. Then the substrate — the
    one place that knows it is launching a claude process — owns clearing the
    gateway's environment, and every caller becomes correct by construction. The
    substrate can derive the key list from the settings file it was handed
    (unset exactly the env keys that file declares) rather than from a hardcoded
    list, which also satisfies the constraint above.
  • Alternative worth pricing: never inherit at all — have daemon-spawn.sh build
    the child environment allowlist-style rather than by mutation. Cleaner
    invariant, larger blast radius; needs its own gate.
  • Does the same inheritance affect the review ENGINE call
    (review-engine.sh → nested codex exec)? It already isolates CODEX_HOME
    and sets SSL_CERT_FILE, but it does not clear ANTHROPIC_*. Probably
    irrelevant (codex does not read ANTHROPIC_*) — confirm rather than assume.

Decision log

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:P1issue-tracker board prioritystatus:ready-for-agentissue-tracker board state

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions