@erclx/aitk 3.7.0 → 3.9.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": "3.7.0",
4
+ "version": "3.9.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -7,7 +7,7 @@ description: Why a project-local rule needs a band, a number checked against two
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a project rule is written straight into the rules folder on a number already taken, so two rules collide and one loses. The subtler collision is with the toolkit itself. A number free in the target today can be the number a shipped rule lands on tomorrow, and the next install double-books it, so a rule the project wrote gets overwritten by one it never chose.
10
+ Without this skill, a project rule is written straight into the rules folder on a number already taken, so two rules collide and one loses. The subtler collision was with the toolkit itself: a number free in the target today could be the number a shipped rule landed on tomorrow, and the next install double-booked it, so a rule the project wrote got overwritten by one it never chose. Writing under `.claude/rules/project/` closes that half regardless of the number, since the sync engine orphans the file by location before it ever compares names, but the band still needs a free number to stay readable against the toolkit's own numbering.
11
11
 
12
12
  The band gets picked by feel, so a UI copy rule lands in the always-on range and loads on every session for the rest of the project's life. The scope key fails in both directions. An always-on rule carrying a path scope fires only on files it was never about, and a path-scoped rule missing it loads constantly. Written from memory rather than from the rule standard, the body comes out in a shape the rest of the catalog does not share.
13
13
 
@@ -15,6 +15,7 @@ The band gets picked by feel, so a UI copy rule lands in the always-on range and
15
15
 
16
16
  - Resolve what the rule enforces and where it applies, asking only for what the request leaves missing
17
17
  - Pick the band from the topic and take its number range and folder from that choice
18
+ - Write under `.claude/rules/project/`, the subfolder the sync engine reads as project-authored by location
18
19
  - Check both the target's used prefixes and the toolkit catalog before taking a number
19
20
  - Read the rule standard before writing the body
20
21
  - Emit the path scope for a path-scoped rule and omit the key entirely for an always-on one
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: create-rule
3
- description: Scaffolds a project-specific governance rule into `.claude/rules/<subdir>/<n>-<slug>.md` with correct frontmatter and a non-colliding number. Use when asked to "add a rule", "create a governance rule", "write a project rule", or when a project needs a coding rule the toolkit does not ship. Do NOT use to edit toolkit source rules under `governance/rules/`.
3
+ description: Scaffolds a project-specific governance rule into `.claude/rules/project/<subdir>/<n>-<slug>.md` with correct frontmatter and a non-colliding number. Use when asked to "add a rule", "create a governance rule", "write a project rule", or when a project needs a coding rule the toolkit does not ship. Do NOT use to edit toolkit source rules under `governance/rules/`.
4
4
  ---
5
5
 
6
6
  # Create rule
7
7
 
8
- Author a project-local governance rule. The rule lives in the target project, not the toolkit, so it is never overwritten by `aitk gov sync` (sync skips rules with no toolkit source match).
8
+ Author a project-local governance rule. The rule lives in the target project, not the toolkit, so `aitk gov sync` never overwrites it: the sync engine orphans anything under `.claude/rules/project/` by location, before it ever checks the rule's name against the toolkit catalog.
9
9
 
10
10
  ## Guards
11
11
 
@@ -21,7 +21,7 @@ Resolve both from the request, and ask only for what is missing. Attach a propos
21
21
 
22
22
  ## Step 2: resolve band and subdir
23
23
 
24
- Pick the band from the topic. Each band owns a number range and a subdir under `.claude/rules/`:
24
+ Pick the band from the topic. Each band owns a number range and a subdir under `.claude/rules/project/`:
25
25
 
26
26
  - `core/` 000-099: global persona, testing, error handling, planning. Always-on, no `paths:`.
27
27
  - `lang/` 100-199: one programming language.
@@ -34,15 +34,15 @@ Pick the band from the topic. Each band owns a number range and a subdir under `
34
34
 
35
35
  Pick the lowest unused number in the band that collides with neither the project nor the toolkit catalog:
36
36
 
37
- - Scan the target's `.claude/rules/<subdir>/` for used prefixes.
38
- - Run `aitk gov list --json 2>/dev/null` and read the shipped rule numbers in the same range, so a later `aitk gov install` cannot double-book the number.
39
- - If `aitk` is not on PATH, scan the target only and warn that a future toolkit install could collide.
37
+ - Scan the target's `.claude/rules/project/<subdir>/` for used prefixes.
38
+ - Run `aitk gov list --json 2>/dev/null` and read the shipped rule numbers in the same range, so the band stays readable against the toolkit's own numbering even though location already keeps a later `aitk gov install` from touching this file.
39
+ - If `aitk` is not on PATH, scan the target only and warn that the band could read confusingly against a later toolkit install.
40
40
 
41
41
  ## Step 4: write the rule
42
42
 
43
43
  Read `${CLAUDE_SKILL_DIR}/../../standards/rule.md` for frontmatter, body shape, and voice before writing the body. Do not work the shape from memory.
44
44
 
45
- Write `.claude/rules/<subdir>/<n>-<slug>.md` where `<slug>` is a 1-to-3-word kebab topic. Preview the resolved path, band, number, and frontmatter, then write immediately. The tool permission dialog is the confirmation gate.
45
+ Write `.claude/rules/project/<subdir>/<n>-<slug>.md` where `<slug>` is a 1-to-3-word kebab topic. Preview the resolved path, band, number, and frontmatter, then write immediately. The tool permission dialog is the confirmation gate.
46
46
 
47
47
  Frontmatter carries the Claude shape. Path-scoped rules emit one `paths:` entry per glob. Always-on rules omit `paths:` entirely.
48
48
 
@@ -65,4 +65,4 @@ Title casing is sentence case, with proper nouns keeping their own casing (`# Ty
65
65
 
