@sublang/playbook 0.9.0 → 1.3.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 (51) hide show
  1. package/README.md +190 -151
  2. package/package.json +50 -6
  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 +158 -12
  12. package/reference/sdlc/code.playbook/bin/run.js +999 -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 +467 -180
  19. package/reference/sdlc/code.playbook/code.gears.md +11 -10
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +16 -19
  21. package/reference/sdlc/code.playbook/code.playbook.js +199 -488
  22. package/reference/sdlc/code.playbook/code.playbook.ts +327 -566
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +0 -3
  24. package/reference/sdlc/code.playbook/code.registry.js +0 -3
  25. package/reference/sdlc/code.playbook/code.registry.ts +0 -6
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +9 -4
  27. package/reference/sdlc/code.playbook/playbook-captain.js +889 -210
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1136 -257
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +21 -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 +1165 -89
  42. package/slc/optimize.md +92 -0
  43. package/slc/text2gears.md +255 -7
  44. package/src/runtime.d.ts +146 -3
  45. package/src/runtime.ts +201 -2
  46. package/src/xstate-playbook-runtime.d.ts +201 -0
  47. package/src/xstate-playbook-runtime.js +2058 -0
  48. package/src/xstate-playbook-runtime.ts +2792 -0
  49. package/src/xstate-runtime.d.ts +95 -0
  50. package/src/xstate-runtime.js +1258 -0
  51. package/src/xstate-runtime.ts +1816 -0
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
 
@@ -91,6 +131,58 @@ bypass permissions. The seeded Codex Reviewer additionally grants
91
131
  available under the Codex sandbox; the Claude agents need no such grant
92
132
  under their auto mode.
