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
| Command | Purpose |
|---|---|
keygen | Create the local ed25519 signing key. |
register | Wire Herkos into an MCP config. |
unregister | Remove Herkos from an MCP config. |
serve | Run the in-path broker in front of an upstream server. |
index | Build the code-graph index for a repo. |
select | Print the minimal span set for a query (the served set). |
scan | Audit an MCP config and emit a security receipt. |
status | Show the current state. |
receipt | Summarize a saved Merkle receipt file (root, enforcement, span count). |
verify | Verify a receipt or an audit-log chain against a public key. |
init | Initialize 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>
| Flag | Description |
|---|---|
--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. |
--all | Broker 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. |
--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>
| Flag | Description |
|---|---|
--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
| Flag | Description |
|---|---|
--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. |
--isolate | Linux 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
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
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>
| Flag | Description |
|---|---|
--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
| Flag | Description |
|---|---|
--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>
| Flag | Description |
|---|---|
--config <mcp.json> | Path to the MCP config to scan. |
--baseline <b.json> | Optional. A baseline receipt to diff against, to catch drift. |
[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
| Flag | Description |
|---|---|
--json | Emit 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>
| Flag | Description |
|---|---|
--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>
| Flag | Description |
|---|---|
--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 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