Your first block

One line guards a whole command family.

git stash is where an agent’s uncommitted work goes to die: it stashes, forgets, and your changes are three pops deep by the time you notice. Declare it off-limits — the hook below is the complete file. Drop it in .claude/hooks/, and every Bash call the agent makes passes through it before running.

Type at it. Try git stash, then get sneaky — hide it behind cd, chain it after &&, pipe into it. The code is editable, too: change the pattern and the verdicts follow.

from captain_hook import block_command

block_command(
    ["git", "stash"],
    reason="git stash hides work the rest of the team can't see",
    hint="commit to a branch or use jj instead",
)

Two things worth noticing:

The family is covered. cd /tmp && git stash, true | git stash, git stash pop — one declaration catches the command anywhere in the line, not just at position zero.

A mention is not a command. echo "git stash" names the command without running it, and it does not block. A token list is argv, so capt-hook compares it against the argv the shell parsed: the words have to be the command, not appear in it.

Hand block_command a string instead of a list and you get the other behavior — a regex over the raw line, which does block that echo. Next: when each one is right.