Reported by @Mega-Therion in #693, with the trace that identified it. Filing the symptom so the fix has an issue to close, per that PR's review.
What happens
_child_env() in pipeline/haiku.py passes the host environment through to the nested claude -p the background summarizer spawns, stripping only the parent-session markers. ANTHROPIC_API_KEY goes through with it.
The Claude CLI resolves credentials in a fixed order, and that key out-ranks a claude.ai login. So on a host where the operator has both — a login they chose, and an API key set in their shell for some unrelated tool — every nested summarizer call authenticates as the key, not as the login.
When that key's balance is exhausted or rate-limited, every background save fails:
[haiku] call exited 1; ...
[haiku] ERROR: call-haiku error: claude exited 1: Credit balance is too low | ⚠ claude.ai connectors are disabled because ANTHROPIC_API_KEY or another auth source is set and takes precedence over your claude.ai login · Unset it to load your organization's connectors
Observed 12 times across several days on one installation.
Why it is hard to see
The operator's own interactive sessions keep working — they run off the login, which is not out-ranked in that context. Only the nested child is affected. In hook-errors.log the whole thing reads as save-session.sh --force exited 1, with the real cause going to the daily narrative log and nowhere else (#694). Nothing at any layer names the variable.
Why the obvious fix is not the whole fix
Stripping ANTHROPIC_API_KEY unconditionally moves the outage rather than removing it: for an operator whose only credential is that key — a normal, documented way to authenticate the CLI, with no claude.ai login and no setup-token — a strip leaves the child unauthenticated and every background save fails, silently, in exactly the same shape.
So the fix has to distinguish the two populations: strip the ambient key when another credential is actually available, keep it when it is the only one there is. What "available" can mean is itself limited — a claude.ai login stored in the macOS Keychain is not visible to this process the way ~/.claude/.credentials.json is — so whatever automatic rule ships needs an explicit operator override alongside it, and the failure needs to name the variable when it does bite.
Acceptance
- An ambient
ANTHROPIC_API_KEY no longer reaches the nested CLI when another credential is available.
- It still reaches it when it is the only credential present.
- An operator can force either behaviour when the automatic rule cannot see their login.
- A failure that this variable plausibly caused says so, in the place the operator is already looking.
[AI-generated]
Reported by @Mega-Therion in #693, with the trace that identified it. Filing the symptom so the fix has an issue to close, per that PR's review.
What happens
_child_env()inpipeline/haiku.pypasses the host environment through to the nestedclaude -pthe background summarizer spawns, stripping only the parent-session markers.ANTHROPIC_API_KEYgoes through with it.The Claude CLI resolves credentials in a fixed order, and that key out-ranks a
claude.ailogin. So on a host where the operator has both — a login they chose, and an API key set in their shell for some unrelated tool — every nested summarizer call authenticates as the key, not as the login.When that key's balance is exhausted or rate-limited, every background save fails:
Observed 12 times across several days on one installation.
Why it is hard to see
The operator's own interactive sessions keep working — they run off the login, which is not out-ranked in that context. Only the nested child is affected. In
hook-errors.logthe whole thing reads assave-session.sh --force exited 1, with the real cause going to the daily narrative log and nowhere else (#694). Nothing at any layer names the variable.Why the obvious fix is not the whole fix
Stripping
ANTHROPIC_API_KEYunconditionally moves the outage rather than removing it: for an operator whose only credential is that key — a normal, documented way to authenticate the CLI, with noclaude.ailogin and nosetup-token— a strip leaves the child unauthenticated and every background save fails, silently, in exactly the same shape.So the fix has to distinguish the two populations: strip the ambient key when another credential is actually available, keep it when it is the only one there is. What "available" can mean is itself limited — a
claude.ailogin stored in the macOS Keychain is not visible to this process the way~/.claude/.credentials.jsonis — so whatever automatic rule ships needs an explicit operator override alongside it, and the failure needs to name the variable when it does bite.Acceptance
ANTHROPIC_API_KEYno longer reaches the nested CLI when another credential is available.[AI-generated]