# PreToolUse guard hook Makes the rewind guard enforceable instead of advisory. The MCP server cannot see another server's tool calls, so `zerto_check_tool` and `zerto_guard_before_mutate` only work if the model chooses to call them. A model that skips the step is not stopped by anything. A `PreToolUse` hook runs in the host, where the tool call genuinely pauses, so a failed checkpoint stops the change. ## Decisions | situation | decision | effect | |---|---|---| | tool in `read_only_tools` | none | runs, no checkpoint | | mutating, checkpoint confirmed | none, plus `additionalContext` | runs, and the model is told which checkpoint to recover from | | mutating, checkpoint failed | `deny` | **the call never happens** | | mutating, VM unknown to Zerto | `prompt` | human decides; nothing to rewind to | | mutating, no VM in the arguments | `prompt` | catalog's `vm_arg` did not match | | unlisted tool | `prompt` | nobody said it was read-only | `ZERTO_HOOK_UNKNOWN` switches the unlisted case to `allow` or `deny`. ## Install ```bash cp hooks/settings.example.json /tmp/x # then merge the hooks block into # .claude/settings.json export ZERTO_REWIND_CONFIG=/abs/path/config.json ``` Both paths in the command must be absolute, and the interpreter must be the venv that has this package installed. ## Timeouts, which matter here The hook is synchronous: the host waits. That is the point, because the checkpoint has to exist before the change does. Budget for the slow path, not the fast one. A successful tag took about 4s against a healthy VPG, but a **refusal took 63s**: `wait_for_tag` waits 45s for a checkpoint that is never going to appear, which is exactly what happens on a VPG whose protected site is AWS or Azure, where tagged checkpoints are not supported. So: - `timeout` in settings.json: 180 (seconds) - `ZERTO_HOOK_GUARD_TIMEOUT`: 150 (seconds), kept under it If the host's timeout fires first it cancels the hook and **discards its output**, and the tool call carries on through the normal permission flow. A timeout is therefore a silent failure of the guard, which is why the hook's own budget is the smaller of the two: it would rather deny than be cancelled. ## Verified behaviour Against a live ZVM 10.9.10, all six rows of the table above. Two worth naming: - `jp-ubuntu` (healthy, local VPG) tagged checkpoint 7180 and allowed the call, passing the tag back through `additionalContext`. - `win2019-1` (VPG `CMH-AWS-1`, protected site AWS) was **denied**: Zerto cannot insert a tagged checkpoint there, so the change would not have been recoverable. Both decisions held with `permission_mode: bypassPermissions`. A hook still blocks when the user has turned permissions off, which is when an agent is most likely to be running unattended. ## Log `~/.zerto-guard-hook.log`, or `ZERTO_HOOK_LOG`. One line per decision.