@erclx/aitk 0.71.0 → 0.73.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 +6 -0
- package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +13 -3
- package/claude/skills/toolkit-operator/REQUIREMENT.md +4 -0
- package/claude/skills/toolkit-operator/SKILL.md +7 -2
- package/docs/agents/install-and-sync.md +6 -0
- package/package.json +1 -1
- package/scripts/lib/sandbox-fixtures.sh +61 -0
- package/tooling/web/reference.md +3 -1
|
@@ -21,6 +21,8 @@ The ban on writing at all fails on a different axis, which is that nothing enfor
|
|
|
21
21
|
|
|
22
22
|
Output drifts everywhere the contract stops. The specified shape covers invocation alone, so a sweep report, a board report, and an analysis each end in a decision the human owns and each buries it under the evidence they would have skipped. A compaction is the same failure one step earlier, since the file that survives it has a stated reader and no stated writer, and the session improvises what to save and loses the reasoning the board never held.
|
|
23
23
|
|
|
24
|
+
Naming that reader without naming the way in fails on the next axis, and it fails circularly. The command that routes a resume request lives in this body, which is the surface a long session is likeliest to have dropped, and dropping it is the condition the handoff exists to survive, so the session holding a complete handoff cannot reach the runbook that reads it back. The review poll is lost in the same moment and recovered by neither, since it is session-scoped and the resume performs no restart, which leaves a reader who follows the whole handoff with a board and no trigger.
|
|
25
|
+
|
|
24
26
|
The runbooks the session cannot run from memory fail on a third axis, which is where they are kept. A runbook reached by an installed path is a dependency on a channel this skill does not travel on, so a project holding the plugin and running no install follows the citation to nothing, and nothing reports the break because a missing file produces no error until someone opens the path. Every one of them therefore has to ship inside the skill, the three covering the moments the loop cannot detect and the fourth holding the review trigger. That fourth one fails on an axis of its own, since it names one client's command as the way to start the loop, so a session holding a different recurring-prompt scheduler reaches no path and a client without that command reaches none either, and the file ships to every target holding the plugin.
|
|
25
27
|
|
|
26
28
|
The session also records nothing of what it learns. Both other callers of memory capture are ship-chain skills and this one never ships, so the session taking every operator correction is the session with no moment that writes one down. Hanging that moment on the merge sweep answers it and bills the operator a capture pass per batch of merges while nothing is being built, which is a cost paid on the days shipping is fastest.
|
|
@@ -41,6 +43,10 @@ The session also records nothing of what it learns. Both other callers of memory
|
|
|
41
43
|
- Re-resolve the board's plan pointers after any archive, since the archiving skill rewrites the task file and knows nothing about the board
|
|
42
44
|
- Lead a sweep report, a board report, and an analysis with the state, the open decisions, and the next action, keeping the evidence below them
|
|
43
45
|
- Write the pre-compact handoff with what no other file carries, and name the runbook that reads it back
|
|
46
|
+
- Carry the resume invocation and the owed poll restart in the handoff file itself, not in the runbook that writes it alone, since the file is what survives a compaction and the runbook is what a session has to already be holding to read
|
|
47
|
+
- State the invocation as a resume request to this skill with one client's command as the example, since the handoff ships to every target holding the plugin
|
|
48
|
+
- Resolve every runbook path the handoff carries to an absolute path as it is written, since the reader holds no skill and the path variable does not expand in the turn that reads the file back
|
|
49
|
+
- Distinguish this resume from the general-purpose `session-resume`, since the name an operator reaches for first reaches a skill that knows nothing about the board
|
|
44
50
|
- Capture what the session learned at the handoff rather than in the merge sweep, and have the sweep report the debt dated from the last handoff, since a capture per batch of merges bills the operator a wait while nothing ships and an undated row reads the same however long the debt has run
|
|
45
51
|
- Carry every runbook the session cannot run from memory inside the skill, so each citation resolves for a project holding the plugin and nothing else
|
|
46
52
|
- State which rule wins where the tracked-file ban collides with the root instruction on small edits, and where a correction no open task owns goes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Orchestrator handoff runbook
|
|
3
|
-
description: Memory capture at the close of a session, what to write to .claude/tasks/session.md before a compaction,
|
|
3
|
+
description: Memory capture at the close of a session, what to write to .claude/tasks/session.md before a compaction, what to leave to the board, and the resume invocation the file carries out
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
Capture what the session learned, then write the pre-compact handoff as orchestrator. Do both before a compaction, because a compaction keeps conclusions and drops the reasoning that produced them, and no other file in the repository carries that reasoning.
|
|
@@ -8,7 +8,7 @@ Capture what the session learned, then write the pre-compact handoff as orchestr
|
|
|
8
8
|
1. Invoke `aitk:claude-memory-capture` and tell it this session does not commit. Capture reads the session and this handoff summarizes it, so capturing first lets the handoff cite what was written instead of restating the same lesson in prose.
|
|
9
9
|
2. Resolve the main worktree root with `git worktree list --porcelain | grep -m 1 '^worktree ' | cut -d' ' -f2-`, falling back to `pwd`. Write `.claude/tasks/session.md` under it.
|
|
10
10
|
3. 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.
|
|
11
|
-
4. Use this shape
|
|
11
|
+
4. 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>`:
|
|
12
12
|
|
|
13
13
|
```markdown
|
|
14
14
|
---
|
|
@@ -35,12 +35,22 @@ description: <what the board cannot show, and the date it was written>
|
|
|
35
35
|
## Standing cautions
|
|
36
36
|
|
|
37
37
|
<commands that lie, tools that measure the wrong tree, and anything unbacked>
|
|
38
|
+
|
|
39
|
+
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.
|
|
40
|
+
|
|
41
|
+
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 knows nothing about this board or the workers on it.
|
|
38
42
|
```
|
|
39
43
|
|
|
40
44
|
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.
|
|
41
45
|
6. Overwrite the previous handoff rather than appending to it. A stale entry read as current is worse than no handoff.
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
The substitution belongs in step 4 because step 6 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.
|
|
48
|
+
|
|
49
|
+
Add a section only for content that fits none of the four and would otherwise be lost. Do not restate the board, and do not summarize the work that shipped, because git already carries it. The closing block is the one exception, and the paragraph below states why.
|
|
50
|
+
|
|
51
|
+
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. `session.md` survives that, so it carries the invocation itself. Each of the two reaches a reader the other cannot.
|
|
52
|
+
|
|
53
|
+
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.
|
|
44
54
|
|
|
45
55
|
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.
|
|
46
56
|
|
|
@@ -21,6 +21,8 @@ The last failure is writing without re-checking. A domain sync brought a stricte
|
|
|
21
21
|
- Map the stated intent to one lifecycle phase, then either run the simplest command that satisfies it or hand off
|
|
22
22
|
- Resolve every stack, rule, snippet, and standard name from a catalog at runtime
|
|
23
23
|
- Run the CLI non-interactively and report the command run, what changed, and the full path of anything written
|
|
24
|
+
- Read the reverse walk beside the forward sections, so a folder the toolkit stopped shipping and a migration with a live case both reach the user
|
|
25
|
+
- Hand off a named migration to the skill the report names, the way an unmigrated domain reaches `migration-standards`
|
|
24
26
|
- Offer every audit whose surface the target carries, and offer none whose surface it lacks
|
|
25
27
|
- Re-check the target after any operation that wrote, and report what those writes changed against the state read before acting
|
|
26
28
|
|
|
@@ -29,6 +31,7 @@ The last failure is writing without re-checking. A domain sync brought a stricte
|
|
|
29
31
|
- Edit a managed file by hand instead of running the CLI that owns it
|
|
30
32
|
- Reimplement a flow another skill owns
|
|
31
33
|
- Hardcode a catalog name
|
|
34
|
+
- Move, delete, or name a command against a folder in `unclaimed`. The toolkit stopped claiming the path and only the user knows whether the project owns what sits there
|
|
32
35
|
- Run an audit the user did not pick, which turns a front door into a full sweep
|
|
33
36
|
- Refuse to finish an operation over an audit finding, since every audit reports judgments beside facts and a router that stops on one is a router a target works around
|
|
34
37
|
- Auto-trigger. It is a door the user opens, and a router that fires on its own routes requests nobody made.
|
|
@@ -38,6 +41,7 @@ The last failure is writing without re-checking. A domain sync brought a stricte
|
|
|
38
41
|
- An intent matching a deep flow hands off rather than running a shallow version of it, since a partial scaffold is harder to recover from than none
|
|
39
42
|
- An ignore-only fix on an unmeasured tooling report stops, names which cause applies, and names the command answering that cause. Unmeasured has several causes and they do not share a remedy, so one suggested command is wrong for at least one of them. No cause asks the user to supply a stack name, and none reads the zero counts under an unmeasured report as a clean target.
|
|
40
43
|
- A re-check with no earlier report to compare against says the write ran without a baseline, rather than describing the target from scratch
|
|
44
|
+
- A report missing a field this skill reads names the CLI version as the cause and reports that section as unread. Neither an absent key nor a hand-rolled substitute for it may be reported as a finding, since the first reads as a clean target and the second reaches a verdict only the field's attribution can make
|
|
41
45
|
|
|
42
46
|
## Out of scope
|
|
43
47
|
|
|
@@ -22,23 +22,28 @@ Load a domain doc with `aitk docs <topic>` only when the intent touches that dom
|
|
|
22
22
|
|
|
23
23
|
Run `aitk sync --check . --json` before routing. It reports what a target is behind on across every surface, so the intent comes from the project state rather than from the user having to know it already. Skip only when the user named a single operation to run.
|
|
24
24
|
|
|
25
|
-
Read
|
|
25
|
+
Read seven fields off the report and carry each to `## Route`:
|
|
26
26
|
|
|
27
27
|
- `unmigrated`: a domain sitting at the root layout with nothing under `.claude/`. The most urgent finding, because that domain reports no drift of its own while being entirely behind
|
|
28
28
|
- `superseded`: a file a newer seed folder replaced. Report it and stop. No command moves it, since the content is the project's own
|
|
29
29
|
- `seeds`: entries are `matching`, `stale`, `drifted`, or `missing`. Anything but `matching` needs the seed handoff
|
|
30
30
|
- `domains[].entries`: per-file `stale`, `customized`, `stranded`, and `orphaned` as before
|
|
31
|
-
- `
|
|
31
|
+
- `reverse`: what the target holds that no live catalog claims. `unclaimed` lists folders at roots the toolkit stopped shipping, each with an `attribution` of `dropped`, `unattributed`, or `project`. Act on the first two and leave `project` alone, which history proved the project owns. `migrations` names a proposal-only skill with a live case here and the `reason` it was measured from
|
|
32
|
+
- `historyUnavailable` on a domain, on `seeds`, or on `reverse`: nothing could be dated, so treat every difference as unverified and say so rather than reporting a file as untouched. It is set on `reverse` when the toolkit itself ships without history, which is the registry-install case, so the walk found nothing rather than finding a clean target
|
|
32
33
|
- `tooling`: read `measured` first. Every count under it is zero when it is false, which is an absence of measurement rather than a measured zero. Past that, `chain` names the stacks the install resolved, nearest first, and `counts.gitignore` counts the managed ignore entries the target is missing.
|
|
33
34
|
|
|
34
35
|
State what the report found in one line per finding before acting on any of it.
|
|
35
36
|
|
|
37
|
+
A `reverse` key the report does not carry at all is a CLI predating the field rather than a target with nothing unclaimed. Say the walk did not run and name the CLI version as the cause. Reading the absent key as an empty answer reports a clean target to a project nobody has looked at, and answering it from a filesystem walk of your own is worse, since that reaches a verdict the attribution the field carries is the only thing entitled to make.
|
|
38
|
+
|
|
36
39
|
## Route
|
|
37
40
|
|
|
38
41
|
Map the stated intent, or what `## Diagnose` found, to one lifecycle phase, then act:
|
|
39
42
|
|
|
40
43
|
- A domain in `unmigrated`: hand off to `migration-standards`
|
|
44
|
+
- An entry in `migrations`: hand off to the skill its `skill` field names, spelled as the report spells it. Both of them propose without writing, so the handoff is where this stops
|
|
41
45
|
- Anything in `superseded`: tell the user which files and what replaced them. Do not move or delete them
|
|
46
|
+
- A folder in `unclaimed`: name it and the attribution it carries. No command moves it and the content may be the project's own, so the decision is the user's
|
|
42
47
|
|
|
43
48
|
- First-time scaffold of a fresh project: hand off to `setup-init`
|
|
44
49
|
- Governance rules for the project stack: hand off to `setup-gov`
|
|
@@ -210,6 +210,12 @@ code change. Scoping to those roots is what keeps the walk useful: walking the
|
|
|
210
210
|
whole tree reports every project folder as unclaimed, which is true and says
|
|
211
211
|
nothing.
|
|
212
212
|
|
|
213
|
+
The managed gate above applies here too, and it is the one place it surprises.
|
|
214
|
+
A directory holding a dropped folder and nothing else reports an empty `reverse`
|
|
215
|
+
rather than the folder, because it carries none of the three markers. Read an
|
|
216
|
+
empty section on an unmanaged target as a walk that never ran rather than as a
|
|
217
|
+
clean result.
|
|
218
|
+
|
|
213
219
|
Each entry carries `rel`, a file count, and an `attribution` of `dropped`,
|
|
214
220
|
`project`, or `unattributed`. A dropped folder and one the project wrote are the
|
|
215
221
|
same bytes at the same path, so the verdict is traced from history rather than
|
package/package.json
CHANGED
|
@@ -99,6 +99,67 @@ stage_toolkit_markdown() {
|
|
|
99
99
|
done < <(find "$src" -maxdepth 1 -type f -name "*.md" ! -name "index.md" | sort | head -n "$count")
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
# The newest top-level path history records a deletion under that the toolkit no
|
|
103
|
+
# longer ships. Read from history rather than hardcoded, so an arm stages a root
|
|
104
|
+
# the walk will actually recognize instead of a name that has since come back.
|
|
105
|
+
# `prompts` is preferred because it is the case measured in a real target, and
|
|
106
|
+
# any other dropped root exercises the same walk.
|
|
107
|
+
pick_dropped_root() {
|
|
108
|
+
local preferred="prompts"
|
|
109
|
+
local first=""
|
|
110
|
+
local candidate
|
|
111
|
+
|
|
112
|
+
while IFS= read -r candidate; do
|
|
113
|
+
[ -e "$PROJECT_ROOT/$candidate" ] && continue
|
|
114
|
+
[ "$candidate" = "$preferred" ] && {
|
|
115
|
+
echo "$preferred"
|
|
116
|
+
return 0
|
|
117
|
+
}
|
|
118
|
+
[ -n "$first" ] || first="$candidate"
|
|
119
|
+
done < <(git -C "$PROJECT_ROOT" log --all --diff-filter=D --name-only --format= |
|
|
120
|
+
awk -F/ 'NF > 1 { print $1 }' | sort -u)
|
|
121
|
+
|
|
122
|
+
echo "$first"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Restores one file's exact published bytes from the commit before it was
|
|
126
|
+
# deleted. Content is what the attribution matches on, so a file written by hand
|
|
127
|
+
# would report unattributed and an arm would assert the wrong verdict.
|
|
128
|
+
#
|
|
129
|
+
# Both reads take the whole listing through a process substitution rather than a
|
|
130
|
+
# pipeline ending in an early exit. `set -o pipefail` is on, and a `grep -m 1`
|
|
131
|
+
# that matches the first line closes the pipe while git is still writing, so the
|
|
132
|
+
# substitution returns git's SIGPIPE status and the arm fails on a listing it
|
|
133
|
+
# actually read.
|
|
134
|
+
restore_dropped_file() {
|
|
135
|
+
local root="$1"
|
|
136
|
+
local rel="" commit="" line
|
|
137
|
+
|
|
138
|
+
while IFS= read -r line; do
|
|
139
|
+
case "$line" in
|
|
140
|
+
"$root"/*)
|
|
141
|
+
rel="$line"
|
|
142
|
+
break
|
|
143
|
+
;;
|
|
144
|
+
esac
|
|
145
|
+
done < <(git -C "$PROJECT_ROOT" log --all --diff-filter=D --name-only \
|
|
146
|
+
--format= -- "$root/")
|
|
147
|
+
|
|
148
|
+
[ -n "$rel" ] || return 1
|
|
149
|
+
|
|
150
|
+
while IFS= read -r line; do
|
|
151
|
+
commit="$line"
|
|
152
|
+
break
|
|
153
|
+
done < <(git -C "$PROJECT_ROOT" log --all --diff-filter=D --format=%H -- "$rel")
|
|
154
|
+
|
|
155
|
+
[ -n "$commit" ] || return 1
|
|
156
|
+
|
|
157
|
+
mkdir -p "$(dirname "$rel")"
|
|
158
|
+
git -C "$PROJECT_ROOT" show "$commit^:$rel" >"$rel" || return 1
|
|
159
|
+
|
|
160
|
+
echo "$rel"
|
|
161
|
+
}
|
|
162
|
+
|
|
102
163
|
# Stages one step of a scenario arm into the sandbox working directory.
|
|
103
164
|
# Scenarios call this once per step so their own git operations stay between
|
|
104
165
|
# the steps, where they are visible.
|
package/tooling/web/reference.md
CHANGED
|
@@ -12,7 +12,7 @@ Golden config files live in `tooling/web/configs/` and are copied into the targe
|
|
|
12
12
|
|
|
13
13
|
- `eslint.config.js`: flat config with `@eslint/js`, `typescript-eslint`, React hooks, import sort, check-file, vitest rules scoped to test files, `eslint-config-prettier` last.
|
|
14
14
|
- `src/test/setup.ts`: `@testing-library/jest-dom` import, `cleanup` after each test.
|
|
15
|
-
- `e2e/screenshot.ts`: `
|
|
15
|
+
- `e2e/screenshot.ts`: capture template. `ROUTES` and `STATES` consts at the top carry one route in a default and a dark state, and the loop below them writes `screenshots/<name>-<state>.png`. Per-project routes and states extend the two consts.
|
|
16
16
|
- `.vscode/extensions.json` and `.vscode/settings.json`: editor wiring for ESLint, Tailwind, Playwright, Vitest.
|
|
17
17
|
- `.github/workflows/verify.yml`: `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests` jobs.
|
|
18
18
|
- `scripts/verify.sh`: extends base verify with typecheck, lint, unit tests, and build in the full order.
|
|
@@ -90,6 +90,8 @@ Append rows:
|
|
|
90
90
|
| `bun run test:e2e` | Run Playwright E2E tests. |
|
|
91
91
|
| `bun run screenshot` | Build, preview, then capture screenshots. |
|
|
92
92
|
|
|
93
|
+
`aitk tooling verify <stack>` is the only automated caller of `bun run screenshot`, running it for any stack whose `package.json` declares the script and asserting that PNG files land under `screenshots/`. No ship chain captures a screenshot, so the output path the seed writes is a contract that one verifier reads rather than a default a ship step depends on.
|
|
94
|
+
|
|
93
95
|
## Verify script
|
|
94
96
|
|
|
95
97
|
The web layer's `scripts/verify.sh` replaces the base version. Order: typecheck, lint, format, spelling, shell, unit tests, build. Stack adapters may override if their typecheck or build differs.
|