@warren-dean/code-kit 0.15.1 → 0.16.1
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +20 -15
- package/bin/code-kit.mjs +39 -8
- package/hooks/guard-bash.mjs +21 -19
- package/hooks/lib/dependencies.mjs +21 -3
- package/hooks/lib/next.mjs +11 -1
- package/hooks/lib/rules.mjs +51 -4
- package/hooks/mod/decisions.mjs +1 -20
- package/hooks/mod/hold.mjs +2 -0
- package/hooks/mod/loop.mjs +80 -9
- package/hooks/mod/register.mjs +85 -32
- package/hooks/mod/register.test.ts +110 -19
- package/hooks/mod/view.mjs +35 -19
- package/package.json +1 -1
- package/skills/decide/SKILL.md +60 -0
- package/skills/dispatch/SKILL.md +1 -1
- package/skills/init/SKILL.md +3 -2
- package/skills/next/SKILL.md +2 -1
- package/skills/review/SKILL.md +1 -1
- package/templates/agent.md +2 -2
- package/templates/claude-md.md +3 -2
package/hooks/mod/view.mjs
CHANGED
|
@@ -101,6 +101,8 @@ export function projectState(check, status, next = null, atWork = new Set()) {
|
|
|
101
101
|
worktree: s.worktree ?? null,
|
|
102
102
|
requirements: s.requirements ?? [],
|
|
103
103
|
waitingOn: s.waitingOn ?? [],
|
|
104
|
+
// LOOP-13: a parked story watches the stories building on it.
|
|
105
|
+
dependsOn: s.dependsOn ?? [],
|
|
104
106
|
milestone: s.milestone ?? null,
|
|
105
107
|
})),
|
|
106
108
|
};
|
|
@@ -1231,13 +1233,7 @@ export function questionAsidePrompt({ q, thread = [], question }) {
|
|
|
1231
1233
|
* names, the lane, what was refused and why, its story, the limits it missed), the aside so far, and the
|
|
1232
1234
|
* question. It answers in the pane, never in the conversation, and acts on nothing.
|
|
1233
1235
|
*/
|
|
1234
|
-
export function approvalAsidePrompt({
|
|
1235
|
-
request,
|
|
1236
|
-
story = null,
|
|
1237
|
-
outside = null,
|
|
1238
|
-
thread = [],
|
|
1239
|
-
question,
|
|
1240
|
-
}) {
|
|
1236
|
+
export function approvalAsidePrompt({ request, story = null, thread = [], question }) {
|
|
1241
1237
|
return [
|
|
1242
1238
|
"The person is deciding whether to approve something code-kit stopped, and asks you about it in code-kit's approval pane. Answer in a few short sentences, in plain words: what it is, why it's needed for the work, what approving it lets happen, and anything risky about it. Use what you know from this conversation and the facts below. If you don't know, say so; don't guess. This answer goes to that pane, not into the conversation: don't act on it, and don't change your plans because of it.",
|
|
1243
1239
|
'',
|
|
@@ -1251,7 +1247,6 @@ export function approvalAsidePrompt({
|
|
|
1251
1247
|
`- story: ${story.id} ${story.title ?? ''}${story.requirements?.length ? ` (${story.requirements.join(', ')})` : ''}`,
|
|
1252
1248
|
]
|
|
1253
1249
|
: []),
|
|
1254
|
-
...(outside ? [`- outside the limits the person set for the lead: ${outside}`] : []),
|
|
1255
1250
|
...(thread.length
|
|
1256
1251
|
? [
|
|
1257
1252
|
'',
|
|
@@ -1350,6 +1345,8 @@ export function resultPane(result, { Box, Text }) {
|
|
|
1350
1345
|
|
|
1351
1346
|
const APPROVAL_LINE =
|
|
1352
1347
|
/^\s*! echo "<what you are approving>" > .*?\.claude\/approvals\/(?:([^/\s]+)\/)?([^/\s]+)\s*$/gm;
|
|
1348
|
+
const LEAD_LINE =
|
|
1349
|
+
/^\s*Decided by the lead: node "[^"]*" approve (.+?)(?: --lane (\S+))? --delegated\b/m;
|
|
1353
1350
|
|
|
1354
1351
|
/**
|
|
1355
1352
|
* A code-kit refusal read back from the text its hooks print (CARD-1): what was refused, the rule and
|
|
@@ -1363,10 +1360,23 @@ export function refusalCard(raw) {
|
|
|
1363
1360
|
const [first, ...rest] = text.split('\n');
|
|
1364
1361
|
const approvals = [...text.matchAll(APPROVAL_LINE)];
|
|
1365
1362
|
const command = text.match(/^Command: (.+)$/m)?.[1] ?? null;
|
|
1363
|
+
// HELM-2: what the lead decides carries its own approve command, never a person's `!` lines.
|
|
1364
|
+
const byLead = text.match(LEAD_LINE);
|
|
1366
1365
|
const request = (what) =>
|
|
1367
|
-
|
|
1368
|
-
? {
|
|
1369
|
-
|
|
1366
|
+
byLead
|
|
1367
|
+
? {
|
|
1368
|
+
names: byLead[1].split(/\s+/),
|
|
1369
|
+
lane: byLead[2] ?? null,
|
|
1370
|
+
what,
|
|
1371
|
+
by: 'lead',
|
|
1372
|
+
}
|
|
1373
|
+
: approvals.length
|
|
1374
|
+
? { names: approvals.map((m) => m[2]), lane: approvals[0][1] ?? null, what, by: 'person' }
|
|
1375
|
+
: null;
|
|
1376
|
+
const todoFor = (lasts) =>
|
|
1377
|
+
byLead
|
|
1378
|
+
? 'The lead decides it on its merits: it approves it, or tells the lane what to use instead.'
|
|
1379
|
+
: `A person approves it, here or with the \`!\` command, ${lasts}.`;
|
|
1370
1380
|
let m = first.match(/^The (.+?) may not write (\S+?)(?: \(owned by the (.+)\))?\.$/);
|
|
1371
1381
|
if (m)
|
|
1372
1382
|
return {
|
|
@@ -1377,23 +1387,25 @@ export function refusalCard(raw) {
|
|
|
1377
1387
|
request: null,
|
|
1378
1388
|
raw: text,
|
|
1379
1389
|
};
|
|
1380
|
-
m = first.match(/^(\S+) is (.+) and needs a person's approval\./);
|
|
1390
|
+
m = first.match(/^(\S+) is (.+) and needs (?:a person's|the lead's) approval\./);
|
|
1381
1391
|
if (m)
|
|
1382
1392
|
return {
|
|
1383
1393
|
kind: 'approval',
|
|
1384
1394
|
title: `Approval needed: ${m[1]}`,
|
|
1385
1395
|
why: `It's ${m[2]}.`,
|
|
1386
|
-
todo: '
|
|
1396
|
+
todo: todoFor('for 60 minutes'),
|
|
1387
1397
|
request: request(`write ${m[1]}`),
|
|
1388
1398
|
raw: text,
|
|
1389
1399
|
};
|
|
1390
|
-
m = first.match(
|
|
1400
|
+
m = first.match(
|
|
1401
|
+
/^(\S+) is (.+); committing it needs (?:a person's|the lead's) approval in force\./,
|
|
1402
|
+
);
|
|
1391
1403
|
if (m)
|
|
1392
1404
|
return {
|
|
1393
1405
|
kind: 'approval',
|
|
1394
1406
|
title: `Commit refused: ${m[1]}`,
|
|
1395
1407
|
why: `It's ${m[2]}.`,
|
|
1396
|
-
todo: '
|
|
1408
|
+
todo: todoFor('for 60 minutes'),
|
|
1397
1409
|
request: request(`commit ${m[1]}`),
|
|
1398
1410
|
raw: text,
|
|
1399
1411
|
};
|
|
@@ -1402,17 +1414,21 @@ export function refusalCard(raw) {
|
|
|
1402
1414
|
kind: 'kit',
|
|
1403
1415
|
title: 'Kit edit refused',
|
|
1404
1416
|
why: "The .claude kit is changed only by the lead or with a person's approval.",
|
|
1405
|
-
todo: '
|
|
1417
|
+
todo: todoFor('for 60 minutes'),
|
|
1406
1418
|
request: request('change the .claude kit'),
|
|
1407
1419
|
raw: text,
|
|
1408
1420
|
};
|
|
1409
|
-
m = first.match(
|
|
1421
|
+
m = first.match(
|
|
1422
|
+
/^a new dependency \((.+?)\) (?:needs a person's approval|is the lead's decision)\./,
|
|
1423
|
+
);
|
|
1410
1424
|
if (m)
|
|
1411
1425
|
return {
|
|
1412
1426
|
kind: 'dependency',
|
|
1413
1427
|
title: `Install refused: ${m[1]}`,
|
|
1414
|
-
why:
|
|
1415
|
-
|
|
1428
|
+
why: byLead
|
|
1429
|
+
? "A new dependency is the lead's decision."
|
|
1430
|
+
: "A new dependency needs a person's approval.",
|
|
1431
|
+
todo: todoFor('until the install is committed (at most 7 days)'),
|
|
1416
1432
|
request: request(command ?? `install ${m[1]}`),
|
|
1417
1433
|
raw: text,
|
|
1418
1434
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warren-dean/code-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Keeps AI coding agents inside your project's rules: lanes, layer rules, protected paths and proof before finish, enforced by Claude Code hooks and in CI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Warren Langeveldt",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: decide
|
|
3
|
+
description: The lead decides what a lane asked for and couldn't do itself (a new package, a migration, a protected file, a UX question) against the story's requirements, the spec, the principles and the architecture. Approves it, answers the lane with something that fits better, or takes it to the person only when it crosses a guardrail. Use when code-kit's loop or `code-kit next` says a lane waits on your decision, when a lane hands back a change request, or when the person runs /code-kit:decide [request numbers].
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Decide a lane's request
|
|
7
|
+
|
|
8
|
+
The person sets the guardrails: the specs, the architecture (contracts, layers, the rules in `.claude/code-kit.json`), the screens' visual design, CI, weakened tests, and product questions the spec doesn't answer. Inside them, you run the team. A lane that needs something it can't do itself asks you, and you decide on the merits. Passing a request to the person because you could is not deciding: they'd approve it by default, and the check would be gone.
|
|
9
|
+
|
|
10
|
+
The CLI is `node "${CLAUDE_PLUGIN_ROOT}/bin/code-kit.mjs"`.
|
|
11
|
+
|
|
12
|
+
## 1. Find the requests
|
|
13
|
+
|
|
14
|
+
`requests --json` lists each open request with its number (`n`), the lane, what it asked for (`names`, `what`), and whose decision it is (`by`). The argument, if given, names the numbers to take. Take every request `by: "lead"`. A request `by: "person"` is theirs: see step 4.
|
|
15
|
+
|
|
16
|
+
For each, read the lane's change request (its last report, or ask the lane with SendMessage if it's still running), its story in the plan, and the requirements the story cites, in the specs.
|
|
17
|
+
|
|
18
|
+
## 2. Judge it
|
|
19
|
+
|
|
20
|
+
**A package.** Approve it only when all of these hold:
|
|
21
|
+
|
|
22
|
+
- The story's requirements need what it does. Name the requirement.
|
|
23
|
+
- Nothing the project already depends on does the job: read the manifest (`package.json`, `pyproject.toml`, `Cargo.toml`…) and search the code for an existing helper.
|
|
24
|
+
- It fits the principles (`docs.principles`) and the lane's layer: a layer's `denyPackages` in the config, and anything the principles say about dependencies, such as no SDK in the domain layer, or a port before a vendor.
|
|
25
|
+
- It's the lightest thing that does the job. A whole framework for one function is the wrong answer; the standard library or a few lines of code may be the right one.
|
|
26
|
+
- It's maintained, and its licence is one the project can ship. For npm packages, `approve` checks the registry against `approvals.delegate.dependencies`. For other ecosystems the check is yours: look at the package's page.
|
|
27
|
+
|
|
28
|
+
**A protected file** (a migration, a validator, anything in `protected` that's yours to approve). Approve it when the change carries out what the story's requirements ask, and nothing more: a migration that adds the columns the spec names, a validator change the spec's rule requires. A change the spec doesn't call for is scope creep; send it back.
|
|
29
|
+
|
|
30
|
+
**A UX question** (what a screen does on an error, an empty list, a slow load, a second tap, the wording the spec implies). Answer it from the spec and the principles the person agreed, and write the answer where the lane will read it: the story in the plan, or the spec section's notes. Ask the person only when the spec and the principles don't settle it. A screen's visual design is theirs: it's approved before the screen is built.
|
|
31
|
+
|
|
32
|
+
## 3. Act on it
|
|
33
|
+
|
|
34
|
+
- **Yes.** Approve it for the lane and the story, saying why in the reason:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/code-kit.mjs" approve <package or approval> --lane <lane> --delegated --story ST-n --reason "<the requirement it serves, what the project already has, how it fits>"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then resume the lane: SendMessage to its agent if it's still running, or dispatch the story again with "approved: <what>" in the brief.
|
|
41
|
+
|
|
42
|
+
- **Something fits better.** Drop the request with the reason, and tell the lane what to use instead:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/code-kit.mjs" requests drop <n> --reason "<use X instead, because …>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- **It crosses a guardrail.** A package that would break a principle, change the architecture or need a spec change; a change to the spec or a contract; a product question the spec doesn't answer. Take it to the person with your recommendation, and carry on with what doesn't depend on it:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
node "${CLAUDE_PLUGIN_ROOT}/bin/code-kit.mjs" ask "<the question, in a sentence>" --story ST-n --blocks --why "<which guardrail it crosses>" --option "<choice>: <what it does>" --option "…"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 4. The person's requests
|
|
55
|
+
|
|
56
|
+
A request `by: "person"` is a guardrail the lane hit: a spec, a contract, a design, CI, or a weakened test. Check the lane really needs it first: often the story can be done inside the guardrail, and you tell the lane how and drop the request. If it does need it, the request is already in the person's Decisions tab. Add your recommendation with `ask` when the choice isn't obvious from the request alone.
|
|
57
|
+
|
|
58
|
+
## 5. Report
|
|
59
|
+
|
|
60
|
+
One line per request: what was asked, what you decided, and why. "ST-138: pillow approved for api (MED-5 needs HEIC decoding; nothing installed reads HEIC)." Then carry on with the build.
|
package/skills/dispatch/SKILL.md
CHANGED
|
@@ -89,4 +89,4 @@ Give them the same brief. Claude Code opened in that worktree then acts as the l
|
|
|
89
89
|
|
|
90
90
|
- Set each dispatched story's `**Status:**` in the plan to `in progress`, and commit it on the lead's branch.
|
|
91
91
|
- Tell the person, in a few lines: what was dispatched, to which lane and branch, what's still blocked and on what, and what's ready next.
|
|
92
|
-
- As each agent finishes, read its report. If it came back
|
|
92
|
+
- As each agent finishes, read its report. If it came back with a change request or a question, decide it yourself with `/code-kit:decide`, and bring to the person only what crosses a guardrail. If it came back done, run the review skill on its branch.
|
package/skills/init/SKILL.md
CHANGED
|
@@ -73,7 +73,8 @@ Write `.claude/code-kit.draft.json`. Follow `${CLAUDE_PLUGIN_ROOT}/README.md`
|
|
|
73
73
|
- **`shell.restricted`:** commands that affect a shared local service, limited to the lanes that own it.
|
|
74
74
|
- **`postEdit`:** the project's existing per-file linters and formatters, with `{file}`.
|
|
75
75
|
- **`checks`:** the typecheck, test, architecture and database commands, each scoped by `files`. Only include commands that pass on the current code, or ones the person chose to keep.
|
|
76
|
-
- **`harness.autonomy`:** ask the person how hands-off they want the build. With the code-kit mod (Claude Code 2.1.287 or later), once the plan has stories, a lead loop can keep the work moving between their prompts: it prompts the lead to dispatch ready stories, review finished ones and merge them where merges are delegated. Offer the three choices in plain words: `autonomous` (it keeps going on its own; they can pause it from the band), `propose` (each step waits in the band for their Go), or `off`. Put their answer in the draft as `"harness": { "autonomy": "…" }`. If they'd rather decide later, leave it out: the loop then asks them in the band before its first step. With `autonomous`, the lead owns delivery, so also draft `
|
|
76
|
+
- **`harness.autonomy`:** ask the person how hands-off they want the build. With the code-kit mod (Claude Code 2.1.287 or later), once the plan has stories, a lead loop can keep the work moving between their prompts: it prompts the lead to dispatch ready stories, review finished ones and merge them where merges are delegated. Offer the three choices in plain words: `autonomous` (it keeps going on its own; they can pause it from the band), `propose` (each step waits in the band for their Go), or `off`. Put their answer in the draft as `"harness": { "autonomy": "…" }`. If they'd rather decide later, leave it out: the loop then asks them in the band before its first step. With `autonomous`, the lead owns delivery, so also draft `"merge": true` in `approvals.delegate`: the lead merges a reviewed branch once every check passes.
|
|
77
|
+
- **`approvals.delegate`, who decides what (HELM-1):** the person sets the guardrails and decides what crosses them; the lead decides everything inside them, so lanes ask the lead, never the person. Draft `"dependencies": {}` (the lead approves a package only when the story's requirements need it and it fits the spec, the principles and the architecture; npm packages must also pass the default registry limits on licence, popularity and age) and `"protected"` listing every protected approval except those guarding the specs, contracts and the architecture's rules, the screens' designs (`design`), and CI. Show the person the split in two lines, what they keep and what the lead decides, and ask if they want to keep anything else. `tests` (weakening a test) is always theirs.
|
|
77
78
|
- **`harness.agents.lanes.model`:** ask which model the lane agents run on. Each lane agent builds one story inside its own paths, with its requirements and acceptance criteria in its brief, and the hooks, `verify` and the lead's review catch what it gets wrong, so Sonnet usually does the work well for much less than the session's model; recommend `sonnet`, and say the lead, the reviewer and the security reviewer keep the session's model. The mod sets it as each lane agent starts; a lane's agent file with its own `model:` keeps that. Put their answer in `harness` as `"agents": { "lanes": { "model": "sonnet" } }`, or leave it out for the session's model.
|
|
78
79
|
- **`harness.report.on`:** ask whether agents may draft bug reports for code-kit itself when code-kit gets in their way (a refusal that shouldn't have happened, a crash). Each report holds only code-kit's own facts (its version, the rule, what it said, the command), never the project's code, paths or data, and waits in their Decisions tab: they read it and send it to code-kit's public GitHub under their own account, or discard it. Off unless they say yes; put `"report": { "on": true }` in `harness` if they do.
|
|
79
80
|
- **`approvals.lead`:** ask the person whether they'll ever approve from a phone or another chat-only client, where a `!` command arrives as plain text. If so, set it to `true`: the lead then records approvals they give in chat (`code-kit approve`), and runs the `shell.block` commands marked `person: true` when they say so. Mark a `shell.block` command `person: true` only if the person wants to be able to have the lead run it on their say-so. Leave the setting out if the lead will run unattended.
|
|
@@ -143,7 +144,7 @@ Once they approve (with any changes):
|
|
|
143
144
|
9. **A team, only if there is one.** Not every developer works in a team. Ask once: "Do other developers work in this repository with their own Claude Code sessions?" If yes, run `/code-kit:team-init` now (it asks who the tech lead is and who owns which lanes, and writes the `team` section). If no, or not yet, leave it out and say `/code-kit:team-init` sets it up any time.
|
|
144
145
|
10. Set up each companion the config now wants (`"adapters": { "<name>": true }`) by running its init skill, for example `/context-graph:init`, which asks nothing. Do it before reporting, so it's in place before the coding loop starts; `code-kit next` also gives `setup` until it is.
|
|
145
146
|
|
|
146
|
-
Report what was set up, what's enforced from now on, how many existing violations the baseline holds, and the open questions. Say who does what from here: the person owns the intent and the rules; the lead owns delivery, so it dispatches, reviews, sends back and merges, and
|
|
147
|
+
Report what was set up, what's enforced from now on, how many existing violations the baseline holds, and the open questions. Say who does what from here: the person owns the intent and the rules; the lead owns delivery, so it dispatches, reviews, sends back and merges, and decides what lanes ask for inside the guardrails, and only what crosses a guardrail (the specs, the architecture, a design, a product question the spec doesn't answer) comes to the person.
|
|
147
148
|
|
|
148
149
|
If the project has no `.ctx/` folder and Context Graph isn't installed, don't install it unless the person asks: "Context Graph can give each lane agent the why behind the files it edits (cards, rules and decisions kept in git), with this spec's requirements and layer rules in them: `/plugin marketplace add warrendeanlangeveldt/context-graph`, then `/plugin install context-graph@context-graph`."
|
|
149
150
|
|
package/skills/next/SKILL.md
CHANGED
|
@@ -26,6 +26,7 @@ It returns `step`, `why`, `args`, `then` (steps that can follow straight after)
|
|
|
26
26
|
| Config, but no specs, plan or stories | `spec-design` |
|
|
27
27
|
| A companion the config wants, not set up yet | `setup`: run that tool's init skill (`args`), before code |
|
|
28
28
|
| An older setup missing what init now adds, nothing in flight | `update`: re-run init, before any new story |
|
|
29
|
+
| A lane waits on a request you decide | `decide`: approve it, or answer with an alternative |
|
|
29
30
|
| Stories finished on their branches | `review`, then `dispatch` what's ready |
|
|
30
31
|
| Design stories ready (`**Lane:** design`) | `design`, then `dispatch` what needs no design |
|
|
31
32
|
| Stories ready | `dispatch` |
|
|
@@ -51,7 +52,7 @@ Run the named skill with the Skill tool: `code-kit:<step>`, with `args` (and the
|
|
|
51
52
|
After a step finishes, run `next --json` again and carry on with the new step, without asking, as long as nothing needs the person. Stop and hand over when:
|
|
52
53
|
|
|
53
54
|
- a skill asks the person questions (spec-design's rounds, spec-check's blocking questions, review's scope questions);
|
|
54
|
-
- something needs the person's approval (init's draft, an approval
|
|
55
|
+
- something needs the person's approval (init's draft, an approval that's theirs: `requests --json` marks it `by: "person"`). What a lane asks for that's yours (`by: "lead"`) you decide with `/code-kit:decide`, without stopping. If the config has `approvals.lead`, ask for it in chat: when they approve in their own message, record it with the `code-kit approve` command the refusal names (their words as the reason) and carry on;
|
|
55
56
|
- a person has to act: merge a pull request to a protected branch, add a CI secret;
|
|
56
57
|
- the step is `wait` or `done`;
|
|
57
58
|
- the same step comes back twice in a row with nothing changed. Report what's stuck instead of looping.
|
package/skills/review/SKILL.md
CHANGED
|
@@ -46,7 +46,7 @@ Read the story, every requirement it cites, and the full diff (`git diff <base>.
|
|
|
46
46
|
- **Tested:** a test proves each acceptance criterion and names the requirement ID. The test would fail if the behaviour were broken; one that asserts nothing, or only asserts a mock, doesn't count.
|
|
47
47
|
- **Its journeys still pass end to end:** where the project has a QA lane, run the end-to-end suites that cover this story's requirements (the qa lane's command, filtered to them) against the branch. A journey that broke fails the review, even when the story's own tests pass. A story the QA lane delivered is reviewed the same way: each journey's test proves the requirements it cites, through the real screens and services, with no mocked responses.
|
|
48
48
|
- **The spec-check report matches:** its table has no row still `missing` or `conflicts` without an answer, and its questions were answered, not guessed.
|
|
49
|
-
- **Only the story:** changes beyond the story (refactors elsewhere, other stories' requirements,
|
|
49
|
+
- **Only the story:** changes beyond the story (refactors elsewhere, other stories' requirements) are sent back, or split into their own story. A new dependency is yours to judge, as in `/code-kit:decide`: the story's requirements need it, nothing the project has does the job, and it fits the principles and the layer. Only what crosses a guardrail (the spec, a contract, the architecture) is the person's call.
|
|
50
50
|
- **Contracts respected:** the code uses the contracts as written. A lane that needed a contract change should have asked, not worked around it.
|
|
51
51
|
|
|
52
52
|
## 4. The security review
|
package/templates/agent.md
CHANGED
|
@@ -22,8 +22,8 @@ Always:
|
|
|
22
22
|
- Read every file you change in full, plus its imports and its callers.
|
|
23
23
|
- Search before you build; reuse existing services, providers, components and schemas.
|
|
24
24
|
- Write only in your owned paths. For anything else, write a short change request for the lead and stop.
|
|
25
|
-
-
|
|
26
|
-
- A new dependency needs
|
|
25
|
+
- You answer to the lead, never the person. A question the spec doesn't settle (a product choice, UX the spec is silent on, an account): write it for the lead, with the choices and what each does, and carry on with what doesn't depend on it, or stop. The lead decides, or asks the person.
|
|
26
|
+
- A new dependency needs the lead's approval. Before asking, check the project doesn't already have something that does the job. If the install is refused, put in a change request for the lead: the package, the story and requirement that need it, what you checked, and anything lighter that would do; then stop. The lead approves it, or tells you what to use instead.
|
|
27
27
|
- Build every feature end to end. No mocks, stubs, placeholder screens or "coming soon".
|
|
28
28
|
- Prove each acceptance criterion with a test whose title names the requirement ID, e.g. `BOOK-4 …`.
|
|
29
29
|
- Fixing a bug: first write a test that fails because of the bug, through the code that's already there, then fix it. `verify` runs your test without the fix, and it must fail on an assertion, not because it calls something the fix adds.
|
package/templates/claude-md.md
CHANGED
|
@@ -6,17 +6,18 @@ The code-kit plugin enforces the rules in `.claude/code-kit.json` on every file
|
|
|
6
6
|
- the layer rules ({{layer names, in order}});
|
|
7
7
|
- spec-check before lane code{{; designs approved before screens}};
|
|
8
8
|
- an audit log of every change to protected paths (`.claude/approval-log.jsonl`), which the person reviews in the pull request;
|
|
9
|
-
-
|
|
9
|
+
- an approval for every new dependency and every protected change, per lane. Inside the guardrails, you decide: a lane asks you, never the person, and you approve it only when the story's requirements need it and it fits the spec, the principles and the architecture, or you tell the lane what to use instead (`/code-kit:decide`). The person decides what crosses a guardrail: {{the approvals the person keeps: those not in approvals.delegate, e.g. "spec changes, contracts, the screens' designs, CI"}}, weakened tests, and product questions the spec doesn't answer;
|
|
10
10
|
{{If approvals.lead is on: - approvals from chat. When the person approves in their own message (a `!` command doesn't work on a phone), record it with the `code-kit approve` command from the refusal, with their words as the reason. Never record an approval they haven't given, and never on a lane's say-so;}}
|
|
11
11
|
- the project's checks before any agent finishes.
|
|
12
12
|
|
|
13
|
-
When something needs the person to decide or do (a product choice, an account only they can create,
|
|
13
|
+
UX is yours: what a screen does on an error, an empty list or a slow load, and the wording the spec implies, answered from the spec and the principles the person agreed. A screen's visual design is theirs. When something needs the person to decide or do (a product choice the spec doesn't settle, an account only they can create, a design to sign off), ask it with `code-kit ask "<question>" --option "<choice>: <what it does>"` (`--story ST-n --blocks` holds the story until they answer). It waits in their Decisions tab, and their answer comes back to you; asking only in chat, it scrolls away. Lanes don't ask the person: they write the question for the lead.
|
|
14
14
|
{{If harness.report.on: - When code-kit itself is wrong (a refusal that shouldn't have happened, a crash), draft a report with `code-kit report "<title>" --what "…" --expected "…"`: only code-kit's facts, never the project's. The person reads it and sends it, or not.}}
|
|
15
15
|
|
|
16
16
|
If a hook blocks you, fix the cause; never work around it.
|
|
17
17
|
|
|
18
18
|
The build runs from the specs in {{docs.specs}} and the stories in {{docs.plan}}. `/code-kit:next` picks the right step from the project's state; the steps are:
|
|
19
19
|
|
|
20
|
+
- `/code-kit:decide` decides what a lane asked for, on its merits;
|
|
20
21
|
- `/code-kit:dispatch` starts ready stories on their lanes, each on its own `<lane>/st-<n>` branch;
|
|
21
22
|
- `/code-kit:review` checks a finished branch against its requirements before the lead merges it;
|
|
22
23
|
- `/code-kit:status` shows what's done, in review, ready and blocked, and what's untested;
|