@erclx/aitk 0.9.0 → 0.11.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.
Files changed (37) hide show
  1. package/README.md +17 -13
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/claude-address-review/SKILL.md +3 -4
  4. package/claude/skills/claude-autoship/SKILL.md +1 -1
  5. package/claude/skills/claude-diagram/SKILL.md +1 -1
  6. package/claude/skills/claude-docs/SKILL.md +1 -1
  7. package/claude/skills/claude-memory-review/SKILL.md +1 -1
  8. package/claude/skills/claude-pr-review/SKILL.md +1 -1
  9. package/claude/skills/claude-review/SKILL.md +1 -1
  10. package/claude/skills/claude-seed-sync/SKILL.md +1 -1
  11. package/claude/skills/claude-ui-test/SKILL.md +1 -1
  12. package/claude/skills/claude-ux-audit/SKILL.md +1 -1
  13. package/claude/skills/claude-worktree/SKILL.md +2 -2
  14. package/claude/skills/git-followup/SKILL.md +1 -1
  15. package/claude/skills/git-issue/SKILL.md +1 -6
  16. package/claude/skills/git-pr/SKILL.md +1 -6
  17. package/claude/skills/git-split/REQUIREMENT.md +2 -1
  18. package/claude/skills/git-split/SKILL.md +2 -0
  19. package/docs/agents.md +36 -0
  20. package/docs/target-projects.md +1 -1
  21. package/package.json +1 -1
  22. package/scripts/core/regen-claude-copies.sh +10 -1
  23. package/scripts/core/verify.sh +1 -1
  24. package/src/cli.ts +4 -0
  25. package/src/commands/comments.ts +234 -0
  26. package/src/commands/gov.ts +40 -0
  27. package/src/comments/scan.ts +338 -0
  28. package/src/comments/trend.ts +207 -0
  29. package/src/comments/vocabulary.ts +85 -0
  30. package/src/git-env.ts +36 -0
  31. package/src/git-ignore.ts +46 -0
  32. package/src/gov/consumed.ts +129 -0
  33. package/src/indexes/walk.ts +1 -29
  34. package/standards/index.md +1 -1
  35. package/standards/prose.md +14 -1
  36. package/standards/readme.md +15 -1
  37. package/standards/skill.md +14 -0
package/README.md CHANGED
@@ -13,29 +13,31 @@ claude plugin marketplace add https://github.com/erclx/aitk
13
13
  claude plugin install aitk@aitk
14
14
  ```
15
15
 
16
- The skills are then available as `/aitk:<name>`. Run `/reload-plugins` to pick them up inside a session that was already open. Updates arrive on release, so a push to this repo does not reach an installed copy.
16
+ The skills land as `/aitk:<name>`. If your session was already open, run `/reload-plugins` to pick them up. Updates arrive on release, so a push to this repo won't reach your installed copy.
17
17
 
18
- Several skills call the `aitk` CLI to read catalogs and run installs, and the plugin does not put it on your path. Install it from the registry.
18
+ Several skills call the `aitk` CLI to read catalogs and run installs, and the plugin doesn't put it on your path. Install it from the registry.
19
19
 
20
20
  ```bash
21
21
  bun install --global @erclx/aitk
