@erclx/aitk 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,7 +65,7 @@ Scaffolding your first project? Start with target projects, then the AI workflow
65
65
  - [Operating model](docs/operating-model.md): orchestrator and worker roles for building across parallel sessions
66
66
  - [Visual design workflow](docs/visual-design-workflow.md): tiered guide for design and wireframe authoring
67
67
  - [Target projects](docs/target-projects.md): scaffold, add a domain later, sync upstream drift
68
- - [Agents](docs/agents.md): CLI flags, exit codes, and JSON output shapes
68
+ - [Agents](docs/agents/index.md): CLI flags, exit codes, and JSON output shapes
69
69
  - [Docs index](docs/index.md): every reference doc in this repo
70
70
 
71
71
  ## Development
@@ -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.39.0",
4
+ "version": "0.40.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -36,7 +36,7 @@ Read these from the project root on both paths, skipping any that do not exist:
36
36
 
37
37
  Read a standard from `${CLAUDE_SKILL_DIR}/../../standards/` instead when the project does not have it.
38
38
 
39
- On the source path, also read the UI surfaces matched in Step 1 plus `docs/agents.md` and `docs/index.md` for output shape or framing rules already documented.
39
+ On the source path, also read the UI surfaces matched in Step 1 plus `docs/agents/output-shape.md` and `docs/index.md` for output shape or framing rules already documented.
40
40
 
41
41
  On the greenfield path, also read `.claude/ARCHITECTURE.md` for platform, tech stack, and surface type. Do not scan `src/`, stylesheets, or UI modules. Step 1 already established they hold nothing.
42
42
 
@@ -7,13 +7,14 @@ description: What feature planning is for, the gaps it closes, and why it stops
7
7
 
8
8
  ## Gap
9
9
 
10
- Without this skill, implementation starts before anyone knows what it touches. A session reads no project context and rediscovers a settled constraint halfway through, the file list emerges as the work goes rather than before it, and the ambiguities that needed a decision get resolved silently in whichever direction the first edit happened to go.
10
+ Without this skill, implementation starts before anyone knows what it touches. A session reads no project context and rediscovers a settled constraint halfway through, the file list emerges as the work goes rather than before it, and the ambiguities that needed a decision get resolved silently in whichever direction the first edit happened to go. A constraint naming a surface to leave alone forbids two different acts at once, so the executing session picks one and the branch either grows an excluded concern or ships a reference to a file the change deleted.
11
11
 
12
12
  ## Must
13
13
 
14
14
  - Read the project's own Claude setup before scanning source, so the plan inherits decisions already made instead of reopening them
15
15
  - Name every file the work touches with the reason it is touched
16
16
  - Surface each unresolved ambiguity as a numbered question carrying a suggested answer and an empty answer slot, so the plan is decision-ready in one pass
17
+ - State which act a constraint forbids when it names a surface to leave alone, since conforming that surface and retargeting a pointer into it are different acts and only one is out of scope
17
18
  - Scale the output to the work. A two-file change with nothing to decide should not produce a plan file.
18
19
  - Stop at the plan and wait to be told to continue
19
20
 
@@ -38,13 +38,21 @@ Measure against the tree rather than recall. Grep for each construct the plan wi
38
38
  Construct the plan with these sections:
39
39
 
40
40
  - **Summary:** three to five one-line bullets covering the goal, the main deliverables, and the key trade-off or decision. Aimed at humans scanning the plan, not agents executing it. Full mode only.
41
- - **Constraints:** durable rules the work must respect (patterns to reuse, surfaces not to touch, platform limits). Optional. Include when an orchestrator or prior context supplies them, omit the section otherwise.
41
+ - **Constraints:** durable rules the work must respect (patterns to reuse, surfaces not to touch, platform limits). Optional. Include when an orchestrator or prior context supplies them, omit the section otherwise. A constraint naming a surface to leave alone carries the distinction under Constraints below.
42
42
  - **Files to touch:** each file with a one-line reason
43
43
  - **Risks:** conflicts, coupling, or tricky spots. When the plan establishes a resource with more than one consumer, list the consumers and mark each read or write, because a policy stated over that resource has to hold for the writers and not just the consumer that prompted it. If none, use `None identified.`
44
44
  - **Questions:** numbered list of things to resolve before starting. Each carries a `- Suggested:` line and an `- Answer:` slot (see Suggestions below). If none, use `None identified.`
45
45
 
46
46
  Prefer `None identified.` over low-signal fillers. A small feature should produce a short plan, not a padded one. Small mode skips the summary since the plan is already short enough to scan in full.
47
47
 
48
+ ### Constraints
49
+
50
+ A constraint naming a surface to leave alone forbids two different acts. Name which one, since a constraint carrying only the surface leaves the executing session to guess.
51
+
52
+ - Forbid conforming the surface to whatever shape the change introduces. This is the act a scope constraint means, and it keeps the branch from growing a second concern.
53
+ - Never forbid retargeting a pointer the change breaks. A rename, a split, or a deletion that leaves a citation behind ships a dangling reference, so fixing it is required work rather than scope creep.
54
+ - Decide both acts for every surface the constraint names. Carving the distinction out for one file and leaving its siblings under the bare wording is how a plan ships one correct call beside one broken reference.
55
+
48
56
  ### Suggestions
49
57
 
