Files
Sylpheed/docker/decoder/sylph-decoder
MechaCat02 b305aa4a5a docker: support a long-lived Claude token, and stop the seeding fighting it
The rotating OAuth credential file is why the agents kept parking, and a
long-lived token removes the failure by construction instead of recovering from
it after the fact.

MEASURED 2026-09-04. ~/.claude/.credentials.json holds a refresh token that
ROTATES ON USE. Seeding both containers from the host left three clients holding
one token; the first to refresh invalidated the other two, and on the failed
refresh Claude Code CLEARS the stored tokens -- writes empty strings, keeps the
metadata, and parks at "Login expired".

  decoder credentials emptied  13:04:28
  decoder last transcript      13:04:29   <- one second later

The emptying and the park are the same event, which is why it never self-heals:
not a stale token a retry could fix, but no token at all, with no browser in the
container to complete /login. A hollow file passes every "does it exist" check --
508 B healthy against 280 B emptied -- which is how three separate diagnoses
missed it. And recovery re-armed the bug: after re-seeding, host and decoder held
the IDENTICAL refresh token hash.

`claude setup-token` issues a long-lived token against the same Claude
subscription. Checked, not assumed: `claude auth login` defaults to --claudeai
and it is `--console` that means Console/API billing, so this is not the separate
API bill. `CLAUDE_CODE_OAUTH_TOKEN` is recognised by the installed binary.

Passed as an ENVIRONMENT VARIABLE, both halves of the failure are gone: nothing
rotates, so peers cannot invalidate each other, and there is no file for Claude
Code to empty on a failure.

Both launchers read $HOME/.sylph-claude-token if present -- same pattern as
SYLPH_GIT_CREDENTIALS -- and both entrypoints skip OAuth seeding entirely when
the variable is set, because copying the rotating file in would re-create the
exact collision the token exists to remove.

Inert until the file exists. Without it, nothing changes.

Also worth recording for the preflight work: `claude auth status` prints JSON
with loggedIn/authMethod/subscriptionType. That is a far better SessionStart
assertion than checking a file exists, and it would have caught this on the first
iteration rather than the third incident.
2026-09-04 15:20:31 +02:00

20 KiB
Executable File