22
22
  ```
23
23
 
24
- [Bun](https://bun.sh) is the CLI runtime and has to be on the path first. Confirm the install by resolving `aitk --help`.
24
+ [Bun](https://bun.sh) is the CLI runtime and has to be on your path first. Confirm the install by resolving `aitk --help`.
25
25
 
26
26
  ## Why
27
27
 
28
- Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Across enough projects the copies drift, and agents stop getting consistent signals.
28
+ Every AI coding setup accumulates the same assets. Prompts to reuse, rules agents should follow, slash commands, skills, seed docs, sync scripts. Once you have enough projects, your copies drift and your agents stop getting consistent signals.
29
29
 
30
30
  Three design choices shape the toolkit.
31
31
 
32
32
  - Agent-first: every command has a non-interactive path and a JSON catalog. If a Claude Code skill or any other agent cannot drive the CLI without prompts, the design is wrong.
33
- - Text-native: conventions, rules, and prompts are authored as markdown that humans and agents read the same way. No hidden behavior, no compiled state.
34
- - One source, many consumers: this repo is the authoritative copy. Target projects install and sync on demand, never author in place.
33
+ - Text-native: conventions, rules, and prompts are authored as markdown that you and your agents read the same way. No hidden behavior, no compiled state.
34
+ - One source, many consumers: this repo is the authoritative copy. Your projects install and sync on demand, never author in place.
35
+
36
+ Two limits worth knowing before you install. Claude Code is the only agent runtime the plugin targets, and the CLI needs Bun on your path. Snippets are the one surface that also travels to Gemini chat.
35
37
 
36
38
  ## What is inside
37
39
 
38
- Each domain has a canonical source in this repo and a thin install or sync CLI on the target side. The links run to internal narrative, written for someone maintaining the toolkit rather than installing it.
40
+ Each domain has a canonical source in this repo and a thin install or sync CLI on your side. The links run to internal narrative, written for someone maintaining the toolkit rather than installing it, so skip them on a first pass.
39
41
 
40
42
  - [Claude Code plugin](.claude/context/claude-plugin.md): skills for planning, review, docs sync, and the git ship chain
41
43
  - [Governance rules](.claude/context/governance.md): Cursor rules and stacks, installable per project
@@ -49,6 +51,8 @@ Each domain has a canonical source in this repo and a thin install or sync CLI o
49
51
 
50
52
  ## Documentation
51
53
 
54
+ Scaffolding your first project? Start with target projects, then the AI workflow loop. Everything else answers questions that arrive later.
55
+
52
56
  - [AI workflow](docs/ai-workflow.md): feature-development loop inside a toolkit-managed project
53
57
  - [Operating model](docs/operating-model.md): orchestrator and worker roles for building across parallel sessions
54
58
  - [Visual design workflow](docs/visual-design-workflow.md): tiered guide for design and wireframe authoring
@@ -58,7 +62,7 @@ Each domain has a canonical source in this repo and a thin install or sync CLI o
58
62
 
59
63
  ## Development
60
64
 
61
- Working on the toolkit starts from a clone. Running the CLI does not, since it installs from the registry.
65
+ Working on the toolkit starts from a clone. Running the CLI doesn't, since it installs from the registry. Skip this section unless you're changing the toolkit itself.
62
66
 
63
67
  ### Prerequisites
64
68
 
@@ -67,7 +71,7 @@ Working on the toolkit starts from a clone. Running the CLI does not, since it i
67
71
  - [GitHub CLI](https://cli.github.com) (optional) for ship flows
68
72
  - Shell: `zsh` or bash 4+ (`brew install bash` on macOS).
69
73
 
70
- Clone the repo, then run the bootstrap script. It installs dependencies, links the CLI globally, and adds the Claude Code shell aliases to `~/.zshrc`.
74
+ Clone the repo, then run the bootstrap script. It installs dependencies, links the CLI globally, and adds the Claude Code shell aliases to your `~/.zshrc`.
71
75
 
72
76
  ```bash
73
77
  git clone https://github.com/erclx/aitk.git
@@ -76,7 +80,7 @@ bun install
76
80
  bun run bootstrap
77
81
  ```
78
82
 
79
- The script is idempotent. Re-run it after pulling upstream changes without duplicating anything. It confirms the install by resolving `aitk --help` on the last step. See [zshrc aliases](docs/zshrc-aliases.md) for what each alias does.
83
+ The script is idempotent, so re-run it after pulling upstream changes without duplicating anything. It confirms the install by resolving `aitk --help` on the last step. See [zshrc aliases](docs/zshrc-aliases.md) for what each alias does.
80
84
 
81
85
  With the CLI linked, scaffold a fresh project.
82
86
 
@@ -86,13 +90,13 @@ git init
86
90
  aitk init
87
91
  ```
88
92
 
89
- `aitk init` installs base tooling configs, Claude seeds, governance rules, standards, and snippets in one pass, and scaffolds a `.claude/wiki/` stub for the project's own reference pages. Governance defaults to the `base` stack, so a bare init lands the coding and doc-authoring rules in `.claude/rules/` alongside the standards they route to. Pass `--stack <name>` for a framework stack, or `--skip governance` to leave rules out. Run `aitk tooling list --json` to see the catalog.
93
+ `aitk init` installs base tooling configs, Claude seeds, governance rules, standards, and snippets in one pass, and scaffolds a `.claude/wiki/` stub for your project's own reference pages. Governance defaults to the `base` stack, so a bare init lands the coding and doc-authoring rules in `.claude/rules/` alongside the standards they route to. Pass `--stack <name>` for a framework stack, or `--skip governance` to leave rules out. Run `aitk tooling list --json` to see the catalog.
90
94
 