66
66
  ## After writing
67
67
 
68
- Emit the full path on its own line: `.claude/rules/<subdir>/<n>-<slug>.md`. Remind the user that Claude Code loads path-scoped rules when it reads a matching file, and always-on rules every session.
68
+ Emit the full path on its own line: `.claude/rules/project/<subdir>/<n>-<slug>.md`. Remind the user that Claude Code loads path-scoped rules when it reads a matching file, and always-on rules every session.
@@ -11,9 +11,12 @@ Without this skill, a new skill lands in the wrong shape and the wrong place. A
11
11
 
12
12
  A skill born without its requirement is the second failure, and it surfaces much later. Coverage of the corpus is what the operator reads to decide whether a skill should exist, so every skill created without the sibling decays that reading, and the sweep that closes the gap has to reconstruct what the skill was for from the body it already shipped.
13
13
 
14
+ A third failure is a folder created for a moment a rule, a verb, or an existing skill already reaches, or for a procedure no session would get wrong from first principles. Nothing caught that before the folder existed, so the corpus grew by a skill an inward audit later had to argue for removing, with only a commit body recording the argument.
15
+
14
16
  ## Must
15
17
 
16
18
  - Read the authoring standard and the prose standard before drafting, so the draft starts conformant rather than getting corrected into shape
19
+ - Answer, in writing, whether a rule, a verb, or an existing skill already reaches this moment, and whether the body carries a procedure a session would get wrong from first principles. A folder that fails either belongs to the surface that already covers it, not to a new skill.
17
20
  - Draft the sibling `REQUIREMENT.md` beside the body, from what the skill is for rather than from the drafted body
18
21
  - Confirm the name and both files with the user before writing. The name is the routing key and a folder that disagrees with its frontmatter fails silently.
19
22
  - Write to the conventional skills path, so discovery finds it without configuration
@@ -23,6 +26,7 @@ A skill born without its requirement is the second failure, and it surfaces much
23
26
  - Auto-trigger. Creation is a deliberate act and a skill invented from an ambiguous request is worse than none.
24
27
  - Write either file before the user has seen it
25
28
  - Derive the requirement from the drafted body, which records the draft's overfitting as the requirement
29
+ - Gate creation on whether anything will invoke the new skill beyond the author typing its name. That question has no answer yet.
26
30
 
27
31
  ## Guards
28
32
 
@@ -31,4 +35,4 @@ A skill born without its requirement is the second failure, and it surfaces much
31
35
  ## Out of scope
32
36
 
33
37
  - Editing an existing skill, which the authoring standard and the skill's own requirement govern
34
- - Judging whether the skill is warranted. A skill nobody needed is an audit finding, not a creation-time refusal.
38
+ - Whether anything ends up invoking the new skill: the usage census in `.claude/context/claude-plugin/skill-strategy.md`, read once the skill has run
@@ -18,9 +18,15 @@ Read these files in parallel:
18
18
 
19
19
  ## Steps
20
20
 
21
- 1. Draft the full `SKILL.md` from the user's description
22
- 2. Draft the sibling `REQUIREMENT.md` from what the skill is for, in the shape the standard states. Write the gaps from the user's description rather than from the drafted body, since a requirement derived from the body records whatever the draft overfitted to.
23
- 3. Confirm the skill name and both files with the user before writing
24
- 4. Write to `.claude/skills/<name>/SKILL.md` and `.claude/skills/<name>/REQUIREMENT.md`
21
+ 1. Answer three questions in writing before drafting anything. Tell the user and stop if a rule, a verb, or an existing skill already reaches this moment, or if the body carries no procedure a session would get wrong from first principles:
22
+ - Does a rule, a verb, or an existing skill already reach this moment? A folder that only wraps something already reachable duplicates it rather than adding to the catalog.
23
+ - Does the body carry a procedure a session would get wrong from first principles? A one-line wrapper around a single command needs no skill.
24
+ - Will anything invoke it other than the author typing its name? Carry this one into the drafted `REQUIREMENT.md`'s `Must not` section as a review criterion instead, since nothing can answer it before the skill has run.
25
+ 2. Draft the full `SKILL.md` from the user's description
26
+ 3. Draft the sibling `REQUIREMENT.md` from what the skill is for, in the shape the standard states. Write the gaps from the user's description rather than from the drafted body, since a requirement derived from the body records whatever the draft overfitted to.
27
+ 4. Confirm the skill name and both files with the user before writing
28
+ 5. Write to `.claude/skills/<name>/SKILL.md` and `.claude/skills/<name>/REQUIREMENT.md`
25
29
 
