Conditions compose
Commands are one attack surface. Files are the other: an agent that writes TOKEN=sk-live-... into .env has just committed your secret to its transcript. This guard watches for exactly that — and nothing else. Three conditions, one veto: pick a tool, a path, and file content, and see which combination fires:
The composition rules, in the order the widget just taught them:
only_if conditions AND together. Tool must match, path must match, content must match — miss any one and the hook stays quiet. Writing a secret to src/config.py passes (wrong path); writing prose to .env passes (no secret pattern).
skip_if is a veto. .env.example matches every only_if condition, and the skip wins anyway. Vetoes are how you carve the sanctioned exception out of a broad rule without weakening the rule.
A Read never trips a write guard. Tool("Edit|Write") scopes the hook to mutations. The agent can read .env all day — this hook has no opinion about that.