91
- For the full outsider journey (scaffold, add a domain later, sync upstream drift), see [target projects](docs/target-projects.md).
95
+ For the full journey from scaffold through adding a domain later to syncing upstream drift, see [target projects](docs/target-projects.md).
92
96
 
93
97
  ## Contributing
94
98
 
95
- Portfolio project. Issues are welcome. Pull requests are accepted by invitation only. See the [contributing guidelines](CONTRIBUTING.md) for the local loop, the authoring split, and the commit convention.
99
+ Portfolio project. Issues are welcome. Pull requests are accepted by invitation only, so open an issue rather than a branch. Read the [contributing guidelines](CONTRIBUTING.md) for the local loop, the authoring split, and the commit convention before you file anything.
96
100
 
97
101
  ## License
98
102
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aitk",
3
3
  "description": "Automated governance, versioning, and discovery tools for Claude Code.",
4
- "version": "0.9.0",
4
+ "version": "0.11.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -73,10 +73,9 @@ bullet per finding, each opening with the bolded finding identifier.
73
73
  Close the body with `🤖 Addressed by Claude Code` on its own line so the reply
74
74
  reads as an independent machine pass, not a human sign-off.
75
75
 
76
- Before posting, scan the reply for em dashes and semicolons and rewrite each,
77
- splitting into two sentences or using a comma. The standards-audit hook skips
78
- `.claude/.tmp/`, so this scan is the only gate on the published reply. Post it to
79
- the PR:
76
+ Before posting, run the banned-character scan in `.claude/standards/prose.md`
77
+ against the reply. The hook skips `.claude/.tmp/`, so this scan is the only gate
78
+ on the published reply. Post it to the PR:
80
79
 
81
80
  ```bash
82
81
  gh pr comment <number> --body-file .claude/.tmp/address-review/reply-<number>.md
@@ -11,7 +11,7 @@ Chain the post-plan pipeline in a single run. Every step has a stop condition. S
11
11
  ## Guards
12
12
 
13
13
  - All `.claude/plans/` and `.claude/review/` reads resolve at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`.
14
- - Run `git branch --show-current` and replace `/` with `-` to derive `<slug>`. If empty, stop: `❌ Detached HEAD. Checkout the feature branch first.`
14
+ - Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. This skill takes the stop rather than the `latest` fallback, since it commits and opens a pull request. If empty, stop: `❌ Detached HEAD. Checkout the feature branch first.`
15
15
  - If `.claude/plans/feature-<slug>.md` does not exist at the main worktree root, stop: `❌ No approved plan at .claude/plans/feature-<slug>.md. Run /claude-feature first.`
16
16
  - If the working tree has uncommitted changes unrelated to the plan, stop: `❌ Uncommitted changes outside the plan. Commit or stash before autoshipping.`
17
17
 
@@ -75,7 +75,7 @@ When sources came from a code scan rather than planning prose, lead the explanat
75
75
 
76
76
  Quote node labels containing spaces or special characters with double quotes (`A["Web shell"]`). Avoid parentheses inside labels, they break some renderers. Use `<br/>` for line breaks inside labels.
77
77
 
78
- Apply the toolkit's prose bans to the whole file, including inside mermaid `subgraph` labels and node text. No em-dashes, no semicolons. Use a colon or split into two sentences instead. The pedagogical voice the standard asks for is a yield on voice alone and buys no exemption from these bans.
78
+ Run the banned-character scan in `.claude/standards/prose.md` against the whole file, including inside mermaid `subgraph` labels and node text, or `${CLAUDE_SKILL_DIR}/../../standards/prose.md` when the project does not have it. A colon also works as a replacement inside a label. The pedagogical voice the diagram standard asks for is a yield on voice alone and buys no exemption from these bans.
79
79
 
80
80
  Nothing enforces the ban inside the diagram. The standards-audit hook toggles on a fence and skips every line within it, so a label carrying an em dash passes silently while the same character in the explanation paragraph below is caught. Check the labels by reading them. This is the one place in the file where the author is the only gate.
81
81
 
