Skip to main content
Runtime Hooks are trusted project policy that runs around agent execution. The same hook pack applies to direct chat, durable Run-backed chat, Channels, and agent nodes inside Project Loops. Create .polpo/hooks/quality.json:
Assign it in the agent’s agent.json:
Validate and deploy it with:

Decisions and order

Controlling hooks run sequentially by scope, priority, and declaration order. Observe-only hooks run concurrently and cannot change execution. A handler can return allow, deny, ask, defer, modify, or stop. tool:before may replace proposed input through modify.data.input. Polpo then applies the ordinary tool policy, approval, and schema validation before execution. tool:after may replace the normalized model-visible result through modify.data.result. Hooks never grant a capability the agent did not already have. Without terminationGate, turn:stop supports one bounded quality recovery step. If a hook returns feedback, Polpo makes one additional tool-free model call, checks the result again, and ends. Completed tools are never replayed.

Handlers and security

Handlers can run a sandbox command, call a public https endpoint, invoke a Polpo tool or mcp_tool, perform a bounded prompt, or invoke a bounded verifier agent. Use Connections for HTTP authentication. Inline authorization headers, tokens, API keys, and secret environment variables are rejected. Events use a versioned, redacted envelope and a stable idempotency key. Payloads, timeouts, output, recursion depth, prompt calls, and verifier turns are bounded. Provider-native tools execute at the provider; a pre-side-effect tool:before decision therefore requires a locally executed Polpo or Connection tool. On Polpo Cloud, a command hook without an explicit timeoutMs gets 60 seconds so a cold managed sandbox can start before the command runs. An explicit timeout still wins. The portable OSS default remains five seconds, and GET /v1/hooks/capabilities reports the managed command default. Set POLPO_RUNTIME_HOOKS=off as an emergency kill switch on a managed host.

Termination gate: validate and repair in the same agent

This opt-in extends turn:stop; ordinary stop hooks keep their existing behavior. Configure a deterministic validator and explicit cumulative limits:
The validator returns one of these results:
continue reopens the operational phase of the same invocation, with its authorized tools, history, sandbox and working copy. Diagnostics are model-visible JSON; the candidate is available at hook.data.candidate, alongside terminationAttempt and correctionCycle. The rejected final response is buffered, then replaced by the validated result. Structured output still uses the separate tool-free formatting phase; validation can return the agent to work before a new final output is produced. Tool/progress events remain observable. Remove the steps matcher to apply the pack to chat as well as Loop nodes. Validators use the same authorized tool executor; include the validation tool in the applicable tool policy. maxCycles is the number of allowed repairs (1–20); maxDurationMs is elapsed time from invocation start (at most one hour); maxTokens bounds reported agent/compaction tokens (at most 10 million). Agent maxTurns is an additional cumulative limit. Multiple matching gates use the strictest limits. Budgets survive checkpoints and cannot be loosened by resuming. Input tokens already processed by a provider cannot be preempted; the next output is capped and over-budget usage stops execution. Nested tool/model costs are separate. Validators themselves must be deterministic command, http, tool or mcp_tool handlers, bounded by timeout. Prompt/verifier-agent hooks remain available outside a gate. Empty output, missing decisions, invalid feedback, timeouts and checkpoint-write failures fail closed, even if onFailure says continue. stop with non-empty string feedback is a compatibility form of continue inside a gate. continue outside a configured gate is rejected. Diagnostics remain subject to the hook contract’s redaction and size limits. Durable Run chat and sequential Project Loop nodes persist history, cumulative budgets, step-invocation identity and pending/accepted validation together. A recorded validation decision is replayed without rerunning its handler. An accepted checkpoint returns its stored result without inference or rebilling previous usage. An interruption during a model/tool operation is marked termination_gate_effect_unconfirmed: it requires reconciliation and never blindly repeats the operation. Validators must honor their idempotency key because an external effect can precede its ledger write. Managed repair cycles retain the active sandbox lease for the current invocation. A checkpoint persists conversation and validation state; it is not a snapshot of an arbitrary sandbox. Recovery after loss of the worker or sandbox still requires the host to restore the working copy and reconcile uncertain effects. This feature does not add automatic crash retries. Direct HTTP chat supports continuation during the request, but has no crash-resume promise. Parallel graph branches do not yet have individual durable checkpoints: a durable gate in such a branch is rejected before inference. Client-tool handoff remains a handoff and does not count as successful termination. Existing public Project Loop approval-resume rules remain unchanged; this feature does not introduce a new retry endpoint. Errors use termination_gate_* codes, including cycles_exhausted, turns_exhausted, time_exhausted, tokens_exhausted, usage_unknown, checkpoint_invalid, checkpoint_too_large, effect_unconfirmed, parallel_unsupported and rejected. Traces distinguish validating, continuing and accepted, with stable hook execution IDs. In Cloud, runtime.termination-gate.mode and runtime.hooks.mode must both enforce for the target project/environment. Default gate rollout is off. A configured gate whose rollout or handler is disabled blocks execution instead of silently removing validation. Inspect polpo hooks capabilities --json: portable terminationGate states contract support; managed.terminationGate.enabled states availability on the target. Author packs under .polpo/hooks, run polpo hooks validate, then deploy normally.