Houston docs

Hooks

Hooks (Settings, Hooks) run your own shell commands at set points in the agent loop. Each hook names an event and, for tool events, a matcher glob on the tool name. The other events match only an empty or * matcher.

Events

EventWhenWhat it can do
PreToolUsebefore a tool call runsblock the call, approve it (skipping the approval prompt), or rewrite its arguments
PostToolUseafter a tool callappend output to the tool result so the agent sees it (auto-format after every edit, run tests after a write)
UserPromptSubmitwhen you submit a message, before the turn runsblock the prompt or inject extra context
SessionStartonce when a run beginsadd context to the system prompt
Stopwhen the agent would end its turnforce another turn with the reason fed back ("run the tests before you stop"), bounded so a hook can't keep the agent going forever
PreCompactbefore the conversation is compactedfold context into the material being summarized, so it survives compaction

The exit-code contract

The simplest way to write a hook:

  • a non-zero exit blocks the blocking events (PreToolUse, UserPromptSubmit, Stop)
  • plain stdout and stderr are fed back to the agent

JSON output

For finer control, a hook prints a single JSON object on stdout:

FieldEffect
decision"block" vetoes the action even on a zero exit; "approve" (PreToolUse only) skips the approval prompt. A block always wins over an approve.
reasona human-readable explanation, fed back to the agent (and shown with a block)
additionalContextextra context added where the event fires: the tool result (PreToolUse), your message (UserPromptSubmit), the system prompt (SessionStart), or the material being summarized (PreCompact)
updatedInput(PreToolUse only) replacement arguments the tool runs with
systemMessagea note for you, never added to the model's context

Rewrites are re-checked. A rewrite that fails the tool's schema fails the call rather than falling back to the original arguments. Rewritten arguments are matched against your permission rules again, so the approval decision is made on what will actually run: a rewrite that lands on a deny rule is refused outright, even if the hook also approved. A hook can tighten policy, but it can never loosen a managed or project deny.

How hooks run

  • Several matches run in order. Any block wins, and the last rewrite wins.
  • Sandboxed: hooks run in the same project sandbox as run_shell, with no network.
  • Failing safe: a hook that can't be started counts as failed, so a PreToolUse or UserPromptSubmit hook that can't run blocks rather than lets the action through.

Environment variables

VariableHolds
$HOUSTON_HOOK_EVENTthe event name
$HOUSTON_TOOL_NAMEthe tool name
$HOUSTON_TOOL_INPUTthe tool's arguments
$HOUSTON_TOOL_RESULTthe tool result (PostToolUse)
$HOUSTON_USER_PROMPTyour message (UserPromptSubmit)

Large payloads. A payload over 16 KB (a large write, a long tool output, a long pasted prompt) is too big for an environment variable, so it's written to a private temp file instead. The variable is left unset, and $HOUSTON_TOOL_INPUT_FILE, $HOUSTON_TOOL_RESULT_FILE, or $HOUSTON_USER_PROMPT_FILE holds the file's path. A hook that may see large payloads should read whichever of the two is set. The file is removed once the hooks finish.