@@ -181,7 +181,7 @@ A plan can serve more than one task, and archiving on the first task to close st
181
181
 
182
182
  Write the retarget as a markdown link, `Plan: [feature-<slug>](../.tmp/plans-archive/feature-<slug>.md)`, updating both halves so the text and the target stay in step. This branch is the only writer that produces a `Plan:` line nobody authored by hand, so a retarget that emits a bare path converts every task to the old form as it closes and drifts the board back to two shapes on its own.
183
183
 
184
- **Reviews.** Derive `<slug>` from the current branch name (replace `/` with `-`). If `.claude/review/review-<slug>.md` exists, delete it. `claude-review` writes with this convention. Do not sweep any other `review-*.md` file.
184
+ **Reviews.** Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result. If `.claude/review/review-<slug>.md` exists, delete it. `claude-review` writes with this convention. Do not sweep any other `review-*.md` file.
185
185
 
186
186
  Do not sweep `ui-checklist-*.md` (pending human verification) or `ux-audit-*.md` (standalone deliverable).
187
187
 
@@ -78,7 +78,7 @@ Rules that resist crisp one-line phrasing default to **Delete** over promote. Ne
78
78
 
79
79
  ### Step 4: write the proposal to the review file
80
80
 
81
- Derive a slug from the current git branch: run `git branch --show-current` and replace `/` with `-`. Fall back to `latest` on empty output.
81
+ Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result.
82
82
 
83
83
  Write the full proposal to `.claude/review/memory-review-<slug>.md` at the main worktree root. Do not print it inline.
84
84
 
@@ -131,7 +131,7 @@ The `What is right` section is optional, capped at three bullets, and included o
131
131
 
132
132
  Close the body with `🤖 Reviewed by Claude Code` on its own line so the review reads as an independent machine pass, not a human sign-off.
133
133
 
134
- Before posting, scan the body for em dashes and semicolons and rewrite each, splitting into two sentences or using a comma. The standards-audit hook skips `.claude/.tmp/`, so this scan is the only gate on the published comment.
134
+ Before posting, run the banned-character scan in `.claude/standards/prose.md` against the body. The hook skips `.claude/.tmp/`, so this scan is the only gate on the published comment.
135
135
 
136
136
  ```bash
137
137
  gh pr review <number> --comment --body-file .claude/.tmp/pr-review/body-<number>-<short-sha>.md
@@ -116,7 +116,7 @@ If nothing is wrong, use: `✅ No findings.`
116
116
 
117
117
  ### Persist
118
118
 
119
- Derive a slug from the current git branch: run `git branch --show-current` and replace any `/` with `-`. If the result is empty (detached HEAD), use `latest`.
119
+ Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result.
120
120
 
121
121
  Write the full report directly to `.claude/review/review-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
122
122
 
@@ -52,7 +52,7 @@ Before proposing an Update, grep the target section for the seed text's keywords
52
52
 
53
53
  ## Step 4: write the proposal to the review file
54
54
 
55
- Derive a slug from the current git branch: run `git branch --show-current` and replace `/` with `-`. Fall back to `latest` on empty output.
55
+ Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result.
56
56
 
57
57
  Write the full proposal to `.claude/review/seed-audit-<slug>.md` at the main worktree root. Do not print the proposal inline.
58
58
 
@@ -57,7 +57,7 @@ If all changes are automatable, skip the manual checklist:
57
57
 
58
58
  ### Persist the checklist
59
59
 
60
- Derive a slug from the current git branch: run `git branch --show-current` and replace any `/` with `-`. If the result is empty (detached HEAD), use `latest`.
60
+ Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result.
61
61
 
62
62
  When a manual checklist is produced, write it directly to `.claude/review/ui-checklist-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
63
63
 
@@ -58,7 +58,7 @@ If nothing is wrong, use: `✅ No observations.`
58
58
 
59
59
  ### Persist
60
60
 
61
- Derive a slug from the current git branch: run `git branch --show-current` and replace any `/` with `-`. If the result is empty (detached HEAD), use `latest`.
61
+ Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. Fall back to `latest` on an empty result.
62
62
 
63
63
  Write the full report directly to `.claude/review/ux-audit-<slug>.md` at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`. Create the directory if it does not exist. Always overwrite.
64
64
 
@@ -34,10 +34,10 @@ The directory test separates the defect from a genuinely bare repository, which
34
34
 
