Docs › Extending AstraCode
Hooks
Run your own script when the agent is about to do something, and let it approve, block or rewrite the action.
A hook is your script, run at a specific moment in an agent run, given the event as JSON on stdin. It can let the action through, block it, or change it.
This is the escape hatch for anything AstraCode's own settings do not cover: enforce a house rule, refuse a command shape, log every edit somewhere, run a formatter at exactly the moment you want it.
The events
| Event | Claude Code's name | When it fires |
|---|---|---|
| sessionStart | SessionStart | A conversation begins: a chat's first message, a CLI run, a conversation's first request. Its context goes with that request. |
| beforeSubmitPrompt | UserPromptSubmit | Before your message is sent. May refuse or rewrite it. |
| preToolUse | PreToolUse | Before any tool runs. May allow, refuse, ask, or rewrite its input. |
| beforeShellExecution | Before a shell command specifically. | |
| postToolUse | PostToolUse | After a tool returns. May add context to what the agent reads. |
| afterFileEdit | After a file is changed. | |
| stop | Stop | A run ends. May submit a follow-up, up to the hook's `loop_limit` in a row (5 by default, `null` for no limit). |
| subagentStart | SubagentStart | A subagent starts. Observation only. |
| subagentStop | SubagentStop | A subagent ends. Observation only. |
Where hooks.json lives
Yours: ~/.astracode/hooks.json and ~/.cursor/hooks.json. The project's: .astracode/hooks.json and .cursor/hooks.json in every folder of the workspace, each run from its own folder. Hooks inside an agent file apply to that agent's tool calls only.
A project's hooks run only in a trusted workspace. A hook is a shell command, so a repository you have not trusted never gets to run one. In the CLI a
-prun trusts its folder, as Claude Code's does; a conversation,acporreviewneeds--trust,ASTRACODE_TRUST=1, or a folder you trusted once.
How one is defined
Each hook names its event, a command, and optionally a timeout in seconds (30 by default), a matcher (a regular expression over the tool name, ours, Cursor's or Claude Code's: Shell, Bash, Read), and failClosed. The command runs as sh -c from its folder, given the event as JSON on stdin. Cursor's file shape and Claude Code's (PascalCase events, a matcher with its own hooks list) are both read as they are.
At the timeout the hook and everything it started are killed. Its stdout and stderr are kept to 64 KB each, and the context it adds to a tool result to 8,000 characters.
What a hook can say back
Exit 0 and JSON on stdout: permission (allow, deny or ask), user_message for you, agent_message for the agent, updated_input to replace the tool's input (or prompt for beforeSubmitPrompt), additional_context for the agent, followup_message from a stop hook. Exit 0 with nothing, or with prose, says nothing.
Exit 2 blocks, with the reason taken from stderr (or stdout when stderr is empty). On a stop hook it asks the agent to keep going with that reason; after a tool, the reason is passed to the agent.
Claude Code's answers are honoured too: hookSpecificOutput.permissionDecision with its permissionDecisionReason, hookSpecificOutput.updatedInput and additionalContext, decision: "block" with reason, decision: "approve", continue: false with stopReason, and systemMessage. A hook written for Claude Code is also given Claude Code's payload: PreToolUse, Bash, an absolute tool_input.file_path, tool_response.
A blocking hook is a real veto:
beforeShellExecutionreturning a block stops the command, whatever the approval mode says.
Any other failure, a crash or a timeout, fails open: the action goes ahead and the failure is logged. Set "failClosed": true on a hook that guards something, and a failure denies instead.
Seeing what they did
The Customize page shows a log of recent hook runs, and the full output goes to an output channel. A hook that fails quietly is a hook you will spend an afternoon on.
If you have no hooks.json, none of this runs and it costs nothing.
All documentation
Get started
Agent
- Agent overview
- Approvals and permissions
- Plan mode
- What the agent can do
- Running commands
- Browser tools
- Checkpoints and undo
- Infrastructure as code
- Running several agents at once
- Subagents and background tasks
- Remote agents in GitHub Actions