26
30
  Every skill carries a requirement. A skill created without one is a gap someone closes in a later sweep, and the sweep has to reconstruct what the skill was for from the body it already shipped.
31
+
32
+ The two-question check has a shipped precedent. Pull request `#516` dropped `git-stash` for wrapping a single git command that needed no skill body, and `release-changelog` for being low-frequency and invoked by no other skill. The first is question one, and the second is question three read back after the fact, which is why it stays a review criterion rather than something this skill can gate on.
@@ -11,10 +11,13 @@ Without this skill, a snippet is drafted the way any other markdown file is draf
11
11
 
12
12
  The write surface is the second failure. The toolkit authors at `snippets/` and a target project holds only the installed copy under `.claude/snippets/`, so a session picks whichever folder it noticed first. A toolkit snippet written into the consumed copy fails the drift assertion that regenerates that folder. A snippet written there in a target project is correct and looks identical, which is why the surface has to be resolved from what the project has rather than guessed.
13
13
 
14
+ Inside the project surface, a third failure sits one level deeper. A project-authored snippet sharing a name with a toolkit one used to be indistinguishable from it, so `aitk snippets sync` could not tell which side owned the file. The sync engine now reads ownership by location for anything under `.claude/snippets/project/`, so the skill has to write there rather than beside the toolkit-installed files.
15
+
14
16
  ## Must
15
17
 
16
18
  - Read the bundled snippet reference before drafting, since the shape rules are what the invocation channels depend on
17
19
  - Resolve the write surface from which snippet folder the project has, rather than from whichever one the session noticed first
20
+ - On the project surface, write under its `project/` subfolder so the sync engine reads the file as project-authored by location
18
21
  - Confirm the slug and the full body with the user before writing
19
22
  - Emit the written path in full, so the terminal can resolve it
20
23
  - State what the resolved surface implies after writing, since a root file needs the consumed copy regenerated and a project-local one needs copying to the toolkit to ship
@@ -20,11 +20,11 @@ Creates one snippet file. Read these files in parallel:
20
20
  1. Resolve the write surface: `snippets/` at the root if present, which is the toolkit's own authoring source. Otherwise `.claude/snippets/`, a target project's installed copy.
21
21
  2. Draft the content from the user's description. The snippet reference governs structure, invocation, and authoring conventions.
22
22
  3. Confirm the slug and full content with the user before writing
23
- 4. Write the file to `<surface>/<category>/<slug>.md`, or to `<surface>/<slug>.md` when the snippet takes no category
23
+ 4. Write the file. On the root surface: `<surface>/<category>/<slug>.md`, or `<surface>/<slug>.md` when the snippet takes no category. On the `.claude/` surface: the same shape nested one level deeper under `project/`, so the sync engine's location rule holds it apart from a toolkit-installed snippet regardless of what its name matches.
24
24
 
25
25
  ## After writing
26
26
 
27
27
  Emit the full path on its own line.
28
28
 
29
29
  - Root surface: this is the toolkit's authoring source. Remind the user to run `bun run check` to regenerate the consumed copy under `.claude/`.
