Files
claude-foundations/HOOKS.md
Paul O'Reilly 729b065f44 hooks: MiniMax gotchas reminder (UserPromptSubmit keyword trigger)
Injects a reminder to read the project's memory/gotchas-minimax.md when a prompt mentions
MiniMax or mm-worktree-task, once per session, with the real resolved path. Supervising
MiniMax units has repeatable failure modes (claimed-green dodges, fakes-only tests, a unit
routing around a permission gate) and the write-ups only help if they are opened.

Never blocks: always exits 0 on missing jq, malformed stdin or an unwritable TMPDIR.
Installed into both custom config homes (anthropic + minimax).

Claude-Session: https://claude.ai/code/session_014KNyfHmHpMbdMrHZXDRkAp
2026-09-23 13:51:54 +12:00

6.3 KiB

Hooks

Claude Code hooks that run automatically in response to events. Source of truth lives here; symlinks point from ~/.claude/hooks/ back to this directory.

Available Hooks

Hook Event File
Pre-compact backup PreCompact (auto + manual) hooks/pre-compact-backup.sh
Post-edit lint PostToolUse (Edit/Write/MultiEdit) hooks/post-edit-lint.sh
Pre-commit lint Git pre-commit hooks/pre-commit-lint.sh
WezTerm profile theme SessionStart (per-profile) hooks/set-wezterm-profile.sh
MiniMax gotchas reminder UserPromptSubmit (keyword) hooks/minimax-gotchas-reminder.sh

Post-edit Lint

Formats and lints files after every Edit/Write/MultiEdit. Dispatches to project-local formatters/ directory (symlinks to claude-foundations/formatters/).

Flow:

  1. Extracts file_path and cwd from stdin JSON
  2. Walks up from cwd to find formatters/ directory
  3. Creates a git hash-object checkpoint (.pre-lint file with blob SHA)
  4. Runs the matching formatter script
  5. On clean pass: removes checkpoint, exits 0 (silent)
  6. On lint errors: keeps checkpoint, exits 2 (feeds errors back to Claude via stderr)

Requires: python3 (for JSON parsing from stdin). Formatter tools are optional — missing tools silently pass.

Revert: git cat-file blob $(cat <file>.pre-lint) > <file>

Pre-commit Lint

Git pre-commit hook that runs project formatters on staged files. Reuses the same formatter scripts.

Flow: iterates staged files → runs matching formatter → re-stages formatted files → exits non-zero if lint errors remain (blocks commit).

Install: symlink .git/hooks/pre-commit → pre-commit-lint.sh, or use scripts/setup-formatters.sh.

Pre-compact Backup

Saves a copy of the session transcript before context compaction so no conversation history is lost. Backs up to ~/.claude/transcript-backups/ with timestamped filenames. Auto-prunes backups older than 30 days.

Triggers: Both auto-compaction (context window full) and manual (/compact command).

Requires: python3 (for JSON parsing from stdin).

Installation

The easiest way is to run the install script:

cd ~/dev/claude/projects/claude-foundations
scripts/install-hooks.sh

This symlinks all hooks into ~/.claude/hooks/ and prints the settings.json config to add.

Manual installation

  1. Symlink each hook into ~/.claude/hooks/:

    mkdir -p ~/.claude/hooks
    ln -sf "$(pwd)/hooks/pre-compact-backup.sh" ~/.claude/hooks/pre-compact-backup.sh
    ln -sf "$(pwd)/hooks/post-edit-lint.sh" ~/.claude/hooks/post-edit-lint.sh
    ln -sf "$(pwd)/hooks/pre-commit-lint.sh" ~/.claude/hooks/pre-commit-lint.sh
    
  2. Add the hook configuration to ~/.claude/settings.json:

    {
      "hooks": {
        "PreCompact": [
          {
            "matcher": "auto",
            "hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15, "statusMessage": "Backing up transcript before compaction..." }]
          },
          {
            "matcher": "manual",
            "hooks": [{ "type": "command", "command": "~/.claude/hooks/pre-compact-backup.sh", "timeout": 15, "statusMessage": "Backing up transcript before compaction..." }]
          }
        ],
        "PostToolUse": [
          {
            "matcher": "Edit|Write|MultiEdit",
            "hooks": [{ "type": "command", "command": "~/.claude/hooks/post-edit-lint.sh", "timeout": 30, "statusMessage": "Formatting and linting..." }]
          }
        ]
      }
    }
    
  3. For per-project formatters, run:

    scripts/setup-formatters.sh <project-dir> <ext> [<ext> ...]
    

WezTerm Profile Theme

Sets the WezTerm terminal theme when a Claude session starts or resumes, by emitting an OSC 1337 SetUserVar escape sequence. WezTerm fires its user-var-changed Lua event and applies the matching color scheme and background image from wezterm.lua.

Derives profile name from CLAUDE_CONFIG_DIR (e.g. ~/.claude-octopus → octopus). No-ops for the default profile.

Writes to /dev/tty to reach WezTerm directly, bypassing Claude Code's stdout capture. Safe in non-WezTerm terminals — the sequence is silently ignored.

Configure per profile in ~/.claude-<name>/settings.json:

"SessionStart": [
  { "hooks": [{ "type": "command", "command": "~/.claude/hooks/set-wezterm-profile.sh" }] }
]

MiniMax Gotchas Reminder

Fires on UserPromptSubmit when the prompt mentions MiniMax (minimax, mini-max, mini max) or mm-worktree-task, and injects a reminder to read the project's memory/gotchas-minimax.md before dispatching, briefing or gating a MiniMax unit.

Why it exists: supervising MiniMax units has a repeatable set of failure modes — agents reporting a green suite that was skipped, stale, or could never fail; following a brief's letter into a real defect; stating unreproduced root causes confidently; and (once) routing around a permission gate. Those write-ups are worthless if the supervising session never opens them.

Behaviour:

  • Once per session. A sentinel under $TMPDIR/claude-minimax-gotchas/<session_id> means a long MiniMax session is not nagged on every prompt.
  • Project-aware. Walks up from the session's cwd for memory/gotchas-minimax.md and names the real path; adds memory/gotchas-testing.md when it exists (fakes-only tests). With neither, it falls back to the standing rules plus a pointer to the known copies.
  • Never blocks. Always exits 0; missing jq, malformed stdin or an unwritable $TMPDIR all mean "stay silent".

Installed in both custom config homes (~/.claude-oreillyit-anthropic/settings.json and ~/.claude-oreillyit-minimax/settings.json):

{
  "hooks": {
    "UserPromptSubmit": [
      { "hooks": [ { "type": "command", "command": "~/.claude/hooks/minimax-gotchas-reminder.sh", "timeout": 10 } ] }
    ]
  }
}

Test it without waiting for a prompt:

echo '{"session_id":"t1","cwd":"'"$PWD"'","prompt":"dispatch a minimax unit"}' \
  | ~/.claude/hooks/minimax-gotchas-reminder.sh | jq -r '.hookSpecificOutput.additionalContext'

Adding New Hooks

  1. Create the script in hooks/
  2. Add an entry to this file
  3. Symlink into ~/.claude/hooks/
  4. Add the matcher config to ~/.claude/settings.json