monkeyshape 0.0.0-stage → 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/LICENSE +21 -0
- package/README.md +54 -2
- package/config/biome.base.json +71 -0
- package/config/tsconfig.base.json +31 -0
- package/docs/workflow.md +131 -0
- package/package.json +68 -4
- 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/baseline.ts +55 -0
- package/src/adapters/config.ts +25 -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 +281 -0
- package/src/api/monkeyshape.ts +8 -0
- package/src/cli/main.ts +359 -0
- package/src/core/arch.ts +224 -0
- package/src/core/budgets.ts +187 -0
- package/src/core/check.ts +122 -0
- package/src/core/coverage.ts +118 -0
- package/src/core/decisions.ts +65 -0
- package/src/core/garden.ts +41 -0
- package/src/core/glob.ts +22 -0
- package/src/core/handoff.ts +183 -0
- package/src/core/hooks.ts +60 -0
- package/src/core/jsonc.ts +26 -0
- package/src/core/layout.ts +123 -0
- package/src/core/markdown.ts +93 -0
- package/src/core/model.ts +100 -0
- package/src/core/parse.ts +41 -0
- package/src/core/paths.ts +19 -0
- package/src/core/ratchet.ts +75 -0
- package/src/core/refs.ts +214 -0
- package/src/core/report.ts +67 -0
- package/src/core/rules/ast.ts +50 -0
- package/src/core/rules/decodeStrict.ts +60 -0
- package/src/core/rules/effectRunAtEdge.ts +33 -0
- package/src/core/rules/engine.ts +150 -0
- package/src/core/rules/noErrorSpread.ts +28 -0
- package/src/core/rules/noNondeterminism.ts +65 -0
- package/src/core/rules/noThrow.ts +79 -0
- package/src/core/rules/registry.ts +15 -0
- package/src/core/scaffold.ts +90 -0
- package/src/core/scope.ts +120 -0
- package/src/core/skills.ts +291 -0
- package/src/core/tracks.ts +358 -0
- package/src/helpers/decodeStrict.ts +8 -0
- package/src/schemas/config.ts +221 -0
- package/src/schemas/errors.ts +31 -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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 clinsky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
-
#
|
|
1
|
+
# monkeyshape
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Opinionated checks, configs and conventions for humans and coding agents building software
|
|
4
|
+
together on **Bun**, **TypeScript**, **Effect** and **beads**.
|
|
5
|
+
|
|
6
|
+
Agents write a lot of prose and forget most of it. A rule written in `AGENTS.md` works only if
|
|
7
|
+
it is loaded and noticed; a check works every time and costs no context until it fires.
|
|
8
|
+
monkeyshape turns lessons into checks, keeps everything loaded automatically on a budget,
|
|
9
|
+
and treats real-world results as the judge of done.
|
|
10
|
+
|
|
11
|
+
```console
|
|
12
|
+
$ mshape check
|
|
13
|
+
src/core/cache.ts:1 rules/no-nondeterminism
|
|
14
|
+
reads the wall clock. Use Clock or DateTime.now so tests control time.
|
|
15
|
+
|
|
16
|
+
src/core/client.ts arch/host-access
|
|
17
|
+
imports 'node:fs/promises', but module 'core' has no hostAccess. Reach the host through a service in an adapter module.
|
|
18
|
+
|
|
19
|
+
mshape check failed: 2 problems
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
bunx --package monkeyshape mshape init my-app
|
|
26
|
+
```
|
|
27
|
+
|
|
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
|
+
|
|
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.
|
|
37
|
+
|
|
38
|
+
The conventions in full: [docs/workflow.md](docs/workflow.md). An existing repo:
|
|
39
|
+
[docs/adopting.md](docs/adopting.md).
|
|
40
|
+
|
|
41
|
+
## What `mshape check` enforces
|
|
42
|
+
|
|
43
|
+
| Check | Removes |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `arch` | Layering drift, host access from pure code (common paths, statically; not a sandbox), unvetted packages, import cycles |
|
|
46
|
+
| `rules` | Silent decoding, hidden clocks/env/timers, thrown errors, nested runtimes, spread errors |
|
|
47
|
+
| `refs` | Docs and comments that point at paths, scripts or decisions that don't exist |
|
|
48
|
+
| `budgets` | Bloated `AGENTS.md`, decision logs and memories; oversized files |
|
|
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 |
|
|
51
|
+
|
|
52
|
+
Existing violations can be grandfathered with `mshape baseline --init`; counts may then only
|
|
53
|
+
go down. Every escape hatch (`// shape-ignore <rule>: <reason>`, config allowances) needs a reason.
|
|
54
|
+
|
|
55
|
+
Early (0.x). What ships and what's next: [docs/roadmap.md](docs/roadmap.md). MIT licensed.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.15/schema.json",
|
|
3
|
+
"root": false,
|
|
4
|
+
"vcs": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"clientKind": "git",
|
|
7
|
+
"useIgnoreFile": true
|
|
8
|
+
},
|
|
9
|
+
"formatter": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"indentStyle": "space",
|
|
12
|
+
"indentWidth": 2,
|
|
13
|
+
"lineWidth": 100
|
|
14
|
+
},
|
|
15
|
+
"javascript": {
|
|
16
|
+
"formatter": {
|
|
17
|
+
"quoteStyle": "double",
|
|
18
|
+
"semicolons": "always"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"linter": {
|
|
22
|
+
"enabled": true,
|
|
23
|
+
"rules": {
|
|
24
|
+
"preset": "recommended",
|
|
25
|
+
"correctness": {
|
|
26
|
+
"useImportExtensions": "error"
|
|
27
|
+
},
|
|
28
|
+
"suspicious": {
|
|
29
|
+
"noExplicitAny": "error",
|
|
30
|
+
"noConsole": "error"
|
|
31
|
+
},
|
|
32
|
+
"style": {
|
|
33
|
+
"noNonNullAssertion": "error",
|
|
34
|
+
"noEnum": "error",
|
|
35
|
+
"noNamespace": "error",
|
|
36
|
+
"noParameterAssign": "error",
|
|
37
|
+
"useImportType": "error",
|
|
38
|
+
"useExportType": "error"
|
|
39
|
+
},
|
|
40
|
+
"performance": {
|
|
41
|
+
"noBarrelFile": "error",
|
|
42
|
+
"noReExportAll": "error"
|
|
43
|
+
},
|
|
44
|
+
"nursery": {
|
|
45
|
+
"noFloatingPromises": "error",
|
|
46
|
+
"noMisusedPromises": "error"
|
|
47
|
+
},
|
|
48
|
+
"complexity": {
|
|
49
|
+
"useLiteralKeys": "off"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"assist": {
|
|
54
|
+
"enabled": true,
|
|
55
|
+
"actions": {
|
|
56
|
+
"source": {
|
|
57
|
+
"organizeImports": "on"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"overrides": [
|
|
62
|
+
{
|
|
63
|
+
"includes": ["src/api/**"],
|
|
64
|
+
"linter": { "rules": { "performance": { "noBarrelFile": "off" } } }
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"includes": ["src/cli/**", "tools/**", "**/*.test.ts", "**/*.test.tsx"],
|
|
68
|
+
"linter": { "rules": { "suspicious": { "noConsole": "off" } } }
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"lib": ["ESNext"],
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleResolution": "bundler",
|
|
8
|
+
"moduleDetection": "force",
|
|
9
|
+
"types": ["bun"],
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"erasableSyntaxOnly": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"skipLibCheck": true,
|
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
|
17
|
+
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUncheckedIndexedAccess": true,
|
|
20
|
+
"exactOptionalPropertyTypes": true,
|
|
21
|
+
"noImplicitOverride": true,
|
|
22
|
+
"noImplicitReturns": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
25
|
+
"noUnusedLocals": true,
|
|
26
|
+
"noUnusedParameters": true,
|
|
27
|
+
"noUncheckedSideEffectImports": true,
|
|
28
|
+
"allowUnreachableCode": false,
|
|
29
|
+
"allowUnusedLabels": false
|
|
30
|
+
}
|
|
31
|
+
}
|
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,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monkeyshape",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Opinionated checks, configs and conventions for humans and coding agents building together on Bun, TypeScript, Effect and beads.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"bun",
|
|
7
|
+
"typescript",
|
|
8
|
+
"effect",
|
|
9
|
+
"effect-ts",
|
|
10
|
+
"static-analysis",
|
|
11
|
+
"linter",
|
|
12
|
+
"quality-gate",
|
|
13
|
+
"coding-agents",
|
|
14
|
+
"ai-agents",
|
|
15
|
+
"developer-tools",
|
|
16
|
+
"beads"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/clinsky/monkeyshape.git"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/clinsky/monkeyshape#readme",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/clinsky/monkeyshape/issues"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"packageManager": "bun@1.4.2",
|
|
29
|
+
"engines": {
|
|
30
|
+
"bun": ">=1.4.2"
|
|
31
|
+
},
|
|
32
|
+
"bin": {
|
|
33
|
+
"mshape": "./src/cli/main.ts"
|
|
34
|
+
},
|
|
35
|
+
"exports": {
|
|
36
|
+
".": "./src/api/monkeyshape.ts",
|
|
37
|
+
"./tsconfig.base.json": "./config/tsconfig.base.json",
|
|
38
|
+
"./biome": "./config/biome.base.json"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"src",
|
|
42
|
+
"config",
|
|
43
|
+
"template",
|
|
44
|
+
"skills",
|
|
45
|
+
"!src/**/*.test.ts",
|
|
46
|
+
"README.md",
|
|
47
|
+
"docs/workflow.md",
|
|
48
|
+
"LICENSE"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"typecheck": "tsc -p .",
|
|
52
|
+
"lint": "biome ci --error-on-warnings .",
|
|
53
|
+
"fix": "biome check --write .",
|
|
54
|
+
"mshape": "bun src/cli/main.ts",
|
|
55
|
+
"shape": "bun src/cli/main.ts check",
|
|
56
|
+
"check": "bun run typecheck && bun run lint && bun run shape && bun test"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"oxc-parser": "0.156.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"effect": "4.0.0"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@biomejs/biome": "2.5.15",
|
|
66
|
+
"@types/bun": "1.4.2",
|
|
67
|
+
"effect": "4.0.0",
|
|
68
|
+
"typescript": "7.0.2"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -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.
|