Herkos / Docs / CLI reference

CLI reference

Every herkos command and its flags. The binary is a single Go executable; run any command with no arguments to see its usage.

Commands at a glance

CommandPurpose
keygenCreate the local ed25519 signing key.
registerWire Herkos into an MCP config.
unregisterRemove Herkos from an MCP config.
serveRun the in-path broker in front of an upstream server.
indexBuild the code-graph index for a repo.
selectPrint the minimal span set for a query (the served set).
scanAudit an MCP config and emit a security receipt.
statusShow the current state.
receiptSummarize a saved Merkle receipt file (root, enforcement, span count).
verifyVerify a receipt or an audit-log chain against a public key.
initInitialize Herkos in the current setup.

keygen

Create the local ed25519 signing key. It is written 0600 and stays on your machine. Every receipt is signed with it.

$ herkos keygen

register

Wire Herkos into an MCP config. Three modes. Wrap an existing server with --server <name>: Herkos rewrites that entry in place to launch through the broker, preserving its env, and leaves no direct entry the agent could still call - so there is no bypass. Add a new brokered server by passing the upstream command after --. Broker everything with --all: it wraps every local stdio server in the config, discovering each server's tools and pinning them as its allowlist.

$ herkos register --config <mcp.json> --server <name> --allow-tool <tool>
FlagDescription
--config <mcp.json>Path to the MCP config to rewrite.
--server <name>Wrap the server already named in the config, in place. unregister reverses it losslessly. Preferred: no un-brokered entry is left behind.
--allBroker every local stdio server in the config in one pass, pinning each to its currently-exposed tools. Skips remotes and already-brokered entries. Not combinable with --server.
--allow-tool <tool>Allow a tool by name. Repeat for each tool. Anything not listed is denied.
-- <upstream cmd>Add-new mode: the upstream server command. Everything after -- is passed through.
Prefer --server

Add-new mode (passing a command after --) leaves the original server entry untouched, so the agent can still reach it un-brokered. Use --server <name> to wrap a server that is already in the config; it rewrites that one entry and leaves no bypass.

unregister

Remove Herkos from an MCP config and restore the original launch line.

$ herkos unregister --config <mcp.json>
FlagDescription
--config <mcp.json>Path to the MCP config to restore.

serve

Run the in-path broker. Herkos sits in front of the upstream server and passes only the tools/call whose tool name you allowed. A call to any other tool is blocked in-path and answered with a JSON-RPC error; the session keeps running.

$ herkos serve --allow-tool read_file --allow-tool list_dir -- npx -y @some/mcp-server
FlagDescription
--allow-tool <tool>Allow a tool by name. Repeat for each tool. Deny-by-default for everything else. The agent's tools/list is also trimmed to this set, so it never loads the schema of a tool it cannot call.
--served-span <FILE:START-END>Pin a served span (end exclusive, the form herkos select prints). Repeat for each. Arms the content gate; needs --index.
--index <path>Code-graph index built by herkos index. With --served-span, its files are fingerprinted so out-of-set verbatim lines can be recognized.
--root <dir>Repo root the index's file paths are relative to. Default .
--key <path>Signing key path. Created on first use if missing.
--receipts <dir>Opt-in. Write a signed, hash-chained audit log of every brokered tool call to a fresh file in this directory. Sealed on shutdown; the tip hash is printed so you can anchor it. Verify with herkos verify.
--isolateLinux only. Run the upstream in a fresh network namespace with no route out (only loopback), so it cannot open its own socket to any host. For servers that only need stdio to Herkos. Unprivileged.
-- <upstream cmd>The upstream MCP server command to broker.
$ herkos serve --allow-tool read_file --receipts ~/.herkos/audit --isolate -- npx -y @some/mcp-server
--isolate, end to end

The same egress probe run as the upstream reaches HTTP 200 without --isolate and returns 000 (no route) with it. stdio - the MCP transport between the agent, Herkos, and the server - is unaffected, since it is not network. A server that needs its own outbound network should not be isolated. See the security model.

$ herkos serve --allow-tool post_message --index .herkos/index --served-span auth.go:1-40 -- npx -y @some/mcp-server
Scope

By default the broker gates the tool name of outbound tools/call only: it does not inspect arguments or gate other methods. With a served set pinned (--served-span plus --index) it also blocks arguments carrying repo lines from outside that set (after normalizing case and whitespace, so a reflow or recase trips), a userspace tripwire that encoding or paraphrase still defeats. See the security model.

index

Build the code-graph index for a repo. This is the tree-sitter parse that select and the content gate read; it stays on disk and is rebuilt when you re-run it.

$ herkos index --out .herkos/index <dir>
FlagDescription
--out <path>Index output path. Default <dir>/.herkos/index.
<dir>The repo directory to index.

select

Print the minimal span set for a query against a prebuilt index - the served set. These are the same spans that, on the egress path, become the deny-by-default allowlist. Pure-Go; it reads the index, it does not parse source.

$ herkos select --index .herkos/index --anchor Authenticate --budget 200
FlagDescription
--index <path>Path to an index built by herkos index. Required.
--anchor <symbol>Symbol to anchor the query on. Repeat for each. At least one required.
--budget <N>Line budget for the span set. Default 200.

Each printed span has the form FILE:START-END (end exclusive) - the exact form serve --served-span expects.

scan

Audit an MCP config and emit a security receipt: over-scoped tools, poisoned tool descriptions, and servers with unrestricted egress. Pass a baseline to diff against a known-good state.

$ herkos scan --config <mcp.json> --baseline <b.json>
FlagDescription
--config <mcp.json>Path to the MCP config to scan.
--baseline <b.json>Optional. A baseline receipt to diff against, to catch drift.
example output
  [unbrokered] codegraph: launched directly, not through the herkos broker
  [remote] bank: remote http server at an external URL; the stdio broker cannot mediate it
herkos scan: 0 over-scoped, 0 poisoned, 0 unrestricted-egress, 1 unbrokered, 0 unpinned-install, 1 remote - your code never left this machine

status

Show the current state. Add --json for machine-readable output.

$ herkos status --json
FlagDescription
--jsonEmit status as JSON instead of human-readable text.

receipt

Summarize a saved receipt file. Prints its Merkle root, enforcement mode, and span count without contacting any service. To cryptographically re-check the signature and root, use herkos verify --pubkey.

$ herkos receipt --file <r.json>
FlagDescription
--file <r.json>Path to the receipt file to summarize.

verify

Verify a receipt against an explicit public key, fully offline. It auto-detects the file: a single Merkle receipt verifies its signature and root; an audit-log chain (from serve --receipts) verifies the whole hash-chain and reports whether it was cleanly sealed. A truncated log - one missing its signed close record - is reported as INCOMPLETE with a non-zero exit, so silent tail-dropping is detectable.

$ herkos verify --file <receipt-or-chain.jsonl> --pubkey <hex>
FlagDescription
--file <path>The receipt file or audit-log chain to verify.
--pubkey <hex>Hex ed25519 public key (printed by herkos keygen and on serve startup). Required.
receipt vs verify

receipt summarizes a single Merkle receipt (root, enforcement, span count) from the file as-is. verify takes an explicit --pubkey and cryptographically re-checks the signature and root, so a third party can confirm a receipt or audit log without trusting your machine, and it understands the hash-chained serve --receipts log.

init

Initialize Herkos in the current setup.

$ herkos init