@erclx/aitk 3.26.0 → 3.27.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/REQUIREMENT.md +8 -2
- package/claude/skills/claude-orchestrate/SKILL.md +5 -3
- package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +44 -0
- package/docs/agents/sessions.md +10 -0
- package/docs/operating-model.md +1 -1
- package/governance/rules/claude/510-context.md +0 -1
- package/governance/rules/claude/520-wireframes.md +0 -8
- package/governance/rules/claude/530-requirements.md +0 -8
- package/governance/rules/claude/540-architecture.md +0 -10
- package/governance/rules/claude/550-design.md +0 -8
- package/governance/rules/claude/555-tasks.md +0 -8
- package/governance/rules/claude/556-groundwork.md +0 -9
- package/governance/rules/claude/557-intake.md +0 -9
- package/governance/rules/claude/559-memory.md +0 -9
- package/governance/rules/claude/560-diagrams.md +0 -1
- package/governance/rules/claude/561-teach.md +1 -9
- package/governance/rules/claude/562-session.md +0 -4
- package/governance/rules/claude/570-skill.md +2 -3
- package/governance/rules/claude/580-readme.md +0 -8
- package/governance/rules/claude/590-rule-authoring.md +0 -13
- package/governance/rules/claude/591-standard-authoring.md +0 -8
- package/governance/rules/core/045-memory.md +2 -2
- package/governance/rules/lang/120-bash.md +3 -2
- package/package.json +1 -1
- package/src/commands/sessions.ts +40 -0
- package/src/sessions/claim.ts +59 -0
- package/src/worktree.ts +43 -0
- package/standards/markdown.md +1 -1
- package/standards/teach.md +1 -1
|
@@ -67,12 +67,16 @@ The session also records nothing of what it learns. Both other callers of memory
|
|
|
67
67
|
- Write each re-test into the row and its measurement into that task's Findings, since a result reported in chat is gone at the next compaction and the next pass measures the same thing
|
|
68
68
|
- Plan a row the re-test clears, since a cleared row carrying no plan is one the next pass looks at again
|
|
69
69
|
- Split a task whose file set collides with every other by construction, rather than re-measuring a scoping defect that reads as a blocker
|
|
70
|
+
- Check a candidate branch is unclaimed by an existing worktree or a live session before dispatching a background worker for it, since the measured failure this closes is a worker colliding with someone else's work already sitting in the row
|
|
71
|
+
- Cap concurrent self-dispatched workers at three, counted by a session name no human-launched worker carries, since the evidence behind self-dispatch is one task shipped once
|
|
72
|
+
- Report each self-dispatch and the row it fired against loudly enough to follow, since a person no longer watches the launch step happen
|
|
73
|
+
- Stop dispatching once `## Run now` is empty or every row in it reads claimed, rather than waking again to fire on a board nobody is clearing
|
|
70
74
|
|
|
71
75
|
## Must not
|
|
72
76
|
|
|
73
77
|
- Implement a feature or edit any tracked file from this session, at any size, since the ban offers no proportionality exception
|
|
74
78
|
- Merge. Recommend merge or changes and leave the gate to the human.
|
|
75
|
-
- Spawn worker
|
|
79
|
+
- Spawn a worker with the Agent tool, since an in-process subagent shares this session's context and cannot be steered or reached independently. A dispatched `claude --bg` process is not this: it is a separate session with its own worktree and its own PR, gated by the collision check and the worker cap.
|
|
76
80
|
- Hand a worker anything but a plan, because scope lives there
|
|
77
81
|
- Run a second orchestrator against the same board
|
|
78
82
|
- Promote a task to fill the queue when nothing qualifies. A thin queue is a real answer.
|
|
@@ -88,10 +92,12 @@ The session also records nothing of what it learns. Both other callers of memory
|
|
|
88
92
|
- Cross-version sequencing asked for: say no surface carries it, rather than asserting an active version the tree does not state
|
|
89
93
|
- This body dropped from a long session approaching a compaction: name the re-invocation and the runbook paths, since the routing lives in the body and a user-invoked skill routes nothing once it is gone
|
|
90
94
|
- Blocker only an operator can clear: record the row as untestable this pass and name the action owed, rather than re-measuring what no session can move
|
|
95
|
+
- Collision check refuses, with no session registry or no repository resolved: treat the candidate as unverified and fall back to the human-launch line, rather than reading a check that could not run as a clear one
|
|
96
|
+
- Worker cap already at three: stop dispatching for the pass and leave the row ready, rather than queueing past it
|
|
91
97
|
|
|
92
98
|
## Out of scope
|
|
93
99
|
|
|
94
100
|
- Writing the plan itself, which `claude-feature` owns and this session runs rather than reimplements
|
|
95
101
|
- Reviewing a worker's pull request, which `claude-pr-review` owns
|
|
96
|
-
- Entering the worktree a build runs in, which the human
|
|
102
|
+
- Entering the worktree a build runs in, which the worker opens for itself whether a human launched it or this session dispatched it
|
|
97
103
|
- The operating model this enacts, which the toolkit's own docs hold
|
|
@@ -10,7 +10,8 @@ This session is the orchestrator: the one warm session that holds the
|
|
|
10
10
|
cross-feature picture. It plans and reviews.
|
|
11
11
|
|
|
12
12
|
It does not build, and it does not merge. Building happens in cold worker
|
|
13
|
-
sessions
|
|
13
|
+
sessions, dispatched by this skill once the collision check clears or launched
|
|
14
|
+
by the human when it does not. Merging is the human's gate.
|
|
14
15
|
|
|
15
16
|
This skill holds the framing, the board procedure, and the dispatch. Every step
|
|
16
17
|
that builds something runs an existing skill. The queue rules below decide which
|
|
@@ -101,7 +102,7 @@ Write no shape for a correction. A correction is a sentence, and a format for ad
|
|
|
101
102
|
1. Plan the next feature. Run `claude-feature` here, with the cross-feature context, to write a plan to `.claude/plans/`. Planning stays in this warm session so the plan front-loads reasoning a cold worker would otherwise re-derive. Every plan written from here also carries a constraint per track in flight, which the paragraph below this list states.
|
|
102
103
|
2. Decide parallelism and merge order. Note which plans touch a shared wiring seam so their PRs merge in sequence, not at once.
|
|
103
104
|
3. Verify the plan against the tree. Reading it is not enough, since a plan goes stale from whatever merged after it was written. Grep for each construct it names and count the sites against the count it claims. Check that every phase label it cites is still open. Open each file it describes rather than trusting its account of the contents. Correct the plan before handing it over.
|
|
104
|
-
4. Hand off.
|
|
105
|
+
4. Hand off. Read `${CLAUDE_SKILL_DIR}/references/orchestrator-dispatch.md` and follow it: check the branch is unclaimed, check the worker cap, then dispatch a background worker with `claude --bg`. Fall back to the human-launch line it replaces when the check refuses, the cap is reached, or the row fails Parallelism against something already in flight.
|
|
105
106
|
5. Review the PR. When a worker opens a PR, run `claude-pr-review` to post findings to it. This is the deep, independent pass. The worker's autoship self-review was only the green gate.
|
|
106
107
|
- Learning that a PR moved is the mechanical half, so read `${CLAUDE_SKILL_DIR}/references/orchestrator-poll.md` and start the poll it carries on the first dispatch rather than checking the board by hand. That runbook holds the routing, and a summary of it here is a second source that drifts from it.
|
|
107
108
|
6. Dispatch the handback. A pass posting anything owed, a finding at any severity or a testing question, tells the session holding that branch to run `claude-address-review`, rather than waiting for a person to relay it. Re-review when the answer lands, then the human merges. Tell the trailing worker to rebase when its branch shares a seam with the merged one.
|
|
@@ -126,7 +127,8 @@ Stamp the block with the commit this session read the tree at, which the same se
|
|
|
126
127
|
- Run one orchestrator at a time. The board is gitignored, so a second session sees none of this one's writes: two task files land minutes apart under different labels for the same work, one session archives a task mid-sweep in the other, and each archives a plan the other had retargeted. An Owner column does not fix this, since neither session can read the other's rows.
|
|
127
128
|
- Do not implement features in this session. Hand the plan to a worker.
|
|
128
129
|
- Do not merge. Recommend merge or changes. The human merges.
|
|
129
|
-
- Do not spawn worker
|
|
130
|
+
- Do not spawn a worker with the Agent tool. An in-process subagent shares this session's context and cannot be steered or reached independently, which breaks the property this boundary protects rather than the mechanism it names. The dispatch in `orchestrator-dispatch.md` is a separate `claude --bg` process with its own worktree and its own PR, so it preserves that property instead.
|
|
131
|
+
- Dispatch a background worker only once the collision check in `orchestrator-dispatch.md` clears and the worker cap still has room. Colliding with an existing worktree or session, or exceeding the cap, is what the check and the cap exist to catch, not a judgment call this session makes case by case.
|
|
130
132
|
- Do not edit tracked files from this session, at any size. The boundary offers no proportionality exception and nothing enforces it.
|
|
131
133
|
- Do not hand a worker anything but a plan, since scope lives there. A plan carries exact diffs only when they are already known, otherwise it states the scope and the open questions and lets the worker write the diff.
|
|
132
134
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Orchestrator dispatch runbook
|
|
3
|
+
description: The collision check before a self-dispatch, the worker cap, the launch command, and the loop's stopping condition
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Run this at loop step 4, for a `## Run now` row whose plan is verified and whose file set has already cleared the Parallelism test against every track in flight, in place of handing the worktree to a human.
|
|
7
|
+
|
|
8
|
+
## Derive the candidate
|
|
9
|
+
|
|
10
|
+
Resolve `<slug>` from the row's plan the way `claude-worktree` Step 2 resolves a plan-matched name, per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Resolve `<type>` off that plan's `## Summary` and `**Files to touch:**` lines, per `${CLAUDE_SKILL_DIR}/../../standards/branch.md`, defaulting to `feat` when the lines settle nothing. The candidate branch is `<type>/<slug>`.
|
|
11
|
+
|
|
12
|
+
## Check the branch is unclaimed
|
|
13
|
+
|
|
14
|
+
Run `aitk sessions list --branch <type>/<slug> --json` and read `claimed` off the record.
|
|
15
|
+
|
|
16
|
+
- `claimed: true`: the row is not free. Report what holds it, `worktree` when it names a path and `sessions` when it carries a row, and move to the next candidate rather than colliding.
|
|
17
|
+
- `claimed: false` and `sessionsReadable: true`: proceed to the cap check.
|
|
18
|
+
- `claimed: false` and `sessionsReadable: false`, or the command refuses, or the record carries no `claimed` key (`reason` reads `no-registry` or `no-repository`): treat the candidate as unverified rather than clear. Report the refusal and fall back to the human-launch line below. Dispatching on a check that could not be read reproduces the exact collision this exists to prevent.
|
|
19
|
+
|
|
20
|
+
Reading `claimed` off the record is what keeps this a check rather than a rule a session can talk itself out of. The field is already the composed answer across the worktree listing and the live session listing, so nothing here re-derives the OR.
|
|
21
|
+
|
|
22
|
+
## Check the worker cap
|
|
23
|
+
|
|
24
|
+
Run `aitk sessions list --json` with no `--branch`, then count entries whose `name` starts with `orchestrator-` and whose `repository` matches this run's own (`git rev-parse --path-format=absolute --git-common-dir`). An unscoped listing spans every repository on the machine, so the repository match is what keeps a busy sibling project from binding this one's cap. Every dispatch below names its session that way for exactly this count, so a worker the human launched by hand carries no such name and is never counted against it.
|
|
25
|
+
|
|
26
|
+
Three already out: report the cap and stop dispatching for this pass, leaving the row ready for the next one. The cap binds the self-dispatch path alone, since the evidence behind it is one task shipped once and the operator's own launches stay uncapped by count.
|
|
27
|
+
|
|
28
|
+
## Dispatch
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
claude --bg -n "orchestrator-<slug>" "/aitk:claude-autoship .claude/tasks/<task-file>.md"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`claude-autoship`'s own Step 0 enters the worktree, so this session never does. `--bg, --background` starts the session as a background agent and returns immediately, and `-n, --name` sets the display name `aitk sessions list` reads back for the worker cap.
|
|
35
|
+
|
|
36
|
+
Report the dispatch as loudly as the human-launch line it replaces: name the branch, the task, and the session name, so a person reading the transcript can follow what fired without watching it happen.
|
|
37
|
+
|
|
38
|
+
## Fall back to the human
|
|
39
|
+
|
|
40
|
+
Hand the row to the human-launch line in step 4 instead of dispatching when any of these hold, and name which one: the collision check refused, the cap is reached, or the row's file set failed the Parallelism test against something already out.
|
|
41
|
+
|
|
42
|
+
## Stop the loop
|
|
43
|
+
|
|
44
|
+
Wrapped in `/loop`, re-run the check against `## Run now` on each wake. Stop rather than firing again once the group is empty or every row in it reads `claimed: true`. Report that once, on the wake that finds it, and let the loop end rather than continuing to poll a board nobody is clearing. `orchestrator-poll.md` already carries this reasoning for the review trigger, and it binds a dispatcher the same way.
|
package/docs/agents/sessions.md
CHANGED
|
@@ -34,6 +34,16 @@ A bare run reports every repository and carries a `repository` field on each row
|
|
|
34
34
|
|
|
35
35
|
The match can return more than one session. Read the count rather than the first row, since nothing stops two sessions holding one branch, and a caller that treats the result as singular picks among candidates without knowing it.
|
|
36
36
|
|
|
37
|
+
## Whether a branch is already claimed
|
|
38
|
+
|
|
39
|
+
With `--branch`, the JSON record also carries `worktree` (the path of any worktree already checked out to it, or `null`) and `claimed` (`true` when either a worktree or a live session already holds the branch).
|
|
40
|
+
|
|
41
|
+
Read `claimed` rather than composing the two fields by hand. A worktree can outlive the session that made it, and a session can hold a branch before a worktree exists for it, so either field alone can miss a real claim. A dispatcher deciding whether it is safe to start a build against a branch reads this one field instead of re-deriving the OR itself.
|
|
42
|
+
|
|
43
|
+
`worktree` and `claimed` are `null` on a bare run with no `--branch`, since neither question has a branch to answer about. A refusal (`no-registry` or `no-repository`) carries neither key at all, which a caller should read as unverified rather than as clear.
|
|
44
|
+
|
|
45
|
+
`sessionsReadable` is `false` when the session roster could not be read, which leaves `claimed` covering the worktree half alone. A `false` here is a report that ran short of evidence, not a report that the branch is clear, so a caller reads it as unverified alongside `claimed` rather than trusting `claimed` on its own.
|
|
46
|
+
|
|
37
47
|
## Why the verb exists
|
|
38
48
|
|
|
39
49
|
A session listing reports a name, a kind, a status, and how long each session has been running. None of those names a branch. Resolving a branch to a session therefore meant ordering the roster by start time and matching it against the order the worktrees were created, which is an inference that fails whenever two sessions start inside the same minute.
|
package/docs/operating-model.md
CHANGED
|
@@ -37,7 +37,7 @@ and no later session recovers that vantage.
|
|
|
37
37
|
One feature travels this path end to end.
|
|
38
38
|
|
|
39
39
|
1. Orchestrator plans the next feature with `claude-feature`, writing a plan to `.claude/plans/`. Planning stays in the warm session because good planning is cross-feature. It needs the contract other features consume and the shared wiring seam. A cold session would re-derive or guess.
|
|
40
|
-
2.
|
|
40
|
+
2. Orchestrator checks the branch is unclaimed and the worker cap has room, then dispatches a background worker with `claude --bg` against the plan. It falls back to naming the invocation for a human to run through `claude-worktree` and `claude-autoship` when the check refuses, the cap is reached, or the plan collides with a track already in flight. Either way, the worker enters its own worktree, builds, self-checks, opens a PR, and stops at the PR boundary.
|
|
41
41
|
3. Orchestrator reviews the PR with `claude-pr-review` and posts findings to it.
|
|
42
42
|
4. Orchestrator tells the session holding that branch to run `claude-address-review` once the pass posted a finding at any severity, resolving the target then with `aitk sessions list --branch` and reporting the invocation for the human when no live session holds it. The worker addresses the findings, rebases onto `origin/main` when a sibling landed first and left the branch unable to merge, then pushes a follow-up. A pass carrying only minor findings dispatches too, since the grade runs low often enough that a floor at should-fix loses fixes a worker would have made. `claude-pr-review` states that threshold and the heading follows it, so an open heading is itself the signal to send.
|
|
43
43
|
5. Orchestrator closes the review out with `claude-pr-review` again. The second pass reads only the commits the follow-up added, or the worker's response alone when the follow-up added none, and posts under `## Review` when it finds anything and under `## Review closed` when it finds nothing, so a reader learns from the heading whether work is still owed and takes the merge decision from the counts on the line under it. Repeat from step 4 until a pass closes the review.
|
|
@@ -10,7 +10,6 @@ paths:
|
|
|
10
10
|
|
|
11
11
|
- Before non-trivial work in a domain, read its `.claude/context/<domain>.md` entry. Use `.claude/context/index.md` to find it.
|
|
12
12
|
- Leave the entry conforming when work in its domain changes what it describes.
|
|
13
|
-
- Rewrite the decision a change supersedes rather than appending a second one narrating the transition.
|
|
14
13
|
|
|
15
14
|
## Narration pronouns
|
|
16
15
|
|
|
@@ -6,14 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Wireframe standards
|
|
8
8
|
|
|
9
|
-
## Layout and intent
|
|
10
|
-
|
|
11
|
-
- Draw each surface as an ASCII block inside a `plaintext` fence, one fence per distinct layout.
|
|
12
|
-
- Label a region with its role. Never label one with a class name, a token name, or a computed value.
|
|
13
|
-
- Carry on-screen copy verbatim, and mark copy the surface templates.
|
|
14
|
-
- State interaction intent, never the mechanism behind it. Send algorithms, handlers, and thresholds to a `.claude/context/` entry.
|
|
15
|
-
- Update a surface's wireframe in the same pull request that changes its layout or its interaction.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the wireframes standard for layout and interaction intent: ASCII layout, region labels, variants, copy, and what moves to `.claude/context/`. It is the single source. Read it with `aitk standards wireframes`.
|
|
@@ -6,14 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Requirements standards
|
|
8
8
|
|
|
9
|
-
## Scope and non-goals
|
|
10
|
-
|
|
11
|
-
- State a goal as a user-facing outcome, never as the implementation delivering it.
|
|
12
|
-
- Record explicit non-goals. Mark a deferred item `(deferred)`.
|
|
13
|
-
- Leave the MVP list as written once its features ship. Do not renumber it, extend it, or annotate an entry with status.
|
|
14
|
-
- Add later scope as a new section rather than as an extension of the MVP list.
|
|
15
|
-
- Drop a section rather than pad it. Include `## Distribution` only when the project ships outside its own repository.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the requirements standard for what belongs in the problem, goals, non-goals, MVP features, tech stack, and constraints. It is the single source. Read it with `aitk standards requirements`.
|
|
@@ -6,16 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Architecture standards
|
|
8
8
|
|
|
9
|
-
## Decisions
|
|
10
|
-
|
|
11
|
-
- Give each decision its own H3 under `## Key technical decisions`, naming what it chose and the alternative it passed over.
|
|
12
|
-
- Keep line-by-line function behavior and full type definitions out.
|
|
13
|
-
|
|
14
|
-
## Verification anchors
|
|
15
|
-
|
|
16
|
-
- Close a decision citing a measured number with `Measured at <short-sha> on <YYYY-MM-DD>.` Leave a decision citing none unanchored.
|
|
17
|
-
- Refresh that anchor whenever the number is re-read, whether or not it moved.
|
|
18
|
-
|
|
19
9
|
## Authority
|
|
20
10
|
|
|
21
11
|
- Follow the architecture standard for the overview, named decision entries, and risks. It is the single source. Read it with `aitk standards architecture`.
|
|
@@ -6,14 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Design standards
|
|
8
8
|
|
|
9
|
-
## Tokens
|
|
10
|
-
|
|
11
|
-
- Describe a token as intent rather than as a computed value.
|
|
12
|
-
- Keep CSS classes, component filenames, and prop names out.
|
|
13
|
-
- Carry a token system as a table, one row per token, and a component rule as a short bullet.
|
|
14
|
-
- Keep the token table headers verbatim.
|
|
15
|
-
- Record a non-obvious omission, such as no motion or no custom icons.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the design standard for visual intent, the token tables, and the render contract. It is the single source. Read it with `aitk standards design`.
|
|
@@ -6,14 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Tasks standards
|
|
8
8
|
|
|
9
|
-
## What a task carries
|
|
10
|
-
|
|
11
|
-
- Name where the task came from, through a `Plan:`, `Groundwork:`, `Intake:`, or `Issue:` line under the title.
|
|
12
|
-
- Size the outcomes so one pull request closes all of them. Split the task before handing it off.
|
|
13
|
-
- Use `## Outcomes` and `## Findings` and add no third heading. Note status inline on an outcome.
|
|
14
|
-
- Keep class names, file paths, function names, and prop names out of every entry and title.
|
|
15
|
-
- Never delete a task file. A shipped task moves to the archive under its own name.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the tasks standard for filenames, frontmatter, what belongs, and the task file format. It is the single source. Read it with `aitk standards tasks`.
|
|
@@ -6,15 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Groundwork standards
|
|
8
8
|
|
|
9
|
-
## Folder name
|
|
10
|
-
|
|
11
|
-
- Name a new track `.claude/groundwork/<nn>-<slug>/`, a two-digit zero-padded ordinal followed by a kebab-case slug. Take the ordinal from the highest one already present across both `.claude/groundwork/` and `.claude/intake/`, incremented, or `01` when neither folder holds an entry. Never renumber an existing folder.
|
|
12
|
-
|
|
13
|
-
## Measuring and closing
|
|
14
|
-
|
|
15
|
-
- Never carry a figure from an earlier session without re-measuring it. Mark an inference as an inference.
|
|
16
|
-
- Never close a track while an open question quietly fails an outcome. Resolve it, or record it as knowingly accepted.
|
|
17
|
-
|
|
18
9
|
## Authority
|
|
19
10
|
|
|
20
11
|
- Follow the groundwork standard for reserved numbering, frontmatter and dating, what each required file holds, and the conventions a track keeps. It is the single source. Read it with `aitk standards groundwork`.
|
|
@@ -6,15 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Intake standards
|
|
8
8
|
|
|
9
|
-
## Folder name
|
|
10
|
-
|
|
11
|
-
- Name a new dump `.claude/intake/<nn>-<slug>/`, a two-digit zero-padded ordinal followed by a kebab-case slug. Take the ordinal from the highest one already present across both `.claude/intake/` and `.claude/groundwork/`, incremented, or `01` when neither folder holds an entry. Never renumber an existing folder.
|
|
12
|
-
|
|
13
|
-
## The answer contract
|
|
14
|
-
|
|
15
|
-
- Never fill a `You:` slot and never infer a disposition from an empty one. Empty means unread, never agreement.
|
|
16
|
-
- Report unread items by count on a resume pass. Do not decide one.
|
|
17
|
-
|
|
18
9
|
## Authority
|
|
19
10
|
|
|
20
11
|
- Follow the intake standard for the folder layout, frontmatter and dating, the item format, and retrieval. It is the single source. Read it with `aitk standards intake`.
|
|
@@ -6,15 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Memory standards
|
|
8
8
|
|
|
9
|
-
## Routing
|
|
10
|
-
|
|
11
|
-
- Write no memory entry for a fact a per-domain context entry already owns.
|
|
12
|
-
|
|
13
|
-
## The pen
|
|
14
|
-
|
|
15
|
-
- Never delete a memory entry. Retire one by moving it to an archive under its own name, since the folder is gitignored and a wrong call has no undo.
|
|
16
|
-
- Never hand-edit `.claude/memory/index.md`. A hook regenerates it from sibling frontmatter.
|
|
17
|
-
|
|
18
9
|
## Authority
|
|
19
10
|
|
|
20
11
|
- Follow the memory standard for the filename and type prefix, the frontmatter, the body shape per type, links between entries, and the lifecycle. It is the single source. Read it with `aitk standards memory`.
|
|
@@ -16,4 +16,3 @@ paths:
|
|
|
16
16
|
|
|
17
17
|
- Write a new diagram to `.claude/diagrams/<kind>.md`, never to `.claude/DIAGRAMS.md`
|
|
18
18
|
- Convert a `.claude/DIAGRAMS.md` left by an older install into per-kind entries before editing it
|
|
19
|
-
- Refresh only the entries whose source signal moved. Do not rewrite the folder wholesale.
|
|
@@ -6,16 +6,8 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Teach standards
|
|
8
8
|
|
|
9
|
-
## What a workspace keeps
|
|
10
|
-
|
|
11
|
-
- Never renumber an existing folder, lesson, or record. A later reader cites it by the name it opened under.
|
|
12
|
-
- Write every success line as a task the learner can be asked to perform, never as something they will understand.
|
|
13
|
-
- Keep a reference page free of the learner. A page carrying second person or a quiz belongs under `lessons/`.
|
|
14
|
-
- Record the wrong answer a learner gave, never a count of what they missed.
|
|
15
|
-
- Date the workspace once, in the `MISSION.md` frontmatter. Never repeat the date in the body of any file.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the teach standard for the folder layout, ordinal naming, frontmatter, and the mission and learning-record formats. It is the single source. Read it with `aitk standards teach`.
|
|
20
|
-
- Read `references/glossary.md` inside the `claude-teach` skill for the glossary every workspace carries at its root. It is the single source for the entry shape, the ordering, and which terms the file carries. Read it rather than invoking the skill, which resumes a workspace and runs lessons.
|
|
12
|
+
- Read `references/glossary.md` inside the `aitk:claude-teach` skill for the glossary every workspace carries at its root. It is the single source for the entry shape, the ordering, and which terms the file carries. Read it rather than invoking the skill, which resumes a workspace and runs lessons.
|
|
21
13
|
- Report it rather than proceeding silently when that file does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
|
|
@@ -9,10 +9,6 @@ paths:
|
|
|
9
9
|
## What a handoff carries
|
|
10
10
|
|
|
11
11
|
- Follow this rule rather than `555-tasks.md` for a `session-` file. A handoff is not a task and carries neither `## Outcomes` nor `## Findings`.
|
|
12
|
-
- Never write into a file another session owns. Overwrite only the file the writing session already wrote.
|
|
13
|
-
- Resolve the containing folder at the main worktree root, never inside a linked worktree.
|
|
14
|
-
- Write only what a compaction destroys. Do not restate the board and do not summarize what shipped.
|
|
15
|
-
- Cite a commit, a task, or a file and line for every claim, so a reader can tell a read from a recall.
|
|
16
12
|
|
|
17
13
|
## Authority
|
|
18
14
|
|
|
@@ -11,9 +11,8 @@ paths:
|
|
|
11
11
|
|
|
12
12
|
## Before editing
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
- Report it rather than proceeding silently when `create-skill` does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
|
|
14
|
+
- Confirm `aitk:create-skill`'s two creation-time questions are answered before a new `SKILL.md` lands, whether drafted by hand, by another skill, or by `aitk:create-skill` itself. Carry the third question into the sibling `REQUIREMENT.md`'s `Must not` section as a review criterion rather than a gate.
|
|
15
|
+
- Report it rather than proceeding silently when `aitk:create-skill` does not resolve. It ships with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have it.
|
|
17
16
|
|
|
18
17
|
## After editing
|
|
19
18
|
|
|
@@ -6,14 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# README standards
|
|
8
8
|
|
|
9
|
-
## Audience and voice
|
|
10
|
-
|
|
11
|
-
- Write a repository-root README for someone deciding whether to commit to the project. A nested README keeps the reference voice.
|
|
12
|
-
- Address the reader in second person.
|
|
13
|
-
- Ground a claim in a command, a number, or a named constraint rather than an adjective.
|
|
14
|
-
- Name what the project does not do.
|
|
15
|
-
- Link out to full API documentation, license text, contribution guidelines, and troubleshooting rather than carrying them.
|
|
16
|
-
|
|
17
9
|
## Authority
|
|
18
10
|
|
|
19
11
|
- Follow the readme standard for voice, structure, required and optional sections, heading hierarchy, badge classes, per-project-type content, and what to link out rather than inline. It is the single source. Read it with `aitk standards readme`.
|
|
@@ -6,19 +6,6 @@ paths:
|
|
|
6
6
|
|
|
7
7
|
# Rule authoring standards
|
|
8
8
|
|
|
9
|
-
## Numbering
|
|
10
|
-
|
|
11
|
-
- Name a rule `.claude/rules/<subdirectory>/<n>-<slug>.md`. Give every rule a numeric prefix and keep the slug to one to three kebab words.
|
|
12
|
-
- Treat `000-899` as reserved for a rule set that ships to targets, `000-599` across the shared subdirectories and `600-899` held for ones it has not added.
|
|
13
|
-
- Number a rule the project authored itself in `900-999` and write it at `.claude/rules/project/<subdirectory>/<n>-<slug>.md`.
|
|
14
|
-
- Do not take a reserved number for a project-authored rule because nothing installed holds it today. A later release can ship into it.
|
|
15
|
-
|
|
16
|
-
## Body
|
|
17
|
-
|
|
18
|
-
- State one directive per bullet in imperative voice. Do not explain the reasoning behind a rule.
|
|
19
|
-
- Cut a rule that resists crisp one-line phrasing.
|
|
20
|
-
- Do not restate a rule a sibling rule or `CLAUDE.md` already owns. Point once.
|
|
21
|
-
|
|
22
9
|
## Authority
|
|
23
10
|
|
|
24
11
|
- Follow the rule-authoring standard for rule frontmatter, body shape, and voice. It is the single source. Read it with `aitk standards rule`.
|
|
@@ -7,14 +7,6 @@ paths:
|
|
|
7
7
|
|
|
8
8
|
# Standard authoring standards
|
|
9
9
|
|
|
10
|
-
## The scope statement
|
|
11
|
-
|
|
12
|
-
- Govern one document type per standard, or one attribute across every document.
|
|
13
|
-
- Open with a `## Scope` section naming what the standard governs and a `Does not govern:` list, placed above the shape rules.
|
|
14
|
-
- Put the governed path in backticks in the first sentence, anchored deep enough to resolve from a project root. Keep an attribute standard's first sentence free of backticks and say in it that it governs an attribute.
|
|
15
|
-
- Give each `Does not govern:` entry an excluded concern and the owner it goes to. Cut an entry naming no owner.
|
|
16
|
-
- Declare a yield, an exemption, or a handoff from both sides of the boundary.
|
|
17
|
-
|
|
18
10
|
## Authority
|
|
19
11
|
|
|
20
12
|
- Follow the standard-authoring standard for a standard's frontmatter, shape, scope, and success criterion. It is the single source. Read it with `aitk standards standard`.
|
|
@@ -7,6 +7,6 @@ description: Keep memory writes scoped to .claude/memory/ and out of context-own
|
|
|
7
7
|
## Writing memory
|
|
8
8
|
|
|
9
9
|
- Write all memory files to `.claude/memory/`, not `~/.claude/projects/`
|
|
10
|
-
- A fact about a domain goes to that domain's `.claude/context/` entry, not to memory. `claude-memory-capture` routes it there and `claude-docs` folds it in. Memory keeps only what no context entry owns.
|
|
10
|
+
- A fact about a domain goes to that domain's `.claude/context/` entry, not to memory. `aitk:claude-memory-capture` routes it there and `aitk:claude-docs` folds it in. Memory keeps only what no context entry owns. Report it rather than proceeding silently when either skill does not resolve. Both ship with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have them.
|
|
11
11
|
- Never delete a memory entry. Retire one by moving it to `.claude/.tmp/memory-archive/`. A bulk retire runs through the shell, where no file edit fires a path-scoped rule, and the folder is gitignored with nothing to recover from.
|
|
12
|
-
- Follow the memory standard
|
|
12
|
+
- Follow the memory standard for the filename and type prefix, the frontmatter, the body shape each type carries, and the lifecycle. Read it with `aitk standards memory`. Check every entry in the pen against that standard and fix what breaks it, since nothing keeps the folder conforming on its own.
|
|
@@ -8,9 +8,10 @@ paths:
|
|
|
8
8
|
|
|
9
9
|
## Skill routing
|
|
10
10
|
|
|
11
|
-
- Use `bash-script` for an interactive or human-facing script: prompts, a visual timeline UI, framed terminal output.
|
|
12
|
-
- Use `cli-script` for a non-interactive script: automation, CI, cron, a pipeline helper, or anything run by an agent rather than watched by a person.
|
|
11
|
+
- Use `aitk:bash-script` for an interactive or human-facing script: prompts, a visual timeline UI, framed terminal output.
|
|
12
|
+
- Use `aitk:cli-script` for a non-interactive script: automation, CI, cron, a pipeline helper, or anything run by an agent rather than watched by a person.
|
|
13
13
|
- Load the matched skill's own reference templates rather than hand-rolling interactivity or logging patterns outside them.
|
|
14
|
+
- Report it rather than proceeding silently when the matched skill does not resolve. Both ship with the plugin and this rule ships with the CLI, so a project that installed governance alone does not have them.
|
|
14
15
|
|
|
15
16
|
## Lint gate
|
|
16
17
|
|
package/package.json
CHANGED
package/src/commands/sessions.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Command } from 'commander'
|
|
2
|
+
import { checkClaim, type ClaimReport } from '@/sessions/claim'
|
|
2
3
|
import {
|
|
3
4
|
repositoryOf,
|
|
4
5
|
type ResolvedSession,
|
|
@@ -58,6 +59,18 @@ export function register(program: Command): void {
|
|
|
58
59
|
'A bare run reports every repository and carries the repository field,',
|
|
59
60
|
'so a caller filtering by hand has something that identifies one.',
|
|
60
61
|
'',
|
|
62
|
+
'With --branch, the JSON also carries "worktree" (the path of any',
|
|
63
|
+
'worktree already checked out to it, or null) and "claimed" (true when',
|
|
64
|
+
'either a worktree or a live session already holds it). A dispatcher',
|
|
65
|
+
'reads "claimed" rather than composing the two fields itself, since',
|
|
66
|
+
'either one alone can miss a real claim: a worktree can outlive the',
|
|
67
|
+
'session that made it, and a session can hold a branch before a',
|
|
68
|
+
'worktree exists for it.',
|
|
69
|
+
'',
|
|
70
|
+
'"sessionsReadable" is false when the session roster could not be read,',
|
|
71
|
+
'which leaves "claimed" covering the worktree half alone. Treat that',
|
|
72
|
+
'case as unverified rather than as a clean "false".',
|
|
73
|
+
'',
|
|
61
74
|
'The match can return more than one session. Read the count rather than',
|
|
62
75
|
'the first row, since two sessions can hold one branch.',
|
|
63
76
|
'',
|
|
@@ -132,9 +145,17 @@ async function runList(opts: ListCommandOptions): Promise<number> {
|
|
|
132
145
|
)
|
|
133
146
|
: report.sessions
|
|
134
147
|
|
|
148
|
+
const claim = opts.branch
|
|
149
|
+
? await checkClaim(opts.branch, {
|
|
150
|
+
cwd: process.cwd(),
|
|
151
|
+
resolve: async () => report,
|
|
152
|
+
})
|
|
153
|
+
: null
|
|
154
|
+
|
|
135
155
|
intro('aitk sessions list')
|
|
136
156
|
reportConfidence(report)
|
|
137
157
|
reportSessions(shown, opts.branch, repository)
|
|
158
|
+
if (claim) reportClaim(claim)
|
|
138
159
|
outro()
|
|
139
160
|
|
|
140
161
|
if (opts.json) {
|
|
@@ -144,6 +165,9 @@ async function runList(opts: ListCommandOptions): Promise<number> {
|
|
|
144
165
|
confidence: report.confidence,
|
|
145
166
|
branch: opts.branch ?? null,
|
|
146
167
|
repository,
|
|
168
|
+
worktree: claim?.worktree ?? null,
|
|
169
|
+
claimed: claim?.claimed ?? null,
|
|
170
|
+
sessionsReadable: claim?.sessionsReadable ?? null,
|
|
147
171
|
sessions: shown,
|
|
148
172
|
})}\n`,
|
|
149
173
|
)
|
|
@@ -229,3 +253,19 @@ function reportSessions(
|
|
|
229
253
|
.join('\n'),
|
|
230
254
|
)
|
|
231
255
|
}
|
|
256
|
+
|
|
257
|
+
function reportClaim(claim: ClaimReport): void {
|
|
258
|
+
logStep('Claim')
|
|
259
|
+
|
|
260
|
+
if (claim.worktree) {
|
|
261
|
+
logInfo(`Worktree: ${claim.worktree}`)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
logInfo(claim.claimed ? 'Claimed.' : 'Unclaimed.')
|
|
265
|
+
|
|
266
|
+
if (!claim.sessionsReadable) {
|
|
267
|
+
logWarn(
|
|
268
|
+
'The session roster could not be read, so this reads the worktree listing alone. Treat the session half as unverified rather than clear.',
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
repositoryOf,
|
|
3
|
+
resolveSessions,
|
|
4
|
+
type ResolvedSession,
|
|
5
|
+
type SessionReport,
|
|
6
|
+
} from '@/sessions/resolve'
|
|
7
|
+
import { listWorktrees, type WorktreeEntry } from '@/worktree'
|
|
8
|
+
|
|
9
|
+
export interface ClaimReport {
|
|
10
|
+
readonly claimed: boolean
|
|
11
|
+
readonly worktree: string | null
|
|
12
|
+
readonly sessions: readonly ResolvedSession[]
|
|
13
|
+
/** False when the session roster could not be read, so `claimed` covers the worktree half alone and cannot be trusted as a clean "unclaimed". */
|
|
14
|
+
readonly sessionsReadable: boolean
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface ClaimOptions {
|
|
18
|
+
readonly cwd?: string
|
|
19
|
+
readonly resolve?: () => Promise<SessionReport>
|
|
20
|
+
readonly listWorktrees?: (cwd: string) => Promise<readonly WorktreeEntry[]>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Answers whether a branch is already claimed, composing the two readings
|
|
25
|
+
* neither surface can answer alone: a worktree can outlive the session that
|
|
26
|
+
* made it, and a session can hold a branch before a worktree exists for it.
|
|
27
|
+
*/
|
|
28
|
+
export async function checkClaim(
|
|
29
|
+
branch: string,
|
|
30
|
+
opts: ClaimOptions = {},
|
|
31
|
+
): Promise<ClaimReport> {
|
|
32
|
+
const cwd = opts.cwd ?? process.cwd()
|
|
33
|
+
const resolve = opts.resolve ?? resolveSessions
|
|
34
|
+
const listAll = opts.listWorktrees ?? listWorktrees
|
|
35
|
+
|
|
36
|
+
const [repository, worktrees, report] = await Promise.all([
|
|
37
|
+
repositoryOf(cwd),
|
|
38
|
+
listAll(cwd),
|
|
39
|
+
resolve(),
|
|
40
|
+
])
|
|
41
|
+
|
|
42
|
+
const worktree =
|
|
43
|
+
worktrees.find((entry) => entry.branch === branch)?.path ?? null
|
|
44
|
+
|
|
45
|
+
const sessions =
|
|
46
|
+
report.kind === 'resolved'
|
|
47
|
+
? report.sessions.filter(
|
|
48
|
+
(session) =>
|
|
49
|
+
session.branch === branch && session.repository === repository,
|
|
50
|
+
)
|
|
51
|
+
: []
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
claimed: worktree !== null || sessions.length > 0,
|
|
55
|
+
worktree,
|
|
56
|
+
sessions,
|
|
57
|
+
sessionsReadable: report.kind === 'resolved',
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/worktree.ts
CHANGED
|
@@ -37,3 +37,46 @@ export async function mainWorktreeRoot(): Promise<string> {
|
|
|
37
37
|
|
|
38
38
|
return line ? line.slice('worktree '.length).trim() : process.cwd()
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
export interface WorktreeEntry {
|
|
42
|
+
readonly path: string
|
|
43
|
+
readonly branch: string | null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parses `git worktree list --porcelain`, which emits one block per worktree
|
|
48
|
+
* separated by a blank line. A detached worktree carries no `branch` line,
|
|
49
|
+
* reported here as `null` rather than a guessed name.
|
|
50
|
+
*/
|
|
51
|
+
export async function listWorktrees(
|
|
52
|
+
cwd: string = process.cwd(),
|
|
53
|
+
): Promise<readonly WorktreeEntry[]> {
|
|
54
|
+
const result = await $`git -C ${cwd} worktree list --porcelain`
|
|
55
|
+
.quiet()
|
|
56
|
+
.nothrow()
|
|
57
|
+
if (result.exitCode !== 0) return []
|
|
58
|
+
|
|
59
|
+
const entries: WorktreeEntry[] = []
|
|
60
|
+
let path: string | undefined
|
|
61
|
+
let branch: string | null = null
|
|
62
|
+
|
|
63
|
+
for (const line of result.stdout.toString().split('\n')) {
|
|
64
|
+
if (line.startsWith('worktree ')) {
|
|
65
|
+
if (path !== undefined) entries.push({ path, branch })
|
|
66
|
+
path = line.slice('worktree '.length).trim()
|
|
67
|
+
branch = null
|
|
68
|
+
continue
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (line.startsWith('branch ')) {
|
|
72
|
+
const ref = line.slice('branch '.length).trim()
|
|
73
|
+
branch = ref.startsWith('refs/heads/')
|
|
74
|
+
? ref.slice('refs/heads/'.length)
|
|
75
|
+
: ref
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (path !== undefined) entries.push({ path, branch })
|
|
80
|
+
|
|
81
|
+
return entries
|
|
82
|
+
}
|
package/standards/markdown.md
CHANGED
|
@@ -13,7 +13,7 @@ Governs what a check can decide about a markdown file: headings, paragraph and l
|
|
|
13
13
|
|
|
14
14
|
The two frontmatter fields it reaches are `title` and `description`. They are named here rather than in the statement above, since a backticked token in a scope statement's first sentence is published as the standard's jurisdiction.
|
|
15
15
|
|
|
16
|
-
The split with the voice guidance is what reads the rule rather than what the rule covers. Every ban below ships as data `aitk markdown audit` and the installed audit hook both read, so a violation is measured on every run. Cadence, rhythm, and information density are judgments a reader settles, and those travel in the `write-human` skill, which a markdown edit routes to.
|
|
16
|
+
The split with the voice guidance is what reads the rule rather than what the rule covers. Every ban below ships as data `aitk markdown audit` and the installed audit hook both read, so a violation is measured on every run. Cadence, rhythm, and information density are judgments a reader settles, and those travel in the `aitk:write-human` skill, which a markdown edit routes to.
|
|
17
17
|
|
|
18
18
|
Does not govern:
|
|
19
19
|
|
package/standards/teach.md
CHANGED
|
@@ -97,7 +97,7 @@ Record the wrong answer rather than the fact of an error. A wrong answer names t
|
|
|
97
97
|
|
|
98
98
|
## GLOSSARY.md
|
|
99
99
|
|
|
100
|
-
Required in every workspace, holding one entry per term the subject defines. The glossary reference the `claude-teach` skill carries fixes what an entry looks like, how the file orders and groups them, and which terms it carries, so this standard states only that the file exists and sits at the workspace root. That reference ships with the plugin rather than installing here, because a promoted glossary keeps its shape wherever it lands and no project folder covers every destination. Say so and stop rather than working the shape from memory when the project has no plugin to read it from.
|
|
100
|
+
Required in every workspace, holding one entry per term the subject defines. The glossary reference the `aitk:claude-teach` skill carries fixes what an entry looks like, how the file orders and groups them, and which terms it carries, so this standard states only that the file exists and sits at the workspace root. That reference ships with the plugin rather than installing here, because a promoted glossary keeps its shape wherever it lands and no project folder covers every destination. Say so and stop rather than working the shape from memory when the project has no plugin to read it from.
|
|
101
101
|
|
|
102
102
|
Name the lesson or reference page a term first appears in as that reference requires. A workspace is the case it was written for, so a glossary here has a first appearance to name.
|
|
103
103
|
|