@erclx/aitk 0.44.0 → 0.46.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 (38) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/claude-autoship/SKILL.md +15 -10
  3. package/claude/skills/claude-docs/SKILL.md +16 -2
  4. package/claude/skills/claude-memory-capture/REQUIREMENT.md +14 -4
  5. package/claude/skills/claude-memory-capture/SKILL.md +45 -16
  6. package/claude/skills/claude-memory-review/REQUIREMENT.md +8 -2
  7. package/claude/skills/claude-memory-review/SKILL.md +41 -25
  8. package/claude/skills/claude-orchestrate/SKILL.md +5 -0
  9. package/claude/skills/claude-seed-sync/REQUIREMENT.md +3 -1
  10. package/claude/skills/claude-seed-sync/SKILL.md +16 -4
  11. package/claude/skills/git-ship/SKILL.md +14 -11
  12. package/claude/skills/session-resume/SKILL.md +2 -2
  13. package/claude/skills/toolkit-operator/SKILL.md +18 -1
  14. package/docs/agents/commands.md +36 -35
  15. package/docs/agents/index.md +1 -0
  16. package/docs/agents/indexes.md +3 -1
  17. package/docs/agents/install-and-sync.md +46 -0
  18. package/docs/agents/scripting.md +4 -3
  19. package/docs/agents/skills-audit.md +55 -0
  20. package/docs/ai-workflow.md +3 -2
  21. package/docs/target-projects.md +5 -1
  22. package/package.json +1 -1
  23. package/scripts/core/verify.sh +8 -0
  24. package/src/claude/seeds.ts +7 -1
  25. package/src/claude/skills-audit.ts +215 -0
  26. package/src/claude/skills-list.ts +3 -3
  27. package/src/commands/claude.ts +283 -5
  28. package/src/commands/context.ts +1 -4
  29. package/src/commands/sync.ts +54 -1
  30. package/src/sync/check.ts +71 -0
  31. package/src/sync/layout.ts +139 -0
  32. package/src/sync/seeds-report.ts +111 -0
  33. package/src/ui.ts +5 -0
  34. package/tooling/claude/reference.md +11 -1
  35. package/tooling/claude/seeds/.claude/hooks/memory-index.sh +60 -0
  36. package/tooling/claude/seeds/.claude/memory/index.md +8 -0
  37. package/tooling/claude/seeds/.claude/settings.json +4 -0
  38. package/tooling/claude/seeds/CLAUDE.md +3 -0
