@erclx/aitk 0.108.0 → 0.110.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "0.108.0",
4
+ "version": "0.110.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -45,7 +45,6 @@ The session also records nothing of what it learns. Both other callers of memory
45
45
  - List a candidate's file set against every track in flight, and serialize when the sets are not disjoint
46
46
  - Place every finding a merged pull request produced against the surface that owns it
47
47
  - Place what the return leg carries by what it changes, sending an answer that settles a finding onto the pull request and one that corrects this session's model of the world to the task owning that surface, since neither becomes a record by being read
48
- - Date the roadmap line from that file's last commit, so an old sequence reads as old
49
48
  - Keep one planned, non-conflicting task in reserve beyond what is running
50
49
  - Refill the queue while a wave is still building, rather than on a merge and a thinning list alone, since neither of those fires across the window planning costs nothing
51
50
  - Carry a constraint naming each in-flight track's file set in every plan written from here, stating per set which of the two acts it forbids, since a bare path list leaves a broken citation in place
@@ -86,8 +85,7 @@ The session also records nothing of what it learns. Both other callers of memory
86
85
  ## Guards
87
86
 
88
87
  - Priority file absent: report the queue and say the order is unrecorded rather than inferring it from the index
89
- - Roadmap absent: omit the roadmap line rather than asserting a version the file does not state
90
- - Roadmap present but never committed: report the date as uncommitted, since a blank reads as a formatting slip
88
+ - Cross-version sequencing asked for: say no surface carries it, rather than asserting an active version the tree does not state
91
89
  - This body dropped from a long session approaching a compaction: name the re-invocation and the runbook paths, since the routing lives in the body and a user-invoked skill routes nothing once it is gone
92
90
  - Blocker only an operator can clear: record the row as untestable this pass and name the action owed, rather than re-measuring what no session can move
93
91
 
@@ -28,7 +28,6 @@ Read the board in parallel, resolving the paths at the main worktree root per Wo
28
28
  - `.claude/tasks/backlog.md`: what is not being scheduled, when the file exists
29
29
  - `.claude/tasks/index.md`: what is queued
30
30
  - `.claude/plans/*.md`: features already planned and ready to hand off
31
- - `.claude/ROADMAP.md`: sequencing rationale, when the file exists
32
31
  - open PRs via `gh pr list --json number,title,headRefName,isDraft`
33
32
 
34
33
  Then output the state of play so the human knows what to launch, review, and merge.
@@ -37,7 +36,7 @@ Then output the state of play so the human knows what to launch, review, and mer
37
36
 
38
37
  Row position under `## Needs a plan` is what gets planned next, top first, per `.claude/standards/tasks.md`. `backlog.md` carries what nobody is scheduling and is explicitly unordered, so read it for what exists and never as a queue. Report a backlog count rather than its rows, since listing them puts the length back in front of the reader the cut took it away from.
39
38
 
40
- The roadmap is optional and this skill does not require it. It carries why a sequence is what it is, changes only when strategy changes, and is absent in a project whose scope has already shipped. Report what it says and name it as the source. Never assert an active version the file does not state, and say nothing about one when the file is missing.
39
+ No surface carries cross-version sequencing, so report none. A row's `Waiting on` cell states why that row sits where it does, and reasoning spanning several rows reaches this session only through whoever remembers it. Say nothing about an active version, since nothing in the tree states one and a version asserted from the board is the unsourced claim this omission exists against.
41
40
 
42
41
  A compaction is a moment this skill cannot detect, so the human asks for each side of it and this skill reads the matching runbook when they do.
43
42
 
@@ -56,8 +55,6 @@ That routing lives in this body and this skill is user-invoked, so a session tha
56
55
  ```plaintext
57
56
  Orchestrator ready.
58
57
 
59
- Roadmap: vX.Y, <the Now row's outcome>, as of <date>.
60
-
61
58
  Ready to build (hand each to its own worker):
62
59
 
63
60
  <feature>
@@ -80,9 +77,7 @@ Next: <the single most useful action>
80
77
 
81
78
  Omit any section with nothing in it. Recommend a handoff only for a plan whose file set is disjoint from every track already in flight, per Parallelism below.
82
79
 
83
- Omit the `Roadmap` line when `.claude/ROADMAP.md` is absent. Quote the `Now` row rather than restating it, and date the line from `git log -1 --format=%ad --date=short -- .claude/ROADMAP.md` so an old sequence reads as old instead of as the state of play.
84
-
85
- That command returns nothing for a roadmap that exists but has never been committed, which is the state `claude-roadmap` leaves behind when it writes the file and declines to stage it. Write `uncommitted` as the date in that case. A blank there would read as a formatting slip rather than as the newest possible sequence.
80
+ The block opens on the board rather than on a version, because no committed file states one. Adding a version line here would restate what a reader can already see on the rows, dated by nothing, which is how the retired sequencing surface produced an unsourced claim on every run.
86
81
 
87
82
  ### Every later turn
88
83
 
@@ -103,18 +98,15 @@ Write no shape for a correction. A correction is a sentence, and a format for ad
103
98
 
104
99
  ## The loop
105
100
 
106
- 1. Own the roadmap while a scope exists to sequence.
107
- - Capture a needed draft or resequence of `.claude/ROADMAP.md` in the plan or a task file, naming the MVP list in `.claude/REQUIREMENTS.md` as the source, so a worker runs `claude-roadmap` in its branch and the tracked edit ships in a PR rather than dirtying main
108
- - Stop owning it once that list has shipped, since later work then arrives as discrete items rather than as versions
109
- 2. Plan the next feature. Run `claude-feature` here, with the cross-feature context, to write a plan to `.claude/plans/`. Planning stays in this warm session so the plan front-loads reasoning a cold worker would otherwise re-derive. Every plan written from here also carries a constraint per track in flight, which the paragraph below this list states.
110
- 3. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
111
- 4. Verify the plan against the tree. Reading it is not enough, since a plan goes stale from whatever merged after it was written. Grep for each construct it names and count the sites against the count it claims. Check that every phase label it cites is still open. Open each file it describes rather than trusting its account of the contents. Correct the plan before handing it over.
112
- 5. Hand off. The human opens a worker worktree with `claude-worktree` and runs `claude-autoship` against the plan. The orchestrator does not spawn workers.
113
- 6. Review the PR. When a worker opens a PR, run `claude-pr-review` to post findings to it. This is the deep, independent pass. The worker's autoship self-review was only the green gate.
101
+ 1. Plan the next feature. Run `claude-feature` here, with the cross-feature context, to write a plan to `.claude/plans/`. Planning stays in this warm session so the plan front-loads reasoning a cold worker would otherwise re-derive. Every plan written from here also carries a constraint per track in flight, which the paragraph below this list states.
102
+ 2. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
103
+ 3. Verify the plan against the tree. Reading it is not enough, since a plan goes stale from whatever merged after it was written. Grep for each construct it names and count the sites against the count it claims. Check that every phase label it cites is still open. Open each file it describes rather than trusting its account of the contents. Correct the plan before handing it over.
104
+ 4. Hand off. The human opens a worker worktree with `claude-worktree` and runs `claude-autoship` against the plan. The orchestrator does not spawn workers.
105
+ 5. Review the PR. When a worker opens a PR, run `claude-pr-review` to post findings to it. This is the deep, independent pass. The worker's autoship self-review was only the green gate.
114
106
  - Learning that a PR moved is the mechanical half, so read `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` and start the poll it carries on the first dispatch rather than checking the board by hand. That runbook holds the routing, and a summary of it here is a second source that drifts from it.
115
- 7. Dispatch the handback. A pass posting a finding at any severity tells the session holding that branch to run `claude-address-review`, rather than waiting for a person to relay it. Re-review when the answer lands, then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
107
+ 6. Dispatch the handback. A pass posting a finding at any severity tells the session holding that branch to run `claude-address-review`, rather than waiting for a person to relay it. Re-review when the answer lands, then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
116
108
  - Read the threshold off `claude-pr-review`, which states it once and governs the heading with it, so an open heading and an owed dispatch answer the same question and either one is enough to send
117
- - Resolve the target at the moment of sending with `aitk sessions list --branch`, never from a mapping written down earlier, since names rotate as sessions end and one recorded earlier in a session has failed inside the hour. The runbook read at step 6 routes on the count and the confidence it answers with
109
+ - Resolve the target at the moment of sending with `aitk sessions list --branch`, never from a mapping written down earlier, since names rotate as sessions end and one recorded earlier in a session has failed inside the hour. The runbook read at step 5 routes on the count and the confidence it answers with
118
110
  - Open the message with the worktree and branch the sender believes the reader holds, asking to be corrected, whenever that mapping is inferred rather than confirmed
119
111
  - Name the skill for the reader to run rather than writing an invocation, which arrives as text
120
112
  - Read the pull request's own draft flag rather than the state a worker reports, since two reported a draft that read ready inside ninety seconds
@@ -134,7 +126,7 @@ Stamp the block with the commit this session read the tree at, which the same se
134
126
  - Run one orchestrator at a time. The board is gitignored, so a second session sees none of this one's writes: two task files land minutes apart under different labels for the same work, one session archives a task mid-sweep in the other, and each archives a plan the other had retargeted. An Owner column does not fix this, since neither session can read the other's rows.
135
127
  - Do not implement features in this session. Hand the plan to a worker.
136
128
  - Do not merge. Recommend merge or changes. The human merges.
137
- - Do not spawn worker sessions with agents. The human launches each worktree so every build is an independent, steerable stream with its own PR. The handback dispatch in step 7 reaches a session the human already launched, so it leaves this boundary where it is.
129
+ - Do not spawn worker sessions with agents. The human launches each worktree so every build is an independent, steerable stream with its own PR. The handback dispatch in step 6 reaches a session the human already launched, so it leaves this boundary where it is.
138
130
  - Do not edit tracked files from this session, at any size. The boundary offers no proportionality exception and nothing enforces it.
139
131
  - Do not hand a worker anything but a plan, since scope lives there. A plan carries exact diffs only when they are already known, otherwise it states the scope and the open questions and lets the worker write the diff.
140
132
 
@@ -7,7 +7,7 @@ description: What the independent pull request review is for, the gaps it closes
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a pull request is reviewed only by the session that wrote it, which cannot see the roadmap sequence or a sibling branch in flight. Findings land in chat, where they are read once and leave the thread with no record. A review that opens and never closes is worse than none, since a reader scanning the thread cannot tell an unanswered review from a confirmed one, and the author's claim that findings are fixed is the only evidence they are.
10
+ Without this skill, a pull request is reviewed only by the session that wrote it, which cannot see the board's order or a sibling branch in flight. Findings land in chat, where they are read once and leave the thread with no record. A review that opens and never closes is worse than none, since a reader scanning the thread cannot tell an unanswered review from a confirmed one, and the author's claim that findings are fixed is the only evidence they are.
11
11
 
12
12
  A finding also stops being true by argument rather than by a fix. A worker naming the plan question that already declined it, or a constraint the pass could not see, settles it in the exchange that carried the answer, and the pass that accepts the argument drops the finding from its next body. A reader then sees a finding raised once and never mentioned again, which is indistinguishable from one everyone forgot.
13
13
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: claude-pr-review
3
- description: Reviews an open pull request from an independent session and posts findings as a review comment on the PR. Posts a first pass against the whole change and every later pass against only the commits added since, under `## Review` while any finding is open and `## Review closed` once a pass carries none. Reads project docs and the roadmap for cross-feature context a self-review lacks. Use when asked to "review the PR", "review this feature's PR", "post a PR review", "re-review the PR", "close out the review", "confirm the findings are fixed", or acting as the orchestrator reviewing a worker's PR. Do NOT use to review local uncommitted changes. That is `claude-review`.
3
+ description: Reviews an open pull request from an independent session and posts findings as a review comment on the PR. Posts a first pass against the whole change and every later pass against only the commits added since, under `## Review` while any finding is open and `## Review closed` once a pass carries none. Reads project docs and the task board for cross-feature context a self-review lacks. Use when asked to "review the PR", "review this feature's PR", "post a PR review", "re-review the PR", "close out the review", "confirm the findings are fixed", or acting as the orchestrator reviewing a worker's PR. Do NOT use to review local uncommitted changes. That is `claude-review`.
4
4
  ---
