@erclx/aitk 3.41.1 → 3.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.41.1",
4
+ "version": "3.42.1",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: migration-standards-drop
3
+ description: Why the standards-tree drop ships as an ordered proposal, what the two pre-delete reads catch, and why one citation form serves every surface inside a target
4
+ ---
5
+
6
+ # Migration standards drop requirement
7
+
8
+ ## Gap
9
+
10
+ Without this skill, nothing names the tree. The sync engine registers governance alone and the unmigrated scan carries an empty root-layout set, both by decision rather than by omission, so a target holding 21 installed standards files reports clean and the drop runs off whoever remembers to look. The census that found the population walked one folder on one machine and moved the count from four to seven.
11
+
12
+ The order is the second failure and it has two halves. A session that deletes before syncing lands the installed rules citing a path it removed, and one that sweeps before syncing repoints citations the sync then rewrites.
13
+
14
+ The delete otherwise runs blind in two directions. Two of the five targets measured on 2026-08-28 carried a runtime reader, one a hook hand-parsing a standard for its banned-word set, and a hook whose input is gone audits nothing while reporting a clean run. In the other direction, nothing separates a file the project wrote from a toolkit copy by name, and the corpus had moved on from all 20 files at one target, so a content diff sorts every file as changed and a session reading that diff either keeps everything or loses the one file no corpus carries.
15
+
16
+ The repoint form is the fourth. A session applying the citation rule it knows from a shipped skill writes `${CLAUDE_SKILL_DIR}/../../standards/<name>.md`, which from a project-local skill at `.claude/skills/<name>/` resolves back into the tree the same pass deleted, and reports the sweep finished.
17
+
18
+ The last is the name map. `prose` split into `markdown.md` plus the `write-human` skill and resolves as no standard, so a mechanical one-to-one repoint produces a citation to nothing and every check on it passes.
19
+
20
+ ## Must
21
+
22
+ - Detect from a read of `.claude/standards/` itself, since no report names the tree and a session waiting for one waits forever
23
+ - Report the state a binary behind the published version puts the sync in, before naming a sync a stale binary would run
24
+ - Split the tree against `aitk standards list --json` three ways, separating an unchanged toolkit copy from a drifted one and from a name that resolves to no standard
25
+ - Name every runtime reader ahead of any delete, splitting a reader from a citation by whether the file is markdown, and say when the search could not run
26
+ - Give every citation inside a target one target form, `aitk standards <name>`, and say why the plugin-root form fails there
27
+ - Order the proposal sync, drop, sweep, and state that the sweep re-reads after the sync rather than before it
28
+ - Report an unmatched name as the user's to place, naming the `prose` split as the recorded instance
29
+ - Report the measured empty case as a pass, since the guard is what proves the read ran
30
+
31
+ ## Must not
32
+
33
+ - Run the sync, delete or move a file under the tree, or rewrite a citation
34
+ - Sort a drifted file as project-authored or as toolkit-owned on a content diff alone
35
+ - Propose the plugin-root citation form for a surface inside a target
36
+ - Relocate the install stamp. One visit per target is cheaper than two and a skill is not a visit, so the stamp rides with whatever else reaches the target.
37
+ - Stay in the catalog on the author typing its name alone. Nothing can answer that before the skill has run, so read the census back once it has and retire it if the answer is nobody.
38
+
39
+ ## Guards
40
+
41
+ - A directory with no `.claude/` stops, since nothing there installed a tree
42
+ - A `.claude/standards/` holding no markdown is the pass rather than a refusal
43
+ - No `aitk` on `PATH` stops, since every citation this move writes names a verb the target has to run
44
+
45
+ ## Out of scope
46
+
47
+ - Classifying `CLAUDE.md` sections into the three-tier model: `migration-claude-md`
48
+ - Relocating `docs/` files by audience: `migration-context`
49
+ - Splitting a retired `.claude/` file into the folder that replaced it, which pairs one file against one folder rather than dropping a corpus: `migration-superseded`
50
+ - Reconciling a seed file against its source section by section: `claude-seed-sync`
51
+ - Applying the drop and the sweep, which the user does after reviewing
52
+
53
+ ## Why it ships while its consumer row is parked
54
+
55
+ The one task performing this move is parked on the operator declining outside-repository work, so the skill arrives with three known consumers and no live instance. It ships anyway, because the parked row is about who is authorized to visit a target rather than about the move being wrong, and the skill is what makes the move repeatable by whoever is authorized. The evidence behind it comes from the census rather than from a run, which is the weaker of the two and is recorded here as such.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: migration-standards-drop
3
+ description: Proposes the ordered drop of an installed `.claude/standards/` tree and the repoint of every citation at `aitk standards <name>`, separating a toolkit copy from a file the project wrote and naming any runtime reader before a delete is proposed. Use when asked to "drop the standards tree", "repoint the standards citations", "my project still has .claude/standards/", or when a toolkit update leaves an installed standards copy no command refreshes. Do NOT delete the tree, run the sync, or rewrite a citation. Proposal only.
4
+ ---
5
+
6
+ # Migration standards drop
7
+
8
+ ## Guards
9
+
10
+ - If `.claude/` does not exist at `pwd`, stop: `❌ No .claude/ directory. Nothing here installed a standards tree.`
11
+ - If `.claude/standards/` holds no markdown, that is the pass: `✅ No installed standards tree. Nothing to drop.`
12
+ - If `aitk` is not on `PATH`, stop: `❌ aitk is not on PATH. Every citation this move writes names a verb the target has to run.`
13
+
14
+ Detection is the directory read above and nothing else. No report names this tree, since the sync engine registers governance alone and the unmigrated scan covers a root layout an older toolkit wrote rather than a copy under `.claude/`. A session waiting for a command to raise the tree waits forever.
15
+
16
+ ## Step 1: read the version the sync would run from
17
+
18
+ Run `aitk sync --check . --json` and read its `skew` object. The sync in Step 5 installs the rules the running binary carries, so a binary predating the citation change installs rules naming the path this move removes, and the sweep then has more to fix than it started with.
19
+
20
+ - `state` is `behind`: stop. `❌ The aitk on PATH is <installed> against <latest> published. A gov sync from it installs rules citing the standards path. Update, then re-run.`
21
+ - `state` is `unknown`: report the reason and continue. A version that could not be read is unread rather than stale.
22
+ - `state` is `current`: continue.
23
+
24
+ ## Step 2: split the tree three ways
25
+
26
+ Run `aitk standards list --json`. Each entry carries `name` and `content`, so the comparison needs no second read. Match every `.claude/standards/<stem>.md` against `name`:
27
+
28
+ - **Matched, content identical.** A toolkit copy the corpus still carries unchanged. The drop loses nothing.
29
+ - **Matched, content differs.** A toolkit copy that has drifted, and the diff cannot say which side moved. Report it as a read the user owes rather than sorting it either way. All 20 files measured at one target on 2026-08-28 read as changed, because the corpus had moved on since the install, and none of them was project-authored.
30
+ - **Unmatched.** No standard resolves under that name. Either the project wrote the file or the toolkit retired the name, and the catalog cannot separate the two.
31
+
32
+ Report a project-authored file as one this move keeps. Its destination is `standards/<name>.md` at the project root, which `aitk standards <name>` resolves ahead of the package corpus, so the citation form Step 4 gives every other file serves it too.
33
+
34
+ `prose` is the recorded retirement. It split into `markdown.md` plus the `write-human` skill and resolves as no standard at all, so a citation repointed one-to-one from it names nothing. Report an unmatched name as the user's to place and name that split as the instance.
35
+
36
+ ## Step 3: name every runtime reader before naming a delete
37
+
38
+ Run both from the project root, in parallel:
39
+
40
+ - `git grep -ln 'claude/standards' -- '*.md'`: the citations Step 4 repoints
41
+ - `git grep -ln 'claude/standards' -- . ':!*.md'`: the readers
42
+
43
+ The extension is the split. Markdown cites the tree and a session reads the citation. A hook, a script, or a config opens a file under it at run time, and dropping the tree under one leaves a check whose input is gone reporting success. Two of the five targets in the 2026-08-28 census carried a reader, one of them a hook hand-parsing a standard for a banned-word set.
44
+
45
+ Report each reader with what replaces it. A reader parsing a standard for a list the CLI now ships reads that list through the verb instead, which is `aitk markdown audit <file> --json` for the banned-word case.
46
+
47
+ When `pwd` is not a git work tree, say the reader search did not run rather than reporting no reader.
48
+
49
+ ## Step 4: give every citation one target
50
+
51
+ Every citation repoints to `aitk standards <name>`, whatever surface it sits on. One form rather than a choice per surface, which is the part a session gets wrong:
52
+
53
+ - A rule under `.claude/rules/` is markdown a glob match loads, so `${CLAUDE_SKILL_DIR}` expands to nothing there
54
+ - A project-local skill under `.claude/skills/<name>/` expands that variable to its own folder, so `${CLAUDE_SKILL_DIR}/../../standards/` resolves back into the tree being dropped
55
+ - `CLAUDE.md` and a context entry expand no variable at all
56
+
57
+ The plugin-root form belongs to a skill the toolkit ships beside its own corpus. Proposing it inside a target writes a path that resolves to the deleted tree.
58
+
59
+ A citation naming a name Step 2 left unmatched carries no target. Report it under what the user supplies.
60
+
61
+ ## Step 5: output the ordered proposal
62
+
63
+ The order is fixed and the reverse is the failure. Deleting before the sync lands the installed rules citing a path that is gone, and sweeping before the sync repoints citations the sync then rewrites. The sweep re-reads after the sync for that reason, since the sync fixes the rules it installed and leaves a project's own rules and prose alone.
64
+
65
+ Take the drop command from whether the tree is tracked, read with `git ls-files .claude/standards`. A tracked tree goes out through `git rm -r` so the index moves with the files, and an untracked one through `rm -rf`. A tree holding both needs both commands, since `git rm -r` takes the tracked files, exits zero, and leaves every untracked one where it was.
66
+
67
+ Print the blocks below, omitting any that is empty.
68
+
69
+ ````markdown
70
+ ## Drop
71
+
72
+ `.claude/standards/` holds <n> files: <n> unchanged toolkit copies, <n> drifted, <n> matching no standard.
73
+
74
+ ## Read before dropping
75
+
76
+ - `.claude/standards/<name>.md` drifted from the corpus copy. Confirm the project did not edit it.
77
+
78
+ ## Keep
79
+
80
+ - `.claude/standards/<name>.md` matches no standard. Move it to `standards/<name>.md` at the project root, which `aitk standards <name>` resolves first.
81
+
82
+ ## Runtime readers
83
+
84
+ - `.claude/hooks/<file>.sh` parses a standard at run time. Route it through `aitk markdown audit <file> --json` before the drop, or it reports a clean run having read nothing.
85
+
86
+ ## Citations to repoint
87
+
88
+ - `CLAUDE.md:42` → `aitk standards markdown`
89
+ - `.claude/rules/core/<n>-<slug>.md:8` → `aitk standards skill`
90
+
91
+ ## You supply
92
+
93
+ - The destination for the `prose` citations. It split into `markdown.md` plus the `write-human` skill, so no single name replaces it.
94
+
95
+ ## Run in this order
96
+
97
+ ```bash
98
+ aitk gov sync
99
+ git rm -r .claude/standards
100
+ ```
101
+
102
+ Then re-read the citations and repoint what the sync left.
103
+
104
+ ## Confirm
105
+
106
+ Run `aitk standards <name>` from inside this project for every name the repointed citations carry, and confirm each resolves.
107
+
108
+ ## Reminder
109
+
110
+ Nothing above was written or run. The tree holds files a delete cannot recover, so the drop and the sweep are yours to apply.
111
+ ````
112
+
113
+ Run nothing and write nothing: not the sync, not a delete or a move under `.claude/standards/`, not a citation rewrite. The install stamp is out of scope too, and travels with whatever else reaches this target. The user applies the move after reviewing it.
@@ -259,14 +259,15 @@ This section is the corpus the coverage claim is measured against: every name `a
259
259
 
260
260
  ### Keep the project current with the toolkit
261
261
 
262
- | Skill | When to use |
263
- | --------------------------- | ---------------------------------------------------------------------------------- |
264
- | `aitk:claude-seed-sync` | After a toolkit update, to reconcile installed seeds without losing customizations |
265
- | `aitk:migration-claude-md` | When `CLAUDE.md` grew past what always-load context should carry |
266
- | `aitk:migration-context` | When `docs/` holds agent-flavored files belonging in `.claude/context/` |
267
- | `aitk:migration-superseded` | When a drift report names a `.claude/` file a folder has replaced |
268
- | `aitk:toolkit-feedback` | When something in the toolkit is broken, missing, or off |
269
- | `aitk:toolkit-triage` | In the toolkit repo, to work through the open feedback issues |
262
+ | Skill | When to use |
263
+ | ------------------------------- | ---------------------------------------------------------------------------------- |
264
+ | `aitk:claude-seed-sync` | After a toolkit update, to reconcile installed seeds without losing customizations |
265
+ | `aitk:migration-claude-md` | When `CLAUDE.md` grew past what always-load context should carry |
266
+ | `aitk:migration-context` | When `docs/` holds agent-flavored files belonging in `.claude/context/` |
267
+ | `aitk:migration-superseded` | When a drift report names a `.claude/` file a folder has replaced |
268
+ | `aitk:migration-standards-drop` | When the project still holds an installed `.claude/standards/` tree |
269
+ | `aitk:toolkit-feedback` | When something in the toolkit is broken, missing, or off |
270
+ | `aitk:toolkit-triage` | In the toolkit repo, to work through the open feedback issues |
270
271
 
271
272
  ### Generate an artifact on demand
272
273
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "3.41.1",
4
+ "version": "3.42.1",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -36,6 +36,29 @@ GOV_EXPECTED_UNREFERENCED="260-shadcn 320-tanstack-query"
36
36
  # a reader has to be able to open, and `aitk audits run` owns writing it.
37
37
  AUDITS_BASELINE=".claude/audits/baseline.json"
38
38
 
39
+ # The corpora a `src/` test asserts over from outside `src/`, censused in
40
+ # `.claude/context/development/verification.md`. This array and that list are two
41
+ # copies of one set with nothing comparing them, so a corpus joining the census
42
+ # joins this array in the same change. The first four are directory prefixes
43
+ # because their tests walk the tree whole, which is what reaches a rule or a
44
+ # skill a branch adds rather than edits.
45
+ TEST_CORPORA_PATTERNS=(
46
+ '^claude/skills/'
47
+ '^governance/rules/'
48
+ '^\.claude/hooks/'
49
+ '^tooling/claude/seeds/\.claude/hooks/'
50
+ '^standards/markdown\.md$'
51
+ '^tooling/base/reference\.md$'
52
+ '^tooling/web/configs/scripts/worktree-port\.sh$'
53
+ '^\.cspell/banned-spellings\.txt$'
54
+ '^scripts/lib/worktree\.sh$'
55
+ '^scripts/core/check-ignore-parity\.sh$'
56
+ )
57
+ TEST_CORPORA=$(
58
+ IFS='|'
59
+ printf '%s' "${TEST_CORPORA_PATTERNS[*]}"
60
+ )
61
+
39
62
  check_dependencies() {
40
63
  command -v bun >/dev/null 2>&1 || log_error "bun is not installed"
41
64
  }
@@ -639,11 +662,11 @@ main() {
639
662
  fi
640
663
 
641
664
  log_step "Tests"
642
- if has_changed '^src/|^vitest\.config\.ts$|^tsconfig\.json$|^package\.json$'; then
665
+ if has_changed "^src/|^vitest\.config\.ts\$|^tsconfig\.json\$|^package\.json\$|$TEST_CORPORA"; then
643
666
  run_check "bun run test" "Tests failed"
644
667
  log_info "Tests passed"
645
668
  else
646
- log_info "Skipped, no TypeScript changes"
669
+ log_info "Skipped, no TypeScript or asserted-corpus changes"
647
670
  fi
648
671
 
649
672
  if [ "$NESTED" = false ]; then
@@ -45,6 +45,11 @@ export const SETUP_CASES: readonly SkillCase[] = [
45
45
  'This file was replaced by a folder, help me split its content into it.',
46
46
  expect: 'migration-superseded',
47
47
  },
48
+ {
49
+ prompt:
50
+ 'This project still carries a copy of the standards folder, get rid of it and point everything at the CLI.',
51
+ expect: 'migration-standards-drop',
52
+ },
48
53
  {
49
54
  prompt:
50
55
  "Before I run this sync, tell me exactly what it's going to overwrite.",