Skip to content

Instantly share code, notes, and snippets.

@possibilities
Created March 14, 2026 17:17
Show Gist options
  • Select an option

  • Save possibilities/224e0048dde48e273e8752a9c503e26c to your computer and use it in GitHub Desktop.

Select an option

Save possibilities/224e0048dde48e273e8752a9c503e26c to your computer and use it in GitHub Desktop.

claudehooks

E2E test harness for Claude Code. Drives the TUI via pexpect PTY, detects state through hooks.

See CLAUDE.md for full development docs.

Hooks

auto-approve

All tool calls are auto-approved without permission prompts, except AskUserQuestion and ExitPlanMode.

tool-redirect

Configured tools are blocked with a custom redirect message. Everything else passes through.

plan-tracker

Captures versioned snapshots of plan files as they're created and modified. A PostToolUse hook sets a dirty flag when Write/Edit touches a /plans/*.md file, and a Stop hook snapshots the plan content to ~/.local/state/claude/plan-tracker/{slug}.jsonl (one JSONL file per plan slug). Deduplicates by content hash — only records a new version when the content actually changed.

job-state

Per-job lifecycle log keyed by PPID. Fires on every hook event but only records job_start, session_clear, pid_change, mode_change, and stop. State files at ~/.local/state/claude/job-state/{ppid}.jsonl (override via JOB_STATE_DIR). An index.json maps session_id → ppid for resume detection. On resume (new PPID), creates a symlink so all writes go to the original state file. External scripts can determine job status by reading the JSONL.

exit-plan-messenger

Injects messages at key moments in the plan-exit lifecycle. Three independent message types, any combination works:

Message Config key When injected Mechanism
Contextfull on_exit_plan_contextfull Pre-implementation (option 2, no clear) PostToolUse additionalContext
Contextless on_exit_plan_contextless Pre-implementation (option 1, after clear) SessionStart additionalContext
Plan-implemented-stop on_plan_implemented_stop Post-implementation (after Claude stops) Stop hook blocks with message
  • Planless auto-approve: PermissionRequest hook auto-approves ExitPlanMode when tool_input has no plan key (PreToolUse allow doesn't bypass the plan dialog — PermissionRequest is required)

Lifecycle (option 2, no clear): PreToolUse writes breadcrumb → PostToolUse injects contextfull as additionalContext, writes plan-impl-stop breadcrumb if configured, deletes breadcrumb → Claude implements → Stop: plan-impl-stop breadcrumb triggers block → re-fire passes through.

Lifecycle (option 1, clear): PreToolUse writes breadcrumb → context clears → SessionStart injects contextless as additionalContext, writes plan-impl-stop breadcrumb if configured, deletes breadcrumb → Claude implements → Stop: plan-impl-stop breadcrumb triggers block.

Behavior

All behavior tests run twice: once bare (no plugin hooks) and once with the full plugin loaded. This ensures the plugin's hooks don't alter baseline Claude Code behavior.

starts

Verifies Claude boots up and reaches idle prompt.

clears

Verifies /clear creates a new session ID.

plans

Verifies Claude creates a plan and reaches the approval prompt.

mode-transitions

Verifies that plan↔act mode transitions emit synthetic mode_change events in session-state JSONL. Triggers a plan, accepts with option 2 (contextfull), and asserts mode_transitions() / mode_at() return correct results.

plan-exit-transcript

Tests the hidden messages Claude receives after ExitPlanMode approval:

  • Option 1 (clear context): new session gets a synthetic user message with "Implement the following plan:", the plan content, a path to the old transcript, and a TeamCreate suggestion. Old transcript ends with rejection + interruption. Negative: no tool_result, no "approved your plan" language.
  • Option 2 (keep context): same session continues with an ExitPlanMode tool_result containing "User has approved your plan", the plan save path, and plan content. Negative: no synthetic user message, no transcript reference, no "Implement" prefix, no planContent field.

Canaries

bash-outputs

Negative test that verifies the Bash tool shows (No output) for commands that produce stdout. Runs two sequential Bash commands (echo + fastclaude/ask) and asserts the tool_response contains real output. Currently expected to fail — will pass when the upstream bug is fixed.

Statusline

context-monitor

Wraps the existing statusline command to track context window usage and fire desktop notifications on threshold crossings (20%, 25%, 30%...). Chains to claudectl show-statusline transparently.

Config: ~/.config/claudectl/context-monitor.yaml (see statusline/context-monitor-config.example.yaml)

Dependencies: notifyctl

Install: ./bin/install (symlinks context-monitor into ~/.local/bin/)

Config

Config lives in claudectl.yaml. Searched at:

  1. Project root: ./claudectl.yaml or ./.claudectl.yaml
  2. XDG fallback: ~/.config/claudectl/config.yaml

First match wins. All keys are optional.

on_exit_plan_contextless: >-
  Continue implementing the plan.
  Read the plan file and pick up where you left off.
on_exit_plan_contextfull: >-
  You just exited plan mode.
  Continue implementing the plan.
on_plan_implemented_stop: >-
  Run the tests before you stop.
tool_redirects:
  WebSearch: |
    Use searchctl instead of WebSearch.
    Run via Bash: searchctl web-search "query"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment