@erclx/aitk 0.67.0 → 0.69.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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-orchestrate/REQUIREMENT.md +9 -0
- package/claude/skills/claude-orchestrate/SKILL.md +13 -7
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +12 -7
- package/claude/skills/project-commands/SKILL.md +13 -5
- package/docs/agents/commands.md +1 -1
- package/docs/agents/context-audit.md +5 -1
- package/docs/agents/index.md +1 -1
- package/docs/agents/markdown-audit.md +27 -7
- package/docs/target-projects.md +2 -2
- package/package.json +1 -1
- package/scripts/core/verify.sh +34 -0
- package/src/commands/markdown.ts +27 -6
- package/src/markdown/gate.ts +28 -0
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/reference.md +1 -1
- package/tooling/claude/seeds/CLAUDE.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
|
@@ -11,6 +11,10 @@ Without this skill, the session holding the cross-feature picture starts buildin
|
|
|
11
11
|
|
|
12
12
|
The queue fails in both directions. It empties and a free worker waits, or it fills with whatever is oldest rather than with what establishes a mechanism. A plan handed over unverified is the quiet one, since it goes stale from whatever merged after it was written, and a worker that trusts its account of the tree builds against a shape that no longer exists. A second orchestrator makes all of this unrecoverable, because the board is gitignored and neither session can read the other's writes.
|
|
13
13
|
|
|
14
|
+
Refilling on a merge and on a thinning ready list leaves the window between them unwatched. A wave mid-build has merged nothing and has moved no rows, so both conditions stay silent across the whole build and the wave finishes into an empty queue, which lands planning on the critical path directly after the stretch where it would have cost nothing.
|
|
15
|
+
|
|
16
|
+
Writing those plans against the tree alone is the second half, since several branches are already changing the shape a plan describes. A plan carrying a bare path list rather than a constraint per in-flight track leaves the worker guessing which act each path forbids, which is the dangling citation the rule against bare paths already exists to prevent.
|
|
17
|
+
|
|
14
18
|
The session also writes surfaces it is told only how to read. Refilling the queue promotes and demotes rows in the priority file with no stated method, so a session invents one, and an inline rewrite exits clean when it matches nothing and leaves the board wrong with nothing reporting it. A row carrying prose where a plan pointer belongs costs a worker dispatch, because the ship chain refuses at its guard after the worktree is already open. A plan archived from a worker's own branch strands the pointer the board still carries, and the row reads as correct until someone follows it.
|
|
15
19
|
|
|
16
20
|
The ban on writing at all fails on a different axis, which is that nothing enforces it and a session weighs proportionality against it. A one-line prose correction found while orchestrating satisfies the root instruction to handle a small edit immediately and violates this rule, and a session given no statement of which one wins takes the smaller apparent cost and authors the change. That removes the independent pass the repository built to catch what a self-review misses, and the vantage does not come back, since no later session can review the change without re-deriving the context that produced it. A correction no open task owns has nowhere to go either, so the route matters as much as the ban.
|
|
@@ -19,6 +23,8 @@ Output drifts everywhere the contract stops. The specified shape covers invocati
|
|
|
19
23
|
|
|
20
24
|
The runbooks the session cannot run from memory fail on a third axis, which is where they are kept. A runbook reached by an installed path is a dependency on a channel this skill does not travel on, so a project holding the plugin and running no install follows the citation to nothing, and nothing reports the break because a missing file produces no error until someone opens the path. Every one of them therefore has to ship inside the skill, the three covering the moments the loop cannot detect and the fourth holding the review trigger. That fourth one fails on an axis of its own, since it names one client's command as the way to start the loop, so a session holding a different recurring-prompt scheduler reaches no path and a client without that command reaches none either, and the file ships to every target holding the plugin.
|
|
21
25
|
|
|
26
|
+
The session also records nothing of what it learns. Both other callers of memory capture are ship-chain skills and this one never ships, so the session taking every operator correction is the session with no moment that writes one down. Hanging that moment on the merge sweep answers it and bills the operator a capture pass per batch of merges while nothing is being built, which is a cost paid on the days shipping is fastest.
|
|
27
|
+
|
|
22
28
|
## Must
|
|
23
29
|
|
|
24
30
|
- Read the priority file for execution order, since the index sorts by filename and states no order
|
|
@@ -28,11 +34,14 @@ The runbooks the session cannot run from memory fail on a third axis, which is w
|
|
|
28
34
|
- Place every finding a merged pull request produced against the surface that owns it
|
|
29
35
|
- Date the roadmap line from that file's last commit, so an old sequence reads as old
|
|
30
36
|
- Keep one planned, non-conflicting task in reserve beyond what is running
|
|
37
|
+
- 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
|
|
38
|
+
- 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
|
|
31
39
|
- Write the priority file with an editing tool that errors on a non-match, since the board is where a silent failure costs a dispatch
|
|
32
40
|
- Carry a plan pointer in the Plan column and a file set in the Touches column, so a row's readiness and disjointness claims stay checkable
|
|
33
41
|
- Re-resolve the board's plan pointers after any archive, since the archiving skill rewrites the task file and knows nothing about the board
|
|
34
42
|
- Lead a sweep report, a board report, and an analysis with the state, the open decisions, and the next action, keeping the evidence below them
|
|
35
43
|
- Write the pre-compact handoff with what no other file carries, and name the runbook that reads it back
|
|
44
|
+
- Capture what the session learned at the handoff rather than in the merge sweep, and have the sweep report the debt dated from the last handoff, since a capture per batch of merges bills the operator a wait while nothing ships and an undated row reads the same however long the debt has run
|
|
36
45
|
- Carry every runbook the session cannot run from memory inside the skill, so each citation resolves for a project holding the plugin and nothing else
|
|
37
46
|
- State which rule wins where the tracked-file ban collides with the root instruction on small edits, and where a correction no open task owns goes
|
|
38
47
|
- State the review trigger as a recurring prompt rather than as one client's command, since the runbook ships to targets running whatever client they run
|
|
@@ -35,7 +35,7 @@ Then output the state of play so the human knows what to launch, review, and mer
|
|
|
35
35
|
|
|
36
36
|
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.
|
|
37
37
|
|
|
38
|
-
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. On a request to write the handoff or save the session, read `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` and follow it. It writes `.claude/tasks/session.md` with the state of play, the decisions taken under delegated authority, the mistakes worth not repeating, and the standing cautions. On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
|
|
38
|
+
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. On a request to write the handoff or save the session, read `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` and follow it. It captures what the session learned, then writes `.claude/tasks/session.md` with the state of play, the decisions taken under delegated authority, the mistakes worth not repeating, and the standing cautions. That capture is the only one this session runs, since the refill sweep reports it as owed rather than paying it. On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
|
|
39
39
|
|
|
40
40
|
The review trigger takes the same shape. `references/orchestrator-poll.md` holds the loop prompt and the condition under which the poll runs, and `scripts/poll.sh` is what the prompt invokes. A session holding a recurring-prompt scheduler starts and cancels that loop itself, and no hook or check does, so the condition holds only while whoever holds the loop applies it.
|
|
41
41
|
|
|
@@ -94,13 +94,15 @@ Write no shape for a correction. A correction is a sentence, and a format for ad
|
|
|
94
94
|
## The loop
|
|
95
95
|
|
|
96
96
|
1. Own the roadmap while a scope exists to sequence. 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. Stop owning it once that list has shipped, since later work then arrives as discrete items rather than as versions.
|
|
97
|
-
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.
|
|
97
|
+
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.
|
|
98
98
|
3. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
|
|
99
99
|
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.
|
|
100
100
|
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.
|
|
101
101
|
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. 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. It routes a moved or answered pull request straight to a re-review and reports an opened one without acting, which keeps every first pass a batched judgment this session triggers.
|
|
102
102
|
7. Close the loop. After the worker runs `claude-address-review`, re-review if needed, then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
|
|
103
103
|
|
|
104
|
+
A plan written here is written against a tree several branches are already changing, so it names the file set of every track in flight as a constraint, one set per track, read from the Touches column of that track's row. State for each set which of the two acts it forbids, per Constraints in `.claude/standards/plan.md`, or `${CLAUDE_SKILL_DIR}/../../standards/plan.md` when the project does not have it. A bare path list leaves the worker guessing, which is how a plan ends up forbidding the repair of a citation the change broke.
|
|
105
|
+
|
|
104
106
|
## Boundaries
|
|
105
107
|
|
|
106
108
|
- 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.
|
|
@@ -114,11 +116,13 @@ The tracked-file boundary collides with `CLAUDE.md`, which says to handle a smal
|
|
|
114
116
|
|
|
115
117
|
## Refilling the ready queue
|
|
116
118
|
|
|
117
|
-
Keep enough planned, non-conflicting tasks available that a free worker never waits, and place the findings the last merge produced before promoting anything new. Run this after every merge
|
|
119
|
+
Keep enough planned, non-conflicting tasks available that a free worker never waits, and place the findings the last merge produced before promoting anything new. Run this after every merge, whenever the ready list thins, and whenever a wave is in flight with fewer unclaimed plans than there are workers building. `${CLAUDE_SKILL_DIR}/references/orchestrator-sweep.md` wraps this procedure for a batch of merges and adds the plan re-verification that a merge invalidates.
|
|
120
|
+
|
|
121
|
+
The third trigger reaches a window the first two cannot. A session with three workers mid-build has merged nothing and has watched its ready list sit still, so both reactive triggers stay silent across the one stretch where planning costs the session nothing, and the wave finishes into an empty `## Run now`. Nothing starts this pass, in the way nothing starts the review poll, so it holds only while the session applies it.
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
It counts unclaimed plans against workers rather than reading the reserve in step 4, which is sized for one worker finishing and falls short of a wave landing together. A plan a worker has already taken serves nobody who finishes next, so counting it is what lets the queue read full while it is about to empty. How many to write forward past that floor is the parallelism call rather than a count of free slots, and `## Parallelism` below states what binds it.
|
|
120
124
|
|
|
121
|
-
|
|
125
|
+
### Running the refill
|
|
122
126
|
|
|
123
127
|
1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
|
|
124
128
|
2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
|
|
@@ -126,10 +130,10 @@ Capture is told this session does not commit, so it skips routing and writes mem
|
|
|
126
130
|
4. Read `.claude/tasks/priority.md` and count entries under its `## Run now` heading that carry a written plan. Keep one in reserve beyond what is running.
|
|
127
131
|
5. Promote by whether a task establishes functionality rather than by age. Prefer a task that adds or proves a mechanism over one that trims, tidies, or audits an existing surface.
|
|
128
132
|
6. Before promoting a candidate, list the files it touches against every task already running, per Parallelism below. Name the overlap and serialize when the sets are not disjoint.
|
|
129
|
-
7. Write a plan for each newly promoted task with `claude-feature`, then report:
|
|
133
|
+
7. Write a plan for each newly promoted task with `claude-feature`, carrying the in-flight constraint that The loop above states, then report:
|
|
130
134
|
|
|
131
135
|
```plaintext
|
|
132
|
-
|
|
136
|
+
Capture: owed since <the last handoff, or session start when none has run>
|
|
133
137
|
Findings placed: <finding> → <destination>
|
|
134
138
|
Archived: <task>
|
|
135
139
|
Promoted: <task>, touches <surfaces>, parallel with <task> because <disjoint sets>
|
|
@@ -137,6 +141,8 @@ Serialized: <task> behind <task>, both write <file>
|
|
|
137
141
|
Ready now: <tasks with plans, and what each waits on>
|
|
138
142
|
```
|
|
139
143
|
|
|
144
|
+
The capture row states a standing debt rather than a per-run result. Running capture from here costs the operator a pass between merges while nothing ships, so the row leaves the timing to them and dates the debt, since a capture owed for twenty minutes and one owed all day want different answers and undated text reads the same either way. `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` holds the step that pays it.
|
|
145
|
+
|
|
140
146
|
That block is the detail. Lead the reply with the three slots under Every later turn above, so the human reads what they own before the evidence for it.
|
|
141
147
|
|
|
142
148
|
Treat a task that edits `.claude/context/` entries wholesale as conflicting with every other task, because the root instruction file requires each task to update its own domain entry as it lands.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Orchestrator handoff runbook
|
|
3
|
-
description:
|
|
3
|
+
description: Memory capture at the close of a session, what to write to .claude/tasks/session.md before a compaction, and what to leave to the board
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Capture what the session learned, then write the pre-compact handoff as orchestrator. Do both before a compaction, because a compaction keeps conclusions and drops the reasoning that produced them, and no other file in the repository carries that reasoning.
|
|
7
7
|
|
|
8
|
-
1.
|
|
9
|
-
2.
|
|
10
|
-
3.
|
|
8
|
+
1. Invoke `aitk:claude-memory-capture` and tell it this session does not commit. Capture reads the session and this handoff summarizes it, so capturing first lets the handoff cite what was written instead of restating the same lesson in prose.
|
|
9
|
+
2. Resolve the main worktree root with `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. Write `.claude/tasks/session.md` under it.
|
|
10
|
+
3. Write only what a compaction destroys and no other file already carries. The board holds the ordering and what each task waits on, a task file holds its own findings, and a groundwork folder holds its track.
|
|
11
|
+
4. Use this shape:
|
|
11
12
|
|
|
12
13
|
```markdown
|
|
13
14
|
---
|
|
@@ -36,7 +37,11 @@ description: <what the board cannot show, and the date it was written>
|
|
|
36
37
|
<commands that lie, tools that measure the wrong tree, and anything unbacked>
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
5. Cite a commit, a task, or a file and line for every claim, so the next session can tell a read from a recall.
|
|
41
|
+
6. Overwrite the previous handoff rather than appending to it. A stale entry read as current is worse than no handoff.
|
|
41
42
|
|
|
42
43
|
Add a section only for content that fits none of the four and would otherwise be lost. Do not restate the board, and do not summarize the work that shipped, because git already carries it.
|
|
44
|
+
|
|
45
|
+
Step 1 exists because both other callers of capture are ship-chain skills and this session never ships. Without a call here, the session that receives every operator correction is the one session that records none. A compaction arriving with no warning takes the capture with it, and firing it once per batch of merges leaves the same window open across a long planning stretch, since a sweep runs only on a merge. The refill sweep reports the debt between handoffs so the operator knows one is owed.
|
|
46
|
+
|
|
47
|
+
Capture is told this session does not commit, so it skips routing and writes memory files alone. A routed fact lands in a context entry, which is a tracked file, and the orchestrator's boundaries forbid writing one from this session. That split is correct rather than a limitation, since a domain fact belongs to the task that owns the surface and goes in that task's Findings, while what this session produces is feedback about how to work, which is the class the memory folder keeps.
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: project-commands
|
|
3
|
-
description: Runs a command the project documents in
|
|
3
|
+
description: Runs a command the project documents in its development context entry and stops there. Use when asked to "start the app", "start the dev server", "run the checks", "run the build", "spin it up", or "what commands does this project have". Do NOT use to confirm a change works in a running app, which needs verification past the launch. Do NOT use to deploy, publish, or release.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Project commands
|
|
7
7
|
|
|
8
|
-
Read
|
|
8
|
+
Read the project's development context entry, run the command the user named, report where it landed, and stop.
|
|
9
9
|
|
|
10
10
|
The value is the stop. A launch that continues into log inspection, browser checks, or unrelated defects is the failure this skill exists to avoid.
|
|
11
11
|
|
|
12
12
|
## Guards
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- Resolve the entry before anything else. Take the flat `development.md` under `.claude/context/` when it exists, and `.claude/context/development/overview.md` when the domain outgrew one file and split into a folder, which is where the `## Scripts` table lands in a split. Test both paths, then read one. If neither resolves, stop with the line below and let the user decide. Do not read another file to reconstruct it, because a guess is worse than a stop when the user cannot see it was a guess.
|
|
15
15
|
- If the entry documents no command matching the request, stop and list what it does document. Do not infer a command from a filename or a framework.
|
|
16
16
|
- If the resolved command has an effect that outlives the process and stopping it does not undo, print it for the user to run and stop. Deploying, publishing, releasing, migrating, and resetting are the common shapes, and the test is the effect rather than the name. A script called `infra:apply` or `promote` qualifies.
|
|
17
17
|
|
|
18
|
+
The stop names the flat path in both cases, since a project carrying neither has no entry to point at and the flat one is where a project without a split keeps it:
|
|
19
|
+
|
|
20
|
+
```plaintext
|
|
21
|
+
❌ No .claude/context/development.md. This project has no documented dev loop.
|
|
22
|
+
```
|
|
23
|
+
|
|
18
24
|
## Step 1: read the entry
|
|
19
25
|
|
|
20
|
-
Read
|
|
26
|
+
Read the path the guard resolved, from the project root, the whole entry rather than a named section. That file and no others. A second file is a discovery chain, and this skill has none. Testing two candidate paths is not one, since the test happens before any read and exactly one file is opened.
|
|
27
|
+
|
|
28
|
+
A split domain keeps its other sub-area files out of reach on purpose. `overview.md` carries the run commands, and the siblings beside it cover verification stages, hooks, and scratch, none of which this skill runs.
|
|
21
29
|
|
|
22
30
|
## Step 2: resolve the command
|
|
23
31
|
|
|
@@ -67,7 +75,7 @@ One block per command when the request resolved to more than one.
|
|
|
67
75
|
For a request with no command to run, list what the entry documents instead:
|
|
68
76
|
|
|
69
77
|
```plaintext
|
|
70
|
-
📋 Documented in
|
|
78
|
+
📋 Documented in <the entry path the guard resolved>
|
|
71
79
|
|
|
72
80
|
- `<command>`: <purpose as the entry states it>
|
|
73
81
|
```
|
package/docs/agents/commands.md
CHANGED
|
@@ -33,7 +33,7 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
|
|
|
33
33
|
| `aitk records validate` | Report a session record against the standard governing it, per kind (`--json`) |
|
|
34
34
|
| `aitk comments scan` | Measure comment density by language and comment kind, with a trend recomputed from git |
|
|
35
35
|
| `aitk context audit` | Report required sections, length, cited paths, catalog tables, provenance, superseded-decision narration, and index drift |
|
|
36
|
-
| `aitk markdown audit` |
|
|
36
|
+
| `aitk markdown audit` | Fail any markdown path on a banned character, word, or spelling, and report the structural checkpoints |
|
|
37
37
|
| `aitk claude skills audit` | Report both skill corpora against the mechanical rules in `standards/skill.md` |
|
|
38
38
|
| `aitk capture [source]` | Render HTML capture sources to PNG, toolkit-only and absent from an installed package |
|
|
39
39
|
|
|
@@ -74,6 +74,10 @@ The citation check resolves every path into an audited folder that appears anywh
|
|
|
74
74
|
|
|
75
75
|
Three exclusions keep it from firing on prose about paths. Fenced blocks are skipped in markdown, which covers a standard displaying a path as an example. Fixture and harness trees are skipped by location, covering sandbox scenarios that describe their own scratch tree, the eval harness naming its target project, and `*.test.ts`. A path into a folder the project does not carry is skipped, so a skill directing a reader to `.claude/wireframes/index.md` stays valid in a project that has wireframes and silent in one that does not.
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
Two cases remain, and no syntax separates either from a real reference. One is a sentence naming a hypothetical entry to show the shape of a name. The other is a line instructing a target project about its own tree, which resolves against the target rather than against this repository and passes here only while the two layouts agree. Splitting a seeded domain into a folder ends that agreement and turns every such line red at once.
|
|
78
|
+
|
|
79
|
+
Append `<!-- audit-ignore-citations -->` to the source line in either case. The marker suppresses citation checking for its own line only.
|
|
80
|
+
|
|
81
|
+
The marker itself stays out of anything that installs. A seed, a plugin skill body, and a stack reference all reach a target, so a marker there lands as toolkit bookkeeping in someone else's tree. Reword those lines to drop the path instead, and where a stop message has to spell it, move that message into a fenced block, which this check already skips.
|
|
78
82
|
|
|
79
83
|
The pattern spells the `.claude/` prefix, so a folder resolved at the project root is measured by every other check and contributes nothing here. Widening it to a bare `docs/x.md` would match prose that references nothing, which is a separate decision from where entries come from. A run whose folders all resolved at the root says the check is out of scope rather than reporting that zero paths resolved, and the same run under `--citations-only` refuses, because a gate exiting clean on a scope it could not build is the failure the gate exists to catch.
|
package/docs/agents/index.md
CHANGED
|
@@ -16,7 +16,7 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
16
16
|
- [Docs](docs.md): How aitk docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
|
|
17
17
|
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for aitk indexes regen, plus when it auto-stages what it rewrote
|
|
18
18
|
- [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
|
|
19
|
-
- [Markdown audit](markdown-audit.md): Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why
|
|
19
|
+
- [Markdown audit](markdown-audit.md): Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why the ban half gates while the structural half reports
|
|
20
20
|
- [Output shape](output-shape.md): Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
|
|
21
21
|
- [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
|
|
22
22
|
- [Records](records.md): Validating the gitignored session records under .claude/, the per-kind checks, the refusal reasons, and why the root defaults to the main worktree
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Markdown audit
|
|
3
|
-
description: Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why
|
|
3
|
+
description: Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why the ban half gates while the structural half reports
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Markdown audit
|
|
@@ -49,7 +49,7 @@ Two ban shapes stay unmeasured and the report says so on every run. A phrase ban
|
|
|
49
49
|
|
|
50
50
|
### Bullets, paragraphs, and depth
|
|
51
51
|
|
|
52
|
-
Bullet weight and depth are the checks that moved off `aitk context audit`, unchanged in what they measure. A top-level bullet reports past roughly 400 characters with continuation lines folded in and nested items left out. A run of lines no heading breaks reports past roughly 40 rendered lines, measured at 80 columns, skipping fenced blocks and exempting a flat peer list averaging under 130 characters a bullet and a run that is entirely table rows.
|
|
52
|
+
Bullet weight and depth are the checks that moved off `aitk context audit`, unchanged in what they measure. A top-level bullet reports past roughly 400 characters with continuation lines folded in and nested items left out. A run of lines no heading breaks reports past roughly 40 rendered lines, measured at 80 columns, skipping fenced blocks and exempting a flat peer list averaging under 130 characters a bullet and a run that is entirely table rows. Each file reports its longest run alone, so a second run past the checkpoint in the same file is never named.
|
|
53
53
|
|
|
54
54
|
Every weight and depth measure counts the text a reader is shown. A link reduces to its anchor text and an autolink drops whole, since no reader is shown either destination. A backticked path stays counted, which is where these measures part from the ban scan above: that one blanks a code span so a standard quoting its own banned character does not report itself, and discounting the same span here would under-report a paragraph carrying several. One file holds both span sets and each answers its own question.
|
|
55
55
|
|
|
@@ -82,13 +82,33 @@ A bullet, a heading, a table row, a blockquote, a blank line, and a fence each e
|
|
|
82
82
|
|
|
83
83
|
## Exit codes
|
|
84
84
|
|
|
85
|
-
Exit codes are `0` for a completed run
|
|
85
|
+
Exit codes are `0` for a completed run with no gating finding, `1` for a refusal, and `2` for a ban hit. A banned character, word, or spelling fails the run. Bullet, paragraph, and depth weight are judgments a reader settles, so all three report under every code.
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
`2` rather than `1` for the gate keeps a measurement that succeeded and found something distinct from the audit declining to measure at all. A caller reading one as the other sends a reader hunting a defect that does not exist, which is the distinction `aitk context audit` and the `verify.sh` seed stage already draw between the same two codes.
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
A banned character is a fact rather than a judgment, which is the test that admits it to a gate. What held it back was that gating on day one against a corpus never checked mechanically fails loudly on work nobody has had a chance to fix. The order was to land the verb reporting, measure the corpus once, fix what it finds, and turn the gate on as its own change, and the gate is the last of the four.
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Measured at `4b7b13a2` across 444 files with the paragraph checkpoint at 600: 8 word hits, no character or spelling hits, 119 heavy bullets, 221 heavy paragraphs across 86 files, and 41 files carrying a run past the depth checkpoint. Of the paragraphs, 88 fire on weight alone. This is the baseline the corpus sweep tracked its work against. The ban count is what the gate holds at zero, and it is the only one of the five a gate should ever read.
|
|
92
|
+
|
|
93
|
+
The ban half of that baseline reached zero, which was the precondition the gate waited on, and it was re-measured against the same corpus at the moment the gate landed. The other four moved with the corpus rather than with any decision, so read them from a run rather than from this paragraph.
|
|
94
|
+
|
|
95
|
+
### What a hit asks of an author
|
|
96
|
+
|
|
97
|
+
Rewrite the sentence rather than swapping the banned token for a near-synonym. The rule is about the sense the token carries, so a swap that keeps the sense clears the report without clearing the violation.
|
|
98
|
+
|
|
99
|
+
A code span clears the report too, since the ban scan walks around one, and it is the answer only where the token is genuinely an identifier under discussion. `## Code and identifiers` in `markdown.md` reserves the span for commands, API names, file paths, and identifiers, so backticking a quoted utterance spends one rule to satisfy another and leaves the corpus no cleaner.
|
|
100
|
+
|
|
101
|
+
A hit the closed set cannot separate from correct prose is the case with no third option. `prose.md` bans vague qualifiers and lists the tokens those qualifiers happen to spell, so the temporal `just` reports as the vague one. The rule as written reaches neither, and rewriting the sentence is what the toolkit settled on over building an exemption path, for the reasons below.
|
|
102
|
+
|
|
103
|
+
### Where the rules are enforced
|
|
104
|
+
|
|
105
|
+
Four surfaces read the ban sets and two of them go through this verb. `.claude/hooks/standards-audit.sh` runs it against a single file after each markdown edit, and the `Markdown bans` stage in `scripts/core/verify.sh` runs it across the whole corpus before a push. The hook parsed its own copy of the word bans in awk until the gate landed, which left a British spelling passing at edit time and failing the push with nothing in between explaining the difference.
|
|
106
|
+
|
|
107
|
+
The other two read the standards directly and neither is a consolidation left half done. `claude/skills/claude-standards-audit/SKILL.md` greps the banned tokens agent-side, which is a session reading prose rather than a process it can shell out to, and it ships to every target. The seed copy of the hook keeps its awk, because a scaffolded project may carry no `aitk` and `scripts/core/check-seed-independence.sh` exists to catch seed content depending on the toolkit CLI. Both are the likelier place for the next drift, since nothing compares either against the verb.
|
|
108
|
+
|
|
109
|
+
The hook prefers a checkout's own `src/cli.ts` over a globally installed binary, so it and the push stage read one build. A published binary lags a branch by whatever has not been released, which would put a ban kind added on the branch into the push and not into the edit. It reads its findings out of the `--json` record rather than off the exit code, so an older binary still reports where the fallback applies. A machine with neither runner gets no enforcement at edit time rather than a blocked edit, and the push stage still holds.
|
|
110
|
+
|
|
111
|
+
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a standard bans a token retroactively, and no file in the push that adds the bullet was edited.
|
|
92
112
|
|
|
93
113
|
### Why a recorded count goes stale
|
|
94
114
|
|
|
@@ -106,7 +126,7 @@ The other five were correct prose the closed set cannot separate from a violatio
|
|
|
106
126
|
|
|
107
127
|
### Why they were rewritten rather than exempted
|
|
108
128
|
|
|
109
|
-
Rewriting all five is what settled them, over building an exemption path. An exemption has three consumers, `src/markdown/scan.ts` for the patterns, `src/markdown/bans.ts` for the sets, and `.claude/hooks/standards-audit.sh`, which
|
|
129
|
+
Rewriting all five is what settled them, over building an exemption path. An exemption has three consumers, `src/markdown/scan.ts` for the patterns, `src/markdown/bans.ts` for the sets, and `.claude/hooks/standards-audit.sh`, which held its own copy of the word bans in awk at that point. A mechanism landing in the verb and not the hook leaves an exempted line still failing on edit, which is the surface an author actually meets. Five sentences lost a small amount of naturalness and the count now means what it says.
|
|
110
130
|
|
|
111
131
|
A code span was the first answer for the quoted anti-pattern and it was the wrong one. The ban scan walks around a code span, so backticking a quotation clears the report, and `## Code and identifiers` reserves the span for commands, API names, file paths, and identifiers, which a quoted utterance is none of. Spending one rule to satisfy another leaves the corpus no cleaner than dropping the qualifier does.
|
|
112
132
|
|
package/docs/target-projects.md
CHANGED
|
@@ -46,10 +46,10 @@ The chain is:
|
|
|
46
46
|
|
|
47
47
|
- `aitk init` installs base tooling, Claude seeds, and governance rules into `.claude/rules/` in the same pass
|
|
48
48
|
- `aitk tooling sync <stack>` adds stack-specific deps, scripts, gitignore entries, and drops `.claude/tooling/<stack>.md` (plus parents) as the agent's audit context
|
|
49
|
-
- The agent follows the reference to generate eslint, vitest, playwright configs and the stack's setup script, and extends `.claude/context/ci.md` and `.claude/context/development.md` per the reference's extend sections
|
|
49
|
+
- The agent follows the reference to generate eslint, vitest, playwright configs and the stack's setup script, and extends `.claude/context/ci.md` and `.claude/context/development.md` per the reference's extend sections <!-- audit-ignore-citations -->
|
|
50
50
|
- `setup-verify` runs the installed `package.json` scripts (lint, typecheck, check, test, build) and reports pass or fail
|
|
51
51
|
|
|
52
|
-
Keep the `## Scripts` table in `.claude/context/development.md` current as scripts are added. Base tooling seeds that entry with the commands it installs, and each stack reference extends the table. `project-commands` reads it to start the app or run a check on request, so a command missing from the table cannot be run that way.
|
|
52
|
+
Keep the `## Scripts` table in `.claude/context/development.md` current as scripts are added. Base tooling seeds that entry with the commands it installs, and each stack reference extends the table. `project-commands` reads it to start the app or run a check on request, so a command missing from the table cannot be run that way. A project whose entry outgrew one file and split into `.claude/context/development/` keeps the table in `overview.md`, which is where the skill looks next. <!-- audit-ignore-citations -->
|
|
53
53
|
|
|
54
54
|
### From scaffold to first feature
|
|
55
55
|
|
package/package.json
CHANGED
package/scripts/core/verify.sh
CHANGED
|
@@ -272,6 +272,40 @@ main() {
|
|
|
272
272
|
run_check "cd $PROJECT_ROOT && bun src/cli.ts context audit --citations-only" "A cited context path does not resolve. Run bun src/cli.ts context audit."
|
|
273
273
|
log_info "Context citations resolve"
|
|
274
274
|
|
|
275
|
+
# A banned character, word, or spelling is a fact rather than a threshold, so
|
|
276
|
+
# it fails the push while bullet, paragraph, and depth weight stay advisory
|
|
277
|
+
# for the reason the stage above leaves its own thresholds so.
|
|
278
|
+
#
|
|
279
|
+
# The whole corpus is measured rather than the changed files, because a
|
|
280
|
+
# `Do not use` bullet added to a standard bans a token retroactively and no
|
|
281
|
+
# file in the push that adds it was edited.
|
|
282
|
+
#
|
|
283
|
+
# `--json` sends the record to stdout and the frame to stderr, so a passing
|
|
284
|
+
# run stays silent and a failing one is re-run for its frame rather than
|
|
285
|
+
# parsed out of a stream this script would have to strip. `bun src/cli.ts`
|
|
286
|
+
# rather than `aitk` for the reason the stage above uses it.
|
|
287
|
+
log_step "Markdown bans"
|
|
288
|
+
local ban_status=0 ban_frame
|
|
289
|
+
(cd "$PROJECT_ROOT" && bun src/cli.ts markdown audit --json >/dev/null 2>&1) || ban_status=$?
|
|
290
|
+
case $ban_status in
|
|
291
|
+
0)
|
|
292
|
+
log_info "No banned character, word, or spelling"
|
|
293
|
+
;;
|
|
294
|
+
1)
|
|
295
|
+
log_warn "Skipped, the markdown audit refused and measured nothing"
|
|
296
|
+
;;
|
|
297
|
+
2)
|
|
298
|
+
# `|| true` because the re-run exits non-zero by construction, and `set -e`
|
|
299
|
+
# would take the script down before log_error names the remedy.
|
|
300
|
+
ban_frame=$(cd "$PROJECT_ROOT" && bun src/cli.ts markdown audit 2>&1 || true)
|
|
301
|
+
echo "$ban_frame" | pipe_output
|
|
302
|
+
log_error "Markdown prose carries a banned character, word, or spelling. Rewrite the sentence, and reach for a code span only where the token is genuinely an identifier under discussion."
|
|
303
|
+
;;
|
|
304
|
+
*)
|
|
305
|
+
log_error "The markdown audit exited $ban_status, which is neither a pass nor a finding."
|
|
306
|
+
;;
|
|
307
|
+
esac
|
|
308
|
+
|
|
275
309
|
# The stage above audits this repository. Its seed tree ships into every
|
|
276
310
|
# scaffolded project, so a seed breaking the standard it seeds propagates
|
|
277
311
|
# instead of sitting still, and no rule path reaches the tree to report it.
|
package/src/commands/markdown.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { resolve } from 'node:path'
|
|
|
3
3
|
import type { Command } from 'commander'
|
|
4
4
|
import { type BanReport, banReport, loadStandards } from '@/markdown/bans'
|
|
5
5
|
import { resolveMarkdown } from '@/markdown/files'
|
|
6
|
+
import { isGating } from '@/markdown/gate'
|
|
6
7
|
import { type BanFinding, bodyLines, scanBans } from '@/markdown/scan'
|
|
7
8
|
import {
|
|
8
9
|
type Checkpoints,
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
plural,
|
|
21
22
|
} from '@/ui'
|
|
22
23
|
|
|
24
|
+
const EXIT_GATE = 2
|
|
25
|
+
|
|
23
26
|
interface AuditCommandOptions {
|
|
24
27
|
readonly json?: boolean
|
|
25
28
|
}
|
|
@@ -39,7 +42,7 @@ export function register(program: Command): void {
|
|
|
39
42
|
markdown
|
|
40
43
|
.command('audit')
|
|
41
44
|
.description(
|
|
42
|
-
'
|
|
45
|
+
'Fail on a banned character, word, or spelling, and report bullet, paragraph, and depth weight',
|
|
43
46
|
)
|
|
44
47
|
.argument(
|
|
45
48
|
'[path...]',
|
|
@@ -52,12 +55,18 @@ export function register(program: Command): void {
|
|
|
52
55
|
[
|
|
53
56
|
'',
|
|
54
57
|
'Exit codes:',
|
|
55
|
-
' 0 the audit completed',
|
|
58
|
+
' 0 the audit completed with no gating finding',
|
|
56
59
|
' 1 refused, with the reason on stderr',
|
|
60
|
+
' 2 a banned character, word, or spelling is present',
|
|
61
|
+
'',
|
|
62
|
+
'A ban hit is a fact and gates unconditionally. Bullet, paragraph, and',
|
|
63
|
+
'depth weight are judgments a reader settles, so all three report and',
|
|
64
|
+
'none of them fails a run.',
|
|
57
65
|
'',
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
66
|
+
'Rewrite the sentence carrying a hit rather than swapping the token for',
|
|
67
|
+
'a near-synonym. A code span clears the report and is the answer only',
|
|
68
|
+
'where the token is genuinely an identifier under discussion, which is',
|
|
69
|
+
'what markdown.md reserves the span for.',
|
|
61
70
|
'',
|
|
62
71
|
'Bans and checkpoints are read from markdown.md and prose.md, resolved',
|
|
63
72
|
'under .claude/standards/ then standards/. No folder has to resolve and',
|
|
@@ -156,7 +165,12 @@ async function runAudit(
|
|
|
156
165
|
)
|
|
157
166
|
}
|
|
158
167
|
|
|
159
|
-
|
|
168
|
+
const gating = isGating({
|
|
169
|
+
bans: reports.flatMap((report) => report.bans),
|
|
170
|
+
structure: reports.map((report) => report.structure),
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
return gating ? EXIT_GATE : 0
|
|
160
174
|
}
|
|
161
175
|
|
|
162
176
|
function refuse(message: string): number {
|
|
@@ -218,6 +232,13 @@ function reportBans(reports: readonly FileReport[], bans: BanReport): void {
|
|
|
218
232
|
|
|
219
233
|
const total = carrying.reduce((sum, report) => sum + report.bans.length, 0)
|
|
220
234
|
logWarn(`${plural(total, 'hit')} across ${plural(carrying.length, 'file')}`)
|
|
235
|
+
logWarn('This fails the run. Every other check below reports.')
|
|
236
|
+
logInfo(
|
|
237
|
+
'Rewrite the sentence rather than swapping the token for a near-synonym.',
|
|
238
|
+
)
|
|
239
|
+
logInfo(
|
|
240
|
+
'A code span clears the report and is the answer only where the token is genuinely an identifier under discussion, which is what markdown.md reserves the span for.',
|
|
241
|
+
)
|
|
221
242
|
pipeOutput(
|
|
222
243
|
carrying
|
|
223
244
|
.map(
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { BanFinding } from '@/markdown/scan'
|
|
2
|
+
import type { StructureReport } from '@/markdown/structure'
|
|
3
|
+
|
|
4
|
+
export interface GateInput {
|
|
5
|
+
/** Every ban hit across every file measured, flattened. */
|
|
6
|
+
readonly bans: readonly BanFinding[]
|
|
7
|
+
/**
|
|
8
|
+
* Every structural measure the run made, read by nothing here.
|
|
9
|
+
*
|
|
10
|
+
* Naming it is what makes the split checkable: bullet, paragraph, and depth
|
|
11
|
+
* weight are judgments a reader settles, and a push failing on one teaches a
|
|
12
|
+
* contributor to route around the stage. A signature taking the ban list
|
|
13
|
+
* alone states the same rule and leaves no place to assert it.
|
|
14
|
+
*/
|
|
15
|
+
readonly structure: readonly StructureReport[]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Whether the audit found something that should fail the caller.
|
|
20
|
+
*
|
|
21
|
+
* A banned character, word, or spelling is a fact rather than a threshold, so
|
|
22
|
+
* it gates unconditionally and there is no widened mode to reach for. The
|
|
23
|
+
* standards decide what counts as banned, which keeps this answering how many
|
|
24
|
+
* rather than which.
|
|
25
|
+
*/
|
|
26
|
+
export function isGating({ bans }: GateInput): boolean {
|
|
27
|
+
return bans.length > 0
|
|
28
|
+
}
|
|
@@ -12,7 +12,7 @@ The astro stack covers Astro + TypeScript projects: content sites, marketing sit
|
|
|
12
12
|
2. Add React integration: `bunx astro add react`. Do not use `astro add tailwind`. That command installs the v3 integration. Tailwind v4 arrives via the web manifest.
|
|
13
13
|
3. Install web tooling: `aitk tooling sync web .`
|
|
14
14
|
4. Install astro adapter: `aitk tooling sync astro .`
|
|
15
|
-
5. Extend
|
|
15
|
+
5. Extend the `ci` and `development` context entries under `.claude/context/` per the web reference's extend sections plus the astro rows below.
|
|
16
16
|
6. Run `bun run lint:fix` then `bun run check`.
|
|
17
17
|
|
|
18
18
|
## What ships as golden configs
|
|
@@ -26,7 +26,7 @@ Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and n
|
|
|
26
26
|
- `.cspell/project-terms.txt` and `.cspell/tech-stack.txt`: one word per line, sorted alphabetically.
|
|
27
27
|
- `.lintstagedrc`: the glob map below.
|
|
28
28
|
- `.prettierignore`: created empty. Projects add their own entries.
|
|
29
|
-
- `.claude/context
|
|
29
|
+
- `.claude/context/`: extend the `ci` and `development` entries with project-specific commands, workflows, or deploy steps. Canonical rationale stays in this reference.
|
|
30
30
|
|
|
31
31
|
## Tool pairing
|
|
32
32
|
|
|
@@ -11,7 +11,7 @@ The vite-react stack covers Vite + React + TypeScript projects: web apps and Chr
|
|
|
11
11
|
1. Scaffold with `bunx create-vite@latest <name> --template react-ts` (web apps) or `bunx create-crxjs@latest` (Chrome extensions).
|
|
12
12
|
2. Install base and web tooling: `aitk tooling sync web .`
|
|
13
13
|
3. Install vite-react deps and configs: `aitk tooling sync vite-react .`
|
|
14
|
-
4. Extend
|
|
14
|
+
4. Extend the `ci` and `development` context entries under `.claude/context/` per the web reference's extend sections plus the vite-react rows below.
|
|
15
15
|
5. Run `bun run lint:fix` then `bun run check`.
|
|
16
16
|
|
|
17
17
|
## What ships as golden configs
|
package/tooling/web/reference.md
CHANGED
|
@@ -78,7 +78,7 @@ Under `## Running CI locally`, document that `bun run check:full` runs verify pl
|
|
|
78
78
|
|
|
79
79
|
## Development docs (extend)
|
|
80
80
|
|
|
81
|
-
Extend `.claude/context
|
|
81
|
+
Extend the `development` context entry under `.claude/context/` so the `## Scripts` table lists every web script. Stack adapters add their `dev`, `build`, `preview`, `typecheck` rows.
|
|
82
82
|
|
|
83
83
|
Append rows:
|
|
84
84
|
|