30
- - `.claude/` surface: the file is project-local. `aitk snippets sync` leaves it alone, since sync only updates filenames it recognizes from the toolkit. Remind the user to copy it to the toolkit repo, under `snippets/<category>/<name>.md`, if it should ship to every project.
30
+ - `.claude/` surface: the file is project-local, under `.claude/snippets/project/`. `aitk snippets sync` leaves everything there alone by location rather than by a name it fails to recognize. Remind the user to copy it to the toolkit repo, under `snippets/<category>/<name>.md`, if it should ship to every project.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: restate
3
+ description: Why a plain restatement is asked for by name, and where its boundary sits against the skill that drafts and the command that measures
4
+ ---
5
+
6
+ # Restate requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, a reader who cannot follow a dense answer has to ask for it again in ordinary words, and the second answer is drafted by the same session that produced the first. Nothing tells that session which half of its own text carried the decision, so the rewrite shortens the passage and keeps the abstraction that made it hard to read.
11
+
12
+ The corpus around it covers the neighboring jobs and not this one. `write-human` governs a passage being drafted or revised and arrives on a markdown edit, so it never sees an answer in chat and never reaches a document nobody is editing. `aitk markdown audit` reports sentence spread and repeated openings against a stated range, which measures how a passage moves and says nothing about whether a reader can act on it.
13
+
14
+ A restatement also fails in a way a rewrite does not. A run that compresses by dropping what supports a claim leaves a reader who acts on the plain version and meets a different answer in the source, and that failure is invisible in the restatement itself.
15
+
16
+ ## Must
17
+
18
+ - Take a named markdown path or the preceding answer, resolving the path first, since a reader pointing at a file has already said which one they mean
19
+ - Keep every point that changes a decision and cut what only supports one, which is the split that separates a restatement from a summary
20
+ - Preserve a hedge the source carries, since dropping it manufactures a certainty
21
+ - Cite the carrier of the rhythm and density rules rather than restating them, because a second copy drifts with nothing comparing the two
22
+ - Fire on an explicit request and refuse the model's own judgment about its own output
23
+
24
+ ## Must not
25
+
26
+ - Write a file. A restatement is read once to reach a decision, and a file makes a record nobody opens twice.
27
+ - Add a fact, number, or name the source does not carry
28
+ - Restate the voice, rhythm, or density rules, which live in the skill this body cites
29
+ - Claim the restatement is verified. Nothing checks whether a plain version kept the deciding half, so the sandbox arm asserts what the run did rather than that the output is good.
30
+
31
+ ## Guards
32
+
33
+ - A named path that does not resolve stops the run rather than falling back to the preceding answer, since the two inputs are different requests
34
+ - A request with no path and nothing preceding it stops rather than restating the request itself
35
+
36
+ ## Out of scope
37
+
38
+ - Drafting or revising a passage, which is `write-human` on a markdown edit
39
+ - Measuring cadence in finished output, which `aitk markdown audit` reports from package data
40
+ - Rewriting a document into a file, which is a proposal against the source rather than a restatement of it
41
+ - The banned words, characters, and spellings, which `markdown.md` states and the audit gates
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: restate
3
+ description: Restates a dense answer or a named markdown document in plain language, cutting jargon and keeping only what changes a decision. Use when asked to "restate that in plain language", "say that plainly", "what does this actually mean", "cut the jargon", "give me the plain version", or "restate this document". Do NOT use to draft or revise prose, which is `write-human`, and do NOT fire on the model's own judgment that its own output was dense.
4
+ ---
5
+
6
+ # Restate
7
+
8
+ Return the plain version of something already written. The reader asked because they stopped to decode rather than to decide, so the restatement earns its place by getting them to the decision.
9
+
10
+ ## What to restate
11
+
12
+ - Restate the file when the request names a markdown path, and the preceding answer in the conversation when it names none. A named path wins over an answer sitting in the same turn.
13
+ - Stop when the request names a path that does not resolve: `❌ No file at <path>. Name a path that exists, or ask for the preceding answer instead.`
14
+ - Stop when nothing precedes the request and no path is named: `❌ Nothing to restate. Name a markdown path, or ask right after the answer you want in plain words.`
15
+ - Refuse a request to restate output on the model's own initiative. A person asks for this by name.
16
+
17
+ ## What survives
18
+
19
+ - Keep every point that changes a decision, and cut every point that only supports one. A reader who acts on the restatement and is surprised by the original has been given the wrong half.
20
+ - Name the thing the source names. Replace a term of art with its plain equivalent, and keep the term where the reader has to search for it later.
21
+ - Say what is uncertain where the source hedges, and say it plainly. Dropping a hedge invents a certainty the source does not carry.
22
+ - Introduce no fact, number, or name the source lacks. A restatement changes wording and never claims.
23
+ - Report the reasoning, not the metaphor. An abstraction standing in for a mechanism is what made the source dense.
24
+
25
+ ## How it reads
26
+
27
+ Load the `write-human` skill before writing the restatement. Compression is where a plain version turns into a list of verbless fragments, and that skill states the rhythm and density rules this one does not copy.
28
+
29
+ ## Output
30
+
31
+ Answer in chat. Write no file, since a restatement is read once to reach a decision.
32
+
33
+ Lead with the plain version in prose. Close with one line naming what was cut and why, so the reader can go back for it:
34
+
35
+ ```plaintext
36
+ Cut: <what left, and why it changes no decision>
37
+ ```
38
+
39
+ Name the source path on its own line when the restatement came from a file.
@@ -41,6 +41,6 @@ Importing that catalog wholesale fails on a different measurement. External mate
41
41
 
42
42
  - The banned words, characters, and spellings, which `markdown.md` states for a reader and `aitk markdown audit` gates from package data
43
43
  - Markdown mechanics, being headings, lists, code spans, punctuation, and file references
44
- - Restating text that already exists in plainer words, which is a different job on a different trigger, since a restatement is asked for by name and this arrives on a glob match
44
+ - Restating text that already exists in plainer words, which `restate` owns on a different trigger, since a restatement is asked for by name and this arrives on a glob match. The rules here still govern how that restatement reads, and that body cites this one rather than carrying a copy.
45
45
  - What voice a given surface declares, which belongs to the standard governing that surface
