fix: persist Claude crew authentication across restarts - #34
Open
ruby-dlee wants to merge 13 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Claude direct-account launches now use one authoritative native-credential check and the same upgrade-stable Claude launcher for selection, spawn preflight, and the launched process.
The authentication implementation is committed as
97e3aaaonfm/claude-crew-auth-persist-z3; the synchronized no-mistakes head isff91b956and the open pull request is #34.This branch is intentionally stacked on sibling guardrail commit
126330f, because that change supplies the spawn preflight which consumes this branch's shared account-usability check.The sibling
fm-guardrail-hardening-g6change must land first, after which this branch must be rebased; the stack was not unpicked or rewritten.Unauthenticated homes fail before endpoint creation instead of consuming a worktree lease at a login prompt.
What changed
bin/fm-account-directory.shnow owns the verified macOS Keychain mechanism, one-time setup and repair commands,claude setup-tokentradeoff, and the authoritativecheck-credential claude <account-home>contract.The check clears ambient Anthropic and Claude credentials, sets the literal
CLAUDE_CONFIG_DIR, invokes the passwd-home~/.local/bin/claudesymlink, and requiresauth status --jsonto reportloggedIn=true.Claude selection skips homes that fail that same check and chooses the stable first usable home.
bin/fm-spawn.shlaunches the exact~/.local/bin/claudepath returned by the owner script instead of a PATH-selected wrapper or a stale versioned binary.The sibling preflight remains the only spawn guard and calls the shared check; this change did not add a competing preflight.
Investigation disproved the proposed application-ACL cause.
All three account services mapped to the expected path hashes and had the reported modification times.
security find-generic-password -wsucceeded without prompting for all three broken items and the working temporary item, with secret output discarded.ACL dumps showed the same
/usr/bin/securitydecrypt path for broken and working items.The distinguishing Keychain metadata was the account attribute: the broken imported homes retained the passwd username while the newly authenticated working custom home used
unknown.Passing each broken item's access token only through a transient
CLAUDE_CODE_OAUTH_TOKENenvironment made Claude report authenticated, proving the payload was usable while native discovery was not.The selected repair is therefore a clean, one-time native
claude auth loginafter removing only that literal config directory's stale service entry.claude setup-tokenwas verified as an honoredCLAUDE_CODE_OAUTH_TOKENsource.It was not selected because Claude prints but does not store that one-year inference-only token, which would force Firstmate to add a second credential store and propagate a secret through the launch path.
Native login keeps secret storage and refresh inside Claude's own per-directory Keychain contract.
Verification
tests/fm-account-directory.test.shpassed in full, including authenticated selection, all-unusable refusal, ambient credential clearing, stale version-manifest rejection, exact-launcher spawn, pre-endpoint unauthenticated refusal, and the existing direct-account recovery and rollback coverage.FM_TEST_FOCUSED=credential-preflight tests/fm-account-directory.test.shpassed.bin/fm-lint.shpassed with pinned ShellCheck 0.11.0.bash -npassed for both changed scripts and the changed test.git diff --checkpassed./Users/dongkeun/firstmate/bin/fm-ensure-agents-md.sh .confirmed the existingAGENTS.mdandCLAUDE.mdarrangement was unchanged.The unrelated pre-existing failure in
tests/fm-watch-checkpoint.test.shwas accepted only after direct base/head proof.Running the unmodified file at submitted base
fe94d84b515f0a1b28d8ad988714dbd5b521ebd6exited 1 withsignal checkpoint exit: expected exit 0, got 124.Running the same unmodified file at branch head
97e3aaa2121b07424a44e6a9a73a9d81a1ffc50dproduced the identical assertion and exit code.This branch does not modify that file; no retry, timeout relaxation, or test weakening was added.
No-mistakes recorded the failure as accepted pre-existing evidence and continued, while the authentication suites and all 449 Agent Fleet Python tests passed.
Real-machine use confirmed
provider-command claudereturns/Users/dongkeun/.local/bin/claude.The authoritative check correctly fails all three existing account homes and prints their exact scoped login commands.
The same stable launcher reports
loggedIn=truefor the demonstrably working/tmp/claude-alt-qfS707throwaway custom config directory.A second purpose-made authenticated directory could not be created unattended because OAuth authorization is the one intentional human setup step.
A real Herdr crew was not started because this brief explicitly declared Herdr lifecycle operations not enabled.
Per supervisor decision, neither limitation blocks shipping; end-to-end real-crew verification is explicitly outstanding.
Visual evidence
No visual artifact would add review value for this shell and Keychain mechanism.
No screenshots were captured.
Artifacts
The authentication implementation commit is
97e3aaa; the synchronized pipeline head isff91b956on branchfm/claude-crew-auth-persist-z3.The pull request is #34.
The branch intentionally contains sibling prerequisite
126330fand must be rebased after that prerequisite lands.The important tracked files are
bin/fm-account-directory.sh,bin/fm-spawn.sh, andtests/fm-account-directory.test.sh.The authoritative check is
bin/fm-account-directory.sh check-credential claude <account-home>.Official Claude documentation used during evaluation was https://code.claude.com/docs/en/team and https://code.claude.com/docs/en/env-vars.
Follow-ups
End-to-end verification against a real Claude crew launch is outstanding by explicit supervisor decision.
The account owner runs this exact one-time setup sequence when available:
That initial OAuth step needs the account owner, but subsequent spawns, Firstmate restarts, and Claude Code version upgrades use the persistent Keychain credential without another manual login.
After at least one home passes the authoritative check, run this exact Herdr-enabled smoke sequence from the primary Firstmate home:
The proof is that the pane shows the crewmate consumed the brief instead of
Not logged in - Please run /login, and the task produces its scout report plusdone:status.Firstmate should then follow the ordinary scout review and safe teardown lifecycle.
Merge ordering remains outstanding: land
fm-guardrail-hardening-g6first, then rebase this stacked branch before merge.Do not rewrite the stack into an independent change, because the shared
check-credentialcontract and the sibling preflight were designed together.Pipeline
Updates from git push no-mistakes