Guides
Monitor
Where chock hooks log their decisions for each install method, how to read and sum up the log, and how to export it as evidence.
Every chock hook writes one line per decision to a local log. Nothing leaves the machine. chock status reads the log and sums it up. chock witness export writes one client's records to a file you attach yourself.
The decision log
Every chock hook writes one line per decision to a local JSONL file. It uses no network and sends no telemetry, and it never logs a file's contents. Each install method has its own file, and the engine keeps one rotated file beside it:
- Repo hooks, in the repository:
.chock/log/gate-events.jsonl,.chock/log/gate-events.1.jsonl - Plugin, in your home folder, one folder per agent:
~/.chock/log/<agent>/events.jsonl,~/.chock/log/<agent>/events.1.jsonl
Read it with chock status. Its options, as the engine prints them:
chock status
Policy states and coverage (--only registry,log for more)
usage: chock status [-h] [--repo REPO] [--only ONLY] [--summary] [--verify-log]
[--head SEQ:SHA256] [--policy POLICY] [--since DAYS] [--json]
[--by {policy,rule,agent,event}] [--format {text,md}] [--route {sync,plugin}]
[--level {info,debug}] [--verdict {allow,block,ask,warn,off}]
[--plugin PLUGIN] [--follow]
options:
-h, --help show this help message and exit
--repo REPO Repo root
--only ONLY Comma-separated subset of: policies, registry, log
--summary Log summary: rates, latency vs timeout, faults
--verify-log Walk each decision log's hash chain; exit 1 at its first break
--head SEQ:SHA256 With --verify-log: confirm a head kept earlier is still there
log section:
--policy POLICY Log: restrict to one policy id
--since DAYS Log: only records from the last N days
--json Log: machine-readable output
--by {policy,rule,agent,event}
Log: group by policy, rule, agent or event
--format {text,md} Log: md prints a markdown summary
--route {sync,plugin}
Log: only the sync route (this repo) or the plugin route
--level {info,debug} Log: info shows policy decisions only; debug adds allows
--verdict {allow,block,ask,warn,off}
Log: only records with this verdict
--plugin PLUGIN Log: only records from this plugin (plugin route)
--follow Log: print new records as they are written
chock gate-log
Alias of: status --only log
usage: chock status --only log [-h] [--repo REPO] [--policy POLICY] [--since DAYS]
[--route {sync,plugin}] [--level {info,debug}]
[--verdict {allow,block,ask,warn,off}] [--plugin PLUGIN] [--follow]
[--json] [--by {policy,rule,agent,event}] [--format {text,md}]
Read the decision log, both routes
options:
-h, --help show this help message and exit
--repo REPO Repository root (default: cwd)
--policy POLICY Restrict the report to one policy id
--since DAYS Only records from the last N days
--route {sync,plugin}
Only the sync route (this repo) or the plugin route (~/.chock)
--level {info,debug} info: only decisions a policy made; debug: allows too
--verdict {allow,block,ask,warn,off}
Only records with this verdict
--plugin PLUGIN Only records from this plugin (plugin route)
--follow Print new records as they are written (Ctrl-C stops)
--json Emit machine-readable results
--by {policy,rule,agent,event}
Group counts by policy, rule, agent or event
--format {text,md} md prints a paste-able markdown summary
Sum it up: chock status --summary
chock status --summary reads the same log and reports:
chock status --summary [--since DAYS] [--route sync|plugin] [--json]
- Fires per policy and per client, with block, ask, warn and fault counts and rates. A fault is a hook that could not check the call: reason
guard-errored,guard-missingorfault. - The p50 and p95
duration_msper hook (client and hook point). Atinfo, chock logs only the calls a policy fired on, so the latencies cover those. Setdebugto time every call. - A WARN when a hook's p95 is within 25% of its client's hook timeout. When a hook runs past the client's timeout, the call goes through, so a call slower than that goes through unchecked. It shows an undocumented timeout as
unknownand never warns on it. - The top 5 guard faults, by policy and reason code.
- Heartbeats (
session_startrecords): hook records with nosession_startbefore them, andsession_startrecords with no hook record after them, per install method and client. For a client with no session-start event in agentseam's records, the summary says "no heartbeat available", never that one is missing.
Export evidence: chock witness export
chock witness export --client <client> writes one client's records from both install methods, redacted, to a new local JSON file, and prints the agentseam issue to attach it to. It refuses to overwrite an existing file. It uploads nothing: you read the file and attach it yourself.
chock witness export
Export one client's redacted decision log for its agentseam evidence issue (witness export --client C)
usage: chock witness export [-h] --client CLIENT [--since DAYS] [--out OUT] [--repo REPO]
options:
-h, --help show this help message and exit
--client CLIENT The client: an agentseam id, or a chock install/sync name
--since DAYS Only records from the last N days
--out OUT A new .json file to write; an existing file is refused (default: ./chock-
witness-<client>-<date>.json)
--repo REPO Repository root whose sync-route log is read (default: cwd)
The settings are a person's
Files under .chock/ are a person's to change, the log settings .chock/chock-log.json and ~/.chock/chock-log.json included. Every chock bundle refuses an agent's write to either settings file, through a shell command (best effort) or an Edit/Write. If a repository installs protect-agent-config (0.7.6 in the pinned catalog), the policy refuses any agent write to the .chock/ folder, by shell or by Edit/Write. Its gate makes one exception. It leaves .chock/state and .chock/log to the engine, which owns them. Reading stays allowed. A client with no chock bundle, in a repository without that policy, has no such refusal. Edit the files yourself, in your own editor or shell.
From the engine docs: docs/decision-log.md
Levels
| Level | Writes |
|---|---|
off | nothing |
info (default) | one line each time a policy fires: block, ask, warn, a guard fault, or an override or rollout level that let a finding through; and one line per allowed agent tool call, carrying only its target fingerprint. However many policy hooks judge that call, its allow is one line, written at once by the first hook to run and naming no policy (no policy_id, plugin or match fields): an allowed call is the call's, not any one policy's. A call is known by the client's tool_use_id, else by session, second and target, so with no id two identical calls in one second are one line. Every block, ask, warn, fault and override keeps its own line per policy |
debug | every hook call (one allow line per policy hook), the turn's end included, plus a trace: wire event, tool, matched rule (or "no rule matched"), the guard's exit code, per-stage timings, and the command or path cut to 200 characters with every value the scan-secrets policy would block replaced by [redacted] |
chock status counts allowed tool calls once each, in total (allowed_calls), and never toward a policy: its per-policy columns show what a policy decided, its blocks, asks, warns and overrides.
Each line carries ts, route, level, agent, client (when the payload names one), event, policy_id, surface, verdict, reason, duration_ms, can_ask, actor, session_id (the client's session id, when the payload carries one) and, on a tool call, target. The sync route adds chock_version (left out when the hook's Python has no chock installed). The plugin route adds plugin and plugin_version instead, never chock_version: a plugin runs its own bundled Python, not chock. On the sync route a compiled gate's line is written by gate.py and keeps its own fields (kind, match_count, matches, rules), plus actor, and session_id and target from the hook that ran it. A git hook's line carries actor only: a commit is no tool call.
Heartbeat
Where the client documents a session-start event, chock wires one more hook there (the runtime, with no flags) on both routes, and it writes one line per session at info:
{"ts": "...", "event": "session_start", "route": "sync", "agent": "codex_cli", "session_id": "...", "chock_version": "0.15.2", "level": "info"}
The plugin route's line carries plugin and plugin_version instead of chock_version. The hook never refuses and never blocks the session; a heartbeat that cannot be written is dropped. Most clients fail open when a hook crashes or never loads, so a session with no heartbeat is the sign of a hook that did not run: chock doctor reports it. Antigravity, Mistral Vibe and Windsurf document no session-start event, so they have no heartbeat.
Settings (a person's, only)
{"level": "debug", "max_bytes": 4194304}
One file per scope, both optional, each named chock-log.json inside a .chock folder:
- the environment:
CHOCK_LOG_LEVEL=off|info|debugin the shell the agent client was started from; - the repository:
<repo>/.chock/chock-log.json; - the user:
~/.chock/chock-log.json; - the default:
info,max_bytes1048576 (1 MiB).
The first that sets a value wins. max_bytes must be a whole number from 65536 (64 KiB) to 1073741824 (1 GiB); a value outside that range, an unknown level or key, or unreadable JSON is ignored and named by chock status --only log. CHOCK_GATE_LOG=0 still works: it is a deprecated alias for CHOCK_LOG_LEVEL=off.
An agent cannot change the level. A hook's environment comes from the client, not from the command an agent writes, so CHOCK_LOG_LEVEL=off rm -rf build changes nothing. Every chock bundle refuses an agent's write to either settings file, raising or lowering, through a shell command (best effort) or an Edit/Write (chock-guardrails-protect). A client with no chock bundle installed has no such refusal: there the settings files are protected only by whatever policies the repository itself installs. Edit the file yourself, in your own editor or shell.
Logging never changes a verdict, never raises and never blocks: a line that cannot be written is dropped silently.
Reading it
chock status --only log # both routes, per policy
chock status --only log --route plugin --plugin <name> --verdict block --since 7
chock status --only log --level debug --json # allows included
chock status --only log --follow # print new lines as they are written
Built from engine 5a4b6287a46e and catalog 1e60d211c1bb.