You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Wolts are seeded by copying the shared Claude credentials file (/workspace/wolts/.claude/.credentials.json → per-wolt .claude/.credentials.json, done by create_creature_wolt() at creation and wclaude self-heal at spawn). This works as a day-one bootstrap, but breaks structurally for two or more long-running wolts:
A Claude OAuth grant has one refresh chain, and refresh tokens are single-use (rotation). When the shared access token nears expiry, every running session independently tries to refresh. The first wins and gets a new token pair; every other copy now holds a dead refresh token — its next refresh trips reuse-detection and its access token is revoked (error says revoked, not expired).
Observed live, twice in 12 hours (2026-07-25/26, uxwolt + raggerrabbit both long-running):
22:03 — uxwolt refreshed at 22:01; raggerrabbit's refresh 2 min later → 401 OAuth access token has been revoked, refresh token stripped from his file.
~06:50 next morning — same race, same loser; rabbit's cred file wiped to epoch-zero expiry.
Each recovery is a manual stopgap (kill stale claude proc → copy fresh creds from the healthy wolt → POST /sessions/{name}/resume) that re-arms the same race at the next ~8–12h refresh cycle.
Historical note: this is why the shared seed "never really worked" — the seed had been expired since March (fresh wolts hit login screens, found 2026-07-17); only the one long-running wolt with its own healthy chain survived. Symlinking all wolts to one cred file was already tried and abandoned: Claude Code atomically replaces the file on refresh, which breaks symlinks (see comment in setup_wolt_claude_config).
A second, related pain: all wolts on one grant = one subscription seat's usage limits shared across the colony (org monthly spend limit was hit during incident 2). No token scheme fixes this — it's a capacity/seat question — but it compounds the auth fragility.
Why not share the refresh chain
Rotation makes a refresh chain single-owner by design — any second consumer is always one step behind.
Symlink/hardlink to one file: broken by Claude Code's atomic replace-on-refresh (platform already learned this).
Cred-sync daemon (one canonical refresher, fan-out copies): mostly works, but leaves a race window whenever the canonical session is idle at expiry, and babysits undocumented internal behavior. Fragile forever.
Per-wolt /login: clean (own grant per wolt) but interactive — needs the human in the loop per wolt, and doesn't scale with wolt creation.
Proposed solution: claude setup-token as the platform auth mechanism
claude setup-token mints a one-year, non-rotating OAuth token (sk-ant-oat01-…) designed for headless/CI use — nothing to race, so it is genuinely shareable by every wolt. Current official docs explicitly support it on Pro, Max, Team, or Enterprise plans (authentication docs).
This is what the original CLAUDE_CODE_OAUTH_TOKEN in .env was. It failed because its expiry was unmanaged (silent 1-year time bomb, no refresh, shadowed the self-healing file creds when it died) — the mechanism was right, the lifecycle management was missing.
Onboarding: wolt creation stops copying .credentials.json; wolts authenticate via the shared token.
Verify before building (known upstream risks)
anthropics/claude-code#8938: fresh containers can ignore CLAUDE_CODE_OAUTH_TOKEN during first-run onboarding — exactly our environment. Our pre-written .claude/ config may dodge it; needs a live test.
--bare mode does not read CLAUDE_CODE_OAUTH_TOKEN (not currently used by the platform, but worth noting).
Historical: setup-token may not have worked on Team plans in early versions — the owner's past failed attempt predates current docs. Hence: 5-minute live test first (mint token → fresh test-wolt session boots on it under the Team plan) before any plumbing lands.
Out of scope
Shared-seat usage limits (the spend-limit hit): setup-token fixes the outages, not the budget. A separate seat for heavy-usage wolts is the capacity answer — separate decision.
Pain point
Wolts are seeded by copying the shared Claude credentials file (
/workspace/wolts/.claude/.credentials.json→ per-wolt.claude/.credentials.json, done bycreate_creature_wolt()at creation andwclaudeself-heal at spawn). This works as a day-one bootstrap, but breaks structurally for two or more long-running wolts:revoked, notexpired).Observed live, twice in 12 hours (2026-07-25/26, uxwolt + raggerrabbit both long-running):
22:03— uxwolt refreshed at 22:01; raggerrabbit's refresh 2 min later →401 OAuth access token has been revoked, refresh token stripped from his file.~06:50next morning — same race, same loser; rabbit's cred file wiped to epoch-zero expiry.Each recovery is a manual stopgap (kill stale claude proc → copy fresh creds from the healthy wolt →
POST /sessions/{name}/resume) that re-arms the same race at the next ~8–12h refresh cycle.Historical note: this is why the shared seed "never really worked" — the seed had been expired since March (fresh wolts hit login screens, found 2026-07-17); only the one long-running wolt with its own healthy chain survived. Symlinking all wolts to one cred file was already tried and abandoned: Claude Code atomically replaces the file on refresh, which breaks symlinks (see comment in
setup_wolt_claude_config).A second, related pain: all wolts on one grant = one subscription seat's usage limits shared across the colony (org monthly spend limit was hit during incident 2). No token scheme fixes this — it's a capacity/seat question — but it compounds the auth fragility.
Why not share the refresh chain
/login: clean (own grant per wolt) but interactive — needs the human in the loop per wolt, and doesn't scale with wolt creation.Proposed solution:
claude setup-tokenas the platform auth mechanismclaude setup-tokenmints a one-year, non-rotating OAuth token (sk-ant-oat01-…) designed for headless/CI use — nothing to race, so it is genuinely shareable by every wolt. Current official docs explicitly support it on Pro, Max, Team, or Enterprise plans (authentication docs).This is what the original
CLAUDE_CODE_OAUTH_TOKENin.envwas. It failed because its expiry was unmanaged (silent 1-year time bomb, no refresh, shadowed the self-healing file creds when it died) — the mechanism was right, the lifecycle management was missing.Plumbing (revives the spirit of #249):
claude setup-token→ browser click → paste)..credentials.json; wolts authenticate via the shared token.Verify before building (known upstream risks)
CLAUDE_CODE_OAUTH_TOKENduring first-run onboarding — exactly our environment. Our pre-written.claude/config may dodge it; needs a live test.--baremode does not readCLAUDE_CODE_OAUTH_TOKEN(not currently used by the platform, but worth noting).Out of scope
Shared-seat usage limits (the spend-limit hit): setup-token fixes the outages, not the budget. A separate seat for heavy-usage wolts is the capacity answer — separate decision.
🤖 Generated with Claude Code