#!/usr/bin/env python3 """PreToolUse hook that blocks recursive ``grep``. Recursive grep (``grep -r``/``-R``/``--recursive``/``-d recurse``/``rgrep`` ...) walks an entire directory tree into memory and can OOM-kill the agent process on large repos. The system prompt only *asks* the model to avoid it; this hook turns that into a hard, deterministic block. Protocol: read the PreToolUse envelope as JSON on stdin and signal the decision to the runner: recursive grep -> deny: exit 2 + a deny JSON on stdout (+ reason on stderr) anything else -> allow: exit 0, nothing on stdout Any unexpected condition falls through to "allow" (fail-open), matching the runner's contract -- only an explicit deny blocks the tool call. Detection is a pure function (``command_is_recursive``) with no I/O, so it is trivially unit-testable -- run ``no-recursive-grep-guard.py --self-test``. Parsing is a single quote-aware lexer (``lex``) shared by every stage: * a quoted span is one operand and is never read as a flag (``grep "rm -rf" log`` and ``grep "-r" file`` are not recursive); * shell ``#`` line-comments are dropped; * live command substitutions ``$(...)`` / backticks (unquoted or inside double quotes -- single quotes suppress them) are recursed into; * pipeline/compound operators (``| & ; ( ) { }`` + newlines) split segments, so a recursive flag must belong to grep, not e.g. ``ls -R | grep``; * ``sh``/``bash -c "