46
46
  - Measuring whether finished output followed these rules, which needs a check this skill does not carry
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: write-human
3
- description: Carries the voice, rhythm, sentence construction, and information density rules a banned-word list cannot express, plus the catalog of machine tells that survive a clean ban scan. Use when writing or revising prose a person will read, when a passage reads flat or uniform, or when asked to "make this read like a person", "fix the cadence", "this reads like AI wrote it", "vary the sentences", or "tighten this without gutting it". Do NOT use for banned words, characters, or spellings, which `markdown.md` states and `aitk markdown audit` gates, and do NOT use to restate text that already exists in plainer words.
3
+ description: Carries the voice, rhythm, sentence construction, and information density rules a banned-word list cannot express, plus the catalog of machine tells that survive a clean ban scan. Use when writing or revising prose a person will read, when a passage reads flat or uniform, or when asked to "make this read like a person", "fix the cadence", "this reads like AI wrote it", "vary the sentences", or "tighten this without gutting it". Do NOT use for banned words, characters, or spellings, which `markdown.md` states and `aitk markdown audit` gates, and do NOT use to restate text that already exists in plainer words, which is `restate`, whose body loads these rules from here.
4
4
  ---
5
5
 
6
6
  # Write human
@@ -22,11 +22,11 @@ aitk audits list --json
22
22
 
23
23
  ## What it runs
24
24
 
25
- Sixteen 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.
25
+ Seventeen 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
26
 
27
27
  The verbs walk separate trees and share no state, so they run together. Measured on the authoring machine at twelve verbs, a run finished in 0.8 seconds of wall clock against 4.4 seconds of processor, which is under every other stage in `bun run check`. `aitk deps audit` is the one that changes that reading, since it reaches a network rather than a tree and its latency is the index's rather than this machine's.
28
28
 
29
- Thirteen of the sixteen read a tree on this disk. The two added by `state-scoped-risk.md` read committed state rather than an arriving change, which is the gap every review surface here leaves by construction, and the one added by `label-coverage.md` reads a branch range against a map the project declares.
29
+ Fourteen of the seventeen read a tree on this disk, the one added by `restated.md` among them, since it reads three such trees against each other. The two added by `state-scoped-risk.md` read committed state rather than an arriving change, which is the gap every review surface here leaves by construction, and the one added by `label-coverage.md` reads a branch range against a map the project declares.
30
30
 
31
31
  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.
32
32
 
@@ -47,8 +47,10 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
47
47
  | `aitk claude skills audit` | Report both skill corpora against the mechanical rules in `standards/skill.md` |
48
48
  | `aitk claude skills drift` | Name the shipped skill bodies rewritten between a given ref and `HEAD`, and the installed version against the newest published (`--json`) |
49
49
  | `aitk claude skills reach` | Report the shipped bodies citing a toolkit path no target project receives, exiting 2 on an unqualified one |
50
+ | `aitk claude routing` | Report per `CLAUDE.md` section how many bullets name a path and how many of those a path-scoped rule already covers (`--json`) |
50
51
  | `aitk gov test-order` | Report where an implementation reached history ahead of the test covering it (`--json`) |
51
52
  | `aitk gov superseded` | Report where the tree still asserts a value a changed convention no longer produces, keyed on the value (`--json`) |
53
+ | `aitk gov restated` | Report every instruction the always-loaded file shares with the seed or a shipped skill body, classed and with its anchors named (`--json`) |
52
54
  | `aitk secrets scan` | Report credential-shaped values in the tree the package ships, keyed on issued values rather than on words (`--json`) |
53
55
  | `aitk deps audit` | Report published advisories against the resolved dependency set, refusing rather than reporting clean when the index is unreachable (`--json`) |
54
56
  | `aitk labels audit` | Report the labels a changed set earns from the pull request label map and the paths no row reaches (`--json`) |
@@ -63,27 +65,27 @@ Full help: `aitk <command> --help`. Behavior notes for the install and sync verb
63
65
 
64
66
  Each domain exposes a consistent shape where applicable: `list`, `install`, `sync`, `create`.
65
67
 
66
- | Domain | Subcommands |
67
- | ----------- | ----------------------------------------------------------------------------------------------------------- |
68
- | `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore` |
69
- | `snippets` | `list`, `install`, `sync`, `create` |
70
- | `standards` | `list`, `<name>` |
71
- | `gov` | `list`, `install`, `sync`, `build`, `regen`, `test-order`, `superseded` |
72
- | `claude` | `init`, `sync`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `skills reach`, `setup [dest]` |
73
- | `demo` | `compile`, `run` |
74
- | `wiki` | `init` |
75
- | `design` | `render` |
76
- | `slides` | `render`, `list` |
77
- | `tasks` | `archive`, `validate` |
78
- | `intake` | `list`, `answer` |
79
- | `teach` | `list`, `open`, `resource`, `glossary` |
80
- | `comments` | `scan` |
81
- | `context` | `audit` |
82
- | `markdown` | `audit` |
83
- | `secrets` | `scan` |
84
- | `deps` | `audit` |
85
- | `labels` | `audit` |
86
- | `audits` | `run`, `list` |
68
+ | Domain | Subcommands |
69
+ | ----------- | ---------------------------------------------------------------------------------------------------------------------- |
70
+ | `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore` |
71
+ | `snippets` | `list`, `install`, `sync`, `create` |
72
+ | `standards` | `list`, `<name>` |
73
+ | `gov` | `list`, `install`, `sync`, `build`, `regen`, `test-order`, `superseded` |
74
+ | `claude` | `init`, `sync`, `routing`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `skills reach`, `setup [dest]` |
75
+ | `demo` | `compile`, `run` |
76
+ | `wiki` | `init` |
77
+ | `design` | `render` |
78
+ | `slides` | `render`, `list` |
79
+ | `tasks` | `archive`, `validate` |
80
+ | `intake` | `list`, `answer` |
81
+ | `teach` | `list`, `open`, `resource`, `glossary` |
82
+ | `comments` | `scan` |
83
+ | `context` | `audit` |
84
+ | `markdown` | `audit` |
85
+ | `secrets` | `scan` |
86
+ | `deps` | `audit` |
87
+ | `labels` | `audit` |
88
+ | `audits` | `run`, `list` |
87
89
 
