Autorun Maintainer Skill: The Definitive Guide
You are a Senior QA and Release Engineer specialized in the autorun hook ecosystem. Your mission is to eliminate the "Zombie State" (code edited but hooks stale) and resolve "Invisible Failures" (UI masking the true cause).
1. The Debugging Philosophy: "Trust No UI"
Claude Code's "hook error" is a generic mask. Never trust the UI. You MUST follow the Diagnostic Hierarchy to find the root cause:
Step 1: Plumbing Check (~/.autorun/hook_entry_debug.log)
- Binary Selection: Verify
get_autorun_bin()found the correct venv. - Exit Codes: Did the CLI exit with
0(Allow/Ask) or2(Blocking Workaround)? - Raw Output: Check for non-JSON noise (UV warnings, logs) before or after the JSON block.
- Validation: Did
extract_json()isolate exactly one valid block viajson.loads?
Step 2: Logic Check (~/.autorun/daemon.log)
- FullPayload: Check
FullPayload. Are expected keys present (e.g.,_pid,_cwd)? - Timing: Check
DAEMON PROCESSING END. If duration > 9000ms, it will trigger a Claude timeout. - Piped Commands: If a command like
git log | grep fixis blocked, verify the_not_in_pipepredicate is registered inmain.py:_PREDICATES.
Step 3: Source Check (~/.autorun/daemon_startup.log)
- Stale Code: Is the daemon loading from
.../cache/...(STALE) or.../plugins/autorun/src/...(FRESH)? - Identity: Confirm the Commit Hash and PID change on every restart.
2. Platform Schema Deep Dive (Claude v2.1.41)
Claude Code performs strict JSON validation. A single extra field in a lifecycle event causes a silent failure.
The "Hook Error" Matrix
| Symptom | Event Type | Cause | Resolution |
|---|---|---|---|
| "Invalid Input" | Stop, SessionStart | Sent decision or reason. | STRICT MODE: These events ONLY allow continue, stopReason, suppressOutput, and systemMessage. |
| "Missing context" | UserPromptSubmit, PostToolUse | Missing additionalContext. | Map feedback to additionalContext inside hookSpecificOutput. |
| "JSON failed" | PreToolUse | Missing permissionDecision. | Must exist at top-level AND in hookSpecificOutput. |
| "Double print" | All | hook_entry.py printed noise. | Refactor hook_entry.py to isolate and print exactly one JSON block. |
The "Ask" vs "Deny" Strategy
- The Conflict: Claude Code ignores
permissionDecision: "deny"at exit 0. - The Resolution:
- For AI-only feedback, use Exit 2 + Stderr (Bug #4669).
- For User-facing redirection (e.g., "Use trash instead of rm"), use
decision: "ask". This is the only way to ensure the redirection message is actually visible to the human.
- Gemini Symmetry: Always map
ask->denyfor Gemini incore.py:respond()because Gemini respects JSONdenyand does not support theaskprompt.
3. Deployment & Synchronization Architecture
The "9-Location Bug" (Legacy)
Historically, fixes failed because the code was copied into 9 separate locations. We now use Symlink Architecture:
- UV Tool:
uv tool install --editable . - Gemini:
gemini extensions link /path/to/repo - Result: Edits in
src/reflect immediately in those binaries.
The "Stale Code Trap"
Source edits in src/ are IGNORED by the persistent daemon until autorun --restart-daemon is run. NEVER assume code is active just because you saved the file.
The "One-Liner of Truth" (Mandatory)
uv run --project plugins/autorun python -m autorun --install --force && \
cd plugins/autorun && uv tool install --force --editable . && cd ../.. && \
autorun --restart-daemon
Critical Installer Fixes:
- Invisible Variable: For local marketplaces, Claude fails to substitute
${CLAUDE_PLUGIN_ROOT}.install.pyMUST manually substitute this in the~/.claude/plugins/cache/directory. - Path Doubling:
autorun --statuspreviously failed because it unconditionally appended/plugins/autorunto the marketplace root. Discovery must be idempotent.
4. Stability & Performance Insights
- 1GB Buffer Limit: Client and server must synchronize on a high buffer limit (e.g., 1GB). Large session transcripts (500MB+) will crash the hook with
asyncio.LimitOverrunErrorif left at default (64KB). - Session ID Fallback: If
CLAUDE_SESSION_IDis missing,core.pymust use a PID-based fallback to preventNoneTypecrashes during startup hooks. - Socket Polling:
restart_daemon.pymust useis_daemon_responding()socket checks rather thantime.sleep(). Fragile sleeps lead to race conditions where the client tries to connect before the server is bound. - Plan Recovery:
plan_export.pyuses a "Fresh Context" workaround (Option 1). It must track plan writes in a global database to recover them across session restarts.
5. UI/UX: Formatting & Anti-Duplication
- Avoid Double-Escaping: Never call
json.dumpson strings that will be put into a dict. This causes literal\nin the UI. Pass raw strings; let the finalprint(json.dumps())handle encoding. - Anti-Reversion Warning: Beware of context "compaction." If the AI summarizes the session, it may lose the "Fact" that a fix was applied and accidentally revert code via
git checkout. Always verify the disk state after compaction.
6. Official & Internal References
- Claude Hooks Reference: https://code.claude.com/docs/en/hooks
- Claude Schema Output: https://code.claude.com/docs/en/hooks#json-output
- Gemini Hooks Reference: https://geminicli.com/docs/hooks/reference/
- Claude Bug #4669 (Exit 2): https://claude.com/blog/how-to-configure-hooks
- Internal Path Ref:
notes/autorun_install_paths_reference.md - Lessons Learned:
notes/2026_02_11_lessons_learned_hook_failure_loop_prevention.md
7. Mandatory Verification Checklist
Before declaring a task "Complete," you MUST:
- Schema Test:
echo '{"hook_event_name":"PreToolUse", "tool_name":"Bash", "tool_input":{"command":"rm test"}}' | autorun - Metadata Test:
autorun --version(Verify commit matches current git). - Restart Test: Confirm PID in
~/.autorun/daemon.lockhas changed. - Path Test: Verify
~/.claude/plugins/cache/autorun/autorun/0.11.0/hooks/hooks.jsondoes NOT contain${CLAUDE_PLUGIN_ROOT}. - Pipes Test:
cargo build 2>&1 | head -50(Should be ALLOWED). - Status Test:
autorun --status(Ensure paths aren't doubled).
8. Detailed Architectural Inventory (The 9 Locations)
If synchronization fails, verify these locations for stale code:
- Git Source:
plugins/autorun/src/autorun/ - Dev Venv:
plugins/autorun/.venv/lib/python*/site-packages/autorun/ - Build Artifacts:
plugins/autorun/build/(DELETE THIS) - Claude Cache:
~/.claude/plugins/cache/autorun/autorun/0.11.0/ - UV Tool:
~/.local/share/uv/tools/autorun/(Must be editable) - Gemini Extension:
~/.gemini/extensions/ar/(Must be symlink) - Gemini Venv:
~/.gemini/extensions/ar/.venv/ - Gemini Workspace:
~/.gemini/extensions/pdf-extractor/ - Gemini Build:
~/.gemini/extensions/ar/build/(DELETE THIS)
9. Loop Detection Checklist
You are in a "Failure Loop" if:
- Tests Pass, Hooks Fail: Unit tests use source directly; hooks use stale binaries.
- "Fixed" Code Reappears: Alternating additions/removals of the same lines in git history.
- Multiple Daemons:
pgrep -f "autorun.daemon" | wc -l> 1. - User Reports Broken rm: Safety guards appear inactive d