@erclx/aitk 0.67.0 → 0.68.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 +3 -0
- package/claude/skills/claude-orchestrate/SKILL.md +4 -6
- 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 +26 -6
- 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
|
@@ -19,6 +19,8 @@ Output drifts everywhere the contract stops. The specified shape covers invocati
|
|
|
19
19
|
|
|
20
20
|
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
21
|
|
|
22
|
+
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.
|
|
23
|
+
|
|
22
24
|
## Must
|
|
23
25
|
|
|
24
26
|
- Read the priority file for execution order, since the index sorts by filename and states no order
|
|
@@ -33,6 +35,7 @@ The runbooks the session cannot run from memory fail on a third axis, which is w
|
|
|
33
35
|
- 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
36
|
- 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
37
|
- Write the pre-compact handoff with what no other file carries, and name the runbook that reads it back
|
|
38
|
+
- 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
39
|
- 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
40
|
- 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
41
|
- 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
|
|
|
@@ -116,10 +116,6 @@ The tracked-file boundary collides with `CLAUDE.md`, which says to handle a smal
|
|
|
116
116
|
|
|
117
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 and whenever the ready list thins. `${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.
|
|
118
118
|
|
|
119
|
-
Open the sweep by invoking `aitk:claude-memory-capture`. Both other callers are ship-chain skills and this session never ships, so without this the session that receives every operator correction is the one session that records none. The sweep is the closest bounded moment this session has to a ship, and it already runs once per batch of merges, which beats an end-of-session moment a compaction can cut short.
|
|
120
|
-
|
|
121
|
-
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 Boundaries below forbids writing one from here. That is the correct split rather than a limitation: 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 exactly the class the memory folder keeps.
|
|
122
|
-
|
|
123
119
|
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
120
|
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.
|
|
125
121
|
3. Archive what closed. A task whose outcomes are all `[x]` runs `claude-docs` for the plan sweep, then `claude-tasks` to archive. A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which Boundaries forbids.
|
|
@@ -129,7 +125,7 @@ Capture is told this session does not commit, so it skips routing and writes mem
|
|
|
129
125
|
7. Write a plan for each newly promoted task with `claude-feature`, then report:
|
|
130
126
|
|
|
131
127
|
```plaintext
|
|
132
|
-
|
|
128
|
+
Capture: owed since <the last handoff, or session start when none has run>
|
|
133
129
|
Findings placed: <finding> → <destination>
|
|
134
130
|
Archived: <task>
|
|
135
131
|
Promoted: <task>, touches <surfaces>, parallel with <task> because <disjoint sets>
|
|
@@ -137,6 +133,8 @@ Serialized: <task> behind <task>, both write <file>
|
|
|
137
133
|
Ready now: <tasks with plans, and what each waits on>
|
|
138
134
|
```
|
|
139
135
|
|
|
136
|
+
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.
|
|
137
|
+
|
|
140
138
|
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
139
|
|
|
142
140
|
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
|
|
@@ -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
|
|