Herkos / Docs / Concepts

Concepts

Three ideas carry the whole tool: SpanGate, signed receipts, and the two enforcement modes. Read these and the rest of the docs follow.

SpanGate

SpanGate is the one mechanism, and Herkos is infrastructure that runs it, not an AI agent of its own. For each query, Herkos's local code graph emits a minimal set of (file, line-range) spans. That same set does two jobs at once:

The reason one set can do both is the claim at the center of Herkos: the minimal context an agent needs is exactly the only thing it should be allowed to send. Derive the context and the egress allowlist from one set and they cannot drift apart; split them across two tools and the gap between them is where leaks live. One set, no gap, with a signed receipt over what was served.

query from the agent local code graph emits minimal (file, line-range) spans one span set model context the spans it needs egress allowlist deny-by-default same set

Receipts

Herkos produces two kinds of signed proof, for two different questions. Both are signed with your local ed25519 key and verifiable on your machine, so no server has to vouch for either.

The span receipt: which spans were served

A SpanGate run ships a signed Merkle receipt of the served span set. The receipt commits exactly which (file, line-range) spans the pipeline selected for a query, so you can answer after the fact, with proof, which context was in scope. It is a record you hold, not a log you have to trust a vendor to keep.

a verified receipt
SpanGate demo (files [auth.go db.go])
  served 40 / 500 lines  (the minimal span set for the query)
  bytes blocked from egress: 256  (enforcement=userspace)
  receipt: VERIFIED  root=02659078080f474c9fac20c7a83aa070f95cda014e0b0ea0994d7dde477d3008

The Merkle root is deterministic over the canonicalized span set, so two runs that served the same spans produce the same root. herkos receipt --file <r.json> summarizes a saved receipt; to cryptographically re-check its signature and root, use herkos verify --file <r.json> --pubkey <key.pub>.

The serve audit log: what the broker did

The span receipt proves what went in. The audit log proves what the broker let out. Run herkos serve --receipts <dir> and Herkos writes a per-session log with one record for every brokered tools/call: the tool name, a hash of the request, and whether it was allowed or denied. Each record is ed25519-signed and sha256 hash-chained to the one before it, so any edit, reorder, or dropped record breaks the chain. A reader verifies the whole log offline with only the public key.

When you serve with a pinned span set, the log's opening record also commits a fingerprint of that served context. The signed chain then proves which context-egress binding was in force for the calls it records, not just that some calls happened. Verify a log the same way as a receipt: herkos verify --file <log> --pubkey <hex>.

brokered call tool, req hash, decision ed25519 + hash chain prev hash links each record signed audit log a record you hold VERIFIED offline, public key only FAILED one byte off herkos verify tamper

Enforcement modes

At runtime the broker sits between the agent and the upstream MCP server: it gates each tools/call deny-by-default, forwards allowed calls untouched, and records every brokered call to the signed log. It also trims the tools/list the agent loads to the allowlist, so the agent never loads the schema of a tool it cannot call - fewer tool-catalog tokens at session start, and a smaller surface. How strictly egress is enforced beyond that comes in layers. Be clear about which you are running.

agent any MCP client herkos serve deny-by-default tool gate + content tripwire upstream MCP server possibly untrusted signed audit log hash-chained, context-bound herkos verify offline, public key only tools/call allowed: forwarded denied: blocked in-path every call
ModeStatusWhat it enforces
userspace Shipped Advisory and auditing. Deny-by-default tool-name control on outbound tools/call, plus a signed audit trail. Not a kernel-enforced seal.
serve --isolate Shipped (Linux) Kernel network namespace with no route out: the brokered server gets only loopback and cannot open its own socket to any host. Unprivileged. For servers that only need stdio to Herkos; not a per-destination allowlist.
hardened Roadmap OS-enforced, per-destination byte-level egress boundary using Linux Landlock and seccomp, then eBPF host allowlisting. The airtight mode for servers that do need their own network; not shipped yet.
Read this carefully

userspace mode is not airtight. It gives you deny-by-default tool control and a signed audit trail, not a kernel-enforced seal on outbound bytes. serve --isolate adds a kernel boundary for a server that needs no network of its own. The per-destination seal for servers that do (and the byte-level provenance boundary that ties egress to exactly the served span set) is hardened-mode work, on the roadmap.

The local code graph

The span set comes from a code graph that Herkos builds locally with a tree-sitter parser (Go, TypeScript, and Python today). The graph never leaves your machine, and neither does the signing key. Local-first is not a slogan here; it is what makes the receipt trustworthy, because the thing producing it is under your control.

Next

The security model spells out the threat model and publishes the bypass. The CLI reference documents every command.