# How Chock works

The lifecycle of a policy in a repository, from authoring to a verdict and a log line, with diagrams that cite the engine's files.

A person authors a policy once. \`chock compile\` turns it into the control for each hook point, and \`chock sync\` wires those into the repository. After that, on agents whose hooks chock sets up, the hooks check each tool call, commit and push. Each check returns a verdict and writes one line to a local decision log. The CI gate runs the same check again on each pull request.

> Ask the user before running any command on this page: each one changes how their agent or repository behaves.

## The lifecycle, step by step

These steps follow the main path of the lifecycle diagram. Each step links the engine file that does the work, at the pinned commit:

- [Author a policy](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/scaffold/new.py): The chock new policy \<id\> command writes a policy skeleton. A policy is one folder under .agents/policies/\<id\>/: a manifest, an optional deterministic script, and an eval suite. The policy-init skill writes one from an interview.
- [`chock check`](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/lifecycle.py): Runs the repository's checks in order (validate, verify, evals, matrix, mechanisms, index, conflicts, baseline). The --only flag picks a subset.
- [`chock sync`](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/scaffold/recompile.py): Recompiles every installed policy, then writes each wired agent's hook file, the git hooks and INDEX.md. With --ci it also writes the CI workflow.
- [Agent hook files](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/hooks/in_agent_install.py): One entry per hook, in each agent's own file and format. Every entry runs the same committed launcher command.
- [Launcher](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/hooks/data/launch.sh): Runs the first of git config chock.python, python3, python and py that runs Python 3.11+. With none it exits 2, never allow.
- [Agent runtime](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/gate/runtime_bundle.py): The file `.chock/bin/<agent>.py` holds agentseam's bundle plus chock's handler. A `--guard` call runs the policy's script. A `--gate` call asks the vendored gate runner.
- [Gate runner](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/gate/runner/verdict.py): Evaluates a compiled gate, caps its verdict, and concludes with an exit code. It is assembled into .chock/bin/gate.py, the same runner the git hook and CI run.
- [Decision log](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/src/chock/gate/decision_log.py): One line per hook decision. With repo hooks it is `<repo>/.chock/log/gate-events.jsonl`. With the plugin it is `~/.chock/log/<agent>/events.jsonl`. It never raises, never changes the decision and never logs contents.

## Diagrams

Each box cites the engine file that does the work, at a pinned commit. Each diagram has a page with a card per box.

- [Lifecycle in a repository](https://chock.sh/docs/architecture/lifecycle/index.md): The repo path from end to end. You author a policy, check it and sync it into hook files. Then each tool call, commit, push and CI run goes through the hook to a verdict and one log line.
- [Emitters and hook points](https://chock.sh/docs/architecture/enforcement-surfaces/index.md): Which emitter of chock compile writes each hook point, and the file chock sync installs for it.
- [Stop and resume](https://chock.sh/docs/architecture/stop-and-resume/index.md): A person's stop on agents. It shows the files chock stop and chock stop --everywhere write, the hooks that read them, and the log lines a stop leaves.
- [The life of a policy](https://chock.sh/docs/architecture/life-of-a-policy/index.md): One policy from its manifest in chock-catalog, through chock compile and an install, to a tool call, its verdict and the decision log.

From the engine docs: [docs/architecture.md](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/docs/architecture.md)

## The components

| Component | Path | Role |
| :--- | :--- | :--- |
| **CLI** | `src/chock/cli.py` | One entry point; dispatches to each activity |
| **Scaffold** | `src/chock/scaffold/` | `init` / `new` / `install-skills` (deterministic) |
| **Compiler** | `src/chock/compile/` | Surfaces + per-surface emitters + coverage |
| **Validation** | `src/chock/validation/` | Spec/schema/budget/security/eval checks |
| **Registry** | `src/chock/registry/` | Artifact index + content hashes |
| **Lockfile** | `src/chock/lock.py` | Reproducible, hash-pinned installs |
| **Hooks installer** | `src/chock/hooks/` | Git dispatcher + policy wrappers |
| **Gate build** | `src/chock/gate/build.py` | Loads `hook.gate` from `manifest.yaml` and bakes `gate.json` |
| **Vendored runner** | `src/chock/gate/runner/` | Self-contained runtime that `chock.gate.assemble` builds into one file, `.chock/bin/gate.py` |
| **CI installer** | `src/chock/scaffold/install_ci.py` | Writes the GitHub Actions workflow that runs `ci-gate` |
| **Policies** | `.agents/policies/<id>/` | Installed from a catalog; owned by the adopter, never shipped |
| **Spec** | `spec/` | Neutral format, JSON schemas, enforcement matrix |

## Pointer model

`AGENTS.md` holds a single managed pointer to `.agents/policies/INDEX.md`. `chock sync`
compiles every active rule (full text), every gate, and every skill into that index, capped by
`index.max_tokens` in `.chock/config.yaml`. `INDEX.md` is the ambient attention surface for
the agent; git hooks remain the guaranteed enforcement floor. The pointer is constant
so adapters never have to be rewritten when rules change.

## The CLI is a package manager, not a runtime

The deterministic parts (scaffold, compile, validate, install) live in the **CLI**. The generative
parts — authoring a bespoke policy from an interview — live in **skills** that the CLI *installs into
your own agent* and that your agent runs. Chock ships no LLM of its own.

See [Core Concepts](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/docs/concepts.md) for the vocabulary and [Enforcement Surfaces](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/docs/enforcement-surfaces.md)
for the coverage model in detail.

From the engine docs: [docs/decision-log.md](https://github.com/open-coder-ai/chock/blob/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021/docs/decision-log.md)

## Hash chain

Each line carries `seq`, its place in its file's chain, and `prev`, the sha256 of the line before it
(that line's exact bytes, without the newline). A log's first line names 64 zeros. After a rotation the
new file's first line names the rotated file's last, so the chain runs across both files. Every route
writes through the same journal: runtime hooks, git hooks, the MCP gateway, `chock stop` and
`chock resume`, and overrides.

A writer waits up to one second for the lock. A line it cannot chain (the lock stayed held, or the last
line could not be read) is still written, with `unchained` naming why. A chaining failure never
changes a verdict.

Ask the user before running the commands below:

```bash
chock status --verify-log [--route sync|plugin] [--json]   # exit 0 intact, 1 at a break
chock status --verify-log --head <seq>:<sha256>            # confirm a head you kept is still there
```

It walks each log (rotated file first) and reports the first break: the file, the line, and the
expected and found `prev` or `seq`. An edited, deleted, inserted or reordered line breaks the link of
the line after it. History that is missing or rotated away is not a break: the walk reports
`chain starts at <hash> (seq N)`. Lines written before chaining existed are counted, then the chain
starts. A line written after that by a runtime that does not chain yet (until `chock sync` regenerates
it, or the plugin is reinstalled) is a break of kind `unchained`. The break names the line and says why: a runtime without chaining wrote it, or a writer timed out on the
lock. **An intact chain needs every runtime regenerated** (`chock sync`, or reinstalling the plugin) once this
version is installed; until then, lines from older runtimes break it.

What it shows, and what it does not:

- It shows a change made after the fact to someone who kept an earlier head (`seq` and `sha256`, as
  `--verify-log` prints it and `chock witness export` carries it): `--head` fails once that record
  changes, even when every later hash was recomputed.
- It does not stop anyone who can write the file. A local admin, or any process running as you, can
  rewrite the whole file and every hash, and the walk then passes. Without a kept head, the chain
  shows only edits that left the later links alone.
- Deleting the newest lines, or the oldest lines of the oldest file, leaves no break; only a kept head
  shows the first.
- It makes no claim about any regulation or standard.


---

Built from engine [5a4b6287a46e](https://github.com/open-coder-ai/chock/commit/5a4b6287a46e07f9f856d9bbe10622bd1ff2e021) and catalog [1e60d211c1bb](https://github.com/open-coder-ai/chock-catalog/commit/1e60d211c1bb767152c6ab0167932da06ab3a10f).
