Skip to content

feat(spawn): pin each secondmate's Claude account to its own home - #2859

Open
Lyxterai wants to merge 5 commits into
kunchenguid:mainfrom
Lyxterai:fm/fm-secondmate-account-pin
Open

feat(spawn): pin each secondmate's Claude account to its own home#2859
Lyxterai wants to merge 5 commits into
kunchenguid:mainfrom
Lyxterai:fm/fm-secondmate-account-pin

Conversation

@Lyxterai

Copy link
Copy Markdown

Summary

Gives each persistent secondmate its own durable Claude account (credential/config store), so work done by one secondmate bills that secondmate's own Claude subscription instead of the primary's.

  • Adds a per-secondmate config/claude-account pin resolved fresh from durable state at every spawn (not inherited from the launching environment), so it survives every respawn path: session-start liveness relaunch, /updatefirstmate, and fm-control relaunch.
  • An unpinned secondmate spawn is byte-for-byte unchanged from today.
  • A pinned secondmate's own crewmates inherit the same account through the existing fm-spawn.sh forwarding once the secondmate's own environment carries the value.
  • A pin naming a missing or unusable store refuses loudly and actionably, naming the secondmate and the path, rather than silently falling back to the primary's account.
  • Claude-only by design; other harnesses' account mechanisms are out of scope and not modified.

Test plan

  • New/extended tests colocated in tests/ following the existing <subject>.test.sh pattern (fm-control-relaunch.test.sh, fm-remote-secondmate-lifecycle-e2e.test.sh, fm-spawn-dispatch-profile.test.sh)
  • bin/fm-lint.sh passes, changed bin/*.sh shellcheck-clean
  • bin/fm-doc-audience-check.sh passes
  • Validated through the no-mistakes pipeline; CI green

🤖 Generated with Claude Code

fm-spawn forwarded only firstmate's OWN CLAUDE_CONFIG_DIR onto claude
launches, and only when it happened to be set in the invoking environment.
That is fleet-wide and all-or-nothing: a secondmate that is a separate
business with its own Claude subscription still billed the primary's
account, and forcing the right store by hand at one relaunch reverted on
the next automatic respawn.

A home now pins its Claude account in a local, gitignored
config/claude-account holding the absolute path of a Claude config store.
fm-spawn resolves the store from that file at every launch instead of
inheriting it from the invoking environment, so the pin holds across every
respawn path: a fresh spawn, the session-start liveness respawn that passes
only the task id, a control-plane relaunch, and a remote route's host-local
launch. /updatefirstmate never relaunches an agent, so it cannot move one.

A --secondmate spawn reads the target home's file and a crewmate or scout
spawn reads its own home's, which is what carries the account down to the
workers a pinned second mate spawns itself. A pinned secondmate gets the
store whatever harness its own agent runs, because a codex or cursor second
mate still spawns claude workers. A remote route's pin lives in the remote
home's config/, where the host-local spawn reads and validates it against
the filesystem it is on.

With no pin the forwarded store is firstmate's own CLAUDE_CONFIG_DIR
exactly as before, so unpinned spawns are unchanged. A pin that is not an
absolute, traversal-free, readable, searchable directory refuses the spawn
before any endpoint exists rather than falling back to the primary's
account, because silently billing the wrong subscription is the failure the
pin exists to prevent. A pinned launch reports claude_account=<path>.

The file is deliberately outside the inherited config set: inheriting an
account pin would put the whole fleet back on one subscription.
@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge; no concrete blocking or independently actionable non-blocking defect remains.

The account pin is resolved from the appropriate durable home, validated consistently before spawn and relaunch mutation, and covered across local, remote, pinned, unpinned, and refusal paths.

Reviews (1): Last reviewed commit: "no-mistakes(document): clarify claude-ac..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant