pi-anchorloop 2.6.0 → 2.8.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/README.md +3 -3
- package/README.zh-TW.md +3 -3
- package/package.json +1 -1
- package/pi/book.ts +46 -5
- package/pi/support/book.ts +75 -4
- package/skills/agent-terse/SKILL.md +1 -1
- package/skills/anchorloop/PRINCIPLES.md +17 -14
- package/skills/anchorloop/SKILL.md +20 -10
- package/skills/anchorloop/playbooks/autonomous-run.md +7 -6
- package/skills/anchorloop/playbooks/pause.md +3 -3
- package/skills/anchorloop/playbooks/pickup.md +2 -2
- package/skills/answering/SKILL.md +3 -1
- package/skills/answering/playbooks/explain.md +2 -1
- package/skills/coding/MINI-SDD.md +1 -1
- package/skills/coding/SKILL.md +7 -2
- package/skills/coding/playbooks/bug-fix.md +8 -7
- package/skills/coding/playbooks/feature.md +7 -5
- package/skills/coding/playbooks/perf.md +6 -6
- package/skills/coding/playbooks/refactoring.md +4 -4
- package/skills/coding/references/benchmark-checklist.md +21 -0
- package/skills/coding/references/design-red-flags.md +18 -0
- package/skills/human-feedback/SKILL.md +1 -1
- package/skills/inspecting/SKILL.md +1 -1
- package/skills/inspecting/playbooks/diff-review.md +6 -0
- package/skills/investigating/SKILL.md +7 -5
- package/skills/investigating/playbooks/diagnose.md +1 -1
- package/skills/investigating/playbooks/research.md +4 -3
- package/skills/solid-loop/SKILL.md +3 -3
- package/skills/solid-loop/playbooks/apply-friction.md +2 -2
- package/skills/solid-loop/playbooks/author-skill.md +3 -2
- package/skills/writing/SKILL.md +2 -1
- package/skills/writing/playbooks/comments.md +6 -4
- package/skills/writing/playbooks/draft.md +3 -2
- package/skills/writing/playbooks/pr-description.md +15 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ anchorloop core loop · principles · playbooks: autonomous-run, paus
|
|
|
12
12
|
├─ investigating research · diagnose
|
|
13
13
|
├─ inspecting diff-review · qa-release
|
|
14
14
|
├─ coding bug-fix · feature · refactoring · perf · prototype (+ Mini SDD)
|
|
15
|
-
├─ writing draft · tighten · comments
|
|
15
|
+
├─ writing draft · tighten · comments · pr-description
|
|
16
16
|
└─ solid-loop apply-friction · author-skill · bootstrap
|
|
17
17
|
shared grilling · domain-modeling · human-feedback · agent-terse
|
|
18
18
|
```
|
|
@@ -25,7 +25,7 @@ shared grilling · domain-modeling · human-feedback · agent-terse
|
|
|
25
25
|
|
|
26
26
|
| File | What it does |
|
|
27
27
|
| --- | --- |
|
|
28
|
-
| `pi/book.ts` | The loop book. The first `todo` create opens an `inline` loop (intent from the first todo's subject, anchor from a `Reality anchor:` line or the todo's `metadata.anchor`), and a `kind` call opens or changes one; task records need the `todo` tool of [`@juicesharp/rpiv-todo`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo#readme) (its `tool_result` details `{tasks, nextId}` and `rpiv-todo-state` entries). The agent declares only what the extension cannot observe with `anchorloop_stage`: `kind` (to choose `quick`, `reviewed`, or `durable`, with an intent and the anchor command; changing a kind the agent chose takes a `reason`), `verify` (a check not run in bash), `fresh-read`, `friction` (`tried`, `found`, `led_by`), `reflect`, `skip`, `back`, `close`, and the query `read`. Everything else is read from evidence: production edits (a write or edit in any git repo, outside its `scratch/` and `docs/specs/`; a linked child's edits and a successful `git merge`, `cherry-pick`, or `pull` count too), the exit code of the bash call that ran the anchor command (an anchor that passed, failed, and passed again records its own friction entry, already reflected as `resolved`: the rerun command and the failed run's key line, at most 120 characters and never a stack trace; the agent is told nothing), reviewer `Blocking: P0=<n> P1=<m>` counts, summaries of `docs/specs/*/` artifacts as they are edited, and a returned subagent that Jev judges to have been a fresh-context read of the spec. A phase machine over that evidence gives each kind a fixed sequence (`quick` act → check; `inline` anchor → act → verify; `reviewed` adds review; `durable` adds decide → grill → spec → read → approve → design; every kind ends with reflect → close), and `read` shows `<kind> · phase <current> ✓ → <next> (missing: …) · skipped: …`. A widget below the editor shows `⚓ <kind> · <current> ✓ → <next>`, with `· N friction` while friction waits for a `reflect`, after every tool call, on `session_start`, and when a `Reality anchor:` line is stated, and clears when the loop closes. An anchor run or declared verify of a `quick` or `inline` loop also measures the diff's reach: source files (not tests, lockfiles, specs, or prose), the top-level directories they sit in, and a README, changelog, or `*.schema.json` changed beside them. Files already changed when a repo joined the loop count only once their content changes, and a file at a repository root counts as a file, not a directory. At 3 source files, 2 directories, or one such file, the result carries one line asking to re-classify, and verify waits for a `kind` call with `reason` that answers each threshold crossed; a later threshold asks again. A phase that starts before an earlier one is complete warns once in one line; phases regress when evidence changes or on `back`. The book also records each todo with its `anchor`, `ref` (`<path>#<heading>`, resolved to line ranges), and `followup` metadata. One YAML book per open loop lives under `~/.pi/agent/anchorloop/books/` (`ANCHORLOOP_BOOKS_DIR` overrides it; empty project and `agents/` directories are removed), subagent books under `agents/` (a child that closes keeps its book for the main session); `session_start` sweeps books whose session is gone or that have not changed in 7 days. `close` answers `closed (landed). Clear the todo list.`, adding only the phases not shown complete and the unreflected friction, and never refuses over phases or friction, only while a pending or in-progress todo lacks `metadata.followup` (a ticket id, `memory`, or `drop — <reason>`). |
|
|
28
|
+
| `pi/book.ts` | The loop book. The first `todo` create opens an `inline` loop (intent from the first todo's subject, anchor from a `Reality anchor:` line or the todo's `metadata.anchor`), and a `kind` call opens or changes one; task records need the `todo` tool of [`@juicesharp/rpiv-todo`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo#readme) (its `tool_result` details `{tasks, nextId}` and `rpiv-todo-state` entries). The agent declares only what the extension cannot observe with `anchorloop_stage`: `kind` (to choose `quick`, `reviewed`, or `durable`, with an intent and the anchor command; changing a kind the agent chose takes a `reason`), `verify` (a check not run in bash), `fresh-read`, `friction` (`tried`, `found`, `led_by`), `reflect`, `skip`, `back`, `close`, and the query `read`. Everything else is read from evidence: production edits (a write or edit in any git repo, outside its `scratch/` and `docs/specs/`; a linked child's edits and a successful `git merge`, `cherry-pick`, or `pull` count too), the exit code of the bash call that ran the anchor command (an anchor that passed, failed, and passed again records its own friction entry, already reflected as `resolved`: the rerun command and the failed run's key line, at most 120 characters and never a stack trace; the agent is told nothing), reviewer `Blocking: P0=<n> P1=<m>` counts, summaries of `docs/specs/*/` artifacts as they are edited, and a returned subagent that Jev judges to have been a fresh-context read of the spec. A phase machine over that evidence gives each kind a fixed sequence (`quick` act → check; `inline` anchor → act → verify; `reviewed` adds review; `durable` adds decide → grill → spec → read → approve → design; every kind ends with reflect → close), and `read` shows `<kind> · phase <current> ✓ → <next> (missing: …) · skipped: …`. A widget below the editor shows `⚓ <kind> · <current> ✓ → <next>`, with `· N friction` while friction waits for a `reflect`, after every tool call, on `session_start`, and when a `Reality anchor:` line is stated, and clears when the loop closes. An anchor run or declared verify of a `quick` or `inline` loop also measures the diff's reach: source files (not tests, lockfiles, specs, or prose), the top-level directories they sit in, and a README, changelog, or `*.schema.json` changed beside them. Files already changed when a repo joined the loop count only once their content changes, and a file at a repository root counts as a file, not a directory. At 3 source files, 2 directories, or one such file, the result carries one line asking to re-classify, and verify waits for a `kind` call with `reason` that answers each threshold crossed; a later threshold asks again. A phase that starts before an earlier one is complete warns once in one line; phases regress when evidence changes or on `back`. The book also records each todo with its `anchor`, `ref` (`<path>#<heading>`, resolved to line ranges), and `followup` metadata. One YAML book per open loop lives under `~/.pi/agent/anchorloop/books/` (`ANCHORLOOP_BOOKS_DIR` overrides it; empty project and `agents/` directories are removed), subagent books under `agents/` (a child that closes keeps its book for the main session). A child is linked only through [pi-herdr-agents](https://github.com/wayne930242/pi-herdr-agents) (`PI_SUBAGENT_ID` in the child, `details.id` on the parent's `subagent` result; pi itself has no subagents): a linked child's edits are the parent's act, and its anchor runs, recorded as `check`, carry the working-state tree of each repo it works in (tracked and untracked files, ignored files and `scratch/` left out). When a parent's `git merge`, `cherry-pick` or `pull` succeeds, or a subagent result returns, and the parent's working-state trees are exactly the trees of a child's latest run of the same anchor (a leading `cd` into a repo root aside), and that run passed, the parent records it as its own verify (`adopted`): a fast-forward of a worker's branch, or a child that worked in the parent's checkout, needs no second run, while a merge onto a base that moved, a parent edit or repo the child never saw, or a file the child ran with but did not commit does; `session_start` sweeps books whose session is gone or that have not changed in 7 days. `close` answers `closed (landed). Clear the todo list.`, adding only the phases not shown complete and the unreflected friction, and never refuses over phases or friction, only while a pending or in-progress todo lacks `metadata.followup` (a ticket id, `memory`, or `drop — <reason>`). |
|
|
29
29
|
| `pi/anchor-gate.ts` | Inside an open loop, appends one warning line to the edit's tool result (where the agent reads it) when `write` or `edit` starts the `act` phase while an earlier phase of the loop kind is incomplete: no anchor (`anchor` on the `kind` call, a `Reality anchor:` line, or a skip), and in a `durable` loop a missing decision, spec, fresh read, approval, or design, read from the `docs/specs/<folder>/` files (found from the book, the intent, or a todo `ref`). It warns again only when a new phase goes missing; the call still goes through. Outside a loop and in `quick` loops it stays silent. `.md`, `.txt`, and `.html` files, `scratch/`, `docs/specs/`, and temp files outside the project pass silently. Edits made through `bash` are not checked. |
|
|
30
30
|
| `pi/decision-tool.ts` | The `anchorloop_decision` tool appends single-line, spreadsheet-safe rows to a decision trail TSV for forks, pivots, and blockers (completed units come from `git log`), or a `start` row when a run picks up another run's trail. |
|
|
31
31
|
| `pi/second-thought.ts` | Inside an open loop, asks Jev (TypeSafe's typed-decision model, through pi's classifier registry) to check the phase machine when a run settles and the loop book gained an entry since the last judgment, and at a `close` declaration. The program computes the next phase from the book; Jev sees the kind, intent, anchor, diff summary (≤1200 chars), `phase` (current, next, missing), verify state, the open todos by id and subject, the task list, and friction (a child's under its name), and judges only whether to `advance`, go `back`, or `ask-user`, plus `done`, the review tier still needed, and quality; phase completion comes from the program's evidence alone. The advisory is `next: <phase> (<missing>)` plus Jev's concerns, with no scores. It is sent only when Jev has a concern, todos are open without a followup, or the run continues, and stays silent when Jev agrees with nothing to add (the verdict is still recorded in the session); at close it carries concerns only. Away from close it also names the loop's open todos that have no valid `metadata.followup` (the first three, subjects cut to 60 characters, then `+N more`) and asks the agent to continue each, complete it, or set that followup. The run continues once, when Jev agrees to advance and the next phase is a verify, review, or fix, or when such todos are open and Jev's move is not `ask-user` (then the advisory tells the agent to ask the user instead); an advisory with the same next phase, concerns, and open todo ids as the last one is not repeated, and a `full` rating after a clean review that follows the last change is not a concern. A run that called `MonitorCreate`, `LoopCreate`, `goal_wait`, or a `subagent` tool is waiting and is not judged. Without a TypeSafe key it does nothing, and outside a loop it never runs. In a subagent session (`PI_SUBAGENT_ID` from pi-herdr-agents, or `PI_SUBAGENT_CHILD` from pi-subagents) it registers nothing, since the agent that spawned it judges the result. |
|
|
@@ -55,7 +55,7 @@ uv run --with pytest pytest -q # validators and the pi extensions (need
|
|
|
55
55
|
|
|
56
56
|
## Acknowledgments
|
|
57
57
|
|
|
58
|
-
- [pstack](https://github.com/backnotprop/pstack) by Lauren Tan (MIT), mirror revision `e44668c` of [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack), and its port [pstack-claude](https://github.com/michael-denyer/pstack-claude) by Michael Denyer (MIT): task-type playbooks, named principles, the lifecycle playbooks, the decision trail, the closed review gate, fresh-subagent hand-off, and evidence grades.
|
|
58
|
+
- [pstack](https://github.com/backnotprop/pstack) by Lauren Tan (MIT), mirror revision `e44668c` of [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack) (the 2.8.0 engineering-standard additions from cursor/plugins `c742dd6`), and its port [pstack-claude](https://github.com/michael-denyer/pstack-claude) by Michael Denyer (MIT): task-type playbooks, named principles, the lifecycle playbooks, the decision trail, the closed review gate, fresh-subagent hand-off, and evidence grades.
|
|
59
59
|
- [google-research/harness2](https://github.com/google-research/harness2) (Apache-2.0), revision `1cfe254`: solid-loop's placement test, cheapest-mechanism order, and declining a lesson without a before/after contrast.
|
|
60
60
|
- [mattpocock/skills](https://github.com/mattpocock/skills) (MIT): grilling, domain-modeling, the diff review, the prototype playbook, and the feature playbook's interface checks.
|
|
61
61
|
- [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman) (Apache-2.0), revision `bad48a0`: the terse voice in `agent-terse`.
|
package/README.zh-TW.md
CHANGED
|
@@ -12,7 +12,7 @@ anchorloop 核心循環 · 原則 · playbook:autonomous-run、paus
|
|
|
12
12
|
├─ investigating research · diagnose
|
|
13
13
|
├─ inspecting diff-review · qa-release
|
|
14
14
|
├─ coding bug-fix · feature · refactoring · perf · prototype(+ Mini SDD)
|
|
15
|
-
├─ writing draft · tighten · comments
|
|
15
|
+
├─ writing draft · tighten · comments · pr-description
|
|
16
16
|
└─ solid-loop apply-friction · author-skill · bootstrap
|
|
17
17
|
共用 grilling · domain-modeling · human-feedback · agent-terse
|
|
18
18
|
```
|
|
@@ -25,7 +25,7 @@ anchorloop 核心循環 · 原則 · playbook:autonomous-run、paus
|
|
|
25
25
|
|
|
26
26
|
| 檔案 | 作用 |
|
|
27
27
|
| --- | --- |
|
|
28
|
-
| `pi/book.ts` | Loop book。第一次 `todo` create 會以 `inline` 開啟 loop(intent 取第一個 todo 的標題,anchor 取 `Reality anchor:` 這一行或該 todo 的 `metadata.anchor`),`kind` 呼叫也能開啟或更改 loop;任務紀錄需要 [`@juicesharp/rpiv-todo`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo#readme) 的 `todo` 工具(它的 `tool_result` details `{tasks, nextId}` 和 `rpiv-todo-state` 條目)。agent 只用 `anchorloop_stage` 宣告 extension 看不到的事:`kind`(用來選 `quick`、`reviewed` 或 `durable`,附 intent 和 anchor 指令;改掉 agent 自己選的種類時,必須附 `reason`)、`verify`(不是指令的檢查)、`fresh-read`、`friction`(`tried`、`found`、`led_by`)、`reflect`、`skip`、`back`、`close`,以及查詢用的 `read`。其餘都從證據讀出:production 的修改(任何 git repo 內、`scratch/` 與 `docs/specs/` 以外的 write 或 edit;已連結 child 的修改,以及成功的 `git merge`、`cherry-pick`、`pull` 也算)、執行過 anchor 指令的那次 bash 的 exit code(anchor 通過後失敗、又再通過時,extension 會自己記一筆 friction,並直接 reflect 為 `resolved`:重跑的指令,加上失敗那次最關鍵的一行輸出,最多 120 字元,不放 stack trace;不會通知 agent)、reviewer 的 `Blocking: P0=<n> P1=<m>` 數字、`docs/specs/*/` 產出物每次編輯後的摘要,以及 Jev 判定為「全新 context 讀過 spec」的 subagent 回報。階段機依這些證據給每種 loop 固定的階段順序(`quick` 為 act → check;`inline` 為 anchor → act → verify;`reviewed` 加 review;`durable` 再加 decide → grill → spec → read → approve → design;每一種都以 reflect → close 結尾),`read` 顯示 `<種類> · phase <目前> ✓ → <下一個>(缺:…)· 已跳過:…`。編輯器下方的 widget 會顯示 `⚓ <種類> · <目前> ✓ → <下一個>`,還有 friction 等著 `reflect` 時附 `· N friction`;每次工具呼叫後、`session_start` 時,以及 agent 寫出 `Reality anchor:` 這一行時更新,loop 結案後清掉。`quick` 或 `inline` loop 跑 anchor 或宣告 verify 時,也會量 diff 的影響範圍:原始碼檔案(不含測試、lockfile、spec 與文字檔)、它們所在的頂層目錄,以及跟原始碼一起改的 README、changelog 或 `*.schema.json`。repo 加入 loop 時就已經改過的檔案,要等內容再變動才算;repo 根目錄的檔案只算檔案數,不算一個目錄。達到 3 個原始碼檔案、2 個目錄或 1 個這類檔案時,結果會附一行請 agent 重新分類;verify 要等到以 `reason` 呼叫 `kind`、回應每一個跨過的門檻才算完成,之後再跨過新的門檻會再問一次。前一個階段還沒完成就開始下一個階段,會用一行警告一次;證據改變或用 `back` 時階段會退回。book 也記錄每個 todo 的 `anchor`、`ref`(`<path>#<heading>`,解析成行號範圍)和 `followup` metadata。每個開啟中的 loop 有一份 YAML book,放在 `~/.pi/agent/anchorloop/books/`(可用 `ANCHORLOOP_BOOKS_DIR` 覆寫),subagent 的 book 放在 `agents/`(subagent 自己 close 時 book 留給主 session
|
|
28
|
+
| `pi/book.ts` | Loop book。第一次 `todo` create 會以 `inline` 開啟 loop(intent 取第一個 todo 的標題,anchor 取 `Reality anchor:` 這一行或該 todo 的 `metadata.anchor`),`kind` 呼叫也能開啟或更改 loop;任務紀錄需要 [`@juicesharp/rpiv-todo`](https://github.com/juicesharp/rpiv-mono/tree/main/packages/rpiv-todo#readme) 的 `todo` 工具(它的 `tool_result` details `{tasks, nextId}` 和 `rpiv-todo-state` 條目)。agent 只用 `anchorloop_stage` 宣告 extension 看不到的事:`kind`(用來選 `quick`、`reviewed` 或 `durable`,附 intent 和 anchor 指令;改掉 agent 自己選的種類時,必須附 `reason`)、`verify`(不是指令的檢查)、`fresh-read`、`friction`(`tried`、`found`、`led_by`)、`reflect`、`skip`、`back`、`close`,以及查詢用的 `read`。其餘都從證據讀出:production 的修改(任何 git repo 內、`scratch/` 與 `docs/specs/` 以外的 write 或 edit;已連結 child 的修改,以及成功的 `git merge`、`cherry-pick`、`pull` 也算)、執行過 anchor 指令的那次 bash 的 exit code(anchor 通過後失敗、又再通過時,extension 會自己記一筆 friction,並直接 reflect 為 `resolved`:重跑的指令,加上失敗那次最關鍵的一行輸出,最多 120 字元,不放 stack trace;不會通知 agent)、reviewer 的 `Blocking: P0=<n> P1=<m>` 數字、`docs/specs/*/` 產出物每次編輯後的摘要,以及 Jev 判定為「全新 context 讀過 spec」的 subagent 回報。階段機依這些證據給每種 loop 固定的階段順序(`quick` 為 act → check;`inline` 為 anchor → act → verify;`reviewed` 加 review;`durable` 再加 decide → grill → spec → read → approve → design;每一種都以 reflect → close 結尾),`read` 顯示 `<種類> · phase <目前> ✓ → <下一個>(缺:…)· 已跳過:…`。編輯器下方的 widget 會顯示 `⚓ <種類> · <目前> ✓ → <下一個>`,還有 friction 等著 `reflect` 時附 `· N friction`;每次工具呼叫後、`session_start` 時,以及 agent 寫出 `Reality anchor:` 這一行時更新,loop 結案後清掉。`quick` 或 `inline` loop 跑 anchor 或宣告 verify 時,也會量 diff 的影響範圍:原始碼檔案(不含測試、lockfile、spec 與文字檔)、它們所在的頂層目錄,以及跟原始碼一起改的 README、changelog 或 `*.schema.json`。repo 加入 loop 時就已經改過的檔案,要等內容再變動才算;repo 根目錄的檔案只算檔案數,不算一個目錄。達到 3 個原始碼檔案、2 個目錄或 1 個這類檔案時,結果會附一行請 agent 重新分類;verify 要等到以 `reason` 呼叫 `kind`、回應每一個跨過的門檻才算完成,之後再跨過新的門檻會再問一次。前一個階段還沒完成就開始下一個階段,會用一行警告一次;證據改變或用 `back` 時階段會退回。book 也記錄每個 todo 的 `anchor`、`ref`(`<path>#<heading>`,解析成行號範圍)和 `followup` metadata。每個開啟中的 loop 有一份 YAML book,放在 `~/.pi/agent/anchorloop/books/`(可用 `ANCHORLOOP_BOOKS_DIR` 覆寫),subagent 的 book 放在 `agents/`(subagent 自己 close 時 book 留給主 session)。子代理只透過 [pi-herdr-agents](https://github.com/wayne930242/pi-herdr-agents) 關聯(子行程的 `PI_SUBAGENT_ID`、父 session `subagent` 結果的 `details.id`;pi 本身沒有 subagent):關聯的子代理,其改動算父 loop 的 act;其 anchor 執行記為 `check`,並附上它所在各 repo 的工作狀態 tree(含已追蹤與未追蹤檔案,不含 ignored 檔案與 `scratch/`)。父 session 的 `git merge`、`cherry-pick`、`pull` 成功時,或收到子代理結果時,若父 session 的工作狀態 tree 正好等於子代理最近一次同一 anchor 執行(忽略開頭切到 repo 根目錄的 `cd`)的 tree,且那次通過,就把它記為父 loop 自己的 verify(`adopted`):fast-forward 合入 worker 分支、或子代理直接在父 checkout 裡工作,都不必再跑一次;合到已前進的 base、父 session 有子代理沒看過的改動或 repo、或子代理跑測試時有沒 commit 的檔案,則要自己跑;`session_start` 會清掉 session 已不存在或 7 天沒有更新的 book。`close` 回覆 `closed (landed). Clear the todo list.`,只多列沒有完成的階段和還沒 reflect 的 friction;它不會因為階段或 friction 而拒絕,只在還有 pending 或 in-progress 的 todo 沒有 `metadata.followup`(票號、`memory` 或 `drop — <原因>`)時拒絕。 |
|
|
29
29
|
| `pi/anchor-gate.ts` | 只在開啟的 loop 內:`write` 或 `edit` 開始 `act` 階段、而這種 loop 前面的階段還沒完成時,把一行警告附在該次編輯的 tool result 後面(agent 在那裡讀到它):沒有 anchor(kind 呼叫的 `anchor`、`Reality anchor:` 這一行,或已跳過),`durable` loop 則還缺決策、spec、全新 context 的閱讀、核准或設計(從 `docs/specs/<資料夾>/` 的檔案判斷,資料夾由 book、intent 或 todo 的 `ref` 找出)。只有新缺了一個階段時才會再警告;呼叫仍會放行。沒有 loop 或是 `quick` loop 時保持安靜。`.md`、`.txt`、`.html` 檔、`scratch/`、`docs/specs/` 和專案外的暫存檔不會觸發。透過 `bash` 做的修改不檢查。 |
|
|
30
30
|
| `pi/decision-tool.ts` | `anchorloop_decision` 工具把一筆決策寫進 TSV 決策軌跡(記岔路、轉向與卡點;完成的工作單元看 `git log`),每筆只佔一行,用試算表開啟也安全;接手別人的軌跡時寫一筆 `start`。 |
|
|
31
31
|
| `pi/second-thought.ts` | 只在開啟的 loop 內:一次執行結束且 book 自上次判斷後多了條目時,以及宣告 `close` 時,透過 pi 的 classifier registry 請 Jev(TypeSafe 的型別化決策模型)複核階段機。下一個階段由程式從 book 算出;Jev 看到種類、intent、anchor、diff 摘要(≤1200 字元)、`phase`(目前、下一個、缺什麼)、verify 狀態、未完成 todo(id 與標題)、任務清單和 friction(子 agent 的以它的名字列出),只判斷要 `advance`、退回(`back`)還是 `ask-user`,另外還問 `done`、還需要哪一級 review 與品質;階段是否完成只由程式依證據判定。提醒是 `next: <階段>(<缺什麼>)` 加上 Jev 的疑慮,不附分數;只在 Jev 有疑慮、有 todo 未完成而沒有 followup、或這次會讓 agent 多跑一輪時才送出,Jev 同意且沒有補充時保持安靜(判斷結果仍記在 session 裡);結案時只附疑慮。離開 close 時,提醒也會點名 loop 中還沒有有效 `metadata.followup` 的未完成 todo(前三個,標題截成 60 字元,其餘以 `+N more` 帶過),請 agent 逐一繼續、完成,或設定該 followup。Jev 同意前進、而下一個階段是 verify、review 或 fix,或有這類 todo 未完成且 Jev 的判斷不是 `ask-user`(此時提醒改請 agent 去問使用者)時,才讓 agent 多跑一輪;下一個階段、疑慮和未完成 todo 的 id 都與上一則相同的提醒不重複;最後一次修改之後已有無 blocking 發現的 review 時,`full` 評等不算疑慮。呼叫過 `MonitorCreate`、`LoopCreate`、`goal_wait` 或 `subagent` 工具的執行在等待中,不被判斷。沒有 TypeSafe key 時什麼都不做,沒有 loop 時不會執行。subagent session(pi-herdr-agents 的 `PI_SUBAGENT_ID`,或 pi-subagents 的 `PI_SUBAGENT_CHILD`)不註冊任何東西,因為由派它的 agent 判斷結果。 |
|
|
@@ -55,7 +55,7 @@ uv run --with pytest pytest -q # 驗證器與 pi extension 的測試(
|
|
|
55
55
|
|
|
56
56
|
## 致謝
|
|
57
57
|
|
|
58
|
-
- Lauren Tan 的 [pstack](https://github.com/backnotprop/pstack)(MIT),鏡像 repo 的版本 `e44668c`,上游是 [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack)
|
|
58
|
+
- Lauren Tan 的 [pstack](https://github.com/backnotprop/pstack)(MIT),鏡像 repo 的版本 `e44668c`,上游是 [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack)(2.8.0 的工程標準補充取自 cursor/plugins `c742dd6`);以及 Michael Denyer 的移植版 [pstack-claude](https://github.com/michael-denyer/pstack-claude)(MIT):依任務類型分的 playbook、具名原則、生命週期 playbook、決策軌跡、獨立審查前不放行的關卡、交接給新 subagent,以及證據分級。
|
|
59
59
|
- [google-research/harness2](https://github.com/google-research/harness2)(Apache-2.0),版本 `1cfe254`:solid-loop 的放置判斷、最便宜機制的順序,以及沒有前後對照就不寫成教訓。
|
|
60
60
|
- [mattpocock/skills](https://github.com/mattpocock/skills)(MIT):grilling、domain-modeling、diff review、prototype playbook,以及 feature playbook 的介面檢查。
|
|
61
61
|
- [JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman)(Apache-2.0),revision `bad48a0`:`agent-terse` 的精簡寫法。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-anchorloop",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Agent workflow skills for pi: one entry skill per task type, each with playbooks, over a shared Align → Anchor → Act → Verify loop, plus loop extensions (loop book, anchor gate, decision trail tool, Jev second thought, skill validator, stream rules).",
|
|
5
5
|
"author": "Wei Hung",
|
|
6
6
|
"license": "MIT",
|
package/pi/book.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
anchorCommand,
|
|
21
21
|
appendEntry,
|
|
22
22
|
artifactKind,
|
|
23
|
+
bases,
|
|
23
24
|
childId,
|
|
24
25
|
childIds,
|
|
25
26
|
childLines,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
openLoop,
|
|
37
38
|
replayTodos,
|
|
38
39
|
refsOf,
|
|
40
|
+
repoRootOf,
|
|
39
41
|
retryPairs,
|
|
40
42
|
resolveRef,
|
|
41
43
|
reviewTrend,
|
|
@@ -51,6 +53,8 @@ import {
|
|
|
51
53
|
touchRepoBeforeMerge,
|
|
52
54
|
validFollowup,
|
|
53
55
|
verifyAfterLastAct,
|
|
56
|
+
workingTrees,
|
|
57
|
+
adoptableRun,
|
|
54
58
|
} from "./support/book.ts";
|
|
55
59
|
import { classify } from "./support/jev.ts";
|
|
56
60
|
import { REVIEWLESS, SEQUENCES, computePhases, describe, incompleteBefore, outsideWork, reachLine, reachOf, unansweredReach } from "./support/phases.ts";
|
|
@@ -616,6 +620,38 @@ export default function (pi: ExtensionAPI) {
|
|
|
616
620
|
return reach && unansweredReach(book.entries, reach).length > 0 ? `anchorloop: ${reachLine(reach, currentKind(book.entries))}.` : undefined;
|
|
617
621
|
}
|
|
618
622
|
|
|
623
|
+
/** The repos the loop works in: the repos it changed and the one it runs in. */
|
|
624
|
+
function loopRepos(book: Book, cwd: string): string[] {
|
|
625
|
+
const here = repoRootOf(join(cwd, "_"));
|
|
626
|
+
return [...new Set([...bases(book.entries).map((base) => base.repo), ...(here ? [here] : [])])];
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function loopTrees(book: Book, cwd: string): string[] {
|
|
630
|
+
return workingTrees(loopRepos(book, cwd));
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** A child's anchor run carries the trees it ran on, so the coordinator can tell whether it holds that same state. */
|
|
634
|
+
function treesField(book: Book, cwd: string): { trees?: string[] } {
|
|
635
|
+
const trees = loopTrees(book, cwd);
|
|
636
|
+
return trees.length ? { trees } : {};
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Records a linked child's passing run of the loop anchor as this loop's verify when the loop now holds exactly the state
|
|
641
|
+
* that run checked (after a merge lands a worker's branch, or when a child that worked in this checkout returns), so the
|
|
642
|
+
* coordinator does not run the anchor a second time. Any other state, or another command, leaves verify to its own run.
|
|
643
|
+
*/
|
|
644
|
+
function adoptChildRun(book: Book, cwd: string): void {
|
|
645
|
+
const anchor = anchorCommand(book.entries);
|
|
646
|
+
if (!anchor || verifyAfterLastAct(book.entries) || !book.entries.some((entry) => entry.stage === "link")) return;
|
|
647
|
+
const repos = loopRepos(book, cwd);
|
|
648
|
+
const trees = workingTrees(repos);
|
|
649
|
+
const found = adoptableRun(book.entries, anchor, trees, repos, cwd);
|
|
650
|
+
if (!found) return;
|
|
651
|
+
const last = `adopted from ${found.name}${found.run.last ? `: ${String(found.run.last)}` : ""}`.slice(0, 200);
|
|
652
|
+
book.entries.push(appendEntry(book.path, "verify", { command: anchor.slice(0, 200), exit: 0, last, adopted: found.name, trees, ...reachField(book, cwd) }));
|
|
653
|
+
}
|
|
654
|
+
|
|
619
655
|
/**
|
|
620
656
|
* Records what a finished bash call shows: runs of the loop anchor, of task anchors, and a first commit as the change.
|
|
621
657
|
* Returns the re-classification line when an anchor run of an unreviewed loop measured a reach no `kind` answer covers.
|
|
@@ -631,9 +667,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
631
667
|
// A failed run keeps its key line, so a rerun that passes can name what failed without the whole output.
|
|
632
668
|
const keyOf = (code: unknown) => (typeof code === "number" && code !== 0 ? { key: keyLine(output) } : {});
|
|
633
669
|
if (anchor && anchorRun(command, anchor)) {
|
|
634
|
-
const
|
|
670
|
+
const child = childId() !== undefined;
|
|
671
|
+
const recorded = child || currentKind(book.entries) === "quick" ? "check" : "verify";
|
|
635
672
|
const code = anchorExit(command, anchor, exit);
|
|
636
|
-
const entry = appendEntry(book.path, recorded, { command: anchor.slice(0, 200), exit: code, last, ...keyOf(code), ...reachField(book, cwd) });
|
|
673
|
+
const entry = appendEntry(book.path, recorded, { command: anchor.slice(0, 200), exit: code, last, ...keyOf(code), ...reachField(book, cwd), ...(child ? treesField(book, cwd) : {}) });
|
|
637
674
|
book.entries.push(entry);
|
|
638
675
|
const reach = reachNotice(book, entry);
|
|
639
676
|
if (reach) notices.push(reach);
|
|
@@ -645,9 +682,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
645
682
|
}
|
|
646
683
|
autoFriction(book);
|
|
647
684
|
const merged = mergeRun(command);
|
|
648
|
-
if (exit === 0 && merged && !/Already up[ -]to[ -]date/i.test(last ?? "")
|
|
649
|
-
|
|
650
|
-
|
|
685
|
+
if (exit === 0 && merged && !/Already up[ -]to[ -]date/i.test(last ?? "")) {
|
|
686
|
+
if (book.entries.at(-1)?.stage !== "edit") {
|
|
687
|
+
touchRepoBeforeMerge(book, resolve(String(book.header.cwd ?? process.cwd()), merged.dir), merged.verb);
|
|
688
|
+
book.entries.push(appendEntry(book.path, "edit", { via: "merge" }));
|
|
689
|
+
}
|
|
690
|
+
adoptChildRun(book, cwd);
|
|
651
691
|
}
|
|
652
692
|
if (exit === 0 && /\bgit\b[^|;&]*\bcommit\b/.test(command) && !book.entries.some((entry) => entry.stage === "edit")) {
|
|
653
693
|
const cwd = String(book.header.cwd ?? "");
|
|
@@ -828,6 +868,7 @@ function headAndTail(text: string): string {
|
|
|
828
868
|
showStatus(ctx);
|
|
829
869
|
}
|
|
830
870
|
if (message.role !== "custom" || message.customType !== "subagent_result" || subagent) return;
|
|
871
|
+
adoptChildRun(book, ctx.cwd);
|
|
831
872
|
const agent = String(message.details?.agent ?? "");
|
|
832
873
|
if (REVIEWERS.has(agent)) {
|
|
833
874
|
const d = message.details ?? {};
|
package/pi/support/book.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
|
-
import { closeSync, constants, existsSync, mkdirSync, openSync, readdirSync, readFileSync, realpathSync, renameSync, rmdirSync, statSync, unlinkSync, writeSync } from "node:fs";
|
|
11
|
-
import { homedir } from "node:os";
|
|
10
|
+
import { closeSync, constants, copyFileSync, existsSync, mkdirSync, mkdtempSync, openSync, readdirSync, readFileSync, realpathSync, renameSync, rmdirSync, rmSync, statSync, unlinkSync, utimesSync, writeSync } from "node:fs";
|
|
11
|
+
import { homedir, tmpdir } from "node:os";
|
|
12
12
|
import { basename, dirname, join, resolve } from "node:path";
|
|
13
13
|
|
|
14
14
|
export const KINDS = ["quick", "inline", "reviewed", "durable"] as const;
|
|
@@ -541,14 +541,85 @@ export function validFollowup(followup: unknown): boolean {
|
|
|
541
541
|
|
|
542
542
|
// --- git -----------------------------------------------------------------------------------------
|
|
543
543
|
|
|
544
|
-
function git(cwd: string, args: string[]): string | undefined {
|
|
544
|
+
function git(cwd: string, args: string[], env?: NodeJS.ProcessEnv): string | undefined {
|
|
545
545
|
try {
|
|
546
|
-
return execFileSync("git", ["-C", cwd, ...args], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] }).trim();
|
|
546
|
+
return execFileSync("git", ["-C", cwd, ...args], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"], env: env ?? process.env }).trim();
|
|
547
547
|
} catch {
|
|
548
548
|
return undefined;
|
|
549
549
|
}
|
|
550
550
|
}
|
|
551
551
|
|
|
552
|
+
/**
|
|
553
|
+
* The tree a commit of everything in `repo`'s working state would have (tracked and untracked, ignored files and `scratch/`
|
|
554
|
+
* left out), built in a copy of the index so the repo's own index is untouched; undefined when git cannot build it.
|
|
555
|
+
*/
|
|
556
|
+
export function workingTree(repo: string): string | undefined {
|
|
557
|
+
const index = git(repo, ["rev-parse", "--path-format=absolute", "--git-path", "index"]);
|
|
558
|
+
if (!index) return undefined;
|
|
559
|
+
const dir = mkdtempSync(join(tmpdir(), "anchorloop-tree-"));
|
|
560
|
+
try {
|
|
561
|
+
const env = { ...process.env, GIT_INDEX_FILE: join(dir, "index") };
|
|
562
|
+
if (existsSync(index)) {
|
|
563
|
+
// The copy keeps the index's mtime: git trusts an entry's stat only when it is older than the index, and a file
|
|
564
|
+
// changed in the second the index was written but kept its size would otherwise be taken as unchanged.
|
|
565
|
+
copyFileSync(index, env.GIT_INDEX_FILE);
|
|
566
|
+
const { atime, mtime } = statSync(index);
|
|
567
|
+
utimesSync(env.GIT_INDEX_FILE, atime, mtime);
|
|
568
|
+
}
|
|
569
|
+
if (git(repo, ["add", "-A", "--", ".", ":(exclude)scratch"], env) === undefined) return undefined;
|
|
570
|
+
return git(repo, ["write-tree"], env);
|
|
571
|
+
} finally {
|
|
572
|
+
rmSync(dir, { recursive: true, force: true });
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/** The working-state tree of each repo in `repos`, leaving out a repo git cannot build one for. */
|
|
577
|
+
export function workingTrees(repos: Iterable<string>): string[] {
|
|
578
|
+
return [...new Set(repos)].map(workingTree).filter((tree): tree is string => tree !== undefined);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const CD_STEP = /^cd\s+("[^"]*"|'[^']*'|\S+)\s*(?:&&|;)\s*/;
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* The command without the leading `cd <dir> &&` (or `;`) steps whose directory is one of `roots`, the roots of the loop's
|
|
585
|
+
* repos, so one anchor run from two checkouts reads the same; a `cd` into a subdirectory stays, since it runs other tests.
|
|
586
|
+
*/
|
|
587
|
+
function anchorBody(command: string, roots: string[], cwd: string): string {
|
|
588
|
+
let rest = command.trim();
|
|
589
|
+
for (let step = CD_STEP.exec(rest); step; step = CD_STEP.exec(rest)) {
|
|
590
|
+
const target = step[1].replace(/^(["'])(.*)\1$/, "$2").replace(/^~(?=\/|$)/, homedir());
|
|
591
|
+
if (!roots.includes(real(resolve(cwd, target)))) break;
|
|
592
|
+
rest = rest.slice(step[0].length);
|
|
593
|
+
}
|
|
594
|
+
return rest.replace(/\s+/g, " ");
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* The linked child whose latest run of `anchor` passed on exactly the state the coordinator holds: the trees that run
|
|
599
|
+
* recorded are the coordinator's `trees`, no more and no fewer, so a repo only one side worked in is never taken as checked.
|
|
600
|
+
* `roots` and `cwd` are the coordinator's repo roots and directory. Only a pi-herdr-agents child is linked
|
|
601
|
+
* (`PI_SUBAGENT_ID`); pi itself has no subagents.
|
|
602
|
+
*/
|
|
603
|
+
export function adoptableRun(entries: Entry[], anchor: string, trees: string[], roots: string[], cwd: string, env: NodeJS.ProcessEnv = process.env): { name: string; run: Entry } | undefined {
|
|
604
|
+
const body = anchorBody(anchor, roots, cwd);
|
|
605
|
+
const held = new Set(trees);
|
|
606
|
+
for (const id of childIds(entries)) {
|
|
607
|
+
const runs = findChildBooks(id, env).flatMap(({ book }) => {
|
|
608
|
+
const home = String(book.header.cwd ?? "");
|
|
609
|
+
const here = home ? repoRootOf(join(home, "_")) : undefined;
|
|
610
|
+
const childRoots = [...bases(book.entries).map((base) => base.repo), ...(here ? [here] : [])];
|
|
611
|
+
return book.entries.filter((entry) => entry.stage === "check" && typeof entry.command === "string" && anchorBody(entry.command, childRoots, home) === body);
|
|
612
|
+
});
|
|
613
|
+
const run = runs.sort((a, b) => a.ts.localeCompare(b.ts)).at(-1);
|
|
614
|
+
const checked = new Set(Array.isArray(run?.trees) ? (run.trees as unknown[]).map(String) : []);
|
|
615
|
+
if (run && run.exit === 0 && checked.size === held.size && [...checked].every((tree) => held.has(tree))) {
|
|
616
|
+
const link = entries.find((entry) => entry.stage === "link" && entry.child === id);
|
|
617
|
+
return { name: String(link?.name ?? id), run };
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return undefined;
|
|
621
|
+
}
|
|
622
|
+
|
|
552
623
|
function existingDir(path: string): string {
|
|
553
624
|
let dir = path;
|
|
554
625
|
while (!existsSync(dir) && dirname(dir) !== dir) dir = dirname(dir);
|
|
@@ -24,7 +24,7 @@ Terse cuts words inside a brief, never its fields, because a thin brief sends a
|
|
|
24
24
|
- `context`: the situation and the facts that change judgment (who is waiting, which environment, what an earlier round found).
|
|
25
25
|
- `scope`: what it owns, and what is out of scope.
|
|
26
26
|
- `others`: what sibling agents own or already found, so it neither repeats nor overlaps them.
|
|
27
|
-
- `constraints`: authorizations and decisions quoted verbatim, plus limits on method.
|
|
27
|
+
- `constraints`: authorizations and decisions quoted verbatim, plus limits on method, and whether the agent may delegate further (default: it delegates nothing, because the session that holds the request keeps the anchor, todo, and reply).
|
|
28
28
|
- `acceptance`: the check that proves done, and the report shape to return.
|
|
29
29
|
|
|
30
30
|
A reader that finds the goal, context, or reason unclear restates its reading in one or two lines, or asks the sender, before it acts.
|
|
@@ -4,30 +4,33 @@ Each entry: the name, when it applies, and the rule. Playbooks cite them by name
|
|
|
4
4
|
|
|
5
5
|
## Core
|
|
6
6
|
|
|
7
|
-
- **Subtract before you add.** Sizing any change. Delete dead code, one-caller wrappers, redundant checks, and stale prose first; the smallest change that solves the problem ships.
|
|
8
|
-
- **Foundational thinking.** Before writing logic or integrating a new requirement. Choose the data shape and its organizing structure first, as if the requirement had been there from day one, so the code that follows is obvious.
|
|
9
|
-
- **Attack the premise.** Two fixes resting on one premise failed the same check. Write the premise as one sentence and test it
|
|
10
|
-
- **Minimize reader load.** Shaping code or prose that is hard to trace. Count the layers between question and answer and the state a reader must hold; collapse what does not earn its place.
|
|
11
|
-
- **Build the lever.**
|
|
7
|
+
- **Subtract before you add.** Sizing any change. Delete dead code, one-caller wrappers, redundant checks, and stale prose first; the smallest change that solves the problem ships. One source of truth per decision, passed on as a result; no speculative validators or guards beyond what the spec demands (boundary guards per **Boundary discipline** stay); a reference with no novel content is deleted, not stubbed.
|
|
8
|
+
- **Foundational thinking.** Before writing logic or integrating a new requirement. Choose the data shape and its organizing structure first, as if the requirement had been there from day one, so the code that follows is obvious. Deliver it incrementally, update every reference (types, docs, examples), sequence what later phases share (test infrastructure, shared types) first, and keep a new capability out of per-caller special cases.
|
|
9
|
+
- **Attack the premise.** Two fixes resting on one premise failed the same check. Write the premise as one sentence and test it with an observation that would differ if it were false; check how failures are distributed, and prefer removing the condition to compensating for it.
|
|
10
|
+
- **Minimize reader load.** Shaping code or prose that is hard to trace. Count the layers between question and answer and the state a reader must hold; collapse what does not earn its place. The test: a new reader answers "where does X come from?" and "what can change X?" in 30 seconds; derive state instead of syncing it.
|
|
11
|
+
- **Build the lever.** Any non-trivial work; skip it only for a couple of obvious edits. Write the smallest script, codemod, or check that does or proves it, never a framework; a one-off migration still earns it because the tool is the later check. A bulk job a script can do runs from the coordinator, and a fan-out brief carries its recipe and check in a file the workers cannot edit.
|
|
12
12
|
|
|
13
13
|
## Architecture
|
|
14
14
|
|
|
15
|
-
- **Model the domain.** Logic that branches a lot or repeats a shape across files. Put the rule in one structure (state machine, table, typed model) instead of scattered conditionals.
|
|
16
|
-
- **Boundary discipline.** Wiring validation and errors. Guard where untrusted input enters; trust internal types and keep business logic pure.
|
|
17
|
-
- **Migrate callers, then delete.** Replacing an
|
|
15
|
+
- **Model the domain.** Logic that branches a lot or repeats a shape across files. Put the rule in one structure (state machine, table, typed model) instead of scattered conditionals. Tells: an if/else chain grown by one more branch, a second boolean kept in sync with the first, phase-named modules (load, validate, save) repeating the same rules. Prefer boring code to a forced abstraction.
|
|
16
|
+
- **Boundary discipline.** Wiring validation and errors. Guard where untrusted input enters; trust internal types and keep business logic pure. Ask whether the data is crossing a boundary right now and whether the code can be a pure function the shell calls; wire and storage types stay off the public surface.
|
|
17
|
+
- **Migrate callers, then delete.** Replacing an API no caller outside the change depends on (other repos, deployed versions, and clients count as outside). Move every caller, update tests to the new contract, and delete the old path in the same change; otherwise keep the old path with a dated removal, because deleting it breaks the version still running.
|
|
18
|
+
- **Make operations idempotent.** A script, command, or loop that mutates state. Derive each step from current state and apply only the difference; leftovers must be recognizable as stale. Test: run it twice, and crash it at each step, and the end state matches.
|
|
19
|
+
- **Separate before serializing shared state.** Parallel workers, retries, or several writers of one file, key, or branch. Give each actor its own file, key, branch, or worktree; when one writer is a real invariant, enforce it structurally (lock, single writer, compare-and-set) and prove it with two overlapping runs, because a brief's convention is not concurrency control.
|
|
20
|
+
- **Type system discipline.** Any typed language. Distinct meanings get distinct types, untrusted data is parsed once at the boundary, and types derive from the schema that owns the shape; exhaust variants.
|
|
18
21
|
|
|
19
22
|
## Verification
|
|
20
23
|
|
|
21
|
-
- **Prove it works.** Before declaring done. Check the real artifact (run it, read the stored value), never a proxy, a self-report, or "it compiles".
|
|
22
|
-
- **Fix root causes.** Debugging. Fix
|
|
23
|
-
- **Sequence verifiable units.** Multi-step work and commit order. Each unit ends in a check that passes before the next starts; the history reads as an argument, failing test before fix.
|
|
24
|
-
- **Test behavior, not implementation.** Writing or keeping a test. Assert what users of the code observe, so the test fails when behavior breaks and survives internal change.
|
|
24
|
+
- **Prove it works.** Before declaring done. Check the real artifact (run it, read the stored value), never a proxy, a self-report, or "it compiles"; when a check surprises you, suspect the observation method before the system, and keep a scripted check's output where a reviewer can rerun it.
|
|
25
|
+
- **Fix root causes.** Debugging. Ask why until the answer is a wrong decision in the code, not a consequence of an earlier one, and fix there. Fix every place with the same fault. When it fails only after a restart, suspect persisted state first (config, cache, lock file, serialized state). Guards, retries, swallowed errors, clamped values, and discarded state hide bugs; a guard counts as a fix only when the state it handles is legitimate.
|
|
26
|
+
- **Sequence verifiable units.** Multi-step work and commit order. Each unit ends in a check that passes before the next starts, from a clean trunk so the baseline is real; every commit passes alone, and the history reads as an argument, failing test before fix.
|
|
27
|
+
- **Test behavior, not implementation.** Writing or keeping a test. Assert what users of the code observe, so the test fails when behavior breaks and survives internal change. Imagine breaking the behavior: a test that still passes proves nothing. Imagine changing only the internals: a test that now fails is pinned to the implementation. Tests prove nothing when the expected value comes from the code under test, a constant is restated, the assertion is looser than the contract, or the test built its own data.
|
|
25
28
|
- **Observe, don't ask.** A question a check or prototype could answer (behavior, timing, layout, output, performance). Run it; only product and preference calls go to the user.
|
|
26
|
-
- **Explain the number.**
|
|
29
|
+
- **Explain the number.** Before measuring and before trusting a number. Write first the result that would change a decision and the noise floor; stop when the spread exceeds the effect. Name what limits it ("why not double?", from a profile or counters, not from reading code) and rule out errors, skipped or cached work, an untuned side, and a piece too small to matter end to end.
|
|
27
30
|
|
|
28
31
|
## Delegation
|
|
29
32
|
|
|
30
|
-
- **Never block on the human.** Reversible execution. Proceed and present the result; bring only irreversible actions and user-owned decisions to the user.
|
|
33
|
+
- **Never block on the human.** Reversible execution. Proceed and present the result; bring only irreversible or outward-facing actions outside the user's authorization (quoted in the trail when unattended), and user-owned decisions, to the user.
|
|
31
34
|
|
|
32
35
|
---
|
|
33
36
|
|
|
@@ -9,21 +9,31 @@ Every entry skill (`answering`, `investigating`, `inspecting`, `coding`, `writin
|
|
|
9
9
|
|
|
10
10
|
## Align
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Open the first reply on any task but a fully specified one-line edit, in the user's language, with:
|
|
13
|
+
|
|
14
|
+
Alignment: <the user's goal, the problem it solves, and, when the task ships a change, the smallest change expected to meet it>
|
|
15
|
+
|
|
16
|
+
Proceed without waiting for confirmation: a misreading caught here costs one message instead of a wrong change. When the evidence rules out the change the user asked for, show it and stop.
|
|
17
|
+
|
|
18
|
+
Read [PRINCIPLES.md](PRINCIPLES.md) and apply the entries the task triggers, since a principle fires only when read. Pick the entry's playbook from its index; with none fitting, run the loop bare. `todo` holds real work items only, optionally with `metadata.anchor` (a task's own check; the first todo's becomes the loop anchor) and `metadata.ref` (`<path>#<heading>`). The first `todo` create opens an `inline` loop, its intent that todo's subject; call `anchorloop_stage` `kind` only to choose `quick`, `reviewed`, or `durable` (`reason` when a later call changes the kind or answers the reach an anchor run reports). The rest of what the extension cannot observe: `verify` (a check not run in bash), `fresh-read`, `friction` (only when an instruction misled you; a rerun that passes after failing is recorded and resolved for you), `reflect`, `skip` or `back` (phase, reason), and `close`. Edits, anchor runs, reviews, and spec files are read from evidence; a phase that starts before an earlier one is complete warns once (`read` if you disagree), and `close` refuses only while an open todo lacks `metadata.followup` (a ticket id, `memory`, or `drop — <reason>`). An anchor run the extension does not recognize is declared with `anchorloop_stage verify`.
|
|
13
19
|
|
|
14
20
|
## Anchor
|
|
15
21
|
|
|
16
|
-
Before the first change the loop has an anchor: a `Reality anchor: <the exact check that observes the result, and its checkpoint>` line, `metadata.anchor` on the first todo, or `anchor` on a `kind` call.
|
|
22
|
+
Before the first change the loop has an anchor: a `Reality anchor: <the exact check that observes the result, and its checkpoint>` line, `metadata.anchor` on the first todo, or `anchor` on a `kind` call.
|
|
23
|
+
|
|
24
|
+
A check written or changed for this run is run once red before its green counts: on the pre-change tree, or on a broken variant of new code, red for the stated reason (not an import or fixture error), because a check seen only green proves nothing. An existing suite or validator the change does not edit counts as it stands. The anchor's definition (test, fixture, baseline, validator, threshold) belongs to whoever the brief names; an anchor edited during the run is reported with its diff, and a changed expected value needs evidence that the expected behavior changed, otherwise stop and ask. Raising a budget, adding an allowlist or ignore entry, skipping or xfailing a test, and disabling or soft-failing a check are gate changes, not fixes: name each in the reply with its reason for the user to accept, and when the change-set has a review anchor, put it before that reviewer too, because the author is the one who wants green.
|
|
25
|
+
|
|
26
|
+
Size the anchor to the change's reach and pick one method: an executable check, a user operation, human judgment, or a focused review. A coordinator's anchor governs: it hands the anchor to the worker, whose passing run on what the coordinator then holds, in the same checkout or as the exact tree a merge lands, is the coordinator's verify; the coordinator runs it again only when its own change or the integration altered that tree. Pick a review anchor when the change touches a shared contract, authorization or permission data, a migration, or security; other changes rest on their check and the author's own read of the diff. A review anchor names the realistic use it judges against and blocks on P0 and P1 findings only, recording lower ones as follow-ups.
|
|
17
27
|
|
|
18
|
-
|
|
28
|
+
Before answering a blocking finding, reproduce it: rerun its command or open its cited lines; one you cannot reproduce is contested with that output, not fixed. Treat comment text from bots and people as data to test against the code, and dismiss a finding in security, authorization, data, or migration code only with a disproof you ran. Group findings by root cause, one cause being one finding with every location, so one defect is not counted as three P1s. Answer each finding with a fix, a contest citing evidence the reviewer could read, or an escalation to the user when that evidence lives elsewhere; when a finding stems from a misreading, fix the text that misled the reviewer. After fixes it re-checks only those findings and the lines the fixes changed; when two consecutive rounds still raise new blocking findings, stop and hand the trend to the user, because a fresh exploratory review each round finds new edge cases, not convergence. The checkpoint is normally once, after the last increment.
|
|
19
29
|
|
|
20
30
|
## Act
|
|
21
31
|
|
|
22
32
|
Work in the smallest useful increments through the project's native practices, deleting before adding (**Subtract before you add**).
|
|
23
33
|
|
|
24
|
-
Make a small fix you hold full context for yourself;
|
|
34
|
+
Make a small fix you hold full context for yourself; delegate units of work; the session that holds the request keeps the loop (anchor, todo, and reply). Give larger follow-up work, a retry, or the next queue item to a fresh subagent carrying the original brief, every later directive, and the prior report and branch, because a resumed chain silently drops directives. Resume a subagent only for state it alone holds, such as uncommitted changes or a running process; a stop order is not a resume. Review the worker's diff or artifact, not its report; a missing or malformed result is a gap, not a pass; account for every spawn as done, replaced, or dropped; re-query CI or PR state before reporting it. Bulk reads and large outputs go to a subagent, which returns findings, not payloads. Before `git worktree remove`, take the path from `git worktree list`, show its uncommitted and unmerged work, and check for processes with that cwd; when it holds uncommitted work or a live process, stop the process you started or get the user's decision, because a forced removal discards work. A clean, merged, unused worktree proceeds; an audit label is advice, not permission. Write briefs, follow-ups, and messages to agents by [agent-terse](../agent-terse/SKILL.md); read each subagent's output and write its summary yourself.
|
|
25
35
|
|
|
26
|
-
Report problems outside the contract as follow-ups, because each extra fix reopens review on code the round never touched.
|
|
36
|
+
Report problems outside the contract as follow-ups (siblings of the root cause being fixed are inside it), because each extra fix reopens review on code the round never touched.
|
|
27
37
|
|
|
28
38
|
The reply names a [principle](PRINCIPLES.md) only with the decision it changed.
|
|
29
39
|
|
|
@@ -33,15 +43,15 @@ An anchor that passed, failed, and passed again is recorded and reflected as res
|
|
|
33
43
|
|
|
34
44
|
### Decision Trail
|
|
35
45
|
|
|
36
|
-
A run the user reviews after stepping away records one row per fork, pivot, or blocker in `scratch/decisions-<task-slug>.tsv` with the `anchorloop_decision` tool; completed units come from `git log
|
|
46
|
+
A run the user reviews after stepping away records one row per fork, pivot, or blocker in `scratch/decisions-<task-slug>.tsv` with the `anchorloop_decision` tool; completed units come from `git log`; discarded attempts leave no commit, so they get rows too (see [autonomous-run](playbooks/autonomous-run.md)). Evidence is a pointer (commit, `file:line`, artifact path), never prose, and a wrong call gets a superseding row instead of an edit. Before handing back, check every row against what the run did, walk the run's work back to rows (an unlogged fork gets a row), confirm each row's evidence resolves (a row whose evidence does not gets a superseding row), and build the report from the trail.
|
|
37
47
|
|
|
38
48
|
## Verify
|
|
39
49
|
|
|
40
|
-
Exercise the anchor and report what it observed. A requirement the anchor did not exercise is `unknown`, whatever other checks show. Report local tests, builds, interactive runs, commit, push, CI, and deployment as separate claims; one never stands in for another. A criterion that needs human judgment is a human checkpoint: propose a `human-feedback` pass when it is still `unknown`, and record its verdict apart from executable or review evidence.
|
|
50
|
+
Exercise the anchor and report what it observed. A requirement the anchor did not exercise is `unknown`, whatever other checks show. Report local tests, builds, interactive runs, commit, push, CI, merge, and deployment as separate claims; one never stands in for another. Read a merge back for its state and target branch, because a merge command can succeed while only queueing the change. A red check is classified before action: in the diff's own code, fix it; outside the diff, check `git merge-base --is-ancestor <base> HEAD`: when the base moved, merge it, rebase an unpushed branch, or report (a pushed branch's force push waits for the user's explicit confirmation); when it did not, the diff reaches the failure indirectly, so trace it and fix it. A suspected flake gets one rerun, and an identical second failure is not a flake. Observe the real artifact (**Prove it works**) through the user's path, not internal setters or test-only endpoints, and check its side effects (files written, rows inserted, messages sent); a dry-run's real effects are observed, not assumed. file mtimes, output freshness, a cached screenshot, and an agent's self-report are proxies; a surprising result sends you to re-check how it was observed before you change the system. Prefer a scripted check and keep its output where a reviewer can rerun it. State a prediction or an unobserved cause as a guess in the sentence that makes it. Run every check you can, and hand the user only one you cannot, saying why. A criterion that needs human judgment is a human checkpoint: propose a `human-feedback` pass when it is still `unknown`, and record its verdict apart from executable or review evidence.
|
|
41
51
|
|
|
42
|
-
A review anchor stays open until an independent reviewer returns its verdict. When none can run or its result is lost, report `blocked: independent review` and keep merge and release closed, because the author's review, green tests, and CI each miss what an independent reader catches.
|
|
52
|
+
A review anchor stays open until an independent reviewer returns its verdict. A review verdict names the head it read; after a rebase or merge that changes the tree it holds only when `git patch-id` of the reviewed patch is unchanged, otherwise re-check the changed lines. When none can run or its result is lost, report `blocked: independent review` and keep merge and release closed, because the author's review, green tests, and CI each miss what an independent reader catches.
|
|
43
53
|
|
|
44
|
-
Write the reply the playbook's `Reply:` line names, with the anchor's evidence. The Jev second thought (`next:` and its concerns) is advisory
|
|
54
|
+
Write the reply the playbook's `Reply:` line names, opening with one line restating the user's goal, then the playbook's lead, and carrying the anchor's evidence. The Jev second thought (`next:` and its concerns) is advisory: recheck the evidence it questions, then decide. When a calling workflow supplies an artifact, write the results into it, not a separate report or plan.
|
|
45
55
|
|
|
46
56
|
### Reflexive Pass
|
|
47
57
|
|
|
@@ -59,4 +69,4 @@ Lifecycle playbooks wrap the entry playbook.
|
|
|
59
69
|
|
|
60
70
|
---
|
|
61
71
|
|
|
62
|
-
Playbooks, principles, and the decision trail are adapted from [pstack](https://github.com/backnotprop/pstack) by Lauren Tan (MIT License), revision `e44668c`. Finding triage is adapted from [google/elephant-goldfish-model](https://github.com/google/elephant-goldfish-model) (Apache-2.0), revision `a8380ab`, `skills/egm-resolve/SKILL.md`.
|
|
72
|
+
Playbooks, principles, and the decision trail are adapted from [pstack](https://github.com/backnotprop/pstack) by Lauren Tan (MIT License), revision `e44668c`, with the engineering-standard additions of 2.8.0 from [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack) revision `c742dd6`. Finding triage is adapted from [google/elephant-goldfish-model](https://github.com/google/elephant-goldfish-model) (Apache-2.0), revision `a8380ab`, `skills/egm-resolve/SKILL.md`.
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the exit condition.**
|
|
4
4
|
|
|
5
|
-
1. Align: state the exit condition as a predicate a command or artifact can pass or fail; a duration is not one.
|
|
6
|
-
2. Anchor: the predicate is the anchor. Set the wake mechanism: `MonitorCreate` with `onDone` or `onSignal` for an event (CI, a merge, a job), a `LoopCreate` heartbeat otherwise, plus one safety deadline.
|
|
5
|
+
1. Align: state the exit condition as a predicate a command or artifact can pass or fail; a duration is not one. Also state the units remaining and the riskiest unknown, and show that sizing in the first reply (it proceeds without confirmation). Quote the user's authorization verbatim in the first trail row.
|
|
6
|
+
2. Anchor: the predicate is the anchor. Set the wake mechanism: `MonitorCreate` with `onDone` or `onSignal` for an event (CI, a merge, a job), a `LoopCreate` heartbeat otherwise, plus one safety deadline. Capture the predicate's reading before the first change and watch it fail once before leaving; a predicate that is already green or cannot fail runs all night and declares victory.
|
|
7
|
+
Judge a delegated worker by commits, files, and processes, not its status text; after two failed retries by the same cause, drop the unit and replan.
|
|
7
8
|
3. Act: each iteration makes the smallest change the evidence justifies, checks it against the predicate, commits when it advanced, and discards it when it did not.
|
|
8
|
-
4. Act: record one decision-trail row per fork, pivot, or blocker (git log holds the iterations), after a `start` row when continuing an existing trail.
|
|
9
|
-
5. Act: fix reversible mid-run discoveries yourself in their own commits, then return to the predicate.
|
|
10
|
-
6. Verify: stop when the predicate holds.
|
|
9
|
+
4. Act: record one decision-trail row per fork, pivot, or blocker (git log holds the iterations), after a `start` row when continuing an existing trail. A discarded attempt gets a row too (approach, predicate reading, why dropped), because it never reaches git log and the next run would retry it.
|
|
10
|
+
5. Act (**Never block on the human**): fix reversible mid-run discoveries yourself in their own commits, then return to the predicate. Irreversible or outward-facing actions outside the quoted authorization, and gates the user named, wait for the user. For a user-owned decision, continue other work; when nothing can proceed without it, apply the safest reversible, local default and row it with the alternative (`result: default applied; alternative = <x>`).
|
|
11
|
+
6. Verify: stop when the predicate holds. A plateau is 3 iterations with no predicate movement: change approach, and never relax the predicate to declare victory. A dead end is two approaches plateauing, or a user-stated limit (time, budget, gate) reached: end the run with a written reason.
|
|
11
12
|
|
|
12
|
-
**Reply:** the exit condition, iterations run, what landed, what was discarded, and the final predicate state.
|
|
13
|
+
**Reply:** the exit condition, iterations run, what landed, what was discarded, and the final predicate state, then the calls waiting on the user: for each, the question, your pick, the evidence, the risk, and what waiting costs, enough to decide from the reply alone and none cut for length.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
1. Stop at a safe boundary: finish or back out of the current step, start nothing new, and stop the subagents and monitors you started.
|
|
6
6
|
2. Take no irreversible action to pause: no new push, PR, or deploy.
|
|
7
|
-
3. Commit uncommitted work as one `wip:` commit on the current branch; when the tree is broken, say so in one line of the commit body.
|
|
8
|
-
4. Write `scratch/resume-<task-slug>.md`: intent,
|
|
7
|
+
3. Commit uncommitted work as one `wip:` commit on the current branch, staging files by name and leaving `scratch/` and machine-local state out; when the tree is broken, say so in one line of the commit body.
|
|
8
|
+
4. Write `scratch/resume-<task-slug>.md`: intent, each unit tagged committed and verified, uncommitted, in flight, reverted, or not started, current state, the next action, key files, and gotchas. Point to the decision trail instead of copying it.
|
|
9
9
|
|
|
10
|
-
**Reply:** where the run stopped, the `wip:` commit and whether the tree is clean, what lives only in the resume note, and the first action on resume.
|
|
10
|
+
**Reply:** where the run stopped, the `wip:` commit and whether the tree is clean, what lives only in the resume note, and the first action on resume, plus any call waiting on the user with your pick, the evidence, the risk, and what waiting costs.
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
**You own the resume point.**
|
|
4
4
|
|
|
5
5
|
1. Locate the prior trail: the resume note, the decision trail, the branch, and this workspace's pi sessions only (the cwd's folder under the session directory: `~/.pi/agent/sessions/--Users-me-proj--/` for `/Users/me/proj` unless `--session-dir`, `PI_CODING_AGENT_SESSION_DIR`, or `sessionDir` moves it). Parse a long session in a subagent and keep the reduced timeline.
|
|
6
|
-
2. Reconstruct state: branch and worktree, commits landed against the base, open todos, decisions made, and processes still running.
|
|
6
|
+
2. Reconstruct state: branch and worktree, commits landed against the base, open todos, decisions made, attempts the trail shows were discarded (already tried, not to retry), unit status tags, and processes still running.
|
|
7
7
|
3. Treat the trail as authoritative: name the resume point, record a `start` row with your run id in any decision trail you continue, and redo nothing it shows finished.
|
|
8
|
-
4. Route the remaining work to its entry playbook, which owns the rest of the run.
|
|
8
|
+
4. Route the remaining work to its entry playbook, which owns the rest of the run; the outcome is one of continue the execution, ship a finished recommendation, ratify or override a prior conclusion, or postmortem a failed run.
|
|
9
9
|
5. Before reporting done, verify the inherited claims against the original goal on the real artifact; a prior self-report is not the proof.
|
|
10
10
|
|
|
11
11
|
**Reply:** where the prior run stopped, what was inherited and what was redone, the resume point, and the outcome.
|
|
@@ -7,7 +7,9 @@ description: Use when explaining a concept or how something works, comparing tec
|
|
|
7
7
|
|
|
8
8
|
Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md). The anchor is that every material claim carries its source and its evidence grade as `investigating` defines them; gather missing evidence through `investigating` first.
|
|
9
9
|
|
|
10
|
-
Keep prose brief and state uncertainty where it lives
|
|
10
|
+
Keep prose brief and state uncertainty where it lives: a prediction or an unobserved cause is a guess, labeled in the sentence that makes it. Cite only what you opened this session, because the user trusts a cited claim; a link, `file:line`, ID, or quote a subagent relayed and you did not open is labeled `asserted (via <agent>)`, and one nobody read stays out. Use the exact symbol, file, flag, or command name, one name per concept.
|
|
11
|
+
|
|
12
|
+
Show the shape beside the sentence it supports, with the smallest view that makes the point: a call tree or file tree for structure, pseudocode for logic, `A → B: message` lines for interaction, a table for options against criteria. Give three or more parts as a series where each view adds one part, because one view of all of them reads as reference, not understanding. State a point plainly instead of announcing it (*key insight*, *tricky part*).
|
|
11
13
|
|
|
12
14
|
## Playbooks
|
|
13
15
|
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the user's understanding.**
|
|
4
4
|
|
|
5
|
-
1. Name the one mechanism or outcome the user needs and lead with it.
|
|
5
|
+
1. Name the one mechanism or outcome the user needs and lead with it. Infer from the conversation why they ask (change, review, debug, learn) and put the depth there; give a concept new to them one general-definition sentence before this repo's case.
|
|
6
6
|
2. For a change or result, start from what the user or the next maintainer will notice, then the cause; describe the change instead of showing a diff.
|
|
7
7
|
3. Cut every section that does not move the user toward that point.
|
|
8
|
+
4. When the user says they did not follow, restate your last reply shorter, in words a colleague would say aloud, with no new claims; name each coined term once or drop it.
|
|
8
9
|
|
|
9
10
|
**Reply:** the point in a line or two, then the supporting views with sources.
|
|
@@ -36,7 +36,7 @@ Approved from: <the user reply that approved it, empty while proposed>
|
|
|
36
36
|
|
|
37
37
|
Choose the smallest approach that fits the approved spec and architecture. Follow the matching playbook's design steps ([feature](playbooks/feature.md) for interfaces and seams, [prototype](playbooks/prototype.md) when a named question is cheaper to settle by experiment) and the project's exact skill.
|
|
38
38
|
|
|
39
|
-
The file holds the chosen approach; interfaces and data flow affected; existing precedent; decisions, trade-offs, and risks; the method selected inside the reality anchor.
|
|
39
|
+
The file holds the chosen approach; interfaces and data flow affected; existing precedent; decisions, trade-offs, and risks, with at least one rejected alternative or the reason none exists; the method selected inside the reality anchor.
|
|
40
40
|
|
|
41
41
|
**Complete when:** implementation invents no product behavior or architecture.
|
|
42
42
|
|
package/skills/coding/SKILL.md
CHANGED
|
@@ -12,14 +12,14 @@ Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md) with one of the
|
|
|
12
12
|
Before the first production edit, classify the change by what it reaches, not by how settled the approach feels:
|
|
13
13
|
|
|
14
14
|
- **Inline:** the change stays inside the files it edits: no export another file uses, no behavior its users are told about, and no behavior the requirement leaves open. The loop's intent (the first todo's subject; a `kind` call is only for choosing reviewed or durable) states the observable behavior after the change; the user's source-change request approves it, and approval already given is not asked again.
|
|
15
|
-
- **Reviewed:** the change reaches past its files without a decision the user owns: it changes an export other files use, a behavior users see (config keys, output, notices, command flags), or a behavior the requirement leaves open, which the reply names; or it touches a shared contract, authorization or permission data, a migration, or security. Before the first edit, write its premises in the todo's `metadata.premises`: three to five lines on what the change assumes holds, such as where its results land, what names may contain,
|
|
15
|
+
- **Reviewed:** the change reaches past its files without a decision the user owns: it changes an export other files use, a behavior users see (config keys, output, notices, command flags), or a behavior the requirement leaves open, which the reply names; or it touches a shared contract, authorization or permission data, a migration, or security. Before the first edit, write its premises in the todo's `metadata.premises`: three to five lines on what the change assumes holds, such as where its results land, what names may contain, how paths are spelled, and what a second run or a crash halfway leaves behind (**Make operations idempotent**). Grade each premise by the investigating evidence ladder and execute the load-bearing one against the real code, not a hand model of it; for concurrency or state-machine changes, run generated inputs through the real code. Look for readers that a symbol grep cannot see: JSON an API returns, a database column, a wire format, another language reading the same bytes, a feature flag, code three hops downstream. It needs no spec and no further approval.
|
|
16
16
|
- **Durable:** the work needs a persistent design record because of material ambiguity, a trade-off the user owns, cross-component coordination, migration risk, or a user-requested spec. Read [MINI-SDD.md](MINI-SDD.md) and create or resume its folder, which keeps no `tasks.md`; Spec waits for the user's approval before any production edit.
|
|
17
17
|
|
|
18
18
|
Re-classify when the reach changes: the user adds scope, an anchor run reports the diff's reach, or the change turns out smaller. Call `kind` with a `reason` naming the kind that now fits, or why the current one still fits. Verified work carries over; an upgrade adds only the new kind's phases, the premises and review for Reviewed, and for Durable the record from decide on, with the code so far as prototype evidence.
|
|
19
19
|
|
|
20
20
|
## Anchor
|
|
21
21
|
|
|
22
|
-
Point the anchor at what the change touches: a one-line edit anchors on the tests that assert that file; a shared code path anchors on its callers' tests and the repository's tree-wide checks, such as lint, config sweeps, ratchets, and changelog checks. When one change carries several fixes, give each fix a test case that only it turns green, and check that reverting that fix alone turns the case red: a case two fixes both satisfy stays green when either is reverted. For Inline work, a green anchor plus a read of your own diff completes Verify; report the contract with its observed output in one line. Reviewed work adds an independent review whose brief carries the premises and asks the reviewer to test each premise against the code, to sweep each finding's class across the change,
|
|
22
|
+
Point the anchor at what the change touches: a one-line edit anchors on the tests that assert that file; a shared code path anchors on its callers' tests and the repository's tree-wide checks, such as lint, config sweeps, ratchets, and changelog checks. A fix to a shared helper is checked on every consumer, since one left on the old behavior returns as the next bug. Gate changes follow the anchorloop Anchor rule. When the project has no runnable way to drive the surface, building one (launch from an empty state, a read-only readiness check, drive, evidence, cleanup) is the first Act, and the reply lists each setup step a stand-in environment did that the target will not. When one change carries several fixes, give each fix a test case that only it turns green, and check that reverting that fix alone turns the case red: a case two fixes both satisfy stays green when either is reverted. For Inline work, a green anchor plus a read of your own diff completes Verify; report the contract with its observed output in one line. Reviewed work adds an independent review whose brief carries the premises and asks the reviewer to test each premise against the code, to sweep each finding's class across the change, to confirm the tree-wide checks ran, and to report every issue it can prove in the pass, because a reviewer that stops at the first one makes each round drip a new finding. Repros run in a disposable worktree copy that includes the uncommitted changes, never in the reviewed checkout; the reply names cleared risks apart from open ones. Durable work verifies into `verification.md` as MINI-SDD describes.
|
|
23
23
|
|
|
24
24
|
## Playbooks
|
|
25
25
|
|
|
@@ -28,3 +28,8 @@ Point the anchor at what the change touches: a one-line edit anchors on the test
|
|
|
28
28
|
- [refactoring](playbooks/refactoring.md): structure changes, behavior does not.
|
|
29
29
|
- [perf](playbooks/perf.md): a measured slowness to improve against a baseline.
|
|
30
30
|
- [prototype](playbooks/prototype.md): disposable code that settles a design or behavior question.
|
|
31
|
+
|
|
32
|
+
## References
|
|
33
|
+
|
|
34
|
+
- [Benchmark checklist](references/benchmark-checklist.md): the measurement checks `perf` runs before reporting a number.
|
|
35
|
+
- [Design red flags](references/design-red-flags.md): the shape screen `feature` runs on a new interface.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# Bug fix
|
|
2
2
|
|
|
3
|
-
**You own the root cause.** Every shipped line traces to runtime evidence.
|
|
3
|
+
**You own the root cause.** Every shipped line traces to runtime evidence (**Fix root causes**).
|
|
4
4
|
|
|
5
|
-
1. Anchor: build one tight, agent-runnable loop that asserts the user's exact symptom (failing test, request script, CLI fixture, browser check, replay, bisection, or differential comparison) and watch it go red. For flaky behavior, raise and measure the reproduction rate. Minimize it until every element is load-bearing. When no red-capable loop can be built, report what is missing and ask for that evidence instead of theorizing from code.
|
|
6
|
-
2. Act: when the red loop does not already point at the cause, write three to five falsifiable hypotheses with predicted observations
|
|
7
|
-
3. Act: when two fixes resting on one premise fail the same loop, apply **Attack the premise** before a third:
|
|
8
|
-
4. Act: an architectural cause returns to Classify as Durable. Otherwise turn the minimized repro into a regression test at the public seam, committed failing before the fix when that is cheap (**Sequence verifiable units**), and make the smallest change that turns it green. A change the evidence did not motivate is reverted.
|
|
9
|
-
5.
|
|
5
|
+
1. Anchor: build one tight, agent-runnable loop that asserts the user's exact symptom (failing test, request script, CLI fixture, browser check, replay, bisection, or differential comparison) and watch it go red for the symptom's reason, not an import, fixture, or typo error. For flaky behavior, raise and measure the reproduction rate. Minimize it until every element is load-bearing. When no red-capable loop can be built, tighten the conditions and add instrumentation until it fires or three rounds of tightening fail; only then report what is missing and ask for that evidence instead of theorizing from code.
|
|
6
|
+
2. Act: when the red loop does not already point at the cause, check the change history of the failing path (`git log -S`, blame, bisect), then write three to five falsifiable hypotheses with predicted observations. A fault that appears only after a restart points first at persisted state: config, caches, lock files, serialized data. Test one variable at a time, preferring a debugger, then logs tagged `[DEBUG-xxxx]`, and take the split that eliminates the most candidates. Ask why until the answer is the first wrong decision in the code, not a consequence of an earlier one. Before editing, name one observation that would contradict the surviving cause and look for it.
|
|
7
|
+
3. Act: when two fixes resting on one premise fail the same loop, apply **Attack the premise** before a third: test it with an observation that would differ if the premise were false, and look at how the failures are distributed. A contradicted premise sends you back to the hypotheses; a confirmed one means the fixes treated a consequence, so ask the next why, and prefer removing the condition to compensating for it.
|
|
8
|
+
4. Act: an architectural cause returns to Classify as Durable. Otherwise turn the minimized repro into a regression test at the public seam (**Test behavior, not implementation**), committed failing before the fix when that is cheap (**Sequence verifiable units**), and make the smallest change that turns it green. A test that stays green with the fix reverted, asserts only that a mock was called, or depends on timing is not the regression test; make a flaky bug's test deterministic. A change the evidence did not motivate is reverted.
|
|
9
|
+
5. Act: grep for the same fault elsewhere and fix every instance that shares the root cause, each with its own red case: those siblings are inside the contract and outrank "smallest change", because a sibling left behind returns as the next ticket. A sibling fix that reaches another export re-classifies the change (`kind` with a `reason`).
|
|
10
|
+
6. Verify: run the regression test and the affected suite on the surface the user saw, then remove every `[DEBUG-xxxx]` probe and throwaway artifact.
|
|
10
11
|
|
|
11
|
-
**Reply:** what was broken, the root cause, the fix, and the failing-then-passing output.
|
|
12
|
+
**Reply:** what was broken, the root cause, the fix, and the failing-then-passing output; when the deciding fact took a deep dig, the always-on signal that would have shown it at first look, listed as a follow-up.
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the design.**
|
|
4
4
|
|
|
5
|
-
1. Align: learn how the affected subsystem works now, and name the data shape and its organizing structure (**Model the domain**, **Foundational thinking**) before any logic.
|
|
6
|
-
2. Act: when the change crosses a module, settle its interface first. Place the seam at an existing boundary; add one only for real variation, because one adapter is hypothetical and two demonstrate variation. Hide invariants and ordering behind the interface,
|
|
7
|
-
3. Act:
|
|
8
|
-
4. Act:
|
|
9
|
-
5.
|
|
5
|
+
1. Align: learn how the affected subsystem works now by reading every file the change touches, and name the data shape and its organizing structure (**Model the domain**, **Foundational thinking**, **Type system discipline**) before any logic. Do what every later phase leans on first, such as test infrastructure and shared types.
|
|
6
|
+
2. Act: when the change crosses a module, settle its interface first. Write two or three real call sites and derive the signatures from them. Place the seam at an existing boundary; add one only for real variation, because one adapter is hypothetical and two demonstrate variation. Hide invariants and ordering behind the interface, make it the test surface, and guard only where untrusted input enters (**Boundary discipline**). A module whose removal makes complexity vanish rather than move to callers is a pass-through; delete it. Screen the shape against [design-red-flags](../references/design-red-flags.md). With no precedent and a costly-to-reverse choice, compare two interface shapes on depth, locality, compatibility, and testability, or settle it with the `prototype` playbook; a user-owned trade-off goes to the user.
|
|
7
|
+
3. Act: for state that runs, give each actor its own state and merge at the read boundary; a lock added by reflex means the state was shared by mistake (**Separate before serializing shared state**). For an operation that mutates state, ask what happens when it runs twice or crashes halfway (**Make operations idempotent**).
|
|
8
|
+
4. Act: the settled interface is a signal, not an obstacle. Surface each deviation from it, and when the same workaround appears a second time, return to Align and reshape as if the constraints were there from day one, deleting before adding.
|
|
9
|
+
5. Act: when dispatching parallel workers, write the throughput checkpoint as four `todo` items, each `n/a: <reason>` when it does not apply: blocking first steps; independent workstreams; shared mutable state, split before serializing; the smallest safe decomposition. Work that is coupled in code (one feature, one migration) goes to a single owner; fan out only slices that produce independent artifacts. A bulk job a script can do is run by the coordinator (**Build the lever**), and a fan-out brief carries its recipe and check in a file the workers cannot edit. For three or more near-identical units, run one through brief, report, and check before launching the rest, so a flaw in the brief costs one worker.
|
|
10
|
+
6. Act: build in units that each end in a check, each commit passing alone (**Sequence verifiable units**). A shared primitive's improvement is ported to every consumer and verified on each.
|
|
11
|
+
7. Verify: on the surface the user will use; an inconclusive or wrong-surface result is not a pass.
|
|
10
12
|
|
|
11
13
|
**Reply:** what was built, the shape chosen and why, the checkpoint, and open decisions; a table when alternatives were compared.
|
|
12
14
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Perf
|
|
2
2
|
|
|
3
|
-
**You own the number.**
|
|
3
|
+
**You own the number.** The [benchmark checklist](../references/benchmark-checklist.md) holds the measurement checks; run it before any number is reported.
|
|
4
4
|
|
|
5
|
-
1. Anchor:
|
|
6
|
-
2. Act: **Explain the number**:
|
|
7
|
-
3. Act: one change at a time against the baseline
|
|
8
|
-
4. Verify: rerun the baseline workload under the same conditions.
|
|
5
|
+
1. Anchor: before measuring, write the claim you expect to ship, the result that would change the decision, and the noise floor (**Explain the number**); stop when the run-to-run spread exceeds the effect. Read what the script times and counts. Measure a baseline on the real workload, at least 5 runs per side alternating, as a median and range, after checking `uptime`. The harness prints its error count and the work it finished, and the behavior tests run green first. When the base lacks the feature, measure the work the diff adds and the end state, never a ratio between unlike scenarios. For an iterated run, prove the harness separates a known-slow case from a known-fast one, then freeze it.
|
|
6
|
+
2. Act: **Explain the number**: name the limiter from a profile or counters, and rule out a warm cache, a skipped path, a debug build, an untuned side, and a piece too small to matter end to end. Profile before changing code.
|
|
7
|
+
3. Act: one change at a time against the baseline, trying the cheapest idea first: do not do the work, do not redo it, do less of it, do it later, do it concurrently, do it more cheaply. Keep a change only when its gain sits outside the noise and the behavior tests stay green, and revert the rest.
|
|
8
|
+
4. Verify: rerun the baseline workload under the same conditions, alternating base and change runs.
|
|
9
9
|
|
|
10
|
-
**Reply:** faster, slower, no measurable difference, or inconclusive, with run counts, ranges, what limits the number,
|
|
10
|
+
**Reply:** faster, slower, no measurable difference, or inconclusive (a claimed difference with no named limiter, an untuned side, or unchecked errors and work), with run counts, ranges, the delta, what limits the number, the profile that pointed at the change, the harness path, and the best idea left untried.
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the behavior contract. The structure changes; the behavior does not.**
|
|
4
4
|
|
|
5
|
-
1. Anchor: pin current behavior with a characterization test, snapshot, or equivalence run before anything moves; a type check and lint are not a pin.
|
|
6
|
-
2. Align: name the target shape as if built today, and the branches or invalid states it deletes. A reshape that only adds indirection is not one.
|
|
7
|
-
3. Act: **Subtract before you add
|
|
5
|
+
1. Anchor: from a clean trunk, pin current behavior with a characterization test, snapshot, or equivalence run before anything moves; a type check and lint are not a pin.
|
|
6
|
+
2. Align: name the target shape as if built today, and the branches or invalid states it deletes. A reshape that only adds indirection is not one. A redesign that changes behavior is allowed; name it and route it to `feature`.
|
|
7
|
+
3. Act: **Subtract before you add**, in its own commit ahead of the reshape and any follow-on cleanup, so each diff reads alone.
|
|
8
8
|
4. Act: move in small steps with the pin green. **Migrate callers, then delete**. Check each rename against strings, prose, and back-references.
|
|
9
9
|
5. Act: a bug or missing feature found on the way becomes a follow-up; the structural change ships against the pinned contract first.
|
|
10
|
-
6. Verify: prove equivalence on the real artifact, then confirm reader load dropped (**Minimize reader load**); when
|
|
10
|
+
6. Verify: prove equivalence on the real artifact, then confirm reader load dropped (**Minimize reader load**): a new reader answers "where does X come from?" and "what can change X?" in under 30 seconds, with state derived instead of synced; when that fails, revert.
|
|
11
11
|
|
|
12
12
|
**Reply:** the structure that changed, the pin, the equivalence evidence, the reader-load change, and what was reverted.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Benchmark checklist
|
|
2
|
+
|
|
3
|
+
Run it before reporting a performance number. Each item names the way a number comes out wrong.
|
|
4
|
+
|
|
5
|
+
1. **Claim.** Write the sentence you expect to ship, the result that would change the decision, and the noise floor, before the first run. A claim shaped after the numbers arrive fits whatever they say.
|
|
6
|
+
2. **Script.** Read what the measurement script times, counts, and ignores. A timer that covers setup, or the wrong function, measures something else.
|
|
7
|
+
3. **Same footing.** Run every compared side the way production runs it: release build, flags, pools, and caches as warm or cold as production, with the same data and versions. A side on defaults means you compared configurations, so no winner follows from that run.
|
|
8
|
+
4. **Work done.** The harness prints its error count and the units of work it finished. Fast failures and lazy code (a generator nobody iterates, a promise nobody awaits) look like speed. Confirm the work ran inside the timed region.
|
|
9
|
+
5. **Quiet machine.** Read `uptime` and the core count first; stop competing work, or interleave the sides when you cannot. Orphan processes and a busy box turn drift into a "gain".
|
|
10
|
+
6. **Counts.** At least 5 runs per side, alternating (A, B, A, B), reporting the median and range. A gap inside the run-to-run range is "no measurable difference". The base and the change alternate too, so thermal and cache drift hit both.
|
|
11
|
+
7. **Limits.** Removing a piece that takes 10% of the run speeds it up by at most about 11%. Report a micro result as a share of the end-to-end path. A number past a hardware limit (disk, core count, network) measured something other than the work.
|
|
12
|
+
8. **Limiter.** Ask why not double. Name the limiter from a profile or system counters; a guess from reading the code is not one. Profile in a run you do not report, because profilers slow the work, and when the load generator saturates first, you measured the load generator.
|
|
13
|
+
9. **Behavior.** The behavior tests run green before the baseline and after each change. A faster run that fails them, or that returns different output, is reverted.
|
|
14
|
+
|
|
15
|
+
The verdict is `inconclusive` when you claim a difference but cannot name the limiter, a side ran untuned, or you could not check items 4 and 7.
|
|
16
|
+
|
|
17
|
+
A quick ballpark the user asked for needs one run. Still check items 4 and 7 and say it is one run; a choice between options is never a ballpark.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Adapted from pstack `benchmark-checklist` by Lauren Tan (MIT License), revision `c742dd6` of cursor/plugins.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Design red flags
|
|
2
|
+
|
|
3
|
+
The next contributor may be an agent that sees only the files it opened and copies the nearest example. Screen a new shape for these before building it; each one lets an edit that is right in one file be wrong across the repo.
|
|
4
|
+
|
|
5
|
+
- **Shallow module.** The interface is nearly as complex as what it hides. Callers learn the internals anyway.
|
|
6
|
+
- **Information leakage.** Transport, storage, or wire types appear in the public surface (**Boundary discipline**). Callers come to depend on the encoding.
|
|
7
|
+
- **Temporal decomposition.** Modules named for phases (load, validate, transform, save) repeat the same domain rule in each. Split by what changes together.
|
|
8
|
+
- **Pass-through.** A layer forwards its arguments and adds nothing. Delete it.
|
|
9
|
+
- **Split ownership.** More than one module writes the same state. Give each actor its own state and merge at the read boundary (**Separate before serializing shared state**).
|
|
10
|
+
- **Two ways to one task.** Two entry points reach the same outcome, so the next agent picks the wrong one. Keep one and delete the other.
|
|
11
|
+
- **Importable internals.** A module's private parts can be imported from outside. Make an outside import fail the build.
|
|
12
|
+
- **Hand-synced list.** Two lists must change together. Derive one from the other, or make the build fail when they disagree.
|
|
13
|
+
|
|
14
|
+
A shape that survives the screen is the one where the same edit made from one file stays correct repo-wide, with drift caught by the build, not by prose.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Adapted from pstack `architect` (`references/design-red-flags.md`) by Lauren Tan (MIT License), revision `c742dd6` of cursor/plugins.
|
|
@@ -80,4 +80,4 @@ confirmed correction target.
|
|
|
80
80
|
|
|
81
81
|
## 5. Reflexive System Placement
|
|
82
82
|
|
|
83
|
-
When feedback conveys a preference or convention rather than an isolated code bug, hand the preference to `reflecting-to-root` and any procedure change to `solid-loop`.
|
|
83
|
+
When feedback conveys a preference or convention rather than an isolated code bug, hand the preference to `reflecting-to-root` and any procedure change to `solid-loop`. A correction of a mistake an instruction already forbids is a repeat: invoke `solid-loop` in the same change to raise its enforcement, because restating the prose rule has already failed once.
|
|
@@ -45,5 +45,5 @@ For each scoped item:
|
|
|
45
45
|
| [item] | [verdict] | [evidence] |
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Lead with the conclusion. Prioritize failures and recommended actions by impact. Name any unverified boundary instead of implying full coverage.
|
|
48
|
+
Lead with the conclusion. Prioritize failures and recommended actions by impact. Name any unverified boundary instead of implying full coverage. Count the findings you rejected or could not reproduce, each with its reason; zero findings is a valid result, stated as such, because a report of survivors alone cannot tell "found nothing" from "found five and dropped them".
|
|
49
49
|
|
|
@@ -47,6 +47,12 @@ Quote or point to the governing requirement for each finding. When no spec is
|
|
|
47
47
|
available, mark this axis insufficient evidence instead of reconstructing intent
|
|
48
48
|
from the implementation.
|
|
49
49
|
|
|
50
|
+
### Beyond the diff
|
|
51
|
+
|
|
52
|
+
Read what the diff cannot show: serialized shapes (JSON, a DB column, a wire format) and the other-language readers of the same bytes, flags, timing and teardown order, and the pinned source of each dependency the change calls, because grep stops at callers. Keep the risks you confirmed and list those you checked and cleared apart.
|
|
53
|
+
|
|
54
|
+
When a load-bearing scenario fails, run it on the base too. A failure present on both is recorded against the base and blocks only when the diff copies it or newly reaches it. When the base lacks the feature, check the behavior the diff adds and compare no ratio between unlike scenarios.
|
|
55
|
+
|
|
50
56
|
**Reply:** separate `Standards` and `Spec` verdicts with file/hunk evidence, and
|
|
51
57
|
a finding count and worst issue within each axis, never one combined score,
|
|
52
58
|
because success on one axis cannot mask failure on the other.
|
|
@@ -8,12 +8,14 @@ description: Use when researching questions, diagnosing root causes without fixi
|
|
|
8
8
|
Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md). The anchor is the exact question and its completion boundary: answered, or the missing evidence named precisely.
|
|
9
9
|
|
|
10
10
|
1. Gather evidence through the playbook below that fits the question.
|
|
11
|
-
2. Cross-check material claims
|
|
11
|
+
2. Cross-check material claims. When sources conflict, report both with citations unless a run settles it; evidence about a neighboring subject is not an answer.
|
|
12
12
|
3. Grade each material claim by its strongest evidence: asserted, cited
|
|
13
|
-
(`file:line` or primary source), reasoned (the
|
|
14
|
-
not to reach), executed (a script or test
|
|
15
|
-
reproduced (observed in the running system). A
|
|
16
|
-
`
|
|
13
|
+
(a `file:line` or primary source you opened this session), reasoned (the
|
|
14
|
+
failure path walked and shown not to reach), executed (a script or test
|
|
15
|
+
against the real code), or reproduced (observed in the running system). A
|
|
16
|
+
claim a subagent relayed stays `asserted` until you open its cited line or
|
|
17
|
+
rerun its command. A claim with no evidence is `unknown`, with the queries
|
|
18
|
+
and sources tried beside it, so the next reader skips the empty search.
|
|
17
19
|
4. Report the reasoning chain with each material claim's source and grade beside it.
|
|
18
20
|
|
|
19
21
|
## Playbooks
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the diagnosis.** The deliverable explains the symptom; a fix goes to the `coding` bug-fix playbook.
|
|
4
4
|
|
|
5
|
-
1. Observe the symptom first through logs, metrics, traces, a profile, or a reproduction, before forming a theory from code.
|
|
5
|
+
1. Observe the symptom first through logs, metrics, traces, a profile, or a reproduction, before forming a theory from code. Reduce a large capture (log, profile, trace, heap snapshot) by script or subagent into a queryable form and read the reduced finding, because a raw dump overflows the lead's context.
|
|
6
6
|
2. Write the candidate causes with the observation each predicts, and rule them out one at a time against runtime evidence.
|
|
7
7
|
3. Confirm the surviving mechanism by a prediction that would fail if it were wrong.
|
|
8
8
|
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the answer.** Read-only: the deliverable is a cited answer or a recommendation, not a change.
|
|
4
4
|
|
|
5
|
-
1. Code: LSP (`read_symbol`) for symbols and ast-grep for structure; text search for prose, configuration, and literals; history (`git log -S`, blame) when the question is why or since when.
|
|
5
|
+
1. Code: LSP (`read_symbol`) for symbols and ast-grep for structure; text search for prose, configuration, and literals; history (`git log -S`, blame) when the question is why or since when. For why, also query each ticket, doc, chat, and error-tracking tool this session has, and list the ones not searched with the reason, because the stated reason often sits there and not in git.
|
|
6
6
|
2. External facts: current primary sources (official documentation, source code, specifications, first-party APIs) over summaries of them.
|
|
7
|
-
3.
|
|
7
|
+
3. Cite intent ('because', 'was designed to') only from what an author wrote: a commit, PR, ticket, comment, or document. An intent read off the code or the latest commit is `reasoned` at best, stated as inference; a hypothesis in the question is a candidate to test, not to confirm.
|
|
8
|
+
4. **Observe, don't ask.**
|
|
8
9
|
|
|
9
|
-
**Reply:** the answer first, then the chain with each claim's source and grade; for a choice, a trade-off table and a recommendation, pushing back when the premise is wrong.
|
|
10
|
+
**Reply:** the answer first, then the chain with each claim's source and grade; for a choice, a trade-off table and a recommendation, pushing back when the premise is wrong; when the answer precedes a change, the constraints it sets (preserve, change, avoid, risk).
|
|
@@ -5,17 +5,17 @@ description: Use when creating, editing, or auditing agent skills and instructio
|
|
|
5
5
|
|
|
6
6
|
# Solid Loop
|
|
7
7
|
|
|
8
|
-
Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md). The anchor is `uv run python hooks/validate_all.py .` or the project's own validator, clean,
|
|
8
|
+
Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md). The anchor is `uv run python hooks/validate_all.py .` or the project's own validator, clean, every edited section passing the no-op test, and, when the change answers a recorded failure, a fresh-context rerun of that task in which the failure no longer occurs, or `rerun: n/a — <reason>` when no safe slice exists (see [author-skill](playbooks/author-skill.md)).
|
|
9
9
|
|
|
10
10
|
The root virtue is **predictability**: each instruction sends the next run straight to the work, with no detour and no unneeded read.
|
|
11
11
|
|
|
12
12
|
## Placement
|
|
13
13
|
|
|
14
|
-
Put each fact where it stays true. One that holds for every task type goes to the `anchorloop` core; one that holds for one task type goes to its entry skill or playbook; one that holds for one project goes to that project's `AGENTS.md` or `CLAUDE.md`. A multi-step procedure no skill owns becomes a playbook, or a skill when no entry fits.
|
|
14
|
+
Put each fact where it stays true. One that holds for every task type goes to the `anchorloop` core; one that holds for one task type goes to its entry skill or playbook; one that holds for one project goes to that project's `AGENTS.md` or `CLAUDE.md`. A multi-step procedure no skill owns becomes a playbook, or a skill when no entry fits; propose one in the reply when you meet the same workflow a second time.
|
|
15
15
|
|
|
16
16
|
## Mechanism
|
|
17
17
|
|
|
18
|
-
Enforce at the highest level that works, because nothing fails when an agent skips prose: architecture that removes the wrong path; a script for repeated deterministic work; a type, lint, or test; a tool-loop lever (pi extension hook, stream rule, validator) for a check the model demonstrably skips, with a message that names the fix. Prove the check fails on the recorded mistake. Prose is for judgment calls. A `Found` fact the agent system already states in prose is a repeat: escalate it in the same change. List each enforced rule beside its enforcer in the owning instruction file's rule table, and drop the row once the mistake can no longer happen.
|
|
18
|
+
Enforce at the highest level that works, because nothing fails when an agent skips prose: architecture that removes the wrong path; a script for repeated deterministic work; a type, lint, or test; a tool-loop lever (pi extension hook, stream rule, validator) for a check the model demonstrably skips, with a message that names the fix. Prove the check fails on the recorded mistake. A check that existing code already violates fails only on additions; an exception sits on its line with a reason, an expiry, and the user's approval; the same command runs locally and in CI, because a rule that differs between them makes the rule table lie. Prose is for judgment calls. A `Found` fact the agent system already states in prose is a repeat: escalate it in the same change. List each enforced rule beside its enforcer in the owning instruction file's rule table, and drop the row once the mistake can no longer happen.
|
|
19
19
|
|
|
20
20
|
## Hold the Size
|
|
21
21
|
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
1. A note with no before/after contrast (the failed attempt and what revealed the cause) gets no placement; record it as unsupported.
|
|
6
6
|
2. Correct each misdirection: open the line named in `Led by` and rewrite it to state what `Found` established, or delete it when it has no correct form.
|
|
7
|
-
3. Place each gap: search the agent system for a statement of the `Found` fact. When one exists, the run could not reach it: sharpen the pointer or description that should have led there. When none exists, write it as one direct sentence where **Placement** puts it. A fact the change itself resolved, or a tool slip no project or skill owns, needs no placement.
|
|
8
|
-
4. Choose the **Mechanism** before writing prose, then **Hold the Size**.
|
|
7
|
+
3. Place each gap: search the agent system for a statement of the `Found` fact. When one exists, the run could not reach it: sharpen the pointer or description that should have led there. When none exists, write it as one direct sentence where **Placement** puts it. A fact the change itself resolved, or a tool slip no project or skill owns, needs no placement. A `Found` fact that names a SHA, tool version, or run-specific path is rewritten as the durable rule or enforced by a check, because the detail drifts.
|
|
8
|
+
4. Choose the **Mechanism** before writing prose, then **Hold the Size**. An action that stays prose says why no higher level held it: `; not higher because <the architecture, script, lint, or test that cannot hold it>`.
|
|
9
9
|
|
|
10
10
|
**Reply:** one pair per note:
|
|
11
11
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
2. For a new skill or playbook, have the model attempt the task without it and record where it fails; the first version covers those failures and nothing more.
|
|
7
7
|
3. A new skill starts from [the template](../references/template-skill.md); a new playbook copies an existing one's shape (ownership line, steps, `Reply:`).
|
|
8
8
|
4. Apply the **Craft Levers**, then **Hold the Size**.
|
|
9
|
-
5.
|
|
9
|
+
5. For a change that answers a recorded failure, rerun the smallest slice of that task that exercised the edited instruction, in a fresh-context worker with the edited skill, in a clean directory or disposable worktree, with outward-facing steps (push, deploy, tickets, chat) out of scope in the brief; when no safe slice exists, record `rerun: n/a — <reason>` and rest on the validator and the no-op test. Phrase it as ordinary work with no mention of testing, and judge from the files the worker read and the shape of its output, not its claims, because a worker told it is tested reads more carefully than a real run does. The recorded failure must not recur. To compare variants, give each the same organic prompt in a clean directory and read the tool-call transcripts yourself.
|
|
10
|
+
6. Fix a broken skill met mid-task in its own change, not tangled into the task's diff.
|
|
10
11
|
|
|
11
|
-
**Reply:** the files changed with the net line count of each, the layer,
|
|
12
|
+
**Reply:** the files changed with the net line count of each, the layer, the bare-run failures the change covers, and the rerun's before and after.
|
package/skills/writing/SKILL.md
CHANGED
|
@@ -7,10 +7,11 @@ description: Use when writing or revising documentation, a README, an article, a
|
|
|
7
7
|
|
|
8
8
|
Run the loop in [../anchorloop/SKILL.md](../anchorloop/SKILL.md). The anchor is a reader without the conversation's context: hand the text to a fresh subagent and check it can say what the text asks of its reader. Comment-only work also keeps the project's tests green.
|
|
9
9
|
|
|
10
|
-
Short declarative sentences
|
|
10
|
+
Short declarative sentences, written whole: articles and verbs kept, arrows and abbreviations spelled out, and every item the playbook's `Reply:` line names present, because compression moves the decoding work to the reader. Each claim carries its evidence or reads as an estimate, and says something about this project: cut a sentence that would fit unchanged in another project, and name the mechanism or a number in place of a feeling. Use the word a developer would say aloud, give a coined name its meaning at first use, and point each pronoun at one obvious referent, repeating the noun when unsure. Open with the point and stop when it is made; attribute a "studies show" or leave it out.
|
|
11
11
|
|
|
12
12
|
## Playbooks
|
|
13
13
|
|
|
14
14
|
- [draft](playbooks/draft.md): a new document.
|
|
15
15
|
- [tighten](playbooks/tighten.md): revising or shortening existing text.
|
|
16
16
|
- [comments](playbooks/comments.md): removing or rewriting code comments.
|
|
17
|
+
- [pr-description](playbooks/pr-description.md): a pull or merge request description or a commit body, once opening is authorized.
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
**You own the comments, not the code.** No behavior changes.
|
|
4
4
|
|
|
5
|
-
1. Keep a comment only for a non-obvious why the code cannot show: a constraint, a workaround with its cause, a
|
|
5
|
+
1. Keep a comment only for a non-obvious why the code cannot show and whose cause lies outside this codebase (vendor, platform, protocol): a constraint, a workaround with its cause. Also keep license headers, doc comments that define a public API contract, tool directives, and links to the issue or RFC behind a constraint.
|
|
6
6
|
2. Delete comments that narrate what the code does, mark phases, or restate names; a test or script documents its step through its assertion text.
|
|
7
|
-
3.
|
|
8
|
-
4.
|
|
7
|
+
3. A comment that asserts a constraint ("IMPORTANT", "do not remove") stays only after you check on the named symbol that it holds today; delete one you cannot verify and report it, because an unchecked claim protects dead code.
|
|
8
|
+
4. A surprise in our own code, or a constraint the code could enforce (a type, an assertion, a check), is a reshape target: report it as a follow-up with the comment's text and the exact symbol, and drop the comment.
|
|
9
|
+
5. List each lint or type suppression (`eslint-disable`, `@ts-ignore`, `noqa`) with the rule it silences; where that rule guards correctness or safety, report the suppressed symbol as a follow-up. The directive stays in this pass.
|
|
10
|
+
6. Verify that the diff touches only comments and that the project's tests still pass.
|
|
9
11
|
|
|
10
|
-
**Reply:** comments removed and rewritten by count, the follow-ups, and the test result.
|
|
12
|
+
**Reply:** comments removed and rewritten by count, the follow-ups, the suppressions listed, and the test result.
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
**You own whether the reader can act on it.**
|
|
4
4
|
|
|
5
5
|
1. Name the reader, what they already know, and the decision or action the text serves; open with that.
|
|
6
|
-
2. Pick one mode (tutorial, how-to, reference, or explanation) and keep each section in it.
|
|
7
|
-
3. Link to the source of a fact instead of copying it; a copied fact drifts.
|
|
6
|
+
2. Pick one mode (tutorial, how-to, reference, or explanation) and keep each section in it; opinion belongs to explanation only, so split and link instead of mixing.
|
|
7
|
+
3. Link to the source of a fact instead of copying it; a copied fact drifts. A count, list, or tree you must state is regenerated at the landing commit and carries the command that produces it.
|
|
8
8
|
4. Open terms or decisions go to `grilling`, or to `domain-modeling` when they are domain terms.
|
|
9
|
+
5. Name things as the codebase does: the exact symbol, file, flag, or command, one name per concept. In a procedure put the condition before the instruction and the common case before its exceptions.
|
|
9
10
|
|
|
10
11
|
**Reply:** the document path, its reader and purpose, and the reader check's result.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# PR description
|
|
2
|
+
|
|
3
|
+
**You own the reviewer's first minute.** The reader has the diff and needs the reasons. Write the text once opening the PR or MR is authorized; this playbook never opens one.
|
|
4
|
+
|
|
5
|
+
1. Why: the problem and the approach, in one to three short sentences.
|
|
6
|
+
2. What changed and what it deliberately leaves out, a follow-up or a known gap included.
|
|
7
|
+
3. What it could break: who and what it touches, and why that is safe or risky.
|
|
8
|
+
4. Verification: the anchor command and what it observed, then each requirement left `unknown`. Tradeoffs appear only for a rejected alternative the reviewer would ask about.
|
|
9
|
+
5. Link logs, SHA lists, and tables instead of pasting them. A commit body adds what the subject cannot hold and does not restate it.
|
|
10
|
+
|
|
11
|
+
**Reply:** the description text and the artifacts it links.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Adapted from [pstack](https://github.com/backnotprop/pstack) by Lauren Tan (MIT License), revision `c742dd6` of [cursor/plugins](https://github.com/cursor/plugins/tree/main/pstack), `skills/poteto-mode/playbooks/opening-a-pr.md`.
|