@sublang/playbook 1.3.0 → 3.0.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 +101 -338
- package/docs/cli.md +102 -0
- package/docs/configuration.md +158 -0
- package/docs/embedding.md +161 -0
- package/package.json +7 -3
- package/reference/sdlc/code.md +105 -0
- package/reference/sdlc/code.playbook/bin/playbook.js +236 -38
- package/reference/sdlc/code.playbook/bin/run.js +27 -2
- package/reference/sdlc/code.playbook/code.fsm.js +38 -36
- package/reference/sdlc/code.playbook/code.fsm.ts +38 -36
- package/reference/sdlc/code.playbook/code.gears.md +30 -26
- package/reference/sdlc/code.playbook/code.playbook.js +4 -0
- package/reference/sdlc/code.playbook/code.playbook.ts +6 -0
- package/reference/sdlc/code.playbook/playbook-captain.js +67 -8
- package/reference/sdlc/code.playbook/playbook-captain.ts +80 -9
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +38 -32
- package/reference/sdlc/discuss.md +93 -0
- package/reference/sdlc/discuss.playbook/discuss.fsm.js +5 -4
- package/reference/sdlc/discuss.playbook/discuss.fsm.ts +5 -4
- package/reference/sdlc/discuss.playbook/discuss.gears.md +19 -12
- package/reference/sdlc/discuss.playbook/discuss.playbook.js +3 -0
- package/reference/sdlc/discuss.playbook/discuss.playbook.ts +5 -0
- package/slc/link.md +33 -14
- package/src/xstate-playbook-runtime.js +64 -19
- package/src/xstate-playbook-runtime.ts +87 -24
- package/src/xstate-runtime.d.ts +1 -0
- package/src/xstate-runtime.js +19 -0
- package/src/xstate-runtime.ts +20 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
|
|
3
|
+
|
|
4
|
+
# Configuring agents
|
|
5
|
+
|
|
6
|
+
`playbook` reads one config at
|
|
7
|
+
`${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml`. The
|
|
8
|
+
first launch seeds it from the bundled starter and prints the path;
|
|
9
|
+
later launches reuse it untouched.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
$EDITOR "${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Anatomy
|
|
16
|
+
|
|
17
|
+
The config is top-level (no `config:` wrapper): a `captain` agent (it
|
|
18
|
+
runs both visible Captain work and hidden judge calls), optional
|
|
19
|
+
`layout` / `notifications` / `theme`, and a `playbooks` map of enabled
|
|
20
|
+
playbooks.
|
|
21
|
+
|
|
22
|
+
Each `captain` or `players.<role>` value is either an adapter shorthand
|
|
23
|
+
(`claude`, `codex`) or a block carrying that agent's own `adapter`,
|
|
24
|
+
`model`, `effort`, and `permissions`. Settings are inline per agent, so
|
|
25
|
+
tuning one player never changes another
|
|
26
|
+
([DR-021](../specs/decisions/021-inline-agent-settings.md)). Other
|
|
27
|
+
adapter ids pass through to `tmux-play` with a warning, because
|
|
28
|
+
`playbook` cannot preflight their auth.
|
|
29
|
+
|
|
30
|
+
Within a `playbooks.<id>` block, `from` (the registry module), `command`
|
|
31
|
+
(an optional slash-command override), and `players` are launcher-owned;
|
|
32
|
+
every other key is that playbook's option slice. The launcher injects
|
|
33
|
+
the rest — you do not write host wiring by hand.
|
|
34
|
+
|
|
35
|
+
The seeded config runs the Coder on Claude Opus 4.8 1m and the Reviewer
|
|
36
|
+
on GPT-5.5:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
captain:
|
|
40
|
+
adapter: claude
|
|
41
|
+
model: claude-opus-4-8
|
|
42
|
+
effort: high
|
|
43
|
+
permissions:
|
|
44
|
+
mode: auto # protected auto mode for the Claude Captain
|
|
45
|
+
|
|
46
|
+
playbooks:
|
|
47
|
+
code:
|
|
48
|
+
from: '@sublang/playbook/code/registry'
|
|
49
|
+
players:
|
|
50
|
+
coder:
|
|
51
|
+
adapter: claude
|
|
52
|
+
model: claude-opus-4-8[1m]
|
|
53
|
+
effort: xhigh
|
|
54
|
+
permissions:
|
|
55
|
+
mode: auto # protected auto mode for the Claude Coder
|
|
56
|
+
reviewer:
|
|
57
|
+
adapter: codex
|
|
58
|
+
model: gpt-5.5
|
|
59
|
+
effort: xhigh
|
|
60
|
+
permissions:
|
|
61
|
+
mode: auto
|
|
62
|
+
writablePaths:
|
|
63
|
+
- .git # allow git metadata writes under Codex auto mode
|
|
64
|
+
committer: coder # which role commits — `coder` or `reviewer`
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`committer` is CODE's one option: an alias naming which role runs the
|
|
68
|
+
commit turn (fallback semantics:
|
|
69
|
+
[PBRT-8](../specs/dev/playbook-runtime.md#pbrt-8)). Each role's per-run
|
|
70
|
+
prompt names its pinned `model`, else its `adapter`
|
|
71
|
+
([PBRT-4](../specs/user/playbook-runtime.md#pbrt-4)), so commit trailers
|
|
72
|
+
credit the concrete model rather than the adapter family.
|
|
73
|
+
|
|
74
|
+
## Choosing the Captain agent
|
|
75
|
+
|
|
76
|
+
Hidden routing and adjudication calls run tool-free, which is what keeps
|
|
77
|
+
the Captain routing instead of doing the work itself. Claude enforces
|
|
78
|
+
that at the provider level. The Codex adapter cannot — it rejects any
|
|
79
|
+
tool list — so a `captain:` on `codex` falls back to a prompt-level
|
|
80
|
+
restriction
|
|
81
|
+
([DR-013 A1](../specs/decisions/013-routing-only-captain-control.md#addendum-a1-prompt-level-isolation-for-adapters-without-tool-enforcement)).
|
|
82
|
+
Codex remains a good choice for *players*, where full tools are wanted.
|
|
83
|
+
|
|
84
|
+
Adapter readiness is intentionally light: `claude` is ready with local
|
|
85
|
+
Claude Code auth or `ANTHROPIC_API_KEY`; `codex` with local Codex CLI
|
|
86
|
+
auth or `OPENAI_API_KEY`. A known adapter that is not ready blocks the
|
|
87
|
+
launch and prints the help text.
|
|
88
|
+
|
|
89
|
+
## Per-launch overlays
|
|
90
|
+
|
|
91
|
+
To retune one launch without editing the file, overlay a fragment in
|
|
92
|
+
the same format with `--with` (repeatable, later files win; maps merge
|
|
93
|
+
recursively, other values replace):
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
playbook --with fast-lineup.yaml
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
# fast-lineup.yaml — swap the Coder for one run; nothing is written back.
|
|
101
|
+
playbooks:
|
|
102
|
+
code:
|
|
103
|
+
players:
|
|
104
|
+
coder:
|
|
105
|
+
adapter: codex
|
|
106
|
+
model: gpt-5.5
|
|
107
|
+
effort: medium
|
|
108
|
+
permissions:
|
|
109
|
+
mode: auto
|
|
110
|
+
# The seeded `committer` is `coder`, so this role runs the commit
|
|
111
|
+
# turn; a Codex agent needs the `.git` grant to write git metadata.
|
|
112
|
+
writablePaths:
|
|
113
|
+
- .git
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Fragments merge into the agent block rather than replacing it, so
|
|
117
|
+
settings the base defines and the fragment omits — here `mode: auto` —
|
|
118
|
+
survive. Anything the adapter itself requires must still be stated: a
|
|
119
|
+
role switched to `codex` needs its own `writablePaths` grant, because
|
|
120
|
+
the base Claude block had no reason to carry one.
|
|
121
|
+
|
|
122
|
+
The global file is never modified, and `--with` is not forwarded to
|
|
123
|
+
`tmux-play` ([PBCLI-25](../specs/user/playbook-cli.md#pbcli-25)).
|
|
124
|
+
|
|
125
|
+
## Defaults for `playbook run`
|
|
126
|
+
|
|
127
|
+
An optional top-level `run` block supplies the non-interactive host's
|
|
128
|
+
lineup so you stop retyping flags — `run.captain`, `run.players.<role>`,
|
|
129
|
+
and a `run.player` catch-all for any other required role, each an
|
|
130
|
+
`<adapter>[:<model>][@<effort>]` string. Flags win per role, and
|
|
131
|
+
`resume` always keeps the lineup stored with the parked session
|
|
132
|
+
([PBCLI-28](../specs/user/playbook-cli.md#pbcli-28),
|
|
133
|
+
[DR-017](../specs/decisions/017-run-defaults-config.md)).
|
|
134
|
+
|
|
135
|
+
```yaml
|
|
136
|
+
run:
|
|
137
|
+
captain: claude:claude-opus-4-8@high
|
|
138
|
+
players:
|
|
139
|
+
coder: claude:claude-opus-4-8[1m]@xhigh
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Migrating from `profiles`
|
|
143
|
+
|
|
144
|
+
Configs written before 3.0.0 carried a top-level `profiles` map. The
|
|
145
|
+
launcher rewrites such a config on the next launch — inlining each
|
|
146
|
+
profile's settings into the agent that named it, keeping your comments,
|
|
147
|
+
and saving the original as `<config>.bak` — then continues. Nothing to
|
|
148
|
+
do by hand.
|
|
149
|
+
|
|
150
|
+
## Using a raw tmux-play config
|
|
151
|
+
|
|
152
|
+
For a one-off, pass a raw `tmux-play` config explicitly. This bypasses
|
|
153
|
+
the seed, composition, and readiness gate, forwarding arguments to
|
|
154
|
+
`tmux-play` verbatim ([PBCLI-1](../specs/user/playbook-cli.md#pbcli-1)):
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
playbook --config ./tmux-play.config.yaml
|
|
158
|
+
```
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
|
|
3
|
+
|
|
4
|
+
# Embedding the runtime in your own host
|
|
5
|
+
|
|
6
|
+
The playbook runtime is host-agnostic; cligent's `tmux-play` adapter is
|
|
7
|
+
one host, and [spex](https://github.com/sublang-ai/spex) (the desktop
|
|
8
|
+
app) is another. This guide shows how to wire a playbook runtime into
|
|
9
|
+
your own host.
|
|
10
|
+
|
|
11
|
+
> **Release note:** this guide targets the semver-stable 1.0 six-port
|
|
12
|
+
> contract; see the [CHANGELOG](../CHANGELOG.md) for migration details.
|
|
13
|
+
|
|
14
|
+
## The runtime contract
|
|
15
|
+
|
|
16
|
+
The port and runtime contracts live in the type-only module
|
|
17
|
+
[`@sublang/playbook/runtime`](../src/runtime.ts) — a public,
|
|
18
|
+
semver-stable surface (`PlayerResult`, `PlaybookPorts`,
|
|
19
|
+
`PlaybookRuntime`, `PlaybookSession`, `PlayerCallOptions`,
|
|
20
|
+
`CaptainCallOptions`, `CaptainResult`, `PlaybookTraceEvent`, and
|
|
21
|
+
`PlaybookRuntimeFactory`) that imports no CODE or FSM types, so a host
|
|
22
|
+
satisfies it once and inherits every playbook. The CODE runtime
|
|
23
|
+
re-exports `PlayerResult`, `PlaybookPorts`, `PlaybookSession`, and
|
|
24
|
+
`PlaybookRuntime` from `@sublang/playbook/code/playbook`;
|
|
25
|
+
`PlaybookRuntimeFactory` is available from `@sublang/playbook/runtime`.
|
|
26
|
+
|
|
27
|
+
Generated linked runtimes reuse the XState integration engine exposed
|
|
28
|
+
as `@sublang/playbook/xstate-runtime`, including strict JSON
|
|
29
|
+
validation, normalized snapshots, quiescence waiting, and the
|
|
30
|
+
nested-playbook bridge.
|
|
31
|
+
|
|
32
|
+
## Constructing a runtime against your own ports
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import createPlaybookRuntime from '@sublang/playbook/code/playbook';
|
|
36
|
+
import type {
|
|
37
|
+
CaptainCallOptions,
|
|
38
|
+
CaptainResult,
|
|
39
|
+
PlaybookPorts,
|
|
40
|
+
} from '@sublang/playbook/runtime';
|
|
41
|
+
import { randomUUID } from 'node:crypto';
|
|
42
|
+
import PQueue from 'p-queue';
|
|
43
|
+
|
|
44
|
+
declare const captainAdapter: {
|
|
45
|
+
run(
|
|
46
|
+
prompt: string,
|
|
47
|
+
options: {
|
|
48
|
+
signal: AbortSignal;
|
|
49
|
+
visibility: 'visible' | 'hidden';
|
|
50
|
+
resume: string | false;
|
|
51
|
+
allowedTools?: readonly string[];
|
|
52
|
+
},
|
|
53
|
+
): Promise<CaptainResult>;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Construct one host-wide lane and reuse it for every runtime. Passing each
|
|
57
|
+
// call's signal to both the lane and adapter cancels queued and active work.
|
|
58
|
+
const captainLane = new PQueue({ concurrency: 1 });
|
|
59
|
+
|
|
60
|
+
async function runCaptain(
|
|
61
|
+
prompt: string,
|
|
62
|
+
signal: AbortSignal,
|
|
63
|
+
options: CaptainCallOptions,
|
|
64
|
+
): Promise<CaptainResult> {
|
|
65
|
+
return await captainLane.add(
|
|
66
|
+
() => captainAdapter.run(prompt, { signal, ...options }),
|
|
67
|
+
{ signal },
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ports: PlaybookPorts = {
|
|
72
|
+
callPlayer: async (playerId, prompt, signal, { resume }) => {
|
|
73
|
+
// `resume === false` starts fresh; a string selects that player's
|
|
74
|
+
// prior backend conversation. Return the adapter's next token.
|
|
75
|
+
return { status: 'ok', finalText: 'done', resumeToken: 'next-token' };
|
|
76
|
+
},
|
|
77
|
+
callCaptain: async (prompt, signal, options) => {
|
|
78
|
+
// Forward every option exactly: omission preserves configured tools, while
|
|
79
|
+
// an explicit empty allowlist requests a tool-free call and must fail closed
|
|
80
|
+
// when the adapter cannot enforce it.
|
|
81
|
+
return await runCaptain(prompt, signal, options);
|
|
82
|
+
},
|
|
83
|
+
callJudge: async (prompt, signal) => {
|
|
84
|
+
// Judge work is hidden control work: run it fresh and tool-free.
|
|
85
|
+
const result = await runCaptain(prompt, signal, {
|
|
86
|
+
visibility: 'hidden',
|
|
87
|
+
resume: false,
|
|
88
|
+
allowedTools: [],
|
|
89
|
+
});
|
|
90
|
+
if (result.status !== 'ok' || result.finalText === undefined) {
|
|
91
|
+
throw new Error(result.error ?? 'Judge call failed');
|
|
92
|
+
}
|
|
93
|
+
return result.finalText;
|
|
94
|
+
},
|
|
95
|
+
callPlaybook: async (request, signal) => {
|
|
96
|
+
throw new Error('No nested playbook host configured');
|
|
97
|
+
},
|
|
98
|
+
emitStatus: async (message, data) => {
|
|
99
|
+
/* … */
|
|
100
|
+
},
|
|
101
|
+
emitTelemetry: async ({ topic, payload }) => {
|
|
102
|
+
/* … */
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const runtime = createPlaybookRuntime({
|
|
107
|
+
coderPlayer: 'claude',
|
|
108
|
+
reviewerPlayer: 'codex',
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const playbookSessionId = randomUUID();
|
|
112
|
+
await runtime.init({
|
|
113
|
+
sessionId: playbookSessionId,
|
|
114
|
+
playbookId: 'code',
|
|
115
|
+
rootSessionId: playbookSessionId,
|
|
116
|
+
depth: 0,
|
|
117
|
+
ports,
|
|
118
|
+
});
|
|
119
|
+
await runtime.handleBossInput({
|
|
120
|
+
text: 'Start fixing the bug',
|
|
121
|
+
signal: new AbortController().signal,
|
|
122
|
+
});
|
|
123
|
+
await runtime.dispose();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Sessions and traces
|
|
127
|
+
|
|
128
|
+
Every init-to-dispose lifecycle is one playbook session. Its
|
|
129
|
+
`playbook.trace` telemetry carries that immutable ID plus a contiguous
|
|
130
|
+
sequence across exact Boss input, judge/player calls, FSM transitions,
|
|
131
|
+
visible Captain work, nested playbook calls, status, settlement, and
|
|
132
|
+
disposal. Each resolved player starts fresh in a new playbook session
|
|
133
|
+
and then resumes only from the latest opaque `resumeToken` its adapter
|
|
134
|
+
returned; trace data and tokens never enter Boss-visible status text.
|
|
135
|
+
Because trace observers do receive opaque resume tokens, persisted
|
|
136
|
+
traces should be protected as sensitive data.
|
|
137
|
+
|
|
138
|
+
See
|
|
139
|
+
[`code.playbook.test.ts`](../reference/sdlc/code.playbook/code.playbook.test.ts)
|
|
140
|
+
for the full range of port shapes (classifier, judge, abort, interrupt,
|
|
141
|
+
status/telemetry) the runtime is contract-tested against.
|
|
142
|
+
|
|
143
|
+
## Reading the published spec contracts
|
|
144
|
+
|
|
145
|
+
The authored compiler-phase specs ship in the package and are exposed
|
|
146
|
+
as a public, semver-stable surface under `@sublang/playbook/slc/*`.
|
|
147
|
+
Resolve and read one with `import.meta.resolve` plus `fs`:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { readFile } from 'node:fs/promises';
|
|
151
|
+
import { fileURLToPath } from 'node:url';
|
|
152
|
+
|
|
153
|
+
const url = import.meta.resolve('@sublang/playbook/slc/link.md');
|
|
154
|
+
const link = await readFile(fileURLToPath(url), 'utf8');
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The four specs are [`slc/text2gears.md`](../slc/text2gears.md),
|
|
158
|
+
[`slc/gears2fsm.md`](../slc/gears2fsm.md),
|
|
159
|
+
[`slc/link.md`](../slc/link.md) — the FSM-to-runtime contract that
|
|
160
|
+
`@sublang/playbook/runtime` projects into TypeScript — and
|
|
161
|
+
[`slc/optimize.md`](../slc/optimize.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sublang/playbook",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Composable XState v5 playbook runtime with compiled Captain, CODE, and DISCUSS workflows driven by GEARS specs.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,6 +39,8 @@
|
|
|
39
39
|
"slc/text2gears.md",
|
|
40
40
|
"slc/optimize.md",
|
|
41
41
|
"reference/sdlc/captain.md",
|
|
42
|
+
"reference/sdlc/code.md",
|
|
43
|
+
"reference/sdlc/discuss.md",
|
|
42
44
|
"reference/sdlc/captain.playbook/captain.gears.md",
|
|
43
45
|
"reference/sdlc/captain.playbook/captain.fsm.ts",
|
|
44
46
|
"reference/sdlc/captain.playbook/captain.fsm.js",
|
|
@@ -74,7 +76,8 @@
|
|
|
74
76
|
"reference/sdlc/discuss.playbook/discuss.playbook.d.ts",
|
|
75
77
|
"reference/sdlc/discuss.playbook/discuss.registry.ts",
|
|
76
78
|
"reference/sdlc/discuss.playbook/discuss.registry.js",
|
|
77
|
-
"reference/sdlc/discuss.playbook/discuss.registry.d.ts"
|
|
79
|
+
"reference/sdlc/discuss.playbook/discuss.registry.d.ts",
|
|
80
|
+
"docs"
|
|
78
81
|
],
|
|
79
82
|
"bin": {
|
|
80
83
|
"playbook": "reference/sdlc/code.playbook/bin/playbook.js"
|
|
@@ -117,6 +120,7 @@
|
|
|
117
120
|
"scripts": {
|
|
118
121
|
"build": "tsc",
|
|
119
122
|
"test": "vitest run",
|
|
123
|
+
"test:acceptance": "vitest run --config vitest.acceptance.config.ts",
|
|
120
124
|
"playbook": "node reference/sdlc/code.playbook/bin/playbook.js"
|
|
121
125
|
},
|
|
122
126
|
"publishConfig": {
|
|
@@ -126,7 +130,7 @@
|
|
|
126
130
|
"dependencies": {
|
|
127
131
|
"@anthropic-ai/claude-agent-sdk": "^0.3.154",
|
|
128
132
|
"@openai/codex-sdk": "^0.139.0",
|
|
129
|
-
"@sublang/cligent": "^0.
|
|
133
|
+
"@sublang/cligent": "^0.16.0",
|
|
130
134
|
"@sublang/spex": "^0.3.0",
|
|
131
135
|
"p-queue": "^9.3.1",
|
|
132
136
|
"xstate": "^5.19.4",
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: Apache-2.0 -->
|
|
2
|
+
<!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
|
|
3
|
+
|
|
4
|
+
# Code
|
|
5
|
+
|
|
6
|
+
Players:
|
|
7
|
+
|
|
8
|
+
- Coder
|
|
9
|
+
- Reviewer
|
|
10
|
+
- Committer = Coder | Reviewer
|
|
11
|
+
|
|
12
|
+
## Coder
|
|
13
|
+
|
|
14
|
+
When Boss gives a coding intent, Captain shall relay it to Coder along with the following prompt:
|
|
15
|
+
> Assess whether this can be completed in a single commit, following best practices.
|
|
16
|
+
> If yes, implement and test, updating both code and specs; otherwise, decompose into tasks as a new IR under @specs/intents (or @specs/iterations in older scaffolds) and stop without implementing any IR task.
|
|
17
|
+
> For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.
|
|
18
|
+
> Ensure @specs/map.md reflects the changes.
|
|
19
|
+
> Do not commit.
|
|
20
|
+
The resulting changes are regarded as Initial Changes.
|
|
21
|
+
|
|
22
|
+
When Reviewer raises any findings, Captain shall relay them to Coder along with the following prompt:
|
|
23
|
+
> For each review item below for the above changes, challenge or accept it, with strong reasoning, solid evidence, and comprehensive thinking.
|
|
24
|
+
> Stage all current changes that belong in the repo before making any edits, and leave your edits unstaged/untracked.
|
|
25
|
+
|
|
26
|
+
When a new IR or IR task passes review and is committed, Captain shall prompt Coder:
|
|
27
|
+
> Continue to implement IR-<#> if not all deliverables and tasks are done.
|
|
28
|
+
> Implement one task at a time (including corresponding tests if any).
|
|
29
|
+
> Stop after each task for review — do not commit yet.
|
|
30
|
+
> If relevant, mark progress in the IR.
|
|
31
|
+
The resulting changes are regarded as Initial Changes.
|
|
32
|
+
|
|
33
|
+
When an IR is done, Captain shall prompt Coder:
|
|
34
|
+
> Read IR-<#> and corresponding commits.
|
|
35
|
+
> According to @specs/meta.md, add or update spec items to fully capture:
|
|
36
|
+
>
|
|
37
|
+
> - the external behavior users rely on,
|
|
38
|
+
> - the internal system behavior, and
|
|
39
|
+
> - the integration/system test cases.
|
|
40
|
+
>
|
|
41
|
+
> The spec items should be the *minimal* set needed to reimplement code without the IR.
|
|
42
|
+
> The set should be complete and coherent.
|
|
43
|
+
> Avoid implementation specifics.
|
|
44
|
+
> Avoid redundant spec items.
|
|
45
|
+
> Ensure @specs/map.md reflects the changes.
|
|
46
|
+
|
|
47
|
+
## Reviewer
|
|
48
|
+
|
|
49
|
+
For each finding in a review round, Coder either addresses it with changes or challenges it with a rebuttal.
|
|
50
|
+
Any code change to address findings starts a new round of review, even if some findings are also rebutted.
|
|
51
|
+
Rounds continue until Reviewer raises no findings.
|
|
52
|
+
|
|
53
|
+
Spec item files are the files under @specs/ that hold spec items — @specs/packages/ and @specs/compositions/ in the current layout, or @specs/user/, @specs/dev/, and @specs/test/ in the legacy one; decision and intent records (iteration records in older scaffolds), @specs/map.md, and @specs/meta.md are not spec item files.
|
|
54
|
+
|
|
55
|
+
When Reviewer begins the first review round on changes from a Boss coding intent, Captain shall relay the intent to Reviewer.
|
|
56
|
+
|
|
57
|
+
When Reviewer begins the first review round on changes from an IR task, Captain shall relay the IR's task description to Reviewer.
|
|
58
|
+
|
|
59
|
+
When Committer commits Initial Changes, Captain shall prompt Reviewer to begin a review round:
|
|
60
|
+
> Review the latest commit.
|
|
61
|
+
> Refer to the commit message.
|
|
62
|
+
|
|
63
|
+
When any changes are made by Coder but not reviewed (outside of any Initial Changes), Captain shall prompt Reviewer to begin a review round:
|
|
64
|
+
> Review the unstaged and untracked changes in the context of the staged changes.
|
|
65
|
+
> Understand the intent.
|
|
66
|
+
|
|
67
|
+
When Reviewer begins a review round involving spec item files, Captain shall prompt Reviewer:
|
|
68
|
+
> Verify any affected spec items are:
|
|
69
|
+
>
|
|
70
|
+
> - Complete & coherent: sufficient for you to reimplement code.
|
|
71
|
+
> - Right level: external behavior users rely on or internal system behavior (organized per @specs/meta.md), not implementation specifics; integration/system testing, not unit testing.
|
|
72
|
+
> - Minimal: essential and concise; every item earns its place; also check with other items.
|
|
73
|
+
> - Well organized: spec packages are finely scoped, with high cohesion and low coupling.
|
|
74
|
+
>
|
|
75
|
+
> Flag anything missing, redundant, over-specified, or under-specified.
|
|
76
|
+
|
|
77
|
+
When Reviewer begins a review round involving any changes outside spec item files, Captain shall prompt Reviewer:
|
|
78
|
+
> Flag any issues or improvements (numbered; no duplication).
|
|
79
|
+
> Think thoroughly — don't just approve or reject.
|
|
80
|
+
|
|
81
|
+
When Reviewer begins any review round, Captain shall prompt Reviewer:
|
|
82
|
+
> For context discovery, @specs/map.md indexes all spec files and @specs/meta.md describes the spec format.
|
|
83
|
+
> Verify @specs/map.md reflects the changes.
|
|
84
|
+
> If the change is ready to commit or push, don't raise nitpicks.
|
|
85
|
+
> Do not edit files or commit; report findings only.
|
|
86
|
+
|
|
87
|
+
When Coder raises any rebuttals, Captain shall relay them to Reviewer along with the following prompt:
|
|
88
|
+
> For each rebuttal below, challenge or accept it, with strong reasoning, solid evidence, and comprehensive thinking.
|
|
89
|
+
> Do not edit files or commit; report findings only.
|
|
90
|
+
|
|
91
|
+
## Committer
|
|
92
|
+
|
|
93
|
+
When Coder makes any Initial Changes or Reviewer raises no findings on uncommitted changes, Captain shall prompt Committer:
|
|
94
|
+
> Make a commit of the changes that belong in the repo, following @specs/packages/git.md (reread if necessary).
|
|
95
|
+
> If that spec is absent, follow the legacy @specs/dev/git.md; if neither exists, follow the repository's existing commit conventions and do not search elsewhere.
|
|
96
|
+
> Write the commit message concisely.
|
|
97
|
+
|
|
98
|
+
When Captain prompts Committer and only Coder has played since the last commit, Captain shall also append:
|
|
99
|
+
> Coder is \<coder-llm\>.
|
|
100
|
+
|
|
101
|
+
When Captain prompts Committer and both Coder and Reviewer have played since the last commit, Captain shall also append:
|
|
102
|
+
> Coder is \<coder-llm\>; Reviewer is \<reviewer-llm\>.
|
|
103
|
+
|
|
104
|
+
When Captain prompts Committer, Captain shall also append:
|
|
105
|
+
> Format the `Co-authored-by` `<model>` token as the conventional human form of the substituted id (e.g., `claude-opus-4-7` → `Claude-Opus-4.7`, `gpt-5.5` → `GPT-5.5`).
|