@warren-dean/code-kit 0.3.4
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.
- package/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +23 -0
- package/LICENSE +21 -0
- package/README.md +369 -0
- package/SECURITY.md +7 -0
- package/bin/code-kit.mjs +398 -0
- package/hooks/guard-bash.mjs +223 -0
- package/hooks/guard-paths.mjs +70 -0
- package/hooks/hooks.json +71 -0
- package/hooks/lane-audit.mjs +58 -0
- package/hooks/lib/adapters/context-graph.mjs +34 -0
- package/hooks/lib/adapters/index.mjs +34 -0
- package/hooks/lib/baseline.mjs +23 -0
- package/hooks/lib/checks.mjs +67 -0
- package/hooks/lib/config.mjs +211 -0
- package/hooks/lib/dependencies.mjs +129 -0
- package/hooks/lib/diff.mjs +122 -0
- package/hooks/lib/glob.mjs +42 -0
- package/hooks/lib/hook.mjs +19 -0
- package/hooks/lib/layers.mjs +57 -0
- package/hooks/lib/next.mjs +197 -0
- package/hooks/lib/plan.mjs +206 -0
- package/hooks/lib/rules.mjs +313 -0
- package/hooks/lib/trace.mjs +69 -0
- package/hooks/lib/verify.mjs +146 -0
- package/hooks/post-edit-check.mjs +40 -0
- package/hooks/stop-check.mjs +84 -0
- package/package.json +41 -0
- package/skills/check/SKILL.md +19 -0
- package/skills/dispatch/SKILL.md +83 -0
- package/skills/init/SKILL.md +151 -0
- package/skills/next/SKILL.md +52 -0
- package/skills/review/SKILL.md +57 -0
- package/skills/spec-check/SKILL.md +27 -0
- package/skills/spec-design/SKILL.md +137 -0
- package/skills/status/SKILL.md +42 -0
- package/templates/agent.md +29 -0
- package/templates/brief.md +45 -0
- package/templates/claude-md.md +23 -0
- package/templates/github-workflow.yml +23 -0
- package/templates/plan.md +30 -0
- package/templates/spec.md +52 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-kit",
|
|
3
|
+
"description": "code-kit: keeps AI coding agents inside each project's rules, enforced by Claude Code hooks and in CI, from idea to merged code",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "Warren Langeveldt"
|
|
6
|
+
},
|
|
7
|
+
"plugins": [
|
|
8
|
+
{
|
|
9
|
+
"name": "code-kit",
|
|
10
|
+
"source": "./",
|
|
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.3.4",
|
|
13
|
+
"category": "development",
|
|
14
|
+
"tags": ["guardrails", "architecture", "lanes", "layers", "spec-driven", "ci", "multi-agent"],
|
|
15
|
+
"license": "MIT"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-kit",
|
|
3
|
+
"version": "0.3.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
|
+
"author": {
|
|
6
|
+
"name": "Warren Langeveldt"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"repository": "https://github.com/warrendeanlangeveldt/code-kit",
|
|
10
|
+
"homepage": "https://github.com/warrendeanlangeveldt/code-kit#readme",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"claude-code",
|
|
13
|
+
"guardrails",
|
|
14
|
+
"architecture",
|
|
15
|
+
"lanes",
|
|
16
|
+
"layers",
|
|
17
|
+
"spec-driven-development",
|
|
18
|
+
"ci",
|
|
19
|
+
"multi-agent",
|
|
20
|
+
"hooks",
|
|
21
|
+
"skills"
|
|
22
|
+
]
|
|
23
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Warren Langeveldt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# code-kit
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
You need Claude Code, Node 22 or later, and git. Then, in Claude Code:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
/plugin marketplace add warrendeanlangeveldt/code-kit
|
|
13
|
+
/plugin install code-kit@code-kit
|
|
14
|
+
/code-kit:next
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`/code-kit:next` works out where your project stands and takes you through the next step. A blank folder starts with speccing an idea; an existing codebase starts with drafting its rules. Nothing is enforced until you approve the rules it drafts. In a project without `.claude/code-kit.json`, the plugin does nothing.
|
|
18
|
+
|
|
19
|
+
## Why
|
|
20
|
+
|
|
21
|
+
Rules in `CLAUDE.md` and agent prompts are advice. Over a long session, or across a dozen parallel subagents, advice drifts:
|
|
22
|
+
|
|
23
|
+
- a backend agent "quickly fixes" a frontend file, and two agents overwrite each other's work;
|
|
24
|
+
- a domain module starts importing the database client, and the layering the architecture doc describes stops being true;
|
|
25
|
+
- a contract or schema changes with no record of who changed it or why;
|
|
26
|
+
- code gets written before anyone checked it against the spec, or a screen before it was designed;
|
|
27
|
+
- an agent declares "done" with failing type checks, or with work nobody committed;
|
|
28
|
+
- someone force-pushes, commits to `main`, adds a dependency, or runs a deploy nobody asked for.
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
## What it enforces
|
|
33
|
+
|
|
34
|
+
- **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.
|
|
35
|
+
- **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.
|
|
36
|
+
- **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.
|
|
37
|
+
- **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.
|
|
38
|
+
- **Designs before screens** (optional): a screen file can't be written until the design register lists it.
|
|
39
|
+
- **Shell rules:**
|
|
40
|
+
- no force-push, pushing to or committing on protected branches, `--no-verify`, destructive deletes, or piping downloads into a shell;
|
|
41
|
+
- 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;
|
|
42
|
+
- no forged approvals;
|
|
43
|
+
- the project's own blocked commands (deploys, releases) and lane-restricted commands (shared local services).
|
|
44
|
+
- **Proof before finishing:** before any agent finishes, the plugin runs:
|
|
45
|
+
- an ownership audit of every uncommitted change;
|
|
46
|
+
- the layer rules;
|
|
47
|
+
- the project's checks, for the files that changed.
|
|
48
|
+
|
|
49
|
+
A lane also has to commit its work first.
|
|
50
|
+
|
|
51
|
+
- **The same rules in CI:** `code-kit verify` checks a pull request as a whole, including commits made outside Claude Code:
|
|
52
|
+
- a `<lane>/…` branch stays in that lane's paths, apart from manifest and lockfile changes logged under a dependency approval;
|
|
53
|
+
- every protected change is in the approval log, and the log is append-only;
|
|
54
|
+
- no new layer violations, and the baseline doesn't grow;
|
|
55
|
+
- no screens without an approved design, and no committed secrets;
|
|
56
|
+
- the project's checks pass.
|
|
57
|
+
|
|
58
|
+
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.
|
|
59
|
+
|
|
60
|
+
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"`.
|
|
61
|
+
|
|
62
|
+
## When to use it
|
|
63
|
+
|
|
64
|
+
Use it when:
|
|
65
|
+
|
|
66
|
+
- **Several agents work on one codebase at once**, such as a lead delegating to frontend, backend and data lanes, possibly in separate worktrees. Lanes are what keep them out of each other's files.
|
|
67
|
+
- **The architecture has layers worth protecting**, like domain, services, adapters and UI, or a shared package that mustn't reach into apps.
|
|
68
|
+
- **Some files need an audit trail:** API contracts, schemas, registers, the kit's own config.
|
|
69
|
+
- **The project has specs or designs** that code should follow rather than improvise.
|
|
70
|
+
- **"Done" has to mean done:** checks passing and work committed, not an agent's say-so.
|
|
71
|
+
- **You're starting from an idea**, and want the specification worked out before anyone writes code.
|
|
72
|
+
|
|
73
|
+
It's overkill for a throwaway script, a spike, or a single-file change. In those, just don't add `.claude/code-kit.json`: the plugin stays installed and does nothing.
|
|
74
|
+
|
|
75
|
+
Set it up at the start of a new build, straight from the architecture docs, or bring it into an existing codebase at any point (init works the rules out from the code). Re-run init whenever the shape of the project changes: new apps or packages, moved folders, a changed plan.
|
|
76
|
+
|
|
77
|
+
## Where it runs
|
|
78
|
+
|
|
79
|
+
- **In Claude Code**, as a plugin. It's installed once per machine and governs only projects that have `.claude/code-kit.json`.
|
|
80
|
+
- **On every tool call** in those projects, through Claude Code hooks:
|
|
81
|
+
|
|
82
|
+
| Hook | Runs | Enforces |
|
|
83
|
+
| ------------------------ | --------------------------- | ----------------------------------------------------------------- |
|
|
84
|
+
| `PreToolUse` Edit/Write | `hooks/guard-paths.mjs` | lanes, protected paths, spec-check and design gates |
|
|
85
|
+
| `PreToolUse` Bash | `hooks/guard-bash.mjs` | shell rules, dependencies, approval log and secret scan on commit |
|
|
86
|
+
| `PostToolUse` Edit/Write | `hooks/post-edit-check.mjs` | layer rules and the project's `postEdit` commands |
|
|
87
|
+
| `PostToolUse` Bash | `hooks/lane-audit.mjs` | ownership of files written by shell commands |
|
|
88
|
+
| `Stop`, `SubagentStop` | `hooks/stop-check.mjs` | proof before finishing |
|
|
89
|
+
|
|
90
|
+
- **For the main session and every subagent**, including agents in worktrees under `.claude/worktrees/`.
|
|
91
|
+
- **In CI**, through `code-kit verify` in a GitHub Actions workflow that init can install (`templates/github-workflow.yml`).
|
|
92
|
+
- **Locally, with Node 22 or later.** Nothing is sent anywhere. The CLI in `bin/` runs the same rules from a terminal.
|
|
93
|
+
|
|
94
|
+
## Install
|
|
95
|
+
|
|
96
|
+
**Requirements:** Claude Code, Node 22 or later, and git. [gitleaks](https://github.com/gitleaks/gitleaks) is optional: when it's installed, every commit gets a secret scan.
|
|
97
|
+
|
|
98
|
+
**The plugin**, from this repository's marketplace:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
/plugin marketplace add warrendeanlangeveldt/code-kit
|
|
102
|
+
/plugin install code-kit@code-kit
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
To update later, run `/plugin marketplace update code-kit` and restart Claude Code; sessions started before an update keep the old hooks. To pin it for a whole team, add it to the project's `.claude/settings.json`:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"extraKnownMarketplaces": {
|
|
110
|
+
"code-kit": { "source": { "source": "github", "repo": "warrendeanlangeveldt/code-kit" } }
|
|
111
|
+
},
|
|
112
|
+
"enabledPlugins": { "code-kit@code-kit": true }
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**The command line** is optional: the skills run it for you in a session. Use it for CI, or from a terminal:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
npx @warren-dean/code-kit check # no install
|
|
120
|
+
npm i -g @warren-dean/code-kit # or install it, then: code-kit check
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**From a clone**, for working on code-kit itself: `/plugin marketplace add <path to the clone>`.
|
|
124
|
+
|
|
125
|
+
## One command: `/code-kit:next`
|
|
126
|
+
|
|
127
|
+
Don't want to remember which skill comes when? Run `/code-kit:next`, from a blank folder or at any point in a build:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
/code-kit:next a booking app for mobile dog groomers
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
It reads where the project stands and runs the right skill. It carries on to the following step until something needs you: questions to answer, a draft to approve, a pull request to merge, or lanes still building.
|
|
134
|
+
|
|
135
|
+
| The project has | `next` runs |
|
|
136
|
+
| ---------------------------------------------- | ------------------------------------------------ |
|
|
137
|
+
| Nothing | spec-design |
|
|
138
|
+
| A spec still being shaped | spec-design, picking up where it stopped |
|
|
139
|
+
| A ready spec, existing code, or a draft config | init |
|
|
140
|
+
| Stories finished on their branches | review, then dispatch |
|
|
141
|
+
| Stories ready | dispatch |
|
|
142
|
+
| Stories being built | nothing: it tells you what's running |
|
|
143
|
+
| Everything done | a status summary, then offers the next milestone |
|
|
144
|
+
|
|
145
|
+
`code-kit next` on the command line shows the same decision without running anything.
|
|
146
|
+
|
|
147
|
+
## Start from an idea
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
/code-kit:spec-design a booking app for mobile dog groomers
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
spec-design works an idea into a specification with you before any code exists. It asks the questions that decide the build, a few at a time with a recommended answer, and writes every decision down:
|
|
154
|
+
|
|
155
|
+
1. **Frame:** the problem, the users, the outcome, the constraints and the non-goals.
|
|
156
|
+
2. **Explore:** two or three different shapes of solution, the main user journeys, and the riskiest assumptions. You choose.
|
|
157
|
+
3. **Scope:** capability areas, and what the first release has to deliver end to end.
|
|
158
|
+
4. **Specify:** one spec per area, with numbered, testable requirements covering data, states, rules, permissions, errors and acceptance criteria.
|
|
159
|
+
5. **Architecture, principles and plan:** the layers, contracts, definition of done, and stories split into lanes.
|
|
160
|
+
6. **Check:** every journey maps to requirements and every requirement to a story, with no gaps left as "TBD".
|
|
161
|
+
|
|
162
|
+
It writes `docs/brief.md` (with the decision log and open questions), `docs/specs/NN-<area>.md`, `docs/architecture.md`, `docs/principles.md` and `docs/plan.md`. Those are exactly what `/code-kit:init docs/` turns into lanes and layers, and what lanes spec-check against. Run it again to resume where it left off, to change a decision, or to spec a new feature in an existing codebase.
|
|
163
|
+
|
|
164
|
+
Requirements are headings (`### BOOK-4 Cancel a booking`). Stories are `### ST-12` headings in the plan with `**Lane:**`, `**Requirements:**`, `**Depends on:**` and `**Status:**` lines (`templates/plan.md`). Those two formats are what the build loop below runs on.
|
|
165
|
+
|
|
166
|
+
## Set up a project
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
/code-kit:init docs/
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- **A new build:** init reads the docs in full: the architecture and layer map, the plan or work split, and the principles. It drafts the rules from them.
|
|
173
|
+
- **An existing codebase (brownfield):** the docs can be thin or missing. Init works the layers out from the code: which folders import which, and who works where according to the git history. It also runs each check once and flags any that already fail, so you decide what to do with them.
|
|
174
|
+
- **Either way:** you get a draft (`.claude/code-kit.draft.json`), one agent per lane, any project skills you approve, a CLAUDE.md section and a list of questions (see [The agents and skills it creates](#the-agents-and-skills-it-creates)). Nothing is enforced until you approve and the draft becomes `.claude/code-kit.json`.
|
|
175
|
+
|
|
176
|
+
**Existing violations.** Brownfield code usually breaks some layer rules already. On approval, `baseline --write` records them in `.claude/code-kit.baseline.json`:
|
|
177
|
+
|
|
178
|
+
- the violations it records don't block;
|
|
179
|
+
- new ones, even in the same file, do;
|
|
180
|
+
- the baseline only ever shrinks: re-recording drops what's been fixed and refuses anything new.
|
|
181
|
+
|
|
182
|
+
**No specs yet?** Leave `docs.specs` out, and lanes aren't held to a spec-check report. Add it once specs exist.
|
|
183
|
+
|
|
184
|
+
## The agents and skills it creates
|
|
185
|
+
|
|
186
|
+
code-kit ships no fixed team. Init writes one for each project, from its docs or its code, and re-running init keeps it in step as the project changes.
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
.claude/
|
|
190
|
+
├── code-kit.json # the rules: lanes, layers, protected paths, checks
|
|
191
|
+
├── agents/
|
|
192
|
+
│ ├── web-engineer.md # one lane agent per lane
|
|
193
|
+
│ ├── api-engineer.md
|
|
194
|
+
│ └── db-engineer.md
|
|
195
|
+
└── skills/
|
|
196
|
+
└── new-migration/ # project recipes, only the ones you approve
|
|
197
|
+
└── SKILL.md
|
|
198
|
+
CLAUDE.md # plus a section telling the lead how the rules work
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**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:
|
|
202
|
+
|
|
203
|
+
| Actor | Who it is | May write |
|
|
204
|
+
| ------------------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------- |
|
|
205
|
+
| The person | You | Anything; you also approve and merge |
|
|
206
|
+
| The lead | The main Claude Code session | Contracts, specs, config, the kit: `lead.paths` |
|
|
207
|
+
| A lane agent | A subagent whose name is a lane's `agent` in the config, or a session in a `.lane` worktree | Only its lane's paths, after its spec-check |
|
|
208
|
+
| Any other subagent | Explore, Plan, reviewers, anything not mapped to a lane | Nothing: read-only |
|
|
209
|
+
|
|
210
|
+
**Lane agents** (`.claude/agents/<agent>.md`, from `templates/agent.md`). Each is filled in from the project's docs, or from the code for brownfield projects:
|
|
211
|
+
|
|
212
|
+
- the paths the lane owns, its layers and what they may depend on;
|
|
213
|
+
- the specs it reads;
|
|
214
|
+
- the skills it uses: spec-check, plus its project recipes;
|
|
215
|
+
- the command that proves its work, and the lane's own rules.
|
|
216
|
+
|
|
217
|
+
It also carries the working rules: start from the story's branch and spec-check, build end to end with no mocks or placeholders, name requirement IDs in test titles, and commit before finishing.
|
|
218
|
+
|
|
219
|
+
The config's `lanes.<name>.agent` must match the agent file's `name`. That's how the hooks know a subagent is the web lane and not a read-only helper.
|
|
220
|
+
|
|
221
|
+
**Instructions and enforcement are separate.** The agent file tells the agent the rules, so it rarely hits them. The hooks enforce them whether or not the agent follows its file:
|
|
222
|
+
|
|
223
|
+
- writes outside its lane are blocked;
|
|
224
|
+
- code before a spec-check report is blocked;
|
|
225
|
+
- finishing with failing checks or uncommitted work is blocked.
|
|
226
|
+
|
|
227
|
+
Editing an agent file can't loosen a rule. And the agent files are kit files (`.claude/**`), so only the lead changes them, and every change is logged.
|
|
228
|
+
|
|
229
|
+
**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.
|
|
230
|
+
|
|
231
|
+
**How the spec is enforced, step by step:**
|
|
232
|
+
|
|
233
|
+
1. The brief names the story's requirement IDs.
|
|
234
|
+
2. The agent runs the spec-check skill and saves a requirement table for its branch.
|
|
235
|
+
3. The path guard blocks any code in its lane until that report exists.
|
|
236
|
+
4. The agent's tests name the requirement IDs.
|
|
237
|
+
5. The stop hook runs the checks before the agent can finish.
|
|
238
|
+
6. Review compares the branch with the requirements and the report, and `verify` checks the rules again in CI.
|
|
239
|
+
|
|
240
|
+
**Project skills** (`.claude/skills/<recipe>/SKILL.md`) are the step-by-step recipes your docs describe, like "add a migration" or "add an endpoint". Init lists the ones it finds and writes them only if you say yes, never as empty stubs. Each is listed in the owning lane agent's "Skills to use". Like the agents, they're kit files: the lead maintains them, and changes are logged.
|
|
241
|
+
|
|
242
|
+
**Kept in step.** When the project changes (a new app, a new lane, moved folders), re-run `/code-kit:init`. It drafts new agents for new lanes and updates the paths of existing ones, keeping anything written by hand. You see the difference and approve it before anything changes.
|
|
243
|
+
|
|
244
|
+
## Build
|
|
245
|
+
|
|
246
|
+
Once init has switched the rules on, the lead runs the build in a loop:
|
|
247
|
+
|
|
248
|
+
```text
|
|
249
|
+
/code-kit:dispatch next # start every ready story on its lane
|
|
250
|
+
/code-kit:review ST-12 # check a finished branch, then merge or send it back
|
|
251
|
+
/code-kit:status # where the build stands against the spec
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
- **Dispatch** picks the stories whose dependencies are done. It checks that no open question blocks them and that their contracts exist, then starts each lane agent in its own worktree on the branch `<lane>/st-<n>`, in parallel. Each brief names the story's requirements and acceptance criteria. Lanes spec-check first, build end to end, name requirement IDs in their test titles, and commit.
|
|
255
|
+
- **Review** runs `verify` on the branch, then checks each requirement: built end to end, proved by a test, matching the spec-check report, and nothing beyond the story. It ends with merge, send back with the list of problems, or a question for you.
|
|
256
|
+
- **Status** traces every requirement to its story, branch and tests. It shows what's done, in review, ready and blocked, which requirements no test names, and where the plan's status lines are out of date.
|
|
257
|
+
|
|
258
|
+
## Enforce it in CI
|
|
259
|
+
|
|
260
|
+
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.
|
|
261
|
+
|
|
262
|
+
`verify` can't see spec-check reports, because `.claude/state/` isn't committed. Review covers those.
|
|
263
|
+
|
|
264
|
+
## Keep it up to date
|
|
265
|
+
|
|
266
|
+
Re-run `/code-kit:init` whenever the build moves on: new apps or packages, moved folders, a changed plan, or files `unowned` keeps listing. It drafts the whole config again, then shows you the difference before anything changes:
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
+ lane jobs: jobs-engineer, workers/jobs/**
|
|
270
|
+
~ lane backend: exclude + workers/jobs/**
|
|
271
|
+
~ layer services: mayImport - schemas
|
|
272
|
+
Owner backend lane / backend-engineer → jobs lane / jobs-engineer: 14 file(s), e.g. workers/jobs/run.ts
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Lanes never change silently: only when you approve the diff.
|
|
276
|
+
|
|
277
|
+
## The CLI
|
|
278
|
+
|
|
279
|
+
Run from the project root, as `code-kit <command>` once installed (`npm i -g @warren-dean/code-kit`), or `npx @warren-dean/code-kit <command>`. Add `--config .claude/code-kit.draft.json` to any command to read a draft instead. In a session, the `/code-kit:check` skill runs `check` and `unowned` for you. `next` also works in a project without code-kit, or outside a git repository.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
code-kit check # validate and summarise
|
|
283
|
+
code-kit who <path>... # owner and layer of each path
|
|
284
|
+
code-kit unowned # tracked files nobody may write
|
|
285
|
+
code-kit diff --config .claude/code-kit.draft.json # what a draft changes
|
|
286
|
+
code-kit baseline [--write] # layer violations in the code as it is
|
|
287
|
+
code-kit graph [--depth N] # which folders import which
|
|
288
|
+
code-kit verify [--base ref] [--branch name] [--no-checks] # a branch's changes, for CI and review
|
|
289
|
+
code-kit status [--base ref] [--json] # stories and requirements against the spec
|
|
290
|
+
code-kit next [--base ref] [--json] # the step to take now, from the project's state
|
|
291
|
+
code-kit trace <path>... [--json] # what a file is for: requirements, lane, layer rules
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`verify` compares the branch with where it left `--base` (default `origin/main`, then `main`). A branch named `<lane>/…`, or given as `--branch`, is held to that lane. `--no-checks` leaves the project's checks to CI's own steps. `status` reads `docs.specs` and `docs.plan`.
|
|
295
|
+
|
|
296
|
+
## Config
|
|
297
|
+
|
|
298
|
+
`.claude/code-kit.json`. Globs use `*` (one segment), `**` (any depth), `**/` (zero or more folders), `?` and `{a,b}`. Patterns under `shell` are regular expressions.
|
|
299
|
+
|
|
300
|
+
| Field | Required | What it is |
|
|
301
|
+
| ------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
302
|
+
| `version` | yes | `1` |
|
|
303
|
+
| `docs.specs` | no | Folder of specs. With it, a lane needs a spec-check report before writing code on a branch |
|
|
304
|
+
| `docs.principles`, `docs.plan` | no | The engineering principles and the implementation plan |
|
|
305
|
+
| `lead.paths` | yes | What the main session writes. `.claude/**` is always added. |
|
|
306
|
+
| `lead.outside` | no | Paths outside the repository the lead may write, e.g. `../shared-lib/**`. Claude's memory and scratchpad are always included. |
|
|
307
|
+
| `anyActor` | no | Paths every writer may change (e.g. the lockfile). `.claude/state/**` is always included. |
|
|
308
|
+
| `lanes.<name>` | yes (may be `{}`) | `{ agent, paths, exclude? }`: the agent name maps a subagent to its lane. A worktree with a `.lane` file holding the lane name makes the main session that lane. |
|
|
309
|
+
| `protected[]` | no | `{ glob, approval, why }`: logged on every commit. Anyone but the lead needs a person's approval (see [Approvals](#approvals)). `.claude/**` is always protected as `kit`. |
|
|
310
|
+
| `designGate` | no | `{ register, screens: [{ glob, not? }], howTo }`: screen files wait until the register (`{ "screens": [{ "file": … }] }`) lists them |
|
|
311
|
+
| `layers[]` | no | `{ name, paths, mayImport, denyPackages? }`: the first layer whose paths match a file owns it. A layer may always import itself. |
|
|
312
|
+
| `importAliases` | no | `{ "@app/domain": "packages/domain/src" }`: resolves non-relative imports to repository paths |
|
|
313
|
+
| `shell.block[]` | no | `{ pattern, why }`: never run |
|
|
314
|
+
| `shell.restricted[]` | no | `{ pattern, lanes, why }`: only the lead and these lanes |
|
|
315
|
+
| `postEdit[]` | no | `{ files, exclude?, run }`: after each edit of a matching file. `{file}` is the file. Exit 127 (tool not installed) is skipped. |
|
|
316
|
+
| `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). |
|
|
317
|
+
| `adapters` | no | `{ "<adapter>": false }` switches off an adapter that would otherwise be detected. See [Adapters](#adapters). |
|
|
318
|
+
| `branches.protected` | no | Default `["main", "master"]` |
|
|
319
|
+
|
|
320
|
+
Add `.claude/approvals/`, `.claude/state/` and `.claude/code-kit.draft.json` to `.gitignore`, and `.claude/approval-log.jsonl merge=union` to `.gitattributes`, so merging branches that both logged changes keeps every entry. Commit `.claude/code-kit.baseline.json` if the project has one.
|
|
321
|
+
|
|
322
|
+
## Approvals
|
|
323
|
+
|
|
324
|
+
The lead edits protected paths directly. The audit log records every committed change as `lead`, and the person reviews it in the pull request. To attach a reason, to let a lane commit a protected file, or to allow a new dependency, a person runs a command at the terminal (the `!` prefix in Claude Code runs it; hooks never see it). The refusal an agent gets names the exact command.
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
echo "Approve the reset password screens" > .claude/approvals/design # anyone
|
|
328
|
+
echo "Approve the reset password screens" > .claude/approvals/web/design # the web lane only
|
|
329
|
+
echo "Date formatting for ST-12" > .claude/approvals/web/dep-dayjs # the web lane adds dayjs
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- **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.
|
|
333
|
+
- **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.
|
|
334
|
+
- **Worktrees:** approvals live in the main checkout, so a lane working in its own worktree sees the ones given at the lead's terminal.
|
|
335
|
+
- **Lifetime:** 60 minutes. Agents can't create, edit or even mention approvals or the log.
|
|
336
|
+
|
|
337
|
+
## Adapters
|
|
338
|
+
|
|
339
|
+
Other tools share a project with code-kit and keep files of their own. An adapter tells code-kit about one such tool, without the core knowing its name. Each adapter lives in `hooks/lib/adapters/`, and declares:
|
|
340
|
+
|
|
341
|
+
- how to detect the tool;
|
|
342
|
+
- what the tool adds to the rules: paths for the lead, paths any actor may write, protected paths, blocked commands;
|
|
343
|
+
- the setup init should apply.
|
|
344
|
+
|
|
345
|
+
While the tool is detected, its additions are merged into the effective config, like the kit's own defaults. Run `code-kit adapters` to see them, or switch one off with `"adapters": { "<name>": false }`.
|
|
346
|
+
|
|
347
|
+
| Adapter | Detected by | Adds |
|
|
348
|
+
| --------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
349
|
+
| `context-graph` | `.ctx/` | `.ctx/**` for the lead. `.ctx/decisions.ctx` and `.ctx/cards.ctx` for any actor, since every agent records decisions and file cards. `graph.ctx` and `config.toml` are protected (approval `ctx`). No Claude actor may write a `Ctx-Ratified-By` trailer: ratifying is a person's act. |
|
|
350
|
+
|
|
351
|
+
Its setup:
|
|
352
|
+
|
|
353
|
+
- ignore ctx's working files;
|
|
354
|
+
- add `merge=union` for `decisions.ctx` and `cards.ctx`, so lanes' decisions and cards from parallel branches all survive a merge;
|
|
355
|
+
- keep the two CLAUDE.md blocks pointing to each other.
|
|
356
|
+
|
|
357
|
+
To add one, write `hooks/lib/adapters/<tool>.mjs` in the same shape and list it in `hooks/lib/adapters/index.mjs`.
|
|
358
|
+
|
|
359
|
+
The other direction is `code-kit trace <path> --json`. It's the contract other tools read: the requirements a file delivers (from the `ST-n` stories its commits name, and the current story branch), its lane and owner, and its layer with what that layer may import. Context Graph's tool adapter calls it, so a file's card and the slice before an edit carry the spec requirement and the layer rule.
|
|
360
|
+
|
|
361
|
+
## Develop
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
npm test # unit tests, then the hooks end to end in throwaway repositories
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
## Licence
|
|
368
|
+
|
|
369
|
+
MIT. See [LICENSE](LICENSE). To report a security problem, see [SECURITY.md](SECURITY.md).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Security
|
|
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.
|
|
4
|
+
|
|
5
|
+
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
|
+
|
|
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.
|