93
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. To stop retyping those flags, set durable defaults
153
+ once in the user config's top-level `run:` block — `run.captain`,
154
+ `run.players.<role>`, and a `run.player` catch-all for any other
155
+ required role, each the same agent string; flags keep winning per
156
+ role, and `resume` always keeps the lineup stored with the parked
157
+ session ([PBCLI-28](specs/user/playbook-cli.md#pbcli-28),
158
+ [DR-017](specs/decisions/017-run-defaults-config.md)). Pass a
159
+ playbook option with
160
+ `--option <key>=<value>`, and add `--json` to print one JSON envelope
161
+ (`outcome`, `sessionId`, and the output or pending questions) instead
162
+ of plain text. It exits `0` on a terminal outcome, `2` on failure, `3`
163
+ when the playbook needs a Boss reply, and `1` on a bad argument or
164
+ module. See [PBCLI-18](specs/user/playbook-cli.md#pbcli-18).
165
+
166
+ When the playbook stops to ask the Boss something, the run is parked,
167
+ not lost: the question prints to stdout, the session is saved under
168
+ `${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions/`, and stderr
169
+ names the exact command that continues it. Answer with `resume`:
170
+
171
+ ```sh
172
+ playbook run resume 4f2c…9ab1 "keep the scope small; skip the docs"
173
+ playbook run resume --last # most recently parked session; reply on stdin
174
+ ```
175
+
176
+ A resumed run picks the playbook up exactly where it parked — same
177
+ session id, same workflow state, and each agent continues its own
178
+ conversation — then prints the final output and exits `0`, or parks
179
+ again with the next question and exits `3`. The agent lineup, options,
180
+ and working directory are stored with the session, so `resume` takes no
181
+ binding flags. In scripts, capture the session id from the `--json`
182
+ envelope, like Claude Code's `session_id` or `codex exec resume`. See
183
+ [PBCLI-22](specs/user/playbook-cli.md#pbcli-22) and
184
+ [DR-014](specs/decisions/014-durable-one-shot-run-sessions.md).
185
+
94
186
  ### Configure agents
95
187
 
96
188
  Edit the seeded user config when you want different coding agents:
@@ -99,33 +191,44 @@ Edit the seeded user config when you want different coding agents:
99
191
  $EDITOR "${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml"
100
192
  ```
101
193
 
194
+ To retune a single launch without editing that file, overlay a
195
+ fragment in the same format with `--with` (repeatable, later files
196
+ win; maps merge recursively, other values replace):
197
+
198
+ ```sh
199
+ playbook --with fast-lineup.yaml
200
+ ```
201
+
202
+ ```yaml
203
+ # fast-lineup.yaml — swap the Coder for one run; nothing is written back.
204
+ profiles:
205
+ codex-fast: { adapter: codex, model: gpt-5.5, reasoningEffort: medium }
206
+ playbooks:
207
+ code:
208
+ players:
209
+ coder: codex-fast
210
+ ```
211
+
212
+ See [PBCLI-25](specs/user/playbook-cli.md#pbcli-25) and
213
+ [DR-015](specs/decisions/015-per-run-agent-tuning.md).
214
+
102
215
  The config is top-level (no `config:` wrapper): a `profiles` map of
103
- reusable agent settings, a `captain` Judge agent, optional `layout` /
104
- `notifications` / `theme`, and a `playbooks` map of enabled playbooks. Each
105
- `captain` or `players.<role>` value is a profile id or an adapter
216
+ reusable agent settings, a `captain` agent (it runs both visible
217
+ Captain work and hidden judge calls), optional `layout` /
218
+ `notifications` / `theme`, and a `playbooks` map of enabled playbooks.
219
+ Each `captain` or `players.<role>` value is a profile id or an adapter
106
220
  shorthand (`claude`, `codex`); other adapter ids are passed through to
107
221
  `tmux-play` with a warning because `playbook` cannot preflight their
108
222
  auth. Name profiles by their underlying agent/model (e.g. `claude-opus`,
109
- `codex-gpt`) so the profile ids read distinctly from the `coder` /
110
- `reviewer` player roles that reference them. Within a `playbooks.<id>` block, `from` (the registry module),
111
- `command` (an optional slash-command override), and `players` are
112
- launcher-owned; every other key (e.g. CODE's `committer`) is that
113
- playbook's option slice. The launcher injects `captain.from` and the
114
- namespaced `<id>-<role>` host players, so you do not write those by
223
+ `codex-gpt`) so the profile ids read distinctly from the player roles
224
+ that reference them. Within a `playbooks.<id>` block, `from` (the
225
+ registry module), `command` (an optional slash-command override), and
226
+ `players` are launcher-owned; every other key is that playbook's option
227
+ slice. The launcher injects the rest — you do not write host wiring by
115
228
  hand.
116
229
 
117
- CODE's per-run `<coder-llm>` / `<reviewer-llm>` prompt strings come from
118
- each role's pinned `model`, else its `adapter`
119
- ([PBRT-4](specs/user/playbook-runtime.md#pbrt-4)) — so the Committer's
120
- commit-message trailers can name the concrete model
121
- (e.g. `claude-opus-4-8[1m]`) rather than the adapter family (`claude`).
122
- `committer` is an optional CODE alias naming which role — `coder` or
123
- `reviewer` — runs the commit turn; the seeded config points it at the
124
- Coder, and absent the alias the Committer falls back to the Coder
125
- ([PBRT-8](specs/user/playbook-runtime.md#pbrt-8)).
126
-
127
230
  For example, the seeded config runs the Coder on Claude Opus 4.8 1m and
128
- the Reviewer on GPT-5.5, with the Committer aliased to the Coder:
231
+ the Reviewer on GPT-5.5:
129
232
 
130
233
  ```yaml
131
234
  profiles:
@@ -134,13 +237,13 @@ profiles:
134
237
  model: claude-opus-4-8
135
238
  reasoningEffort: high
136
239
  permissions:
137
- mode: auto # protected auto mode for the Claude Captain
240
+ mode: auto # protected auto mode for the Claude Captain
138
241
  claude-opus-1m:
139
242
  adapter: claude
140
243
  model: claude-opus-4-8[1m]
141
244
  reasoningEffort: xhigh
142
245
  permissions:
143
- mode: auto # protected auto mode for the Claude Coder
246
+ mode: auto # protected auto mode for the Claude Coder
144
247
  codex-gpt:
145
248
  adapter: codex
146
249
  model: gpt-5.5
@@ -148,19 +251,27 @@ profiles:
148
251
  permissions:
149
252
  mode: auto
150
253
  writablePaths:
151
- - .git # allow git metadata writes under Codex auto mode
254
+ - .git # allow git metadata writes under Codex auto mode
152
255
 
153
256
  captain: claude-opus
154
257
 
155
258
  playbooks:
156
259
  code:
157
- from: "@sublang/playbook/code/registry"
260
+ from: '@sublang/playbook/code/registry'
158
261
  players:
159
262
  coder: claude-opus-1m
160
263
  reviewer: codex-gpt
161
- committer: coder # which role commits — `coder` or `reviewer`
264
+ committer: coder # which role commits — `coder` or `reviewer`
162
265
  ```
163
266
 
267
+ `committer` is CODE's one option: an alias naming which role runs the
268
+ commit turn (fallback semantics:
269
+ [PBRT-8](specs/dev/playbook-runtime.md#pbrt-8)). Each role's per-run
270
+ prompt names its pinned `model`, else its `adapter`
271
+ ([PBRT-4](specs/user/playbook-runtime.md#pbrt-4)), so commit trailers
272
+ can credit the concrete model (e.g. `claude-opus-4-8[1m]`) rather than
273
+ the adapter family.
274
+
164
275
  If you need a separate config file for a one-off run, pass a raw
165
276
  `tmux-play` config explicitly; this bypasses the seed, composition, and
166
277
  readiness gate and forwards the arguments to `tmux-play` verbatim
@@ -172,33 +283,23 @@ playbook --config ./tmux-play.config.yaml
172
283
 
173
284
  ### Install (contributors / from source)
174
285
 
175
- Clone, install, and run the suite locally:
286
+ The checked-in lockfile resolves every runtime contract required by the
287
+ source tree:
176
288
 
177
289
  ```sh
178
290
  git clone https://github.com/sublang-ai/playbook.git
179
291
  cd playbook
180
- pnpm install
292
+ pnpm install --frozen-lockfile
181
293
  pnpm build
182
294
  pnpm test
183
295
  ```
184
296
 
185
- `pnpm install` here installs the `@sublang/cligent` version pinned
186
- in the checked-in `pnpm-lock.yaml` the same version CI installs
187
- via `--frozen-lockfile`, so contributor checkouts and CI agree.
188
- The published `package.json` declares `@sublang/cligent` as
189
- `^0.13.0`, so an end-user install with no lockfile (e.g., `npm
190
- install -g @sublang/playbook`) resolves a compatible cligent 0.13.x
191
- release (see [RELEASE-14](specs/dev/release.md#release-14)). To
192
- refresh the contributor pin within that range, run
193
- `pnpm update @sublang/cligent` and commit the resulting
194
- `pnpm-lock.yaml` change. To adopt a later cligent minor, update the
195
- `package.json` specifier and lockfile together.
196
- No local link required for any of this. To point pnpm at a local
197
- `cligent` checkout
198
- instead, copy
199
- [`pnpm-workspace.yaml.example`](pnpm-workspace.yaml.example)
200
- into place; the override is gitignored so it never leaks into a
201
- production install.
297
+ To co-develop Playbook with an unreleased cligent checkout, clone
298
+ cligent beside this repository, build it, and copy
299
+ `pnpm-workspace.yaml.example` to the gitignored
300
+ `pnpm-workspace.yaml`. That optional override links the sibling checkout
301
+ in place of the registry version. Do not commit the local lockfile
302
+ rewrite it produces ([RELEASE-11](specs/dev/release.md#release-11)).
202
303
 
203
304
  Drive a Boss turn against the source tree with the launcher, which
204
305
  resolves `tmux-play`, the Playbook Captain shell, and the CODE registry
@@ -218,87 +319,33 @@ globally.
218
319
 
219
320
  The Boss pane starts at the Playbook Captain shell. Use `/code <task>`
220
321
  to explicitly select the CODE playbook, or use ordinary text and let the
221
- shell route it. Once a turn reaches CODE, the CODE judge classifies it
222
- into an FSM event (start a coding turn, continue or summarize an IR,
223
- interrupt to a named state, or nothing) per
322
+ compiled default Captain ask a material routing question or plan one or more
323
+ enabled playbook calls. It cannot answer the initial intent directly;
324
+ calls run sequentially so Captain can reassess after every child result
325
+ and then return a concrete result or actionable conclusion. Once a turn
326
+ reaches CODE, the CODE judge classifies it into an FSM event (start a coding
327
+ turn, continue or summarize an iteration, interrupt to a named state, or
328
+ nothing) per
224
329
  [PBRT-1](specs/user/playbook-runtime.md#pbrt-1).
225
330
  When a player surfaces a clarifying question
226
- the FSM parks at `awaitBossReply` and the pane shows the question; your
227
- next turn is normally classified as the reply, or a fresh directive
331
+ the FSM parks, the pane shows the question, and your
332
+ next turn is normally classified as the reply or a fresh directive
228
333
  abandons it ([PBRT-2](specs/user/playbook-runtime.md#pbrt-2)).
229
334
 
230
335
  The Captain pane shows `/code` start/stop/finished status with `◇` lines
231
- and streams the CODE state machine with the four-glyph vocabulary `◆ ▸ ⮕ ⤷` per
232
- [PBRT-3](specs/user/playbook-runtime.md#pbrt-3), while player prompts
233
- ride their own panes.
234
-
235
- Published configs import the shell adapter from
236
- `@sublang/playbook/playbook-captain` and enable CODE through a
237
- `captain.options.playbooks.code` block whose `from` is
238
- `@sublang/playbook/code/registry`. The generic `playbook` launcher
239
- composes this for you from the top-level `profiles` / `playbooks`
240
- config above.
336
+ and streams CODE progress with captain-speech classification/questions
337
+ per [PBRT-3](specs/user/playbook-runtime.md#pbrt-3), while player
338
+ prompts ride their own panes.
241
339
 
242
340
  ### Embedding the runtime in your own host
243
341
 
244
- The runtime is host-agnostic; the `tmux-play` adapter is one host.
245
- The port and runtime contracts live in the type-only module
246
- [`@sublang/playbook/runtime`](src/runtime.ts) a public, semver-stable
247
- surface (`PlayerResult`, `PlaybookPorts`, `PlaybookRuntime`,
248
- `PlaybookRuntimeFactory`) that imports no CODE or FSM types, so a host
249
- satisfies it once and inherits every playbook. The CODE runtime
250
- re-exports `PlayerResult`, `PlaybookPorts`, and `PlaybookRuntime` from
251
- `@sublang/playbook/code/playbook`; `PlaybookRuntimeFactory` is available
252
- from `@sublang/playbook/runtime`.
253
- Construct the runtime against your own ports:
254
-
255
- ```ts
256
- import createPlaybookRuntime from '@sublang/playbook/code/playbook';
257
- import type { PlaybookPorts } from '@sublang/playbook/runtime';
258
-
259
- const ports: PlaybookPorts = {
260
- callPlayer: async (playerId, prompt, signal) => { /* … */ },
261
- callJudge: async (prompt, signal) => { /* … */ },
262
- emitStatus: async (message, data) => { /* … */ },
263
- emitTelemetry: async ({ topic, payload }) => { /* … */ },
264
- };
265
-
266
- const runtime = createPlaybookRuntime({
267
- coderPlayer: 'claude',
268
- reviewerPlayer: 'codex',
269
- });
270
-
271
- await runtime.init(ports);
272
- await runtime.handleBossInput({
273
- text: 'Start fixing the bug',
274
- signal: new AbortController().signal,
275
- });
276
- await runtime.dispose();
277
- ```
278
-
279
- See
280
- [`code.playbook.test.ts`](reference/sdlc/code.playbook/code.playbook.test.ts)
281
- for the full range of port shapes (classifier, judge, abort, interrupt,
282
- status/telemetry) the runtime is contract-tested against.
283
-
284
- ### Reading the published spec contracts
285
-
286
- The authored compiler-phase specs ship in the package and are exposed
287
- as a public, semver-stable surface under `@sublang/playbook/slc/*`.
288
- Resolve and read one with `import.meta.resolve` plus `fs`:
289
-
290
- ```ts
291
- import { readFile } from 'node:fs/promises';
292
- import { fileURLToPath } from 'node:url';
293
-
294
- const url = import.meta.resolve('@sublang/playbook/slc/link.md');
295
- const link = await readFile(fileURLToPath(url), 'utf8');
296
- ```
297
-
298
- The three specs are [`slc/text2gears.md`](slc/text2gears.md),
299
- [`slc/gears2fsm.md`](slc/gears2fsm.md), and [`slc/link.md`](slc/link.md)
300
- — the FSM-to-runtime contract that `@sublang/playbook/runtime` projects
301
- into TypeScript.
342
+ The runtime is host-agnostic the `tmux-play` adapter is one host. The
343
+ port and runtime contracts live in the type-only, semver-stable module
344
+ [`@sublang/playbook/runtime`](src/runtime.ts): a host satisfies the six
345
+ ports once and inherits every playbook. See
346
+ [docs/embedding.md](docs/embedding.md) for the contract surface, a
347
+ complete ports example, session/trace semantics, and how to read the
348
+ published compiler-phase specs from the package.
302
349
 
303
350
  ## Workflow
304
351
 
@@ -306,33 +353,25 @@ playbook is itself spec-driven: the compiler phases are specs in `slc/`,
306
353
  and the reference playbook is regenerated from its prose source. The
307
354
  loop:
308
355
 
309
- 1. **Edit source.** For the reference, that's
310
- [`reference/sdlc/code.md`](reference/sdlc/code.md).
356
+ 1. **Edit source.** The worked examples include
357
+ [`reference/sdlc/code.md`](reference/sdlc/code.md) and the generic
358
+ [`reference/sdlc/captain.md`](reference/sdlc/captain.md).
311
359
  2. **Recompile gears** per [`slc/text2gears.md`](slc/text2gears.md) into
312
- the package's `code.gears.md`.
313
- 3. **Recompile FSM** per [`slc/gears2fsm.md`](slc/gears2fsm.md) into
314
- the package's `code.fsm.ts`.
360
+ the source's `<name>.playbook/<name>.gears.md`.
361
+ 3. **Recompile FSM and runtime** per
362
+ [`slc/gears2fsm.md`](slc/gears2fsm.md) and
363
+ [`slc/link.md`](slc/link.md) into that playbook artifact directory.
315
364
  4. **Sync runtime, tests, and downstream specs** so `pnpm test` stays
316
365
  green and the introspect contract holds 1:1 between gear items and
317
- FSM captain-invoking states.
366
+ FSM direct-Captain, delegated-player, and nested-playbook states.
318
367
  5. **Commit** with co-author trailers per
319
368
  [`specs/dev/git.md`](specs/dev/git.md).
320
369
 
321
370
  The behavioral contract between gears and FSM
322
371
  ([PLAYBOOK-1..6](specs/dev/playbook.md)) and the runtime contract that
323
- ports satisfy ([PBRT-5..16](specs/dev/playbook-runtime.md)) are pinned
324
- in [`specs/dev/`](specs/dev/) and verified by tests under the reference
325
- package.
326
-
327
- ## Requirements
328
-
329
- - Node.js ≥ 20.6.0 (the `playbook` launcher uses
330
- `import.meta.resolve`, unflagged since this release)
331
- - pnpm 9 (for the reference package)
332
- - A configured `tmux-play` host (for live Boss turns) — requires
333
- `tmux` and [`glow`](https://github.com/charmbracelet/glow#installation)
334
- on `PATH`; cligent 0.4+ uses `glow` to render Markdown pane
335
- output and fails fast without it
372
+ ports satisfy ([the PBRT dev items](specs/dev/playbook-runtime.md)) are
373
+ pinned in [`specs/dev/`](specs/dev/) and verified by tests under the
374
+ reference package.
336
375
 
337
376
  ## Contributing
338
377
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@sublang/playbook",
3
- "version": "0.9.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
- "description": "Reference CODE playbook — XState v5 FSM, host-agnostic runtime, and Playbook Captain shell for a coder/reviewer/committer loop driven by GEARS spec items.",
5
+ "description": "Composable XState v5 playbook runtime with compiled Captain, CODE, and DISCUSS workflows driven by GEARS specs.",
6
6
  "license": "Apache-2.0",
7
7
  "homepage": "https://github.com/sublang-ai/playbook#readme",
8
8
  "repository": {
@@ -28,9 +28,24 @@
28
28
  "src/runtime.ts",
29
29
  "src/runtime.js",
30
30
  "src/runtime.d.ts",
31
+ "src/xstate-runtime.ts",
32
+ "src/xstate-runtime.js",
33
+ "src/xstate-runtime.d.ts",
34
+ "src/xstate-playbook-runtime.ts",
35
+ "src/xstate-playbook-runtime.js",
36
+ "src/xstate-playbook-runtime.d.ts",
31
37
  "slc/link.md",
32
38
  "slc/gears2fsm.md",
33
39
  "slc/text2gears.md",
40
+ "slc/optimize.md",
41
+ "reference/sdlc/captain.md",
42
+ "reference/sdlc/captain.playbook/captain.gears.md",
43
+ "reference/sdlc/captain.playbook/captain.fsm.ts",
44
+ "reference/sdlc/captain.playbook/captain.fsm.js",
45
+ "reference/sdlc/captain.playbook/captain.fsm.d.ts",
46
+ "reference/sdlc/captain.playbook/captain.playbook.ts",
47
+ "reference/sdlc/captain.playbook/captain.playbook.js",
48
+ "reference/sdlc/captain.playbook/captain.playbook.d.ts",
34
49
  "reference/sdlc/code.playbook/code.fsm.ts",
35
50
  "reference/sdlc/code.playbook/code.fsm.js",
36
51
  "reference/sdlc/code.playbook/code.fsm.d.ts",
@@ -48,7 +63,18 @@
48
63
  "reference/sdlc/code.playbook/playbook-captain.d.ts",
49
64
  "reference/sdlc/code.playbook/code.gears.md",
50
65
  "reference/sdlc/code.playbook/playbook.config.template.yaml",
51
- "reference/sdlc/code.playbook/bin/playbook.js"
66
+ "reference/sdlc/code.playbook/bin/playbook.js",
67
+ "reference/sdlc/code.playbook/bin/run.js",
68
+ "reference/sdlc/discuss.playbook/discuss.gears.md",
69
+ "reference/sdlc/discuss.playbook/discuss.fsm.ts",
70
+ "reference/sdlc/discuss.playbook/discuss.fsm.js",
71
+ "reference/sdlc/discuss.playbook/discuss.fsm.d.ts",
72
+ "reference/sdlc/discuss.playbook/discuss.playbook.ts",
73
+ "reference/sdlc/discuss.playbook/discuss.playbook.js",
74
+ "reference/sdlc/discuss.playbook/discuss.playbook.d.ts",
75
+ "reference/sdlc/discuss.playbook/discuss.registry.ts",
76
+ "reference/sdlc/discuss.playbook/discuss.registry.js",
77
+ "reference/sdlc/discuss.playbook/discuss.registry.d.ts"
52
78
  ],
53
79
  "bin": {
54
80
  "playbook": "reference/sdlc/code.playbook/bin/playbook.js"
@@ -58,6 +84,14 @@
58
84
  "types": "./src/runtime.d.ts",
59
85
  "default": "./src/runtime.js"
60
86
  },
87
+ "./xstate-runtime": {
88
+ "types": "./src/xstate-runtime.d.ts",
89
+ "default": "./src/xstate-runtime.js"
90
+ },
91
+ "./captain/playbook": {
92
+ "types": "./reference/sdlc/captain.playbook/captain.playbook.d.ts",
93
+ "default": "./reference/sdlc/captain.playbook/captain.playbook.js"
94
+ },
61
95
  "./code/playbook": {
62
96
  "types": "./reference/sdlc/code.playbook/code.playbook.d.ts",
63
97
  "default": "./reference/sdlc/code.playbook/code.playbook.js"
@@ -70,7 +104,15 @@
70
104
  "types": "./reference/sdlc/code.playbook/playbook-captain.d.ts",
71
105
  "default": "./reference/sdlc/code.playbook/playbook-captain.js"
72
106
  },
73
- "./slc/*": "./slc/*"
107
+ "./slc/*": "./slc/*",
108
+ "./discuss/playbook": {
109
+ "types": "./reference/sdlc/discuss.playbook/discuss.playbook.d.ts",
110
+ "default": "./reference/sdlc/discuss.playbook/discuss.playbook.js"
111
+ },
112
+ "./discuss/registry": {
113
+ "types": "./reference/sdlc/discuss.playbook/discuss.registry.d.ts",
114
+ "default": "./reference/sdlc/discuss.playbook/discuss.registry.js"
115
+ }
74
116
  },
75
117
  "scripts": {
76
118
  "build": "tsc",
@@ -82,9 +124,11 @@
82
124
  "provenance": true
83
125
  },
84
126
  "dependencies": {
85
- "@anthropic-ai/claude-agent-sdk": "^0.3.143",
127
+ "@anthropic-ai/claude-agent-sdk": "^0.3.154",
86
128
  "@openai/codex-sdk": "^0.139.0",
87
- "@sublang/cligent": "^0.13.0",
129
+ "@sublang/cligent": "^0.15.0",
130
+ "@sublang/spex": "^0.3.0",
131
+ "p-queue": "^9.3.1",
88
132
  "xstate": "^5.19.4",
89
133
  "yaml": "^2.9.0"
90
134
  },