anthropics / anthropics/claude-code
[BUG] `claude -p` under macOS launchd takes ~143s per call (plugin autoupdate + async SessionStart hook wait before result); 3s from a terminal
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 147k
- Forks
- 24k
- PR merge metrics
- PR metrics pending
Description
Summary
claude -p (print mode, tools off, empty MCP map) takes ~143 s for a one-word answer when the process is started by macOS launchd, versus ~3 s for the identical command from a terminal. The model round trip is ~2 s in both cases; the rest is user-level settings work around the turn. Passing --setting-sources project from an empty directory (so no user hooks/plugins load) brings the launchd run down to 2 s and the keychain login still works.
The result text is not printed until this work finishes, so scheduled jobs that wrap claude -p in a subprocess timeout (ours: 300 s, real prompts ~25k tokens) time out every call while the same script works when run by hand.
Environment
- Claude Code 2.1.267 (native arm64 binary,
~/.local/bin/claude), macOS 25.6.0 (Darwin), Apple Silicon - Logged in with claude.ai (Max) OAuth;
ANTHROPIC_API_KEYunset - User settings enable several plugins (superpowers, security-guidance, i-have-adhd, impeccable, ui-design, last30days) and a handful of command hooks
Repro
Throwaway LaunchAgent (any label), RunAtLoad, running:
source "$HOME/.bash_profile"; unset ANTHROPIC_API_KEY
claude -p --debug-file /tmp/cc-launchd.debug.log --model sonnet --no-session-persistence \
--tools "" --strict-mcp-config --mcp-config '{"mcpServers":{}}' --output-format text \
--system-prompt "You answer in one word." "Say the word ready." </dev/null >/tmp/out.txt 2>&1
launchctl bootstrap gui/$(id -u) that.plist→rc=0 elapsed=143s- Same command line in a terminal (also with
env -i HOME=… PATH=…) →rc=0 elapsed=3–5s - Same LaunchAgent with
--setting-sources projectadded andWorkingDirectoryset to an empty dir →rc=0 elapsed=2s, answerReady. --bareis not a workaround: it skips keychain reads, so it answersNot logged in · Please run /login.
Debug log timeline (launchd run, gaps > 4 s)
GAP 5s after: File ~/.claude.json written atomically
next: [skills] failed to read ~/.claude/skills/<x>/SKILL.md: Error: EINTR: interrupted system call
GAP 5s after: installPluginsForHeadless: starting
GAP 29s after: "Hook Stop (Stop) success: …" (all Stop hooks finished here)
next: plugin autoupdate: checking installed plugins
GAP 17s after: Fetching manifest version for figma@claude-plugins-official: 2.2.111
next: Preserving file permissions … (~/.claude.json write)
GAP 63s after: [event-loop-stall] blocked for 610ms …
next: [engine] turn 1 end (turns=1 usage in=2 out=6 api=1948ms stop=end_turn resultLen=6)
then: "Hook SessionStart:startup (SessionStart) success: {"async": true, "asyncTimeout": 180000} …"
[uds-messaging] Shutting down … result printed, exit
api=1948ms for the actual request. The 63 s gap ends exactly when an async SessionStart hook (security-guidance's ensure_agent_sdk.py, which answers {"async": true, "asyncTimeout": 180000}) is logged as complete, so print mode appears to wait for async SessionStart hooks before emitting the result. The hook script itself finishes in <1 s when run directly under launchd, so the wait is not the hook's own runtime. In a second launchd run the same phase logged Lock acquisition took longer than expected - another Claude instance may be running (43 s) before the ~/.claude.json write.
Expected
In -p mode the result should be printed as soon as the turn ends; plugin auto-update and async SessionStart hooks should not sit between the model response and stdout. At minimum, a flag or env to skip plugin auto-update and async hook waits in print mode without giving up the keychain login (--bare currently bundles those together).
Workaround we shipped
--setting-sources project with cwd set to an empty temp dir, for every headless call made from a scheduled job.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the claude -p LaunchAgent command from the issue and inspect /tmp/cc-launchd.debug.log, comparing it with the terminal and --setting-sources project runs. Trace the gaps around plugin autoupdate, the async SessionStart hook, and the turn result; done means print mode emits the result after the turn without those waits while preserving keychain login.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, shell, typescript
- Domain
- cli, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100