@@ -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.44.0",
4
+ "version": "0.46.0",
5
5
  "author": {
6
6
  "name": "Eric Le",
7
7
  "url": "https://github.com/erclx"
@@ -101,12 +101,15 @@ Do not auto-fix findings. The stop here is deliberate.
101
101
 
102
102
  Invoke each sub-skill in order via the Skill tool. After each returns, invoke the next immediately. Do not output text between steps.
103
103
 
104
- 1. `aitk:claude-docs`: sync `.claude/` planning docs against session decisions
105
- 2. `aitk:docs-sync`: sync public docs against changes since main
106
- 3. Run `git add -A` to stage files the sync skills wrote
107
- 4. `aitk:git-stage`: group staged changes and commit by concern
108
- 5. `aitk:git-branch`: rename the branch to conventional format
109
- 6. `aitk:git-pr`: push and open the pull request
104
+ 1. `aitk:claude-memory-capture`: route what this session learned to the context entries that own it, and write the residue to `.claude/memory/`
105
+ 2. `aitk:claude-docs`: sync `.claude/` planning docs against session decisions, folding in the routed facts
106
+ 3. `aitk:docs-sync`: sync public docs against changes since main
107
+ 4. Run `git add -A` to stage files the sync skills wrote
108
+ 5. `aitk:git-stage`: group staged changes and commit by concern
109
+ 6. `aitk:git-branch`: rename the branch to conventional format
110
+ 7. `aitk:git-pr`: push and open the pull request
111
+
112
+ Capture runs first because a routed fact lands in a context entry, which is a tracked file. Running it after `git-pr`, where it used to sit, leaves that edit outside the branch and outside the pull request, so the fact reaches nothing. Memory files stay gitignored either way, which is why the old order was invisible.
110
113
 
111
114
  After the PR is created, mark it as draft:
112
115
 
@@ -116,23 +119,25 @@ gh pr ready --undo
116
119
 
117
120
  After marking draft, watch CI. Poll `gh pr checks <number>` until no check is pending, then read the final status. On all-pass, continue. On any failure, stop and report the failing check with its URL. Do not auto-fix.
118
121
 
119
- 7. `aitk:claude-memory-capture`: extract durable patterns from the session into `.claude/memory/`
120
- 8. `aitk:claude-memory-review`: if `claude-memory-capture` wrote or updated at least one entry this session, propose fixes scoped to those entries, writing the decision-ready receipt while session context is fresh. Skip when capture wrote nothing.
122
+ 8. `aitk:claude-memory-review`: if step 1's capture wrote or updated at least one memory file, propose fixes scoped to those entries, writing the decision-ready receipt while session context is fresh. Skip when capture wrote nothing to the folder, which is the ordinary outcome once routing has taken the domain facts.
123
+
124
+ Review stays last because its receipt is gitignored and needs nothing from the commit, and because a proposal is worth more once CI has said whether the branch stands.
121
125
 
122
126
  Stop at the Propose phase. Do not run Apply. Promoting an entry to `CLAUDE.md` or a skill body mutates how the agent operates and ships as its own change, separate from this feature.
123
127
 
124
128
  ## Output
125
129
 
126
- Respond with up to four lines:
130
+ Respond with up to five lines:
127
131
 
128
132
  ```plaintext
129
133
  ✅ Autoshipped (draft): <PR url>
130
134
  <N minor findings kept in .claude/review/review-<slug>.md>
135
+ <N facts routed to context entries>
131
136
  <N memories captured in .claude/memory/>
132
137
  <Memory proposal at .claude/review/memory-review-<slug>.md>
133
138
  ```
134
139
 
135
- Omit the second line if there were no minor findings. Omit the third and fourth lines if `claude-memory-capture` wrote nothing this session, since no captures means no scoped review and no proposal.
140
+ Omit the second line if there were no minor findings, and the third if nothing routed. Omit the fourth and fifth if `claude-memory-capture` wrote no memory file this session, since an empty pen means no scoped review and no proposal. A run that routes every fact and writes none is the shape to expect, and it reports three lines.
136
141
 
137
142
  ## Failure recovery
138
143
 
@@ -77,7 +77,7 @@ Then run Steps 4 through 8. Step 3 is the only one this skips, because it is the
77
77
  Three of the steps that follow write, so each earns the reach separately:
78
78
 
79
79
  - Steps 4 and 5 stub against the diff. These are why the skip is not a stop. A session that changed no docs is exactly when an uncovered surface or diagram kind goes unnoticed.
80
- - Step 7 rewrites context entries against the diff. The Diff baseline section above already groups it with Steps 4 and 5 as a scoped-set step, so a quiet session is no different from any other for it.
80
+ - Step 7 rewrites context entries against the diff and against the facts `claude-memory-capture` routed. The Diff baseline section above groups its diff half with Steps 4 and 5 as a scoped-set step, so a quiet session is no different from any other for it. The routed half reads a named file and runs whatever the diff shows.
81
81
  - Step 8 reads the board rather than the session. Its board-wide scan exists to clear a plan an earlier run stranded, and a run that stops at Step 2 can never reach one.
82
82
 
83
83
  This changes which steps the skill reaches. It does not widen what any of them reads. Steps 4, 5, and 7 still take the same scoped set the Diff baseline section defines, and that section's rule is about the input a write is handed rather than about which writes run.
@@ -201,7 +201,17 @@ Do not edit `CLAUDE.md` inline. Every `CLAUDE.md` change goes through the show-d
201
201
 
202
202
  ## Step 7: refresh context entries
203
203
 
204
- Read `.claude/context/index.md` at `pwd` to see which domain entries exist. Skip this step silently if the directory does not exist or has no entries. When the baseline is unusable, scope it to the working tree and untracked files, and skip it only when that set is empty, reporting `⚠ No diff to scope against. Skipped the context refresh.`
204
+ Read `.claude/context/index.md` at `pwd` to see which domain entries exist. Skip this step silently if the directory does not exist or has no entries.
205
+
206
+ Two sources feed this step, the same split Step 2 runs on. The diff carries what the repository changed. The routed facts carry what the session learned, which a diff cannot show.
207
+
208
+ **Routed facts.** Derive `<slug>` per `.claude/standards/slug.md`, falling back to `latest` on an empty result, and read `.claude/.tmp/memory-routing/<slug>.md` at the main worktree root. `claude-memory-capture` writes it, one H2 per target entry naming the path, with the fact underneath. Fold each fact into the entry its heading names, then delete the handoff file so a later run does not fold it twice.
209
+
210
+ This half is not diff-scoped and must not be. A gotcha a session hit while working is exactly the fact the diff never shows, and scoping it to changed files would drop the entries worth keeping. The handoff is a named input rather than a scan, so the reach stays bounded to what capture decided.
211
+
212
+ Skip this half silently when the file is absent, which is every run where nothing routed.
213
+
214
+ **The diff.** When the baseline is unusable, scope this half to the working tree and untracked files, and skip it only when that set is empty, reporting `⚠ No diff to scope against. Skipped the context refresh.` The routed half still runs, since it reads a file rather than a diff.
205
215
 
206
216
  Reuse the diff from the baseline above, names and content both. For each existing `.claude/context/<domain>.md`:
207
217
 
@@ -214,6 +224,10 @@ Write each updated entry immediately. Output one line per file:
214
224
 
215
225
  `✅ Context: .claude/context/<domain>.md`
216
226
 
227
+ Add a line naming the handoff when one was consumed:
228
+
229
+ `🧹 Folded: .claude/.tmp/memory-routing/<slug>.md`
230
+
217
231
  The base lint-staged config runs `aitk indexes regen` on every committed `*.md`, so `.claude/context/index.md` refreshes automatically on commit. No manual step needed.
218
232
 
219
233
  ## Step 8: sweep consumed scratch
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: claude-memory-capture
3
- description: What earns a memory file at the end of a session, the threshold that keeps the folder signal-bearing, and why capture never curates
3
+ description: Which surface a session fact is owed to, what earns a memory file once routing has run, and why capture never edits a context entry itself
4
4
  ---
5
5
 
6
6
  # Claude memory capture requirement
@@ -9,20 +9,28 @@ description: What earns a memory file at the end of a session, the threshold tha
9
9
 
10
10
  Without this skill, what a session learned dies with it, and the correction the user made in message four is re-earned next week. What does get written is a narrative of how the session went wrong rather than a rule that fires again, so a reader gets a story and no instruction. A new file lands beside one already holding the same topic, and the folder grows two entries per subject until nothing in it can be trusted as current.
11
11
 
12
- The threshold is what the folder lives or dies on. A first-occurrence slip saved as feedback is noise that costs every later session a read, and a fact the repository already records is worse, because it duplicates a source that will be updated without it. From a linked worktree, writes resolved against `pwd` land in a second memory folder nothing else reads.
12
+ Writing every fact to one folder is the deeper gap, because the folder has no reader. A fact about a domain has an owning surface already, the context entry the three-tier model loads on demand, and filing it in memory instead puts it where only a deliberate sweep will ever find it. The measured outcome is a store that grows on every ship and is drained by nothing.
13
+
14
+ The threshold is what the remaining folder lives or dies on. A first-occurrence slip saved as feedback is noise that costs every later session a read, and a fact the repository already records is worse, because it duplicates a source that will be updated without it. From a linked worktree, writes resolved against `pwd` land in a second memory folder nothing else reads.
13
15
 
14
16
  ## Must
15
17
 
16
18
  - Resolve every read and write at the main worktree root, so parallel worktrees write one folder
17
- - Classify each candidate as feedback, project, user, or reference before writing
19
+ - Classify each candidate as feedback, project, user, or reference before routing or writing
20
+ - Route a project candidate whose subject names an entry in `.claude/context/index.md` to that entry, and hand it off as a file rather than an edit
21
+ - Keep a candidate that matches no entry, or two entries with no clear owner, as a memory file
18
22
  - Apply the save threshold, firing feedback only on an explicit correction or a pattern that repeated twice
19
23
  - Grep the folder for an existing file on the topic and update it in place rather than adding a second
20
24
  - Keep a feedback or project body to the rule, one line of why, and one line of when it fires next
21
- - Append the row to the index so the entry is discoverable
25
+ - Write frontmatter the index renderer can read, so the generated catalog stays current
22
26
  - Report that nothing was worth capturing rather than manufacturing an entry to show work
23
27
 
24
28
  ## Must not
25
29
 
30
+ - Edit a context entry, which `claude-docs` owns
31
+ - Route a feedback, user, or reference candidate, since no context entry owns how to work or who to ask
32
+ - Route anything when the caller does not commit, because a context entry is a tracked file
33
+ - Hand-append a row to the memory index, which is generated from sibling frontmatter
26
34
  - Write a session narrative or a recovery account in place of the pattern
27
35
  - Save a first-occurrence slip as feedback
28
36
  - Create a second file on a topic the folder already holds
@@ -33,8 +41,10 @@ The threshold is what the folder lives or dies on. A first-occurrence slip saved
33
41
 
34
42
  - No correction, confirmation, or context disclosure worth persisting: stop with a pass
35
43
  - Memory folder absent at the main root: create it rather than stopping
44
+ - Session in the main worktree, or a caller that does not commit: skip routing and write every candidate as a memory file
36
45
 
37
46
  ## Out of scope
38
47
 
48
+ - Editing the context entries themselves, which `claude-docs` owns on its own pass
39
49
  - Curating what is already in the folder, which `claude-memory-review` owns
40
50
  - Promoting an entry into an instruction file or a skill body, which mutates how the agent operates and ships as its own change
@@ -1,24 +1,28 @@
1
1
  ---
2
2
  name: claude-memory-capture
3
- description: Extracts durable patterns from the current session and writes them to `.claude/memory/` as feedback, project, user, or reference memory files. Use when asked to "capture memory", "capture lessons", "wrap up the session", "end of session memory", or as the final step in autoship. Do NOT use to curate existing memory. Use `claude-memory-review` for that.
3
+ description: Extracts durable patterns from the current session, routes a domain fact to the context entry that owns it, and writes the residue to `.claude/memory/` as feedback, project, user, or reference files. Use when asked to "capture memory", "capture lessons", "wrap up the session", "end of session memory", or as a step in autoship. Do NOT use to curate existing memory. Use `claude-memory-review` for that.
4
4
  ---
5
5
 
6
6
  # Claude memory capture
7
7
 
8
- Scan the current session for patterns worth persisting, write them as memory files, and update the index. Pair with `claude-memory-review` for later curation.
8
+ Scan the current session for patterns worth persisting, send each to the surface that owns it, and leave in `.claude/memory/` only what no surface owns. Pair with `claude-memory-review` for later curation.
9
+
10
+ A fact about a domain belongs in that domain's context entry, which the three-tier model already loads on demand. Writing it to memory instead puts it in a folder nothing opens. Routing is therefore the point of this skill and the memory file is the fallback.
9
11
 
10
12
  ## Guards
11
13
 
12
14
  - All `.claude/memory/` reads and writes resolve at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`.
13
- - If `.claude/memory/` does not exist at the main worktree root, create it.
15
+ - If `.claude/memory/` does not exist at the main worktree root, create it, along with an `index.md` carrying `title` and `subtitle` frontmatter. `aitk claude init` seeds both, and a project predating that seed has neither. Regeneration errors without the index, so the first write into a bare folder would report a frontmatter failure against a file that is fine.
14
16
  - If the session produced no user corrections, confirmations, or context disclosures worth persisting, stop: `✅ Nothing worth capturing.`
17
+ - Routing edits a tracked file, so it runs only where the caller commits. When the session is in the main worktree, or the caller states it does not commit, skip Step 3 and write every candidate as a memory file. `claude-orchestrate` is the caller this covers.
15
18
 
16
19
  ## Step 1: read context
17
20
 
18
21
  Read in parallel from the project root, skipping any that do not exist:
19
22
 
20
23
  - `CLAUDE.md`: Memory section rules, including save thresholds and file format overrides
21
- - `.claude/memory/MEMORY.md`: existing index, to avoid duplicates
24
+ - `.claude/memory/index.md`: existing index, to avoid duplicates
25
+ - `.claude/context/index.md`: the domain catalog Step 3 routes against
22
26
  - `.claude/standards/prose.md`: prose conventions applied to memory file bodies
23
27
 
24
28
  Read a standard from `${CLAUDE_SKILL_DIR}/../../standards/` instead when the project does not have it.
@@ -34,42 +38,67 @@ Scan the session and group candidate patterns into four types:
34
38
 
35
39
  Apply the save threshold: a feedback memory only fires on explicit user correction, or on a pattern that repeated twice in the session. First-occurrence slips are noise. Project, user, and reference memories fire on first disclosure.
36
40
 
37
- ## Step 3: dedupe
41
+ ## Step 3: route what a context entry owns
42
+
43
+ Only a **project** candidate is routable. Feedback, user, and reference describe how to work or who to ask rather than how a domain behaves, and no context entry owns them.
44
+
45
+ For each project candidate, match its subject against `.claude/context/index.md`. The test is a named entry, not a judgment about fit: the fact names a surface that already has an entry in the catalog. Route it to that entry.
46
+
47
+ Fail closed. A project candidate matching no entry stays a memory file, and so does one matching two entries where neither is clearly the owner. The residue is what the folder is for, and a fact filed under the wrong entry is worse than one in memory because a context entry is a surface sessions trust.
48
+
49
+ Do not edit a context entry here. `claude-docs` owns those edits and folds the routed facts in on its own pass, or two skills write one file at the same step. Write each routed fact to `.claude/.tmp/memory-routing/<slug>.md` at the main worktree root instead, appending when the file exists:
50
+
51
+ ```markdown
52
+ ## .claude/context/<domain>.md
53
+
54
+ <the fact in one or two sentences, stated as a fact about the domain rather than as a session narrative>
55
+ ```
56
+
57
+ 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.
38
58
 
39
- For each candidate, grep `.claude/memory/` for an existing file on the same topic. If one exists, update it in place rather than create a new file.
59
+ The handoff is a file rather than a spoken result so the routed fact survives a compaction between this step and the `claude-docs` pass, and so the standalone caller leaves something behind for a later `/claude-docs` to consume.
40
60
 
41
- ## Step 4: write
61
+ ## Step 4: dedupe
62
+
63
+ For each remaining candidate, grep `.claude/memory/` for an existing file on the same topic. If one exists, update it in place rather than create a new file.
64
+
65
+ ## Step 5: write the residue
42
66
 
43
67
  For each new memory, write to `.claude/memory/<type>-<slug>.md` with this frontmatter:
44
68
 
45
69
  ```markdown
46
70
  ---
47
- name: <memory name>
71
+ title: <one-line human title, as it should read in the index>
48
72
  description: <one-line description per .claude/standards/prose.md § Frontmatter descriptions>
49
- type: <feedback|project|user|reference>
73
+ category: <Feedback|Project|User|Reference>
50
74
  ---
51
75
 
52
76
  <memory body>
53
77
  ```
54
78
 
79
+ `category` is the type in sentence case, which is what the index renderer groups on, while the filename keeps the lowercase `<type>-` prefix. A description opening with a backtick or a colon needs single quotes, or the frontmatter fails to parse and the index goes stale.
80
+
55
81
  Feedback and project bodies must be three lines: the rule or fact on one line, a `**Why:**` line naming the session signal, and a `**How to apply:**` line for when the rule fires next. Keep each line tight. No narrative.
56
82
 
57
83
  User and reference bodies are a single sentence each.
58
84
 
59
- Then append a row to the matching table in `.claude/memory/MEMORY.md`:
60
-
61
- ```markdown
62
- | <name> | <file> | <description> |
63
- ```
85
+ Do not edit the index. `.claude/memory/index.md` is generated from sibling frontmatter by a `PostToolUse` hook, the same way the task board's index is, so a hand-appended row is drift the next regeneration discards.
64
86
 
65
87
  ## Output
66
88
 
67
- Respond with one line per memory written or updated:
89
+ Respond with one line per fact routed, written, or updated:
68
90
 
91
+ - `➡️ Routed: <fact subject> → .claude/context/<domain>.md`
69
92
  - `✅ Wrote: .claude/memory/<file> (<type>)`
70
93
  - `✏️ Updated: .claude/memory/<file> (<type>)`
71
94
 
72
- When at least one entry was written or updated, add a closing line so the standalone caller proposes fixes while context is fresh:
95
+ When anything routed, add a line naming the handoff so the caller knows a `claude-docs` pass is owed:
96
+
97
+ `→ Routed facts wait at .claude/.tmp/memory-routing/<slug>.md. Run /claude-docs to fold them in.`
98
+
99
+ Omit that line when the caller runs `claude-docs` itself later in its own chain.
100
+
101
+ When at least one memory file was written or updated, add a closing line so the standalone caller proposes fixes while context is fresh:
73
102
 
74
103
  `→ Run /claude-memory-review to propose fixes for the pen before the session ends.`
75
104
 
@@ -9,9 +9,13 @@ description: What memory review is for, the gaps it closes, and why every action
9
9
 
10
10
  Without this skill, the memory folder grows and never drains. Entries pile up restating rules a durable surface already carries, nothing decides which memory has earned a place in one, and a rule that does get promoted arrives verbatim in a file whose voice it does not match. The folder then reads as a second source of truth that no surface points at.
11
11
 
12
+ A pen the caller cannot face is the same gap wearing a different shape. Once routing at capture takes the domain facts, what reaches this skill is feedback about how to work, which is a working set rather than a backlog, and the proposal is a size a person actually reads. An entry leaving the pen is archived rather than deleted, because a folder git does not hold gives a wrong bulk call no undo.
13
+
12
14
  ## Must
13
15
 
14
- - Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or a deletion rather than surviving by default
16
+ - Treat the folder as a holding pen, so every entry in scope leaves it as a promotion, a handoff, or an archive rather than surviving by default
17
+ - Archive an entry out of the pen rather than deleting it, since nothing recovers a file from a gitignored folder
18
+ - Hand a fact a context entry owns to `claude-docs` through the routing file, rather than editing the entry here
15
19
  - Verify the rule is not already stated or implied in the target before proposing a promotion, by reading the target rather than trusting the memory's claim about it
16
20
  - Rewrite a rule into the destination's voice instead of moving it unchanged
17
21
  - Write the proposal to a receipt on disk and take no action until the user decides per item
@@ -25,7 +29,9 @@ Without this skill, the memory folder grows and never drains. Entries pile up re
25
29
  - Author a governance rule inline. Coding-standards rules have an owner and a scaffolding path, and a rule written here bypasses both.
26
30
  - Mutate tracked files from the main worktree
27
31
  - Answer a question raised in a decision slot while applying. Discussion and application are separate passes so an approval is never inferred from a reply.
28
- - Delete a memory entry outside the approved-per-item pass. The folder is gitignored with no history behind it, so a removal any other phase makes has no undo and no record of what it took.
32
+ - Delete a memory entry at all. Every exit from the pen is a move into the archive.
33
+ - Move an entry out of the pen outside the approved-per-item pass. The folder is gitignored with no history behind it, so a removal any other phase makes leaves no record of what it took.
34
+ - Edit a context entry, or hand-edit the generated memory index
29
35
 
30
36
  ## Guards
31
37
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: claude-memory-review
3
- description: Reviews `.claude/memory/` and proposes per-entry actions (promote to `CLAUDE.md`, move into a skill body, hand off to governance, or delete as stale). Also runs the discuss, challenge, apply, and cleanup phases on an existing review file. Use when asked to "review memory", "discuss memory questions", "challenge the promotes", "apply memory decisions", "cleanup memory review", "promote memory", or "consolidate memories". Do NOT auto-apply. Output a grouped proposal and wait for block-by-block approval.
3
+ description: Reviews `.claude/memory/` and proposes per-entry actions (promote to `CLAUDE.md`, move into a skill body, route to a context entry, hand off to governance, or retire as stale). Also runs the discuss, challenge, apply, and cleanup phases on an existing review file. Use when asked to "review memory", "discuss memory questions", "challenge the promotes", "apply memory decisions", "cleanup memory review", "promote memory", or "consolidate memories". Do NOT auto-apply. Output a grouped proposal and wait for block-by-block approval.
4
4
  ---
5
5
 
6
6
  # Claude memory review
@@ -19,9 +19,9 @@ If the user re-pings the skill with no new phrase and a receipt exists, default
19
19
 
20
20
  ## Guards
21
21
 
22
- - All `.claude/memory/` reads, edits, and deletes resolve at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`.
22
+ - All `.claude/memory/` reads, edits, and archive moves resolve at the main worktree root, not the current worktree. See Worktrees in `CLAUDE.md`.
23
23
  - If no `.claude/memory/` directory exists at the main worktree root, stop: `❌ No .claude/memory/ directory found.`
24
- - If `.claude/memory/` contains no `*.md` entries other than `MEMORY.md`, stop: `✅ No memory entries to review.`
24
+ - If `.claude/memory/` contains no `*.md` entries other than `index.md`, stop: `✅ No memory entries to review.`
25
25
  - Cleanup is exempt from the two stops above. It works on receipts in `.claude/review/`, and a drained pen is the normal state once Apply has run, so a pen-shaped stop would strand the receipt it exists to delete.
26
26
  - Resolve the main root via `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. All review and memory reads anchor here.
27
27
 
@@ -38,8 +38,8 @@ Propose is the ship-time entry point. The ship skills run it right after capture
38
38
 
39
39
  Read in parallel from the project root:
40
40
 
41
- - `.claude/memory/MEMORY.md`: the index
42
- - every other `*.md` file under `.claude/memory/`: individual entries with frontmatter (`name`, `description`, `type`)
41
+ - `.claude/memory/index.md`: the generated index
42
+ - every other `*.md` file under `.claude/memory/`: individual entries with frontmatter (`title`, `description`, `category`)
43
43
 
44
44
  ### Step 2: read promotion targets
45
45
 
@@ -55,27 +55,32 @@ Read any authoring reference the project does not have from `${CLAUDE_SKILL_DIR}
55
55
 
56
56
  ### Step 3: classify each entry
57
57
 
58
- `.claude/memory/` is a holding pen. Default every entry to promote or delete on review. Skip is the rare exception, reserved for active task overlap or user-type memories with no in-repo target.
58
+ `.claude/memory/` is a holding pen. Default every entry to promote or retire on review. Skip is the rare exception, reserved for active task overlap or user-type memories with no in-repo target.
59
+
60
+ `claude-memory-capture` routes a project fact naming a domain with a context entry to that entry, so a pen filled since routing shipped is mostly feedback: rules about how to work, which no context entry owns. Propose against what the pen holds rather than expecting the older mix. An entry carried from before routing may still name a domain that has a context entry, and that entry's action is **Promote to a context entry**, which hands it to `claude-docs` the same way capture does rather than editing the entry here.
59
61
 
60
62
  For each in-scope entry (see Scope), pick one action:
61
63
 
62
64
  - **Promote to `CLAUDE.md`**: the rule is cross-domain behavior or a design principle applied across the whole project.
63
65
  - **Promote to a skill body**: the rule fires only when editing a specific path-scoped domain. Name the target skill.
64
66
  - **Promote to a standards file**: the rule is an authoring reference that belongs in `.claude/standards/<domain>.md`.
67
+ - **Promote to a context entry**: the entry states a fact about a domain carrying an entry in `.claude/context/index.md`. Append it to `.claude/.tmp/memory-routing/<slug>.md` in the format `claude-memory-capture` writes, and tell the user to run `/claude-docs` from a branch. Do not edit the context entry here.
65
68
  - **Hand off to governance**: the rule is coding-standards class (typescript, testing, naming, error-handling, performance, logging, concurrency, planning). Do not author the rule file inline. In the toolkit repo, point the user at `aitk-governance` and `.claude/standards/rule.md`, which own the source-of-truth rules under `governance/rules/`. In a target project, point the user at the `create-rule` skill, which scaffolds a project-local rule under `.claude/rules/`. Never edit the synced `.claude/rules/` copies of toolkit rules, because `aitk gov sync` overwrites them. Stop at handoff.
66
- - **Delete**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative.
69
+ - **Retire**: the rule is stale, already absorbed into a durable surface, too vague to phrase as a rule, or a one-time incident narrative. Apply moves the file to `.claude/.tmp/memory-archive/` rather than deleting it.
70
+
71
+ Retire is an archive, not a deletion. `.claude/memory/` is gitignored with no history behind it, and a first pass over a folder this size is a bulk judgment with no undo. A plan and a task both archive rather than delete for the same reason, and this costs one `mv` against an unrecoverable wrong call. The archive is worth less than a plan's, since a promoted entry survives in its destination and a stale one is discarded on purpose, which is why it is cheap rather than free.
67
72
 
68
73
  When two or more memories collapse into one rule on the same target, propose them as a single merged edit under the matching promote category. The consolidate case is a variant of promote, not a separate action.
69
74
 
70
75
  #### Absorbed-already check
71
76
 
72
- Before proposing promote, grep the target surface for the rule's keywords. If the rule is already stated there, the action is **Delete**, not promote. Do not rely on memory-file claims that a rule is documented elsewhere. Verify.
77
+ Before proposing promote, grep the target surface for the rule's keywords. If the rule is already stated there, the action is **Retire**, not promote. Do not rely on memory-file claims that a rule is documented elsewhere. Verify.
73
78
 
74
79
  The check covers implication, not only keyword match. If an adjacent bullet in the target section already implies the rule, merge into that bullet rather than append a second.
75
80
 
76
81
  #### Crispness check
77
82
 
78
- Rules that resist crisp one-line phrasing default to **Delete** over promote. Never promote a memory unchanged. Rewrite to match the destination surface's tone. Use terser phrasing for `CLAUDE.md` and imperative phrasing for skill bodies.
83
+ Rules that resist crisp one-line phrasing default to **Retire** over promote. Never promote a memory unchanged. Rewrite to match the destination surface's tone. Use terser phrasing for `CLAUDE.md` and imperative phrasing for skill bodies.
79
84
 
80
85
  ### Step 4: write the proposal to the review file
81
86
 
@@ -90,7 +95,7 @@ Structure: a summary block at the top, a legend, then one H2 per numbered item.
90
95
 
91
96
  **Pending:** <all numbers>
92
97
 
93
- Legend: ✅ applied · ⏭ skipped · 🗑 deleted · 🤝 handed off · 📝 pending
98
+ Legend: ✅ applied · ⏭ skipped · 📦 retired · 🤝 handed off · 📝 pending
94
99
 
95
100
  How to respond: fill in `Decision:` per item (`apply`, `skip`, `defer`, or a question with `?`), then re-ping the skill. Say "discuss" for question rounds, "apply" to commit. Chat shortcut: `all`, `none`, or a list of numbers.
96
101
 
@@ -106,7 +111,7 @@ Why: <one-line pulled from the memory's Why>
106
111
 
107
112
  Decision:
108
113
 
109
- ## 2. 📝 Delete
114
+ ## 2. 📝 Retire
110
115
 
111
116
  `<memory-file>`
112
117
 
@@ -115,7 +120,7 @@ Reason: <one-line reason>
115
120
  Decision:
116
121
  ````
117
122
 
118
- For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `aitk-governance` and `.claude/standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For Delete items, skip the rewrite block. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
123
+ For Hand off items, the body is a pointer to the governance target instead of a rewritten rule: `aitk-governance` and `.claude/standards/rule.md` in the toolkit repo, or the `create-rule` skill in a target project. For Retire items, skip the rewrite block. Every item gets a `Decision:` slot regardless of action. `Take:` is added only when a question response is needed.
119
124
 
120
125
  Tell the user `✅ Wrote proposal to .claude/review/memory-review-<slug>.md`. Ask them to fill in `Decision:` per item, then re-ping with "discuss" for question rounds or "apply" to commit.
121
126
 
@@ -127,9 +132,9 @@ Trigger: user says "challenge the promotes", "challenge before apply", or asks f
127
132
 
128
133
  1. Read the latest `.claude/review/memory-review-*.md` at the main root.
129
134
  2. For each promote item, apply three tests:
130
- - **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to delete.
131
- - **Delta**: if the rule is a nice-to-have next to existing bullets, flip to delete.
132
- - **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to delete.
135
+ - **Absorbed**: grep the target surface for the rule's keywords. If already stated or implied, flip to retire.
136
+ - **Delta**: if the rule is a nice-to-have next to existing bullets, flip to retire.
137
+ - **Generality**: if the rule fires only on one literal trigger phrase, rewrite broader or flip to retire.
133
138
  3. Rewrite the review file in place with the updated actions and a one-line reason under each flip.
134
139
 
135
140
  ## Discuss phase
@@ -139,16 +144,16 @@ Trigger: user says "discuss", "respond to questions", or any `Decision:` value c
139
144
  1. Read the latest `.claude/review/memory-review-*.md` at the main root.
140
145
  2. For each item whose `Decision:` contains `?` or any unrecognized verb (anything other than `apply`, `skip`, `defer`):
141
146
  - Write a `Take:` line under `Decision:`, separated by exactly one blank line. If a `Take:` line already exists, overwrite it.
142
- - Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `delete` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
147
+ - Format: pick + one-line reason. Max 2 sentences. Decision-help style. State the recommendation (`apply` / `skip` / `retire` / specific alternative) first, then the reason. Do not enumerate tradeoffs unless one changes the call.
143
148
  - Leave the H2 emoji as 📝 pending.
144
149
  3. Skip items whose `Decision:` is `apply`, `skip`, `defer`, or empty.
145
150
  4. End with: `💬 Discussed: <nums> | ⏩ Skipped (committed or empty): <nums>`. Remind the user to refine `Decision:` lines and re-ping with "discuss" for another round, or "apply" when ready to commit.
146
151
 
147
- Do not act on any item. Do not delete memory files. Do not edit MEMORY.md. Do not edit promotion targets. Discuss only.
152
+ Do not act on any item. Do not archive memory files. Do not edit promotion targets. Discuss only.
148
153
 
149
154
  ## Apply phase
150
155
 
151
- Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked files (target surfaces, memory files, `MEMORY.md`).
156
+ Trigger: user says "apply", "commit", "ship the review", or re-pings with no question items remaining. Mutates tracked promotion targets and moves memory files into the archive.
152
157
 
153
158
  Before applying any item, check the worktree state:
154
159
 
@@ -173,13 +178,24 @@ Free-form text after the verb is a reason. Capture it in the receipt but do not
173
178
 
174
179
  Action by action type:
175
180
 
176
- - **Promote**: use `Edit` to insert the rewritten rule into the target surface. Then delete the memory file and remove its row from `.claude/memory/MEMORY.md`.
177
- - **Hand off**: do not edit governance. Delete the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
178
- - **Delete**: remove the memory file and its row from `.claude/memory/MEMORY.md`.
181
+ - **Promote**: use `Edit` to insert the rewritten rule into the target surface, then archive the memory file.
182
+ - **Promote to a context entry**: append the fact to `.claude/.tmp/memory-routing/<slug>.md`, then archive the memory file. `claude-docs` folds it in on its next run from a branch, which is what keeps one skill writing context entries.
183
+ - **Hand off**: do not edit governance. Archive the memory file only if the user confirmed the handoff explicitly. Otherwise leave it in place.
184
+ - **Retire**: archive the memory file.
185
+
186
+ Archiving means creating `.claude/.tmp/memory-archive/` at the main worktree root and moving the file there under its original name, overwriting any file already at that name. Never delete a memory entry. Nothing recovers one from a gitignored folder.
187
+
188
+ Do not hand-edit `.claude/memory/index.md`. Once every archive move is done, regenerate it instead:
189
+
190
+ ```bash
191
+ aitk indexes regen --no-stage --root <main-root> <main-root>/.claude/memory/index.md
192
+ ```
193
+
194
+ The `PostToolUse` hook that keeps the index current matches `Write|Edit|MultiEdit`, and an archive move is a shell `mv`, so nothing fires on it. Without this call the index keeps a row per archived entry and drifts exactly the way the hand-appended one did. Run it once after the last move rather than per item.
179
195
 
180
196
  Apply edits one at a time via `Edit`. Claude Code's tool permission dialog is the confirmation gate per edit. Never rewrite a whole file.
181
197
 
182
- As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 🗑 for deleted, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the review file. It stays as a receipt until Cleanup runs or the next Propose pass overwrites it.
198
+ As each item resolves, update its status in the review file: flip the H2 emoji from 📝 to ✅ for applied, ⏭ for skipped, 📦 for retired, or 🤝 for handed off. Refresh the summary block counts at the top. Do not delete the review file. It stays as a receipt until Cleanup runs or the next Propose pass overwrites it.
183
199
 
184
200
  **Chat shortcut:** the user replies with `all`, `none`, a comma-separated list of numbers, or `skip <nums>`. Write the matching verb into the `Decision:` slot of every item the reply names, `apply` for `all` or a bare list and `skip` for a `skip` reply, then run the parse above against the file. A reply of `none` writes nothing. A slot the reply does not name keeps its own value, so the receipt stays the source of truth and an empty slot still means take no action.
185
201
 
@@ -189,7 +205,7 @@ End with: `✅ Applied: <nums> | ⏭ Skipped: <nums> | 📝 Pending: <nums>`. Om
189
205
 
190
206
  Trigger: user says "cleanup" or "delete the receipt" after Apply has run.
191
207
 
192
- Cleanup removes one receipt and nothing else. Apply is the only phase that deletes a memory entry, and it does so per approved item against a folder that is gitignored with no history behind it, so a deletion made anywhere else has no undo and leaves no record of what it took. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
208
+ Cleanup removes one receipt and nothing else. Apply is the only phase that moves a memory entry out of the pen, and it does so per approved item into `.claude/.tmp/memory-archive/`. A user asking to sweep stale memories wants Propose, which classifies entries and writes a decision slot per entry.
193
209
 
194
210
  If no `.claude/review/memory-review-*.md` exists at the main root, stop: `✅ No review receipt to clean up.` Every other refusal in this skill carries a message, and the phase reads a receipt before it does anything else.
195
211
 
@@ -197,7 +213,7 @@ If no `.claude/review/memory-review-*.md` exists at the main root, stop: `✅ No
197
213
  2. Delete that one file. Leave every other receipt beside it in place, because the pending test above covers the file it read and nothing has tested the rest.
198
214
  3. Leave every memory entry in place. A `Skip` decision is terminal, and applied promotions, governance handoffs, and user-type memories each stay as the review left them.
199
215
 
200
- Do not promote, rewrite, or delete a memory entry. Receipts only.
216
+ Do not promote, rewrite, or archive a memory entry. Receipts only.
201
217
 
202
218
  ## After completion
203
219
 
@@ -205,7 +221,7 @@ Output one line per action taken in the most recent phase:
205
221
 
206
222
  - `✅ Promoted: .claude/memory/<memory-file> → <target>`
207
223
  - `✅ Handed off: .claude/memory/<memory-file> → governance`
208
- - `🗑 Deleted: .claude/memory/<memory-file>`
224
+ - `📦 Retired: .claude/memory/<memory-file> → .claude/.tmp/memory-archive/`
209
225
  - `🗑 Swept: .claude/review/<review-file>`
210
226
 
211
227
  If the user accepted nothing, output: `✅ No changes applied.`
@@ -112,6 +112,10 @@ Write no shape for a correction. A correction is a sentence, and a format for ad
112
112
 
113
113
  Keep enough planned, non-conflicting tasks available that a free worker never waits, and place the findings the last merge produced before promoting anything new. Run this after every merge and whenever the ready list thins. `@.claude/snippets/claude/orchestrator-sweep.md` fires this procedure after a batch of merges and adds the plan re-verification that a merge invalidates.
114
114
 
115
+ Open the sweep by invoking `aitk:claude-memory-capture`. Both other callers are ship-chain skills and this session never ships, so without this the session that receives every operator correction is the one session that records none. The sweep is the closest bounded moment this session has to a ship, and it already runs once per batch of merges, which beats an end-of-session moment a compaction can cut short.
116
+
117
+ Capture is told this session does not commit, so it skips routing and writes memory files alone. A routed fact lands in a context entry, which is a tracked file, and Boundaries below forbids writing one from here. That is the correct split rather than a limitation: a domain fact belongs to the task that owns the surface and goes in that task's Findings, while what this session produces is feedback about how to work, which is exactly the class the memory folder keeps.
118
+
115
119
  1. Run `gh pr list --state open` and `git log --oneline -8`. Report any pull request whose review has not been posted and stop for that one first.
116
120
  2. For each pull request merged since the last sweep, place every finding it produced. Route a finding that changes a rule to the standard or rule that states it, one that changes another task to that task's Findings, and one that overturns a groundwork lean to that folder marked answered. Never leave a finding in a pull request thread alone.
117
121
  3. Archive what closed. A task whose outcomes are all `[x]` runs `claude-docs` for the plan sweep, then `claude-tasks` to archive. A task whose outcomes describe standing policy rather than a deliverable never closes on its own, so hand it to a worker to encode the policy where it is enforced, then cut the outcomes with the reason recorded and archive once that branch merges. Encoding it from this session would write a tracked file, which Boundaries forbids.
@@ -121,6 +125,7 @@ Keep enough planned, non-conflicting tasks available that a free worker never wa
121
125
  7. Write a plan for each newly promoted task with `claude-feature`, then report:
122
126
 
123
127
  ```plaintext
128
+ Captured: <memory file> (<type>), or "nothing worth capturing"
124
129
  Findings placed: <finding> → <destination>
125
130
  Archived: <task>
126
131
  Promoted: <task>, touches <surfaces>, parallel with <task> because <disjoint sets>
@@ -17,7 +17,9 @@ Two failures belong to the audit rather than to the diff. A decision taken in ch
17
17
 
18
18
  - Read seed and standard content from the CLI rather than holding a copy, so the audit and the install cannot disagree
19
19
  - Diff per section, treating the preamble as a section of its own
20
- - Separate a customized section from a stale one, and default the customized one to no action
20
+ - Separate a customized section from a stale one by reading the attribution the drift report records, not by how the section looks, and default the customized one to no action
21
+ - Fall back to appearance only when attribution is unavailable, and mark every verdict reached that way as unverified
22
+ - Leave a file the report proves untouched to the bulk sync that owns it, rather than auditing what carries no edits
21
23
  - Persist the proposal and every decision to a review file that stays the source of truth across re-pings
22
24
  - Apply one section at a time, never by rewriting a file
23
25
 
@@ -12,19 +12,30 @@ Surfaces drift between the toolkit's current seed docs and what was installed in
12
12
  - If the `aitk` CLI is not on PATH, stop: `❌ aitk CLI not found. Install the toolkit first.`
13
13
  - If no `.claude/` directory exists at the project root, stop: `❌ No .claude/ directory found. Run aitk claude init first.`
14
14
 
15
- ## Step 1: read toolkit sources
15
+ ## Step 1: read toolkit sources and the drift report
16
16
 
17
- Run both in parallel from the project root:
17
+ Run all three in parallel from the project root:
18
18
 
19
19
  ```bash
20
20
  aitk claude seeds list --json 2>/dev/null
21
21
  aitk standards list --json 2>/dev/null
22
+ aitk sync --check . --json 2>/dev/null
22
23
  ```
23
24
 
24
25
  Seeds emit an array of `{name, source, target, content}`. Standards emit `{standards: [{name, description, target, content}]}`. In both cases `target` is the path relative to the project root where the file installs. Merge the two into one list of entries tagged by source (`seed` or `standard`).
25
26
 
26
27
  If the target project has no `.claude/standards/` directory, skip the standards stage silently.
27
28
 
29
+ ### Narrow the set by attribution
30
+
31
+ The report is what separates a file the project edited from one the toolkit moved on without it. Read `seeds.entries` for seed paths and `domains[].entries` for standards, then drop from the merged list every entry the report attributes as `stale`. A stale file matches a version the toolkit published, so it carries no edits to lose and `aitk standards sync` takes it whole. Section-merging it is work with no decision behind it.
32
+
33
+ Keep every seed regardless of state. `CLAUDE.md` is the file a project edits most, and its `drifted` verdict is the case this skill exists for.
34
+
35
+ Record the dropped standards as one line in the scope table rather than as rows: `<n> standards stale, taken by aitk standards sync`.
36
+
37
+ Fall back to the appearance heuristic in step 3 when the report cannot attribute, which is `historyUnavailable` set on the relevant section or the command failing outright. Say so in the summary block, because a fallback audit reports guesses rather than facts.
38
+
28
39
  ## Step 2: read installed copies
29
40
 
30
41
  For each entry in the merged list, read the file at its `target` path from the project root. Run reads in parallel. Mark missing files for **Add** treatment. Skip non-text seeds (`.json`) for section diffing. Record a one-line note in the scope table that the user can compare manually.
@@ -41,8 +52,9 @@ For each seed file present in both sides, parse the body into a preamble (everyt
41
52
  - **Toolkit-only section** (present in source, absent in target): candidate to **Add**.
42
53
  - **Target-only section** (present in target, absent in source): preserve, never propose removal. These are user customizations.
43
54
  - **Drifted section** (present in both, content differs): candidate to **Update**.
44
- - If the target version looks customized (extra bullets, project-specific paths, filled-in placeholders), call it out as **Customized**. Default action: skip, record in the scope table only, never numbered.
45
- - If the target version looks like the original toolkit version with the toolkit having moved on, call it out as **Stale**. Default action: propose update.
55
+ - Read the file's verdict from the report rather than judging it by eye. `drifted` means the content matches no version the toolkit ever published, so the project wrote it: call it **Customized**, default to skip, record in the scope table only, never numbered.
56
+ - `stale` at the file level means the toolkit moved and the project did not, so any section differing inside it is **Stale**. Default action: propose update.
57
+ - Only when the report could not attribute the file, judge by appearance: a version carrying extra bullets, project-specific paths, or filled-in placeholders reads as **Customized**, and one reading like the original toolkit text reads as **Stale**. Mark every verdict reached this way as unverified in the proposal.
46
58
 
47
59
  The user judges intent. The skill makes the judgment legible.
48
60