Execution Hooks
Technical reference. This page is for integrations, advanced configuration, or platform operations. For portal tasks, start with the user guide.
Hooks are operator-defined interceptors that fire at execution lifecycle points. They enable custom governance, validation, and observability without code changes.
Hooks are workload-scoped. Managing them requires hook.manage on the
workspace that owns the workload. Runtime execution loads the enabled hook set
with the workload context and evaluates matching hooks while steps and agent
tools run.
A hook_definition can also ship as a package-local asset inside an official
or community plugin package. Installing that package materializes the hook
definition into the workspace, but it is not usable until explicitly bound to
a release role — see Plugins & Connectors for the package
install lifecycle and
Resolving And Binding Installed Assets
for the bind step. The event/matcher/evaluation mechanics below apply
identically to hand-authored and package-installed hooks.
Hook events
| Event | When | Can Block |
|---|---|---|
PreStepUse | Before any step executes | Yes |
PostStepUse | After step completes | No |
PreToolUse | Before agent tool call | Yes |
PostToolUse | After agent tool returns | No |
Hook types
| Type | How it runs | Use case |
|---|---|---|
function | Calls a registered hook function by name | Prebuilt guards, validators |
Only function hooks are part of the current public contract. Function hooks
reference a runtime-registered function through definition.function_ref.
Hook Fields
| Field | Description |
|---|---|
event | One of PreStepUse, PostStepUse, PreToolUse, or PostToolUse. |
matcher | Optional regex matched against the tool name for tool events. |
hook_type | Currently function. |
definition | Hook-specific JSON. For prebuilt hooks, use {"function_ref": "<name>"}. |
priority | Higher priority hooks are listed first. Matching hooks still evaluate in parallel. |
enabled | Disabled hooks are stored but not evaluated. |
timeout_seconds | Per-hook timeout. Timed-out hooks emit diagnostics and continue. |
Each workload can have up to 50 enabled hooks. Hook definitions are capped at
32 KiB after canonical JSON serialization.
Matcher regexes use the same operator-authored regex guard as custom
guardrails: patterns over 512 characters, malformed regexes, and nested
unbounded quantifier shapes such as (a+)+ are rejected at authoring time.
Previously persisted unsafe matchers fail closed at runtime: tool-scoped events
are blocked and emit a hook diagnostic. Residual backtracking shapes that pass
the authoring heuristic are bounded by a per-match runtime deadline and also
fail closed with a hook diagnostic instead of wedging the executor.
Creating a hook
curl -X POST http://localhost:8000/v1/workloads/{id}/hooks \
-H "Content-Type: application/json" \
-d '{
"event": "PreToolUse",
"matcher": "postgres_query|mysql_query",
"hook_type": "function",
"definition": {"function_ref": "sql_injection_guard"},
"timeout_seconds": 5
}'API Reference
# List hooks for a workload
curl http://localhost:8000/v1/workloads/{workload_id}/hooks
# Create a hook
curl -X POST http://localhost:8000/v1/workloads/{workload_id}/hooks \
-H "Content-Type: application/json" \
-d '{"event":"PreToolUse","hook_type":"function","definition":{"function_ref":"ssrf_guard"}}'
# Disable a hook without deleting it
curl -X PATCH http://localhost:8000/v1/workloads/{workload_id}/hooks/{hook_id} \
-H "Content-Type: application/json" \
-d '{"enabled": false}'
# Delete a hook
curl -X DELETE http://localhost:8000/v1/workloads/{workload_id}/hooks/{hook_id}SDK Usage
from orqestra_sdk import OrqestraClient
async with OrqestraClient("http://localhost:8000") as client:
hooks = await client.hooks.list_hooks(workload_id)
created = await client.hooks.create_hook(
workload_id,
{
"event": "PreToolUse",
"matcher": "http_request|web_fetch",
"hook_type": "function",
"definition": {"function_ref": "ssrf_guard"},
"timeout_seconds": 5,
},
)
await client.hooks.delete_hook(workload_id, created["hook_id"])Prebuilt hooks
The runtime ships three injection guard hooks:
| Hook | Targets | What it detects |
|---|---|---|
command_injection_guard | code_execution | Semicolons, pipes, $(), rm -rf, banned commands |
sql_injection_guard | postgres_query, mysql_query, snowflake_query, … | UNION SELECT, ; DROP, OR 1=1, SLEEP() |
ssrf_guard | http_request, web_fetch | Private IPs, cloud metadata endpoints (169.254.169.254) |
Enable them by creating hooks with hook_type: "function" and
definition.function_ref set to the guard name.
SSRF Private Host Allowance
ssrf_guard blocks private, loopback, and link-local IP literals by default.
If a private IP is intentional, pass allowed_private_hosts in the hook
definition config:
{
"function_ref": "ssrf_guard",
"allowed_private_hosts": ["10.10.0.15"]
}Use this only for known internal services. Cloud metadata endpoints remain blocked.
Evaluation
Matching hooks run in parallel. If any hook returns block, the tool
call is rejected. The most restrictive decision wins:
block > modify > continueTimed-out hooks fail open (return continue) to prevent hanging.
Hook failures and timeouts emit runtime warnings and a hook_evaluation
evidence artifact. Blocking hooks preserve the hook ID and reason so the
execution record can explain why the tool call was rejected.
Operator Workflow
- Identify the workload and tool surface you want to guard.
- Create a disabled hook with the intended
event,matcher, andfunction_ref. - Enable the hook in a non-production workspace and run a known-safe tool call.
- Run a known-bad tool call and confirm the execution is blocked with the hook reason.
- Inspect evidence for
hook_evaluationwarnings or advisories. - Promote the same hook definition through the governed release or workspace operations path used by your environment.