The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Gatekeeper listing page.
A policy-based gatekeeper service that sits between AI agents and real-world tools (shell, HTTP, filesystem), enforcing approvals, denials, USD budgets, and audit logging.
If you're running AI agents (Claude, GPT, local LLMs, MCP servers) that execute tool calls against real systems — and you're responsible for what happens when those calls go wrong — Gatekeeper is for you. Specifically:
You were probably using: nothing (and trusting the prompt), ad-hoc Python wrappers around subprocess, a cloud LLM gateway, or shell-level sudoers rules that don't understand tool semantics.
AI agents need to execute actions in the real world: running shell commands, writing files, making HTTP requests. Without guardrails, an agent can accidentally (or adversarially) execute dangerous operations.
The Gatekeeper intercepts all tool requests and:
scope: run, keyed on runId: caps a single agentic run at the action boundary, where recursive burn compounds)/v1/messages call is audited, the API key stays centralized, and real per-token cost is metered onto the audit row and into budgets (off by default; see docs/API.md)All decisions are logged to an append-only audit trail (JSONL or Postgres). JSONL receipts include a sequence, previous-entry hash, and entry hash for independent tamper/gap verification. An aggregation endpoint (/usage) exposes call counts — and real cost/token sums — by actor × tool × day. A budget endpoint (/budget) surfaces current spend vs cap per configured rule.
Gatekeeper only controls actions that are actually routed through it. It does not infer coverage from installation. Verify the client's actual routing configuration before describing a runtime as protected.
The gatekeeper CLI previews every client configuration change, creates timestamped backups before applying one, and can restore the last patch:
Supported setup targets are claude-code, openclaw, and mcp. Fresh Claude Code patches set GATEKEEPER_FAIL_CLOSED=1. Existing fail-open hooks remain usable, but doctor reports them as a protection failure with the exact migration command.
The Cloud connection protocol is implemented for dogfooding, but the hosted team product is not
generally available. The experimental connection flow uses browser device authorization and a scoped
instance token stored locally with mode 0600:
Do not expect the public Cloud endpoint to be available during demand validation. Disconnect revokes Cloud access without turning off local OSS enforcement. See RUNESTONE_CLOUD.md.
Gatekeeper only controls actions that are actually routed through it. Native or bypass routes remain outside its boundary, so verify each client's real routing configuration before describing a runtime as protected.
The local Gatekeeper server and MCP integration are free. We're testing demand for Gatekeeper Team at $49/month, for up to five members and five instances: route an agent's held action to an accountable teammate for approval or denial, with a record of what happened. This is a proposed Cloud service, not a public hosted product; no payment is collected during this test.
See the proposed workflow and share your team's needs. You can also optionally report whether you've routed a first real action through local Gatekeeper or used it again on a later day. These are manual form choices, not verified external activation. Don't send commands or raw audit logs; this test adds no automatic usage reporting to the MCP server.
Coding agents fail in subtle ways. They start with a safe task, then escalate into sensitive local operations while trying to be helpful. Gatekeeper ships a built-in rule pack that catches these crossings.
Real failure pattern: A coding agent debugging a Puppeteer / Chromium
"Safe Storage" prompt on macOS first applied a normal flag-based fix
(--use-mock-keychain, --password-store=basic, throwaway --user-data-dir).
When the prompt persisted, the agent pivoted to inspecting the user's
Keychain — and proposed deleting entries "so there's nothing to access."
Gatekeeper classifies these against a built-in rule pack:
| Resource class | Examples |
|---|---|
credential_store | macOS Keychain (find / dump / delete) |
private_key | ~/.ssh/id_*, *.pem, ~/.ssh directory enumeration |
cloud_credentials | ~/.aws/credentials, ~/.config/gcloud/, ~/.azure/ |
env_secret | cat .env, .env.* reads via shell |
package_registry_token | ~/.npmrc, ~/.pypirc |
developer_auth | ~/.git-credentials, gh auth token |
browser_profile | Chrome / Chromium / Brave / Arc / Firefox profile dirs |
unknown_sensitive | Broad recursive home-dir secret greps |
Each rule has an effect (allow | require_approval | deny), a stable
category, a risk level, and an optional safer_alternative redirect.
Rules are mirrored into riskFlags (boundary:keychain-read,
category:credential_store_access, risk:high) so existing audit consumers
work unchanged.
Defaults always load — no opt-in required. Override or extend them under
sensitive_boundaries: in your policy.yaml; the full reference dump lives
at policies/sensitive-boundaries.yaml.
A demo fixture for the Puppeteer → Keychain escalation is at
examples/sensitive-boundaries/keychain-scope-creep.json.
@runestone-labs/gatekeeper-claude-code is a
Claude Code PreToolUse hook that routes Bash / Write / Edit / WebFetch
through Gatekeeper before Claude Code executes them. Install once globally,
drop the settings.example.json
snippet into ~/.claude/settings.json, and every gated tool call gets
evaluated against the boundary pack:
The legacy hook remains fail-open by default if the Gatekeeper server is down. The setup
CLI sets GATEKEEPER_FAIL_CLOSED=1 for new managed installations and reports existing configurations
that do not. Approval-required Bash, Write, and WebFetch calls are registered
as exact idempotent holds and executed locally once after approval. Edit is
policy-checked but is never reduced to a destructive whole-file write. See
integrations/claude-code/README.md
for the full configuration reference.
@runestone-labs/gatekeeper-mcp is a stdio MCP
server that lets any MCP client (Claude Desktop, Claude Code, Cursor, …) run
real tool calls — shell_exec, files_write, http_request, a generic
gatekeeper_call, plus gatekeeper_health — but only by routing every call
through Gatekeeper. Identity, role, and origin are pinned server-side (the
model can't escalate via tool arguments), and it fails closed: a deny, a
pending approval, or any malformed Gatekeeper response surfaces as an error,
never as a successful result.
Add it to your MCP client config:
It's also listed on the MCP Registry (preview) as
io.github.runestone-labs/gatekeeper. See
integrations/mcp-server/README.md for
the full tool table and security model.
This gatekeeper protects against:
rm -rf / or overwrites critical filesThis gatekeeper does NOT protect against:
The fastest way to try Gatekeeper:
npm run bootstrap creates .env from .env.example and writes a random 48-character GATEKEEPER_SECRET into it. Skip if you already have a .env you want to keep — docker-compose will error clearly if the secret isn't set.
Gatekeeper is now running at http://127.0.0.1:3847 with demo mode enabled.
Test it with the quickstart script (walks through DENY, ALLOW, and APPROVE):
Or test individual decisions:
To customize policy:
For manual installation without Docker, see below.
See all three decision types in action:
The demo runs through:
rm -rf /) is blockedls -la) requires approval, then auto-approveddemo.cast - Terminal recording (asciinema format)demo.gif - Animated GIF for sharingdemo.mp4 - Video filedata/audit/YYYY-MM-DD.jsonl - Audit log with all demo actionsThe gatekeeper uses a pluggable provider system for flexibility:
data/audit/All tool requests must include actor.role to enforce principal policies. For safe retries, include an idempotencyKey.
Response (200):
Response (202):
Response (403):
If a tool is configured with decision: approve, you can pre-authorize a specific call
with a capability token scoped to tool + args hash:
Include the capabilityToken in the tool request. Gatekeeper will allow the call
without manual approval if the token is valid.
Response:
See policy.example.yaml for a complete example.
For a complete policy writing tutorial, see docs/POLICY_GUIDE.md.
approve: Creates pending approval, sends notification via configured providerApproval links are:
For a detailed approval workflow guide, see docs/APPROVALS.md.
All requests are logged via the configured audit sink. Default (jsonl) writes to data/audit/YYYY-MM-DD.jsonl:
Logs are:
For a complete audit log reference with querying examples, see docs/AUDIT_LOGS.md.
Install the TypeScript client for integrating your agent with Gatekeeper:
See the full client README for all available methods.
Gatekeeper is designed to be agent-agnostic. Any agent that can route tool calls over HTTP can integrate with Gatekeeper. See INTEGRATING_AGENTS.md for the integration pattern.
OSS Local remains free and authoritative. Runestone is validating an optional hosted layer for shared approvals, policy versions, redacted evidence, drift alerts, and weekly reports. The proposed Team plan is $49/month for five instances and five members.
Cloud development remains frozen until at least five qualified external teams and three explicit $49/month commitments cross the public demand gate. Join demand validation.
Cloud never receives raw prompts, results, file contents, HTTP bodies or headers, environment values, or arbitrary custom arguments. See RUNESTONE_CLOUD.md for the exact versioned schemas and failure behavior.
| Feature | Implementation | Rationale |
|---|---|---|
| Approval signing | HMAC-SHA256 of full payload | Prevents parameter tampering |
| Single-use approvals | Status field + atomic update | Prevents replay attacks |
| Expiry | 1 hour default | Limits approval window |
| Input validation | Zod with .strict() | Rejects unknown fields |
| Shell constraints | cwd allowlist, timeout caps | Limits blast radius |
| SSRF protection | DNS resolution + IP checks | Blocks internal access |
| Audit logging | Append-only via pluggable sink | Tamper-evident trail |
The memory module provides graph-based knowledge storage (entities, episodes, evidence) via PostgreSQL + Apache AGE. It is an optional module — Gatekeeper works as a standalone policy engine without it.
Without a database: Only core tools (shell.exec, files.write, http.request) are registered. Policy enforcement, approvals, and JSONL audit logging work normally.
With a database: Memory tools are additionally registered, providing a knowledge graph for AI assistants.
| Tool | Description |
|---|---|
memory.upsert | Create/update entities (people, projects, concepts) |
memory.link | Create relationships between entities |
memory.unlink | Remove relationships between entities |
memory.query | Query entities (with full-text search) and traverse relationships |
memory.episode | Log decisions, events, and observations |
memory.evidence | Attach evidence/provenance to entities or episodes |
The database schema is split into two modules:
src/db/schema/audit.ts — Audit logs table (core gatekeeper, always available)src/db/schema/memory.ts — Knowledge graph tables: entities, episodes, evidence (optional module)The KG schema is a generic entity/episode/evidence model. Application-specific ontology (entity types, facet types, edge relations) is defined by the consuming application, not by gatekeeper.
See docs/MEMORY.md for setup and full API reference.
Apache-2.0 - See LICENSE for details.