@erclx/aitk 0.82.2 → 0.84.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/claude-docs/SKILL.md +3 -1
- package/claude/skills/git-pr/references/labels.md +7 -1
- package/docs/agents/capture.md +3 -1
- package/docs/agents/install-and-sync.md +3 -1
- package/docs/agents/markdown-audit.md +9 -3
- package/docs/ai-workflow.md +6 -2
- package/docs/target-projects.md +7 -1
- package/docs/visual-design-workflow.md +3 -1
- package/governance/rules/core/070-planning.md +1 -0
- package/governance/rules/core/075-dependencies.md +25 -0
- package/governance/rules/lib/300-testing-ts.md +1 -1
- package/governance/rules/lib/360-security-server.md +39 -0
- package/governance/rules/lib/370-database.md +35 -0
- package/governance/stacks/python.toml +1 -1
- package/package.json +1 -1
- package/standards/index.md +1 -1
- package/standards/markdown.md +1 -0
- package/standards/publish.md +13 -3
- package/standards/tasks.md +3 -1
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +19 -2
|
@@ -213,7 +213,9 @@ A plan can serve more than one task, and archiving on the first task to close st
|
|
|
213
213
|
|
|
214
214
|
Write the retarget as a markdown link, `Plan: [feature-<slug>](../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.
|
|
215
215
|
|
|
216
|
-
**Reviews.** Derive `<slug>` per `.claude/standards/slug.md`, or `${CLAUDE_SKILL_DIR}/../../standards/slug.md` when the project does not have it. Fall back to `latest` on an empty result.
|
|
216
|
+
**Reviews.** Derive `<slug>` per `.claude/standards/slug.md`, or `${CLAUDE_SKILL_DIR}/../../standards/slug.md` when the project does not have it. Fall back to `latest` on an empty result.
|
|
217
|
+
|
|
218
|
+
If `.claude/review/review-<slug>.md` exists, delete it. `claude-review` writes with this convention. Do not sweep any other `review-*.md` file.
|
|
217
219
|
|
|
218
220
|
Do not sweep `ui-checklist-*.md` (pending human verification) or `ux-audit-*.md` (standalone deliverable).
|
|
219
221
|
|
|
@@ -40,7 +40,13 @@ The map is authored by hand and nothing detects a directory it fails to cover, s
|
|
|
40
40
|
|
|
41
41
|
Apply labels after the pull request resolves, never as a flag on the create. `gh pr create --label` fails whole on a label the remote does not carry, so a name the map got wrong opens no pull request at all and the run stops with the branch pushed and nothing to review. A `gh pr edit --add-label` against a pull request that already exists costs a warning instead, and it is one command across both the create and the edit path rather than two flags that have to stay in step.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Labelling runs whenever this skill runs and at no other time. Nothing else computes the set, so a push made any other way leaves the labels exactly as the last run left them. Any caller invoking this skill again reaches the step again, and it recomputes over the whole branch diff rather than over the new commits.
|
|
44
|
+
|
|
45
|
+
An ordinary branch therefore labels once, when the pull request opens. The return leg that answers a review hands its push to `git-followup`, which refreshes the body without invoking this skill, so the commits that answer a review reach no labelling step.
|
|
46
|
+
|
|
47
|
+
A follow-up push reaching a surface the earlier ones did not merges under-labelled, with nothing to report the miss. Keeping the step in one skill is worth that cost, since a review fix lands in the files the review named and rarely opens a surface the branch had not already touched.
|
|
48
|
+
|
|
49
|
+
`--add-label` adds and never removes. A label a person applied by hand is not this skill's to strip, and a re-run over a branch that has since dropped a surface keeps the label that surface earned.
|
|
44
50
|
|
|
45
51
|
## A label the remote does not carry
|
|
46
52
|
|
package/docs/agents/capture.md
CHANGED
|
@@ -13,7 +13,9 @@ aitk capture assets/install.html
|
|
|
13
13
|
aitk capture assets --out .claude/review/captures
|
|
14
14
|
```
|
|
15
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.
|
|
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.
|
|
17
|
+
|
|
18
|
+
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
19
|
|
|
18
20
|
| Option | Behavior |
|
|
19
21
|
| ------------------ | ------------------------------------------------- |
|
|
@@ -271,7 +271,9 @@ so this section reports and gates nothing.
|
|
|
271
271
|
`aitk init` installs up to six core domains and reports each one independently. A
|
|
272
272
|
domain that fails does not abort the run, so the command finishes the rest and
|
|
273
273
|
exits 1 naming the failures. Passing any flag skips the confirmation prompt,
|
|
274
|
-
which is what makes it scriptable.
|
|
274
|
+
which is what makes it scriptable.
|
|
275
|
+
|
|
276
|
+
`--stack` defaults to `base`, and the default
|
|
275
277
|
does not read as a passed flag, so a bare `aitk init` installs governance and
|
|
276
278
|
still prompts. `--skip` takes `wiki`, `standards`, and `governance`, and warns
|
|
277
279
|
without aborting on any other value. `--standards` defaults to `all` and reaches
|
|
@@ -96,9 +96,11 @@ Exit codes are `0` for a completed run with no gating finding, `1` for a refusal
|
|
|
96
96
|
|
|
97
97
|
A banned character is a fact rather than a judgment, which is the test that admits it to a gate. What held it back was that gating on day one against a corpus never checked mechanically fails loudly on work nobody has had a chance to fix. The order was to land the verb reporting, measure the corpus once, fix what it finds, and turn the gate on as its own change, and the gate is the last of the four.
|
|
98
98
|
|
|
99
|
-
Measured at `4b7b13a2` across 444 files with the paragraph checkpoint at 600: 8 word hits, no character or spelling hits, 119 heavy bullets, 221 heavy paragraphs across 86 files, and 41 files carrying a run past the depth checkpoint. Of the paragraphs, 88 fire on weight alone.
|
|
99
|
+
Measured at `4b7b13a2` across 444 files with the paragraph checkpoint at 600: 8 word hits, no character or spelling hits, 119 heavy bullets, 221 heavy paragraphs across 86 files, and 41 files carrying a run past the depth checkpoint. Of the paragraphs, 88 fire on weight alone. That is the baseline the corpus sweep started from, and the ban count is the only one of the five a gate should ever read.
|
|
100
100
|
|
|
101
|
-
The ban half
|
|
101
|
+
The ban half reached zero, which was the precondition the gate waited on, and it was re-measured against the same corpus at the moment the gate landed. Three sweep slices then took the structural half, and the corpus reports 1 heavy bullet and 22 heavy paragraphs across 6 files on 2026-08-06, every one on a ground the triage record holds as exempt.
|
|
102
|
+
|
|
103
|
+
Depth is the one measure no slice triaged, so its figure moved with the sweep rather than with the corpus. Read all four structural counts from a run rather than from this paragraph.
|
|
102
104
|
|
|
103
105
|
### What a hit asks of an author
|
|
104
106
|
|
|
@@ -114,7 +116,9 @@ Four surfaces read the ban sets and two of them go through this verb. `.claude/h
|
|
|
114
116
|
|
|
115
117
|
The other two read the standards directly and neither is a consolidation left half done. `claude/skills/claude-standards-audit/SKILL.md` greps the banned tokens agent-side, which is a session reading prose rather than a process it can shell out to, and it ships to every target. The seed copy of the hook keeps its awk, because a scaffolded project may carry no `aitk` and `scripts/core/check-seed-independence.sh` exists to catch seed content depending on the toolkit CLI. Both are the likelier place for the next drift, since nothing compares either against the verb.
|
|
116
118
|
|
|
117
|
-
The hook prefers a checkout's own `src/cli.ts` over a globally installed binary, so it and the push stage read one build. A published binary lags a branch by whatever has not been released, which would put a ban kind added on the branch into the push and not into the edit. It reads its findings out of the `--json` record rather than off the exit code, so an older binary still reports where the fallback applies.
|
|
119
|
+
The hook prefers a checkout's own `src/cli.ts` over a globally installed binary, so it and the push stage read one build. A published binary lags a branch by whatever has not been released, which would put a ban kind added on the branch into the push and not into the edit. It reads its findings out of the `--json` record rather than off the exit code, so an older binary still reports where the fallback applies. It reads `bans.missingStandards` out of the same record, so a standard the verb found under neither root reaches the author as a check narrowed to what it could read.
|
|
120
|
+
|
|
121
|
+
A machine with neither runner still blocks no edit, and it says so rather than exiting clean. The push stage holds either way. An edit nobody checked and an edit carrying no violation are one silence to a reader, so the enforcement a machine lacks is reported rather than inferred.
|
|
118
122
|
|
|
119
123
|
The stage measures the whole corpus rather than the changed files. A `Do not use` bullet added to a standard bans a token retroactively, and no file in the push that adds the bullet was edited.
|
|
120
124
|
|
|
@@ -146,4 +150,6 @@ The verb reads the two attribute standards and nothing else. The five standards
|
|
|
146
150
|
|
|
147
151
|
`publish.md` describes a scan applying the same punctuation bans to finished text on its way out. No code implemented that scan before this command, so nothing is duplicated, and a later surface should call this verb rather than build a second one.
|
|
148
152
|
|
|
153
|
+
That standard's cross-reference rule is out of reach rather than merely unimplemented. It resolves by destination, bare where the destination auto-links a pull request or issue number and backticked where it does not, so this verb sees only the half where the backticked form is correct. A check here would report every compliant reference in the tree and reach none of the published text that goes wrong, which is why the rule holds on reading alone.
|
|
154
|
+
|
|
149
155
|
The list-density rule at `standards/markdown.md` is out of scope on purpose, since it carries no number and what a density figure should measure is still open.
|
package/docs/ai-workflow.md
CHANGED
|
@@ -89,7 +89,9 @@ An execution that picks other than the suggestion rewrites the `- Suggested:` li
|
|
|
89
89
|
|
|
90
90
|
`aitk records validate plans` reports where a plan and that standard disagree: a filename that is not `feature-<slug>.md`, a missing required section, a files-to-touch entry naming no file, and a question carrying a suggestion with no answer slot. The same verb takes `groundwork`, `intake`, and `memory`, which are governed the same way and were unreachable for the same reason. Nothing fires it automatically, because all four folders are gitignored and every check the repository runs reads changed files from git. It reports and never writes, since the folders are per-machine scratch with no history to recover a wrong repair from.
|
|
91
91
|
|
|
92
|
-
`aitk records push` carries these folders off the disk they live on, and `aitk records pull` brings them back. Eight of them are backed: `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `task-archive`, and `tasks`. The history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree, so every path a task file cites stays where it is.
|
|
92
|
+
`aitk records push` carries these folders off the disk they live on, and `aitk records pull` brings them back. Eight of them are backed: `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `task-archive`, and `tasks`. The history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree, so every path a task file cites stays where it is.
|
|
93
|
+
|
|
94
|
+
A person points it at a private repository once and both verbs refuse until they have, and `push` refuses when that origin is also a remote of the project, since the payload is the memory pen and the groundwork trails. `.husky/post-merge` runs the push after its archive loop, on every merge rather than only on one that closed a task. See [records](agents/records.md) for the refusal table.
|
|
93
95
|
|
|
94
96
|
A plan that ships is archived, never deleted. `aitk:claude-docs` moves it to `.claude/plans-archive/` and retargets the task file's `Plan:` line at the new location, so a completed task still leads to the reasoning behind it. Both folders are gitignored, which is why a deleted plan had no recovery path. A plan cited by more than one task stays put until the last of them closes, since moving it early would strand every other pointer.
|
|
95
97
|
|
|
@@ -97,7 +99,9 @@ The sweep reads the whole board rather than the tasks the session touched. It is
|
|
|
97
99
|
|
|
98
100
|
`aitk:claude-docs` decides which task closed by reading the diff rather than the conversation. It resolves a merge base against `origin/main`, unions the committed diff with the working tree and untracked files, then matches unchecked outcomes on the board against what shipped. A task that shipped without ever being discussed still gets marked. Requirements, architecture, and design stay session-sourced, because a diff cannot carry a judgment.
|
|
99
101
|
|
|
100
|
-
`.claude/tasks/` is gitignored and resolves at the main worktree root, so every session shares one board. One file per task is what keeps concurrent sessions from overwriting each other, since a gitignored board has no history to recover a lost write from. Its `index.md` is generated by a hook rather than by `bun run check`, because the whole-repo index walk skips gitignored folders.
|
|
102
|
+
`.claude/tasks/` is gitignored and resolves at the main worktree root, so every session shares one board. One file per task is what keeps concurrent sessions from overwriting each other, since a gitignored board has no history to recover a lost write from. Its `index.md` is generated by a hook rather than by `bun run check`, because the whole-repo index walk skips gitignored folders.
|
|
103
|
+
|
|
104
|
+
`.claude/memory/` carries the same arrangement, its own hook regenerating `index.md` from each entry's `title`, `description`, and `category`. A hand-maintained `priority.md` sits beside it carrying execution order and what each task is waiting on, which the alphabetical index cannot express.
|
|
101
105
|
|
|
102
106
|
`aitk tasks validate` checks what those rows claim against what the tree holds: every plan pointer resolves, every row and task file map one to one, no task sits in two groups, and no two rows marked ready touch the same file. That last check is the half a reader cannot run by eye, and it is what keeps two workers from being handed colliding work. It reports and never writes, because a row is the orchestrator's claim and a validator repairing one would assert the claim it exists to test. Nothing fires it automatically, since the board is gitignored per-machine scratch with no shared moment to hang a hook on, so the orchestrator's sweep calls it at the point the readiness claim is made.
|
|
103
107
|
|
package/docs/target-projects.md
CHANGED
|
@@ -124,7 +124,13 @@ That third one matters most on an older project. Before it existed, a target hol
|
|
|
124
124
|
|
|
125
125
|
The fourth cause runs backwards. Every one above starts from what the toolkit ships and asks whether the target matches, so a folder the toolkit dropped appears in none of them. `reverse` walks the target instead and reports a folder sitting at a top-level path the toolkit once shipped and has since deleted.
|
|
126
126
|
|
|
127
|
-
Each entry carries a verdict, since a dropped folder and one the project wrote are the same bytes at the same path.
|
|
127
|
+
Each entry carries a verdict, since a dropped folder and one the project wrote are the same bytes at the same path.
|
|
128
|
+
|
|
129
|
+
- `dropped` names the commit that published the content
|
|
130
|
+
- `unattributed` means the toolkit shipped that path and the content matches no version it published
|
|
131
|
+
- `project` means the folder only shares a retired name
|
|
132
|
+
|
|
133
|
+
Nothing acts on any of them, and the verdict is what makes the list safe to read.
|
|
128
134
|
|
|
129
135
|
The same field names a proposal-only skill with a live case here under `migrations`, which is how `aitk:migration-claude-md` and `aitk:migration-context` become reachable. Each entry carries the measurement behind the proposal rather than the proposal alone.
|
|
130
136
|
|
|
@@ -14,7 +14,9 @@ Two tools anchor tier 1 and tier 2. [Stitch](../wiki/tools/stitch.md) is the age
|
|
|
14
14
|
|
|
15
15
|
## Tier 0: prose only
|
|
16
16
|
|
|
17
|
-
The default. `.claude/DESIGN.md` holds visual intent as prose plus token tables for color, typography, spacing, borders, motion, and iconography. `.claude/WIREFRAMES.md` holds ASCII layouts.
|
|
17
|
+
The default. `.claude/DESIGN.md` holds visual intent as prose plus token tables for color, typography, spacing, borders, motion, and iconography. `.claude/WIREFRAMES.md` holds ASCII layouts.
|
|
18
|
+
|
|
19
|
+
Claude Code reads both and writes the implementation. Works for CLI tools, internal dashboards, admin panels, and backend-focused projects.
|
|
18
20
|
|
|
19
21
|
### Seed shape
|
|
20
22
|
|
|
@@ -12,4 +12,5 @@ description: Enforce planning standards before implementation
|
|
|
12
12
|
- State where the search ran and why each candidate was rejected. Do not assert a search without naming its results.
|
|
13
13
|
- Propose the simplest solution that satisfies the requirement before implementing complex patterns.
|
|
14
14
|
- Write or update tests as part of every implementation plan.
|
|
15
|
+
- Write the test for a behavior before the code that implements it. Confirm visual output after implementing it, not before.
|
|
15
16
|
- Do not modify code without a confirmed plan.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Require a dependency to be declared in the manifest before it is imported
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.ts'
|
|
5
|
+
- '**/*.tsx'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
- '**/*.jsx'
|
|
8
|
+
- '**/*.py'
|
|
9
|
+
- '**/package.json'
|
|
10
|
+
- '**/pyproject.toml'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Dependency standards
|
|
14
|
+
|
|
15
|
+
## Declaration
|
|
16
|
+
|
|
17
|
+
- Declare a package in the project manifest before importing it anywhere in the source.
|
|
18
|
+
- Add a package with the package manager command that writes the manifest and the lockfile together, such as `bun add` or `uv add`. Never hand-edit the manifest and never install without recording the result.
|
|
19
|
+
- Commit the lockfile with the manifest change in the same commit.
|
|
20
|
+
- Declare a package used only by tests, builds, or tooling as a development dependency.
|
|
21
|
+
- Never import a package that arrives only as a transitive dependency of another package.
|
|
22
|
+
|
|
23
|
+
## Removal
|
|
24
|
+
|
|
25
|
+
- Remove a package from the manifest in the change that removes its last import.
|
|
@@ -32,7 +32,7 @@ paths:
|
|
|
32
32
|
## Conventions
|
|
33
33
|
|
|
34
34
|
- Use `.test.ts` / `.test.tsx` for unit tests.
|
|
35
|
-
- Use `.spec.ts` / `.spec.tsx` for integration tests
|
|
35
|
+
- Use `.spec.ts` / `.spec.tsx` for integration tests and for Playwright tests under `e2e/`.
|
|
36
36
|
- Do not make real network calls in unit tests.
|
|
37
37
|
- `describe()` labels use the exact identifier of the subject under test in its natural casing.
|
|
38
38
|
- `it()` descriptions use "should" + sentence case.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce server-side authorization, secret handling, and abuse limits on request handlers
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.py'
|
|
5
|
+
- '**/*.ts'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Server security standards
|
|
10
|
+
|
|
11
|
+
## Authorization
|
|
12
|
+
|
|
13
|
+
- Authorize every request on the server, whatever the client already checked.
|
|
14
|
+
- Derive the caller identity from the verified session or token. Never read it from a request body, query string, or header the client sets.
|
|
15
|
+
- Check that the caller owns or may reach the specific record a request names, not only that the caller is signed in.
|
|
16
|
+
- Deny by default. Grant a route access through an explicit allow.
|
|
17
|
+
|
|
18
|
+
## Credentials
|
|
19
|
+
|
|
20
|
+
- Hash passwords with a memory-hard algorithm and a per-record salt. Never store a reversible password.
|
|
21
|
+
- Compare tokens, signatures, and password hashes with a constant-time function.
|
|
22
|
+
- Expire and revoke sessions and refresh tokens on the server. Do not rely on client-side deletion.
|
|
23
|
+
|
|
24
|
+
## Secrets
|
|
25
|
+
|
|
26
|
+
- Read every secret from the environment or a secret manager at runtime.
|
|
27
|
+
- Never commit a secret, connection string, or private key to the repository.
|
|
28
|
+
- Never return a secret, connection string, or internal hostname in a response body.
|
|
29
|
+
|
|
30
|
+
## Abuse limits
|
|
31
|
+
|
|
32
|
+
- Rate-limit authentication, password reset, and any endpoint that sends mail or costs money per call.
|
|
33
|
+
- Set an explicit maximum body size and request timeout on every endpoint.
|
|
34
|
+
- Bound pagination parameters with a server-side maximum.
|
|
35
|
+
|
|
36
|
+
## Transport
|
|
37
|
+
|
|
38
|
+
- Serve every route over TLS and reject plaintext requests.
|
|
39
|
+
- Restrict CORS to an explicit origin list. Never reflect the request origin or pair a wildcard with credentials.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce persistence boundaries for migrations, query construction, transactions, and rollback
|
|
3
|
+
paths:
|
|
4
|
+
- '**/*.py'
|
|
5
|
+
- '**/*.ts'
|
|
6
|
+
- '**/*.js'
|
|
7
|
+
- '**/*.sql'
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Persistence standards
|
|
11
|
+
|
|
12
|
+
## Schema changes
|
|
13
|
+
|
|
14
|
+
- Express every schema change as a migration file committed to version control.
|
|
15
|
+
- Ship a tested rollback path with every migration that changes a schema.
|
|
16
|
+
- Never alter a deployed schema outside a migration.
|
|
17
|
+
- Never edit a migration that has run in a shared environment. Add a new one.
|
|
18
|
+
- Separate a destructive migration from the deploy that stops reading the dropped column.
|
|
19
|
+
|
|
20
|
+
## Query construction
|
|
21
|
+
|
|
22
|
+
- Pass every runtime value as a bound parameter.
|
|
23
|
+
- Never interpolate, concatenate, or format a value into a statement string.
|
|
24
|
+
- Name the columns a read needs. Do not select every column by wildcard.
|
|
25
|
+
|
|
26
|
+
## Transactions
|
|
27
|
+
|
|
28
|
+
- Give each transaction one owner that opens it, commits it, and rolls it back.
|
|
29
|
+
- Never open a transaction inside a function that was handed one.
|
|
30
|
+
- Keep network calls, queue publishes, and filesystem writes outside an open transaction.
|
|
31
|
+
|
|
32
|
+
## Access patterns
|
|
33
|
+
|
|
34
|
+
- Load related rows in the query that fetches their parents. Do not resolve a relation lazily inside an iteration.
|
|
35
|
+
- Scope a connection or session to the request that opened it and release it on exit.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
extends = "base"
|
|
2
|
-
rules = ["110-python", "340-pydantic", "330-testing-py"]
|
|
2
|
+
rules = ["110-python", "340-pydantic", "330-testing-py", "360-security-server", "370-database"]
|
package/package.json
CHANGED
package/standards/index.md
CHANGED
|
@@ -17,7 +17,7 @@ Reference docs for consistent authoring across the toolkit and target projects.
|
|
|
17
17
|
- [Memory reference](memory.md): Filename and type prefix, frontmatter, the body shape per type, links between entries, and the lifecycle from write to retire
|
|
18
18
|
- [Plan reference](plan.md): Filename and slug, required sections, the suggested-and-answer contract, and the lifecycle from the live folder to the archive
|
|
19
19
|
- [Prose reference](prose.md): Voice, language, and frontmatter wording for reference markdown
|
|
20
|
-
- [Publish reference](publish.md): Scan
|
|
20
|
+
- [Publish reference](publish.md): Scan an author runs against finished text, the cross-reference form each destination takes, and the response to an unreadable source
|
|
21
21
|
- [Readme reference](readme.md): Readme voice, structure, and content conventions
|
|
22
22
|
- [Requirements reference](requirements.md): Shape and content rules for .claude/REQUIREMENTS.md
|
|
23
23
|
- [Governance rule reference](rule.md): Rule frontmatter, body shape, and voice for .claude/rules files
|
package/standards/markdown.md
CHANGED
|
@@ -17,6 +17,7 @@ Does not govern:
|
|
|
17
17
|
- What sections a document has, or what belongs in each: the standard for that document type
|
|
18
18
|
- The text inside a fenced block, which follows the conventions of its own language rather than these
|
|
19
19
|
- The scan that applies the punctuation bans to finished text on its way out: `publish.md`
|
|
20
|
+
- Whether a pull request or issue number is backticked, which turns on where the text is published rather than on the text: `publish.md`
|
|
20
21
|
|
|
21
22
|
## Headings
|
|
22
23
|
|
package/standards/publish.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Publish reference
|
|
3
|
-
description: Scan
|
|
3
|
+
description: Scan an author runs against finished text, the cross-reference form each destination takes, and the response to an unreadable source
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Publish reference
|
|
7
7
|
|
|
8
8
|
## Scope
|
|
9
9
|
|
|
10
|
-
Governs the scan an author runs against finished text on its way out, and the responses available when a source it reaches for cannot be read. It is an attribute standard rather than a document-type one, so it applies
|
|
10
|
+
Governs the scan an author runs against finished text on its way out, the form a pull request or issue reference takes in every destination, and the responses available when a source it reaches for cannot be read. It is an attribute standard rather than a document-type one, so it applies wherever no automated check covers the text, whether that text is leaving through a channel or sitting in the repository, and it carries no template because a scan has no document to shape.
|
|
11
11
|
|
|
12
12
|
Does not govern:
|
|
13
13
|
|
|
@@ -32,7 +32,17 @@ Restructure the sentence rather than substituting the character. A semicolon swa
|
|
|
32
32
|
|
|
33
33
|
`versioning.md` holds the label rule and the table of surfaces. Read it at scan time rather than working the format from memory.
|
|
34
34
|
|
|
35
|
-
Scope this check by destination. Text published to a remote takes it. Text scanned on its way into the repository, where the reader has the task board,
|
|
35
|
+
Scope this check by destination. Text published to a remote takes it. Text scanned on its way into the repository, where the reader has the task board, skips it.
|
|
36
|
+
|
|
37
|
+
## Cross-reference form
|
|
38
|
+
|
|
39
|
+
A number referring to a pull request or an issue takes the form its destination renders. Write it bare where the destination auto-links it, and in backticks where it does not. Both spellings are correct, each in one place, so a reference moved from one destination to the other is rewritten rather than copied.
|
|
40
|
+
|
|
41
|
+
Text published to a remote is the auto-linking half: a pull request body, an issue body, a comment on either, and a commit message. Write `#123` there, and `owner/repo#123` where the reference crosses repositories, which the same auto-linking reaches. A markdown file browsed from the repository tree is the other half, where neither spelling links and the backticked one marks the number as an identifier.
|
|
42
|
+
|
|
43
|
+
A commit message takes the bare form even though it is also read through the log, where nothing links. The remote is what the form is chosen for, since a reader in the log loses only a link that plain text never carried.
|
|
44
|
+
|
|
45
|
+
Text quoted from another surface keeps the spelling it arrived with. A reference inside a quotation belongs to what is being quoted rather than to the text doing the quoting, so rewriting it reports the source as having said something it never said.
|
|
36
46
|
|
|
37
47
|
## An unreadable source
|
|
38
48
|
|
package/standards/tasks.md
CHANGED
|
@@ -54,7 +54,9 @@ Readiness is three groups under fixed headings, `## Run now`, `## Up next`, and
|
|
|
54
54
|
- `## Up next`: a written plan exists, and the task carries a stated reason it cannot start. The `Waiting on` column names that reason.
|
|
55
55
|
- `## Needs a plan`: everything else. The task has no plan, or the plan it carries no longer describes the work.
|
|
56
56
|
|
|
57
|
-
Each group fixes its own columns, which follow from the test above it rather than from preference. Neither half of the `## Run now` test is checkable without the file set and the plan sitting beside the task.
|
|
57
|
+
Each group fixes its own columns, which follow from the test above it rather than from preference. Neither half of the `## Run now` test is checkable without the file set and the plan sitting beside the task.
|
|
58
|
+
|
|
59
|
+
The `Waiting on` column under `## Up next` carries that reason in one of three forms. `## Needs a plan` states no file set at all, because a task with no plan has no bounded one to state. A group with no rows keeps its heading and its header row.
|
|
58
60
|
|
|
59
61
|
Under `## Up next` a collision names the file held by the task already running, a sibling task names that task, and an external condition names both the condition and what would satisfy it. Naming what would satisfy it is what separates a blocked row from one nobody has examined, so a cell stating a condition with no way out of it fails the test. The header text is the contract the way the group names are, because anything reading the cell resolves the column by header rather than by position.
|
|
60
62
|
|
|
@@ -33,6 +33,7 @@ esac
|
|
|
33
33
|
# bullet added to markdown.md is parsed by nothing and enforces silently.
|
|
34
34
|
standard="${CLAUDE_PROJECT_DIR:-.}/.claude/standards/prose.md"
|
|
35
35
|
words=""
|
|
36
|
+
unread=""
|
|
36
37
|
if [ -f "$standard" ]; then
|
|
37
38
|
words=$(grep '^- Do not use ' "$standard" |
|
|
38
39
|
grep -o '`[^`]*`' |
|
|
@@ -40,6 +41,12 @@ if [ -f "$standard" ]; then
|
|
|
40
41
|
grep -x '[a-z][a-z]*' |
|
|
41
42
|
sort -u |
|
|
42
43
|
paste -sd '|' -)
|
|
44
|
+
else
|
|
45
|
+
# An absent standard empties the word list, and the awk below reads an empty
|
|
46
|
+
# list as nothing to look for rather than as nothing found. The path is kept
|
|
47
|
+
# so the report names what could not be read, since a file carrying no banned
|
|
48
|
+
# word and a file nobody checked produce the same silence otherwise.
|
|
49
|
+
unread="$standard"
|
|
43
50
|
fi
|
|
44
51
|
|
|
45
52
|
hits=$(awk -v words="$words" '
|
|
@@ -66,8 +73,18 @@ hits=$(awk -v words="$words" '
|
|
|
66
73
|
}
|
|
67
74
|
' "$file")
|
|
68
75
|
|
|
69
|
-
[ -z "$hits" ] && exit 0
|
|
76
|
+
[ -z "$hits" ] && [ -z "$unread" ] && exit 0
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
nl=$'\n'
|
|
79
|
+
msg=""
|
|
80
|
+
|
|
81
|
+
if [ -n "$unread" ]; then
|
|
82
|
+
msg=$(printf 'Standards-audit: no word ban checked in %s. Found no standard at %s, so only the character bans ran. Restore it with `aitk standards install`.' "$file" "$unread")
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if [ -n "$hits" ]; then
|
|
86
|
+
found=$(printf 'Standards-audit: prose.md and markdown.md violations in %s. Rewrite or restructure (do not lazy-swap).\n%s' "$file" "$hits")
|
|
87
|
+
msg="${msg:+$msg$nl}$found"
|
|
88
|
+
fi
|
|
72
89
|
|
|
73
90
|
jq -nc --arg msg "$msg" '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:$msg}}'
|