Skip to content

Latest commit

 

History

History
327 lines (260 loc) · 13.9 KB

cli.md

File metadata and controls

327 lines (260 loc) · 13.9 KB

Command line

interlock (also python -m interlock) is installed with the package. Each command's --help shows the same text as below. --no-color (before the command) turns off color; color is also off when output isn't a terminal or NO_COLOR is set.

Command Does
doctor check that protection is actually on
report summarize a receipt log: blocks, monitor findings, latency
hook decide one coding-agent tool call (run by the agent)
install-hook put interlock in front of Claude Code, Codex or Cursor
policy check a declarative policy file, or show a built-in pack
learn draft a reviewable policy from observed receipts
trust trust a project's policy overlay
mcp inventory the MCP servers configured on this machine
reviews decide pending reviews; serve their status to agents
drift diff a live surface's tool listing against a recorded corpus

interlock doctor

Check that interlock protection is actually on.

Runs host-level checks and, when you point it at them, checks your policy, your sidecar and your receipt log:

interlock doctor
interlock doctor --rules myapp.policy:RULES --receipts audit.jsonl --key-file audit.key
interlock doctor --sidecar ~/.interlock/guard.sock --json

Inside your own process, call interlock.posture.attest() (or require()) instead: it sees the installed engine, sink, guards and approver directly.

Exit codes: 0 enforced, 1 degraded (warnings), 2 unprotected (a check failed).

usage: interlock doctor [-h] [--rules MODULE:ATTR] [--policy FILE] [--sidecar PATH]
                        [--receipts FILE] [--key-file FILE] [--json]
  --rules                    load this policy (same spec as interlock-sidecar --rules)
  --policy                   load this declarative policy file (JSON, or YAML with PyYAML)
  --sidecar                  probe the sidecar listening on this socket
  --receipts                 check this receipt log
  --key-file                 the receipt MAC key, to verify the log's chain
  --json                     machine-readable output

interlock report

Summarize a receipt log: what interlock blocked, rewrote and escalated, what monitor mode would have done, how long evaluation took, and whether any receipts were lost.

interlock report audit.jsonl --key-file audit.key
interlock report audit.jsonl --since 24h --monitor     # "would have blocked"
interlock report audit.jsonl --json

The chain is verified first when --key-file is given; the report always says whether it was. Receipts hold argument digests, never values.

Exit codes: 0 ok, 2 the chain is broken, 3 the log could not be read.

usage: interlock report [-h] [--since DURATION] [--monitor] [--top N] [--key-file FILE] [--json]
                        file
  file                       a receipt log written by FileSink
  --since                    only receipts newer than this: 30m, 24h, 7d (default: all)
  --monitor                  show what monitor mode would have blocked or rewritten
  --top                      rows per table
  --key-file                 the MAC key, to verify the chain
  --json                     machine-readable output

interlock hook

Decide one coding-agent tool call (run by the agent, not by you).

The agent passes its hook payload on stdin; the verdict goes back on stdout and the exit code, in that agent's own protocol. interlock install-hook writes the command line; you do not normally run this by hand, except to test:

echo '{"hook_event_name":"PreToolUse","tool_name":"Bash",
       "tool_input":{"command":"git push --force origin main"},
       "session_id":"s","cwd":"/tmp"}' | interlock hook --agent claude-code

Any error - unreadable input, a policy that will not load, a crash - denies the call (fail closed) unless --on-error allow, which lets the call through and says so loudly.

usage: interlock hook [-h] --agent {claude-code,codex,cursor} [--policy FILE]
                      [--rules MODULE:ATTR] [--sidecar PATH] [--receipts FILE] [--key-file FILE]
                      [--no-receipts] [--no-overlay] [--monitor] [--on-error {deny,allow}]
                      [--reviews {fallback,always,off}] [--review-db FILE]
  --agent                    
  --policy                   policy file (default ~/.interlock/policy.json, else the built-in coding-agent pack)
  --rules                    a Python policy module instead
  --sidecar                  ask this sidecar instead
  --receipts                 receipt log (default ~/.interlock/receipts.jsonl when its key exists)
  --key-file                 receipt MAC key
  --no-receipts              write no receipts
  --no-overlay               ignore project overlays
  --monitor                  record what would happen, never block
  --on-error                 what an internal error does (default deny)
  --reviews                  settle escalations through the review queue: when the agent can't ask (default), always, or never
  --review-db                review queue (default ~/.interlock/reviews.db)

