Headless `claude -p` wedges at bootstrap when spawned by a macOS LaunchAgent — regression in 2.1.203, persists in 2.1.204 (2.1.202 unaffected)
Summary
Since v2.1.203, ANY claude -p invocation whose process ancestry is a macOS LaunchAgent (gui domain) hangs indefinitely at bootstrap: no transcript file is created under ~/.claude/projects/, zero network sockets are opened, no stderr is produced, and the process sleeps on its main thread until killed. The identical commands run from an interactive shell — including fully detached (setsid-equivalent, stdin /dev/null) and with a minimal environment — complete normally in seconds. v2.1.202 runs the same LaunchAgent workloads green.
Environment
- macOS (Darwin 25.5.0, Apple Silicon)
- Claude Code 2.1.203 and 2.1.204 (native installer; versions in
~/.local/share/claude/versions/) - LaunchAgent in the gui domain (
launchctl print gui/$UID/<label>shows it loaded),WorkingDirectoryset, PATH provided via the wrapper script
Timeline evidence
A production LaunchAgent pipeline (3 scheduled headless runs/day) ran green for days on 2.1.202. The CLI auto-updated to 2.1.203 at 22:14 on 7 Jul; the very next scheduled run (07:00, 8 Jul) wedged and every launchd-spawned run since has wedged identically (2.1.204 auto-installed mid-window; same behaviour). Interactive sessions on the same machine, same versions, work throughout.
Bisect (all under REAL launchd via launchctl kickstart, 120s timeout each, v2.1.204)
| Probe | Invocation | Result |
|---|---|---|
| A | claude -p "Reply with exactly: PROBE_A_OK" --bare (ANTHROPIC_API_KEY in env) | WEDGED |
| B | A + --strict-mcp-config --mcp-config <empty mcpServers json> | WEDGED |
| C | B + --permission-mode bypassPermissions --disallowedTools "<long list>" | WEDGED |
| D | C with a ~15KB prompt | WEDGED |
| E | claude -p "..." with OAuth/keychain auth (no --bare, no API key) | WEDGED |
So: auth mode (API key vs OAuth), --bare, MCP config, permission mode, tool deny-lists, and prompt size are ALL eliminated. The launchd ancestry itself is the trigger.
Also eliminated interactively (all COMPLETE from a shell on 2.1.204): detached + no TTY + stdin /dev/null; minimal env (HOME/PATH/USER/TMPDIR only); the exact production flag sets, sandbox settings included.
Observed state of a wedged process
sample <pid>: main thread parked in the CLI binary (dyld start → main), no interesting activitylsof: ~13 fds, no TCP/UDP sockets at all- No transcript/session file ever created under
~/.claude/projects/<cwd-slug>/ - No child processes (rules out a hung hook — and
--bareskips hooks anyway) - Killable with plain SIGTERM
Repro
- Install 2.1.203 or 2.1.204.
- Create a minimal gui LaunchAgent whose program is a bash wrapper that runs
claude -p "Reply OK" --barewithANTHROPIC_API_KEYset, stdout/stderr to a log file. launchctl bootstrap gui/$UID <plist>thenlaunchctl kickstart gui/$UID/<label>.- The process hangs indefinitely; the same wrapper run from a terminal completes in seconds.
- Repoint the CLI launcher symlink at 2.1.202 and kickstart again: completes normally.
Impact
Any unattended/scheduled Claude Code automation on macOS (LaunchAgent-driven agents, cron-adjacent schedulers) is fully broken on ≥2.1.203, and silently: no error, no log line, just a parked process. Given auto-updates land silently, production automations break overnight with no code change — ours cost two days of a production pipeline before the version delta was identified.
Happy to provide the full launchd plists, wrapper scripts, and sample output.