35
35
  Try each source in order. Stop at the first match.
36
36
 
37
- 1. **Plan matched to current branch.** Take the branch name and replace `/` with `-` to get `<slug>`. If `<main-root>/.claude/plans/feature-<slug>.md` exists, use `<slug>`.
37
+ 1. **Plan matched to current branch.** Derive `<slug>` per Deriving the branch slug in `.claude/standards/skill.md`, or `${CLAUDE_SKILL_DIR}/../../standards/skill.md` when the project does not have it. An empty result falls through to the next source here rather than becoming `latest`, since the slug is one candidate among several. If `<main-root>/.claude/plans/feature-<slug>.md` exists, use `<slug>`.
38
38
  2. **Single plan file.** List `<main-root>/.claude/plans/feature-*.md`. If exactly one match, derive `<slug>` from the filename.
39
39
  3. **Multiple plan files, no branch match.** Ask the user which plan. Show the candidate slugs as a numbered list. Do not pick.
40
- 4. **Current branch.** When no plan exists, use the branch name (with `/` replaced by `-`) if it is not `main` or `master`.
40
+ 4. **Current branch.** When no plan exists, use the `<slug>` from step 1 if it is not `main` or `master`.
41
41
  4b. **Session context.** When on `main` or `master` with no matching plan, read the current conversation to infer a kebab slug from the topic being discussed. Propose it: `Infer: <slug>. Confirm or rename?` Do not enter the worktree until the user confirms or provides a corrected name.
42
42
  5. **Ask.** None of the above applies. Ask the user for a name. Do not invent one.
43
43
 
@@ -24,7 +24,7 @@ its own reply, so skip the comment in step 6. The push and body sync still run.
24
24
  3. Invoke `aitk:git-commit` to generate one conventional commit from the staged diff
25
25
  4. Run `git push` to the tracking branch
26
26
  5. Check for existing review comments: `gh api 'repos/{owner}/{repo}/pulls/<number>/comments' --jq 'length'`, resolving `<number>` from `gh pr view --json number`.
27
- 6. When invoked with `reply-owned`, skip this step's comment: the caller posts the reply. Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh pr comment --body`, first scanning it for em dashes and semicolons and rewriting each since the hook does not see an inline comment body. If it is zero, run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
27
+ 6. When invoked with `reply-owned`, skip this step's comment: the caller posts the reply. Otherwise, if the count is above zero, the followup addresses review feedback: post a one-line summary of the fix with `gh pr comment --body`, first running the banned-character scan in `.claude/standards/prose.md` against it, or `${CLAUDE_SKILL_DIR}/../../standards/prose.md` when the project does not have it, since the hook does not see an inline comment body. If it is zero, run `gh pr view --json url,title,body` and update the body with `gh pr edit --body` when the new commit changes scope, and the title with `gh pr edit --title` when the scope shifted enough to make it inaccurate.
28
28
 
29
29
  ## After completion
30
30
 
@@ -40,12 +40,7 @@ After outputting the preview, execute the final command immediately. Claude Code
40
40
 
41
41
  ### Pre-publish scan
42
42
 
