@sublang/playbook 7.0.0 → 8.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 (61) hide show
  1. package/README.md +17 -4
  2. package/docs/cli.md +74 -29
  3. package/docs/configuration.md +209 -112
  4. package/docs/embedding.md +71 -25
  5. package/package.json +4 -3
  6. package/reference/sdlc/captain.playbook/captain.playbook.js +3 -3
  7. package/reference/sdlc/captain.playbook/captain.playbook.ts +3 -3
  8. package/reference/sdlc/code.md +1 -1
  9. package/reference/sdlc/code.playbook/bin/interactive-session.js +816 -0
  10. package/reference/sdlc/code.playbook/bin/launch-config.js +1078 -116
  11. package/reference/sdlc/code.playbook/bin/playbook.js +489 -34
  12. package/reference/sdlc/code.playbook/bin/run.js +283 -298
  13. package/reference/sdlc/code.playbook/bin/session-store.js +818 -26
  14. package/reference/sdlc/code.playbook/code.fsm.d.ts +5 -5
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.js +2 -2
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +2 -2
  17. package/reference/sdlc/code.playbook/code.fsm.js +7 -11
  18. package/reference/sdlc/code.playbook/code.fsm.ts +9 -17
  19. package/reference/sdlc/code.playbook/code.gears.md +1 -1
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +2 -1
  21. package/reference/sdlc/code.playbook/code.playbook.js +12 -13
  22. package/reference/sdlc/code.playbook/code.playbook.ts +22 -15
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +5 -13
  24. package/reference/sdlc/code.playbook/code.registry.js +3 -10
  25. package/reference/sdlc/code.playbook/code.registry.ts +7 -32
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +39 -14
  27. package/reference/sdlc/code.playbook/playbook-captain.js +970 -289
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1403 -396
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +41 -49
  30. package/reference/sdlc/decide.md +4 -4
  31. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +9 -9
  32. package/reference/sdlc/decide.playbook/decide.fsm.js +21 -14
  33. package/reference/sdlc/decide.playbook/decide.fsm.ts +27 -23
  34. package/reference/sdlc/decide.playbook/decide.gears.md +3 -5
  35. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +9 -13
  36. package/reference/sdlc/decide.playbook/decide.playbook.js +171 -134
  37. package/reference/sdlc/decide.playbook/decide.playbook.ts +238 -162
  38. package/reference/sdlc/decide.playbook/decide.registry.d.ts +5 -13
  39. package/reference/sdlc/decide.playbook/decide.registry.js +3 -9
  40. package/reference/sdlc/decide.playbook/decide.registry.ts +7 -31
  41. package/reference/sdlc/review.md +4 -5
  42. package/reference/sdlc/review.playbook/review.fsm.d.ts +9 -11
  43. package/reference/sdlc/review.playbook/review.fsm.js +30 -24
  44. package/reference/sdlc/review.playbook/review.fsm.ts +39 -35
  45. package/reference/sdlc/review.playbook/review.gears.md +6 -5
  46. package/reference/sdlc/review.playbook/review.playbook.d.ts +2 -1
  47. package/reference/sdlc/review.playbook/review.playbook.js +16 -21
  48. package/reference/sdlc/review.playbook/review.playbook.ts +26 -26
  49. package/reference/sdlc/review.playbook/review.registry.d.ts +5 -13
  50. package/reference/sdlc/review.playbook/review.registry.js +3 -16
  51. package/reference/sdlc/review.playbook/review.registry.ts +7 -38
  52. package/slc/gears2fsm.md +27 -23
  53. package/slc/link.md +113 -93
  54. package/slc/text2gears.md +19 -18
  55. package/src/runtime.d.ts +20 -16
  56. package/src/runtime.ts +19 -23
  57. package/src/xstate-playbook-runtime.d.ts +21 -17
  58. package/src/xstate-playbook-runtime.js +241 -149
  59. package/src/xstate-playbook-runtime.ts +331 -178
  60. package/src/xstate-runtime.js +63 -24
  61. package/src/xstate-runtime.ts +96 -28
package/README.md CHANGED
@@ -19,7 +19,11 @@ SubLang Playbook addresses both:
19
19
 
20
20
  ![Venn diagram: Skill is flexible, Workflow is deterministic, and Playbook sits in the intersection as both.](docs/assets/playbook-venn.svg)
21
21
 
