Gateway API
defenseclaw-gateway HTTP surface — every route registered in internal/gateway/api.go, the auth + CSRF model, and the verdict shape that inspect/scan endpoints return. Authoritative source is api.go itself.
defenseclaw-gateway exposes an HTTP surface used by hook scripts, the OpenClaw plugin, the CLI, and the TUI. This page lists every route the gateway actually registers, grouped by purpose.
This is not an OpenAPI spec — request/response shapes evolve and the canonical source is the handler code. For exact field names, point at the handler in internal/gateway/api.go (which mux.HandleFunc references the implementing file).
Last audited: every entry on this page was verified against mux.HandleFunc calls in internal/gateway/api.go:Run() (lines 304-393). If you add or rename a route in code, update this page in the same PR — make docs-check will fail otherwise.
Bind address
| Knob | Default | Where set |
|---|---|---|
gateway.api_port | 18970 | ~/.defenseclaw/config.yaml |
gateway.api_bind | 127.0.0.1 | ~/.defenseclaw/config.yaml (override only when running the sandbox/lan profile) |
gateway.port (proxy) | 18789 | Separate from the API server — the proxy port the LiteLLM/Bifrost upstream listens on |
The gateway binds to localhost by default. To expose the API to the LAN (sandbox/multi-host setups), set gateway.api_bind: "0.0.0.0" in ~/.defenseclaw/config.yaml. defenseclaw setup does this for you when it provisions the sandbox profile.
Auth
Every request — except GET /health — must carry the gateway token. Two header forms are accepted (constant-time compared in tokenAuth):
X-DefenseClaw-Token: <token>
Authorization: Bearer <token>The token is resolved from one of, in priority order:
- The env var named by
gateway.token_env(custom name — operator intent wins) DEFENSECLAW_GATEWAY_TOKEN(canonical)OPENCLAW_GATEWAY_TOKEN(legacy fallback for existing installs)gateway.tokendirectly in~/.defenseclaw/config.yaml
There is no standalone token file (~/.defenseclaw/gateway-token is sometimes mentioned in older docs but the gateway never reads it). Use defenseclaw keys set DEFENSECLAW_GATEWAY_TOKEN to set the canonical env var; it lands in ~/.defenseclaw/.env.
CSRF protection
Every state-changing request also requires X-DefenseClaw-Client (any non-empty value identifying the caller — cli, openclaw-plugin, inspect-hook/1.0, etc.). The middleware rejects same-origin browser requests that lack it with 403. See apiCSRFProtect in api.go.
X-DefenseClaw-Client: cliEndpoints
Health & status
| Method | Path | Auth | Purpose |
|---|---|---|---|
GET | /health | exempt | Liveness + uptime + version. Used by k8s probes and defenseclaw doctor. |
GET | /status | required | Active connector + enforcement flags + connector_mode + provenance. Used by defenseclaw status and the TUI. |
GET | /v1/connectors | required | Lists every connector registered in the gateway (name, description, source, hook capabilities, tool inspection mode). |
Connector hooks
Each connector registers exactly one hook endpoint. The path is owned by the connector, declared in its HookAPIPath() method, and registered dynamically in registerConnectorHookRoutes.
| Method | Path | Connector | Source |
|---|---|---|---|
POST | /api/v1/claude-code/hook | Claude Code | internal/gateway/connector/claudecode.go |
POST | /api/v1/codex/hook | Codex | internal/gateway/connector/codex.go |
POST | /api/v1/cursor/hook | Cursor | internal/gateway/connector/hook_only.go |
POST | /api/v1/windsurf/hook | Windsurf | same |
POST | /api/v1/geminicli/hook | Gemini CLI | same |
POST | /api/v1/copilot/hook | GitHub Copilot CLI | same |
POST | /api/v1/hermes/hook | Hermes | same |
All hook endpoints share a per-IP rate limiter (20 RPS, burst 40 — see hookLimiter in api.go). Loopback callers (the on-host hook scripts) are exempt; the limit only applies to remote callers.
Inspection (rate-limited)
The /api/v1/inspect/* family is the hot path that connector hooks and the OpenClaw plugin call to score a single tool call, prompt, or completion. Mounted under a sub-mux that wraps the per-IP rate limiter.
| Method | Path | Used by | Purpose |
|---|---|---|---|
POST | /api/v1/inspect/tool | Hook scripts, OpenClaw plugin | Inspect a tool call (name + args). Returns the verdict envelope below. |
POST | /api/v1/inspect/request | Hook scripts, plugin | Inspect an outbound LLM request (prompt). |
POST | /api/v1/inspect/response | Hook scripts, plugin | Inspect a model response. |
POST | /api/v1/inspect/tool-response | Hook scripts, plugin | Inspect a tool's output before it returns to the agent. |
Code & network scanning
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/scan/code | CodeGuard scan of a code blob — used by the codeguard skill and the IDE plugin to lint with the rule pack's code-scanning rules. |
POST | /api/v1/network-egress | Egress decision for an outbound HTTP/DNS lookup (used by the OpenShell sandbox profile). |
Asset scanning
| Method | Path | Purpose |
|---|---|---|
POST | /v1/skill/scan | Run the skill scanner against a fetched skill bundle. |
POST | /v1/plugin/scan | Run the plugin scanner against a plugin manifest + sources. |
POST | /v1/mcp/scan | Run the MCP scanner against an MCP server's mcpServers.json. |
POST | /v1/skill/fetch | Fetch a skill from a registry source so it can be scanned before install. |
Asset enable / disable
| Method | Path | Purpose |
|---|---|---|
POST | /skill/disable | Quarantine a skill by key. |
POST | /skill/enable | Re-enable a previously disabled / quarantined skill. |
POST | /plugin/disable | Quarantine a plugin by name. |
POST | /plugin/enable | Re-enable a plugin. |
Inventory
| Method | Path | Purpose |
|---|---|---|
GET | /skills | List discovered skills with admission state. |
GET | /mcps | List discovered MCP servers with admission state. |
GET | /tools/catalog | Aggregate tool catalogue across the active connector. |
Policy
| Method | Path | Purpose |
|---|---|---|
POST | /policy/evaluate | Evaluate the OPA admission policy against an arbitrary input. Used internally by the scanners and exposed for debugging. |
POST | /policy/evaluate/firewall | Evaluate the firewall sub-policy in isolation. |
POST | /policy/evaluate/audit | Evaluate the audit sub-policy. |
POST | /policy/evaluate/skill-actions | Evaluate the skill_actions sub-policy by severity. |
POST | /policy/reload | Reload the OPA policy bundle (policies/<name>.yaml + policies/rego/) without restarting the gateway. Returns 200 + the active policy name. |
Guardrail control plane
| Method | Path | Purpose |
|---|---|---|
POST | /v1/guardrail/event | Submit a guardrail event (used by the LiteLLM bridge for upstream-triggered events). |
POST | /v1/guardrail/evaluate | Evaluate the guardrail rule pack against arbitrary content. |
GET | /v1/guardrail/config | Return the active guardrail config the gateway resolved at boot — handy for verifying setup guardrail actually wrote what you thought. |
Enforcement logging
These endpoints are write-only "I just blocked / allowed something" telemetry endpoints used by the OpenClaw plugin to keep the gateway's audit DB authoritative when the plugin makes the decision out-of-band.
| Method | Path | Purpose |
|---|---|---|
POST | /enforce/block | Log an enforcement-time block. |
POST | /enforce/allow | Log an enforcement-time allow. |
POST | /enforce/blocked | List recent enforcement-time blocks. |
POST | /enforce/allowed | List recent enforcement-time allows. |
Audit
| Method | Path | Purpose |
|---|---|---|
POST | /audit/event | Append a single audit-event JSON to the SQLite store. Used by hook scripts and plugin SDKs. |
The gateway has no streaming or query HTTP endpoint — read history through the CLI:
defenseclaw-gateway audit export --output audit.jsonl # JSONL of audit_events
tail -f ~/.defenseclaw/gateway.jsonl | jq # Live tail of the JSONL fallback
defenseclaw alerts # Recent alerts (paginated)
defenseclaw tui # Live dashboardConfig
| Method | Path | Purpose |
|---|---|---|
POST | /config/patch | Apply a JSON-Patch-style update to a single config key (used by the TUI's quick-edit panel). For full reloads, restart the gateway — see setup guardrail which restarts when needed. |
AI usage / discovery (AIBOM)
The continuous AI Discovery surface — see AI Discovery for the operator workflow.
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/agents/discovery | Receive an agent-discovery report from the on-host scanner. |
GET | /api/v1/ai-usage | Snapshot of detected AI components by ecosystem. |
POST | /api/v1/ai-usage/scan | Trigger an on-demand AI usage scan. |
GET | /api/v1/ai-usage/discovery | Discovered agents, models, tools. |
GET | /api/v1/ai-usage/components | Aggregated components across the active workspace. |
GET | /api/v1/ai-usage/components/{ecosystem}/{name}/locations | Where the component was detected. |
GET | /api/v1/ai-usage/components/{ecosystem}/{name}/history | Detection history for one component. |
GET | /api/v1/ai-usage/confidence/policy | Show the active confidence-scoring policy. |
POST | /api/v1/ai-usage/confidence/policy/validate | Dry-run validation of a candidate policy file. |
Codex bridge
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/codex/notify | Codex agent-turn-complete notifier. The Codex notify-bridge.sh shim posts each turn's JSON arg here so the gateway can audit turn counts and completion reasons. |
OTLP receiver
The gateway accepts OTLP-HTTP from connectors (Codex, Gemini CLI native OTLP) and from the local-observability stack. Body is OTLP-JSON.
| Method | Path | Purpose |
|---|---|---|
POST | /v1/logs | Ingest OTLP logs. |
POST | /v1/metrics | Ingest OTLP metrics. |
POST | /v1/traces | Ingest OTLP traces. |
POST | /otlp/{token}/... | Same three signals, but the token rides in the URL path instead of a header. Useful for OTLP exporters (Gemini CLI's settings.json) that can't set arbitrary HTTP headers. |
See internal/gateway/otel_ingest.go for the parsing details and Local observability for the operator setup.
Verdict envelope
The four /api/v1/inspect/* endpoints return a ToolInspectVerdict (or its near-twin for response-side inspection):
{
"action": "block | confirm | alert | allow",
"raw_action": "block",
"severity": "CRITICAL | HIGH | MEDIUM | LOW | INFO",
"confidence": 0.93,
"reason": "matched: shell.dangerous-rm:Recursive delete on root",
"findings": ["shell.dangerous-rm"],
"detailed_findings": [
{
"rule_id": "shell.dangerous-rm",
"title": "Recursive delete on root",
"severity": "CRITICAL",
"confidence": 0.93,
"evidence": "rm -rf /",
"tags": ["destructive", "shell"]
}
],
"mode": "action | observe",
"would_block": true,
"approval_timeout_ms": 0
}Notable behaviours:
actionis the effective verdict, not the raw policy decision.applyMode()downgradesblock/confirm/alerttoallowwhen the gateway is inobservemode, but preserves the raw verdict inraw_actionand the would-have-blocked signal inwould_block. This is how observe-mode dry-runs work without touching the rule pack.confirmis the in-process HITL signal. The gateway resolves the operator approval inline (via the in-processHILTApprovalManagerit constructs inSetHILTApprovalManager()) before returning. There is no HTTP HITL surface — every HITL decision happens in-process and the verdict is downgraded toalloworblockbefore the response is written. The TUI reads HITL state from the audit DB, not from a/v1/hilt/*endpoint.
Other endpoints return their own shapes — /v1/skill/scan returns a scanner-specific envelope, /audit/event returns {"status": "stored", "id": "..."}, /skill/disable returns {"status": "disabled", "skillKey": "..."}. Always confirm against the handler code before assuming a shape.
Headers
| Header | Direction | Purpose |
|---|---|---|
X-DefenseClaw-Token (or Authorization: Bearer ...) | request | Gateway auth. Required on every endpoint except GET /health. |
X-DefenseClaw-Client | request | CSRF marker — any non-empty caller identifier (cli, openclaw-plugin, inspect-hook/1.0). Required on every state-changing endpoint. |
X-DefenseClaw-Request-Id | request (optional) | Caller-supplied correlation id. The gateway also accepts the more common X-Request-Id and X-Correlation-Id for compatibility with OpenTelemetry / Envoy / Microsoft / New Relic instrumentation. If unset, the gateway mints one. See requestctx.go. |
CLI commands
Every defenseclaw verb, grouped by what you are trying to do — first run, setup, audit, scanning, gateway control, status, uninstall.
Configuration
~/.defenseclaw/config.yaml schema, environment variables, on-disk layout, and per-connector source-of-truth files. The single source of truth for "where does this setting live?"