50
58
  Attach a `- Suggested:` line to every question, then an empty `- Answer:` slot below it. A blank answer means accept the suggestion at execution time. This makes the plan decision-ready in one pass, with no separate decision-help round.
@@ -145,4 +145,4 @@ Replace bracketed values with the values from this run. Drop the "Folders bootst
145
145
  ## Reference
146
146
 
147
147
  - `.claude/context/indexes.md`: system rationale, frontmatter contract, when to adopt
148
- - `docs/agents.md`: `aitk indexes regen` flags, exit codes, JSON shape
148
+ - `docs/agents/indexes.md`: `aitk indexes regen` flags, exit codes, JSON shape
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Capture
3
+ description: Rendering committed HTML sources to PNG, what the command asserts about fonts, and why it is toolkit-only
4
+ ---
5
+
6
+ # Capture
7
+
8
+ `aitk capture [source]` renders HTML capture sources to PNG, which is how a committed documentation image regenerates from its committed source. The source defaults to `assets/`, where a directory expands to every `.html` directly inside it, so adding a capture means dropping a file beside the first one and running the same bare command.
9
+
10
+ ```bash
11
+ aitk capture
12
+ aitk capture assets/install.html
13
+ aitk capture assets --out .claude/review/captures
14
+ ```
15
+
16
+ `assets/` now holds two sources, so a bare `aitk capture` rebuilds both. `install.html` is hand-authored and its text came from a real run. `hero.html` is generated by `scripts/core/regen-hero.sh` from the CLI catalogs and must not be edited by hand, since `bun run check` regenerates it and fails on the difference. Only the HTML is asserted for drift. The PNG is a chromium render whose bytes move with the browser version, so rebuild it with `aitk capture assets/hero.html` when the check reports the HTML changed.
17
+
18
+ | Option | Behavior |
19
+ | ------------------ | ------------------------------------------------- |
20
+ | `--out <dir>` | Write every PNG here instead of beside its source |
21
+ | `--selector <sel>` | Element to capture (default: `.window`) |
22
+
23
+ ## What the command asserts
24
+
25
+ Each source renders at `deviceScaleFactor` 2 with a transparent background, and the success line reports the pixel dimensions the element wrapped to. Size is reported and never asserted. The height of a terminal frame is whatever its text wrapped to at a fixed width, so pinning that number would harden an accident.
26
+
27
+ What is asserted is the font. The command reads the first family the captured element declares and fails when the browser did not resolve it, because a fallback face rewraps the block and silently changes the output. Sources therefore name a real font rather than relying on `monospace`. A source that cannot render reports its own line and exits 1 without dropping the rest of the batch.
28
+
29
+ The browser binary installs separately from the package. A fresh clone runs `bunx playwright install chromium` once, and a run that cannot launch one reports the engine's own remediation inside the frame and exits 1 rather than escaping as a stack trace.
30
+
31
+ The command is toolkit-only. Its render module holds every browser reference in the toolkit and `files` in `package.json` excludes it, so an installed `aitk` carries the command, reports it as absent on one line, and exits 1. Every other command is unaffected, which is the reason the browser import sits behind a dynamic import rather than at a command's top level.
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: Command catalog
3
+ description: Every project-level command and every domain subcommand, plus the shape each domain exposes
4
+ ---
5
+
6
+ # Command catalog
7
+
8
+ Full help: `aitk <command> --help`. Behavior notes for the install and sync verbs live in `install-and-sync.md`.
9
+
10
+ ## Project-level
11
+
12
+ | Command | Purpose |
13
+ | ------------------------ | ---------------------------------------------------------------------------------------------- |
14
+ | `aitk init [path]` | Bootstrap a project with selected toolkit domains |
15
+ | `aitk sync [path]` | Sync all installed domains in a target project |
16
+ | `aitk sync --check` | Report toolkit drift without writing (`--json`, `--exit-code`) |
17
+ | `aitk sandbox [cat:cmd]` | Run sandbox scenarios (interactive or routed), toolkit-only like the tree it reads |
18
+ | `aitk sandbox reset` | Reset sandbox to baseline |
19
+ | `aitk sandbox clean` | Wipe the sandbox |
20
+ | `aitk sandbox check` | Score a provisioned sandbox against a scenario expectation (`--json` for the verdict) |
21
+ | `aitk sandbox coverage` | Report which scenarios declare expectations (`--json`, `--strict`, `--skills`) |
22
+ | `aitk indexes regen` | Regenerate `index.md` files from sibling frontmatter |
23
+ | `aitk docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
24
+ | `aitk design render` | Render `.claude/DESIGN.md` tokens to HTML and CSS |
25
+ | `aitk slides render` | Render a `.claude/SLIDES.md` source into a PowerPoint deck |
26
+ | `aitk slides list` | List the available slide layouts (`--json` for the catalog) |
27
+ | `aitk feedback` | Write toolkit feedback from stdin to `.claude/review/`, or open a GitHub issue with `--github` |
28
+ | `aitk transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
29
+ | `aitk tasks archive` | Move a shipped task off the board, clear its ordering row, and regenerate the index |
30
+ | `aitk comments scan` | Measure comment density by language and comment kind, with a trend recomputed from git |
31
+ | `aitk context audit` | Report required sections, length, depth, bullet weight, cited paths, provenance, and drift |
32
+ | `aitk capture [source]` | Render HTML capture sources to PNG, toolkit-only and absent from an installed package |
33
+
34
+ ## Domain commands
35
+
36
+ Each domain exposes a consistent shape where applicable: `list`, `install`, `sync`, `create`.
37
+
38
+ | Domain | Subcommands |
39
+ | ----------- | ---------------------------------------------------------------------- |
40
+ | `tooling` | `list`, `sync`, `ref`, `create`, `verify`, `inject`, `prune-gitignore` |
41
+ | `snippets` | `list`, `install`, `sync`, `create` |
42
+ | `standards` | `list`, `install`, `sync` |
43
+ | `gov` | `list`, `install`, `sync`, `build` |
44
+ | `claude` | `init`, `sync`, `seeds list`, `skills list`, `setup [dest]` |
45
+ | `wiki` | `init` |
46
+ | `design` | `render` |
47
+ | `slides` | `render`, `list` |
48
+ | `tasks` | `archive` |
49
+ | `comments` | `scan` |
50
+ | `context` | `audit` |
51
+
52
+ Common patterns:
53
+
54
+ - `list --json` → machine-readable catalog on stdout.
55
+ - `install <name> <path>` → install a specific entry into a target project.
56
+ - `sync <path>` → reapply all installed entries in a target project.
57
+ - `create [name]` → scaffold a new authoring entry in this repo.
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Comments
3
+ description: Comment density by language and kind, the two structural exclusions, and how the degradation sweep finds its vocabulary
4
+ ---
5
+
6
+ # Comments
7
+
8
+ `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.
9
+
10
+ ```bash
11
+ aitk comments scan
12
+ aitk comments scan src --json
13
+ aitk comments scan --since v0.5.0
14
+ ```
15
+
16
+ | Option | Behavior |
17
+ | -------------------- | --------------------------------------------------------------- |
18
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
19
+ | `--since <rev>` | Report the trend from this revision instead of a snapshot alone |
20
+ | `--languages <list>` | Comma-separated subset of `ts,sh` (default: both) |
21
+
22
+ 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.
23
+
24
+ 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.
25
+
26
+ `--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.
27
+
28
+ ## Degradation sweep
29
+
30
+ 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.
31
+
32
+ `090-code-comments` is the rule that publishes the list, and it ships on the `base` stack. A project that installs or syncs governance for the first time after that rule landed gets a sweep that previously reported skipped, so hits appear where the command used to stay quiet. Edit the backticked terms in the installed copy to change what that project sweeps for. The sweep matches comment text, so a comment naming a term as an example is a hit, and a hit is a prompt to read the line rather than a verdict on it.
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Context audit checks
3
+ description: What each non-gating check reports, the unit each checkpoint is measured in, and which folders each check reaches
4
+ ---
5
+
6
+ # Context audit checks
7
+
8
+ What each finding from `aitk context audit` means. The command surface, its flags, and the one gating check are in `context-audit.md`.
9
+
10
+ ## Required sections
11
+
12
+ The required-section check reports what does not declare `## Overview` and `## Layout`, the two sections `.claude/standards/context.md` marks required. The list is held in code beside the numeric checkpoints rather than parsed out of the standard, so it fails on a defect rather than on a rewrite of the wording around it. A heading at any level counts, because a domain that split into a folder carries its overview in a sibling named `overview.md` where the section is the `#` title and an `##` beneath it would repeat the filename. Matching exactly is what keeps `## Layout catalog` from satisfying `Layout`.
13
+
14
+ Which unit answers depends on the folder. Entries of the folder named under `.claude/` are one domain each, so each answers for itself and a finding names the entry. Entries of a folder a domain split into describe that one domain between them, so any sibling answers and a finding names the folder. Holding a split folder to the rule per file would report every child beside its `overview.md`, and rolling the named folder up would let one conforming entry stand in for every other domain sitting next to it.
15
+
16
+ It reports rather than gates, the closer call because a missing section reads more like a fact than the other judgments. What settles it is that the standard sanctions omitting `## Layout` from a domain owning no paths in the repo, and no measure separates that from an entry that forgot it. A domain covering only external tools is that case, and it reports on every run. The JSON record carries the findings as `missingSections` and the list as `checkpoints.requiredSections`.
17
+
18
+ ## Length and depth
19
+
20
+ Length and depth quote their checkpoints from `.claude/standards/context.md`: roughly 150 rendered lines for an entry, roughly 40 for a run no heading breaks. Depth measures the longest such run rather than everything under one `##`, skips fenced blocks so a markdown example does not read as three headings, and exempts a run whose lines are all list items at one indent averaging under 130 characters. The weight condition is what separates a scannable catalog of one-liners from a stack of paragraph-bullets, which reach the same count and read nothing alike.
21
+
22
+ Both checks count rendered lines rather than source lines, wrapping each line at 80 columns and summing the heights. Entries here are authored one line per bullet, so a block of fifteen paragraph-bullets occupies fifteen source lines and renders past sixty, which source counting cannot see. Measuring one checkpoint in each unit would put an entry length beside a run length that mean different things. Their exclusions still differ: the file measure counts fenced blocks and frontmatter, while the run measure skips a fence so an example cannot break the run around it. A reference-heavy entry therefore ranks by its examples, which the length legend states on every run. Runs count blank lines, which the standard leaves open, so a hand reader who drops them lands a line or two lower. Both sections state the width on every run, since a number in rendered lines cannot be reproduced without it.
23
+
24
+ ## Bullet weight and tables
25
+
26
+ The bullet check reports a top-level bullet past roughly 400 characters, which is where a bullet stops carrying a decision alone and starts carrying the incident that motivated it beside the decision. Continuation lines fold into the bullet they belong to, so a heavy bullet cannot fall under the checkpoint by wrapping across two source lines, while a nested item is left out because the parent's own text is what the checkpoint asks about. Findings group by entry and narrow to `.claude/context/` for the reasons the provenance ones do both. Unlike the peer-list threshold above it, this corpus has no gap behind the number: bullet weight decays smoothly from a median near 170, so the number is a judgment where that one was a measurement, and a bullet reading well past it means the number is wrong rather than the rule.
27
+
28
+ The table check reports a catalog that grows a row per shipped thing, not a table count. A fixed comparison table never reflows, so its size costs nothing. A table qualifies at six or more body rows whose first column mostly carries a path, command, or link, which is what separates a catalog from a comparison without reading the prose.
29
+
30
+ ## Provenance
31
+
32
+ The provenance check reports the markers narrating how a domain reached its shape rather than describing what it is: a date, a change number, or a release label. The standard admits a rejected alternative and the reasoning that killed it while refusing the provenance attached to it, so a marker names a line to read rather than a line to delete. Findings group by entry and sort left to right within a line, since what a reader acts on is which file to open. Fenced blocks are excluded, which keeps a pinned version in an install command from reading as a claim the entry makes. Frontmatter is excluded with them, since the content checks read the body alone, and that is what keeps a diagram entry's dated `verified` stamp a record of its last check rather than a marker to settle. Length is the exception, counting the whole file, so a reader applying the 150-rendered-line checkpoint against the body alone lands a few lines under what the tool reports.
33
+
34
+ ## Which folders each check reaches
35
+
36
+ The provenance, bullet-weight, and required-section checks cover `.claude/context/` alone, while length, depth, and the table finding reach every audited folder. The rule is stated in `.claude/standards/context.md`, which opens its scope by handing diagrams and wireframes to `diagrams.md` and `wireframes.md`, and the sibling standards do not restate it. A marker reported in a diagram entry would cite a rule that entry's own standard routes elsewhere. The split is between kinds of rule rather than kinds of folder, and what decides it is whether the remedy is actionable rather than what the check measures. Subdividing a run and splitting a file mean something in any entry, so length and depth generalize. Moving an incident out of a bullet and keeping the decision means nothing in a folder whose entries declare no decisions, which is why bullet weight narrows despite measuring a distance like the two that do not. Required sections narrow for a plainer reason: the names are the context standard's own, and neither sibling standard states a required section at all. The scoping key is the folder an entry was audited under, so `--folder` still reaches a folder the default list does not carry, and a domain split into `context/<sub-area>/` is governed as `context`. Every run states the reach, including a run where no audited folder is the governed one. The JSON record carries it as `checkpoints.provenanceFolder` and a per-folder `governsContent`.
37
+
38
+ ## Index drift
39
+
40
+ Index drift compares an index against its siblings in both directions. An entry the index does not link is invisible to a session choosing what to open, and a linked name resolving to nothing sends one to a path that opens nothing.
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Context audit
3
+ description: Running the audit, its flags and folder scope, the exit codes, and the citation gate that is the only failing one
4
+ ---
5
+
6
+ # Context audit
7
+
8
+ `aitk context audit [path]` reports the structural state of the folders following the index-plus-entry contract, meaning a generated `index.md` beside entries carrying frontmatter. It reads and reports. Fixing what it finds is separate work. What each finding means is in `context-audit-checks.md`.
9
+
10
+ ```bash
11
+ aitk context audit
12
+ aitk context audit --json
13
+ aitk context audit --citations-only
14
+ aitk context audit --folder context,diagrams
15
+ aitk context audit --folder docs
16
+ ```
17
+
18
+ | Option | Behavior |
19
+ | ------------------ | -------------------------------------------------------------------- |
20
+ | `--json` | Add a machine-readable record on stdout, keeping the frame |
21
+ | `--folder <list>` | Comma-separated folder names (default: the three below) |
22
+ | `--citations-only` | Run the gating citation check alone, printing nothing when it passes |
23
+
24
+ ## Folder scope
25
+
26
+ Scope defaults to `context`, `diagrams`, and `wireframes`, and a folder the project does not carry is skipped rather than reported. A domain that outgrew one file and split into `<domain>/` is audited as its own folder, so a split entry measures at the same grain as a flat one.
27
+
28
+ A name passed to `--folder` resolves under `.claude/` first and at the project root second, which is what puts `docs/` and any later corpus in reach of the same engine. The root base is reached only by a name the caller passes, so the default list still resolves under `.claude/` alone and a project holding a root `wireframes/` is not audited against a standard it never adopted. The scope line prints the resolved path, so a project carrying both spellings reads which one was taken. The JSON record carries the base per folder as `folders[].base`.
29
+
30
+ A run where no requested name resolves refuses, whichever list it read. Naming the absent ones narrows to `--folder`, since a project carrying one of the three default folders is the ordinary case and a name it never asked for is not a typo. The JSON record carries those names as `unresolvedFolders`.
31
+
32
+ ## Exit codes
33
+
34
+ Exit codes are `0` for a clean run, `1` for a refusal, and `2` for an unresolved citation. Only the citation check sets a failing code. Required-section, length, depth, bullet weight, table, provenance, and index findings print and return `0`, because each is a judgment and failing a push on one would make the check something to route around.
35
+
36
+ ## The citation gate
37
+
38
+ The citation check resolves every path into an audited folder that appears anywhere in the repository, and it is the half wired into `bun run check`. A stale reference has a silent failure mode: the session opens nothing and carries on.
39
+
40
+ Three exclusions keep it from firing on prose about paths. Fenced blocks are skipped in markdown, which covers a standard displaying a path as an example. Fixture and harness trees are skipped by location, covering sandbox scenarios that describe their own scratch tree, the eval harness naming its target project, and `*.test.ts`. A path into a folder the project does not carry is skipped, so a skill directing a reader to `.claude/wireframes/index.md` stays valid in a project that has wireframes and silent in one that does not.
41
+
42
+ What remains is a sentence naming a hypothetical entry to show the shape of a name, which no syntax separates from a real reference. Append `<!-- audit-ignore-citations -->` to that source line. The marker suppresses citation checking for its own line only.
43
+
44
+ The pattern spells the `.claude/` prefix, so a folder resolved at the project root is measured by every other check and contributes nothing here. Widening it to a bare `docs/x.md` would match prose that references nothing, which is a separate decision from where entries come from. A run whose folders all resolved at the root says the check is out of scope rather than reporting that zero paths resolved, and the same run under `--citations-only` refuses, because a gate exiting clean on a scope it could not build is the failure the gate exists to catch.
@@ -0,0 +1,17 @@
1
+ ---
2
+ title: Docs
3
+ description: How aitk docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
4
+ ---
5
+
6
+ # Docs
7
+
8
+ `aitk docs` emits the toolkit's own reference docs so an agent in a target project can orient without the toolkit source checked out. The CLI resolves `docs/` and `.claude/context/` from its install root, and which of the two it finds depends on how the CLI was installed. A registry install carries `docs/` alone, since `.claude/` is not published. A clone or a linked worktree carries both.
9
+
10
+ - `aitk docs list [--json]` lists the downstream catalog: the consumer-facing `docs/` surface plus per-domain narrative from `.claude/context/` when that root is present. Toolkit-internal context entries (`ci`, `development`, `extensions`, `sandbox`) are dropped. From a registry install the context section is absent rather than empty.
11
+ - `aitk docs <topic>` prints one doc to stdout, resolved by exact name from `docs/` first, then `.claude/context/`. Any doc the install carries is reachable by name, including the toolkit-internal topics the list omits.
12
+
13
+ A domain too large for one file splits into `<domain>/` with a generated `index.md`, and both verbs name it by the folder. `aitk docs <domain>` prints that index, which is the catalog routing to the sub-area files, and the listing describes it from the index's `subtitle` where a sibling file supplies `description`. A sibling file wins over a folder of the same name. A folder carrying no `index.md` is absent from both, since a catalog is what makes the sub-areas reachable.
14
+
15
+ Data prints to stdout and the frame to stderr, so `aitk docs <topic> > out.md` captures clean markdown. With no topic and no verb, `aitk docs` runs `list`. An unknown topic names the available topics on stderr and exits 1.
16
+
17
+ Only a `---` block opening on the first line counts as frontmatter, so a document body carrying horizontal rules emits whole.
@@ -0,0 +1,23 @@
1
+ ---
2
+ title: Agents
3
+ subtitle: CLI catalog and invocation rules for agents, split by command domain. Start with overview.
4
+ category: Agent surface
5
+ ---
6
+
7
+ # Agents
8
+
9
+ CLI catalog and invocation rules for agents, split by command domain. Start with overview.
10
+
11
+ - [Capture](capture.md): Rendering committed HTML sources to PNG, what the command asserts about fonts, and why it is toolkit-only
12
+ - [Command catalog](commands.md): Every project-level command and every domain subcommand, plus the shape each domain exposes
13
+ - [Comments](comments.md): Comment density by language and kind, the two structural exclusions, and how the degradation sweep finds its vocabulary
14
+ - [Context audit checks](context-audit-checks.md): What each non-gating check reports, the unit each checkpoint is measured in, and which folders each check reaches
15
+ - [Context audit](context-audit.md): Running the audit, its flags and folder scope, the exit codes, and the citation gate that is the only failing one
16
+ - [Docs](docs.md): How aitk docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
17
+ - [Indexes](indexes.md): Flags, exit codes, and JSON shape for aitk indexes regen, plus when it auto-stages what it rewrote
18
+ - [Install and sync](install-and-sync.md): What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
19
+ - [Output shape](output-shape.md): The two framed shapes every command renders into, and how JSON and --names modes keep stdout clean
20
+ - [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
21
+ - [Sandbox](sandbox.md): Scenario routing, the expectation scoring surface, and the coverage census over scenarios and skills
22
+ - [Scripting](scripting.md): The runtime catalogs that replace hardcoded names, what each carries, and a headless invocation per domain
23
+ - [Tasks](tasks.md): Selecting a shipped task by stem or pull request, the refusal reasons, and why the board root defaults to the main worktree
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Indexes
3
+ description: Flags, exit codes, and JSON shape for aitk indexes regen, plus when it auto-stages what it rewrote
4
+ ---
5
+
6
+ # Indexes
7
+
8
+ `aitk indexes regen` rewrites `index.md` files from sibling frontmatter. With no positional paths, it walks the current directory. With paths, each resolves by walking up to the nearest indexed ancestor, bounded by `--root`. Duplicates dedupe. The whole-repo walk prunes `.git`, `node_modules`, and anything `.gitignore` covers via `git check-ignore`.
9
+
10
+ A positional path is not filtered that way, because the walk-up resolves on the filesystem and never consults git. That is the only way to regenerate an index inside a gitignored folder, and it is how `.claude/tasks/` stays current.
11
+
12
+ | Option | Behavior |
13
+ | --------------- | ---------------------------------------------------------------- |
14
+ | `--dry-run` | Report which indexes would change without writing |
15
+ | `--json` | Emit a machine-readable record per index on stdout |
16
+ | `--root <path>` | Walk-up boundary when positional paths are passed (default: CWD) |
17
+ | `--no-stage` | Skip the auto `git add` on modified indexes |
18
+
19
+ Exit codes: `0` clean, `1` frontmatter error or missing index, `2` drift found in `--dry-run`.
20
+
21
+ When positional paths are passed inside a git repo, modified `index.md` files are staged so lint-staged and Claude `PostToolUse` hooks commit the regenerated catalog. Whole-repo walks never auto-stage, and neither does a path git ignores, since staging one always fails and the warning would fire on every edit.
22
+
23
+ Skills can parse drift without branching on exit code:
24
+
25
+ ```bash
26
+ aitk indexes regen --dry-run --json | jq '.results[] | select(.action == "would-write")'
27
+ ```
28
+
29
+ For the system rationale, frontmatter contract, when to adopt, and bootstrap path, see `.claude/context/indexes.md`.
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: Install and sync
3
+ description: What each install and sync verb writes, refuses, or leaves alone, and how drift is attributed in a target project
4
+ ---
5
+
6
+ # Install and sync
7
+
8
+ The behavior notes behind the verbs listed in `commands.md`. Each one records what the verb writes, what it refuses, and what it deliberately leaves alone.
9
+
10
+ ## Domain sync
11
+
12
+ `aitk gov sync` updates only rules already present under `.claude/rules/` and
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`
15
+ from the retired build. Use `aitk gov install` to add rules.
16
+
17
+ `aitk standards sync` matches by filename against `.claude/standards/` and
18
+ regenerates that folder's `index.md` on every completed run. It is the one sync
19
+ that refuses under `AITK_NON_INTERACTIVE=1` when drift exists, logging a warning
20
+ and exiting 0 without writing, because standards are seeds a project edits. Run
21
+ it interactively, or use the `claude-seed-sync` skill for a per-section audit
22
+ that preserves customizations.
23
+
24
+ `aitk snippets sync` behaves the same way against `.claude/snippets/`. It
25
+ matches by path relative to that directory, so a snippet the toolkit no longer
26
+ ships, or one authored directly in the target, is reported and skipped rather
27
+ than deleted. It is not preset-aware, so a project that installed `essentials`
28
+ does not grow new snippets on a sync. Use `aitk snippets install` to add them.
29
+
30
+ ## Install guards
31
+
32
+ `aitk gov install` and `aitk snippets install` require their first argument
33
+ under `AITK_NON_INTERACTIVE=1`. Both used to fall back to an interactive picker
34
+ that resolved to its first option headlessly, so `aitk gov install` with no
35
+ stack installed whichever stack sorted first and `aitk snippets install` with no
36
+ category installed every category. Each now reports the valid names on stderr
37
+ and exits 1. Every documented agent path already passes the argument, including
38
+ `aitk init`. The confirm-then-apply prompt after it still resolves to `Yes`
39
+ headlessly, so a call that names its stack or category is unchanged.
40
+
41
+ `aitk gov install` also refuses the toolkit root as a target, matching
42
+ `aitk snippets install`. Both resolve the target before anything else, so a path
43
+ that does not exist fails rather than being scaffolded.
44
+
45
+ ## Governance regen
46
+
47
+ `aitk gov regen` is the one governance verb that runs against the toolkit root,
48
+ because the `.claude/rules/` it writes there is produced output rather than an
49
+ operator's working copy. It reads the stack recorded in `internal/governance.toml`,
50
+ installs it alongside anything under `internal/rules/`, and clears the
51
+ destination first so a rule the record stopped naming disappears. It takes
52
+ `--root <path>` and defaults to the toolkit root, prints nothing on success, and
53
+ reports the reason on stderr with exit 1 when the record names a stack or rule
54
+ that does not resolve. `scripts/core/regen-claude-copies.sh` calls it, and the
55
+ Consumed copies stage of `bun run check` asserts the result is committed.
56
+
57
+ ## Whole-project sync
58
+
59
+ `aitk sync` runs every installed domain sync, then offers to commit the result
60
+ and open a pull request. Under `AITK_NON_INTERACTIVE=1` it applies the domain
61
+ syncs and then refuses the git workflow, reporting the branch and commit it
62
+ would have created and exiting 0. Nothing is staged, committed, or pushed
63
+ headlessly. Run it interactively to reach the commit and pull request options.
64
+ It also refuses a target whose working tree is dirty, so commit or stash first.
65
+
66
+ ## Drift reporting
67
+
68
+ `aitk sync --check` reports drift and writes nothing, so it needs no clean tree
69
+ and is safe to run at any time. Each file is classified as `stale` when it still
70
+ matches what the toolkit installed, `customized` when the project edited it,
71
+ `stranded` when it sits at a path the toolkit no longer installs to, `orphaned`
72
+ when the project authored it, or `drifted` when no stamp covers it. Use `--json`
73
+ for the machine-readable report and `--exit-code` to fail a CI job. Orphaned
74
+ files are excluded from that exit code, since a project-authored rule never
75
+ converges. Attribution reads `.claude/aitk.json`, which every install and sync
76
+ writes.
77
+
78
+ A target installed before stamping shipped has no such file, and the report
79
+ falls back to the toolkit's own git history. Installed content matching any
80
+ version that history ever published proves the file is untouched, so it reports
81
+ `stale` naming the commit it came from, and content matching no published
82
+ version stays `drifted`. A toolkit reached outside a git clone, which is what a
83
+ registry install is, cannot run that fallback and reports
84
+ `historyUnavailable` alongside the unattributed files.
85
+
86
+ Each domain carries its own toolkit anchor in that file, so syncing one domain
87
+ never advances the revision another measures from, and each reports the upstream
88
+ commits touching its own source path. The `covers` field names the domains a
89
+ target has actually stamped, so a domain that was never stamped is legible
90
+ rather than reading as a clean one.
91
+
92
+ ## Bootstrap
93
+
94
+ `aitk init` installs up to six core domains and reports each one independently. A
95
+ domain that fails does not abort the run, so the command finishes the rest and
96
+ exits 1 naming the failures. Passing any flag skips the confirmation prompt,
97
+ which is what makes it scriptable. `--stack` defaults to `base`, and the default
98
+ does not read as a passed flag, so a bare `aitk init` installs governance and
99
+ still prompts. `--skip` takes `wiki`, `standards`, and `governance`, and warns
100
+ without aborting on any other value.
101
+
102
+ ## Unguarded tooling primitives
103
+
104
+ `aitk tooling inject` and `aitk tooling prune-gitignore` are the unguarded
105
+ primitives beneath `sync`. They apply one stack with no scan and no prompt, and
106
+ they deliberately skip the check that rejects `claude`, which is how `aitk
107
+ claude` drives its own stack through them. Use `sync` unless you are scripting
108
+ provisioning. Both frame their own output, so pass `--nested` when calling from
109
+ inside an already-open frame.
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Output shape
3
+ description: The two framed shapes every command renders into, and how JSON and --names modes keep stdout clean
4
+ ---
5
+
6
+ # Output shape
7
+
8
+ Every CLI command renders into one of two framed shapes. Data goes to stdout. UI and logs go to stderr. Help output is the exception. It prints to stdout so it can be piped and grepped.
9
+
10
+ ## Data shape (lists, runs, errors)
11
+
12
+ ```plaintext
13
+
14
+ │ aitk <domain>
15
+
16
+ ├ Section
17
+ │ ✓ item
18
+ │ ✓ item
19
+
20
+ ```
21
+
22
+ Rules:
23
+
24
+ - `┌` opens the frame on stderr
25
+ - `│ aitk <domain>` is the command banner, one per invocation
26
+ - `├ Section` headers introduce groups of items. `log_step` produces the blank `│` spacer before each.
27
+ - `└` closes the frame on stderr, wired via `trap close_timeline EXIT`
28
+ - Errors render as `│ ✗ message` inside the same frame. Never emit a lone error line without a frame.
29
+
30
+ ## Help shape
31
+
32
+ ```plaintext
33
+
34
+ ├ Usage: aitk <domain> [command]
35
+
36
+ │ Commands:
37
+ │ ...
38
+
39
+ ```
40
+
41
+ Help skips the banner. The `Usage:` line sits directly on `├`. Help writes to stdout because `--help` is documentation, not runtime UI.
42
+
43
+ ## JSON and `--names` modes
44
+
45
+ `--json` and `--names` keep stdout clean and machine-readable. The frame still renders on stderr (open, banner, close) so the stream discipline is consistent across modes. Consumers that only read stdout see pure data.
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Overview
3
+ description: What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
4
+ ---
5
+
6
+ # Overview
7
+
8
+ CLI catalog and invocation rules for agents working in this repository.
9
+
10
+ This folder is an index of what an agent can run and how to run it cleanly from a script. It does not cover domain behavior. Read `CLAUDE.md` for project behaviors and load the matching `.claude/skills/aitk-*` skill when working inside a domain.
11
+
12
+ ## Invocation rules
13
+
14
+ See `CLAUDE.md` design principles. They apply to every command in this folder.
15
+
16
+ ## Where to start
17
+
18
+ - `output-shape.md`: the stream contract every command renders into, which is what a caller parsing stdout depends on
19
+ - `commands.md`: the full command catalog, project-level and per-domain
20
+ - `scripting.md`: the runtime catalogs that replace hardcoded names, plus headless invocation examples
21
+
22
+ ## Related
23
+
24
+ - `CLAUDE.md`: project behaviors and design principles
25
+ - `.claude/skills/aitk-*`: domain-scoped guidance for editing work
26
+ - `docs/index.md`: full docs directory
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Sandbox
3
+ description: Scenario routing, the expectation scoring surface, and the coverage census over scenarios and skills
4
+ ---
5
+
6
+ # Sandbox
7
+
8
+ `aitk sandbox` provisions isolated project states, scores a provisioned one against a declared expectation, and reports which scenarios declare an expectation at all.
9
+
10
+ ## Scenarios
11
+
12
+ Scenarios live under `scripts/sandbox/`, one folder per category. `scripts/sandbox/fixtures/` is the exception, holding file content that scenarios stage rather than scenarios of its own, so both pickers filter it out. `files` in `package.json` excludes that tree, so an installed `aitk` carries the command, reports it as toolkit-only on one line, and exits 1 rather than failing on the missing directory. Route non-interactively with `SANDBOX_SCENARIO`:
13
+
14
+ ```bash
15
+ SANDBOX_SCENARIO=sync aitk sandbox infra:tooling
16
+ ```
17
+
18
+ Scenario categories: `infra:*` (domain flows), `git:*`, `scaffold:*`. `create` scenarios require interactive input and loop on empty input, so skip them in automated runs.
19
+
20
+ ## Scenario expectations
21
+
22
+ `aitk sandbox check <category>:<command> [arm]` scores a provisioned sandbox against the arm's `expect.toml`, printing a verdict on stderr and, with `--json`, the same verdict as a record on stdout.
23
+
24
+ ```bash
25
+ aitk sandbox check claude:docs drift --json
26
+ ```
27
+
28
+ | Flag | Effect |
29
+ | ------------------- | ---------------------------------------------------------- |
30
+ | `--envelope <file>` | Read `is_error`, `num_turns`, denials, and the reply text |
31
+ | `--writes <file>` | Newline-delimited paths the session wrote, for write scope |
32
+ | `--json` | Emit the verdict record on stdout |
33
+ | `--strict` | Exit 1 on `unchecked` instead of 0 |
34
+
35
+ The verdict `state` is `pass`, `fail`, or `unchecked`. An arm with no `expect.toml` is `unchecked` and exits 0, so the harness stays usable while expectations roll out. A declaration that exists but asserts nothing is a failure, since an expectation file that asserts nothing passes every run.
36
+
37
+ Omitting `--writes` or `--envelope` does not silently drop the assertion kinds that need them. Write scope, the turn ceiling, and the reply assertion report as unchecked and appear in the count, so the standalone command cannot claim more coverage than it had. A verdict never reports `pass` with zero assertions.
38
+
39
+ An envelope that parses but carries no `result` field skips the reply assertion the same way an absent file does. An envelope carrying an empty `result` fails it, since a run that returned no text is a finding rather than a gap in the input.
40
+
41
+ Exit 0 means `pass` or `unchecked`. Exit 1 means `fail`, or a caller error: a malformed target, or a sandbox that was never provisioned. A missing sandbox reports as an error rather than a failed verdict, because failing every path assertion would read as a skill that did nothing. `--strict` moves `unchecked` to exit 1 for a caller that has finished arming its scenarios.
42
+
43
+ ## Scenario coverage
44
+
45
+ `aitk sandbox coverage` reports which scenarios declare expectations and which only provision a state. It reads the fixture tree, so it needs no provisioned sandbox and runs nothing. Where that tree does not ship it exits 1 and prints no percentage, since a denominator nobody looked at is not a coverage result. A tree that is present and holds no scenarios is a real zero and still reports one.
46
+
47
+ ```bash
48
+ aitk sandbox coverage --json
49
+ ```
50
+
51
+ | Flag | Effect |
52
+ | ---------- | ----------------------------------------------------------- |
53
+ | `--json` | Emit the coverage record on stdout |
54
+ | `--strict` | Exit 1 while any scenario declares no expectation |
55
+ | `--skills` | Add a per-skill asserted, should-be-asserted, exempt census |
56
+
57
+ The record carries every scenario with the arms that declare, plus `totalScenarios`, `armedScenarios`, and `armedArms`. Scenarios and arms count separately, since several arms can share one scenario and dividing one by the other overstates the rollout.
58
+
59
+ ### The skills census
60
+
61
+ `--skills` answers what the scenario count cannot, which is whether anything can fail a given skill. It adds `skills`, `totalSkills`, `asserted`, `shouldBeAsserted`, `exempt`, `staleExemptions`, and `supersededExemptions` to the record, and keeps the scenario view rather than replacing it. The two denominators disagree on purpose: an armed scenario under `infra/` or `tooling/` exercises a CLI domain and pairs with no skill at all.
62
+
63
+ A skill pairs to a scenario by filename, `<category>-<command>` first and bare `<command>` second, so `claude/setup-init.sh` reaches the `setup-init` skill. `should-be-asserted` is the default rather than a queue to drain, and which of those skills earns an arm is a project decision the census does not make. `exempt` means no arm should be written and holds only with a reason, declared in `scripts/sandbox/exempt.toml` and limited to a harness limit the checker cannot reach past or a skill that writes no artifact. An armed arm outranks an exemption. An exemption naming no shipped skill, or naming one an arm now asserts, exits 1 without `--strict`. Each armed arm reports as `<category>:<command>/<arm>`, so two same-named arms under different scenarios stay distinct.
64
+
65
+ `scripts/sandbox/run.sh` calls this after a headless run and merges the verdict into the envelope it prints. It also writes that merged record to `.claude/.tmp/sandbox-runs/<target>-<arm>-<timestamp>.json` with a `writes` array appended, and logs the path on stderr. Both fields are what a later re-score needs, since `--envelope` and `--writes` read files the run deletes on exit. Stdout carries the same bytes it did before the record existed.