monkeyshape 0.1.0 → 0.2.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 +13 -37
- package/docs/workflow.md +131 -0
- package/package.json +5 -1
- package/skills/handoff/SKILL.md +54 -0
- package/skills/milestone/SKILL.md +107 -0
- package/skills/review-pr/SKILL.md +135 -0
- package/skills/roadmap/SKILL.md +66 -0
- package/skills/track/SKILL.md +75 -0
- package/src/adapters/init.ts +176 -0
- package/src/adapters/process.ts +38 -0
- package/src/adapters/reviews.ts +170 -0
- package/src/adapters/skills.ts +113 -0
- package/src/adapters/tracks.ts +616 -0
- package/src/adapters/workspace.ts +48 -35
- package/src/cli/main.ts +300 -63
- package/src/core/check.ts +29 -4
- package/src/core/handoff.ts +183 -0
- package/src/core/hooks.ts +60 -0
- package/src/core/layout.ts +98 -26
- package/src/core/markdown.ts +93 -0
- package/src/core/model.ts +24 -1
- package/src/core/refs.ts +19 -13
- package/src/core/scaffold.ts +90 -0
- package/src/core/skills.ts +291 -0
- package/src/core/tracks.ts +358 -0
- package/src/schemas/config.ts +20 -0
- package/src/schemas/errors.ts +9 -0
- package/template/.github/pull_request_template.md +11 -0
- package/template/.github/workflows/ci.yml +22 -0
- package/template/AGENTS.md +37 -0
- package/template/CLAUDE.md +1 -0
- package/template/DECISIONS.md +8 -0
- package/template/README.md +14 -0
- package/template/docs/roadmap.md +14 -0
- package/template/gitignore +7 -0
- package/template/notes/.gitkeep +0 -0
- package/template/plan/.gitkeep +0 -0
- package/template/shape.config.ts +26 -0
- package/template/test/toolchain.test.ts +7 -0
package/README.md
CHANGED
|
@@ -19,49 +19,24 @@ src/core/client.ts arch/host-access
|
|
|
19
19
|
mshape check failed: 2 problems
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Quick start
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
|
-
|
|
25
|
+
bunx --package monkeyshape mshape init my-app
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
A new repo whose gate (`bun run check`) passes, with one starter test: Bun, TypeScript, Effect,
|
|
29
|
+
beads, the configs, CI, and five skills for your coding agent. Then the working loop, one chat each:
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// biome.json
|
|
38
|
-
{
|
|
39
|
-
"root": true,
|
|
40
|
-
"extends": ["monkeyshape/biome"],
|
|
41
|
-
"files": { "includes": ["src/**", "test/**", "shape.config.ts", "*.json"] }
|
|
42
|
-
}
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
// shape.config.ts
|
|
47
|
-
import { defineConfig } from "monkeyshape";
|
|
48
|
-
|
|
49
|
-
export default defineConfig({
|
|
50
|
-
arch: {
|
|
51
|
-
modules: {
|
|
52
|
-
core: { description: "Deterministic logic. No host I/O." },
|
|
53
|
-
adapters: { description: "Host I/O behind services.", mayImport: ["core"], hostAccess: true },
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
```md
|
|
60
|
-
<!-- AGENTS.md -->
|
|
61
|
-
# My project: commands, gotchas and decision authority for agents, in 150 lines or fewer.
|
|
62
|
-
```
|
|
31
|
+
1. `/roadmap` with a brain-dump: the direction, and one deferred epic per goal.
|
|
32
|
+
2. `/milestone` with your priorities: a plan with acceptance on real data, beads, and
|
|
33
|
+
tracks, each its own worktree from `mshape track new`.
|
|
34
|
+
3. `/track` in each track's worktree: the agent works its queue and opens PRs.
|
|
35
|
+
4. `/handoff` when a chat's context runs low; a fresh chat runs `/track` to continue.
|
|
36
|
+
5. `/review-pr <n>` in its own chat; you merge.
|
|
63
37
|
|
|
64
|
-
|
|
38
|
+
The conventions in full: [docs/workflow.md](docs/workflow.md). An existing repo:
|
|
39
|
+
[docs/adopting.md](docs/adopting.md).
|
|
65
40
|
|
|
66
41
|
## What `mshape check` enforces
|
|
67
42
|
|
|
@@ -72,6 +47,7 @@ Then make it your gate: `tsc && biome ci --error-on-warnings && mshape check &&
|
|
|
72
47
|
| `refs` | Docs and comments that point at paths, scripts or decisions that don't exist |
|
|
73
48
|
| `budgets` | Bloated `AGENTS.md`, decision logs and memories; oversized files |
|
|
74
49
|
| `coverage` | Code that escaped the typechecker or the linter and rots silently |
|
|
50
|
+
| `skills` | Installed skills that agents can't see (a broken `.claude/skills` link) or that lag the package |
|
|
75
51
|
|
|
76
52
|
Existing violations can be grandfathered with `mshape baseline --init`; counts may then only
|
|
77
53
|
go down. Every escape hatch (`// shape-ignore <rule>: <reason>`, config allowances) needs a reason.
|
package/docs/workflow.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# The working loop
|
|
2
|
+
|
|
3
|
+
How a repo made by `mshape init` is worked, by a human and coding agents together. Read this
|
|
4
|
+
once after `init`; the skills it names carry the detail, so you don't need it again.
|
|
5
|
+
|
|
6
|
+
The split: **skills carry judgement, the `mshape` CLI carries everything deterministic.** A
|
|
7
|
+
skill interviews, proposes, writes prose and grooms beads; it never builds a worktree or a
|
|
8
|
+
file layout by hand, because the CLI does that and is tested. Each skill is started by name
|
|
9
|
+
in a fresh chat, so your message can be just the skill and your intent.
|
|
10
|
+
|
|
11
|
+
## Three horizons, three files
|
|
12
|
+
|
|
13
|
+
Plan in detail only what is near. Each horizon has one home and one way of staying true.
|
|
14
|
+
|
|
15
|
+
| Horizon | Home | Written by | Kept true by |
|
|
16
|
+
|---|---|---|---|
|
|
17
|
+
| Direction: months | docs/roadmap.md, plus one deferred beads epic per goal | `/roadmap` | Rewritten in place at each milestone boundary |
|
|
18
|
+
| Milestone: several PRs from several agents | plan/MILESTONE.md | `/milestone` | Frozen for the milestone, replaced at the next |
|
|
19
|
+
| Track state: today | the track's handoff, in `.handoffs` | `/track`, `/handoff` | Overwritten at every handoff |
|
|
20
|
+
|
|
21
|
+
- **The roadmap** opens with a status table, so nobody reads the design as a spec. It is
|
|
22
|
+
never cited by code or by normative docs (AGENTS.md, DECISIONS.md, skills): name the file,
|
|
23
|
+
but the refs check rejects links into its sections. Its goals are deferred epics with no children until a milestone pulls them
|
|
24
|
+
in, so they never crowd `bd ready`.
|
|
25
|
+
- **The milestone plan** says the goal and how you'll know it is met on real data, where
|
|
26
|
+
things stand, the tracks with their beads and acceptance, the interfaces between tracks,
|
|
27
|
+
decision points and what is deferred. When a track diverges from it, the track says so in
|
|
28
|
+
its handoff; a divergence that changes another track's work is a conversation with the
|
|
29
|
+
human, not an edit to the plan. Only handoffs and beads cite it.
|
|
30
|
+
- **A handoff** is what a fresh chat reads to continue a track, and what the human reads to
|
|
31
|
+
decide what to relay. Handoffs live inside git's directory and are linked into every
|
|
32
|
+
checkout as `.handoffs`; they are never committed, so there is one live copy.
|
|
33
|
+
|
|
34
|
+
What a change did and what it showed goes in the **PR body**, which is the narrative the
|
|
35
|
+
human actually reads. Long investigations go in a dated note under `notes/`, which nothing
|
|
36
|
+
normative may cite.
|
|
37
|
+
|
|
38
|
+
Everything else has one home too:
|
|
39
|
+
|
|
40
|
+
- A rule a machine can check is **a check**, whose message gives the reason and the fix. A
|
|
41
|
+
domain invariant is **a test named after it**. The local reason for some code is **a
|
|
42
|
+
comment at that code**.
|
|
43
|
+
- **DECISIONS.md** holds only live decisions worth their budget: a surprising external fact
|
|
44
|
+
that was measured, or a choice between real alternatives that would be expensive to undo.
|
|
45
|
+
The best entries name the tempting wrong fix. A feature design isn't one; it goes in the
|
|
46
|
+
code.
|
|
47
|
+
- **Notes** are immutable: write a new one instead of updating an old one. A lesson that
|
|
48
|
+
should apply going forward is promoted to a check, a test or a decision.
|
|
49
|
+
|
|
50
|
+
## The loop
|
|
51
|
+
|
|
52
|
+
| Step | Started by | What happens |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| Init | you: `mshape init <name>` | A new repo whose gate passes, with one starter test: template, toolchain, beads, the five skills, the handoffs store. |
|
|
55
|
+
| Long term | chat: `/roadmap` + a brain-dump | Interview until goals are clear; write docs/roadmap.md; one deferred epic per goal; open a PR. |
|
|
56
|
+
| Mid term | chat: `/milestone` + priorities | Retrospective on the last milestone; agree a goal with acceptance on real data; write plan/MILESTONE.md; groom beads and the roadmap; garden; create the tracks with `mshape track new`; remove finished ones. |
|
|
57
|
+
| Short term | chat in a track's worktree: `/track` | Read the handoff and the track's queue; work; open PRs. |
|
|
58
|
+
| Hand off | you, near 75% of a chat's context: `/handoff` | The handoff is rewritten so a fresh chat can continue; open one in the same worktree and run `/track`. |
|
|
59
|
+
| Review | chat: `/review-pr <number>` | Review against real data in a scratch worktree (`mshape review <n>`); findings go on the PR; you merge. |
|
|
60
|
+
|
|
61
|
+
A first repo goes: `mshape init`, then `/roadmap`, then `/milestone`, then one chat per track
|
|
62
|
+
running `/track`. The first milestone of a new repo is "a first result on a real target".
|
|
63
|
+
|
|
64
|
+
## Tracks
|
|
65
|
+
|
|
66
|
+
A track is one line of parallel work: a name, a git worktree, a branch, a beads label and a
|
|
67
|
+
handoff, all derived from the name by `mshape track`:
|
|
68
|
+
|
|
69
|
+
- `mshape track new <name>` creates the worktree `.agents/worktrees/<repo>@<name>`, the branch
|
|
70
|
+
`track/<name>` and the handoff, and links the shared paths from `shape.config.ts`
|
|
71
|
+
(gitignored data such as a dataset) into the worktree.
|
|
72
|
+
- `mshape track list` shows the tracks and each one's open beads; `mshape track current`
|
|
73
|
+
names the track of the current directory, and fails with a reason anywhere else.
|
|
74
|
+
- `mshape track rm <name>` removes a finished track. It refuses while the worktree has
|
|
75
|
+
uncommitted work or the branch has unmerged commits, and says which; `--force` discards
|
|
76
|
+
them. Merged means in `main` or in its upstream, which `rm` fetches first, so a PR merged
|
|
77
|
+
on the remote counts before anyone pulls; a merge commit, a rebase and a squash all count. It also refuses while any bead labelled `track:<name>` isn't closed, and `--force`
|
|
78
|
+
doesn't override that: close each one, or move it to the track that will do it.
|
|
79
|
+
|
|
80
|
+
Its beads carry the label `track:<name>`; its queue is `bd ready --label track:<name>`. An
|
|
81
|
+
empty queue doesn't mean the track is done: `bd ready` leaves out beads in progress or blocked.
|
|
82
|
+
The track is done when `mshape track list` shows it with 0 open beads and `merged: yes`.
|
|
83
|
+
|
|
84
|
+
**Ad-hoc tracks.** For work that didn't come from a milestone, run `mshape track new <name>`
|
|
85
|
+
yourself, open a chat in the worktree it prints and run `/track`. The handoff starts as a
|
|
86
|
+
stub, so `/track` interviews you about the work and writes the charter and its beads.
|
|
87
|
+
`mshape track rm <name>` when it's merged.
|
|
88
|
+
|
|
89
|
+
**When to hand off.** At a natural break, around 75% of the context window. A handoff
|
|
90
|
+
records state, lessons not yet promoted, traps and messages for other tracks; you relay
|
|
91
|
+
those messages by pasting them where they belong, or by asking the track's next chat to read
|
|
92
|
+
the other handoff.
|
|
93
|
+
|
|
94
|
+
## Pull requests and review
|
|
95
|
+
|
|
96
|
+
- Agents commit, push and open PRs; the human merges. A track has one PR open at a time, from
|
|
97
|
+
its branch. Batch a track's beads into PRs of one theme, typically 1k to 2.5k changed
|
|
98
|
+
lines: many small PRs cost more review than a few large ones. That is a default for
|
|
99
|
+
batching, not a gate: a small PR is fine when it unblocks work or keeps docs in step with
|
|
100
|
+
code.
|
|
101
|
+
- The PR body says what changed and why, the evidence on real data, the gate output, the bug
|
|
102
|
+
class a new check closes, what is not done, and the beads closed or filed.
|
|
103
|
+
- `bun run check` is the gate, the same locally and in CI. It is green before every PR.
|
|
104
|
+
- `/review-pr` runs in its own chat, in a detached worktree at the PR's head that
|
|
105
|
+
`mshape review <n>` makes and `mshape review rm <n>` removes. A review is not a track: it
|
|
106
|
+
has no handoff, and everything about it lives on the PR. A review holds the PR to 95%,
|
|
107
|
+
not 100%: a blocker is a defect the PR would ship, and the skill says what counts. It
|
|
108
|
+
takes as many rounds as that needs, and LGTM means nothing is open. You merge, and can
|
|
109
|
+
step in at any point.
|
|
110
|
+
|
|
111
|
+
## Beads
|
|
112
|
+
|
|
113
|
+
- A bead points to intent; it isn't a spec. Keep it short: the intent, why, and an outcome
|
|
114
|
+
as acceptance.
|
|
115
|
+
- Three kinds: deferred direction epics (no children), milestone stories labelled by track,
|
|
116
|
+
and interface beads between tracks with an owner and a consumer.
|
|
117
|
+
- **Process beads.** When the process itself gets in the way, file a bead labelled
|
|
118
|
+
`process` saying what broke (`bd create --labels process ...`). `/milestone` reviews them
|
|
119
|
+
at the boundary, and fixes that are general land upstream in monkeyshape.
|
|
120
|
+
|
|
121
|
+
## The milestone boundary
|
|
122
|
+
|
|
123
|
+
The only ceremony, and `/milestone` runs all of it; the skill holds the steps. Between
|
|
124
|
+
boundaries, tracks just work their queues.
|
|
125
|
+
|
|
126
|
+
## Who decides
|
|
127
|
+
|
|
128
|
+
AGENTS.md has a decision-authority section; fill it in for your repo. The default: humans
|
|
129
|
+
own priorities, milestones, merging, spend above a cap and anything that leaves the machine.
|
|
130
|
+
Agents decide design, refactors, docs, checks and beads within the milestone, and explain
|
|
131
|
+
what they did in the PR body. When in doubt, an agent acts and explains.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monkeyshape",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Opinionated checks, configs and conventions for humans and coding agents building together on Bun, TypeScript, Effect and beads.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bun",
|
|
@@ -40,14 +40,18 @@
|
|
|
40
40
|
"files": [
|
|
41
41
|
"src",
|
|
42
42
|
"config",
|
|
43
|
+
"template",
|
|
44
|
+
"skills",
|
|
43
45
|
"!src/**/*.test.ts",
|
|
44
46
|
"README.md",
|
|
47
|
+
"docs/workflow.md",
|
|
45
48
|
"LICENSE"
|
|
46
49
|
],
|
|
47
50
|
"scripts": {
|
|
48
51
|
"typecheck": "tsc -p .",
|
|
49
52
|
"lint": "biome ci --error-on-warnings .",
|
|
50
53
|
"fix": "biome check --write .",
|
|
54
|
+
"mshape": "bun src/cli/main.ts",
|
|
51
55
|
"shape": "bun src/cli/main.ts check",
|
|
52
56
|
"check": "bun run typecheck && bun run lint && bun run shape && bun test"
|
|
53
57
|
},
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: handoff
|
|
3
|
+
description: Use when the human says /handoff, or asks to wrap up a track's chat because the context is running out or the session is ending. Rewrites the track's handoff so a fresh chat running /track can continue with nothing else.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Handoff: hand a track to a fresh chat
|
|
7
|
+
|
|
8
|
+
The next session knows only the repo, the beads and the handoff you write now. Write for an
|
|
9
|
+
agent as capable as you who wasn't here: what it needs to continue, not what you did. What a
|
|
10
|
+
change did belongs in its PR body and commits, not here.
|
|
11
|
+
|
|
12
|
+
## 1. Which track
|
|
13
|
+
|
|
14
|
+
Run `mshape track current`. If it exits 1, tell the human its reason and stop: a handoff
|
|
15
|
+
belongs to a track.
|
|
16
|
+
|
|
17
|
+
## 2. Leave nothing only in this chat
|
|
18
|
+
|
|
19
|
+
- **Uncommitted work:** if no PR is open from the track branch, commit it there, as a WIP
|
|
20
|
+
commit if it isn't finished, and push. If one is open, a push would add it to the PR:
|
|
21
|
+
leave it uncommitted (the next chat opens in this same worktree) and list it in State.
|
|
22
|
+
Never stash: the stash is shared by every worktree.
|
|
23
|
+
- **Beads:** close what merged; claim what is half done; file what you found and didn't do.
|
|
24
|
+
- **Open PRs:** note each one's number and what it waits on.
|
|
25
|
+
|
|
26
|
+
## 3. Rewrite the handoff
|
|
27
|
+
|
|
28
|
+
Overwrite `.handoffs/<name>.md`; don't append. Other tracks write to its Messages while you
|
|
29
|
+
work, so read the file again just before writing, and keep every message you hadn't seen.
|
|
30
|
+
|
|
31
|
+
Keep its format: the title, `Status:` and `Queue:` lines, then exactly the sections Charter,
|
|
32
|
+
State (with today's date), Lessons not yet promoted, Traps, Messages, in that order, with
|
|
33
|
+
`###` for headings inside them. About 120 lines at most.
|
|
34
|
+
|
|
35
|
+
- **Charter:** leave it unless the work changed what the track is for; then rewrite it, and
|
|
36
|
+
say in State that it changed and why.
|
|
37
|
+
- **State:** done (PRs and beads, by number), in flight (the branch, the PR, what is half
|
|
38
|
+
done and the next command to run), and next. Concrete enough to act on without asking.
|
|
39
|
+
- **Lessons not yet promoted:** what you learned that should become a check, a test, an
|
|
40
|
+
AGENTS.md gotcha or a decision. If promoting one is quick, do it now instead and delete
|
|
41
|
+
it here. A lesson that is really a bead becomes one.
|
|
42
|
+
- **Traps:** what will bite the next session. Delete traps that are no longer true.
|
|
43
|
+
- **Messages:** delete the answered ones and keep the open ones. Your messages to other
|
|
44
|
+
tracks go in their handoffs, not here.
|
|
45
|
+
|
|
46
|
+
## 4. Check it and hand over
|
|
47
|
+
|
|
48
|
+
Run `mshape track list`: this track must show `stub` (if the charter isn't agreed yet:
|
|
49
|
+
leave it empty, never write one the human hasn't agreed) or `active`, never `invalid`. If it
|
|
50
|
+
shows `invalid`, each problem is printed under its row: fix them all and run it again. Then
|
|
51
|
+
tell the human, in a few lines: what is done and in flight, any messages they need to relay to another track or decide on, and "open a
|
|
52
|
+
fresh chat in this worktree and run `/track`".
|
|
53
|
+
|
|
54
|
+
Review this skill when a fresh chat had to rediscover something the last one knew.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: milestone
|
|
3
|
+
description: Use at a milestone boundary, when the human brings priorities for the next stretch of work, or when the repo has a roadmap but no milestone plan yet. Runs the retrospective, agrees a goal with acceptance on real data, writes plan/MILESTONE.md, grooms beads and the roadmap, gardens, and creates the tracks with mshape track.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Milestone: the mid horizon and the boundary
|
|
7
|
+
|
|
8
|
+
A milestone is the next significant delivery: several PRs from each of several parallel
|
|
9
|
+
tracks. The boundary is the repo's only ceremony, and this skill runs all of it, in order.
|
|
10
|
+
The human owns priorities and approves the plan; you bring the evidence and the proposal.
|
|
11
|
+
|
|
12
|
+
Run this in the main checkout, on an up-to-date `main`, in a fresh chat.
|
|
13
|
+
|
|
14
|
+
## 1. Gather
|
|
15
|
+
|
|
16
|
+
- plan/MILESTONE.md (the milestone ending), docs/roadmap.md, AGENTS.md.
|
|
17
|
+
- `mshape track list`, and every track's handoff in `.handoffs`: state, lessons not yet
|
|
18
|
+
promoted, messages nobody answered.
|
|
19
|
+
- The milestone's epic and its children (`bd list --parent <epic> --all`), and
|
|
20
|
+
`bd list --label process` for what got in the way.
|
|
21
|
+
- Merged PRs since the plan was written (`gh pr list --state merged`), and their bodies'
|
|
22
|
+
"not done" sections.
|
|
23
|
+
- `mshape garden`.
|
|
24
|
+
|
|
25
|
+
On a repo's first milestone there is nothing to look back on: skip to step 3.
|
|
26
|
+
|
|
27
|
+
## 2. Retrospective
|
|
28
|
+
|
|
29
|
+
Tell the human, briefly: what shipped against each acceptance line, what slipped and why,
|
|
30
|
+
what the process beads and handoff lessons say, and what you would change. Facts with
|
|
31
|
+
links (PRs, beads), not a story. Ask what they saw that you didn't.
|
|
32
|
+
|
|
33
|
+
## 3. Agree the goal
|
|
34
|
+
|
|
35
|
+
Propose one goal, from the human's priorities and the roadmap, with **acceptance on real
|
|
36
|
+
data**: a run on a named real target, or a real repo or user doing the thing, never "tests
|
|
37
|
+
pass". A new repo's first milestone is "a first result on a real target". Say what you
|
|
38
|
+
would defer to make it fit, and why. Iterate until the human agrees; don't write the plan
|
|
39
|
+
before that.
|
|
40
|
+
|
|
41
|
+
## 4. Write plan/MILESTONE.md
|
|
42
|
+
|
|
43
|
+
First move the old plan to notes/, named with today's date (YYYY-MM-DD-milestone-<n>.md).
|
|
44
|
+
Then write the new one, about 500 lines at most:
|
|
45
|
+
|
|
46
|
+
- **Goal, and how we'll know:** the acceptance agreed above.
|
|
47
|
+
- **Where we are:** a gap table, measured where it can be.
|
|
48
|
+
- **What changed since the last milestone, and why.**
|
|
49
|
+
- **Interfaces the tracks share:** every path, command, format or schema two tracks both
|
|
50
|
+
touch, with its owner and consumer, settled before anyone starts. This is the section
|
|
51
|
+
that keeps parallel work from colliding; spend the effort here.
|
|
52
|
+
- **Tracks:** a table of name, charter, beads and acceptance. Split into as many parallel
|
|
53
|
+
tracks as the work allows: each touches disjoint files and meets the others only at the
|
|
54
|
+
interfaces. Derive the number from the work, not a habit: up to about five is usual, and
|
|
55
|
+
one is fine when the work is sequential. When a track ends up holding far more than the
|
|
56
|
+
others, or the riskiest work alongside everything else, split it.
|
|
57
|
+
- **Decision points**, **spend** for big runs, and **deferred items, each with a reason**.
|
|
58
|
+
|
|
59
|
+
The plan is frozen once tracks start. Say so at its top.
|
|
60
|
+
|
|
61
|
+
## 5. Groom
|
|
62
|
+
|
|
63
|
+
- Create the milestone epic, and its stories as children labelled `track:<name>`, with
|
|
64
|
+
dependencies (`bd dep add`). An interface gets its own bead, owned by one track. A bead
|
|
65
|
+
is intent and an outcome as acceptance, about 1,500 characters at most, not a spec.
|
|
66
|
+
- Pull roadmap epics in with `bd undefer`; close epics whose work is done.
|
|
67
|
+
- Close, defer or rewrite every open story the milestone doesn't need, with a reason. A
|
|
68
|
+
story deferred out of the milestone drops its `track:` label.
|
|
69
|
+
- P1 is the critical path only.
|
|
70
|
+
- Re-verify each bd memory (`bd memories`) against the code; rewrite or delete stale ones.
|
|
71
|
+
- Every `TODO(<bead id>)` in code whose bead is now closed: fix it or re-point it.
|
|
72
|
+
|
|
73
|
+
## 6. Garden
|
|
74
|
+
|
|
75
|
+
Act on `mshape garden`: anything over budget or grown since the last boundary gets pruned,
|
|
76
|
+
not waived. Promote each handoff lesson to a check, a test, an AGENTS.md gotcha or a
|
|
77
|
+
decision, or delete it. Try to turn each prose rule into a check, and each review finding
|
|
78
|
+
that recurred into one. A process bead whose fix is general belongs upstream in monkeyshape:
|
|
79
|
+
tell the human; filing outside the repo is theirs to approve.
|
|
80
|
+
|
|
81
|
+
## 7. Roadmap and PR
|
|
82
|
+
|
|
83
|
+
Update docs/roadmap.md: the status table, and what this milestone taught. Then one PR with
|
|
84
|
+
the plan, the roadmap and the garden changes, gate green, the body saying what was decided
|
|
85
|
+
and why. The human merges.
|
|
86
|
+
|
|
87
|
+
## 8. Tracks
|
|
88
|
+
|
|
89
|
+
Once the PR is merged (or the human says to start):
|
|
90
|
+
|
|
91
|
+
- `mshape track rm <name>` for each finished track whose `beads` column in
|
|
92
|
+
`mshape track list` shows 0. A `-` means beads weren't counted, and `rm` may then remove
|
|
93
|
+
the track with only a note. So first get `bd` working, or check by hand that
|
|
94
|
+
`bd list --label track:<name> --limit 0` lists nothing (it hides only closed beads).
|
|
95
|
+
If `rm` refuses, report the reason; never reach for `--force` without the human. If the
|
|
96
|
+
reason is open beads, `--force` won't help, and grooming has already decided each one:
|
|
97
|
+
move it to the track the new plan gives it, or close it if it's done, and list what you
|
|
98
|
+
did in your report. Ask the human only when the plan doesn't say.
|
|
99
|
+
- `mshape track new <name>` for each new track. Fill its handoff: `Status: active`, the
|
|
100
|
+
charter (its beads, the interfaces it owns or consumes), the state ("not started", and
|
|
101
|
+
how to start), the traps you already know, and messages from the plan.
|
|
102
|
+
|
|
103
|
+
Finish by telling the human what to launch: for each track, the worktree path and "open a
|
|
104
|
+
chat there and run `/track`".
|
|
105
|
+
|
|
106
|
+
Review this skill after each boundary it runs: what the retrospective found about the
|
|
107
|
+
process applies to this file too.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-pr
|
|
3
|
+
description: Use when asked to review a pull request (a number or URL), to re-review one after its author replied or pushed fixes, or to review a follow-up PR that answers an earlier review's findings. Runs the change on real data in a scratch worktree, probes what it claims to enforce, posts every finding on the PR with a severity, and re-reviews until it can say "LGTM".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review a pull request
|
|
7
|
+
|
|
8
|
+
A review is judged by what it **ran and read**, not by what it guessed from the diff. Every
|
|
9
|
+
finding carries its evidence: the input that breaks it, a real-data output, or the line of
|
|
10
|
+
code it rests on. Read AGENTS.md first: it holds the rules the PR is reviewed against.
|
|
11
|
+
|
|
12
|
+
**Ground rules**
|
|
13
|
+
- **The PR is the review's only home.** Findings, evidence, replies and what is still open
|
|
14
|
+
all go on it; nothing about the review is kept anywhere else. A fresh chat re-reviewing
|
|
15
|
+
reads the thread.
|
|
16
|
+
- **Don't fix the PR yourself**: the author fixes findings in the same PR.
|
|
17
|
+
- **Hold the PR to 95%, not 100%.** A blocker is a defect the PR would ship and someone
|
|
18
|
+
would hit, shown by a concrete failing input or a real-data result. "Could be better", or
|
|
19
|
+
an edge nobody has, is a nit, in any round. Style never blocks: the linter owns style.
|
|
20
|
+
- **A nit stays open until it's settled:** fixed in this PR, declined with a reason you
|
|
21
|
+
accept, or filed by the author as a bead when it is real work beyond the PR. Never call a
|
|
22
|
+
blocker a nit to close a review.
|
|
23
|
+
- **As many rounds as that takes.** If each fix keeps opening a new blocker, tell the human:
|
|
24
|
+
the design may need rethinking more than another patch. The human can step in at any point.
|
|
25
|
+
- Real data may be read and run freely; spend past the repo's cap, or writes to shared data,
|
|
26
|
+
need the human first (see AGENTS.md).
|
|
27
|
+
|
|
28
|
+
## 1. A worktree at the PR's head
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
N=<pr number>
|
|
32
|
+
gh pr view $N --json title,body,files,commits
|
|
33
|
+
gh api repos/{owner}/{repo}/pulls/$N -q .head.sha # the head you review and anchor to
|
|
34
|
+
mshape review $N # detached worktree at that head, shared data linked; prints its path
|
|
35
|
+
cd <that path> && bun install --frozen-lockfile
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Never review in your own checkout. If the review's head and the API's differ, the author
|
|
39
|
+
pushed meanwhile: run `mshape review $N` again.
|
|
40
|
+
|
|
41
|
+
**A follow-up PR** that answers an earlier review: read that PR's thread first
|
|
42
|
+
(`gh pr view <earlier> --comments`, and its inline comments as in step 5). Each finding it
|
|
43
|
+
claims to answer is a re-review item (step 5), on top of reviewing its own diff.
|
|
44
|
+
|
|
45
|
+
## 2. Read the diff
|
|
46
|
+
|
|
47
|
+
Read the PR body and every changed file. Then go through it for:
|
|
48
|
+
|
|
49
|
+
- **The invariants it claims.** If a schema, check or test says it enforces something, list
|
|
50
|
+
the inputs that should fail. Those are your probes in step 3.
|
|
51
|
+
- **Docs it touches, or should have.** Do AGENTS.md, DECISIONS.md, the skills and the
|
|
52
|
+
handoffs still agree with the change? Grep for prose it made stale.
|
|
53
|
+
- **The usual misses.** New code outside the gate (a tsconfig `include`, a test glob)? A
|
|
54
|
+
check that a free-text field walks around? A check-then-write that isn't atomic? A path
|
|
55
|
+
that breaks in a worktree, a symlink or a fresh clone? An error message that doesn't say
|
|
56
|
+
what to do?
|
|
57
|
+
|
|
58
|
+
## 3. Run it
|
|
59
|
+
|
|
60
|
+
From cheapest to most expensive:
|
|
61
|
+
|
|
62
|
+
1. **Run what the PR adds**, on real data, in every mode it has. Do the numbers in the PR
|
|
63
|
+
body reproduce? Does each exit code mean what its doc says?
|
|
64
|
+
2. **Probe checks adversarially**: throwaway scripts that build inputs which should be
|
|
65
|
+
rejected, one variation each, from a real artifact where there is one. **A bad input
|
|
66
|
+
that passes is a finding**, and the probe's input and output are its evidence on the PR.
|
|
67
|
+
Probes are scratch and are never committed or kept: one worth keeping is a regression
|
|
68
|
+
test, and that is the author's to add (step 4). **When the PR adds a check**, also probe
|
|
69
|
+
it with valid input it must pass: a false failure reaches everyone who runs the check,
|
|
70
|
+
and is a blocker.
|
|
71
|
+
3. **Run the real workflow** when the claim is about what it produces end to end.
|
|
72
|
+
|
|
73
|
+
Don't rerun the gate on the first pass if the PR body shows it green; do on a re-review whose
|
|
74
|
+
fix touched code.
|
|
75
|
+
|
|
76
|
+
## 4. Post on the PR
|
|
77
|
+
|
|
78
|
+
Post **one review**, inline comments anchored to the head commit, built as a JSON file so
|
|
79
|
+
the quoting survives:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# review.json: {commit_id, event: "COMMENT", body, comments: [{path, line, side: "RIGHT", body}]}
|
|
83
|
+
gh api repos/{owner}/{repo}/pulls/$N/reviews --input review.json -q .html_url
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Anchor each comment to a head-commit line that is in the diff; a finding with no such line
|
|
87
|
+
goes in the review body. Each comment opens with a **bold one-sentence finding** and its
|
|
88
|
+
severity (blocker or nit), then the evidence, then a suggested fix.
|
|
89
|
+
|
|
90
|
+
- **A blocker in code asks for a regression test** in the PR: one that fails on this head
|
|
91
|
+
and passes once fixed. A blocker in prose (two docs that disagree, a wrong instruction)
|
|
92
|
+
asks for the fix; there is nothing to test.
|
|
93
|
+
- **If a check could rule out the whole class**, say so: the PR body's "Class closed by"
|
|
94
|
+
line is where the author answers it.
|
|
95
|
+
|
|
96
|
+
The body says what was run and what came out, the blockers, the nits with no line, and what
|
|
97
|
+
looked good. Use `COMMENT`: GitHub refuses approve and request-changes on your own
|
|
98
|
+
account's PR. Then tell the human in a few lines: what you ran, each finding and its
|
|
99
|
+
severity, the review link. **Stop and wait** for the author.
|
|
100
|
+
|
|
101
|
+
## 5. Re-review
|
|
102
|
+
|
|
103
|
+
When told the author responded, read the thread: every reply, the new commits and the fix
|
|
104
|
+
diff (`gh pr view $N --comments`, `gh api repos/{owner}/{repo}/pulls/$N/comments`). The head
|
|
105
|
+
you reviewed last is your previous review's `commit_id`
|
|
106
|
+
(`gh api repos/{owner}/{repo}/pulls/$N/reviews`). Run `mshape review $N` to move the
|
|
107
|
+
worktree to the new head; it prints the previous one too.
|
|
108
|
+
|
|
109
|
+
1. **"Fixed" is a claim.** For each code blocker, find its regression test and run it on
|
|
110
|
+
both heads. It must fail on the old one and pass on the new:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git switch --detach <old head> && git checkout <new head> -- <test file> <files it needs>
|
|
114
|
+
bun test <test file> # must fail
|
|
115
|
+
git reset -q --hard && git switch --detach <new head>
|
|
116
|
+
bun test <test file> # must pass
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The failure on the old head must be the test's own assertion, saying what the finding
|
|
120
|
+
said: a load or import error means it never reached the bug, so check out the helpers
|
|
121
|
+
and fixtures it imports too, and rerun `bun install` if the dependencies changed. A test
|
|
122
|
+
that passes on the old head doesn't test the bug: that is a finding. For a prose
|
|
123
|
+
blocker, read the fix. Rerun the real-data runs the findings rested on.
|
|
124
|
+
2. Look for what the fix opened: a new unchecked field, the mirror case of a new check.
|
|
125
|
+
3. **Pushback is an argument, not a refusal.** If it holds, say so and drop the point; if it
|
|
126
|
+
doesn't, answer with evidence.
|
|
127
|
+
4. Reply in the threads, then post a short summary review: what was re-verified, what is
|
|
128
|
+
resolved, what is still open. Tell the human.
|
|
129
|
+
|
|
130
|
+
**When nothing is open, say "LGTM"** explicitly, on the PR and to the human: every blocker
|
|
131
|
+
resolved and verified, every nit settled. Never while a finding is open or unverified.
|
|
132
|
+
Merging is the human's call. When the review is over, `mshape review rm $N`: it lists what
|
|
133
|
+
it discards, which in a review worktree is only scratch, then removes it.
|
|
134
|
+
|
|
135
|
+
Review this skill when a blocker it should have caught reaches `main`.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: roadmap
|
|
3
|
+
description: Use when the human brings a brain-dump about where the repo is heading (new goals, a change of direction, a fresh repo after mshape init), or asks to rewrite the roadmap. Interviews until the goals are clear, writes docs/roadmap.md with a status table first, keeps one deferred beads epic per goal, and opens a PR.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Roadmap: the long horizon
|
|
7
|
+
|
|
8
|
+
The roadmap is direction, not a spec: months ahead, coarse, rewritten in place, never cited
|
|
9
|
+
by code or normative docs. Your job is to turn a brain-dump into goals clear enough that a
|
|
10
|
+
later `/milestone` can pick one and give it acceptance on real data.
|
|
11
|
+
|
|
12
|
+
Run this in the main checkout, on an up-to-date `main`, in a fresh chat.
|
|
13
|
+
|
|
14
|
+
## 1. Read what exists
|
|
15
|
+
|
|
16
|
+
- docs/roadmap.md, if there is one, and AGENTS.md.
|
|
17
|
+
- The direction epics: `bd list --type epic --all`. Deferred ones are goals not yet pulled
|
|
18
|
+
into a milestone; open ones are in flight; closed ones shipped.
|
|
19
|
+
- If a milestone is running, plan/MILESTONE.md, only to know what is already committed.
|
|
20
|
+
|
|
21
|
+
## 2. Interview
|
|
22
|
+
|
|
23
|
+
Ask in small batches, and propose answers rather than asking open questions: "I read this as
|
|
24
|
+
X; is that right?" is cheaper for the human than "what do you mean?". Keep going until you
|
|
25
|
+
could write, for every goal:
|
|
26
|
+
|
|
27
|
+
- **The consumer:** who or what uses it first. No goal without one.
|
|
28
|
+
- **What done looks like** on real data or a real target, not a feature list.
|
|
29
|
+
- **Why now, or why later**, and what it depends on.
|
|
30
|
+
- **What is out of scope**, said out loud, so the next agent doesn't build it.
|
|
31
|
+
- **Spend or authority** it will need from the human (money, public releases, data).
|
|
32
|
+
|
|
33
|
+
Push back where the brain-dump conflicts with the code, with the repo's principles in
|
|
34
|
+
AGENTS.md, or with itself. The human owns priorities; you own pointing out that two of them
|
|
35
|
+
collide. Stop interviewing when another question would not change what you write.
|
|
36
|
+
|
|
37
|
+
## 3. Write docs/roadmap.md
|
|
38
|
+
|
|
39
|
+
Rewrite it in place; git has the history, so keep no revision log and no frozen copy.
|
|
40
|
+
|
|
41
|
+
- **Open with a status table**: one row per goal, with status `Shipped`, `Milestone N` (in
|
|
42
|
+
progress), `Later` or `Idea`, and the epic id. A reader learns what exists without reading
|
|
43
|
+
the design.
|
|
44
|
+
- Then scope (who it's for, what it is not), then a section per goal: the intent, the
|
|
45
|
+
consumer, what done looks like, and what was learned so far. Far-off detail belongs here,
|
|
46
|
+
not in beads.
|
|
47
|
+
- No dated promises, no restating AGENTS.md or DECISIONS.md, and nothing other docs would
|
|
48
|
+
need to cite: if something must be enforced, it becomes a check, a test or a decision.
|
|
49
|
+
|
|
50
|
+
## 4. One deferred epic per goal
|
|
51
|
+
|
|
52
|
+
For each goal without an epic: `bd create --type epic --title "<goal>" --description "..."`
|
|
53
|
+
with the goal, two or three lines of why, and the roadmap section it comes from, then
|
|
54
|
+
`bd defer <id>`. **No child stories:** a milestone creates those when it pulls the epic in.
|
|
55
|
+
For goals that changed, rewrite the epic; for goals dropped, close it with the reason. Put
|
|
56
|
+
each epic's id in the status table.
|
|
57
|
+
|
|
58
|
+
## 5. PR
|
|
59
|
+
|
|
60
|
+
Branch from `main`, commit, push, and open a PR whose body says what changed in the
|
|
61
|
+
direction and why, which epics were created, rewritten or closed, and what the interview
|
|
62
|
+
left open. Gate green first (`bun run check`). The human merges.
|
|
63
|
+
|
|
64
|
+
Then tell the human the next step: `/milestone` in a fresh chat, with their priorities.
|
|
65
|
+
|
|
66
|
+
Review this skill when a roadmap written with it was hard for `/milestone` to plan from.
|