43
- Before running the final command, scan the title and body for banned characters and rewrite each occurrence:
44
-
45
- - `—` (em dash): split into two sentences or use a comma
46
- - `;` (semicolon): split into two sentences
47
-
48
- These bans come from `.claude/standards/prose.md`. Reading it is not enough. The scan is an explicit step.
43
+ Before running the final command, run the banned-character scan in `.claude/standards/prose.md` against the title and body. The title and body go straight to the remote with nothing checking them on the way, so this scan is the only gate. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/issue.md`.
49
44
 
50
45
  ### Final command
51
46
 
@@ -69,12 +69,7 @@ Leave a box unchecked only for the human-only cases the reference defines, and n
69
69
 
70
70
  ### Pre-publish scan
71
71
 
72
- Before running the final command, scan the PR title and body for banned characters and rewrite each occurrence:
73
-
74
- - `—` (em dash): split into two sentences or use a comma
75
- - `;` (semicolon): split into two sentences
76
-
77
- These bans come from `.claude/standards/prose.md` and apply to PR text on top of `${CLAUDE_SKILL_DIR}/references/pr.md`. Reading `prose.md` is not enough. The scan is an explicit step.
72
+ Before running the final command, run the banned-character scan in `.claude/standards/prose.md` against the PR title and body. The title and body go straight to the remote with nothing checking them on the way, so this scan is the only gate. It applies on top of the banned phrases in `${CLAUDE_SKILL_DIR}/references/pr.md`.
78
73
 
79
74
  ### Final command
80
75
 
@@ -7,7 +7,7 @@ description: What branch splitting is for, the gaps it closes, and how it differ
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, a branch carrying unrelated commits ships as one pull request, which a reviewer reads by skimming because no single concern holds it together. Split by hand, commits get cherry-picked in an order that leaves a branch missing something it depends on. Merge order is the sharpest failure: merging the wrong branch first lands every other branch's content on main and leaves the remaining pull requests empty after rebase, with no signal that anything went wrong.
10
+ Without this skill, a branch carrying unrelated commits ships as one pull request, which a reviewer reads by skimming because no single concern holds it together. Split by hand, commits get cherry-picked in an order that leaves a branch missing something it depends on. Merge order is the sharpest failure: merging the wrong branch first lands every other branch's content on main and leaves the remaining pull requests empty after rebase, with no signal that anything went wrong. Every body it writes stages under `.claude/.tmp/` and leaves through `gh`, neither of which the audit hook watches, so a banned character survives into a published pull request and has to be edited on the remote.
11
11
 
12
12
  ## Must
13
13
 
@@ -17,6 +17,7 @@ Without this skill, a branch carrying unrelated commits ships as one pull reques
17
17
  - Account for every commit ahead of main in the preview
18
18
  - State the merge order and the reason behind it, since the order is not recoverable from reading the pull requests afterward
19
19
  - Carry the restack loop for stacked mode, where each branch is rebased onto main once the one below it merges
20
+ - Scan every generated title and body for banned characters as an explicit step before opening a pull request
20
21
 
21
22
  ## Must not
22
23
 
@@ -69,6 +69,8 @@ If Mode is Independent, append this line to the preview:
69
69
 
70
70
  After outputting the preview, execute the final commands immediately. Claude Code's tool permission dialog is the confirmation gate. Do not wait for user input.
71
71
 
72
+ Before running them, run the banned-character scan in `.claude/standards/prose.md` against every title and body, or `${CLAUDE_SKILL_DIR}/../../standards/prose.md` when the project does not have it. Each body stages under `.claude/.tmp/` and leaves through `gh`, so the hook sees neither and this scan is the only gate.
73
+
72
74
  ### Final commands
73
75
 
74
76
  For independent mode, base every branch on `main`:
package/docs/agents.md CHANGED
@@ -79,6 +79,7 @@ Full help: `aitk <command> --help`.
79
79
  | `aitk feedback` | Write toolkit feedback from stdin to `.claude/review/`, or open a GitHub issue with `--github` |
80
80
  | `aitk transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
81
81
  | `aitk tasks archive` | Move a shipped task off the board, clear its ordering row, and regenerate the index |
82
+ | `aitk comments scan` | Measure comment density by language and comment kind, with a trend recomputed from git |
82
83
 
83
84
  ### Domain commands
84
85
 