interlock install-hook

Put interlock in front of a coding agent's tool calls.

interlock install-hook --for claude-code
interlock install-hook --for all --dry-run       # show the change, write nothing
interlock install-hook --for codex --uninstall

Registers interlock hook --agent <name> in the agent's hook settings (~/.claude/settings.json, ~/.codex/hooks.json, ~/.cursor/hooks.json), keeping every other entry, backing the file up first (.interlock-bak) and replacing any earlier interlock entry. The hook runs this Python and this interlock package, whatever directory the agent runs it from, and denies the call if it cannot start. It also creates ~/.interlock with a default policy that extends the built-in coding-agent pack and a key for the receipt log. Restart running agent sessions afterwards; re-run this if interlock moves.

Run this yourself, outside the agent: the coding-agent pack refuses it from inside one.

Exit codes: 0 done, 1 an agent could not be configured, 64 bad arguments.

usage: interlock install-hook [-h] --for {claude-code,codex,cursor,all} [--settings FILE]
                              [--policy FILE] [--sidecar PATH] [--receipts FILE] [--key-file FILE]
                              [--monitor] [--dry-run] [--uninstall]
  --for                      
  --settings                 the agent's settings file (default: its usual path)
  --policy                   pin this policy file in the hook
  --sidecar                  decide through this sidecar
  --receipts                 receipt log path
  --key-file                 receipt key path
  --monitor                  install in monitor mode
  --dry-run                  print the change only
  --uninstall                remove interlock's hooks

interlock policy

Check a declarative policy file before you rely on it.

interlock policy check policy.json
interlock policy check ~/.interlock/policy.json --overlay .interlock/policy.json
interlock policy show builtin:coding-agent        # print a built-in pack

check loads the file the way the guard will: it lists the rules, the locked ones, any rule quarantined as invalid (with why), and each overlay's status.

Exit codes: 0 valid, 1 loaded with quarantined rules, 2 does not load.

usage: interlock policy [-h] ACTION ...
usage: interlock policy check [-h] [--overlay FILE] [--json] file
usage: interlock policy show [-h] name

interlock learn

Draft a reviewable policy from a receipt log: the actions your guard actually allowed, and an escalation for everything else.

interlock learn --receipts audit.jsonl --out baseline.json
interlock learn --receipts audit.jsonl --out baseline.json --name acme-baseline

Reads a receipt log written by FileSink, keeps the actions observed with an ALLOW verdict (matched case-insensitively), and writes a declarative policy whose single rule escalates any action outside that envelope. The draft is deterministic - two runs over the same log are byte-identical - so a diff between two drafts is worth reviewing.

It is never auto-enforced: this command only writes the file you name. It installs nothing, enables nothing, locks nothing and emits no block rule. Review it with interlock policy check and install it on purpose.

Exit codes: 0 wrote the policy, 3 the log could not be read, held no ALLOW-observed receipt, or the output could not be written (no file is written in those cases); 64 the command line was wrong.

usage: interlock learn [-h] [--receipts FILE] [--out FILE] [--name NAME]
  --receipts                 a receipt log written by FileSink (required)
  --out                      where to write the draft policy (required)
  --name                     the policy 'name' field (default: learned-behavioural-baseline)

interlock trust

Trust (or stop trusting) a project's policy overlay.

interlock trust add                 # the overlay found from this directory
interlock trust add path/to/.interlock/policy.json
interlock trust list                # ok / CHANGED / MISSING
interlock trust remove [PATH]

An overlay (.interlock/policy.json in a repository) is ignored until trusted, and trust is tied to the file's exact content: edit it and it is ignored again until you re-trust it. add shows what the overlay adds before recording it. Run this yourself, outside the agent - the coding-agent pack refuses it from inside one.

usage: interlock trust [-h] [--store FILE] ACTION ...
  --store                    trust file (default ~/.interlock/trusted.json)
usage: interlock trust add [-h] [--yes] [path]
usage: interlock trust list [-h]
usage: interlock trust remove [-h] [path]

interlock mcp

Inventory the MCP servers configured on this machine.

interlock mcp scan                       # every server, with risk notes
interlock mcp scan --json
interlock mcp scan --emit-policy mcp.json  # a rule blocking unlisted servers
interlock mcp where github               # every config that defines it

Reads Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Gemini CLI and Codex configs (user scope, plus the project around --cwd). Never starts a server and never touches the network. Environment and header values are not read into the report - only their names.

Exit codes: 0 no risks found, 1 at least one risk note, 2 nothing matched (where).

usage: interlock mcp [-h] ACTION ...
usage: interlock mcp scan [-h] [--json] [--cwd CWD] [--emit-policy FILE]
usage: interlock mcp where [-h] [--cwd CWD] name

interlock reviews

Decide pending reviews, and serve their status to agents.

interlock reviews list                   # pending first; --status, --all
interlock reviews show r-1a2b3c4d
interlock reviews approve r-1a2b3c4d     # --as NAME (default: your login)
interlock reviews reject r-1a2b3c4d --reason "use the staging table"
interlock reviews revoke r-1a2b3c4d
interlock reviews wait r-1a2b3c4d --timeout 120
interlock reviews mcp                    # read-only MCP server (stdio)

A review is filed when a call escalates and is settled through the queue (see interlock.reviews). After an approval the agent retries the identical call, which runs once. Run approve/reject/revoke yourself, outside the agent: the coding-agent policy refuses them from inside one.

For the agent, add the MCP server to its config, e.g. for Claude Code:

{"mcpServers": {"interlock-reviews": {"command": "interlock", "args": ["reviews", "mcp"]}}}

Exit codes: 0 done, 1 the review can't be changed (wrong state, self-approval, unknown id), 64 bad arguments.

usage: interlock reviews [-h] [--db FILE] [--json] ACTION ...
  --db                       review queue (default ~/.interlock/reviews.db)
  --json                     machine-readable output
usage: interlock reviews list [-h] [--status {pending,approved,rejected,revoked,expired,executed}]
                              [--limit LIMIT]
usage: interlock reviews show [-h] id
usage: interlock reviews approve [-h] [--as NAME] id
usage: interlock reviews reject [-h] [--as NAME] [--reason REASON] id
usage: interlock reviews revoke [-h] [--as NAME] id
usage: interlock reviews wait [-h] [--timeout TIMEOUT] id
usage: interlock reviews mcp [-h]

interlock drift

Diff a live surface's tool listing against a recorded corpus.

interlock drift --corpus corpus.json --live "my-mcp-server --list-tools"
interlock drift --corpus corpus.json --live "..." --surface demo
interlock drift --corpus corpus.json --live "..." --json

The corpus records each covered surface's tool-listing fingerprint and schema shapes (see interlock/drift.py). --live runs a command and reads its standard output as the live tool listing: one tool name per line, or one JSON object per line when you also record schema shapes. --live is a shell string, so a command with arguments or quoted paths works as written.

Every added tool, removed tool and changed schema shape is reported with a severity, and any finding is drift. Nothing is written back and nothing is filed - the corpus is only ever read - so the diff is a report you act on.

Exit codes: 0 no drift, 1 drift found, 64 the command line was wrong, 3 the corpus could not be read or the live command failed.

usage: interlock drift [-h] [--corpus FILE] [--live CMD] [--surface NAME] [--json]
  --corpus                   the recorded corpus to diff against
  --live                     a shell command whose stdout is the live tool listing
  --surface                  which corpus surface the live command describes (default: the corpus's only surface)
  --json                     machine-readable output