feat(agent): 'agent start' (daemonize) + 'agent serve' (foreground)#134
Merged
Conversation
…und) Replaces the clunky 'pass-cli agent &' with a proper lifecycle: - 'agent start' backgrounds the agent and returns once it is unlocked and listening. It spawns a detached 'agent serve' (setsid — survives closing the terminal), keeping stdin+stderr on the terminal for the one-time unlock prompt (keychain is silent), and polls for the socket before returning. - 'agent serve' is an explicit foreground alias for bare 'pass-cli agent'. - --idle/--max-ttl are now persistent flags so all three forms accept them, and 'start' forwards them to the spawned serve. POSIX only; Windows returns a clear 'not supported' (unix-socket transport). Real bug fixed along the way: the detached child must NOT inherit the caller's stdout, or it holds the pipe open forever and hangs any caller that captures it (e.g. out=$(pass-cli agent start)) — verified it hung, then fixed by pointing the child's stdout at /dev/null (stderr stays on the terminal for the prompt/errors). Test: TestIntegration_Agent_StartDaemonizes drives 'agent start' with the password on an OS pipe and a file-backed stderr (a bytes.Buffer stderr would reproduce the same Wait-on-copy-goroutine hang the feature had to fix), then resolves through the detached agent. All 7 agent integration tests pass; unit + lint green on linux/darwin/windows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kVLjbUL4F4CkoA7RbMYy8
agent.md (added in #130) never had Hugo front matter; the markdown validation only flags files touched by a PR, so this surfaced when #134 edited it. Add title/weight/toc matching the sibling operations docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014kVLjbUL4F4CkoA7RbMYy8
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.
Replaces the clunky
pass-cli agent &with a real lifecycle, per your request.New commands
pass-cli agent start— backgrounds the agent and returns as soon as it is unlocked and listening. No&needed. Spawns a detachedagent serve(setsid, so it survives closing the terminal), keeping stdin+stderr on your terminal for the one-time unlock prompt (keychain unlock is silent), and polls for the socket before returningagent started (pid N).pass-cli agent serve— explicit foreground alias for barepass-cli agent(for supervisors, or when you want to&it yourself).--idle/--max-ttlare now persistent flags shared byagent/serve/start(andstartforwards them to the serve process). POSIX-only; Windows returns a clearnot supported(unix-socket transport).Real bug caught while building it
The detached child originally inherited the caller's stdout, so it held the pipe open forever — hanging any caller that captures it, e.g.
out=\$(pass-cli agent start). I reproduced the hang (goroutine dump showedCmd.Waitblocked on the stdout/stderr copy goroutines), then fixed it by pointing the child's stdout at/dev/null(stderr stays on the terminal for the prompt/errors). Verifiedout=\$(...)now returns in 0s.Tests
TestIntegration_Agent_StartDaemonizes— drivesagent startwith the password on an OS pipe + a file-backed stderr (abytes.Bufferstderr reproduces the sameWait-on-copy-goroutine hang the feature had to fix), then resolves through the detached agent.golangci-lintclean on linux/darwin/windows.🤖 Generated with Claude Code