Intercept and control agent behaviour with hooks
In the SDKs the “hook” surface is the JSON-RPC event stream. You observe what the agent does, log it, and decide whether to allow, deny, or alter the next step. The CLI also exposes filesystem-level hooks for pre and post-prompt scripts.
Two layers of hooks
- SDK-level (event stream): subscribe to `tool_start`, `tool_update`, `tool_end`, `file_modified`, `permission_request`, and `error`. Use these for logging, metrics, UI rendering, audit trails, and approval gates.
- CLI-level (filesystem hooks): drop scripts into `~/.autohand/hooks/` to run before or after every prompt the CLI handles. Use these for organisation-wide policy, secret scrubbing, or routing every prompt through a logging pipeline.
The Swift SDK additionally exposes a `HookManager` that the `PermissionManager` consults for in-process approval decisions.
Hook into the event stream
Wrap a `streamPrompt` loop in a small dispatcher. Each branch is a hook: keep them fast, push slow work to a background queue.
Filesystem hooks
The Autohand CLI looks for executable scripts in `~/.autohand/hooks/`. Two slots run on every prompt:
- `pre-prompt`: receives the user prompt on stdin. Exit non-zero to block the prompt; print to stdout to rewrite it.
- `post-prompt`: receives the final assistant response on stdin. Use it for audit logging, redaction, or downstream notifications.
This is the right layer for org-wide policy that should apply to every SDK consumer, including ad-hoc CLI use.
Best practices
- Treat the event stream as your hook surface. It is consistent across SDKs and forward-compatible with new event types.
- Keep handlers fast. Push slow work (network calls, disk writes) to a background queue.
- Use filesystem hooks for policy that has to apply to every CLI run, not just SDK code paths.
- Always handle `error` events and `permission_request` in `interactive` mode.
- Avoid mutating the prompt mid-stream. If you need to redirect the agent, call `abort()` and start a new run.