@@ -95,6 +96,7 @@ Each domain exposes a consistent shape where applicable: `list`, `install`, `syn
95
96
  | `design` | `render` |
96
97
  | `slides` | `render`, `list` |
97
98
  | `tasks` | `archive` |
99
+ | `comments` | `scan` |
98
100
 
99
101
  Common patterns:
100
102
 
@@ -134,6 +136,16 @@ headlessly, so a call that names its stack or category is unchanged.
134
136
  `aitk snippets install`. Both resolve the target before anything else, so a path
135
137
  that does not exist fails rather than being scaffolded.
136
138
 
139
+ `aitk gov regen` is the one governance verb that runs against the toolkit root,
140
+ because the `.claude/rules/` it writes there is produced output rather than an
141
+ operator's working copy. It reads the stack recorded in `internal/governance.toml`,
142
+ installs it alongside anything under `internal/rules/`, and clears the
143
+ destination first so a rule the record stopped naming disappears. It takes
144
+ `--root <path>` and defaults to the toolkit root, prints nothing on success, and
145
+ reports the reason on stderr with exit 1 when the record names a stack or rule
146
+ that does not resolve. `scripts/core/regen-claude-copies.sh` calls it, and the
147
+ Consumed copies stage of `bun run check` asserts the result is committed.
148
+
137
149
  `aitk sync` runs every installed domain sync, then offers to commit the result
138
150
  and open a pull request. Under `AITK_NON_INTERACTIVE=1` it applies the domain
139
151
  syncs and then refuses the git workflow, reporting the branch and commit it
@@ -285,6 +297,30 @@ aitk tasks archive --pull-request 673 --json | jq -r 'if .ok then .task else .re
285
297
 
286
298
  For the board format, the `Pull request:` line, and the archive rules, see `.claude/standards/tasks.md`.
287
299
 
300
+ ## Comments
301
+
302
+ `aitk comments scan [path]` reports comment density for a tree, split by language and by comment kind. It is the only command that parses the target's own source, so its scope stays deliberately narrow: TypeScript and bash, line-oriented, no AST.
303
+
304
+ ```bash
305
+ aitk comments scan
306
+ aitk comments scan src --json
307
+ aitk comments scan --since v0.5.0
308
+ ```
309
+
310
+ | Option | Behavior |
311
+ | -------------------- | --------------------------------------------------------------- |
312
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
313
+ | `--since <rev>` | Report the trend from this revision instead of a snapshot alone |
314
+ | `--languages <list>` | Comma-separated subset of `ts,sh` (default: both) |
315
+
316
+ A line counts as a comment when its first non-whitespace token opens one, which is what keeps a URL in a string literal from reading as a `//` comment without a parser. Density is `commentLines / lines`, reported and never graded. The command produces the number and a rule produces the judgment.
317
+
318
+ Two exclusions are structural rather than tuning. Heredoc bodies are dropped from both the numerator and the denominator, because a scenario script carrying markdown inside one has `#` opening a heading rather than a comment, which inflated a measured 112 comment lines to 427. Fixture trees are pruned by path segment for the same reason. The line-1 shebang is not a comment, since every script has one and counting it puts a floor under density that reports the file count.
319
+
320
+ `--since` recomputes each point from git via `ls-tree` and `cat-file --batch`, checking nothing out. No ledger is written or read. Six points spread evenly across the window by default, and the boundary revision is always included so the series keeps the reading it is measured against. This works only because density is a pure function of a tree. Which author or session wrote a comment is not recoverable from git and does not belong here.
321
+
322
+ The degradation sweep reads its vocabulary from whichever rule publishes a `## Degradation vocabulary` heading, preferring `.claude/rules/` over `governance/rules/`, so one definition serves the toolkit and every target. Discovery anchors on the heading rather than a filename, because a renumbered rule would otherwise empty the vocabulary while the sweep still reported clean. With no such rule the sweep reports **skipped** rather than zero hits, since finding nothing and looking for nothing mean opposite things.
323
+
288
324
  ## Runtime catalogs
289
325
 
290
326
  Use these to discover what's available instead of hardcoding names.
@@ -77,7 +77,7 @@ Run `aitk tooling list --json` and `aitk gov list --json` to see the current cat
77
77
  `governance`, `standards`, and `wiki` are skippable:
78
78
 
79
79
  - `--skip governance`: leave `.claude/rules/` empty. Standards still install, so `.claude/standards/prose.md` lands with nothing pointing at it and no coding standard loads on a file match. The preview names any `--add` rules the skip drops, and the run prints the `aitk gov install <stack> <path>` command to add rules afterward, carrying those extras so one paste restores what the skip declined.
80
- - `--skip standards`: leave standards out. The governance rules still reference `.claude/standards/`, so their authority lines resolve to nothing. Toolkit skills are unaffected, since each falls back to the copy in its own plugin root.
80
+ - `--skip standards`: leave standards out. The governance rules still reference `.claude/standards/`, so their authority lines resolve to nothing. Toolkit skills are unaffected, since each falls back to the copy in its own plugin root. That fallback now carries runtime behavior rather than reference prose alone, because the banned-character scan and the branch-slug transform are defined in the standards and cited by the skills that run them.
81
81
  - `--skip wiki`: skip the `.claude/wiki/` scaffold. A target that already carries a root `wiki/` keeps it, since the verb reports that folder rather than migrating it.
82
82
 
83
83
  ## Add a domain later
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@erclx/aitk",
3
3
  "type": "module",
