Agent gateway route

A hook route for gateways that run agents through their own tool interface and call DefenseClaw for each step. Off by default.

Some gateways run agents for many people through their own tool interface. Instead of posing as one agent (for example as Claude Code), such a gateway can call the agent-gateway route with a small event contract. DefenseClaw evaluates each event on the same path as every connector hook: the same rules, chains, correlation and lineage. Audit and telemetry record the connector as agent-gateway.

The route installs nothing into the gateway. The gateway calls it and enforces the answer.

Turn it on

The route is off by default. While it is off, /api/v1/agent-gateway/hook does not exist.

connectors:
  agent_gateway:
    enabled: true
    instance_name: gas    # optional label for audit on a per-user install

The setting takes effect at the next gateway restart.

  • Per-user install. The route is served on the gateway's TCP API and takes the gateway token, like every hook route. acting_for and root_session_id are ignored and recorded as acting_for_ignored=untrusted_caller and root_session_ignored=untrusted_caller in the local audit. They never change a verdict.
  • Managed device. Only the lifecycle or your administrator's managed policy sets the key. The route is served only on the managed hook socket (/run/defenseclaw-hook/hook.sock on Linux), where the kernel names the caller. The caller must be an enrolled user calling for themselves, or the service account of a trusted connector. Any other caller, root included, is refused with enterprise_managed_connector_unknown.
  • Windows managed devices have no hook socket, so the route is not served there in 1.0.6.

Builds before 1.0.6 refuse connectors.agent_gateway as unknown, so a managed policy that sets it must require release 1.0.6 or later.

Event contract

POST /api/v1/agent-gateway/hook with a JSON body, Content-Type: application/json and an X-DefenseClaw-Client header naming the caller (any value; the gateway refuses a POST without it). The schema is schemas/connectors/agent-gateway-hook.json. Unknown fields, duplicate keys and fields an event does not take are refused with HTTP 400 and a code.

FieldEventsNotes
eventallsession_start, session_end, user_prompt, pre_tool, post_tool, subagent_start, subagent_stop
session_idallrequired
tool_use_idpre_tool, post_toolrequired; pairs a call with its result
toolpre_tool, post_tool{name, kind, input}; kind is shell, file_read, file_write, fetch, mcp or other
tool_responsepost_toolrequired; any JSON
statuspost_toolsuccess, error, denied or cancelled; only success completes a chain step
promptuser_promptrequired; seeds the tool judge's view of the user's intent
parent_session_idsubagent_start, subagent_stoprequired
cwdanyabsolute working directory of the call
traceparentanyW3C trace context
acting_forany{user}; honoured only for a trusted connector
root_session_idanyfor a trusted connector: recorded in the local audit and kept with one person. Chains are evaluated per session; with guardrail.chains.root_scope on they also follow the root id across sessions

tool.kind picks the tool the rules already know: shell is judged by the shell rules (input is the command, or {"command": ...}), file_read and file_write by the path rules (input names path), fetch by the network rules (input is the URL, or {"url": ...}). mcp and other keep the tool name and get every content scan that applies to a tool DefenseClaw does not know. Path rules and ~ resolve against the account that runs the tools.

{"event":"pre_tool","session_id":"s-41","tool_use_id":"t-7","cwd":"/work",
 "tool":{"name":"bash","kind":"shell","input":"git status"}}

The answer is the generic hook answer: action (allow, alert, block), reason, rule_ids and the decision ids.

Fail mode

The calling gateway enforces the answer; DefenseClaw cannot enforce it inside another process. On managed and strict devices, treat a call that gets no answer as a deny. On a per-user install it is the caller's choice; deny is recommended.

Moving from a posed connector

A gateway that sends PreToolUse events to /api/v1/claude-code/hook keeps working. To move, map PreToolUse to pre_tool, PostToolUse to post_tool (add status), UserPromptSubmit to user_prompt, and the Bash tool to kind: shell.