5
5
 
6
6
  # Claude PR review
@@ -32,7 +32,7 @@ Read these in parallel from the project root, skipping any that do not exist:
32
32
  - `CLAUDE.md`: project type, conventions, and commands
33
33
  - `.claude/REQUIREMENTS.md`: feature scope and non-goals
34
34
  - `.claude/ARCHITECTURE.md`: technical design decisions
35
- - `.claude/ROADMAP.md`: where this feature sits and what depends on it
35
+ - `.claude/tasks/priority.md`: where this feature sits on the board and what each neighboring row waits on. Resolve this one at the main worktree root per Worktrees in `CLAUDE.md`, since the board is gitignored and a linked worktree holds no copy of it
36
36
  - `.claude/plans/feature-<slug>.md` for the branch, when present: the intent the PR should satisfy
37
37
 
38
38
  Coding standards from `.claude/rules/` are auto-loaded by Claude Code.
@@ -79,7 +79,7 @@ Read each changed file in scope. Skip deleted files. Run reads in parallel.
79
79
 
80
80
  Review the diff and files for the same axes as `claude-review` (bugs, edge cases, error handling, logic flaws, security, rule violations), then add the three lenses a self-review structurally cannot apply:
81
81
 
82
- - Integration: does this fit the roadmap sequence, the shared wiring seam, and any sibling PR in flight?
82
+ - Integration: does this fit the board's order, the shared wiring seam, and any sibling PR in flight?
83
83
  - Contract: does a contract downstream features depend on land correctly, and should the plan itself be questioned?
84
84
  - Consumers: when the change touches a resource with more than one consumer, enumerate them and check the rule against each. A rule written for the consumer the change targets can be wrong for a sibling that writes.
85
85
 
@@ -116,7 +116,7 @@ The comment is a rendered-for-human GitHub surface, so load the `write-human` sk
116
116
  ```markdown
117
117
  ## Review
118
118
 
119
- X critical, Y should-fix, Z minor. Reviewed against project docs and roadmap.
119
+ X critical, Y should-fix, Z minor. Reviewed against project docs and the board.
120
120
 
121
121
  **`path/to/file.ext`**
122
122
 
@@ -172,14 +172,14 @@ Before posting, run the scan in `.claude/standards/publish.md` against the body,
172
172
  gh pr review <number> --comment --body-file .claude/.tmp/pr-review/body-<number>-<short-sha>.md
173
173
  ```
174
174
 
175
- A pass carrying nothing at all takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No findings. Reviewed against project docs and roadmap.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.`
175
+ A pass carrying nothing at all takes `## Review closed` and a short body, with the footer line included either way. On a first pass, post `✅ No findings. Reviewed against project docs and the board.` On a later pass, post `✅ Prior findings addressed. Re-reviewed <short-sha>, N commits since the prior pass.`
176
176
 
177
177
  A pass carrying only minors is an ordinary finding-carrying pass, so it takes the open heading and the full shape rather than either short line, since the minors have to be readable and neither line reports them. Keep whichever scope sentence the pass owes on the summary line:
178
178
 
179
179
  ```markdown
180
180
  ## Review
181
181
 
182
- 0 critical, 0 should-fix, Z minor. Reviewed against project docs and roadmap.
182
+ 0 critical, 0 should-fix, Z minor. Reviewed against project docs and the board.
183
183
 
184
184
  **`path/to/file.ext`**
185
185
 
@@ -11,7 +11,7 @@ Without this skill, a target holding a retired `.claude/` file is told what repl
11
11
 
12
12
  A second failure comes from the ordering nobody gets right unaided. A retired file committed before its ignore entry was written is tracked and ignored at once, and removing the entry first leaves the file tracked with nothing naming it. No report catches that state, so the mistake is discovered by whoever next wonders why a gitignored path keeps appearing in diffs.
13
13
 
14
- Two more follow from where a session looks when the report is thin. An uppercase stem under `.claude/` is not the test for a superseded file, so a session substituting a folder listing reaches `ARCHITECTURE.md`, `REQUIREMENTS.md`, `ROADMAP.md`, and `DESIGN.md`, each a single file the layout intends to stay one, and proposes shredding four documents. A session falling back to the plugin's own copy of the destination standard proposes a shape the project never adopted, against content only the user can place.
14
+ Two more follow from where a session looks when the report is thin. An uppercase stem under `.claude/` is not the test for a superseded file, so a session substituting a folder listing reaches `ARCHITECTURE.md`, `REQUIREMENTS.md`, and `DESIGN.md`, each a single file the layout intends to stay one, and proposes shredding three documents. A session falling back to the plugin's own copy of the destination standard proposes a shape the project never adopted, against content only the user can place.
15
15
 
16
16
  The last is the two-speed release skew arriving as a confident wrong answer. `superseded` reached a release in `0.46.0`, and an older CLI exits zero with a well-formed report that never mentions the field. A session reading that absent key as an empty array reports a clean layout to exactly the population holding the retired files.
17
17
 
@@ -27,7 +27,7 @@ Stop on any of three conditions, naming which one fired:
27
27
 
28
28
  Test for the key rather than for emptiness. A current CLI reporting `"superseded": []` has looked and found nothing, which is the pass above, and reading an absent key as an empty answer reports a clean layout to the projects this skill exists for.
29
29
 
30
- No listing substitutes for the field. The pairing runs against the seed folder names the toolkit ships, and an uppercase stem is not the test, so a listing of `.claude/*.md` also reaches `ARCHITECTURE.md`, `REQUIREMENTS.md`, `ROADMAP.md`, and `DESIGN.md`. Each of those is a single file the layout intends to stay one. A fallback that proposed splitting them would shred four documents to avoid reporting a stale CLI, which is why this skill stops where its siblings degrade.
30
+ No listing substitutes for the field. The pairing runs against the seed folder names the toolkit ships, and an uppercase stem is not the test, so a listing of `.claude/*.md` also reaches `ARCHITECTURE.md`, `REQUIREMENTS.md`, and `DESIGN.md`. Each of those is a single file the layout intends to stay one. A fallback that proposed splitting them would shred three documents to avoid reporting a stale CLI, which is why this skill stops where its siblings degrade.
31
31
 
32
32
  ## Step 2: resolve the destination standard
33
33
 
@@ -0,0 +1,88 @@
1
+ ---
2
+ title: Audits
3
+ description: Running every health check as one set, what the single verdict means, the exit code each outcome takes, the retained baseline and the delta it reports, and which corpora are kept out of the record
4
+ ---
5
+
6
+ # Audits
7
+
8
+ `aitk audits run` runs every audit this repository owns, reports each one under a single verdict, and compares each count to the floor the last recorded run left behind. Nothing here is a new measure. Every number it prints comes from a verb that already published it, which is what makes the command cheap and what separates it from writing another check.
9
+
10
+ ```bash
11
+ aitk audits run
12
+ aitk audits run --json
13
+ aitk audits run --record
14
+ aitk audits list --json
15
+ ```
16
+
17
+ | Option | Behavior |
18
+ | --------------- | ----------------------------------------------------------------- |
19
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
20
+ | `--root <path>` | Measure this tree instead of the current worktree |
21
+ | `--record` | Write this run's tracked counts to `.claude/audits/baseline.json` |
22
+
23
+ ## What it runs
24
+
25
+ Twelve verbs, listed by `aitk audits list`. Each runs once in its fullest form, and the aggregate reads that verb's own record rather than imposing a shared envelope on it. Every one of those records already has consumers naming its keys, so a common shape would be a breaking change bought for tidiness.
26
+
27
+ The verbs walk separate trees and share no state, so they run together. Measured on the authoring machine, twelve runs finish in 0.8 seconds of wall clock against 4.4 seconds of processor, which is under every other stage in `bun run check`.
28
+
29
+ Each is invoked as the CLI the caller is running rather than as a global `aitk`. A globally installed binary resolves to the main checkout no matter which worktree is executing, so the aggregate would measure a tree the branch never touched and report a pass over it.
30
+
31
+ ## What gates and what reports
32
+
33
+ Three findings fail the run: an unresolved context citation, a banned character, word, or spelling, and a skill folder carrying no `REQUIREMENT.md`. Those are the same three `scripts/core/verify.sh` already fails a push on, and the aggregate adds nothing to the set. Each is a fact with no false-positive class behind it.
34
+
35
+ Everything else reports. A heavy bullet, a long entry, a board row nothing resolves, a degradation term in a comment, and an implementation reaching history ahead of its test are judgments a reader settles. A push failing on one of those teaches contributors to route around the stage, which is the split recorded across every audit here and the one this command inherits rather than moves.
36
+
37
+ Growth against the baseline reports too. The standards behind the largest measures set no hard cap, so a count that rose is a fact about the corpus and a judgment about whether it matters.
38
+
39
+ ## Exit codes
40
+
41
+ | Code | Meaning |
42
+ | ---- | -------------------------------------------------------------------- |
43
+ | `0` | Every audit reported and none carried a finding that is a fact |
44
+ | `1` | Refused, with the reason on stderr |
45
+ | `2` | An audit carries a finding that is a fact |
46
+ | `3` | An audit did not report, so the run measured less than the whole set |
47
+
48
+ `3` is a defect in the run rather than in the tree, which is why it takes a code of its own. An aggregate reporting a pass over a set it never finished measuring is the failure the command exists against, so an unparseable record, a verb that could not be started, and an exit no verb documents all land there instead of quietly counting as clean. The `markdown audit` empty-ban-set exit is the precedent: a corpus walked with nothing looked for is a broken check, not a clean tree.
49
+
50
+ The verdict is published as a field as well as an exit code. A reader branching on `summary.verdict` gets `clean`, `reported`, `findings`, or `incomplete` without inferring the difference between a quiet corpus and one nobody finished measuring.
51
+
52
+ ### An absent corpus is not an unmeasured one
53
+
54
+ A per-machine folder that is not on this disk reports as `absent` and moves neither the verdict nor the exit code. Every one of those folders is gitignored, so a fresh clone and every CI run carry none of them, and counting six expected absences as failures pins the verdict at `incomplete` forever. A signal that never changes is one nobody reads after the second time they see it.
55
+
56
+ The allowance is narrow. It covers a per-machine corpus refusing because its folder is missing, and nothing else. A tracked tree that cannot be found is a broken checkout, and a per-machine verb refusing for any other reason is a broken verb. Both stay `unmeasured`.
57
+
58
+ Every run states how many corpora it measured against how many it skipped, including a run with no findings at all. A count of what passed reads as a verdict on the whole set unless the run also says what it never reached.
59
+
60
+ ### What a shallow checkout changes
61
+
62
+ `aitk gov test-order` scopes its range against the trunk and falls back to the root commit when no trunk ref resolves. A depth-1 checkout has neither, so the range is empty and the verb reports zero of everything rather than refusing. The numbers are real for the history present, which means a shallow run under-reports against a baseline taken from a full clone and shows as shrinkage. That is the safe direction, and it is the reason a `test-order` delta is worth reading only from a clone carrying the history.
63
+
64
+ ## The retained baseline
65
+
66
+ `.claude/audits/baseline.json` holds the counts from the last run recorded with `--record`, alongside the day it was taken and the commit it was read at. Each later run reports which counts moved and by how much.
67
+
68
+ The file is committed. A per-machine record cannot answer the question this half exists for, which is whether a number grew since anyone last looked, and a fresh checkout has to inherit that answer rather than start over. The cost is that a branch moving a count either fixes it or re-records it and says why, which is the shape the consumed-copy assertion already carries.
69
+
70
+ It sits under the project root rather than beside the aggregator in `src/`. The numbers describe one repository's corpus, and `src/` ships to every project that installs the CLI, so a baseline in the package would hand a target these counts to measure its own tree against.
71
+
72
+ ### What is kept out of it
73
+
74
+ A gitignored record folder holds one machine's session scratch. Its counts describe somebody else's disk, so committing them writes a floor no other clone can reproduce and every contributor reads a regression against a number that was never about their tree. The board and five of the six record kinds are therefore reported on every run and recorded in none. `records-standards` is the exception, because that corpus is tracked.
75
+
76
+ An audit that did not report is left out rather than written as zero. Zero there records a clean corpus nobody measured, and the next run reads its real numbers as a regression against a floor that was never taken.
77
+
78
+ ### The first run
79
+
80
+ A run with no baseline behind it says so rather than showing a delta of zero. Those two states say the same thing to a reader and mean opposite things, which is a defect this repository has already had to fix twice elsewhere. The same reasoning covers a check the baseline never recorded, a key the run produced that the record does not carry, and a key the record carries that this run did not produce. Each is named for what it is.
81
+
82
+ A hand-edited baseline that does not parse refuses the whole run. Reading a broken record as an absent one would reset the floor the file exists to hold, silently.
83
+
84
+ ## In the verify pipeline
85
+
86
+ `bun run check` runs the set as a reporting stage after the three gating stages, and never fails on it. Those three stages keep their own specific remedies, so the aggregate reports the rest and the growth, and a fact still fails the push at the stage that names what to do about it.
87
+
88
+ The stage reads `summary`, a flat object of scalars published beside the nested arrays. Every key in it is unique across the whole record, so a shell stage greps one out without a JSON parser. The three verbs the gating stages already ran walk their trees a second time here, which is the 0.8 seconds measured above and the reason the whole set runs rather than only the part those stages skip: one verdict over every audit is the value, and a stage measuring a subset would report a health nobody took.
@@ -46,6 +46,8 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
46
46
  | `aitk claude skills audit` | Report both skill corpora against the mechanical rules in `standards/skill.md` |
47
47
  | `aitk claude skills drift` | Name the shipped skill bodies rewritten between a given ref and `HEAD` (`--json`) |
48
48
  | `aitk gov test-order` | Report where an implementation reached history ahead of the test covering it (`--json`) |
49
+ | `aitk audits run` | Run every audit as one set, report per check under one verdict, and compare each count to the recorded baseline (`--json`, `--record`) |
50
+ | `aitk audits list` | List every audit the set runs, with the corpus each reads and whether it gates (`--json`) |
49
51
  | `aitk capture [source]` | Render HTML capture sources to PNG, toolkit-only and absent from an installed package |
50
52
 
51
53
  ## Domain commands
@@ -68,6 +70,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
68
70
  | `comments` | `scan` |
69
71
  | `context` | `audit` |
70
72
  | `markdown` | `audit` |
73
+ | `audits` | `run`, `list` |
71
74
 
72
75
  Common patterns:
73
76
 
@@ -8,6 +8,7 @@ category: Agent surface
8
8
 
9
9
  CLI catalog and invocation rules for agents, split by command domain. Start with overview.
10
10
 
11
+ - [Audits](audits.md): Running every health check as one set, what the single verdict means, the exit code each outcome takes, the retained baseline and the delta it reports, and which corpora are kept out of the record
11
12
  - [Capture](capture.md): Rendering committed HTML sources to PNG, what the command asserts about fonts, and why it is toolkit-only
12
13
  - [Command catalog](commands.md): Every project-level command and every domain subcommand, plus the shape each domain exposes
13
14
  - [Comments](comments.md): Comment density by language and kind, the two structural exclusions, and how the degradation sweep finds its vocabulary
@@ -11,15 +11,16 @@ What a skill or script reads to discover names at runtime, and how each domain i
11
11
 
12
12
  Use these to discover what's available instead of hardcoding names.
13
13
 
14
- | Command | Returns |
15
- | -------------------------------- | ---------------------------------------------------- |
16
- | `aitk tooling list --json` | Stacks, extends chain, dep and script counts |
17
- | `aitk snippets list --json` | Presets and categories with their slugs |
18
- | `aitk standards list --json` | Standards docs and the paths each governs |
19
- | `aitk gov list --json` | Governance stacks, rule sets, and unreferenced rules |
20
- | `aitk claude seeds list --json` | Seed doc sources with content |
21
- | `aitk claude skills list --json` | Plugin skills, descriptions, requirement flag |
22
- | `aitk docs list --json` | Consumer docs plus per-domain context |
14
+ | Command | Returns |
15
+ | -------------------------------- | ---------------------------------------------------------------- |
16
+ | `aitk tooling list --json` | Stacks, extends chain, dep and script counts |
17
+ | `aitk snippets list --json` | Presets and categories with their slugs |
18
+ | `aitk standards list --json` | Standards docs and the paths each governs |
19
+ | `aitk gov list --json` | Governance stacks, rule sets, and unreferenced rules |
20
+ | `aitk claude seeds list --json` | Seed doc sources with content |
21
+ | `aitk claude skills list --json` | Plugin skills, descriptions, requirement flag |
22
+ | `aitk docs list --json` | Consumer docs plus per-domain context |
23
+ | `aitk audits list --json` | Audits the set runs, the corpus each reads, and whether it gates |
23
24
 
24
25
  ### Catalog fields
25
26
 
@@ -129,4 +130,7 @@ AITK_NON_INTERACTIVE=1 aitk wiki init /path/to/project
129
130
 
130
131
  # Run a sandbox scenario non-interactively
131
132
  SANDBOX_SCENARIO=sync aitk sandbox infra:tooling
133
+
134
+ # Read every audit as one record. Exit 2 is a fact, 3 an audit that did not report
135
+ aitk audits run --json
132
136
  ```
@@ -75,9 +75,9 @@ When features are independent, run them in parallel instead of sequentially. Use
75
75
  - Ship each worktree separately with `aitk:git-ship`
76
76
  - For full autonomy per worktree, invoke `aitk:claude-autoship` instead of the manual chain. Approve the plan, walk away, come back to draft PRs.
77
77
 
78
- To run several worktrees as a coordinated flow rather than ad hoc, assert the orchestrator role in one warm session with `aitk:claude-orchestrate`. It owns the roadmap, handing a needed draft or resequence to a worker that runs `aitk:claude-roadmap` in its branch, plans each feature, refills the ready queue so a free worker never waits, and reviews each worker's PR with `aitk:claude-pr-review`, then tells the session holding that branch to run `aitk:claude-address-review` whenever the pass posted a finding at any severity, which is the same threshold `aitk:claude-pr-review` states and posts its open heading under. The human launches workers and merges. See [operating model](operating-model.md) for the full loop.
78
+ To run several worktrees as a coordinated flow rather than ad hoc, assert the orchestrator role in one warm session with `aitk:claude-orchestrate`. It plans each feature, refills the ready queue so a free worker never waits, and reviews each worker's PR with `aitk:claude-pr-review`, then tells the session holding that branch to run `aitk:claude-address-review` whenever the pass posted a finding at any severity, which is the same threshold `aitk:claude-pr-review` states and posts its open heading under. The human launches workers and merges. See [operating model](operating-model.md) for the full loop.
79
79
 
80
- Roadmap ownership holds while a scope exists to sequence. Once the MVP list in `.claude/REQUIREMENTS.md` has shipped, later work arrives as discrete items and the orchestrator reads `.claude/tasks/priority.md` for execution order instead.
80
+ Execution order comes off `.claude/tasks/priority.md` and nothing sequences work into versions. Scope stays in `.claude/REQUIREMENTS.md` as a statement of what is wanted, and it reaches the board as discrete tasks the orchestrator orders by readiness.
81
81
 
82
82
  Run one orchestrator at a time. The board is gitignored, so a second session reads none of the first one's writes and the two collide on labels and archives. No fixed number caps the worker tracks underneath it. Collision between file sets is what binds, so a candidate opens only when its files are disjoint from every track in flight, and the ceiling in practice is how many outputs one session can still review properly.
83
83
 
@@ -193,7 +193,6 @@ This section is the corpus the coverage claim is measured against: every name `a
193
193
  | `aitk:claude-intake-answer` | When an intake folder holds unread slots waiting on your decision |
194
194
  | `aitk:claude-groundwork` | When the state is unmeasured and more than one approach is live |
195
195
  | `aitk:decision-escalate` | When open decisions turn on your preference and want batching into one set |
196
- | `aitk:claude-roadmap` | When MVP scope needs sequencing into ordered versions |
197
196
  | `aitk:claude-tasks` | When a decided item needs a file on the board, or a shipped one needs archiving |
198
197
  | `aitk:claude-feature` | When the approach is settled and the next step is a plan |
199
198
 
@@ -17,10 +17,10 @@ order, port collisions), see [Claude Code and git worktrees](../wiki/claude/clau
17
17
 
18
18
  The split is by vantage, not by capability. Both are Claude Code sessions.
19
19
 
20
- | Role | Session | Owns | Does not |
21
- | ------------ | ------------------------------------- | ---------------------------------------------- | ----------------------------- |
22
- | Orchestrator | One warm, long-lived session | Roadmap, planning, deep PR review, merge order | Edit tracked files, merge PRs |
23
- | Worker | One cold worktree session per feature | Implement, self-check, open PR | Question the plan, merge |
20
+ | Role | Session | Owns | Does not |
21
+ | ------------ | ------------------------------------- | ------------------------------------- | ----------------------------- |
22
+ | Orchestrator | One warm, long-lived session | Planning, deep PR review, merge order | Edit tracked files, merge PRs |
23
+ | Worker | One cold worktree session per feature | Implement, self-check, open PR | Question the plan, merge |
24
24
 
25
25
  The orchestrator is worth asserting explicitly at the start of a session with
26
26
  `claude-orchestrate`, which loads the loop and its boundaries. It is framing and
@@ -36,13 +36,12 @@ and no later session recovers that vantage.
36
36
 
37
37
  One feature travels this path end to end.
38
38
 
39
- 1. Orchestrator captures a needed roadmap draft or resequence in the plan or a task file, naming `.claude/REQUIREMENTS.md` as the scope source, and a worker runs `claude-roadmap` in its branch so the tracked edit ships in a PR. The skill stops when that file carries a later scope section, since the MVP list it sequences has shipped and a fresh requirements pass owns what follows.
40
- 2. Orchestrator plans the next feature with `claude-feature`, writing a plan to `.claude/plans/`. Planning stays in the warm session because good planning is cross-feature. It needs the contract other features consume and the shared wiring seam. A cold session would re-derive or guess.
41
- 3. The human opens a worker worktree with `claude-worktree` and runs `claude-autoship` against the plan. The worker builds, self-checks, opens a PR, and stops at the PR boundary.
42
- 4. Orchestrator reviews the PR with `claude-pr-review` and posts findings to it.
43
- 5. Orchestrator tells the session holding that branch to run `claude-address-review` once the pass posted a finding at any severity, resolving the target then with `aitk sessions list --branch` and reporting the invocation for the human when no live session holds it. The worker addresses the findings, rebases onto `origin/main` when a sibling landed first and left the branch unable to merge, then pushes a follow-up. A pass carrying only minor findings dispatches too, since the grade runs low often enough that a floor at should-fix loses fixes a worker would have made. `claude-pr-review` states that threshold and the heading follows it, so an open heading is itself the signal to send.
44
- 6. Orchestrator closes the review out with `claude-pr-review` again. The second pass reads only the commits the follow-up added, or the worker's response alone when the follow-up added none, and posts under `## Review` when it finds anything and under `## Review closed` when it finds nothing, so a reader learns from the heading whether work is still owed and takes the merge decision from the counts on the line under it. Repeat from step 5 until a pass closes the review.
45
- 7. The human reads the result and merges. The orchestrator tells any trailing worker whose branch shares a seam with the merged one to run `claude-address-review`, which rebases whether or not the review left anything open.
39
+ 1. Orchestrator plans the next feature with `claude-feature`, writing a plan to `.claude/plans/`. Planning stays in the warm session because good planning is cross-feature. It needs the contract other features consume and the shared wiring seam. A cold session would re-derive or guess.
40
+ 2. The human opens a worker worktree with `claude-worktree` and runs `claude-autoship` against the plan. The worker builds, self-checks, opens a PR, and stops at the PR boundary.
41
+ 3. Orchestrator reviews the PR with `claude-pr-review` and posts findings to it.
42
+ 4. Orchestrator tells the session holding that branch to run `claude-address-review` once the pass posted a finding at any severity, resolving the target then with `aitk sessions list --branch` and reporting the invocation for the human when no live session holds it. The worker addresses the findings, rebases onto `origin/main` when a sibling landed first and left the branch unable to merge, then pushes a follow-up. A pass carrying only minor findings dispatches too, since the grade runs low often enough that a floor at should-fix loses fixes a worker would have made. `claude-pr-review` states that threshold and the heading follows it, so an open heading is itself the signal to send.
43
+ 5. Orchestrator closes the review out with `claude-pr-review` again. The second pass reads only the commits the follow-up added, or the worker's response alone when the follow-up added none, and posts under `## Review` when it finds anything and under `## Review closed` when it finds nothing, so a reader learns from the heading whether work is still owed and takes the merge decision from the counts on the line under it. Repeat from step 4 until a pass closes the review.
44
+ 6. The human reads the result and merges. The orchestrator tells any trailing worker whose branch shares a seam with the merged one to run `claude-address-review`, which rebases whether or not the review left anything open.
46
45
 
47
46
  There is no loop construct here. Each worker is a single build that halts at the
48
47
  PR. The merge stays a manual human gate. Reliability comes from the plan being
@@ -55,7 +54,7 @@ The worker's self-review and the orchestrator's review are not the same pass run
55
54
  twice. They differ by vantage.
56
55
 
57
56
  - Worker self-review, inside `claude-autoship`: the session that wrote the code. Its job is "did I build the plan and does it pass?" Mechanical, and structurally blind to its own misreadings, because the same misreading wrote both the code and the review. This is the green gate that decides whether the PR opens.
58
- - Orchestrator review, via `claude-pr-review`: a fresh session with cross-feature context (the roadmap, a sibling PR in flight, a downstream contract). Its job is "is this right and does it fit?" It can question the plan itself. This is the merge gate.
57
+ - Orchestrator review, via `claude-pr-review`: a fresh session with cross-feature context (the board, a sibling PR in flight, a downstream contract). Its job is "is this right and does it fit?" It can question the plan itself. This is the merge gate.
59
58
 
60
59
  They collide only if the worker also runs a deep pass. Keep the worker's review
61
60
  light and let the orchestrator own the deep, independent one. The human read at
@@ -127,19 +126,19 @@ coordination costs more than the change it was too small.
127
126
 
128
127
  ## Where work comes from
129
128
 
130
- Three tiers hold work at different altitudes.
129
+ Two tiers hold work at different altitudes.
131
130
 
132
- - Roadmap (`.claude/ROADMAP.md`): versions as themes, sequenced. Committed, low churn. Shape governed by `standards/bundled/roadmap.md`.
133
- - Tasks (`.claude/tasks/`): the active few pulled into the current turn, one file each. Gitignored, high churn. Shape governed by `standards/tasks.md`.
131
+ - Tasks (`.claude/tasks/`): the active few pulled into the current turn, one file each. Gitignored, high churn. Shape governed by `standards/tasks.md`. `priority.md` beside them carries execution order, and `backlog.md` carries what nobody is scheduling.
134
132
  - Edits: a few lines, done immediately with no ceremony.
135
133
 
136
- Pre-MVP the roadmap is the backlog, because the scope is finite and known.
137
- Post-MVP the backlog moves to tracked issues, per item, and the roadmap thins to
138
- occasional theme-setting.
134
+ Nothing above these sequences work into versions. Scope is stated in
135
+ `.claude/REQUIREMENTS.md` and reaches the board as discrete tasks, so why one
136
+ task runs before its neighbors is on its row and why one group of work runs
137
+ before another is carried nowhere at all.
139
138
 
140
139
  ## Parallelism
141
140
 
142
- The binding constraint is the human and the shared files, not the roadmap. Cap
141
+ The binding constraint is the human and the shared files, not the board. Cap
143
142
  at two or three worker tracks and split them across the stack so they do not
144
143
  collide on the same files.
145
144
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "0.108.0",
4
+ "version": "0.110.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -25,6 +25,11 @@ SANDBOX_UNDECLARED_CEILING=47
25
25
  # a new arrival against, and a config file would absorb the arrival silently.
26
26
  GOV_EXPECTED_UNREFERENCED="260-shadcn 320-tanstack-query"
27
27
 
28
+ # The retained counts the audit stage compares each run against. Spelled here
29
+ # rather than derived, because this script only ever names the file in a remedy
30
+ # a reader has to be able to open, and `aitk audits run` owns writing it.
31
+ AUDITS_BASELINE=".claude/audits/baseline.json"
32
+
28
33
  check_dependencies() {
29
34
  command -v bun >/dev/null 2>&1 || log_error "bun is not installed"
30
35
  }
@@ -209,10 +214,11 @@ seed_entry_count() {
209
214
  awk '{ total += $1 } END { print total + 0 }'
210
215
  }
211
216
 
212
- # One numeric summary key out of a coverage report. The per-scenario objects carry
213
- # neither key this is called with, so the match reaches the top level alone and
214
- # the caller does not depend on the order the keys are emitted in.
215
- sandbox_summary_field() {
217
+ # One numeric summary key out of a command's JSON record. Every caller passes a
218
+ # name the nested objects in that record do not carry, so the match reaches the
219
+ # top level alone and the caller does not depend on the order the keys are
220
+ # emitted in.
221
+ json_summary_field() {
216
222
  printf '%s' "$2" | grep -o "\"$1\":[0-9]\+" | grep -o '[0-9]\+'
217
223
  }
218
224
 
@@ -466,8 +472,8 @@ main() {
466
472
  # `|| x=""` on both, because a grep that matches nothing exits non-zero and
467
473
  # errexit would take the script down at the assignment, before the guard
468
474
  # below could name what went missing.
469
- total=$(sandbox_summary_field totalScenarios "$coverage_output") || total=""
470
- armed=$(sandbox_summary_field armedScenarios "$coverage_output") || armed=""
475
+ total=$(json_summary_field totalScenarios "$coverage_output") || total=""
476
+ armed=$(json_summary_field armedScenarios "$coverage_output") || armed=""
471
477
  if [ -z "$total" ] || [ -z "$armed" ]; then
472
478
  log_error "The coverage report carried no scenario totals, so the stage measured nothing. Run bun src/cli.ts sandbox coverage --json."
473
479
  fi
@@ -478,6 +484,68 @@ main() {
478
484
  log_info "$armed of $total scenarios declare expectations, $undeclared undeclared against a ceiling of $SANDBOX_UNDECLARED_CEILING"
479
485
  fi
480
486
 
487
+ # The three stages above gate on the three findings here that are facts, and
488
+ # this stage reports the rest. It runs the whole set anyway rather than only
489
+ # what those stages skip, because the aggregate's own value is one verdict
490
+ # over every audit, and a stage measuring a subset would report a health this
491
+ # repository never took.
492
+ #
493
+ # The duplicate walk costs 0.8s wall against roughly 4.4s of processor,
494
+ # measured on the authoring machine at 12 verbs run together. That is under
495
+ # every other stage in this script, which is what settles the open question
496
+ # about whether the pipeline can afford it.
497
+ #
498
+ # This reports and never fails. Growth in a judgment count is the thing the
499
+ # baseline exists to make visible, and failing a push on one would teach a
500
+ # contributor to route around the stage, which is the split every audit stage
501
+ # here already keeps. A fact still fails the push, at the specific stage above
502
+ # that names its own remedy.
503
+ log_step "Audit set"
504
+ local audits_output audits_status=0 audits_grown audits_shrunk audits_facts audits_unmeasured audits_absent audits_unrecorded
505
+ audits_output=$(cd "$PROJECT_ROOT" && bun src/cli.ts audits run --json 2>/dev/null) || audits_status=$?
506
+ if [ -z "$audits_output" ]; then
507
+ log_warn "Skipped, the audit set did not report (exit $audits_status)"
508
+ else
509
+ audits_grown=$(json_summary_field grown "$audits_output") || audits_grown=""
510
+ audits_shrunk=$(json_summary_field shrunk "$audits_output") || audits_shrunk=""
511
+ audits_facts=$(json_summary_field facts "$audits_output") || audits_facts=""
512
+ audits_unmeasured=$(json_summary_field unmeasured "$audits_output") || audits_unmeasured=""
513
+ audits_absent=$(json_summary_field absent "$audits_output") || audits_absent=""
514
+ audits_unrecorded=$(json_summary_field unrecorded "$audits_output") || audits_unrecorded=""
515
+
516
+ # An absent field is a record this stage cannot read, which is not the same
517
+ # as a run with nothing to report. Reading it as zero would print a clean
518
+ # line over a summary nobody parsed.
519
+ if [ -z "$audits_grown" ] || [ -z "$audits_facts" ] || [ -z "$audits_unmeasured" ]; then
520
+ log_warn "The audit record carried no summary, so this stage measured nothing. Run bun src/cli.ts audits run."
521
+ else
522
+ # An absent per-machine folder is the ordinary state here rather than a
523
+ # finding, since every one of them is gitignored and CI carries none. It
524
+ # is still stated, because a stage naming only what it measured claims a
525
+ # coverage it does not have.
526
+ if [ -n "$audits_absent" ] && [ "$audits_absent" -gt 0 ]; then
527
+ log_info "$audits_absent per-machine corpus/corpora absent, so unmeasured here by design"
528
+ fi
529
+ if [ "$audits_unmeasured" -gt 0 ]; then
530
+ log_warn "$audits_unmeasured audit(s) did not report, so the set is incomplete. Run bun src/cli.ts audits run."
531
+ fi
532
+ if [ "$audits_facts" -gt 0 ]; then
533
+ log_warn "$audits_facts audit(s) carry a finding that is a fact. The stage above names the remedy."
534
+ fi
535
+ if [ -n "$audits_unrecorded" ] && [ "$audits_unrecorded" -gt 0 ]; then
536
+ log_warn "$audits_unrecorded tracked audit(s) have no recorded floor. Take one with bun src/cli.ts audits run --record."
537
+ fi
538
+ if [ "$audits_grown" -gt 0 ]; then
539
+ log_warn "$audits_grown measure(s) grew against $AUDITS_BASELINE. Run bun src/cli.ts audits run to see which, then fix them or re-record and say why."
540
+ else
541
+ log_info "No measure grew against $AUDITS_BASELINE"
542
+ fi
543
+ if [ -n "$audits_shrunk" ] && [ "$audits_shrunk" -gt 0 ]; then
544
+ log_info "$audits_shrunk measure(s) fell against $AUDITS_BASELINE"
545
+ fi
546
+ fi
547
+ fi
548
+
481
549
  # The plugin is the second delivery path and this is the only stage gating it,
482
550
  # so the skip below is for a contributor's machine rather than for the merge
483
551
  # gate. A runner installs the CLI as a workflow step, which makes an absent