@sublang/playbook 0.8.0 → 1.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.
Files changed (55) hide show
  1. package/README.md +243 -193
  2. package/package.json +52 -17
  3. package/reference/sdlc/captain.md +102 -0
  4. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +227 -0
  5. package/reference/sdlc/captain.playbook/captain.fsm.js +628 -0
  6. package/reference/sdlc/captain.playbook/captain.fsm.ts +851 -0
  7. package/reference/sdlc/captain.playbook/captain.gears.md +60 -0
  8. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +23 -0
  9. package/reference/sdlc/captain.playbook/captain.playbook.js +1053 -0
  10. package/reference/sdlc/captain.playbook/captain.playbook.ts +1144 -0
  11. package/reference/sdlc/code.playbook/bin/playbook.js +580 -0
  12. package/reference/sdlc/code.playbook/bin/run.js +893 -0
  13. package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -4
  14. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +2 -2
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.js +1 -1
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +6 -6
  17. package/reference/sdlc/code.playbook/code.fsm.js +334 -102
  18. package/reference/sdlc/code.playbook/code.fsm.ts +470 -182
  19. package/reference/sdlc/code.playbook/code.gears.md +11 -10
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +18 -9
  21. package/reference/sdlc/code.playbook/code.playbook.js +1098 -202
  22. package/reference/sdlc/code.playbook/code.playbook.ts +1440 -258
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +17 -5
  24. package/reference/sdlc/code.playbook/code.registry.js +49 -34
  25. package/reference/sdlc/code.playbook/code.registry.ts +75 -41
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +16 -8
  27. package/reference/sdlc/code.playbook/playbook-captain.js +1005 -240
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1310 -301
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +68 -0
  30. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +396 -0
  31. package/reference/sdlc/discuss.playbook/discuss.fsm.js +2066 -0
  32. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +2464 -0
  33. package/reference/sdlc/discuss.playbook/discuss.gears.md +251 -0
  34. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +113 -0
  35. package/reference/sdlc/discuss.playbook/discuss.playbook.js +1514 -0
  36. package/reference/sdlc/discuss.playbook/discuss.playbook.ts +1926 -0
  37. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +58 -0
  38. package/reference/sdlc/discuss.playbook/discuss.registry.js +97 -0
  39. package/reference/sdlc/discuss.playbook/discuss.registry.ts +153 -0
  40. package/slc/gears2fsm.md +557 -57
  41. package/slc/link.md +1097 -80
  42. package/slc/optimize.md +88 -0
  43. package/slc/text2gears.md +247 -5
  44. package/src/runtime.d.ts +145 -3
  45. package/src/runtime.ts +200 -2
  46. package/src/xstate-runtime.d.ts +94 -0
  47. package/src/xstate-runtime.js +1247 -0
  48. package/src/xstate-runtime.ts +1802 -0
  49. package/reference/sdlc/code.playbook/bin/playbook-code.js +0 -487
  50. package/reference/sdlc/code.playbook/code.tmux-play.d.ts +0 -4
  51. package/reference/sdlc/code.playbook/code.tmux-play.js +0 -11
  52. package/reference/sdlc/code.playbook/code.tmux-play.ts +0 -29
  53. package/reference/sdlc/code.playbook/playbook-code.config.template.yaml +0 -72
  54. package/reference/sdlc/code.playbook/tmux-play.config.yaml +0 -55
  55. package/reference/sdlc/code.playbook/tmux-play.production.config.yaml +0 -38
