PreToolUse hook that checks every tool call before the call runs.
Where the hook sits is the point. Permission rules live next to general-purpose interpreters. A deny rule next to a wildcard Python grant stops an honest agent, but not one that has been redirected. The guard reads the command string no matter which interpreter would run it.
Install
In the app, open Enforcement, click Install / update guard, then click Register as PreToolUse. Or from a shell:hooks.PreToolUse. Your existing hooks keep their place and order. Before the change, settings.json is copied to settings.json.mbird-<timestamp>.bak.
What it blocks
The guard blocks a call by exiting with code 2. Every call is added to
~/agent/audit/tools.jsonl with the current enforcement mode, so you can see afterwards what ran while the guard was paused.
State
The guard reads~/.config/mockingbird/enforcement.json again on every call. Pausing and stopping take effect right away, with no restart, re-registration or reinstall.
When enforcement is paused or stopped, a banner appears on every screen and the menu bar icon becomes hollow.
What it checks
The guard reads what a call does, not the data it carries.
Otherwise, the guard doesn’t check file contents. A document that mentions a path isn’t accessing it, and checking prose added nothing. Text about a destructive command deletes nothing. A script that contains one is still refused: once when it’s written to an executable path, and again when it runs.
Unrecognized payloads
Unrecognized payloads are handled on the safe side:- Valid JSON, but no recognizable fields. The guard still checks every byte for a T0 path, because a T0 path in any argument means something is pointing at an original. It only checks for destructive commands when the tool name suggests it runs things:
bash,shell,exec,run,command,terminal,script,osascript,processoreval. That way a search query or message body can still mention those commands. - Not JSON at all. The guard checks the whole payload for both patterns.
How it behaves
These calls were tested against a sandboxedHOME, and every case passed:
Four rules re-run cases from this table on every scan: the two blocks, the prose that’s allowed and the script that’s refused. They set
MB_SELFTEST=1 so the guard responds as if it’s active, whatever the current mode.
Remove the guard
Click Remove in the Enforcement tab, or run_guard-uninstall.sh. This unregisters the hook and renames the script to t0-guard.removed-<timestamp> instead of deleting it. The doctrine’s N6, never delegate deletion, applies to Mockingbird too.