88
90
  Common patterns:
89
91
 
@@ -24,6 +24,8 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
24
24
  - [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
25
25
  - [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
26
26
  - [Records](records.md): Validating the session records under .claude/ and the standards corpus, the per-kind checks, the refusal reasons, reading each folder's size and growth, backing the folders to a private remote, and which root each kind defaults to
27
+ - [Restated instructions](restated.md): Counting the instructions the always-loaded file shares with the seed and the shipped skill bodies, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
28
+ - [Routing report](routing.md): Reading per CLAUDE.md section how many bullets name a path, what counts as naming one, when a rule counts as covering it, the two refusals, and why the verb reports rather than gates
27
29
  - [Sandbox](sandbox.md): Scenario routing, the expectation scoring surface, and the coverage census over scenarios and skills
28
30
  - [Scripting](scripting.md): The runtime catalogs that replace hardcoded names, what each carries, and a headless invocation per domain
29
31
  - [Sessions](sessions.md): Resolving live peer sessions to the worktree and branch each holds, the liveness confidence field, the unresolved reasons, and what the read depends on
@@ -11,7 +11,9 @@ The behavior notes behind the verbs listed in `commands.md`. Each one records wh
11
11
 
12
12
  `aitk gov sync` updates only rules already present under `.claude/rules/` and
13
13
  never adds new ones. A rule the toolkit does not ship is left alone, which is
14
- how project-authored rules survive. It also removes a stale `.claude/GOV.md`
14
+ how project-authored rules survive, and one under `.claude/rules/project/`
15
+ is left alone regardless of its name, since that subfolder is project-authored
16
+ by location. It also removes a stale `.claude/GOV.md`
15
17
  from the retired build. Use `aitk gov install` to add rules.
16
18
 
17
19
  There is no `aitk standards sync` and no `aitk standards install`. The corpus
@@ -23,7 +25,9 @@ the catalog.
23
25
  `aitk snippets sync` matches by path relative to `.claude/snippets/`. It
24
26
  matches by path relative to that directory, so a snippet the toolkit no longer
25
27
  ships, or one authored directly in the target, is reported and skipped rather
26
- than deleted. It is not preset-aware, so a project that installed `essentials`
28
+ than deleted, and a snippet under `.claude/snippets/project/` skips the same
29
+ way regardless of path, since that subfolder is project-authored by location.
30
+ It is not preset-aware, so a project that installed `essentials`
27
31
  does not grow new snippets on a sync. Use `aitk snippets install` to add them.
28
32
 
29
33
  ## Install guards
@@ -0,0 +1,78 @@
1
+ ---
2
+ title: Restated instructions
3
+ description: Counting the instructions the always-loaded file shares with the seed and the shipped skill bodies, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
4
+ ---
5
+
6
+ # Restated instructions
7
+
8
+ `aitk gov restated` reports every instruction the always-loaded file states that a second surface states too. It answers a question nothing else here could: one rule was found written in three places, and it was found by accident when a shipped skill deleted a file the rule said to keep.
9
+
10
+ ```bash
11
+ aitk gov restated
12
+ aitk gov restated --json
13
+ aitk gov restated --root ../my-app
14
+ ```
15
+
16
+ | Option | Behavior |
17
+ | --------------- | ---------------------------------------------------------- |
18
+ | `--root <path>` | Tree to read, defaulting to the current directory |
19
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
20
+
21
+ Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode.
22
+
23
+ ## The corpus it reads
24
+
25
+ Three surfaces, and they are not read symmetrically. Every top-level bullet in `CLAUDE.md` is a subject, and the other two are searched:
26
+
27
+ - `tooling/claude/seeds/CLAUDE.md`, read as bullets, since the seed carries the same shape as the file it is authored from
28
+ - `claude/skills/*/SKILL.md`, read as every prose line and bullet, since the motivating case was stated in a body as a paragraph rather than a list item
29
+
30
+ Frontmatter, headings, tables, and fenced blocks are read past. A heading names a section instead of stating a rule, a fenced block is an example whose words belong to the prose around it, and a body's `description` restates that skill's own purpose, so sweeping it would match every subject naming its domain.
31
+
32
+ A rule stated in two skill bodies and never in `CLAUDE.md` is outside this reading. The bullets there are the subjects, and a subject is what the search runs from.
33
+
34
+ ## How a match is decided
35
+
36
+ Matching is recall-first and keyed on shared distinctive tokens rather than on a phrase two surfaces spell the same way. The case this exists for was one rule written three different ways, so a near-exact matcher would ship a cheap report blind to the defect it was built for.
37
+
38
+ A token is distinctive when it appears in at most 20 of the corpus's statements, which is under one percent of them. `.claude/plans/` sits at 14 and is the anchor the motivating case turns on, while `file` sits at 371 and would match most of the tree.
39
+
40
+ A backticked token counts double. An author marking a span as code named an identifier rather than describing one, so `.claude/plans/archive/` says more about what a statement governs than any two prose words do. Two statements are one rule when their shared anchors reach a weight of 3.
41
+
42
+ Every record names the anchors its match rested on, so a reader can weigh a finding instead of taking it.
43
+
44
+ ## The three classes
45
+
46
+ - **Mirror.** Both files sit on a declared path pair whose duplication is deliberate. `CLAUDE.md` and the seed are the one pair, since the seed is authored from it and `claude-seed-sync` exists to reconcile the two. Excluding by pair rather than by content is the point: the duplication is a location fact this repository already records, and a content test would rediscover it on every run.
47
+ - **Repetition.** Two surfaces state one rule and neither is declared a copy of the other.
48
+ - **Contradiction.** The prohibition falls on one surface alone, on a match strong enough to read that as a disagreement. This is a polarity reading rather than a judgment about meaning, so weigh each against the surfaces it names.
49
+
50
+ The contradiction floor sits above the match floor deliberately. A thin match says two statements touch the same subject, which is not enough to claim one forbids what the other prescribes, so a weak pair reports as a repetition and the loudest class is reserved for a pair sharing real identity.
51
+
52
+ Two further rules decide where a prohibition counts, and both came out of false positives rather than from reasoning ahead of the corpus.
53
+
54
+ Polarity is read off the clause the anchors landed in, and off the densest such clause rather than every one carrying an anchor. A statement states one rule across several clauses, so a union answers true whenever any clause anywhere carries a marker, which is the whole statement again under another name.
55
+
56
+ The marker also has to open its clause, because an instruction leads with its verb. `Never delete a task file` prohibits where `a fallback never fires` reports, and no test reading the marker anywhere in the clause tells those apart. What that costs is a prohibition written mid-clause, which now reads as description and lands the pair in the repetition class, so both surfaces still reach the report and only the label is weaker.
57
+
58
+ A mirror that disagrees stays a finding. The exclusion reaches a repetition alone, because the two files on a declared pair are meant to agree.
59
+
60
+ ## Which surface is authoritative
61
+
62
+ Each restatement names where a later edit starts.
63
+
64
+ - `claude-md` for a seed match, since the always-loaded file is authored first and the seed carries it to a target
65
+ - `skill-body` where the subject names that skill, which is the content-ownership rule that behavior triggered only when editing one domain belongs to that domain's skill
66
+ - `unknown` everywhere else, which is a first-class answer rather than a gap
67
+
68
+ The ownership table assigns a cross-domain rule and a domain-triggered one, and reaches nothing stated in a skill body the always-loaded file never names. Guessing there would put a reader on a surface nobody decided.
69
+
70
+ ## Exit codes
71
+
72
+ Exit codes are `0` when no instruction is restated outside a declared mirror, `1` for a refusal, and `2` for at least one restatement outside one. Mirrors move no exit code.
73
+
74
+ Nothing wires this into `bun run check` or into a hook. A restatement is legitimate more often than not, and gating a measure whose ordinary result is a finding is what teaches contributors to route around the stage. `aitk gov test-order` and `aitk labels audit` are the siblings.
75
+
76
+ Both refusals are absences rather than breaks. A target holds neither the seed nor a shipped skills tree, so `aitk audits run` reads `no-instructions` and `no-surfaces` as a corpus that is not there rather than a verb that failed.
77
+
78
+ An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the record's `counts` rather than the exit when a skill consumes this.
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Routing report
3
+ description: Reading per CLAUDE.md section how many bullets name a path, what counts as naming one, when a rule counts as covering it, the two refusals, and why the verb reports rather than gates
4
+ ---
5
+
6
+ # Routing report
7
+
8
+ `aitk claude routing` reports, per `CLAUDE.md` section, how many top-level bullets name a path and how many of those a path-scoped rule already covers. It answers the tier test in `.claude/rules/claude/592-claude-md.md`, which asks whether a fact applies every session or fires on one path, and which until this verb existed was a judgment nothing counted.
9
+
10
+ ```bash
11
+ aitk claude routing
12
+ aitk claude routing --json
13
+ aitk claude routing ../my-app
14
+ ```
15
+
16
+ | Option | Behavior |
17
+ | -------- | ------------------------------------------------------------ |
18
+ | `[path]` | Repository root to read, defaulting to the current directory |
19
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
20
+
21
+ Under `--json` the record holds stdout alone and the frame still renders on stderr, refusals included, which is the split `output-shape.md` fixes for every mode.
22
+
23
+ The root is the argument rather than the toolkit, matching the reach and drift verbs, so a linked worktree reads its own branch and a target reads its own file.
24
+
25
+ ## What it reads
26
+
27
+ Every H2 and H3 owning at least one top-level bullet. An H3 is reported under the H2 containing it, as `Behavior / Scope discipline`, so a section and its subsections are counted apart rather than summed.
28
+
29
+ Three things are read past. A nested bullet belongs to the one above it rather than to the section. A bullet inside a fenced block is example text rather than instruction. A heading carrying no bullet answers nothing the report asks, so it is dropped rather than listed at zero.
30
+
31
+ ## What counts as naming a path
32
+
33
+ A bullet is path-scoped here when it names a path. That is evidence for the tier judgment rather than the judgment itself, and the gap runs both ways: a bullet naming a folder can still apply every session, and one firing on a path it never spells is invisible to the count. Read a section's number as a place to look rather than as a verdict on it.
34
+
35
+ A backticked token counts when it carries a separator or an alphabetic extension, which admits `src/cli.ts` and `cspell.json` while leaving a flag, a bare word, and a version string out.
36
+
37
+ A shape counts as the folder above its placeholder. `.claude/context/<domain>.md` names `.claude/context/` and nothing narrower, so dropping the token whole would report the section carrying it as naming no path at all. A placeholder opening the first segment has no openable prefix and is dropped.
38
+
39
+ ## When a rule counts as covering it
40
+
41
+ A rule covers a named path only when its glob anchors to a location. A glob opening `**` reaches every folder in the tree, so it answers that a file type is governed and never that a named path is.
42
+
43
+ The corpus-wide markdown rules are what force that. Counting one reports every markdown path as covered, which collapses the column to a constant and tells a reader nothing about which folder somebody actually scoped a rule to.
44
+
45
+ A folder is probed with a handful of extensions rather than matched literally, because a glob narrowed by file type reaches under a folder without ever matching the folder's own name. Globs are read from each rule's frontmatter block alone, so a rule quoting a path in its body does not register a scope it never declared.
46
+
47
+ The paths a section names that no rule reaches are listed beside it, which is where a reader looks first when deciding what a new rule would cover.
48
+
49
+ ## Refusals
50
+
51
+ Two, each naming what a reader does about it. `no-claude-md` is a tree with no always-loaded file. `no-rules` is a tree carrying no path-scoped rule under `.claude/rules/`, where every path would report as uncovered and the column would say nothing.
52
+
53
+ An always-on rule declaring no `paths` is skipped rather than refused. It applies at the same priority as the always-loaded file, so it covers no path in particular.
54
+
55
+ ## Exit codes
56
+
57
+ Exit codes are `0` when the file was read and `1` for a refusal. No finding moves the exit code.
58
+
59
+ Nothing wires this into `bun run check` or into a hook. Whether a bullet belongs in a rule is a judgment, and gating a measure that counts a judgment forces an escape hatch for every deliberate case.
60
+
61
+ An exit code says nothing about a call made from a session, since a shell profile may wrap the binary in a function taking its status from a later command. Read the JSON record's `sections` array rather than the exit when a skill consumes this.
@@ -288,6 +288,7 @@ This section is the corpus the coverage claim is measured against: every name `a
288
288
  | `aitk:youtube-transcripts` | When a video transcript is wanted in the repo as context |
289
289
  | `aitk:claude-teach` | To learn a subject across sessions, in a workspace that holds the progress |
290
290
  | `aitk:write-human` | Before drafting or revising prose, for voice, rhythm, and density |
291
+ | `aitk:restate` | When an answer or a document has to be read again in plain words |
291
292
 
292
293
  Every row answers a question rather than marking a point in a project's life, so a phase above would send a reader to the wrong group.
293
294
 
@@ -12,6 +12,8 @@ paths:
12
12
  ## Before editing
13
13
 
14
14
  - Read the skill's sibling `REQUIREMENT.md` when one exists. If the change closes no gap it states, change the requirement first or drop the change.
15
+ - Confirm `create-skill`'s two creation-time questions are answered before a new `SKILL.md` lands, whether drafted by hand, by another skill, or by `create-skill` itself. Carry the third question into the sibling `REQUIREMENT.md`'s `Must not` section as a review criterion rather than a gate.
16
+ - Report it rather than proceeding silently when `create-skill` does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
15
17
 
16
18
  ## After editing
17
19
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "3.7.0",
4
+ "version": "3.9.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {