Skip to Content
ConceptsKill Switch

Kill Switch

The kill switch lets you disable any registered agent instantly. Once an agent is blocked, the proxy rejects every subsequent request from that agent with HTTP 403 — without forwarding anything to the LLM upstream. No redeployment, no config change, no restart required.

How it works

Every inbound request to the proxy carries an X-Agent-ID header (or the agent ID is inferred from the API key). Before forwarding the request, interceptor.rs queries the agent registry:

inbound request | v interceptor.rs: SELECT status FROM agents WHERE agent_id = $1 | +-- status = "active" --> forward to upstream | +-- status = "blocked" --> return HTTP 403 immediately | +-- DB error --> forward (fail-open)

The check happens before any LLM call is made. A blocked agent consumes zero LLM tokens.

The current implementation performs one database query per request to fetch agent status. A TTL in-process cache is planned to reduce this to zero DB queries for the common case. Until then, each request adds one PostgreSQL round-trip (~0.5ms on a local network).

Blocking an agent

curl -X PUT http://localhost:4001/api/v1/agents/billing-agent \ -H "Authorization: Bearer $GOVRIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"status": "blocked"}'

Response:

{ "agent_id": "billing-agent", "status": "blocked", "updated_at": "2026-03-05T10:30:00.000Z" }

The change takes effect on the next request from that agent. There is no propagation delay beyond the time it takes the next request to hit the proxy.

Re-enabling an agent

curl -X PUT http://localhost:4001/api/v1/agents/billing-agent \ -H "Authorization: Bearer $GOVRIX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"status": "active"}'

HTTP 403 response format

When a blocked agent makes a request, the proxy returns:

HTTP/1.1 403 Forbidden Content-Type: application/json { "error": "agent_blocked", "message": "Agent 'billing-agent' is currently blocked. Contact your administrator.", "agent_id": "billing-agent" }

Your agent code should treat a 403 with error: "agent_blocked" as a signal to stop retrying. Standard 403 retry logic will loop indefinitely — add a check for this error code.

Fail-open behavior

If the agent registry database is unreachable (connection pool exhausted, PostgreSQL down), the kill switch fails open: the request is forwarded to the upstream as if the agent were active.

Fail-open is a deliberate choice. Failing closed (rejecting all traffic when the DB is down) would cause a complete proxy outage whenever PostgreSQL has a hiccup. For most deployments, the risk of an occasional unblocked request during a DB outage is lower than the risk of dropping all traffic. If you need fail-closed behavior, this can be patched in interceptor.rs.

A tracing::warn log line is emitted whenever the kill switch falls back to fail-open:

WARN govrix_scout_proxy::interceptor: agent status check failed, failing open agent_id="billing-agent" error="connection pool timed out"

Implementation

FileRole
crates/govrix-scout-proxy/src/interceptor.rsKill switch check — queries agent status before forwarding
crates/govrix-scout-store/src/agents.rsget_agent() — database read for agent status
Last updated on