Open source · Apache 2.0

Your AI agents
need a bouncer

Every tool call your agent makes — reading files, hitting APIs, running queries — is intercepted, policy-checked, and recorded in a cryptographically signed audit ledger. Before execution. Every time.

View on GitHub PyPI ↗ npm ↗
Python pip install custos-mcp
Node npm install custos-mcp
client
AI Agent
tools/call ──────► ◄────── result
custos
Policy Gate
── allow ──► ◄── result ─
mcp server
Tool
seq:0 read_file allow sha256:a3f2…
seq:1 shell.exec deny sha256:8c1d…
seq:2 http_get allow sha256:f9b4…
Ed25519 signed · hash-chained · tamper-evident
0ms
policy overhead
Ed25519
signed records
2
runtimes, 1 ledger
0
server changes needed
Features

Everything you need.
Nothing you don't.

Custos is infrastructure, not a SaaS dashboard. Drop it in, define a policy, get audited.

🛡

Policy-first enforcement

Every tool call evaluated before execution against a YAML policy. Deny by default. First match wins. No runtime modification needed.

🔐

Cryptographic audit ledger

Ed25519-signed, SHA-256 hash-chained JSONL. Any modification to any record — including deletion or reordering — breaks the chain instantly.

🌐

Two runtimes, one wire format

Python signs. Node verifies. Or vice versa. The ledger format is a formal spec — enforced by a cross-language test on every commit.

In-process SDK

gate.call("tool", args, fn) — no proxy subprocess, no JSON-RPC overhead. Wrap any function and get policy + audit in one line.

🔌

Zero-change stdio proxy

Drop custos proxy -- python -m server in front of any MCP server. No server code changes. All traffic passes through transparently.

📦

Portable evidence bundles

Export a signed .tar.gz containing the full ledger, policy snapshot, and manifest. Verify it offline without running Custos.

📊

Live dashboard

Real-time allow/deny/error breakdown. Filter by tool or decision. Trace correlation across multi-agent pipelines. Runs in Python or Node.

🧩

Optional adapters

Native DSL is zero-dep and ships everywhere. Cedar and OPA adapters available for teams with existing policy infrastructure. OTel spans optional.


Policy DSL

Write rules, not code.

YAML rules evaluated top-to-bottom. First match wins. Rich operators, dotted-path resolution, human-readable reasons recorded in every audit entry.

policy.yaml
# deny everything by default
version: 1
id: production
default: deny

rules:
  # block path traversal first
  - id: no-traversal
    when:
      args.path: {contains: ".."}
    decision: deny
    reason: path traversal blocked

  - id: workspace-reads
    when:
      tool: read_file
      args.path: {prefix: "/workspace/"}
    decision: allow
    reason: workspace-only reads

  - id: safe-http
    when:
      tool: http_request
      args.method: {in: ["GET", "HEAD"]}
      args.url: {regex: "^https://"}
    decision: allow

  - id: deny-shell
    when:
      tool: {regex: "^shell\\."}
    decision: deny
    reason: shell tools disabled

Match operators

Conditions resolve against any field in the call context using dotted paths: tool, actor.id, args.*, server.id.

OperatorExample
glob"agent-*"
prefix{prefix: "/workspace/"}
suffix{suffix: ".json"}
contains{contains: ".."}
regex{regex: "^https://"}
in / not_in{in: ["GET","HEAD"]}
gt / lt / gte / lte{lte: 1048576}
exists{exists: false}

SDK

Drop in anywhere.

In-process SDK for embedding directly in agent code. No proxy required. Same API in Python and TypeScript.

Python
from custos import (
  Gate, Ledger, Actor, Server,
  generate_keypair, load_policy
)

kp     = generate_keypair()
kp.save(".custos")
ledger = Ledger(".custos/ledger.jsonl", kp)
policy = load_policy("policy.yaml")
gate   = Gate(policy, ledger,
           Actor("agent-1"),
           Server("fs"))

r = gate.call(
  "read_file",
  {"path": "/workspace/data.csv"},
  fn=read_file,
)

if r.allowed:
  process(r.result)
else:
  log(f"denied: {r.reason}")
TypeScript
import {
  Gate, Ledger,
  generateKeypair, loadPolicy, newActor
} from "custos-mcp";

const kp     = generateKeypair();
kp.save(".custos");
const ledger = new Ledger(
  ".custos/ledger.jsonl", kp);
const policy = loadPolicy("policy.yaml");
const gate   = new Gate(
  policy, ledger,
  newActor("agent-1"), {id: "fs"});

const r = await gate.call(
  "read_file",
  {path: "/workspace/data.csv"},
  ({path}) => readFile(path),
);

if (r.allowed) process(r.result);
else log(`denied: ${r.reason}`);

Use cases

Built for the real world.

Wherever AI agents run in production, Custos provides the governance layer.

Enterprise AI compliance

SOC 2, HIPAA, ISO 27001 all require audit trails. Export a signed evidence bundle and hand it to your auditor — no access to your systems required.

Multi-agent pipelines

Each sub-agent gets its own policy and actor ID. Correlated trace IDs let you reconstruct exactly what happened across the entire pipeline.

Jailbreak detection

A spike in denied shell.* calls or args.path contains ".." is a signal your agent is being prompted adversarially. Catch it in the ledger.

Development guardrails

Run with a permissive policy during dev, collect the full ledger, review what tools your agent actually calls — then tighten before prod.

Per-customer audit trails

SaaS AI features? Each customer gets their own policy and ledger. Per-customer proof of what the agent accessed on their behalf.

Air-gapped verification

Verify evidence bundles without running Custos. The ledger format is a public spec — implement a verifier in any language.

Start governing your agents.

Open source. Apache 2.0. No vendor lock-in. Runs anywhere Python or Node runs.

Read the docs → pip install custos-mcp npm install custos-mcp