package/README.md CHANGED
@@ -7,28 +7,49 @@
7
7
  [![Node.js](https://img.shields.io/node/v/@sublang/playbook)](https://nodejs.org/)
8
8
  [![CI](https://github.com/sublang-ai/playbook/actions/workflows/ci.yml/badge.svg)](https://github.com/sublang-ai/playbook/actions/workflows/ci.yml)
9
9
 
10
- *Skills made reliable through state machines and visualization.*
10
+ _Skills made reliable through state machines and visualization._
11
11
 
12
12
  playbook is a compiler stack and reference implementation for turning a
13
13
  natural-language procedure into a runnable, inspectable state-machine
14
- agent — a *playbook* — that orchestrates other AI agents (players) per a
15
- spec written in plain prose. Three phases take prose to runtime:
16
-
17
- 1. **text GEARS** ([slc/text2gears.md](slc/text2gears.md)) normative
18
- spec items, one per state behavior, partitioned by trigger and prompt
19
- content.
14
+ agent — a _playbook_ — that orchestrates other AI agents per a spec
15
+ written in plain prose. Instead of a free-form LLM deciding what to do
16
+ next, an explicit finite state machine drives the workflow, every
17
+ Captain-, player-, and nested-playbook-invoking state pinned 1:1 to a
18
+ human-readable spec item and contract-tested.
19
+
20
+ A quick vocabulary, used throughout: the **Boss** is you, the human in
21
+ charge; the **Captain** is the agent pane the Boss talks to;
22
+ **players** are the coding agents a playbook delegates work to; and a
23
+ hidden **judge** classifies free-text Boss input into state-machine
24
+ events, so playbooks need no slash commands of their own. Playbooks run
25
+ inside a *host* built on
26
+ [cligent](https://github.com/sublang-ai/cligent), the sibling SDK that
27
+ drives coding-agent CLIs; cligent's `tmux-play` terminal app is the
28
+ reference host.
29
+
30
+ Three phases take prose to runtime:
31
+
32
+ 1. **text → GEARS** ([slc/text2gears.md](slc/text2gears.md)) — GEARS is
33
+ the intermediate representation: normative spec items, one per state
34
+ behavior, partitioned by trigger and prompt content.
20
35
  2. **GEARS → FSM** ([slc/gears2fsm.md](slc/gears2fsm.md)) — an XState v5
21
- finite state machine; each gear maps to one captain-invoking state
22
- with a typed Captain actor contract.
36
+ finite state machine; each gear maps to one direct-Captain,
37
+ delegated-player, or nested-playbook state with a typed actor
38
+ contract. The compiled FSM can be visualized and simulated with the
39
+ bundled [XState sketch visualizer](views/sketch).
23
40
  3. **FSM → runtime** ([slc/link.md](slc/link.md)) — a host-agnostic
24
41
  module that drives Boss turns through ports the host wires up
25
42
  (cligent's `tmux-play` is one such host).
26
43
 
27
- The repository is itself an end-to-end worked example: this
28
- package — `@sublang/playbook` — is the SDLC coding workflow,
29
- generated from [`reference/sdlc/code.md`](reference/sdlc/code.md)
30
- as its prose source. The runtime drives a coder / reviewer /
31
- committer loop end to end.
44
+ The repository contains end-to-end worked examples. The generic default
45
+ Captain is generated from
46
+ [`reference/sdlc/captain.md`](reference/sdlc/captain.md), CODE — a
47
+ coder / reviewer / committer development loop from
48
+ [`reference/sdlc/code.md`](reference/sdlc/code.md), and DISCUSS two
49
+ agents converging on spec items — from
50
+ [`reference/sdlc/discuss.md`](reference/sdlc/discuss.md). Together they
51
+ show direct Captain work, sequential nested playbook calls, and
52
+ parallel players.
32
53
 
33
54
  ## Getting started — the reference CODE playbook
34
55
 
@@ -40,7 +61,26 @@ the runtime registered behind the built-in Playbook Captain shell for
40
61
  cligent's `tmux-play` host out of the box.
41
62
  The compiled artifacts live under
42
63
  [`reference/sdlc/code.playbook/`](reference/sdlc/code.playbook),
43
- the slc pipeline's `<basename>.<pipeline>/` output directory.
64
+ the [slc](https://github.com/sublang-ai/slc) compiler pipeline's
65
+ `<basename>.<pipeline>/` output directory.
66
+
67
+ > **Release status:** 1.0.0 is the first release of the composed system: the
68
+ > compiled default Captain, CODE and DISCUSS, nested playbook calls, the
69
+ > semver-stable six-port runtime contract (see
70
+ > [docs/embedding.md](docs/embedding.md)), and non-interactive `playbook run`
71
+ > with parked-session resume and per-run agent tuning.
72
+
73
+ ### Requirements
74
+
75
+ - Node.js >= 20.6.0.
76
+ - `tmux` and [`glow`](https://github.com/charmbracelet/glow#installation)
77
+ on `PATH` — the `tmux-play` host renders Markdown pane output with
78
+ glow and fails fast without it.
79
+ - Auth for the seeded agents: a signed-in
80
+ [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview)
81
+ (`~/.claude`) or `ANTHROPIC_API_KEY`, and a signed-in
82
+ [Codex CLI](https://github.com/openai/codex) (`~/.codex`) or
83
+ `OPENAI_API_KEY`.
44
84
 
45
85
  ### Install (users)
46
86
 
@@ -55,232 +95,250 @@ npm install -g @sublang/playbook
55
95
  Then launch the reference playbook in a `tmux-play` session:
56
96
 
57
97
  ```sh
58
- playbook-code
98
+ playbook
59
99
  ```
60
100
 
61
- For a one-shot run without a global install, use the same command
62
- through npx:
101
+ For a one-shot run without a global install, invoke the scoped
102
+ package through npx (it runs the package's `playbook` bin):
63
103
 
64
104
  ```sh
65
- npx playbook-code
105
+ npx @sublang/playbook
66
106
  ```
67
107
 
68
- On first run, `playbook-code` creates a commented user config at
69
- `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook-code.config.yaml`
70
- from the bundled template, prints that path to stderr, then checks the
71
- declared adapters before launching. Later runs reuse that file and do
72
- not overwrite it.
108
+ On first run, `playbook` creates a commented user config at
109
+ `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml`
110
+ from the bundled starter, prints that path to stderr, then composes a
111
+ `tmux-play` config and checks the declared adapters before launching.
112
+ Later runs reuse that file and do not overwrite it.
73
113
 
74
114
  Known adapter readiness is intentionally light: `claude` is ready when
75
115
  local Claude Code auth exists or `ANTHROPIC_API_KEY` is set; `codex` is
76
116
  ready when local Codex CLI auth exists or `OPENAI_API_KEY` is set. If a
77
- known adapter is not ready, `playbook-code` prints its own help text
78
- with the config path, auth pointers, and agent-swap recipe, then exits
79
- without launching. You can view the same recovery text at any time:
117
+ known adapter is not ready, `playbook` prints its own help text with the
118
+ config path, auth pointers, and agent-swap recipe, then exits without
119
+ launching. You can view the same recovery text at any time:
80
120
 
81
121
  ```sh
82
- playbook-code --help
122
+ playbook --help
83
123
  ```
84
124
 
85
- The seed template runs each agent in cligent's protected auto mode
86
- (`permissions.mode: auto`), suppressing routine approval prompts. Its
87
- Codex Reviewer also grants `permissions.writablePaths: [.git]` so git
88
- metadata writes stay available under auto mode without switching to
89
- bypass permissions.
125
+ `playbook --list` prints the configured playbooks with their slash
126
+ commands and intents. Every seeded agent the Captain and both roles —
127
+ runs in cligent's protected auto mode (`permissions.mode: auto`), so
128
+ routine in-session approval prompts are suppressed without switching to
129
+ bypass permissions. The seeded Codex Reviewer additionally grants
130
+ `permissions.writablePaths: [.git]` so git metadata writes stay
131
+ available under the Codex sandbox; the Claude agents need no such grant
132
+ under their auto mode.
133
+
134
+ ### Run a playbook non-interactively
135
+
136
+ `playbook run <from> [task]` runs one playbook once, without tmux-play
137
+ and without a config entry — point it straight at a registry module:
138
+
139
+ ```sh
140
+ playbook run @sublang/playbook/code/registry "add a test for parseArgs" \
141
+ --player coder=claude --player reviewer=codex --cwd ./my-repo
142
+ ```
143
+
144
+ `[task]` is read from stdin when omitted — pipe long or multi-line
145
+ intents the same way you would to `claude -p` or `codex exec`. Roles
146
+ and the captain default to `claude`; bind them with
147
+ `--player <role>=<agent>` and `--captain <agent>`, where `<agent>` is
148
+ `<adapter>[:<model>][@<effort>]` — say `codex:gpt-5.5@xhigh`, or
149
+ `claude@high` for the default model at high reasoning effort; the
150
+ model keeps every interior colon (`opencode:ollama/llama3:8b@max`),
151
+ and unsupported efforts are rejected up front naming the adapter's
152
+ supported values. Pass a playbook option with
153
+ `--option <key>=<value>`, and add `--json` to print one JSON envelope
154
+ (`outcome`, `sessionId`, and the output or pending questions) instead
155
+ of plain text. It exits `0` on a terminal outcome, `2` on failure, `3`
156
+ when the playbook needs a Boss reply, and `1` on a bad argument or
157
+ module. See [PBCLI-18](specs/user/playbook-cli.md#pbcli-18).
158
+
159
+ When the playbook stops to ask the Boss something, the run is parked,
160
+ not lost: the question prints to stdout, the session is saved under
161
+ `${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions/`, and stderr
162
+ names the exact command that continues it. Answer with `resume`:
163
+
164
+ ```sh
165
+ playbook run resume 4f2c…9ab1 "keep the scope small; skip the docs"
166
+ playbook run resume --last # most recently parked session; reply on stdin
167
+ ```
168
+
169
+ A resumed run picks the playbook up exactly where it parked — same
170
+ session id, same workflow state, and each agent continues its own
171
+ conversation — then prints the final output and exits `0`, or parks
172
+ again with the next question and exits `3`. The agent lineup, options,
173
+ and working directory are stored with the session, so `resume` takes no
174
+ binding flags. In scripts, capture the session id from the `--json`
175
+ envelope, like Claude Code's `session_id` or `codex exec resume`. See
176
+ [PBCLI-22](specs/user/playbook-cli.md#pbcli-22) and
177
+ [DR-014](specs/decisions/014-durable-one-shot-run-sessions.md).
90
178
 
91
179
  ### Configure agents
92
180
 
93
181
  Edit the seeded user config when you want different coding agents:
94
182
 
95
183
  ```sh
96
- $EDITOR "${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook-code.config.yaml"
184
+ $EDITOR "${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml"
185
+ ```
186
+
187
+ To retune a single launch without editing that file, overlay a
188
+ fragment in the same format with `--with` (repeatable, later files
189
+ win; maps merge recursively, other values replace):
190
+
191
+ ```sh
192
+ playbook --with fast-lineup.yaml
193
+ ```
194
+
195
+ ```yaml
196
+ # fast-lineup.yaml — swap the Coder for one run; nothing is written back.
197
+ profiles:
198
+ codex-fast: { adapter: codex, model: gpt-5.5, reasoningEffort: medium }
199
+ playbooks:
200
+ code:
201
+ players:
202
+ coder: codex-fast
97
203
  ```
98
204
 
99
- Both CODE players can use `claude` or `codex`; other adapter ids are
100
- passed through to `tmux-play` with a warning because `playbook-code`
101
- does not know how to preflight their auth. The safe tuning points are
102
- `captain.adapter`, `captain.model`, and each role's `adapter` and
103
- `model` under `players.coder` / `players.reviewer`. The composer owns
104
- `captain.from` and points it at the Playbook Captain shell adapter, and
105
- it owns the `coder` / `reviewer` role keys, so leave those keys as-is;
106
- the runtime binds to those host-configuration invariants per
107
- [PBRT-4](specs/user/playbook-runtime.md#pbrt-4) and derives the
108
- `<coder-llm>` / `<reviewer-llm>` substitution strings from each role's
109
- `model` when pinned and `adapter` otherwise so the Committer's
110
- commit-message trailers can name the concrete model
111
- (e.g. `claude-opus-4-8[1m]`) rather than the adapter family
112
- (`claude`).
113
-
114
- `players.committer` is an optional alias naming which role `coder`
115
- or `reviewer` — runs the commit turn; the seeded overlay points it at
116
- the Coder. Absent the alias the Committer falls back to the Coder
117
- ([PBRT-8](specs/user/playbook-runtime.md#pbrt-8)).
118
-
119
- For example, the seeded overlay runs the Coder on Claude Opus 4.8 1m
120
- and the Reviewer on GPT-5.5, with the Committer aliased to the Coder:
205
+ See [PBCLI-25](specs/user/playbook-cli.md#pbcli-25) and
206
+ [DR-015](specs/decisions/015-per-run-agent-tuning.md).
207
+
208
+ The config is top-level (no `config:` wrapper): a `profiles` map of
209
+ reusable agent settings, a `captain` agent (it runs both visible
210
+ Captain work and hidden judge calls), optional `layout` /
211
+ `notifications` / `theme`, and a `playbooks` map of enabled playbooks.
212
+ Each `captain` or `players.<role>` value is a profile id or an adapter
213
+ shorthand (`claude`, `codex`); other adapter ids are passed through to
214
+ `tmux-play` with a warning because `playbook` cannot preflight their
215
+ auth. Name profiles by their underlying agent/model (e.g. `claude-opus`,
216
+ `codex-gpt`) so the profile ids read distinctly from the player roles
217
+ that reference them. Within a `playbooks.<id>` block, `from` (the
218
+ registry module), `command` (an optional slash-command override), and
219
+ `players` are launcher-owned; every other key is that playbook's option
220
+ slice. The launcher injects the rest you do not write host wiring by
221
+ hand.
222
+
223
+ For example, the seeded config runs the Coder on Claude Opus 4.8 1m and
224
+ the Reviewer on GPT-5.5:
121
225
 
122
226
  ```yaml
123
- captain:
124
- adapter: claude
125
- model: claude-opus-4-8
126
- reasoningEffort: high
127
- permissions:
128
- mode: auto
129
-
130
- players:
131
- coder: # role key must stay `coder` — see PBRT-4
227
+ profiles:
228
+ claude-opus:
229
+ adapter: claude
230
+ model: claude-opus-4-8
231
+ reasoningEffort: high
232
+ permissions:
233
+ mode: auto # protected auto mode for the Claude Captain
234
+ claude-opus-1m:
132
235
  adapter: claude
133
236
  model: claude-opus-4-8[1m]
134
237
  reasoningEffort: xhigh
135
238
  permissions:
136
- mode: auto
137
- reviewer: # role key must stay `reviewer` — see PBRT-4
239
+ mode: auto # protected auto mode for the Claude Coder
240
+ codex-gpt:
138
241
  adapter: codex
139
242
  model: gpt-5.5
140
243
  reasoningEffort: xhigh
141
244
  permissions:
142
245
  mode: auto
143
246
  writablePaths:
144
- - .git # allow git metadata writes under Codex auto mode
145
- committer: coder # which role commits — `coder` or `reviewer`
247
+ - .git # allow git metadata writes under Codex auto mode
248
+
249
+ captain: claude-opus
250
+
251
+ playbooks:
252
+ code:
253
+ from: '@sublang/playbook/code/registry'
254
+ players:
255
+ coder: claude-opus-1m
256
+ reviewer: codex-gpt
257
+ committer: coder # which role commits — `coder` or `reviewer`
146
258
  ```
147
259
 
148
- Normal `playbook-code` runs use the seeded path above. If you need a
149
- separate config file for a one-off run, pass it explicitly; this bypasses
150
- the seed and readiness gate and forwards the arguments to `tmux-play`
151
- verbatim, as pinned in
152
- [PBCODE-1](specs/user/playbook-code.md#pbcode-1):
260
+ `committer` is CODE's one option: an alias naming which role runs the
261
+ commit turn (fallback semantics:
262
+ [PBRT-8](specs/dev/playbook-runtime.md#pbrt-8)). Each role's per-run
263
+ prompt names its pinned `model`, else its `adapter`
264
+ ([PBRT-4](specs/user/playbook-runtime.md#pbrt-4)), so commit trailers
265
+ can credit the concrete model (e.g. `claude-opus-4-8[1m]`) rather than
266
+ the adapter family.
267
+
268
+ If you need a separate config file for a one-off run, pass a raw
269
+ `tmux-play` config explicitly; this bypasses the seed, composition, and
270
+ readiness gate and forwards the arguments to `tmux-play` verbatim
271
+ ([PBCLI-1](specs/user/playbook-cli.md#pbcli-1)):
153
272
 
154
273
  ```sh
155
- playbook-code --config ./playbook-code.config.yaml
274
+ playbook --config ./tmux-play.config.yaml
156
275
  ```
157
276
 
158
277
  ### Install (contributors / from source)
159
278
 
160
- Clone, install, and run the suite locally:
279
+ The checked-in lockfile resolves every runtime contract required by the
280
+ source tree:
161
281
 
162
282
  ```sh
163
283
  git clone https://github.com/sublang-ai/playbook.git
164
284
  cd playbook
165
- pnpm install
285
+ pnpm install --frozen-lockfile
166
286
  pnpm build
167
287
  pnpm test
168
288
  ```
169
289
 
170
- `pnpm install` here installs the `@sublang/cligent` version pinned
171
- in the checked-in `pnpm-lock.yaml` the same version CI installs
172
- via `--frozen-lockfile`, so contributor checkouts and CI agree.
173
- The published `package.json` declares `@sublang/cligent` as
174
- `^0.13.0`, so an end-user install with no lockfile (e.g., `npm
175
- install -g @sublang/playbook`) resolves a compatible cligent 0.13.x
176
- release (see [RELEASE-14](specs/dev/release.md#release-14)). To
177
- refresh the contributor pin within that range, run
178
- `pnpm update @sublang/cligent` and commit the resulting
179
- `pnpm-lock.yaml` change. To adopt a later cligent minor, update the
180
- `package.json` specifier and lockfile together.
181
- No local link required for any of this. To point pnpm at a local
182
- `cligent` checkout
183
- instead, copy
184
- [`pnpm-workspace.yaml.example`](pnpm-workspace.yaml.example)
185
- into place; the override is gitignored so it never leaks into a
186
- production install.
187
-
188
- Drive a Boss turn against the source tree (uses the developer
189
- [`tmux-play.config.yaml`](reference/sdlc/code.playbook/tmux-play.config.yaml)
190
- that imports the compiled Playbook Captain shell via relative path):
290
+ To co-develop Playbook with an unreleased cligent checkout, clone
291
+ cligent beside this repository, build it, and copy
292
+ `pnpm-workspace.yaml.example` to the gitignored
293
+ `pnpm-workspace.yaml`. That optional override links the sibling checkout
294
+ in place of the registry version. Do not commit the local lockfile
295
+ rewrite it produces ([RELEASE-11](specs/dev/release.md#release-11)).
296
+
297
+ Drive a Boss turn against the source tree with the launcher, which
298
+ resolves `tmux-play`, the Playbook Captain shell, and the CODE registry
299
+ from the local package:
191
300
 
192
301
  ```sh
193
- pnpm exec tmux-play --config reference/sdlc/code.playbook/tmux-play.config.yaml
302
+ pnpm playbook
194
303
  ```
195
304
 
196
- `pnpm exec` resolves `tmux-play` from the package's local
197
- `node_modules/.bin/`, so this works whether or not `@sublang/cligent` is
198
- installed globally.
305
+ On first run this seeds the generic config at
306
+ `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml`
307
+ (see [Configure agents](#configure-agents)) and launches the composed
308
+ session, so this works whether or not `@sublang/cligent` is installed
309
+ globally.
199
310
 
200
311
  ### Running a Boss turn
201
312
 
202
313
  The Boss pane starts at the Playbook Captain shell. Use `/code <task>`
203
314
  to explicitly select the CODE playbook, or use ordinary text and let the
204
- shell route it. Once a turn reaches CODE, the CODE judge classifies it
205
- into an FSM event (start a coding turn, continue or summarize an IR,
206
- interrupt to a named state, or nothing) per
315
+ compiled default Captain ask a material routing question or plan one or more
316
+ enabled playbook calls. It cannot answer the initial intent directly;
317
+ calls run sequentially so Captain can reassess after every child result
318
+ and then return a concrete result or actionable conclusion. Once a turn
319
+ reaches CODE, the CODE judge classifies it into an FSM event (start a coding
320
+ turn, continue or summarize an iteration, interrupt to a named state, or
321
+ nothing) per
207
322
  [PBRT-1](specs/user/playbook-runtime.md#pbrt-1).
208
323
  When a player surfaces a clarifying question
209
- the FSM parks at `awaitBossReply` and the pane shows the question; your
210
- next turn is normally classified as the reply, or a fresh directive
324
+ the FSM parks, the pane shows the question, and your
325
+ next turn is normally classified as the reply or a fresh directive
211
326
  abandons it ([PBRT-2](specs/user/playbook-runtime.md#pbrt-2)).
212
327
 
213
328
  The Captain pane shows `/code` start/stop/finished status with `◇` lines
214
- and streams the CODE state machine with the four-glyph vocabulary `◆ ▸ ⮕ ⤷` per
215
- [PBRT-3](specs/user/playbook-runtime.md#pbrt-3), while player prompts
216
- ride their own panes.
217
-
218
- Published configs should import the shell adapter from
219
- `@sublang/playbook/playbook-captain`. Existing explicit configs that
220
- still import `@sublang/playbook/code/tmux-play` keep resolving through
221
- a compatibility shim that delegates to the same shell with CODE
222
- registered.
329
+ and streams CODE progress with captain-speech classification/questions
330
+ per [PBRT-3](specs/user/playbook-runtime.md#pbrt-3), while player
331
+ prompts ride their own panes.
223
332
 
224
333
  ### Embedding the runtime in your own host
225
334
 
226
- The runtime is host-agnostic; the `tmux-play` adapter is one host.
227
- The port and runtime contracts live in the type-only module
228
- [`@sublang/playbook/runtime`](src/runtime.ts) a public, semver-stable
229
- surface (`PlayerResult`, `PlaybookPorts`, `PlaybookRuntime`,
230
- `PlaybookRuntimeFactory`) that imports no CODE or FSM types, so a host
231
- satisfies it once and inherits every playbook. The CODE runtime
232
- re-exports `PlayerResult`, `PlaybookPorts`, and `PlaybookRuntime` from
233
- `@sublang/playbook/code/playbook`; `PlaybookRuntimeFactory` is available
234
- from `@sublang/playbook/runtime`.
235
- Construct the runtime against your own ports:
236
-
237
- ```ts
238
- import createPlaybookRuntime from '@sublang/playbook/code/playbook';
239
- import type { PlaybookPorts } from '@sublang/playbook/runtime';
240
-
241
- const ports: PlaybookPorts = {
242
- callPlayer: async (playerId, prompt, signal) => { /* … */ },
243
- callJudge: async (prompt, signal) => { /* … */ },
244
- emitStatus: async (message, data) => { /* … */ },
245
- emitTelemetry: async ({ topic, payload }) => { /* … */ },
246
- };
247
-
248
- const runtime = createPlaybookRuntime({
249
- coderPlayer: 'claude',
250
- reviewerPlayer: 'codex',
251
- });
252
-
253
- await runtime.init(ports);
254
- await runtime.handleBossInput({
255
- text: 'Start fixing the bug',
256
- signal: new AbortController().signal,
257
- });
258
- await runtime.dispose();
259
- ```
260
-
261
- See
262
- [`code.playbook.test.ts`](reference/sdlc/code.playbook/code.playbook.test.ts)
263
- for the full range of port shapes (classifier, judge, abort, interrupt,
264
- status/telemetry) the runtime is contract-tested against.
265
-
266
- ### Reading the published spec contracts
267
-
268
- The authored compiler-phase specs ship in the package and are exposed
269
- as a public, semver-stable surface under `@sublang/playbook/slc/*`.
270
- Resolve and read one with `import.meta.resolve` plus `fs`:
271
-
272
- ```ts
273
- import { readFile } from 'node:fs/promises';
274
- import { fileURLToPath } from 'node:url';
275
-
276
- const url = import.meta.resolve('@sublang/playbook/slc/link.md');
277
- const link = await readFile(fileURLToPath(url), 'utf8');
278
- ```
279
-
280
- The three specs are [`slc/text2gears.md`](slc/text2gears.md),
281
- [`slc/gears2fsm.md`](slc/gears2fsm.md), and [`slc/link.md`](slc/link.md)
282
- — the FSM-to-runtime contract that `@sublang/playbook/runtime` projects
283
- into TypeScript.
335
+ The runtime is host-agnostic the `tmux-play` adapter is one host. The
336
+ port and runtime contracts live in the type-only, semver-stable module
337
+ [`@sublang/playbook/runtime`](src/runtime.ts): a host satisfies the six
338
+ ports once and inherits every playbook. See
339
+ [docs/embedding.md](docs/embedding.md) for the contract surface, a
340
+ complete ports example, session/trace semantics, and how to read the
341
+ published compiler-phase specs from the package.
284
342
 
285
343
  ## Workflow
286
344
 
@@ -288,33 +346,25 @@ playbook is itself spec-driven: the compiler phases are specs in `slc/`,
288
346
  and the reference playbook is regenerated from its prose source. The
289
347
  loop:
290
348
 
291
- 1. **Edit source.** For the reference, that's
292
- [`reference/sdlc/code.md`](reference/sdlc/code.md).
349
+ 1. **Edit source.** The worked examples include
350
+ [`reference/sdlc/code.md`](reference/sdlc/code.md) and the generic
351
+ [`reference/sdlc/captain.md`](reference/sdlc/captain.md).
293
352
  2. **Recompile gears** per [`slc/text2gears.md`](slc/text2gears.md) into
294
- the package's `code.gears.md`.
295
- 3. **Recompile FSM** per [`slc/gears2fsm.md`](slc/gears2fsm.md) into
296
- the package's `code.fsm.ts`.
353
+ the source's `<name>.playbook/<name>.gears.md`.
354
+ 3. **Recompile FSM and runtime** per
355
+ [`slc/gears2fsm.md`](slc/gears2fsm.md) and
356
+ [`slc/link.md`](slc/link.md) into that playbook artifact directory.
297
357
  4. **Sync runtime, tests, and downstream specs** so `pnpm test` stays
298
358
  green and the introspect contract holds 1:1 between gear items and
299
- FSM captain-invoking states.
359
+ FSM direct-Captain, delegated-player, and nested-playbook states.
300
360
  5. **Commit** with co-author trailers per
301
361
  [`specs/dev/git.md`](specs/dev/git.md).
302
362
 
303
363
  The behavioral contract between gears and FSM
304
364
  ([PLAYBOOK-1..6](specs/dev/playbook.md)) and the runtime contract that
305
- ports satisfy ([PBRT-5..16](specs/dev/playbook-runtime.md)) are pinned
306
- in [`specs/dev/`](specs/dev/) and verified by tests under the reference
307
- package.
308
-
309
- ## Requirements
310
-
311
- - Node.js ≥ 20.6.0 (the `playbook-code` shim uses
312
- `import.meta.resolve`, unflagged since this release)
313
- - pnpm 9 (for the reference package)
314
- - A configured `tmux-play` host (for live Boss turns) — requires
315
- `tmux` and [`glow`](https://github.com/charmbracelet/glow#installation)
316
- on `PATH`; cligent 0.4+ uses `glow` to render Markdown pane
317
- output and fails fast without it
365
+ ports satisfy ([the PBRT dev items](specs/dev/playbook-runtime.md)) are
366
+ pinned in [`specs/dev/`](specs/dev/) and verified by tests under the
367
+ reference package.
318
368
 
319
369
  ## Contributing
320
370