@warren-dean/code-kit 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,7 @@
9
9
  "name": "code-kit",
10
10
  "source": "./",
11
11
  "description": "Keeps AI coding agents inside your project's rules, from idea to merged code: spec design, lanes, layer rules, protected paths with an approval log, spec-check and design gates, proof-before-finish checks, dispatch, review, build status and CI verification, configured per project from its docs",
12
- "version": "0.12.2",
12
+ "version": "0.13.0",
13
13
  "category": "development",
14
14
  "tags": ["guardrails", "architecture", "lanes", "layers", "spec-driven", "ci", "multi-agent"],
15
15
  "license": "MIT"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-kit",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "Keeps AI coding agents inside your project's rules, from idea to merged code: spec design, lanes, layer rules, protected paths with an approval log, spec-check and design gates, proof-before-finish checks, dispatch, review, build status and CI verification, configured per project from its docs",
5
5
  "author": {
6
6
  "name": "Warren Langeveldt"
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  What changed in each release of code-kit, newest first. Versions follow the plugin manifest and the npm package `@warren-dean/code-kit`. Each release is also on [GitHub Releases](https://github.com/warrendeanlangeveldt/code-kit/releases).
4
4
 
5
+ ## 0.13.0 (2026-10-14)
6
+
7
+ A fix proves its bug, tests can't be weakened without you, and a passing `verify` says exactly what it covered.
8
+
9
+ - **A fix proves its bug.** A plan story with a `**Fixes:**` line, or a branch named `<lane>/fix-…`, must come with a test that fails without the fix and passes with it. `verify` runs the fix's tests in a fresh checkout with the fix taken out. A test that fails there only because it calls something the fix adds proves nothing, and `verify` asks for one that goes through the existing code. `regression.prepare` sets what that checkout runs first, such as `npm ci`.
10
+ - **Tests aren't weakened without you.** A commit that deletes a test, adds a skip or focus marker, removes cases or assertions, or rewrites a snapshot is refused and held in the band for your `tests` approval. The lead can't give it, and `verify` flags any weakening the approval log doesn't show you approved. A test that's only moved or renamed isn't flagged. `tests` in the config names the test files when the usual conventions don't.
11
+ - **Checks that didn't run are named.** A check whose tool isn't installed is listed under "Not run" by `verify` (and as `skipped` in its JSON), and a merge names it in its output and its merge commit. `ifMissing: "fail"` still fails it instead.
12
+ - **The merge queue merges the commit its review passed.** `queue add` records the reviewed commit, and `queue merge` verifies and merges exactly that commit. A branch that moves on after its review leaves the queue for the lead to review again.
13
+ - **An answer closes its decision at once.** Answering one of the lead's questions, or one in your brief, closes its card straight away. A question's card asks it plainly, with who decides and what it holds up, and the answer box has **Ask about it**. Brief questions owned by the lead alone no longer wait for you.
14
+ - **Clearer documentation.** The README says what a passing `verify` proves and where its limits are, and SECURITY.md lists the features that use the network: delegated dependency approvals, teams, and bug reports you send.
15
+
5
16
  ## 0.12.2 (2026-10-13)
6
17
 
7
18
  The Decisions tab is readable, and old package requests stop waiting.
package/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
 
8
8
  # code-kit
9
9
 
10
- A Claude Code plugin that keeps AI coding agents inside a project's engineering rules. You write the rules once, per project, in `.claude/code-kit.json`. The plugin's hooks enforce them on every tool call, for the main session and every subagent. A rule Claude would otherwise only be _asked_ to follow becomes one the hooks refuse to let it break. The same rules run in CI for every pull request.
10
+ A Claude Code plugin that keeps AI coding agents inside a project's engineering rules. You write the rules once, per project, in `.claude/code-kit.json`. The plugin's hooks check them on every file edit, shell command and finish, for the main session and every subagent. A rule Claude would otherwise only be _asked_ to follow becomes one a hook refuses to let it break, or, for shell commands, reports straight after for the agent to undo. `code-kit verify` runs the same rules on a branch, in review and in CI.
11
11
 
12
- It also carries the work from idea to merged code: spec an idea into requirements, hand stories to lanes, review each branch against its requirements, and track the build against the spec.
12
+ It has two parts. The core is the rules and their checks: who may write where, layers, protected files with an audit log, approvals, and proof before finishing. On top of it sits an optional workflow that carries work from idea to merged code: spec an idea into requirements, hand stories to lanes, review each branch against its requirements, and track the build against the spec. You can use the core without the workflow.
13
13
 
14
14
  **Pairs with [Context Graph](https://github.com/warrendeanlangeveldt/context-graph).** code-kit decides who may change what, and what has to be proved. Context Graph gives each agent the why behind a file before it edits it: the file's card, its rules and the decisions made on it, kept in git. Each detects the other: Context Graph's cards and slices then carry the file's spec requirement and layer rule. Install both for agents that stay in their lane and know why the code is the way it is.
15
15
 
@@ -46,19 +46,20 @@ Rules in `CLAUDE.md` and agent prompts are advice. Over a long session, or acros
46
46
  - an agent declares "done" with failing type checks, or with work nobody committed;
47
47
  - someone force-pushes, commits to `main`, adds a dependency, or runs a deploy nobody asked for.
48
48
 
49
- code-kit stops each of these at the moment it would happen. The hook refuses the tool call and tells the agent why and what to do instead. The rules live in one reviewed file, not in every prompt, so they hold for every agent and every session.
49
+ code-kit catches each of these, most at the moment it would happen: the hook refuses the edit or command and tells the agent why and what to do instead. A file a shell command writes is caught straight after the command, and the agent is told to revert it. The rules live in one reviewed file, not in every prompt, so they hold for every agent and every session. They are guard rails for agents, not a sandbox: see [What verify proves, and its limits](#what-verify-proves-and-its-limits).
50
50
 
51
51
  ## What it enforces
52
52
 
53
- - **Lanes:** each lane agent writes only its own paths. The main session (the lead) writes contracts, specs and config, and delegates the rest. Any other subagent is read-only.
54
- - **Layers:** each layer depends only on the layers it lists, and never on packages it's denied. This is checked before every write (a write that would add a violation is refused, so a layer is never broken on disk), after it, and again before finishing, for JavaScript and TypeScript imports. In brownfield code, existing violations can be recorded in a baseline so only new ones block.
53
+ - **Lanes:** each lane agent writes only its own paths. The main session (the lead) writes contracts, specs and config, and delegates the rest. Any other subagent is read-only. An edit outside those paths is refused before it happens; a file a shell command writes outside them is reported straight after, for the agent to revert, and the finish check refuses to finish until it's gone.
54
+ - **Layers:** each layer depends only on the layers it lists, and never on packages it's denied, for JavaScript and TypeScript imports. An edit that would add a violation is refused before it's written; the rules are checked again after each edit and before finishing, which is what catches a file a shell command wrote. In brownfield code, existing violations can be recorded in a baseline so only new ones block. Imports are found by pattern, not by parsing: see [the limits](#what-verify-proves-and-its-limits).
55
55
  - **Protected paths and the approval log:** every committed change to the kit, registers or contracts is appended to `.claude/approval-log.jsonl`, in the same commit. Only the lead writes these paths without a person's approval, and the person reviews them in the pull request.
56
- - **Spec-check before code:** when the project has specs, a lane can't write code on a branch until the spec-check report for that branch exists.
56
+ - **Spec-check before code:** when the project has specs, a lane can't write code on a branch until it has saved a spec-check report for that branch. The hook checks that the report exists; review checks what it says.
57
57
  - **Designs before screens** (optional): a screen file can't be written until the design register lists it.
58
- - **Shell rules:**
58
+ - **Shell rules**, matched against the command's text before it runs:
59
59
  - no force-push, pushing to or committing on protected branches, `--no-verify`, destructive deletes, or piping downloads into a shell;
60
60
  - no new dependency without a person's approval, for that package and that lane; the approval also covers the manifest and lockfile changes the install makes;
61
61
  - no forged approvals;
62
+ - no commit that weakens a test (deletes it, skips or focuses it, removes cases or assertions, or rewrites a snapshot) without the person's `tests` approval, which the lead can't delegate;
62
63
  - the project's own blocked commands (deploys, releases) and lane-restricted commands (shared local services).
63
64
  - **Proof before finishing:** before any agent finishes, the plugin runs:
64
65
  - an ownership audit of every uncommitted change;
@@ -71,12 +72,33 @@ code-kit stops each of these at the moment it would happen. The hook refuses the
71
72
  - a `<lane>/…` branch stays in that lane's paths, apart from manifest and lockfile changes logged under a dependency approval;
72
73
  - every protected change is in the approval log, and the log is append-only;
73
74
  - no new layer violations, and the baseline doesn't grow;
74
- - no screens without an approved design, and no secrets anywhere in the branch's history, including ones committed and deleted again;
75
+ - no screens without an approved design;
76
+ - no secret files (`.env`, `secrets/`, keys and keystores) anywhere in the branch's history, including ones committed and deleted again, and, where gitleaks is installed, no secrets in any commit's content;
77
+ - no test weakened (deleted, skipped or focused, cut down, or its snapshot rewritten) without the person's `tests` approval in the log;
78
+ - a fix (a plan story with `**Fixes:**`, or a `<lane>/fix-…` branch) comes with a test that fails without it, as the bug, and passes with it;
75
79
  - the project's checks pass.
76
80
 
77
81
  A project without `.claude/code-kit.json` isn't governed at all. An invalid config fails closed: nothing but the config itself can be written until it's fixed.
78
82
 
79
- The hooks are guard rails, not a sandbox ([SECURITY.md](SECURITY.md)): they refuse the actions they recognise. Two limits are deliberate. The finish check stops blocking once it has reported the same problem three times without progress, and says so, for the lead to take up. A check whose tool isn't installed is skipped unless it sets `ifMissing: "fail"`.
83
+ ## What verify proves, and its limits
84
+
85
+ When `verify` passes on a branch, you can conclude:
86
+
87
+ - every file the branch changed is one its lane may write, or is logged under an approval;
88
+ - every protected change is in the approval log, and the log was only appended to;
89
+ - no import found adds a layer violation, and the baseline didn't grow;
90
+ - no test was weakened without the person's `tests` approval, and, on a fix, its tests fail without the fix;
91
+ - the project's checks for the changed files ran and passed, apart from any `verify` lists as **not run**: a check whose tool isn't installed where it ran is skipped, and named, unless the check sets `ifMissing: "fail"`, which fails it instead. Set that on every check that matters, and install the project's tools in CI.
92
+
93
+ It's a check of the branch as it is when it runs, at the commit it names. A merge code-kit makes records that commit, and any checks not run, in the merge commit's message. From the merge queue, it merges exactly the commit the lead's review passed: a branch that moves on after its review leaves the queue to be reviewed again.
94
+
95
+ Its limits:
96
+
97
+ - **Guard rails, not a sandbox** ([SECURITY.md](SECURITY.md)). The hooks refuse what they recognise. Shell commands are matched by their text, so a command written to hide what it does can get past a shell rule, and a file a shell command writes is caught after the command, not before. Tools other than Edit, Write, NotebookEdit and Bash, such as an MCP server that writes files, aren't seen by the hooks at all; the finish check and `verify` still see what they changed in git.
98
+ - **Layers are pattern-matched.** Imports are found with regular expressions for `import`, `export … from`, `require()` and `import()` with a literal path, in JavaScript and TypeScript files. A computed import isn't seen, and an import written inside a comment or a string can be reported as if it were real. An import resolves to a file through a relative path or `importAliases` only. Anything else, a workspace package's name included, counts as a package, held only by `denyPackages`, so map workspace packages and `tsconfig` paths in `importAliases`.
99
+ - **Secrets.** Without gitleaks, only file names are checked (`.env`, `secrets/`, keys and keystores), not what files contain. The CI workflow init installs doesn't install gitleaks; add it if you rely on the scan.
100
+ - **The finish check stops after three tries.** When it has reported the same problem three times without progress, it lets the agent finish and says so, for the lead to take up.
101
+ - **Review is the lead's judgement.** The workflow's skills have the lead review each branch against its requirements, and the merge queue records the commit it reviewed. What the review looked at isn't recorded. `verify` is the mechanical check, and it runs before every merge code-kit makes.
80
102
 
81
103
  ## When to use it
82
104
 
@@ -96,20 +118,20 @@ Set it up at the start of a new build, straight from the architecture docs, or b
96
118
  ## Where it runs
97
119
 
98
120
  - **In Claude Code**, as a plugin. It's installed once per machine and governs only projects that have `.claude/code-kit.json`.
99
- - **On every tool call** in those projects, through Claude Code hooks:
121
+ - **On every edit, shell command and finish** in those projects, through Claude Code hooks:
100
122
 
101
123
  | Hook | Runs | Enforces |
102
124
  | ------------------------ | --------------------------- | ----------------------------------------------------------------- |
103
125
  | `PreToolUse` Edit/Write | `hooks/guard-paths.mjs` | lanes, protected paths, spec-check and design gates |
104
126
  | `PreToolUse` Bash | `hooks/guard-bash.mjs` | shell rules, dependencies, approval log and secret scan on commit |
105
127
  | `PostToolUse` Edit/Write | `hooks/post-edit-check.mjs` | layer rules and the project's `postEdit` commands |
106
- | `PostToolUse` Bash | `hooks/lane-audit.mjs` | ownership of files written by shell commands |
128
+ | `PostToolUse` Bash | `hooks/lane-audit.mjs` | ownership of files a shell command wrote, reported for revert |
107
129
  | `Stop`, `SubagentStop` | `hooks/stop-check.mjs` | proof before finishing |
108
130
 
109
131
  - **For the main session and every subagent**, including agents in worktrees under `.claude/worktrees/`.
110
132
  - **In front of you, in the terminal and the Desktop app,** through the code-kit mod (Claude Code 2.1.287 or later; see [In the session](#in-the-session)). It shows and acts, and never enforces: the hooks above do that everywhere, the mod or not.
111
133
  - **In CI**, through `code-kit verify` in a GitHub Actions workflow that init can install (`templates/github-workflow.yml`).
112
- - **Locally, with Node 22 or later.** Nothing is sent anywhere. The CLI in `bin/` runs the same rules from a terminal.
134
+ - **Locally, with Node 22 or later.** The CLI in `bin/` runs the same rules from a terminal. The rules themselves send nothing over the network. Three features do, and only when you use them: delegated dependency approvals read the package from the npm registry, the team features (`team`, `intend`) talk to GitHub through your `gh`, or to the team provider you configure, and a bug report you send goes to code-kit's GitHub through your `gh`.
113
135
 
114
136
  ## Install
115
137
 
@@ -228,7 +250,7 @@ code-kit ships no fixed team. Init writes one for each project, from its docs or
228
250
  CLAUDE.md # plus a section telling the lead how the rules work
229
251
  ```
230
252
 
231
- **Who's who.** There are four kinds of actor. The hooks tell the three Claude kinds apart on every tool call; the person works outside them:
253
+ **Who's who.** There are four kinds of actor. The hooks tell the three Claude kinds apart on every call they see; the person works outside them:
232
254
 
233
255
  | Actor | Who it is | May write |
234
256
  | ------------------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------- |
@@ -258,14 +280,15 @@ Editing an agent file can't loosen a rule. And the agent files are kit files (`.
258
280
 
259
281
  **Spawned per story.** Dispatch starts a fresh instance of the lane's agent for each story, in its own worktree on `<lane>/st-<n>`. Agents for different lanes run in parallel. Each starts knowing only its agent file and the story's brief, so nothing leaks between stories.
260
282
 
261
- **How the spec is enforced, step by step:**
283
+ **How the spec is followed, step by step** (the steps a hook or `verify` enforces are marked):
262
284
 
263
285
  1. The brief names the story's requirement IDs.
264
286
  2. The agent runs the spec-check skill and saves a requirement table for its branch.
265
- 3. The path guard blocks any code in its lane until that report exists.
266
- 4. The agent's tests name the requirement IDs.
267
- 5. The stop hook runs the checks before the agent can finish.
268
- 6. Review compares the branch with the requirements and the report, and `verify` checks the rules again in CI.
287
+ 3. **Enforced:** the path guard blocks any code in its lane until that report exists.
288
+ 4. The agent's tests name the requirement IDs; `status` lists the requirements no test names.
289
+ 5. **Enforced:** the stop hook runs the checks before the agent can finish.
290
+ 6. Review compares the branch with the requirements and the report.
291
+ 7. **Enforced:** `verify` checks the rules again before merging and in CI.
269
292
 
270
293
  **The security reviewer** (`.claude/agents/security-reviewer.md`, from `templates/security-reviewer.md`) is a reviewer, not a lane: it owns no paths and checks everyone's work. Init writes it whenever the product handles sign-in, personal data, payments, input from outside or secrets, which is nearly always. It only reads (Read, Grep, Glob, and Bash for `git diff` and the project's audit commands), and the hooks hold it to that like any subagent outside the lanes. spec-design gives each spec a short threat model (what's sensitive, who might attack it, the trust boundaries) and security requirements stories cite. When `code-kit security` says a story's change touches something sensitive, the review runs the agent on the diff against those threat models: it attacks authentication and authorisation, injection (prompt injection too), data exposure, secrets, cryptography, SSRF and redirects, deserialisation, new dependencies and the privacy targets, and grades each finding blocker, concern or nit, with where, the attack and the fix. A blocker sends the branch back like a failing test.
271
294
 
@@ -275,29 +298,70 @@ Editing an agent file can't loosen a rule. And the agent files are kit files (`.
275
298
 
276
299
  ## In the session
277
300
 
278
- With Claude Code 2.1.287 or later, code-kit's mod shows the project in the session, in the terminal (VS Code's terminal included) and the Desktop app. Older versions skip it and keep enforcing everything through the hooks.
301
+ With Claude Code 2.1.287 or later, code-kit's mod shows the project in the session, in the terminal (VS Code's terminal included) and the Desktop app. Older versions skip it and keep enforcing everything through the hooks. The mod shows and acts; it never enforces. Mods don't draw in the VS Code extension's chat panel, the Agent SDK or `claude -p`, and outside a project with `.claude/code-kit.json` the mod draws nothing.
302
+
303
+ ### The band
304
+
305
+ The band sits above the prompt. With nothing happening and nothing waiting, it's gone.
306
+
307
+ - **The mission**, while the build is moving (the lead mid-turn, an agent at work, the loop started):
308
+ - **goal**: the milestone being built and how many of its stories are done;
309
+ - **now**: what the lead is doing and the loop's state, with **Pause** or **Resume**;
310
+ - **next**: the step the loop takes next;
311
+ - **agents**: a line per agent at work, with its current tool and how long since;
312
+ - with Context Graph installed, a line when a lane edited files without understanding them, and only then.
313
+ - **you**: what only you can decide, each with the story it's for ("for ST-4 Booking form (BOOK-1)"). **d** ("Why, and what each choice does") opens it as a card in the Decisions tab. Usage and the plan's pause are labelled **note**.
314
+ - **The team**, with `team` in the config: only what of the team needs you. Your stale claim (Keep or Release), a claim of yours changing the same files as someone else's, an intent touching what you own or lease (every intent, with Agree and Drop, for the tech lead), and a pull request in a lane you own.
315
+
316
+ What waits for you there:
317
+
318
+ - **A held call.** An agent installing a new package, writing or committing a protected file, or a lane changing the kit. Rather than stopping the agent, the call waits while the band asks ("web wants to install dayjs · 1:53"). **Approve** opens the confirmation and, once you confirm, the same call runs; **Refuse**, or no answer within `harness.hold.minutes` (2 unless set), refuses it as before. Under `autonomy: autonomous`, a call within `approvals.delegate` is approved as delegated without asking. Nothing is held under `claude -p` or the SDK, where nobody can answer.
319
+ - **Approvals agents asked for.** **Approve…** opens a confirmation with a reason prefilled from the request, which you keep or rewrite. When it isn't clear what it's for, **Ask about it**: the answer comes from a side call over the lead's conversation and code-kit's facts about the request, shown in the pane and never added to the lead's session, and follow-ups carry on the aside. A request waits until it's answered, its file is committed by someone who could, or it's dropped (at most a week); on its card, **Not needed** drops it.
320
+ - **Questions from the lead** ("The lead asks: which weather provider?"), asked with `code-kit ask`: what it can't settle and only you can. **Answer…** opens it as a card with each of the lead's options and what it does, and **Something else…** for your own words; your answer is recorded and sent to the lead. A question can hold its story, which then reads `waiting on you`: nothing dispatches or reviews it, and the stories that depend on it wait, until you answer.
321
+ - **Your brief's open questions**, each with who decides and what it holds up (from the table's Owner and Blocks columns; one owned by the lead alone isn't yours, and doesn't show). **Answer…** sends your answer to the lead, which records it in the brief's decisions, and **Ask about it** in the answer box explains it first, beside the conversation; **Later** puts one off until the next session.
322
+ - **A call Claude Code's own permission check refused** (its auto mode, a deny rule), which code-kit can't approve past: "Claude Code refused the lead's `pnpm db:generate`". **Put it in the prompt** puts the command in your prompt after `!` for you to run, **Done it** tells the lead you ran or allowed it, and **Not now** tells it to carry on with other work.
323
+ - **A bug report for code-kit**, with `harness.report.on`, drafted by an agent code-kit got in the way of. It holds only code-kit's own facts (its version, the rule, what it said, the command), with the project's folders and email addresses taken out. **Read it** shows the exact text; **Send** files it on code-kit's GitHub with your own `gh` (a comment, if it's filed already; without `gh`, you get the link to file it); **Discard** drops it.
324
+ - **Stories waiting for review**, with the loop off: **Review** asks the lead to run `/code-kit:review` on the branch, and **Merge** runs `verify`, checks included, then merges if it passes. While the loop runs, a lane's finished work is the lead's to review and merge, so it never waits here.
325
+ - **Warnings:** a finish check failing in this session, or a story using more than three times the median of the stories finished this session (once three have finished), each with **Lanes** to open the pane; and background agents paused once the plan's 5-hour use passes `harness.background.pauseAtPercent` (80% unless set).
326
+
327
+ Each button has a digit: type it in an empty prompt to press it. The band keeps one line per kind ("2 approvals waiting"); the Decisions tab says how many of each kind, then lists a short card for each decision, five at a time (**j** and **k** move), with the selected one in full below.
328
+
329
+ ### The lead loop
330
+
331
+ The loop keeps the build moving between your prompts, under `harness.autonomy`. `/code-kit:init` asks you how hands-off you want it. Until you've chosen, its first step waits in the band ("code-kit can keep the build moving between your prompts") with **Keep going**, **Ask each time** and **Off**, and your answer is recorded as your setting.
332
+
333
+ - **Each step.** Once the lead has finished a turn, with the lead idle and nothing typed in the prompt, the loop asks `code-kit next` and prompts the lead to dispatch the ready stories, review a finished one, or build its own. It never prompts the same step twice while nothing has changed, and never a story an agent is still on: one its lane agent is building, or a reviewer is reviewing, waits until that agent finishes ("waiting: ST-10 is still with its agent").
334
+ - **A step that doesn't move.** One the lead was prompted with twice in a row that is still next goes to you instead: "Merge lead/st-1: still next after 2 prompts. Ask the lead again?" with **Go**.
335
+ - **Modes.** **Pause** and **Resume** stop and start it. Under `propose`, each step waits in the band for **Go**; under `off`, the loop does nothing. When every story is done, the band says so and the loop stops.
336
+ - **Stalled lanes.** A lane agent with no tool call for `harness.stall.nudgeMinutes` (5) is messaged, unless its work is done (it handed back, or its branch is in review or the merge queue). At `stall.restartMinutes` (10) the lead is asked to stop it and dispatch its story again, at most `stall.maxRestarts` (2) times, and then the band flags the lane.
337
+ - **The reviewer agent**, with `harness.agents.reviewer.on`. A finished branch is first reviewed in the background by code-kit's reviewer agent, which the lead starts: it runs `verify` and the review checklist, read-only, and grades each finding blocker, concern or nit. The lead's review prompt then carries the findings, and a blocker means the branch is sent back. The pane shows each review, running with its clock or what it found. If the reviewer hasn't reported within 15 minutes, or the plan's 5-hour use is past `harness.background.pauseAtPercent`, the lead reviews without it.
338
+ - **The merge queue** (`code-kit queue`). A branch the lead's review passes joins the queue. Branches merge one at a time, in the order they passed, each verified against the base as it is then: the lead merges where `approvals.delegate.merge` is on under `autonomous`, otherwise the band shows the head with **Merge** for you. Who may merge is read from the config committed on the base, so a branch can't grant itself merges. The queue records the commit each review passed, and merges exactly that commit: a branch that moves on after its review leaves the queue (`moved`) for the lead to review it again. A head that conflicts or fails verify goes back to its lane. A merged lane's worktree is removed when it holds nothing uncommitted. The pane lists the queue, and lanes whose branch waits in it read `queued`.
339
+ - **The first merge.** There's none for you: setting up commits the rules you approved straight onto the base, and in a project set up before that, the lead puts them there itself (`code-kit queue rules`) before its first merge.
340
+
341
+ ### The Lanes pane
342
+
343
+ **`/lanes`** opens it; `/lanes` again, or Escape, closes it. It stays current within 2 seconds of a commit, a branch change, a plan edit or an agent starting or stopping. Inline (when the terminal can't dock it beside the transcript), it shows the counts, what needs you and a line per lane.
279
344
 
280
- - **The band** sits above the prompt. While the build is moving (the lead mid-turn, an agent at work, the loop started) it opens with the mission: **goal**, the milestone being built and how many of its stories are done; **now**, what the lead is doing and the loop's state, with **Pause** or **Resume**; **next**, the step the loop takes next; and **agents**, a line per agent at work with its current tool and how long since. With Context Graph installed, a line says when a lane edited files without understanding them, and only then. Beneath, labelled **you**, what only you can decide, each with the story it's for ("for ST-4 Booking form (BOOK-1)"), and **d** ("Why, and what each choice does") opens it as a card in the Decisions tab; usage and the plan's pause are labelled **note**. In a team (`team` in the config), it also names what of the team needs you, and only that: your stale claim (Keep or Release), a claim of yours changing the same files as someone else's, an intent touching what you own or lease (every intent, with Agree and Drop, for the tech lead), and a pull request in a lane you own. While the loop runs, a lane's finished work is the lead's to review and merge, so it never waits here; with the loop off, Review and Merge are offered to you. With nothing happening and nothing waiting, the band is gone. It shows:
281
- - an agent's call held for you: installing a new package, writing or committing a protected file, or a lane changing the kit. Rather than stopping the agent, the call waits while the band asks ("web wants to install dayjs · 1:53"). **Approve** opens the confirmation and, once you confirm, the same call runs; **Refuse**, or no answer within `harness.hold.minutes` (2 unless set), refuses it as before. Under `autonomy: autonomous`, a call within `approvals.delegate` is approved as delegated without asking. Nothing is held under `claude -p` or the SDK, where nobody can answer;
282
- - the lead loop, under `harness.autonomy`. `/code-kit:init` asks you how hands-off you want it. Until you've chosen, the loop's first step waits in the band ("code-kit can keep the build moving between your prompts") with **Keep going**, **Ask each time** and **Off**, and your answer is recorded as your setting. Once the lead has finished a turn, the loop keeps the build moving: with the lead idle and nothing typed in the prompt, it asks `code-kit next` and prompts the lead to dispatch the ready stories, review a finished one, or build its own, never the same step twice while nothing has changed, and never a story an agent is still on: one its lane agent is building, or a reviewer is reviewing, waits until that agent finishes ("waiting: ST-10 is still with its agent"). A step the lead was prompted with twice in a row and that is still next goes to you instead, in the band: "Merge lead/st-1: still next after 2 prompts. Ask the lead again?" with **Go**. **Pause** and **Resume** stop and start it. Under `propose`, each step waits in the band for **Go**; under `off`, the loop does nothing. A lane agent with no tool call for `harness.stall.nudgeMinutes` (5) is messaged, unless its work is done (it handed back, or its branch is in review or the merge queue); at `stall.restartMinutes` (10) the lead is asked to stop it and dispatch its story again, at most `stall.maxRestarts` (2) times, and then the band flags the lane. When every story is done, the band says so and the loop stops. With `harness.agents.reviewer.on`, a finished branch is first reviewed in the background by code-kit's reviewer agent, which the lead starts: it runs `verify` and the review checklist, read-only, and grades each finding blocker, concern or nit. The lead's review prompt then carries the findings, and a blocker means the branch is sent back. The pane shows each review, running with its clock or what it found. If the reviewer hasn't reported within 15 minutes, or the plan's 5-hour use is past `harness.background.pauseAtPercent`, the lead reviews without it. A branch the lead's review passes joins the merge queue (`code-kit queue`). Branches merge one at a time, in the order they passed, each verified against the base as it is then: the lead merges where `approvals.delegate.merge` is on under `autonomous`, otherwise the band shows the head with **Merge** for you. Who may merge is read from the config committed on the base, so a branch can't grant itself merges. There's no first merge for you: setting up commits the rules you approved straight onto the base, and in a project set up before that, the lead puts them there itself (`code-kit queue rules`) before its first merge. A merged lane's worktree is removed when it holds nothing uncommitted. A head that conflicts or fails verify goes back to its lane. The pane lists the queue, and lanes whose branch waits in it read `queued`;
283
- - approvals agents have asked for: **Approve…** opens a confirmation with a reason prefilled from the request, which you keep or rewrite. When it isn't clear what it's for, **Ask about it** in that pane: the answer comes from a side call over the lead's conversation and code-kit's facts about the request, shown in the pane and never added to the lead's session; follow-ups carry on the aside. A request waits until it's answered, its file is committed by someone who could, or it's dropped (at most a week); on its card, **Not needed** drops it;
284
- - questions from the lead ("The lead asks: which weather provider?"): what it can't settle and only you can, asked with `code-kit ask`. **Answer…** opens it as a card with each of the lead's options and what it does, and **Something else…** for your own words; your answer is recorded and sent to the lead. A question can hold its story, which then reads `waiting on you`: nothing dispatches or reviews it, and the stories that depend on it wait, until you answer;
285
- - your brief's open questions: **Answer…** sends your answer to the lead, which records it in the brief's decisions; **Later** puts one off until the next session;
286
- - a call Claude Code's own permission check refused (its auto mode, a deny rule), which code-kit can't approve past: "Claude Code refused the lead's `pnpm db:generate`". **Put it in the prompt** puts a command in your prompt after `!` for you to run, **Done it** tells the lead you ran or allowed it, and **Not now** tells it to carry on with other work;
287
- - with `harness.report.on`, a bug report for code-kit an agent drafted when code-kit got in its way: only code-kit's own facts (its version, the rule, what it said, the command), with the project's folders and email addresses taken out. **Read it** shows the exact text; **Send** files it on code-kit's GitHub with your own `gh` (a comment, if it's filed already; without `gh`, you get the link to file it), and **Discard** drops it;
288
- - stories finished and waiting for review: **Review** asks the lead to run `/code-kit:review` on the branch, and **Merge** runs `verify`, checks included, then merges if it passes;
289
- - a finish check failing in this session: **Lanes** opens the pane;
290
- - a story using more than three times the median of the stories finished this session (once three have finished): **Lanes** opens the pane;
291
- - background agents paused, once the plan’s 5-hour use passes `harness.background.pauseAtPercent` (80% unless set).
345
+ - **The top.** A count of the stories by state (building, in review, queued, sent back, blocked, ready, merged), with the loop's state and the plan's 5-hour use; press a count to show only those lanes. Beneath it, whatever needs you (held calls, approvals, reviews, merges, stalled lanes, outliers) is pinned with its key.
346
+ - **Tabs, on 1 to 7:**
347
+ - **Lanes**: the loop as a card (its mode, the steps it took, the one running and the next), then each lane on fixed columns: its name, state and story, its agent's current or last tool call with the time since beneath (amber once quiet, red when stalled), and its tokens; the lead reads orchestrating while its turn runs. Each lane has its own small pixel character, tinted in the lane's colour, whose pose shows its state: working (animated while its agent works), waiting on you, quiet, stalled, done or resting; the lead's wears a crown. Under each lane, its story's timeline on a shared time axis: building, then in review, with send-backs (↩), approvals (◆) and the merge (✓) marked where they fell. A selected lane shows its stories as cards (state, requirements, what each waits on or its branch), then its agent and the paths it owns.
348
+ - **Decisions**: each decision that needs you as a card: what you asked for, the story and its requirements, what was happening, what's already settled, why the lead couldn't settle it, and each option with what it does.
349
+ - **Journal**: the build from your request to now in plain sentences, by day: the request and the decisions in the brief, the specification, each story handed out, sent back and merged, each approval and who gave it, each milestone finished, and the loop's steps this session, yours in yellow.
350
+ - **Code map**: the whole project's folders by layer when no story is at work, or a story's files in a column per layer with the imports between them. A file fills with a lane's colour while that lane reads or edits it, and says whether its why (its Context Graph card) is written, out of date or not written yet. **j**/**k** select a file to see its card and what it imports and what imports it, and **o** opens it in Context Graph (box-drawing text in the terminal, an SVG on Desktop).
351
+ - **Trail**: every requirement in the specs as a cell by spec, its glyph and colour saying whether it's done and tested, done but untested, in progress, todo, without a story or removed, with a legend counting each. **h**/**l** and **j**/**k** move between cells and specs (or pick one from the list), showing the requirement's stories, their branches, the code they changed and the tests that name it. Beneath the cells, the spec's trail drawn as a flow, each requirement to its stories, code and tests, with a missing link dashed in red.
352
+ - **Queue**: the merge queue.
353
+ - **Usage**.
354
+ - **Keys.** **j** and **k** move between lanes, and the selected lane's acts are on **a** (approve), **r** (review), **s** (send back, with your reason), **m** (merge), **n** (nudge its agent) and **x** (stop it); **p** pauses or resumes the loop, and **f** filters the lanes by name, agent or story.
355
+ - **A story.** **Enter** (or **o**) opens the selected lane's story: its requirements beside its spec-check report, the reviewer's findings by severity (each a way into the diff), `verify`'s problems, its usage and loop steps, and its diff against the base, file by file, with the acts its state allows. **b** or Escape goes back to the lanes.
292
356
 
293
- Each button has a digit: type it in an empty prompt to press it. The band keeps one line per kind ("2 approvals waiting"); the Decisions tab says how many of each kind, then lists a short card for each decision, five at a time (**j** and **k** move), with the selected one in full below.
357
+ ### Other views
294
358
 
295
- - **`/lanes`** opens the Lanes pane. Its first line counts the stories by state (building, in review, queued, sent back, blocked, ready, merged), with the loop's state and the plan's 5-hour use; press a count to show only those lanes. Beneath it, whatever needs you (held calls, approvals, reviews, merges, stalled lanes, outliers) is pinned with its key. Tabs on **1** to **7**: **Lanes** opens on the loop as a card: its mode, the steps it took, the one running and the next. Then each lane on fixed columns: its name, state and story, its agent's current or last tool call with the time since beneath (amber once quiet, red when stalled), and its tokens; the lead reads orchestrating while its turn runs. A selected lane shows its stories as cards (state, requirements, what each waits on or its branch), then its agent and the paths it owns. **Decisions**, each decision that needs you as a card: what you asked for, the story and its requirements, what was happening, what's already settled, why the lead couldn't settle it, and each option with what it does; **Journal**, the build from your request to now in plain sentences, by day: the request and the decisions in the brief, the specification, each story handed out, sent back and merged, each approval and who gave it, each milestone finished, and the loop's steps this session, yours in yellow. Each lane has its own small pixel character, tinted in the lane's colour, whose pose shows its state: working (animated while its agent works), waiting on you, quiet, stalled, done or resting; the lead's wears a crown. Under each lane, its story's timeline on a shared time axis: building, then in review, with send-backs (↩), approvals (◆) and the merge (✓) marked where they fell; **Code map**, the whole project's folders by layer when no story is at work, or a story's files in a column per layer with the imports between them: a file fills with a lane's colour while that lane reads or edits it, and says whether its why (its Context Graph card) is written, out of date or not written yet; **j**/**k** select a file to see its card and what it imports and what imports it, and **o** opens it in Context Graph (box-drawing text in the terminal, an SVG on Desktop); **Trail**, every requirement in the specs as a cell by spec, its glyph and colour saying whether it's done and tested, done but untested, in progress, todo, without a story or removed, with a legend counting each. **h**/**l** and **j**/**k** move between cells and specs (or pick one from the list), showing the requirement's stories, their branches, the code they changed and the tests that name it; beneath the cells, the spec's trail drawn as a flow, each requirement to its stories, code and tests, with a missing link dashed in red; **Queue**, the merge queue; and **Usage**. **j** and **k** move between lanes, and the selected lane's acts are on **a** (approve), **r** (review), **s** (send back, with your reason), **m** (merge), **n** (nudge its agent) and **x** (stop it); **p** pauses or resumes the loop, and **f** filters the lanes by name, agent or story. **Enter** (or **o**) opens the selected lane's story: its requirements beside its spec-check report, the reviewer's findings by severity (each a way into the diff), `verify`'s problems, its usage and loop steps, and its diff against the base, file by file, with the acts its state allows. **b** or Escape goes back to the lanes. Inline (when the terminal can't dock it beside the transcript), it shows the counts, what needs you and a line per lane. It stays current within 2 seconds of a commit, a branch change, a plan edit or an agent starting or stopping. `/lanes` again, or Escape, closes it.
296
359
  - **Refusals** a code-kit hook gives an agent are drawn as cards: what was refused, the rule, what to do, and Approve… where your approval would allow it. The full text is a press away.
297
360
  - **`/harness`** opens the harness settings: how the lead loop acts, how long a call waiting on your approval is held, when a stalled lane is nudged and restarted, the reviewer agent and its model, the use at which background agents pause, and whether agents draft bug reports for code-kit. Changing one asks your reason, writes `.claude/code-kit.json` and logs a `kit` approval. Lanes, paths and rules still change through `/code-kit:init`.
298
- - **`/approvals`** lists the approvals waiting (one per approval and lane, with every file it covers), the approvals in force with minutes left, and every approval given, newest first: who gave it (you, or the lead within your delegated rules), its reason, and the files and branches it covered, merged or not. A request stops waiting once an approval is given for it, or its file is committed by someone who could; a read-only agent such as the reviewer never asks. **`/verify-branch`** runs `code-kit verify` on this branch. Neither calls the model.
361
+ - **`/approvals`** lists the approvals waiting (one per approval and lane, with every file it covers), the approvals in force with minutes left, and every approval given, newest first: who gave it (you, or the lead within your delegated rules), its reason, and the files and branches it covered, merged or not. A request stops waiting once an approval is given for it, or its file is committed by someone who could; a read-only agent such as the reviewer never asks.
362
+ - **`/verify-branch`** runs `code-kit verify` on this branch. Neither it nor `/approvals` calls the model.
299
363
 
300
- Approving from the band records `(approved in the code-kit pane)` with your reason, and a merge from it says it was merged by the person from the pane. A settings change is logged as made in the pane. These happen only on your press: the hooks refuse `approve --via pane`, `merge --person` and `settings set` from every agent. Outside a project with `.claude/code-kit.json`, the mod draws nothing. Mods don't draw in the VS Code extension's chat panel, the Agent SDK or `claude -p`.
364
+ Approving from the band records `(approved in the code-kit pane)` with your reason, and a merge from it says it was merged by the person from the pane. A settings change is logged as made in the pane. These happen only on your press: the hooks refuse `approve --via pane`, `merge --person` and `settings set` from every agent.
301
365
 
302
366
  ## Build
303
367
 
@@ -328,7 +392,7 @@ It's a preview: it's tested end to end against a stand-in for GitHub, and has be
328
392
 
329
393
  ## Enforce it in CI
330
394
 
331
- The hooks only see Claude Code sessions. For everything else, init offers `.github/workflows/code-kit.yml` (from `templates/github-workflow.yml`). It runs `verify` on every pull request, through `npx @warren-dean/code-kit@<version>`, pinned so CI doesn't change under you. It needs no secret. The one setting to make is marking the `code-kit` check as required on the protected branches.
395
+ The hooks only see Claude Code sessions. For everything else, init offers `.github/workflows/code-kit.yml` (from `templates/github-workflow.yml`). It runs `verify` on every pull request, through `npx @warren-dean/code-kit@<version>`, pinned so CI doesn't change under you. It needs no secret. Two settings to make: mark the `code-kit` check as required on the protected branches, and make sure the workflow installs what the project's checks run, since a check whose tool is missing is skipped, and listed as not run, unless it sets `ifMissing: "fail"`. Add gitleaks to the workflow for the secret scan of commits' content.
332
396
 
333
397
  `verify` can't see spec-check reports, because `.claude/state/` isn't committed. Review covers those.
334
398
 
@@ -373,9 +437,9 @@ code-kit sent-back <branch> [--reason "…"] # record a revie
373
437
  code-kit settings [--json] # the harness settings in force, with their defaults
374
438
  code-kit settings set <key> <value> --reason "…" # change one, as the person: written to the config and logged as a kit approval
375
439
  code-kit queue [--json] # the merge queue: branches whose review passed, in order
376
- code-kit queue add|drop <branch> # the lead queues a branch its review passed, or takes it out
440
+ code-kit queue add|drop <branch> # the lead queues a branch at the commit its review passed, or takes it out
377
441
  code-kit queue rules # the lead puts the approved rules onto a base that has none yet (a project set up before 0.8.0)
378
- code-kit queue merge --delegated|--person # merge the head, verified against the base as it is now; a conflict or failed verify sends it back to its lane
442
+ code-kit queue merge --delegated|--person # merge the head at the commit its review passed, verified against the base as it is now; a conflict or failed verify sends it back to its lane, and a branch that moved since its review leaves the queue to be reviewed again
379
443
  code-kit loop [--json] # whether the person paused the lead loop; other tools' background work pauses with it
380
444
  code-kit loop pause|resume # the person's act, as Pause and Resume in the band
381
445
  code-kit story <id> [--json] # one story's requirements, spec-check report, diff against the base and verify (without checks), for the drill-down
@@ -421,7 +485,9 @@ code-kit approve <name>... --reason "…" [--lane name] [--delegated | --via pan
421
485
  | `shell.block[]` | no | `{ pattern, why, person?, command? }`: never run. `person: true` marks a person's act, which the lead may do for them with `approvals.lead` on. `command: true` matches the pattern from the start of each command the line runs, so a heredoc or quoted text that mentions it isn't refused |
422
486
  | `shell.restricted[]` | no | `{ pattern, lanes, why }`: only the lead and these lanes |
423
487
  | `postEdit[]` | no | `{ files, exclude?, run }`: after each edit of a matching file. `{file}` is the file. Exit 127 (tool not installed) is skipped. |
424
- | `checks[]` | no | `{ name, files, exclude?, run[], each?, owners?, ifMissing?, timeoutSeconds? }`: before finishing, when matching files changed. `each` runs the commands in every changed folder matching that glob. `owners` limits who may change the files (the lead always may). `ifMissing: "fail"` makes a missing tool an error (the default is to skip). |
488
+ | `tests[]` | no | Globs naming the test files, for the weakened-test and fix rules. Default: the usual conventions (`*.test.*`, `*.spec.*`, `__tests__/`, `test/`, `tests/`, `e2e/`, `*_test.go`, `test_*.py`). |
489
+ | `regression.prepare` | no | A command run in a fresh checkout before a fix's tests run there without the fix, such as `npm ci`. Without it, the checkout's `node_modules` and virtualenvs are linked in. |
490
+ | `checks[]` | no | `{ name, files, exclude?, run[], each?, owners?, ifMissing?, timeoutSeconds? }`: before finishing, when matching files changed. `each` runs the commands in every changed folder matching that glob. `owners` limits who may change the files (the lead always may). `ifMissing: "fail"` makes a missing tool an error (the default is to skip the check, which `verify` and a merge list as not run). |
425
491
  | `adapters` | no | `{ "<adapter>": false }` switches off an adapter that would otherwise be detected; `true` says the project wants that tool, so until it's set up here `next` gives its setup before any code. See [Adapters](#adapters). |
426
492
  | `approvals.lead` | no | `true` lets the lead act on what the person says in chat, for when `!` isn't available (on a phone, say): it records their approvals with `code-kit approve`, and runs `shell.block` commands marked `person`. Default `false`. See [Approvals](#approvals). |
427
493
  | `approvals.delegate` | no | `{ protected?: [approval names], merge?: true, dependencies?: { licences?, minWeeklyDownloads?, maxMonthsSinceRelease?, allowInstallScripts?: true \| false \| [kinds] } }`: approvals the lead may grant on its own, with `code-kit approve --delegated`, and with `merge`, merges into a protected branch with `code-kit merge --delegated`. Dependencies are checked against the npm registry; the defaults are MIT, Apache-2.0, BSD and ISC, 10,000 weekly downloads, a release within 18 months, and no install scripts. See [Approvals](#approvals). |
@@ -445,7 +511,9 @@ echo "Date formatting for ST-12" > .claude/approvals/web/dep-dayjs #
445
511
  - **Scope:** an approval in a lane's folder serves that lane only; one directly in `.claude/approvals/` serves every agent. The refusal a lane gets names its own folder.
446
512
  - **Dependencies:** each new package needs its own approval, `dep-<package>` (`/` becomes `+`, so `@scope/pkg` is `dep-@scope+pkg`). It allows the install, and the changes the install makes to manifests and lockfiles that no other lane owns. When the lane commits a manifest or lockfile outside its own paths, the commit hook logs it as a `dependency` approval, with the packages and reasons, and `code-kit verify` accepts it.
447
513
  - **Worktrees:** approvals live in the main checkout, so a lane working in its own worktree sees the ones given at the lead's terminal.
448
- - **Lifetime:** 60 minutes; a dependency approval (`dep-…`) lasts until the lane commits the install it allows, at most 7 days, since a story may resume hours later. Agents can't create, edit or even mention approvals or the log.
514
+ - **Tests:** a commit that weakens a test needs `tests`: `echo "The keeps-order test is wrong until ST-9" > .claude/approvals/web/tests`. It's the person's only, never delegated, and used up by the commit, which logs it with what was weakened.
515
+ - **Lifetime:** 60 minutes; a dependency approval (`dep-…`) lasts until the lane commits the install it allows, at most 7 days, since a story may resume hours later.
516
+ - **Agents can't write them.** An edit to an approval or the log is refused, and so is any agent shell command that names them. Like every shell rule, that's a match on the command's text.
449
517
 
450
518
  ### From chat
451
519
 
package/SECURITY.md CHANGED
@@ -1,7 +1,16 @@
1
1
  # Security
2
2
 
3
- code-kit runs as Claude Code hooks: it reads your repository and its git history, and runs the commands your `.claude/code-kit.json` lists as checks. It sends nothing over the network.
3
+ code-kit runs as Claude Code hooks and a command line: it reads your repository and its git history, and runs the commands your `.claude/code-kit.json` lists as checks.
4
+
5
+ The rules themselves send nothing over the network. Three features do, and only when you use them:
6
+
7
+ - **Delegated dependency approvals** (`approvals.delegate.dependencies`): `code-kit approve --delegated` reads each package's metadata and last week's downloads from the npm registry.
8
+ - **Teams** (`team` in the config): claims, intents, codeowners and the board go to GitHub through your own `gh`, or to the team provider you configure.
9
+ - **Bug reports for code-kit** (`harness.report.on`): a report you choose to send is filed on code-kit's GitHub repository through your own `gh`. Its text is shown to you first, with your project's folders, home folder and email addresses taken out.
4
10
 
5
11
  To report a vulnerability, use GitHub's private vulnerability reporting on this repository (Security → Report a vulnerability) rather than a public issue. You'll get a reply within a week.
6
12
 
7
- The hooks are a guard rail for agents, not a sandbox. They stop the actions they recognise; they are not a boundary against a person, or a process deliberately working around them.
13
+ The hooks are a guard rail for agents, not a sandbox. They stop the actions they recognise; they are not a boundary against a person, or a process deliberately working around them. In particular:
14
+
15
+ - shell commands are judged by their text before they run, and by the files they changed after, so a command written to hide what it does can get past a shell rule, and a file it writes is caught after the command, not before;
16
+ - only Edit, Write, NotebookEdit and Bash calls are seen as they happen; other tools, such as an MCP server that writes files, are seen only through what they change in git, by the finish check and `verify`.