How it works
Belay is a local-first security layer that sits at the tool-call boundary of an AI coding agent. Every action an agent tries to take — reading a file, running a shell command, calling an MCP tool — passes a deterministic policy check before it is allowed to happen. This page explains that boundary, the decision engine behind it, and the integration styles that plug into it.
When to read this
Read this to build the mental model behind everything else in the docs: why Belay is deterministic and fast, why it fails closed, and how it wires into different agents. Once this clicks, Verdicts and Audit & tamper-evidence follow naturally.
The tool-call boundary
An AI coding agent doesn't touch your machine directly with its "thoughts" — it acts through tool calls: file reads and writes, shell commands, MCP tool invocations. That boundary is the one place where every consequential action is visible and interceptable.
Belay inserts itself exactly there. Before a tool call executes, the call is
handed to Belay, which returns a verdict. A single agent misstep — or a prompt
injection that hijacks the agent — cannot silently leak a .env file, dump SSH
keys, run rm -rf /, pipe curl | sh, open a reverse shell, or exfiltrate data
to a known sink, because that action has to clear the boundary first.
Belay runs as your user, never root, and does not phone home by default.
Detect → Block → Notify
The product operates on three verbs:
- Detect. Belay auto-detects the AI coding agents installed on the machine — Claude Code, Codex, Cursor, Cline, Roo, Gemini CLI, Goose, OpenClaw, Hermes, Antigravity, opencode, and more — and how to intercept each one, then evaluates every tool call against a deterministic rule catalog.
- Block. Dangerous actions are denied outright. Ambiguous-but-risky actions are escalated to a human for an explicit Allow / Deny.
- Notify. You are informed — through the desktop app's privacy-safe notifications, the local live feed, and optional chat channels — of what was blocked or is awaiting a decision.
The decision engine
The engine that produces each verdict is built around four properties:
- Deterministic. The same tool call always yields the same verdict. Rules are compiled into the binary, and the outcome doesn't depend on a model's mood.
- No LLM on the hot path. There is no language-model call in the gating path. This is a policy engine, not a classifier that might hallucinate.
- Sub-100ms. Because it's deterministic and in-process, the check adds negligible latency to the agent's workflow.
- Fail-closed. If anything goes wrong — an internal error, a timeout, an unanswered escalation — the result is a deny, never an accidental allow.
The engine combines several signals into a single verdict: matches against the rule catalog (secrets, egress, destructive, RCE, supply-chain, persistence, privilege-escalation, recon, config-tamper), plus session correlation that watches for an "arm" step followed by a "sink" step, and the "lethal-trifecta" pattern across a session. Precedence is strict: Deny > Ask > Allow. A deny is never downgraded — not even by the allowlist that exists to wave through benign developer-toolchain activity. The full model is in Verdicts.
Every rule in the catalog is tagged with the OWASP Agentic Security Initiative (ASI) Top 10, the OWASP LLM Top 10, and MITRE ATLAS techniques.
The rule catalog is deterministic and local. A separate, optional static scanner
(belay scan) can consult an LLM cascade to filter false positives before you
install a package — but that is off the enforcement hot path. Runtime gating is
always LLM-free.
Explain & advise
Every verdict carries a plain-English explanation of why it is risky and what
to do — a curated summary / what / why_risky / normal_use /
suggested_action written per rule. You never get a bare rule ID.
An optional AI explainer can add a second, richer explanation. It is off by
default and feature-gated, bring-your-own-key: point it at a local Ollama
model or a cloud provider (Anthropic, OpenAI, Gemini, xAI, DeepSeek, Mistral,
Groq, Cohere, Perplexity, Together, OpenRouter, MiniMax) with a per-provider model
picker. The cloud key is pasted in-app (stored owner-only 0600 at
~/.belay/ai_key, write-only, never logged) or supplied via BELAY_AI_KEY.
Secrets and host paths are redacted before anything is sent, cloud mode
requires explicit consent, and the AI text is advisory only — it never makes
or changes a decision. Any error falls back silently to the curated explanation.
Integration styles
Different agents expose different extension points, so Belay meets each one where
it lives. At a concept level there are a few styles, and you don't pick them by
hand: belay detect reports how each agent will be intercepted, and
belay protect <agent> wires in the right one (belay unprotect <agent> cleanly
removes it).
Hook
For agents with native pre/post tool-call hooks (such as Claude Code and Codex),
Belay registers a hook. It gates the call before it runs, and on the
post-call side it redacts secret-shaped strings from tool output so a
credential that did get read isn't echoed back into the transcript. The hook —
belay hook pretooluse / belay hook posttooluse, installed into the agent's
settings.json — talks to the resident daemon over a local socket.
Gate
The gate style is a one-shot verdict: the tool call is passed in on stdin as
JSON, belay gate returns a decision on stdout, and the process exits. It's the
same policy engine in a pipe-friendly form, for integrations that prefer a
stateless call over a persistent socket client.
Agent-correct interception
Beyond generic hooks, Belay installs the interception each agent actually
supports: Claude Code and Codex get JSON hooks in settings.json; Cursor gets
Cursor hooks; Hermes gets its YAML pre_tool_call hooks; OpenClaw gets an
exec-policy; and MCP-server-driven agents get the mcp-proxy gate below.
MCP proxy
For agents driven through the Model Context Protocol, Belay runs as an MCP stdio proxy that wraps any real MCP server:
belay mcp-proxy -- <server-cmd> [args...]
Every tools/call request flows through the gate, so tool calls made through MCP
servers are checked too — not just the agent's built-in tools. The proxy is
fail-closed: anything that isn't an explicit allow (an unanswered ask, or any
error) becomes a deny.
What Belay does not do
Belay runs unprivileged, as the invoking user, never root — that's a
deliberate design choice. True syscall-level blocking (denying an operation in
the kernel before it happens) requires CAP_SYS_ADMIN/root and is out of scope by
design. Belay enforces at the tool-call boundary and, on Linux with the opt-in
privileged eBPF sensor, can detect and react to out-of-band tampering — but it
does not claim kernel-level pre-write prevention. See
Audit & tamper-evidence for the honest limits of
self-protection.
Related docs
- Verdicts: Allow / Ask / Deny — how a decision is reached and enforced.
- Audit & tamper-evidence — the record every decision leaves behind.
- Quickstart — detect and protect an agent.
- Platform Support — which layers are active per OS.