22
- Vocabulary: the **Boss** is you; the **Captain** is the coordinating agent you talk to; **players** are the agents a playbook delegates work to.
22
+ Vocabulary: the **Boss** is you; the **Captain** is the coordinating agent you
23
+ talk to; a **role** is a playbook-local job such as `coder`; and a **player** is
24
+ a stable Captain-session agent and provider conversation to which one or more
25
+ roles bind. Roles describe the workflow, while player IDs decide which work
26
+ shares conversation continuity.
23
27
 
24
28
  Run `playbook` for an interactive tmux UI powered by [cligent](https://github.com/sublang-ai/cligent), or `playbook run` for the same Captain session without tmux in scripts and CI.
25
29
 
@@ -28,7 +32,10 @@ Run `playbook` for an interactive tmux UI powered by [cligent](https://github.co
28
32
  Out of the box, Playbook includes **CODE** for implementation, **REVIEW** for commit-based review and fixes, and **DECIDE** for independently proposed and reviewed specification decisions.
29
33
  CODE and DECIDE call REVIEW as a nested playbook.
30
34
 
31
- The shared starter config uses Claude as both Captain and Coder, and Codex as Reviewer.
35
+ The shared starter config uses Claude as both Captain and the `dev.coder`
36
+ player, and Codex as `dev.reviewer`. CODE, REVIEW, and DECIDE bind their local
37
+ roles explicitly to those two stable players, so nested and later engagements
38
+ share a conversation only where their bindings name the same player ID.
32
39
 
33
40
  ```sh
34
41
  npm install -g @sublang/playbook
@@ -44,7 +51,7 @@ Prerequisites:
44
51
  - Authenticated [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) or `ANTHROPIC_API_KEY`
45
52
  - Authenticated [Codex CLI](https://github.com/openai/codex) or `OPENAI_API_KEY`
46
53
 
47
- Interactive `playbook` additionally needs `tmux` and [`glow`](https://github.com/charmbracelet/glow#installation) on `PATH`; headless `playbook run` does not.
54
+ Interactive `playbook` additionally needs tmux 3.3 or newer and [`glow`](https://github.com/charmbracelet/glow#installation) on `PATH`; headless `playbook run` does not.
48
55
 
49
56
  CODE works in the current directory and can edit and commit autonomously, so use a clean branch or worktree.
50
57
 
@@ -58,12 +65,18 @@ Type a task, enter `/code <task>` for implementation, or enter
58
65
 
59
66
  On first launch, Playbook writes its config to `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml`.
60
67
 
61
- The same config, compiled Captain, enabled playbooks, players, and nested calls power headless turns.
68
+ The same config, compiled Captain, enabled playbooks, stable players, and
69
+ nested calls power headless turns. Both front ends create the same durable
70
+ logical session: copy the reported session ID to reopen an interactive session
71
+ headlessly or a headless session interactively.
62
72
  Run REVIEW explicitly, or pipe a longer request to Captain:
63
73
 
64
74
  ```sh
65
75
  playbook run "/review review the latest commit"
66
76
  printf '%s\n' 'Implement the approved specification, then review it.' | playbook run
77
+ # Later, either presentation can reopen the returned/reported session id:
78
+ playbook --session 4f2c0000-0000-4000-8000-000000009ab1
79
+ playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 "continue"
67
80
  ```
68
81
 
69
82
  `playbook run` prints the one Boss-visible Captain reply to stdout and operational status to stderr; CODE and DECIDE can complete their nested REVIEW calls there too.
package/docs/cli.md CHANGED
@@ -8,6 +8,9 @@ interactive tmux-play UI and a headless `playbook run` turn for scripts and
8
8
  CI. Both use the same compiled Captain, enabled catalog, players, nested
9
9
  stack, and [config](configuration.md); only presentation differs.
10
10
 
11
+ The interactive form requires tmux 3.3 or newer and `glow` on `PATH`;
12
+ the headless form requires neither presentation tool.
13
+
11
14
  ## Installing agent SDKs
12
15
 
13
16
  Each adapter is backed by a vendor runtime that installing
@@ -56,9 +59,11 @@ following it cannot install a version the gate refuses again
56
59
  ## Interactive
57
60
 
58
61
  ```sh
59
- playbook # launch the configured playbooks in tmux-play
60
- playbook --list # ids, slash commands, and intents; no launch
61
- playbook --help # config path, auth pointers, agent-swap recipe
62
+ playbook # fresh durable session in this directory
63
+ playbook --cwd /path/to/repo # fresh session in an explicit directory
64
+ playbook --session <id> # reopen either front end's settled session
65
+ playbook --list # ids, slash commands, and intents; no launch
66
+ playbook --help # config path, auth pointers, binding recipe
62
67
  ```
63
68
 
64
69
  Without a global install, `npx` runs the same bin — but name each
@@ -78,10 +83,21 @@ already present, since each distinct package set is a distinct tree —
78
83
  and replaying your original arguments, so the printed command works in
79
84
  one hop.
80
85
 
81
- The command resolves its config (seeding it on first run), composes a
82
- `tmux-play` config, checks adapter readiness, and launches. It exits
83
- with tmux-play's status, re-raises a terminating signal on itself, and
84
- exits `127` when it cannot launch at all
86
+ For a managed launch, the outer command resolves current config (seeding it on
87
+ first use), prepares the complete stored catalog and presenter, waits for the
88
+ pane child to acquire the session lease and publish its settled turn-zero
89
+ record, prints the verified session ID, and then attaches. A normal outer
90
+ detach exits `0`; the pane child keeps owning the durable session and accepting
91
+ turns until it shuts down. Preparation, attachment, or required cleanup
92
+ failure prints its diagnostics and exits nonzero.
93
+
94
+ Before native-client hand-off, SIGHUP, SIGINT, or SIGTERM aborts activation,
95
+ joins the child, retires the lease, and only then re-raises the signal. At the
96
+ synchronous native-client hand-off, ownership transfers before tmux starts, so
97
+ later signals use native client detach or termination semantics and do not
98
+ retire the pane child's session. Only `--config` and composed
99
+ `--theme-diagnostics` use the stock subprocess boundary: those forms mirror
100
+ its exit status or signal and exit `127` when it cannot be spawned
85
101
  ([[playbook-cli-1](../specs/packages/playbook-cli.md#playbook-cli-1)],
86
102
  [[playbook-cli-2](../specs/packages/playbook-cli.md#playbook-cli-2)]).
87
103
 
@@ -106,10 +122,12 @@ untouched
106
122
  [[playbook-captain-2](../specs/packages/playbook-captain.md#playbook-captain-2)]).
107
123
 
108
124
  The current CODE, REVIEW, and DECIDE workflows take their deterministic
109
- initial event from the selecting Boss turn. CODE and DECIDE then call
110
- REVIEW as a nested playbook: an exact same-name child role continues the
111
- ancestor's player pane and backend conversation, while any additional
112
- role uses REVIEW's configured fallback. When a player surfaces a
125
+ initial event from the selecting Boss turn. CODE and DECIDE then call REVIEW
126
+ as a nested playbook. Local role names do not imply continuity: each frame
127
+ uses the exact stable player IDs configured under its `roles` map. Equal IDs
128
+ share one pane and provider conversation across nested and later root
129
+ engagements; distinct IDs remain isolated even when their agent settings are
130
+ identical. When a player surfaces a
113
131
  clarifying question the FSM parks, the pane shows the question, and a
114
132
  judge classifies your next turn as its reply or a fresh directive that
115
133
  abandons it
@@ -147,7 +165,7 @@ stderr, and `--verbose` adds only telemetry topic names to stderr.
147
165
 
148
166
  | Flag | Meaning |
149
167
  | --- | --- |
150
- | `--with <path>` | overlay the shared config for a new session; repeatable |
168
+ | `--with <path>` | overlay current config for a fresh session or compatible ordinary reopen; repeatable |
151
169
  | `--no-provision` | do not create missing engine links for configured filesystem registries |
152
170
  | `--json` | print exactly one `sessionId` / `reply` object |
153
171
  | `--verbose` | add Captain telemetry topic names to stderr |
@@ -168,9 +186,14 @@ uncertain boundary, withhold stdout, and are re-raised after lease retirement
168
186
 
169
187
  The former positional `<from>`, `resume`, `--player`, `--captain`,
170
188
  `--option`, `--cwd`, `--last`, run-only `--config`, and top-level `run:`
171
- config are removed. Enable a registry under `playbooks`, tune its inline
172
- agents and options there or in a fresh `--with` overlay, invoke its effective
173
- `/command`, and run from the working directory you want agents to use.
189
+ config are removed from `playbook run`. Enable a registry under `playbooks`,
190
+ declare provider agents once under top-level `players`, bind every local role
191
+ under `playbooks.<id>.roles`, tune compatible model and effort in a `--with`
192
+ overlay, invoke the effective `/command`, and run from the working directory
193
+ you want agents to use. Legacy `playbooks.<id>.players` blocks are rejected and
194
+ are not auto-migrated because choosing equal or distinct new player IDs chooses
195
+ conversation sharing or isolation; see [Migrating per-playbook
196
+ players](configuration.md#migrating-per-playbook-players).
174
197
 
175
198
  ### Piping a Spex update prompt
176
199
 
@@ -208,23 +231,38 @@ module's directory is a git repository, add `node_modules/` to its
208
231
 
209
232
  ### Continuing a Captain session
210
233
 
211
- Every successfully presented headless turn is stored under
212
- `${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions/` before stdout.
213
- Continue the newest logical session, or select the id returned by `--json`:
234
+ Interactive and headless commands write the same logical-session records under
235
+ `${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions/`. A fresh interactive
236
+ child persists turn zero before printing `playbook: session <id>` and opening
237
+ Boss input; a fresh headless turn returns the same kind of ID in `--json`.
238
+ After the current writer exits or explicitly hands off, either presentation
239
+ can reopen either origin:
214
240
 
215
241
  ```sh
242
+ # Reopen the latest settled session headlessly:
216
243
  playbook run --continue "keep the scope small; skip the docs"
244
+
245
+ # Reopen one exact session in either presentation:
246
+ playbook --session 4f2c0000-0000-4000-8000-000000009ab1
217
247
  playbook run --session 4f2c0000-0000-4000-8000-000000009ab1
218
248
  ```
219
249
 
220
- A missing reply is read verbatim from stdin. Continuation restores the exact
250
+ A missing headless reply is read verbatim from stdin. Reopening restores the
221
251
  compiled Captain conversation, engagement stack, nested child boundary,
222
- mapped-player conversations, normalized execution config, and absolute
223
- working directory. It does not reread current config, does not repeat a
224
- settled or pending child start, and rejects `--with` because an existing
225
- session's lineup is frozen
252
+ stable-player ledger, and absolute working directory without replaying a
253
+ settled or pending child start. One exclusive writer owns the session, so a
254
+ detached interactive pane child remains the owner until it shuts down; a
255
+ competing front end fails closed instead of forking the history.
256
+
257
+ An ordinary reopen reads current config and any opening `--with` fragments,
258
+ projects them to the stored catalog and player roster, and requires the stored
259
+ role bindings plus every structural setting to remain exact. Compatible
260
+ current `model` and `effort` selections apply to the next call, including an
261
+ explicit boolean `false` provider-default reset. The retained provider token
262
+ is never silently replaced by a fresh conversation if that selection is not
263
+ supported
226
264
  ([[playbook-cli-22](../specs/packages/playbook-cli.md#playbook-cli-22)],
227
- [DR-031](../specs/decisions/031-shared-captain-session-front-ends.md)).
265
+ [DR-032](../specs/decisions/032-explicit-roles-session-players.md)).
228
266
 
229
267
  ### Recovering an uncertain turn
230
268
 
@@ -238,8 +276,15 @@ playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 --retry-uncertain
238
276
  playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 --discard-uncertain
239
277
  ```
240
278
 
241
- Retry reads no input and reuses the byte-exact recorded turn; it may duplicate
242
- external effects. Discard reads no input and runs no model: it restores the
243
- exact prior settled boundary, or deletes a never-settled fresh session, while
244
- abandoning the attempted work. Session files written by the removed direct
245
- v6 runner are not shared-Captain sessions and cannot be continued.
279
+ Retry reads no input and reuses the byte-exact recorded turn and its exact
280
+ attempted Captain, player, and per-role model/effort selections; current config
281
+ cannot retune that attempt, and retry may duplicate external effects. Discard
282
+ reads no input and runs no model: it restores the exact prior settled boundary,
283
+ or deletes a never-settled fresh session, while abandoning the attempted work.
284
+ An interrupted interactive turn uses the same uncertain record and is
285
+ recovered with these headless commands. Session files written by the removed
286
+ direct v6 runner and legacy record schemas are not shared schema-3 Captain
287
+ sessions and cannot be continued. Explicit selection rejects them. Implicit
288
+ `--continue` reports and skips released schema-2 Captain records, naming each
289
+ session and path; move them outside the sessions directory or remove them to
290
+ silence the warning. Malformed records and unknown schemas still fail closed.
@@ -3,7 +3,7 @@
3
3
 
4
4
  # Configuring agents
5
5
 
6
- `playbook` and every fresh `playbook run` read one config at
6
+ Fresh launches and ordinary reopens read one config at
7
7
  `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml`. The
8
8
  first launch seeds it from the bundled starter and prints the path;
9
9
  later launches reuse it untouched.
@@ -14,28 +14,35 @@ $EDITOR "${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml"
14
14
 
15
15
  ## Anatomy
16
16
 
17
- The config is top-level (no `config:` wrapper): a `captain` agent (it
18
- runs the session Captain's hidden control calls, the hidden judge calls,
19
- and the replies you see in the Captain pane or on headless stdout), optional
20
- `layout` / `notifications` / `theme`, and a `playbooks` map of enabled
21
- playbooks. Those three presentation fields apply only to interactive tmux;
22
- headless runs ignore them.
23
-
24
- Each `captain` or `players.<role>` value is either an adapter shorthand
25
- (`claude`, `codex`) or a block carrying that agent's own `adapter`,
26
- `model`, `effort`, and `permissions`. Settings are inline per agent, so
27
- tuning one player never changes another
28
- ([DR-021](../specs/decisions/021-inline-agent-settings.md)). Other
29
- adapter ids pass through to `tmux-play` with a warning, because
30
- `playbook` cannot preflight their auth.
31
-
32
- Within a `playbooks.<id>` block, `from` (the registry module), `command`
33
- (an optional slash-command override), and `players` are launcher-owned;
34
- every other key is that playbook's option slice. The launcher injects
35
- the rest you do not write host wiring by hand.
36
-
37
- The seeded config runs each Coder on Claude Opus 4.8 1m and each
38
- Reviewer on GPT-5.5:
17
+ The config is top-level (no `config:` wrapper): a `captain` agent, one flat
18
+ `players` map of stable Captain-session agents, a `playbooks` map of enabled
19
+ workflows and their explicit role bindings, and optional `layout` /
20
+ `notifications` / `theme`. The Captain runs hidden control and judge calls and
21
+ writes the replies you see in the Captain pane or on headless stdout. The three
22
+ presentation fields apply only to interactive tmux; headless runs ignore them.
23
+
24
+ A **role** is local to a playbook artifact: CODE's `coder` and REVIEW's `coder`
25
+ have the same semantic name but remain separate declarations. A **player** is
26
+ a stable session-wide provider conversation with an exact ID such as
27
+ `dev.coder`. A role uses only the player named by its binding; matching role
28
+ names, nesting, and ancestry never infer a binding.
29
+
30
+ Each `captain` or `players.<player-id>` value is either an adapter shorthand
31
+ (`claude`, `codex`) or a block carrying that agent's own `adapter`, `model`,
32
+ `effort`, `instruction`, and `permissions`. Settings are inline per stable
33
+ agent ([DR-021](../specs/decisions/021-inline-agent-settings.md)). Dots in a
34
+ player ID are literal characters, not YAML hierarchy. Other adapter IDs pass
35
+ through to `tmux-play` with a warning because `playbook` cannot preflight their
36
+ auth.
37
+
38
+ Within a `playbooks.<id>` block, `from` (the registry module), `command` (an
39
+ optional slash-command override), and `roles` are launcher-owned; every other
40
+ key is that playbook's option slice. Every manifest role must be present
41
+ exactly once. The launcher injects the rest — you do not write host wiring by
42
+ hand.
43
+
44
+ The seeded config runs the stable Coder player on Claude Opus 4.8 1m and the
45
+ stable Reviewer player on GPT-5.5:
39
46
 
40
47
  ```yaml
41
48
  captain:
@@ -45,86 +52,116 @@ captain:
45
52
  permissions:
46
53
  mode: auto # protected auto mode for the Claude Captain
47
54
 
55
+ players:
56
+ dev.coder:
57
+ adapter: claude
58
+ model: claude-opus-4-8[1m]
59
+ effort: xhigh
60
+ permissions:
61
+ mode: auto # protected auto mode for the Claude Coder
62
+
63
+ dev.reviewer:
64
+ adapter: codex
65
+ model: gpt-5.5
66
+ effort: xhigh
67
+ permissions:
68
+ mode: auto
69
+ writablePaths:
70
+ - .git # allow git metadata writes under Codex auto mode
71
+
48
72
  playbooks:
49
73
  code:
50
74
  from: '@sublang/playbook/code/registry'
51
- players:
52
- coder:
53
- adapter: claude
54
- model: claude-opus-4-8[1m]
55
- effort: xhigh
56
- permissions:
57
- mode: auto # protected auto mode for the Claude Coder
75
+ roles:
76
+ coder: dev.coder
58
77
 
59
78
  review:
60
79
  from: '@sublang/playbook/review/registry'
61
- players:
62
- coder:
63
- adapter: claude
64
- model: claude-opus-4-8[1m]
65
- effort: xhigh
66
- permissions:
67
- mode: auto
68
- reviewer:
69
- adapter: codex
70
- model: gpt-5.5
71
- effort: xhigh
72
- permissions:
73
- mode: auto
74
- writablePaths:
75
- - .git # allow git metadata writes under Codex auto mode
80
+ roles:
81
+ coder: dev.coder
82
+ reviewer: dev.reviewer
76
83
 
77
84
  decide:
78
85
  from: '@sublang/playbook/decide/registry'
79
- players:
80
- coder:
81
- adapter: claude
82
- model: claude-opus-4-8[1m]
83
- effort: xhigh
84
- permissions:
85
- mode: auto
86
- reviewer:
87
- adapter: codex
88
- model: gpt-5.5
89
- effort: xhigh
90
- permissions:
91
- mode: auto
92
- writablePaths:
93
- - .git
86
+ roles:
87
+ coder: dev.coder
88
+ reviewer: dev.reviewer
94
89
  ```
95
90
 
96
91
  The current bundled workflows accept no workflow-specific options.
97
- Each role's per-run prompt names its pinned `model`, else its `adapter`
92
+ Each role's per-call prompt names its current `model`, else its player's
93
+ `adapter`
98
94
  ([[playbook-runtime-4](../specs/packages/playbook-runtime.md#playbook-runtime-4)]),
99
95
  so commit trailers credit the concrete model rather than the adapter
100
96
  family.
101
97
 
102
- ## Nested roles and sessions
98
+ ## Role binding forms
99
+
100
+ The shortest binding is a scalar stable player ID:
101
+
102
+ ```yaml
103
+ roles:
104
+ coder: dev.coder
105
+ ```
106
+
107
+ Use a block to override only that role invocation's model or effort:
108
+
109
+ ```yaml
110
+ roles:
111
+ coder:
112
+ player: dev.coder
113
+ model: claude-opus-4-8[1m]
114
+ effort: false # explicitly reset to this provider's default
115
+ ```
116
+
117
+ Omitting `model` or `effort` inherits that player's top-level default. The
118
+ boolean `false` is different: it selects the provider default explicitly, so a
119
+ resumed conversation cannot accidentally retain an earlier selection. A role
120
+ binding cannot override adapter, instruction, permissions, workspace, or tool
121
+ posture; those define the stable player envelope.
122
+
123
+ ## Sharing, isolation, and concurrency
103
124
 
104
- The launcher creates a namespaced fallback player for every configured
105
- playbook role, but a nested call maps an exact same-name role to the
106
- nearest ancestor's effective player and backend conversation. CODE's
107
- nested REVIEW therefore continues CODE's `coder` and uses REVIEW's
108
- configured `reviewer`; DECIDE's nested REVIEW continues both of
109
- DECIDE's roles. A standalone REVIEW starts with REVIEW's own configured
110
- players, and every new root engagement starts fresh
111
- ([DR-030](../specs/decisions/030-shared-mapped-player-continuity.md)).
125
+ Two bindings that name the same player ID deliberately share one sequential
126
+ provider conversation throughout the logical Captain session across nested
127
+ calls, returns, and later root engagements. CODE's and REVIEW's `coder` roles
128
+ therefore share `dev.coder` in the starter, and DECIDE and its nested REVIEW
129
+ share both starter players. Disposal of one playbook frame does not clear that
130
+ session ledger.
112
131
 
113
- The separate fallback entries are still required because tmux creates
114
- its roster at launch time. The host changes which existing panes are
115
- visible as the active nested leaf changes; it does not create a new
116
- host player or backend agent session for a mapped role.
132
+ Two distinct player IDs stay isolated even when their agent blocks are
133
+ byte-for-byte equal. To give standalone REVIEW an independent Coder, define a
134
+ second top-level player and change only its binding:
135
+
136
+ ```yaml
137
+ players:
138
+ review.coder:
139
+ adapter: claude
140
+ model: claude-opus-4-8[1m]
141
+ effort: xhigh
142
+
143
+ playbooks:
144
+ review:
145
+ from: '@sublang/playbook/review/registry'
146
+ roles:
147
+ coder: review.coder
148
+ reviewer: dev.reviewer
149
+ ```
150
+
151
+ Roles a manifest may run concurrently must bind to distinct IDs. DECIDE's
152
+ `coder` and `reviewer` are concurrent, so aliasing both to one player rejects
153
+ before registry import, host creation, or agent work.
117
154
 
118
155
  ## Choosing the Captain agent
119
156
 
120
157
  Every session-Captain call and adjudication call is hidden and runs
121
158
  tool-free, which is what keeps the Captain deciding and reporting
122
- instead of doing the work itself. Claude enforces
123
- that at the provider level. The Codex adapter cannot — it rejects any
124
- tool list — so a `captain:` on `codex` falls back to a prompt-level
125
- restriction
159
+ instead of doing the work itself. Claude and Gemini enforce that at the
160
+ provider level. The Codex, Kimi, and OpenCode adapters cannot — they
161
+ reject any tool list — so a `captain:` using one of them falls back to a
162
+ prompt-level restriction
126
163
  ([DR-013](../specs/decisions/013-routing-only-captain-control.md) A1).
127
- Codex remains a good choice for *players*, where full tools are wanted.
164
+ Those adapters remain good choices for *players*, where full tools are wanted.
128
165
 
129
166
  Adapter readiness is intentionally light: `claude` is ready with local
130
167
  Claude Code auth or `ANTHROPIC_API_KEY`; `codex` with local Codex CLI
@@ -143,40 +180,52 @@ playbook run --with fast-lineup.yaml "/code implement the approved change"
143
180
  ```
144
181
 
145
182
  ```yaml
146
- # fast-lineup.yaml — swap the Coder for one run; nothing is written back.
183
+ # fast-lineup.yaml — retune the shared Coder; nothing is written back.
184
+ players:
185
+ dev.coder:
186
+ model: claude-opus-4-8
187
+ effort: medium
188
+ ```
189
+
190
+ Fragments merge into the agent block rather than replacing it, so
191
+ settings the base defines and the fragment omits — here the adapter,
192
+ instruction, and permissions — survive. Retuning a top-level player affects
193
+ every bound role that does not override that field. To retune only one role,
194
+ overlay its binding instead:
195
+
196
+ ```yaml
147
197
  playbooks:
148
198
  code:
149
- players:
199
+ roles:
150
200
  coder:
151
- adapter: codex
152
- model: gpt-5.5
153
- effort: medium
154
- permissions:
155
- mode: auto
156
- # CODE's Coder commits, so Codex needs the `.git` grant to write
157
- # repository metadata.
158
- writablePaths:
159
- - .git
201
+ player: dev.coder
202
+ effort: low
160
203
  ```
161
204
 
162
- Fragments merge into the agent block rather than replacing it, so
163
- settings the base defines and the fragment omits — here `mode: auto` —
164
- survive. Anything the adapter itself requires must still be stated: a
165
- role switched to `codex` needs its own `writablePaths` grant, because
166
- the base Claude block had no reason to carry one.
167
-
168
205
  The global file is never modified, and `--with` is not forwarded to
169
206
  `tmux-play` ([[playbook-cli-25](../specs/packages/playbook-cli.md#playbook-cli-25)]).
170
- Overlays apply only when creating a fresh session. A continued headless
171
- session restores its frozen config and working directory and rejects `--with`.
172
-
173
- ## Shared headless configuration
174
-
175
- Fresh interactive and headless sessions use the same top-level `captain`
176
- and `playbooks` blocks. A headless session retains the normalized lineup,
177
- catalog, options, and absolute working directory with every durable turn;
178
- continuation does not reread the current file. Presentation-only fields are
179
- inert headlessly.
207
+ Overlays apply when creating a fresh session and as current-config input for a
208
+ compatible ordinary reopen. A selected session keeps its stored catalog,
209
+ player roster, role bindings, adapter, instruction, permissions, and working
210
+ directory; only model and effort may change. The next call reapplies both
211
+ complete selections. An uncertain retry accepts no tuning overlay and uses the
212
+ exact attempted selections already stored with that turn.
213
+
214
+ ## Durable shared configuration
215
+
216
+ Fresh interactive and headless sessions use the same top-level Captain,
217
+ players, role bindings, and playbooks. Both persist the same logical-session
218
+ record, shell snapshot, player ledger, normalized catalog, structural agent
219
+ envelopes, last-applied tuning, and absolute working directory. A session
220
+ created by either front end can reopen through either front end with the same
221
+ public UUID. Presentation-only fields are inert headlessly.
222
+
223
+ An ordinary reopen reads current config and opening overlays, but first
224
+ projects them to the stored playbooks and referenced players. An unrelated new
225
+ entry cannot enter or invalidate the session. Structural drift fails closed;
226
+ compatible model or effort changes apply on the next provider call. Legacy
227
+ record, shell, runtime-snapshot, and trace schemas are rejected rather than
228
+ having role or player identity guessed.
180
229
 
181
230
  ## External playbooks
182
231
 
@@ -187,11 +236,14 @@ and `createRuntime`. Enable it under `playbooks`, bind every role listed in
187
236
  its `requiredRoleIds`, and invoke its effective slash command through Captain:
188
237
 
189
238
  ```yaml
239
+ players:
240
+ my.worker: claude
241
+
190
242
  playbooks:
191
243
  my-workflow:
192
244
  from: /absolute/path/to/my-workflow.ts
193
- players:
194
- worker: claude
245
+ roles:
246
+ worker: my.worker
195
247
  ```
196
248
 
197
249
  ```sh
@@ -205,15 +257,60 @@ Before either front end imports a filesystem registry, the shared launcher
205
257
  checks and, unless `--no-provision` is set, provisions its runtime engine
206
258
  links as described in [Using the CLI](cli.md#external-playbooks-and-engine-provisioning).
207
259
 
260
+ ## Migrating per-playbook players
261
+
262
+ The former `playbooks.<id>.players` shape made agent configuration and local
263
+ workflow roles the same thing. It is removed. For example, this legacy config
264
+ gave CODE and REVIEW two separately configured `coder` entries:
265
+
266
+ ```yaml
267
+ playbooks:
268
+ code:
269
+ from: '@sublang/playbook/code/registry'
270
+ players:
271
+ coder: { adapter: claude, model: claude-opus-4-8[1m] }
272
+ review:
273
+ from: '@sublang/playbook/review/registry'
274
+ players:
275
+ coder: { adapter: claude, model: claude-opus-4-8[1m] }
276
+ reviewer: { adapter: codex, model: gpt-5.5 }
277
+ ```
278
+
279
+ Move each provider agent into the flat top-level map, choose stable IDs, and
280
+ bind the local roles explicitly:
281
+
282
+ ```yaml
283
+ players:
284
+ dev.coder: { adapter: claude, model: claude-opus-4-8[1m] }
285
+ dev.reviewer: { adapter: codex, model: gpt-5.5 }
286
+
287
+ playbooks:
288
+ code:
289
+ from: '@sublang/playbook/code/registry'
290
+ roles: { coder: dev.coder }
291
+ review:
292
+ from: '@sublang/playbook/review/registry'
293
+ roles:
294
+ coder: dev.coder
295
+ reviewer: dev.reviewer
296
+ ```
297
+
298
+ The launcher intentionally does **not** perform this migration for you. It
299
+ cannot know whether the two old `coder` blocks were meant to share one
300
+ conversation or remain isolated. Reusing `dev.coder` above chooses sharing;
301
+ using `code.coder` and `review.coder` would choose isolation. A surviving
302
+ per-playbook `players` block therefore rejects before profile migration,
303
+ registry preparation, or agent work.
304
+
208
305
  ## Migrating direct runs from 6.x
209
306
 
210
307
  The top-level `run:` block is deliberately rejected rather than silently
211
308
  ignored or rewritten, because doing otherwise could change the agents after
212
309
  an upgrade. Re-express `run.captain`, `run.players`, and former `--player`
213
- bindings as the inline agent blocks above; the old `run.player` catch-all has
214
- no shared equivalent, so configure every required role explicitly at
215
- `playbooks.<id>.players.<role>`. Use a fresh `--with` fragment for temporary
216
- lineup changes. Move former `--option` values into their `playbooks.<id>`
310
+ bindings as top-level stable player blocks and explicit role bindings above;
311
+ the old `run.player` catch-all has no shared equivalent, so configure every
312
+ required role at `playbooks.<id>.roles.<role>`. Use a `--with` fragment for
313
+ temporary compatible tuning changes. Move former `--option` values into their `playbooks.<id>`
217
314
  block, run from the desired directory instead of passing `--cwd`, enable a
218
315
  former positional `<from>` as a configured registry, and quote or pipe one
219
316
  `/command task` Boss message. Replace `resume` and `--last` with `--continue`