Guardrail Quickstart
Policy enforcement for programmatic tool execution. 15µs p50 latency. Zero hallucinations. Ungameable. Works with AI agents, CI/CD, automation, and shells.
Try it without installing
The quickest way to see it work is the demo walkthrough — ten real commands with the verdicts the engine actually returned, plus a copy-pasteable curl you can point at your own commands. No signup.
Install the CLI (free tier, no source needed)
The CLI installs with one command on macOS and Linux (x86_64 and arm64) and runs checks locally — no sudo, no source license. macOS support is new and in active testing — if you hit a rough edge, tell us and we’ll fix it fast:
curl -fsSL https://downloads.ellmstack.dev/install.sh | bash
guardrail link # pair this machine with your console account
guardrail check --tool Bash --target "rm -rf /"
# → verdict: deny — rm with destructive flags
The installer verifies the download’s SHA-256, installs to ~/.local/bin, and guardrail link delivers your API key encrypted — it is never printed and never appears in a URL. Overrides: GUARDRAIL_RELEASE_BASE, INSTALL_DIR, GUARDRAIL_FORCE_PLATFORM. Sign up in the console when link asks you to confirm; the free tier covers 8,000 checks/month.
Self-hosted (Docker)
The source ships to licensees under a commercial license agreement — request access and we’ll get you set up. Once you have it:
# Start the stack (engine + console) — builds locally from the shipped source
docker compose up -d
# Check a safe action
curl -s -X POST http://localhost:9090/check \
-H "Authorization: Bearer <your-key>" \
-H "Content-Type: application/json" \
-d '{"tool_name":"Bash","target":"cargo test","params":{}}' | jq .verdict
# → "allow"
# Check a dangerous action
curl -s -X POST http://localhost:9090/check \
-H "Authorization: Bearer <your-key>" \
-H "Content-Type: application/json" \
-d '{"tool_name":"Bash","target":"rm -rf /","params":{}}' | jq .verdict
# → "deny"
# Check an unknown action (fails safe → escalate)
curl -s -X POST http://localhost:9090/check \
-H "Authorization: Bearer <your-key>" \
-H "Content-Type: application/json" \
-d '{"tool_name":"Bash","target":"frobnicate_widget","params":{}}' | jq .verdict
# → "escalate"
Checks are authenticated with Authorization: Bearer <key> by default (keys are issued by the console). On a loopback-only install with no keys configured, you can set GUARDRAIL_NO_AUTH=1 instead.
Protecting a Claude Code Agent (5 Minutes)
Claude Code calls tools like Bash, Read, Write, Edit, WebFetch, WebSearch. Each tool call goes through the guardrail before execution.
Step 1: Start the guardrail
docker compose up -d
Step 2: Create your policy
The bundled policy template already covers Claude Code tools (file_read, shell_exec, run_command, etc.). Add your own:
# Deny: never allow deleting production data
[[category]]
name = "prod_destructive"
verdict = "deny"
[[action]]
name = "delete_prod_db"
category = "prod_destructive"
Restart the server to pick up policy changes — there is no hot reload.
Step 3: Intercept tool calls
The guardrail exposes POST /check. Your agent framework (or a thin middleware) sends each tool call before execution:
import requests
def check_tool(tool_name, target, params=None):
"""Returns 'allow', 'deny', or 'escalate'."""
r = requests.post("http://localhost:9090/check", json={
"tool_name": tool_name,
"target": target,
"params": params or {}
}, headers={"Authorization": "Bearer <your-key>"}, timeout=1)
return r.json()
# In your agent loop:
verdict = check_tool("Bash", "rm -rf /")
if verdict["verdict"] == "deny":
print(f"BLOCKED: {verdict['reason']}")
return # Don't execute
For Claude Code specifically, you can wrap claude with a pre-execution hook that queries the guardrail, or deploy it as a transparent proxy in front of any agent API.
How It Works
Agent Tool Call → Guardrail → Is this in my policy?
├─ Yes, deny category → BLOCK (15µs)
├─ Yes, allow category → ALLOW (15µs)
└─ Unknown → ESCALATE (fails safe)
The guardrail’s classification path doesn’t use regex, prompts, or an LLM. (Regexes appear only in the optional PII/sensitive-content redaction layers — never in the verdict path.)
It compiles your policy (TOML) into a Rete forward-chaining network. Every check is a deterministic inference: insert facts → run rules to fixpoint → read verdict. The same input always produces the same output — bit-for-bit, across restarts, across machines.
Why this matters: a prompt-based guardrail can be socially engineered. A regex filter can be bypassed with encoding tricks. A Rete network with content-addressed hashing and obfuscation-resistant normalization cannot.
Policy: What You Define
| Concept | TOML | What it does |
|---|---|---|
| Category | [[category]] name, verdict = “deny” or “allow” | A bucket (destructive_op, exfiltration, auth_disable) with a verdict |
| Action | [[action]] name, category | Maps a tool name to a category |
| Flag rule | [[flag_rule]] action, flags, category | rm with -rf flags → destructive; rm alone → escalate |
| Param key | [[param_key]] name, category | Flags capability-granting parameters (e.g. a --token key on a read-only tool) |
| Bridge | [[bridge]] sub, super | git_destructive IS_A destructive_op — transitive inheritance |
Adding a new dangerous action is one line of TOML. No recompile. Restart the server to pick up policy changes (there is no hot reload yet).
Verdicts
| Verdict | Meaning |
|---|---|
| Allow | Safe — proceed |
| Deny | Dangerous — block |
| Escalate | Unknown — ask a human (or your optional LLM judge) |
Deny beats Allow. Escalate beats nothing — if an action isn’t classified, it escalates (fail-safe).
Performance
Measured on ordinary x86 hardware. No GPU. No cloud dependency. Full benchmark →
| Metric | Value |
|---|---|
| Per-check latency (p50, pipeline) | 15µs |
| Per-check latency (p50, 1M realistic commands) | 19µs |
| Throughput (single core, sequential) | 37,745 checks/sec |
| Throughput (14 threads, parallel) | 22,096 checks/sec — parallel is slower (see benchmark) |
| Memory per check | ~65 KB |
| Cross-ecosystem accuracy | 115/115 dangerous calls denied, 0 false-ALLOW |
Custom Policies: Real Examples
“Never allow shell commands with pipes to interpreters”
[[action]]
name = "curl_pipe_to_interpreter"
category = "destructive_op"
“My CI agent can write files but not delete them”
[[action]]
name = "file_write"
category = "read_only_op"
[[action]]
name = "delete_file"
category = "destructive_op"
“SOC2: prevent exfiltration of customer data”
[[category]]
name = "customer_data_exfil"
verdict = "deny"
[[action]]
name = "read_customer_db"
category = "customer_data_exfil"
[[action]]
name = "export_customer_csv"
category = "customer_data_exfil"
API Reference
The full API surface (18+ endpoints including approvals, events, audit export, and sessions) is covered in the integration guide. The core three:
POST /check
{
"tool_name": "Bash",
"target": "rm -rf /",
"params": {"cwd": "/home/user"}
}
Response:
{
"verdict": "deny",
"tier": "deterministic",
"action": "rm_rf",
"confidence": "high",
"strategy": "exact_command",
"reason": "rm with destructive flags",
"ellm_trace": ["rm_rf --rel1--> destructive_op", "destructive_op --rel225--> rm_rf"],
"latencies": {
"mapper_us": 2,
"ellm_us": 13,
"llm_us": 0,
"total_us": 15
}
}
GET /health
{"status": "ok"}
GET /metrics
{
"total_checks": 15432,
"allow_count": 12100,
"deny_count": 3100,
"escalate_count": 232,
"avg_latency_us": 19,
"uptime_secs": 86400
}
Deployment Options
| Option | When to use |
|---|---|
docker compose up | Single machine, quick start |
| Kubernetes | Production, multi-replica (manifests ship with the source) |
| Systemd service | Bare metal, no containers |
| Embedded (Rust library) | In-process, zero network latency |
| Python SDK / MCP server | Agent integrations — python-sdk |
| C FFI | Not yet available |
Next Steps
- See it decide: read the demo walkthrough, or self-host with
docker compose up - Write your policy: copy the bundled template, add your actions and categories — see policy tuning
- Understand the boundary: threat model — what we protect against and the known gaps
- Integrate: wire
POST /checkinto your agent’s tool execution loop — integration guide - Go to production: deployment guide — TLS, monitoring, SLI/SLO targets