@erclx/aitk 0.94.0 → 0.95.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-orchestrate/SKILL.md +1 -1
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +11 -39
- package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +1 -1
- package/claude/skills/session-resume/REQUIREMENT.md +14 -3
- package/claude/skills/session-resume/SKILL.md +18 -5
- package/docs/agents/tasks.md +1 -1
- package/package.json +1 -1
- package/src/sandbox/expect.ts +29 -5
- package/src/tasks/archive.ts +13 -5
- package/src/tasks/validate.ts +2 -3
- package/standards/index.md +1 -0
- package/standards/session.md +106 -0
- package/standards/tasks.md +7 -2
|
@@ -38,7 +38,7 @@ The roadmap is optional and this skill does not require it. It carries why a seq
|
|
|
38
38
|
|
|
39
39
|
A compaction is a moment this skill cannot detect, so the human asks for each side of it and this skill reads the matching runbook when they do.
|
|
40
40
|
|
|
41
|
-
On a request to write the handoff or save the session, read `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` and follow it. It captures what the session learned, then writes `.claude/
|
|
41
|
+
On a request to write the handoff or save the session, read `${CLAUDE_SKILL_DIR}/references/orchestrator-handoff.md` and follow it. It captures what the session learned, then writes a session map per `.claude/standards/session.md`, or `${CLAUDE_SKILL_DIR}/../../standards/session.md` when the project does not have it, carrying the state of play, the mistakes worth not repeating, and the standing cautions, with the decisions taken under delegated authority added as this role's extension. That capture is the only one this session runs, since the refill sweep reports it as owed rather than paying it. Write nothing to the handoff that the board, a task file, or a groundwork folder already carries.
|
|
42
42
|
|
|
43
43
|
On a request to resume after a compaction, read `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md`, which reads that file back with the board and the groundwork behind the live work.
|
|
44
44
|
|
|
@@ -1,58 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Orchestrator handoff runbook
|
|
3
|
-
description:
|
|
3
|
+
description: The two sections an orchestrating session adds over the shared session map, how capture runs from a session that never commits, and the resume invocation the file carries out
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Write the pre-compaction handoff as orchestrator. Follow `.claude/standards/session.md`, or `${CLAUDE_SKILL_DIR}/../../standards/session.md` when the project does not have it, for the filename, the three core sections, the write procedure, and the citation rule. Everything below is the extension this role adds over that core, and none of it belongs to a session holding no delegated authority.
|
|
7
7
|
|
|
8
|
-
1.
|
|
9
|
-
2.
|
|
10
|
-
3.
|
|
11
|
-
4. Write only what a compaction destroys and no other file already carries. The board holds the ordering and what each task waits on, a task file holds its own findings, and a groundwork folder holds its track.
|
|
12
|
-
5. Use this shape, resolving `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md` and `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` to absolute paths as you write it and pasting each in place of `<RESUME_RUNBOOK>` and `<POLL_RUNBOOK>`:
|
|
8
|
+
1. Run the capture step the core opens with, and tell `aitk:claude-memory-capture` that this session does not commit.
|
|
9
|
+
2. Add `## Decisions taken under delegated authority` directly after `## State`, holding each decision and why it went that way, so nobody re-proposes it. It sits there rather than after the core because a decision is read against the state it was taken in.
|
|
10
|
+
3. Close the file with the block below, resolving `${CLAUDE_SKILL_DIR}/references/orchestrator-resume.md` and `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` to absolute paths as you write it and pasting each in place of `<RESUME_RUNBOOK>` and `<POLL_RUNBOOK>`:
|
|
13
11
|
|
|
14
12
|
```markdown
|
|
15
|
-
---
|
|
16
|
-
title: Session map
|
|
17
|
-
description: <what the board cannot show, and the date it was written>
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
# Session map
|
|
21
|
-
|
|
22
|
-
<one line marking the file throwaway and naming the board as the real source>
|
|
23
|
-
|
|
24
|
-
## State
|
|
25
|
-
|
|
26
|
-
<what is clean, what is running, what is open, and any untracked file that needs committing>
|
|
27
|
-
|
|
28
|
-
## Decisions taken under delegated authority
|
|
29
|
-
|
|
30
|
-
<each decision and why it went that way, so nobody re-proposes it>
|
|
31
|
-
|
|
32
|
-
## Mistakes worth not repeating
|
|
33
|
-
|
|
34
|
-
<what went wrong and the rule it yields>
|
|
35
|
-
|
|
36
|
-
## Standing cautions
|
|
37
|
-
|
|
38
|
-
<commands that lie, tools that measure the wrong tree, and anything unbacked>
|
|
39
|
-
|
|
40
13
|
Resume by loading the orchestrator skill and asking it to resume after a compaction. This repository spells that `/aitk:claude-orchestrate` followed by the request. Following <RESUME_RUNBOOK> reaches the same place with no skill loaded at all.
|
|
41
14
|
|
|
42
|
-
That resume reads the board and stops. It restarts nothing, so the review poll is a second thing owed here, and <POLL_RUNBOOK> holds the prompt and the condition. Do not reach for `session-resume`, which reads tracked work and
|
|
15
|
+
That resume reads the board and stops. It restarts nothing, so the review poll is a second thing owed here, and <POLL_RUNBOOK> holds the prompt and the condition. Do not reach for `session-resume`, which reads tracked work and reports the newest map without restarting this loop.
|
|
43
16
|
```
|
|
44
17
|
|
|
45
|
-
|
|
46
|
-
7. Overwrite the previous handoff rather than appending to it. A stale entry read as current is worse than no handoff.
|
|
47
|
-
|
|
48
|
-
The substitution belongs in step 5 because step 7 ends the write. A reader who treats the list as finished there ships the literal placeholders, and the variable expands while this runbook renders rather than in the turn that reads the handoff back, so a path left unresolved reaches a session holding no skill as a string matching nothing. `orchestrator-poll.md` resolves its script at the same point and for the same reason.
|
|
18
|
+
The delegated-authority section is the orchestrator's alone because a worker holds no delegation to have exercised, and a section a session cannot fill teaches its reader to skip the file. The closing block is the orchestrator's for the same reason from the other direction: it restarts a review poll no other role runs.
|
|
49
19
|
|
|
50
|
-
|
|
20
|
+
The substitution belongs in step 3 because that step ends the write. A reader who treats the list as finished elsewhere ships the literal placeholders, and the variable expands while this runbook renders rather than in the turn that reads the handoff back, so a path left unresolved reaches a session holding no skill as a string matching nothing. `orchestrator-poll.md` resolves its script at the same point and for the same reason.
|
|
51
21
|
|
|
52
|
-
That block sits in this runbook and again in the file this runbook writes, which is the fix rather than a copy for a later pass to collapse. A session has to already be holding this runbook to read it, and a compaction that took the skill body took the routing to it too, so the session that most needs the resume is the one that can no longer find it.
|
|
22
|
+
That block sits in this runbook and again in the file this runbook writes, which is the fix rather than a copy for a later pass to collapse. A session has to already be holding this runbook to read it, and a compaction that took the skill body took the routing to it too, so the session that most needs the resume is the one that can no longer find it. The map survives that, so it carries the invocation itself. Each of the two reaches a reader the other cannot.
|
|
53
23
|
|
|
54
24
|
The requirement is a resume request to the orchestrator skill with that skill loaded first. The command the block carries is this repository's spelling rather than the only one, since the skill ships to every target holding the plugin and each runs whatever client it runs. The poll restart is named beside it because the resume performs none.
|
|
55
25
|
|
|
56
26
|
Step 1 exists because both other callers of capture are ship-chain skills and this session never ships. Without a call here, the session that receives every operator correction is the one session that records none. A compaction arriving with no warning takes the capture with it, and firing it once per batch of merges leaves the same window open across a long planning stretch, since a sweep runs only on a merge. The refill sweep reports the debt between handoffs so the operator knows one is owed.
|
|
57
27
|
|
|
58
28
|
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 the orchestrator's boundaries forbid writing one from this session. That split is correct rather than a limitation, since 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 the class the memory folder keeps.
|
|
29
|
+
|
|
30
|
+
The core's drift step answers where the working directory carries `claude/skills/` with history behind it, which is the toolkit repository itself, and refuses by naming the absent tree anywhere else. A project consuming the plugin from a marketplace cache is that second case, so read the refusal as the boundary rather than as a fault.
|
|
@@ -6,7 +6,7 @@ description: What to read back after a compaction, and how to treat a groundwork
|
|
|
6
6
|
Resume as orchestrator after a compaction. Read the board and the groundwork behind the live work before answering anything, because a compaction summary keeps conclusions and drops the reasoning that produced them.
|
|
7
7
|
|
|
8
8
|
1. Resolve the main worktree root with `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. Every path below resolves against it.
|
|
9
|
-
2. Read `.claude/tasks/priority.md` for the ordering and what each task waits on. Read `.claude/tasks/session
|
|
9
|
+
2. Read `.claude/tasks/priority.md` for the ordering and what each task waits on. Read the newest `.claude/tasks/session-*.md` when one exists, per `.claude/standards/session.md`, and treat it as the previous session's scratch rather than a source.
|
|
10
10
|
3. Read the task file for every entry under `## Run now`, plus any entry a live pull request names.
|
|
11
11
|
4. Read the groundwork folder each of those tasks cites. Read `README.md` for the file map, then `06-decision.md` when the track is closed, or `07-next-session.md` and the numbered topic files when it is open. A task's Findings section is a lossy summary of its track, so planning against the summary re-derives what the folder already settled.
|
|
12
12
|
5. Run `gh pr list --state open` and `git log --oneline -5` to see what shipped since the folder was written.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-resume
|
|
3
|
-
description: Why resuming reads an index before task files, resolves scratch at the main root, and never mutates what it reports
|
|
3
|
+
description: Why resuming reads the handoff before the board, reads an index before task files, resolves scratch at the main root, and never mutates what it reports
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Session resume requirement
|
|
@@ -9,14 +9,20 @@ description: Why resuming reads an index before task files, resolves scratch at
|
|
|
9
9
|
|
|
10
10
|
Without this skill, a session picking up old work reconstructs state from the git log, which records what shipped and not what is queued, so finished work reads as pending and the actual next item goes unmentioned. The alternative failure is worse for a different reason. A session that reads every task file and every plan to be thorough spends the context the work needs before the work starts, and the summary arrives in a session with no room left to act on it.
|
|
11
11
|
|
|
12
|
+
A compaction keeps conclusions and drops the reasoning that produced them, and the previous session can write that reasoning to a handoff before it goes. A resume that reads the board, the plans, and the memory index alone walks past that file, so the one artifact written to survive the compaction reaches nobody and the next session re-derives what it holds.
|
|
13
|
+
|
|
14
|
+
The task index is a folder catalog rather than a task filter, so it carries a row for the ordering file and one for every handoff on the board. A session reporting each row as a backlog item queues work nobody filed, and the count grows with every session that ever wrote a handoff.
|
|
15
|
+
|
|
12
16
|
From a linked worktree the shared scratch folders resolve against the worktree rather than the main root, where they are empty. That reports no tracked work on a repository carrying a full backlog, and the report is indistinguishable from the true empty case.
|
|
13
17
|
|
|
14
18
|
A resume is a read, and a session that treats it as a cleanup pass offers to archive finished entries or refresh a memory it decided was stale. Both change tracked state on the strength of a summary the user has not confirmed yet.
|
|
15
19
|
|
|
16
20
|
## Must
|
|
17
21
|
|
|
18
|
-
-
|
|
22
|
+
- Read the newest handoff before the board, and report what it carries attributed to its writer
|
|
23
|
+
- Resolve the handoff, plans, memory, and tasks folders at the main worktree root
|
|
19
24
|
- Read the task index before any individual task file, and open only the task files the summary needs
|
|
25
|
+
- Drop the board siblings from the index before reporting it as the backlog, since the catalog filters nothing and carries a row per handoff
|
|
20
26
|
- Preserve the index's order in the report, since the order is the priority
|
|
21
27
|
- Surface only the memory entries that inform the top item
|
|
22
28
|
- Close with one recommendation naming the first item and whether a plan backs it
|
|
@@ -24,15 +30,20 @@ A resume is a read, and a session that treats it as a cleanup pass offers to arc
|
|
|
24
30
|
## Must not
|
|
25
31
|
|
|
26
32
|
- Read the whole tasks folder to build a summary
|
|
33
|
+
- Report the absence of a handoff, which is the common case and would train a reader to skip the line on the run where one exists
|
|
34
|
+
- Restate a handoff's counts, sizes, or costs as current. Each was true when written.
|
|
27
35
|
- Offer to remove, archive, or reorder an entry. Resume reports and does not mutate.
|
|
28
36
|
- Update memory, which changes when a recorded fact becomes wrong rather than on a resume
|
|
29
37
|
|
|
30
38
|
## Guards
|
|
31
39
|
|
|
32
|
-
- All
|
|
40
|
+
- All four surfaces absent or empty reports no tracked work and stops, rather than inventing a next step from the repository
|
|
41
|
+
- A handoff found beside an empty board recommends what the handoff leaves open, since the guard passes on the handoff alone and the recommendation has no backlog item to name
|
|
33
42
|
|
|
34
43
|
## Out of scope
|
|
35
44
|
|
|
45
|
+
- Writing a handoff, which happens at the close of a session rather than at its start. This skill names the standard that governs one and follows it no further.
|
|
46
|
+
- The sections a role adds over the core handoff, which belong to that role's own surface
|
|
36
47
|
- Archiving a shipped task out of the folder: `claude-tasks`
|
|
37
48
|
- Archiving a plan and marking an outcome, which `claude-docs` does when the work ships
|
|
38
49
|
- Implementing the item it recommends, which is the next request rather than part of this one
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-resume
|
|
3
|
-
description: Resumes a previous session by reading tracked work and relevant context. Use when starting a new session, or when asked to "pick up where we left off", "what was I working on", or "resume".
|
|
3
|
+
description: Resumes a previous session by reading the handoff it left behind, tracked work, and relevant context. Use when starting a new session, or when asked to "pick up where we left off", "what was I working on", or "resume".
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Session resume
|
|
@@ -11,19 +11,24 @@ Resolve `.claude/plans/`, `.claude/memory/`, and `.claude/tasks/` at the main wo
|
|
|
11
11
|
|
|
12
12
|
Read these in parallel, skipping any that do not exist:
|
|
13
13
|
|
|
14
|
-
- `.claude/tasks/
|
|
14
|
+
- the newest `.claude/tasks/session-*.md`: the handoff a previous session wrote before a compaction, per `.claude/standards/session.md`, or `${CLAUDE_SKILL_DIR}/../../standards/session.md` when the project does not have it. It leads the report rather than the reads.
|
|
15
|
+
- `.claude/tasks/index.md`: the folder catalog. Read this before any individual task file, and take the backlog from it by dropping the `index`, `priority`, and `session-` rows, which are siblings rather than tasks.
|
|
15
16
|
- `.claude/plans/*.md`: execution detail for in-progress tasks
|
|
16
17
|
- `.claude/memory/index.md` and any memory files relevant to the top backlog item
|
|
17
18
|
|
|
18
19
|
Then read only the task files the summary needs, typically the top one. Do not read the whole folder.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
Most projects carry no handoff. Say nothing about its absence, since a line reporting it every run trains a reader to skip the line on the run where a handoff exists.
|
|
22
|
+
|
|
23
|
+
If all four surfaces are absent or empty, stop: `✅ No tracked work found. Start a new task.`
|
|
21
24
|
|
|
22
25
|
## Step 2: summarize
|
|
23
26
|
|
|
24
|
-
Output
|
|
27
|
+
Output these sections, omitting the first when no handoff was found:
|
|
28
|
+
|
|
29
|
+
**Carried over:** the reasoning the handoff holds, as its writer stated it. Attribute it to the map rather than restating it as fact, and re-measure any count, size, or cost before acting on one.
|
|
25
30
|
|
|
26
|
-
**Up next:** one line per
|
|
31
|
+
**Up next:** one line per task row in `.claude/tasks/index.md`, preserving order. A board carrying handoffs has a row per session that wrote one, so a report listing every row queues work nobody filed.
|
|
27
32
|
|
|
28
33
|
**Active plans:** one line per file in `.claude/plans/`, linking each to its task file in `.claude/tasks/`. Say "None" if empty.
|
|
29
34
|
|
|
@@ -33,6 +38,14 @@ Output three sections:
|
|
|
33
38
|
|
|
34
39
|
End with one line: `Start with: <first Up next item>` and note whether it has a linked plan.
|
|
35
40
|
|
|
41
|
+
When the board is empty and a handoff was found, name what the handoff leaves open instead: `Start with: <the open thread the handoff names>`. A recommendation slot filled with nothing reads as a failed run, and a handoff on an empty board is the shape a session leaves when it was reasoning rather than shipping.
|
|
42
|
+
|
|
36
43
|
Do not offer to remove entries. A completed task is archived out of `.claude/tasks/` when work ships. The git log is the authoritative record of shipped work. Plan files are archived per the plan lifecycle rule in `CLAUDE.md`.
|
|
37
44
|
|
|
38
45
|
Memory is updated only when a recorded fact becomes wrong, never on resume. A domain fact reaches a session through `.claude/context/`, which `claude-memory-capture` routes to and the three-tier model loads on demand, so the memory folder read here is the residue no context entry owns.
|
|
46
|
+
|
|
47
|
+
## Writing the next one
|
|
48
|
+
|
|
49
|
+
This skill reads a handoff and never writes one. Reading and writing are two jobs, and the write happens at the close of a session rather than at its start.
|
|
50
|
+
|
|
51
|
+
Name the standard when the session asks how to leave a handoff behind, and let the session follow it directly. Any session may write one, whatever role it holds, so nothing here routes the request to another skill. A role carrying sections of its own adds them over the core per that role's own runbook.
|
package/docs/agents/tasks.md
CHANGED
|
@@ -103,7 +103,7 @@ The collision check is the one a person cannot run by eye. Paths come from the b
|
|
|
103
103
|
|
|
104
104
|
Exit codes: `0` every check passed, `1` refused, `2` at least one finding. The `reason` field carries which gate refused: `no-board`, `no-ordering`, or `no-groups`. A board grouping under headings of its own trips `no-groups` rather than being read against columns it never declared.
|
|
105
105
|
|
|
106
|
-
Columns are read from each table's own header rather than by position, so a project whose board differs from this one is reported for what it lacks. The `index
|
|
106
|
+
Columns are read from each table's own header rather than by position, so a project whose board differs from this one is reported for what it lacks. The `index` and `priority` siblings are skipped, along with every pre-compaction handoff, which takes one file per session under a `session-` prefix. None of them is a task, and a handoff counted as one would be reported as a task carrying no row on every session that wrote one.
|
|
107
107
|
|
|
108
108
|
Skills branch on the findings rather than on the exit code:
|
|
109
109
|
|
package/package.json
CHANGED
package/src/sandbox/expect.ts
CHANGED
|
@@ -220,15 +220,39 @@ function checkPaths(
|
|
|
220
220
|
)
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
+
/**
|
|
224
|
+
* An entry carrying `*` is matched as a glob, which is what lets an arm forbid
|
|
225
|
+
* a file whose name a run derives rather than fixes. Pinning one spelling of a
|
|
226
|
+
* derived name passes vacuously against every other spelling, which reads as
|
|
227
|
+
* coverage the arm does not have. Returns the offending path so a failure names
|
|
228
|
+
* the file the run wrote rather than the pattern that caught it.
|
|
229
|
+
*/
|
|
230
|
+
function writtenUnder(pattern: string, sandboxDir: string): string | undefined {
|
|
231
|
+
if (!pattern.includes('*')) {
|
|
232
|
+
return existsSync(join(sandboxDir, pattern)) ? pattern : undefined
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const match of new Bun.Glob(pattern).scanSync({
|
|
236
|
+
cwd: sandboxDir,
|
|
237
|
+
dot: true,
|
|
238
|
+
})) {
|
|
239
|
+
return match
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return undefined
|
|
243
|
+
}
|
|
244
|
+
|
|
223
245
|
function checkAbsent(
|
|
224
246
|
expectation: Expectation,
|
|
225
247
|
sandboxDir: string,
|
|
226
248
|
): AssertionResult[] {
|
|
227
|
-
return expectation.absent.map((path) =>
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
249
|
+
return expectation.absent.map((path) => {
|
|
250
|
+
const written = writtenUnder(path, sandboxDir)
|
|
251
|
+
|
|
252
|
+
return written
|
|
253
|
+
? { ok: false, message: `should not exist: ${written}` }
|
|
254
|
+
: { ok: true, message: `absent: ${path}` }
|
|
255
|
+
})
|
|
232
256
|
}
|
|
233
257
|
|
|
234
258
|
/**
|
package/src/tasks/archive.ts
CHANGED
|
@@ -9,12 +9,21 @@ const PLANS_DIR = join('.claude', 'plans')
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Siblings that sit on the board without being tasks: the generated index, the
|
|
12
|
-
* hand-maintained ordering, and
|
|
13
|
-
* reads the same list, so neither verb can
|
|
14
|
-
* does not.
|
|
12
|
+
* hand-maintained ordering, and a handoff a session wrote before the file took
|
|
13
|
+
* one name per session. `validate` reads the same list, so neither verb can
|
|
14
|
+
* count a sibling as a task the other does not.
|
|
15
15
|
*/
|
|
16
16
|
export const RESERVED_STEMS = ['index', 'priority', 'session'] as const
|
|
17
17
|
|
|
18
|
+
/** The pre-compaction handoff takes one file per session, so its stems vary. */
|
|
19
|
+
const SESSION_MAP_PREFIX = 'session-'
|
|
20
|
+
|
|
21
|
+
export function isReservedStem(stem: string): boolean {
|
|
22
|
+
const reserved: readonly string[] = RESERVED_STEMS
|
|
23
|
+
|
|
24
|
+
return reserved.includes(stem) || stem.startsWith(SESSION_MAP_PREFIX)
|
|
25
|
+
}
|
|
26
|
+
|
|
18
27
|
/**
|
|
19
28
|
* `bad-input` describes the command line rather than the board, which is the
|
|
20
29
|
* split `record.ts` draws for the same reason. A caller naming two selectors
|
|
@@ -190,12 +199,11 @@ function isLivePlan(target: string, dir: string, root: string): boolean {
|
|
|
190
199
|
|
|
191
200
|
export async function listTaskStems(dir: string): Promise<string[]> {
|
|
192
201
|
const entries = await readdir(dir)
|
|
193
|
-
const reserved: readonly string[] = RESERVED_STEMS
|
|
194
202
|
|
|
195
203
|
return entries
|
|
196
204
|
.filter((entry) => entry.endsWith('.md'))
|
|
197
205
|
.map((entry) => entry.slice(0, -'.md'.length))
|
|
198
|
-
.filter((stem) => !
|
|
206
|
+
.filter((stem) => !isReservedStem(stem))
|
|
199
207
|
.sort()
|
|
200
208
|
}
|
|
201
209
|
|
package/src/tasks/validate.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
2
|
import { readdir, readFile } from 'node:fs/promises'
|
|
3
3
|
import { join, resolve } from 'node:path'
|
|
4
|
-
import {
|
|
4
|
+
import { isReservedStem, tasksDir } from '@/tasks/archive'
|
|
5
5
|
|
|
6
6
|
const ORDERING_FILE = 'priority.md'
|
|
7
7
|
|
|
@@ -204,12 +204,11 @@ export function readBoard(text: string): {
|
|
|
204
204
|
|
|
205
205
|
async function listTaskStems(dir: string): Promise<string[]> {
|
|
206
206
|
const entries = await readdir(dir)
|
|
207
|
-
const reserved: readonly string[] = RESERVED_STEMS
|
|
208
207
|
|
|
209
208
|
return entries
|
|
210
209
|
.filter((entry) => entry.endsWith('.md'))
|
|
211
210
|
.map((entry) => entry.slice(0, -'.md'.length))
|
|
212
|
-
.filter((stem) => !
|
|
211
|
+
.filter((stem) => !isReservedStem(stem))
|
|
213
212
|
.sort()
|
|
214
213
|
}
|
|
215
214
|
|
package/standards/index.md
CHANGED
|
@@ -21,6 +21,7 @@ Reference docs for consistent authoring across the toolkit and target projects.
|
|
|
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
|
|
24
|
+
- [Session map reference](session.md): Filename and location, the sections a handoff carries, the write and read procedures, and how a role extends it
|
|
24
25
|
- [Claude skill reference](skill.md): Claude skill structure and authoring rules
|
|
25
26
|
- [Slug reference](slug.md): Transform from a git branch name to a slug, and the three responses to an empty result
|
|
26
27
|
- [Standard reference](standard.md): Shape and content rules for authoring a standard
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Session map reference
|
|
3
|
+
description: Filename and location, the sections a handoff carries, the write and read procedures, and how a role extends it
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Session map reference
|
|
7
|
+
|
|
8
|
+
Applies to `.claude/tasks/session-<slug>.md`. A session writes one before a compaction, because a compaction keeps conclusions and drops the reasoning that produced them. It is rewritten whenever the session that owns it learns something the next session would otherwise re-derive, and it is optional: a project whose sessions never approach a compaction carries none.
|
|
9
|
+
|
|
10
|
+
Any session writes one. The role a session holds decides which sections it adds on top of the core, never whether it may write at all.
|
|
11
|
+
|
|
12
|
+
## Scope
|
|
13
|
+
|
|
14
|
+
Governs the pre-compaction handoff at `.claude/tasks/session-<slug>.md`: its filename, its sections, what a writer puts in each, and how a reader picks one up.
|
|
15
|
+
|
|
16
|
+
Does not govern:
|
|
17
|
+
|
|
18
|
+
- The task board the file sits beside, its filenames, and its archiving: `tasks.md`
|
|
19
|
+
- The transform from a branch name to the slug in the filename: `slug.md`
|
|
20
|
+
- The role-specific sections a caller adds over the core, which belong to that caller
|
|
21
|
+
- Which memories a session captures before writing, which is the capture surface's own subject
|
|
22
|
+
|
|
23
|
+
## What a working session map looks like
|
|
24
|
+
|
|
25
|
+
A session map works when the session reading it can act on the reasoning without asking the session that wrote it:
|
|
26
|
+
|
|
27
|
+
- What is clean, what is running, and what is open right now?
|
|
28
|
+
- Which mistake already made would this session repeat?
|
|
29
|
+
- Which command, tool, or held instruction lies about the tree?
|
|
30
|
+
- Where did each claim come from, so a reader can tell a read from a recall?
|
|
31
|
+
|
|
32
|
+
A session map failing these is non-conforming even when it satisfies every shape rule below.
|
|
33
|
+
|
|
34
|
+
## Filename and location
|
|
35
|
+
|
|
36
|
+
- Write one file per session, named `session-<slug>.md`, where `<slug>` is the branch-derived slug
|
|
37
|
+
- Fall back to `session-latest.md` when the branch resolves empty, since a handoff is scratch rather than a commit and a stop would lose the reasoning it exists to save
|
|
38
|
+
- Resolve the containing folder at the main worktree root, never inside a linked worktree
|
|
39
|
+
- Overwrite the file the writing session already owns. A stale entry read as current is worse than no handoff.
|
|
40
|
+
- Never write into a file another session owns. One file per session is what keeps two sessions closing near each other from each writing the whole file, where the loser leaves no trace.
|
|
41
|
+
|
|
42
|
+
## Frontmatter
|
|
43
|
+
|
|
44
|
+
- `title` (required): `Session map`, so every handoff reads the same in a generated catalog
|
|
45
|
+
- `description` (required): what the board cannot show, and the date the file was written
|
|
46
|
+
|
|
47
|
+
## Sections
|
|
48
|
+
|
|
49
|
+
Three sections form the core, in this order, and every session fills all three.
|
|
50
|
+
|
|
51
|
+
- `## State`: what is clean, what is running, what is open, and any untracked file that needs committing
|
|
52
|
+
- `## Mistakes worth not repeating`: what went wrong and the rule it yields
|
|
53
|
+
- `## Standing cautions`: commands that lie, tools that measure the wrong tree, and anything unbacked
|
|
54
|
+
|
|
55
|
+
Add a section only for content that fits none of the three and would otherwise be lost.
|
|
56
|
+
|
|
57
|
+
## Writing one
|
|
58
|
+
|
|
59
|
+
1. Capture what the session learned first, so the map cites what was written instead of restating the same lesson in prose.
|
|
60
|
+
2. Run `aitk claude skills drift <the commit this session started from>` and record what it names under `## Standing cautions`. A skill body enters a session once and re-invoking the skill replays the held copy rather than the file, so the drift is worst at exactly this moment and a name here is a body the session has been following out of date. This step belongs to session length rather than to any role, so every writer runs it, and a refusal names the boundary of what the verb can read rather than a fault.
|
|
61
|
+
3. Recover that commit from how long the session has been running with `git log -1 --format=%H --before='<duration> ago'`, rounding the duration up rather than down. Nothing on the machine records it. A ref older than the oldest load over-reports, and confirming a name costs one read of the body, so the generous end is the safe one and a guess at the exact commit is not worth making.
|
|
62
|
+
4. Write only what a compaction destroys and no other artifact already carries. The board holds the ordering and what each task waits on, a task file holds its own findings, and a measurement folder holds its track.
|
|
63
|
+
5. Cite a commit, a task, or a file and line for every claim, so the next session can tell a read from a recall.
|
|
64
|
+
6. Fill a section from reasoning the session actually holds. A session with no cross-feature picture that fills `## State` from what is already in git has written a summary of the tree, which the reader can produce faster than they can read it.
|
|
65
|
+
|
|
66
|
+
Do not restate the board, and do not summarize the work that shipped, since version control already carries it.
|
|
67
|
+
|
|
68
|
+
## Reading one back
|
|
69
|
+
|
|
70
|
+
- Read the newest map in the folder, by modification time, and treat it as the previous session's scratch rather than as a source
|
|
71
|
+
- Say nothing when no map exists. Absence is the common case, and a line reporting it every run is the noise that makes the present case unnoticeable.
|
|
72
|
+
- Re-measure every count, size, and cost the map states, since each was true when written
|
|
73
|
+
|
|
74
|
+
## Extending it
|
|
75
|
+
|
|
76
|
+
- Carry every core section whatever else a role adds, and state in the surface that adds a section why the core cannot carry it
|
|
77
|
+
- Let the adding surface fix where its own section sits, so a role can place one between core sections where that reads better. The core order holds among the core sections alone.
|
|
78
|
+
- Keep a section out of the core when a session holding no such role would leave it unfilled. An unfilled section teaches a reader to skip the file.
|
|
79
|
+
- Carry a resume instruction inside the map itself when the routing to that instruction is what a compaction takes. The map survives what the instruction was loaded from, so each reaches a reader the other cannot.
|
|
80
|
+
|
|
81
|
+
## Template
|
|
82
|
+
|
|
83
|
+
```markdown
|
|
84
|
+
---
|
|
85
|
+
title: Session map
|
|
86
|
+
description: <what the board cannot show, and the date it was written>
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
# Session map
|
|
90
|
+
|
|
91
|
+
<one line marking the file throwaway and naming the board as the real source>
|
|
92
|
+
|
|
93
|
+
## State
|
|
94
|
+
|
|
95
|
+
<what is clean, what is running, what is open, and any untracked file that needs committing>
|
|
96
|
+
|
|
97
|
+
## Mistakes worth not repeating
|
|
98
|
+
|
|
99
|
+
<what went wrong and the rule it yields>
|
|
100
|
+
|
|
101
|
+
## Standing cautions
|
|
102
|
+
|
|
103
|
+
<commands that lie, tools that measure the wrong tree, and anything unbacked>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
A role-specific section is placed by the surface that adds it, so the skeleton above shows the core alone.
|
package/standards/tasks.md
CHANGED
|
@@ -21,6 +21,7 @@ Does not govern:
|
|
|
21
21
|
- Phase-label format and which surfaces a label may appear on: `versioning.md`
|
|
22
22
|
- Sequencing across versions and why the order is what it is: `roadmap.md`
|
|
23
23
|
- Architectural reasoning that outlives a task: `architecture.md`
|
|
24
|
+
- The pre-compaction handoff sitting in the folder, its filename and its sections: `session.md`
|
|
24
25
|
- When a project opens a task at all, which is project policy rather than a shape rule
|
|
25
26
|
|
|
26
27
|
## Layout
|
|
@@ -29,17 +30,21 @@ Does not govern:
|
|
|
29
30
|
.claude/tasks/
|
|
30
31
|
├── index.md ← generated, never hand-edited
|
|
31
32
|
├── priority.md ← hand-maintained execution order
|
|
32
|
-
├── session
|
|
33
|
+
├── session-<slug>.md ← optional, what a compaction is about to destroy
|
|
33
34
|
├── v09.0-sync-paths.md
|
|
34
35
|
└── v13.0-toolkit-drift.md
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
One file per task is what keeps the board safe under parallel sessions. Two sessions working different tasks never write the same file, which matters because a gitignored board has no history to recover a clobbered write from.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
Siblings sit in the folder without being tasks, and each earns its place by being governed somewhere. `index.md` and `priority.md` are governed here. Every `session-` file is a pre-compaction handoff governed by `session.md`, and each is optional: a project whose sessions never approach a compaction carries none. Anything filtering the folder to tasks skips all of them, so a name outside the set is a task whatever it holds.
|
|
41
|
+
|
|
42
|
+
The handoff takes one file per session for the reason a task does. A single shared path puts two sessions closing near each other on one file that neither can watch the other write, and the loser leaves no trace on a board with no history behind it.
|
|
40
43
|
|
|
41
44
|
`index.md` is generated from sibling frontmatter. The folder is gitignored, so the whole-repo index walk skips it and a hook passing the changed path regenerates it instead. Never hand-edit it.
|
|
42
45
|
|
|
46
|
+
The catalog is the one reader that filters nothing, so it carries a row per sibling alongside the tasks. That is what a folder catalog is for, and the handoffs are what make it worth stating: a board accumulates one row per session that ever wrote one, with nothing pruning them. Anything reading the catalog as the backlog therefore does its own filtering, and a reader that takes every row as a task reports the handoffs as queued work.
|
|
47
|
+
|
|
43
48
|
The `claude-tasks` skill creates and archives task files. `claude-docs` marks outcomes `[x]` in an existing file and sweeps the plans those tasks cite. Neither does the other's job.
|
|
44
49
|
|
|
45
50
|
## Ordering
|