fix(notify): leave headless agent runs alone

AD
3d ago
+98-0

Summary

A script driving an agent (claude -p / --print, codex exec) fires the same hooks as a person at a terminal. Its permission prompts can't be answered by anyone, and the held hook stalls the script for up to 550 seconds on the FIFO; every run's Stop also became a "finished" nudge. notify.sh now skips those runs unless STACKNUDGE_HEADLESS_NUDGES=on.

Changes

  • notify.sh: agent_is_headless inspects the agent process's args (-p / --print, or exec for Codex) and exits without a decision, so the agent's own permission setting decides. STACKNUDGE_HEADLESS_NUDGES=on restores the old behaviour.
  • scripts/test-notify-headless.py: five cases (interactive claude, claude -p prompt, claude --print stop, codex exec prompt, claude -p with the opt-in), reusing the harness in test-notify-subagents.py. Wired into make test-notify.
  • notify.conf.example: the new key, commented out.
  • README: a paragraph on headless runs next to the subagent one.

Testing

Automated, on macOS: python3 scripts/test-notify-headless.py (5/5), python3 scripts/test-notify-subagents.py (25/25), python3 scripts/test-hook-wiring.py (42/42), bash -n notify.sh, ./build.sh, make test-without-xcode (1447 tests, 0 failures), make typecheck-tests.

scripts/test-notify-permission-blocking.py crashes with ValueError: flush of closed file in run_reply_case on this machine, both with and without this change (checked against origin/main's notify.sh), so I could not use it as a check.

Manual, after make reload:

  1. Run claude -p "run ls" (or any prompt that needs a permission). No banner or panel prompt appears and the run isn't held waiting for a reply.
  2. Run claude interactively and trigger a permission prompt. The banner and panel prompt appear as before.
  3. Add STACKNUDGE_HEADLESS_NUDGES=on to ~/.stack-nudge/config and repeat step 1. The prompt now appears.

Related issues

None.

šŸ¤– Generated with Claude Code


Summary by cubic

Stops nudging headless agent runs (claude -p, --print, codex exec): a script driving an agent fires the same hooks as a person at a terminal, but nobody can answer its permission prompts, and a held hook stalls the script for up to 550 seconds. notify.sh now skips those runs — prompts and turn-end notifications alike — and lets the agent's own permission setting decide. STACKNUDGE_HEADLESS_NUDGES=on restores the old behavior.

  • Adds scripts/test-notify-headless.py with five cases, wired into make test-notify.
  • Documents the new setting in the README and notify.conf.example.