4
- "version": "0.9.0",
4
+ "version": "0.11.0",
5
5
  "description": "Infrastructure and quality tooling for developer workflows",
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -23,4 +23,13 @@ mirror_dir "$PROJECT_ROOT/snippets" "$PROJECT_ROOT/.claude/snippets" -name "*.md
23
23
 
24
24
  # `internal/` is the surface the plugin does not symlink. Mirrored on its own so
25
25
  # toolkit sessions read it at a `.claude/` path like every other consumed copy.
26
- mirror_dir "$PROJECT_ROOT/internal" "$PROJECT_ROOT/.claude/internal" -name "*.md"
26
+ # `internal/rules/` is excluded because it lands in `.claude/rules/` below, and
27
+ # mirroring it here too would publish each rule at a second inert path. The
28
+ # exclusion is anchored to that one folder, since an unanchored `*/rules/*` would
29
+ # also drop a later `internal/standards/rules/` and report nothing for it.
30
+ mirror_dir "$PROJECT_ROOT/internal" "$PROJECT_ROOT/.claude/internal" -name "*.md" -not -path "$PROJECT_ROOT/internal/rules/*"
31
+
32
+ # `.claude/rules/` is a subset rather than a mirror, so it resolves through the
33
+ # stack machinery instead of a fourth `mirror_dir` call. The record naming the
34
+ # subset is `internal/governance.toml`.
35
+ bun "$PROJECT_ROOT/src/cli.ts" gov regen --root "$PROJECT_ROOT"
@@ -132,7 +132,7 @@ main() {
132
132
 
133
133
  log_step "Consumed copies"
134
134
  run_check "bash $PROJECT_ROOT/scripts/core/regen-claude-copies.sh" "Consumed-copy regen failed"
135
- assert_no_drift ".claude/standards .claude/snippets .claude/internal" "Consumed copies drifted. Run bun run check and commit .claude/standards, .claude/snippets, and .claude/internal."
135
+ assert_no_drift ".claude/standards .claude/snippets .claude/internal .claude/rules" "Consumed copies drifted. Run bun run check and commit .claude/standards, .claude/snippets, .claude/internal, and .claude/rules."
136
136
  log_info "Consumed copies clean"
137
137
 
138
138
  log_step "Skill references"
package/src/cli.ts CHANGED
@@ -17,6 +17,7 @@ import { register as slides } from '@/commands/slides'
17
17
  import { register as feedback } from '@/commands/feedback'
18
18
  import { register as transcripts } from '@/commands/transcripts'
19
19
  import { register as tasks } from '@/commands/tasks'
20
+ import { register as comments } from '@/commands/comments'
20
21
 
21
22
  const GREY = '\x1b[0;90m'
22
23
  const WHITE = '\x1b[1;37m'
@@ -44,6 +45,7 @@ function showHelp(): void {
44
45
  `${GREY}│${NC} feedback ${GREY}# Write toolkit feedback from stdin to .claude/review/${NC}`,
45
46
  `${GREY}│${NC} transcripts <url> ${GREY}# Fetch a YouTube transcript with metadata frontmatter${NC}`,
46
47
  `${GREY}│${NC} tasks [cmd] ${GREY}# Task board commands (archive)${NC}`,
48
+ `${GREY}│${NC} comments [cmd] ${GREY}# Measure comment density and trend (scan)${NC}`,
47
49
  `${GREY}│${NC}`,
48
50
  `${GREY}│${NC} ${WHITE}Sandbox:${NC}`,
49
51
  `${GREY}│${NC} aitk sandbox ${GREY}# Interactive scenario picker${NC}`,
@@ -73,6 +75,7 @@ function showHelp(): void {
73
75
  `${GREY}│${NC} pbpaste | aitk feedback`,
74
76
  `${GREY}│${NC} aitk transcripts https://youtu.be/VIDEO_ID`,
75
77
  `${GREY}│${NC} aitk tasks archive --pull-request 673 --json`,
78
+ `${GREY}│${NC} aitk comments scan src --json`,
76
79
  `${GREY}└${NC}`,
77
80
  ]
78
81
  console.log(lines.join('\n'))
@@ -107,5 +110,6 @@ slides(program)
107
110
  feedback(program)
108
111
  transcripts(program)
109
112
  tasks(program)
113
+ comments(program)
110
114
 
111
115
  program.parse()