@sublang/playbook 9.0.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/docs/cli.md +109 -21
- package/docs/configuration.md +89 -40
- package/docs/embedding.md +126 -12
- package/package.json +14 -3
- package/reference/sdlc/captain.md +14 -10
- package/reference/sdlc/captain.playbook/captain.fsm.d.ts +33 -13
- package/reference/sdlc/captain.playbook/captain.fsm.js +80 -9
- package/reference/sdlc/captain.playbook/captain.fsm.ts +137 -18
- package/reference/sdlc/captain.playbook/captain.gears.md +10 -6
- package/reference/sdlc/captain.playbook/captain.playbook.d.ts +5 -1
- package/reference/sdlc/captain.playbook/captain.playbook.js +140 -10
- package/reference/sdlc/captain.playbook/captain.playbook.ts +188 -16
- package/reference/sdlc/code.md +35 -16
- package/reference/sdlc/code.playbook/bin/interactive-session.js +228 -23
- package/reference/sdlc/code.playbook/bin/launch-config.js +611 -221
- package/reference/sdlc/code.playbook/bin/playbook.js +304 -178
- package/reference/sdlc/code.playbook/bin/replay-observer.js +221 -0
- package/reference/sdlc/code.playbook/bin/repository-effects.js +2930 -0
- package/reference/sdlc/code.playbook/bin/run.js +669 -215
- package/reference/sdlc/code.playbook/bin/session-store.js +4546 -502
- package/reference/sdlc/code.playbook/code.fsm.d.ts +7 -0
- package/reference/sdlc/code.playbook/code.fsm.js +74 -25
- package/reference/sdlc/code.playbook/code.fsm.ts +83 -29
- package/reference/sdlc/code.playbook/code.gears.md +0 -2
- package/reference/sdlc/code.playbook/code.playbook.d.ts +5 -2
- package/reference/sdlc/code.playbook/code.playbook.js +54 -2
- package/reference/sdlc/code.playbook/code.playbook.ts +75 -6
- package/reference/sdlc/code.playbook/code.registry.d.ts +10 -3
- package/reference/sdlc/code.playbook/code.registry.js +10 -3
- package/reference/sdlc/code.playbook/code.registry.ts +23 -5
- package/reference/sdlc/code.playbook/playbook-captain.d.ts +103 -8
- package/reference/sdlc/code.playbook/playbook-captain.js +1871 -75
- package/reference/sdlc/code.playbook/playbook-captain.ts +2801 -102
- package/reference/sdlc/code.playbook/playbook.config.template.yaml +14 -10
- package/reference/sdlc/code.playbook/session-store.d.ts +82 -0
- package/reference/sdlc/code.playbook/session-store.js +113 -0
- package/reference/sdlc/decide.md +24 -16
- package/reference/sdlc/decide.playbook/decide.fsm.d.ts +7 -0
- package/reference/sdlc/decide.playbook/decide.fsm.js +80 -29
- package/reference/sdlc/decide.playbook/decide.fsm.ts +89 -31
- package/reference/sdlc/decide.playbook/decide.gears.md +0 -1
- package/reference/sdlc/decide.playbook/decide.playbook.d.ts +13 -5
- package/reference/sdlc/decide.playbook/decide.playbook.js +1712 -91
- package/reference/sdlc/decide.playbook/decide.playbook.ts +2677 -136
- package/reference/sdlc/decide.playbook/decide.registry.d.ts +7 -3
- package/reference/sdlc/decide.playbook/decide.registry.js +10 -3
- package/reference/sdlc/decide.playbook/decide.registry.ts +20 -5
- package/reference/sdlc/review.md +36 -18
- package/reference/sdlc/review.playbook/review.fsm.d.ts +7 -0
- package/reference/sdlc/review.playbook/review.fsm.js +133 -12
- package/reference/sdlc/review.playbook/review.fsm.ts +140 -12
- package/reference/sdlc/review.playbook/review.playbook.d.ts +5 -2
- package/reference/sdlc/review.playbook/review.playbook.js +65 -2
- package/reference/sdlc/review.playbook/review.playbook.ts +83 -6
- package/reference/sdlc/review.playbook/review.registry.d.ts +10 -3
- package/reference/sdlc/review.playbook/review.registry.js +10 -3
- package/reference/sdlc/review.playbook/review.registry.ts +23 -5
- package/slc/gears2fsm.md +6 -5
- package/slc/link.md +544 -41
- package/src/accepted-outcome.d.ts +18 -0
- package/src/accepted-outcome.js +94 -0
- package/src/accepted-outcome.ts +140 -0
- package/src/runtime.d.ts +164 -3
- package/src/runtime.ts +213 -2
- package/src/xstate-playbook-runtime.d.ts +149 -10
- package/src/xstate-playbook-runtime.js +2569 -270
- package/src/xstate-playbook-runtime.ts +4133 -490
- package/src/xstate-runtime.d.ts +59 -1
- package/src/xstate-runtime.js +866 -7
- package/src/xstate-runtime.ts +1397 -7
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ playbook
|
|
|
63
63
|
Type a task, enter `/code <task>` for implementation, or enter
|
|
64
64
|
`/decide <question>` for an independently proposed and reviewed decision.
|
|
65
65
|
|
|
66
|
-
On first launch, Playbook writes its config to `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml
|
|
66
|
+
On first launch, Playbook writes its config to `${SPEX_HOME:-$HOME/.spex}/playbook/playbook.config.yaml`. A config left at the former `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml` is moved there on the next launch, unless a relative primary locator would change targets; that case is rejected unchanged with absolute replacements.
|
|
67
67
|
|
|
68
68
|
The same config, compiled Captain, enabled playbooks, stable players, and
|
|
69
69
|
nested calls power headless turns. Both front ends create the same durable
|
package/docs/cli.md
CHANGED
|
@@ -169,7 +169,7 @@ stderr, and `--verbose` adds only telemetry topic names to stderr.
|
|
|
169
169
|
| `--no-provision` | do not create missing engine links for configured filesystem registries |
|
|
170
170
|
| `--json` | print exactly one `sessionId` / `reply` object |
|
|
171
171
|
| `--verbose` | add Captain telemetry topic names to stderr |
|
|
172
|
-
| `--continue` | continue the
|
|
172
|
+
| `--continue` | continue the newest Captain session stored for this working directory, or the reported global fallback |
|
|
173
173
|
| `--session <id>` | continue one durable Captain session explicitly |
|
|
174
174
|
| `--retry-uncertain` | with `--session`, retry its exact recorded uncertain input |
|
|
175
175
|
| `--discard-uncertain` | with `--session`, abandon its uncertain attempt |
|
|
@@ -188,7 +188,7 @@ The former positional `<from>`, `resume`, `--player`, `--captain`,
|
|
|
188
188
|
`--option`, `--cwd`, `--last`, run-only `--config`, and top-level `run:`
|
|
189
189
|
config are removed from `playbook run`. Enable a registry under `playbooks`,
|
|
190
190
|
declare provider agents once under top-level `players`, bind every local role
|
|
191
|
-
under `playbooks.<id>.roles`, tune compatible model and
|
|
191
|
+
under `playbooks.<id>.roles`, tune compatible model, effort, and fast mode in a `--with`
|
|
192
192
|
overlay, invoke the effective `/command`, and run from the working directory
|
|
193
193
|
you want agents to use. Legacy `playbooks.<id>.players` blocks are rejected and
|
|
194
194
|
are not auto-migrated because choosing equal or distinct new player IDs chooses
|
|
@@ -231,15 +231,16 @@ module's directory is a git repository, add `node_modules/` to its
|
|
|
231
231
|
|
|
232
232
|
### Continuing a Captain session
|
|
233
233
|
|
|
234
|
-
Interactive and headless commands write the same logical-session records
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
Interactive and headless commands write the same logical-session records in
|
|
235
|
+
the configured [`sessions` directory](configuration.md#session-storage), whose
|
|
236
|
+
default is `${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions/`. A fresh
|
|
237
|
+
interactive child persists turn zero before printing `playbook: session <id>`
|
|
238
|
+
and opening Boss input; a fresh headless turn returns the same kind of ID in
|
|
239
|
+
`--json`. After the current writer exits or explicitly hands off, either
|
|
240
|
+
presentation can reopen either origin:
|
|
240
241
|
|
|
241
242
|
```sh
|
|
242
|
-
# Reopen the
|
|
243
|
+
# Reopen the newest session stored for this working directory headlessly:
|
|
243
244
|
playbook run --continue "keep the scope small; skip the docs"
|
|
244
245
|
|
|
245
246
|
# Reopen one exact session in either presentation:
|
|
@@ -247,6 +248,14 @@ playbook --session 4f2c0000-0000-4000-8000-000000009ab1
|
|
|
247
248
|
playbook run --session 4f2c0000-0000-4000-8000-000000009ab1
|
|
248
249
|
```
|
|
249
250
|
|
|
251
|
+
Bare `--continue` prefers the newest durable record whose stored working
|
|
252
|
+
directory equals the directory where the command is invoked. If none matches,
|
|
253
|
+
it reports that absence on stderr and selects the globally newest record,
|
|
254
|
+
naming that session and its stored working directory. Use `--session <id>` to
|
|
255
|
+
select one exact session without applying the directory preference. The
|
|
256
|
+
uncertainty rules below still apply to whichever record is selected
|
|
257
|
+
([DR-041](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/041-working-directory-aware-continuation.md)).
|
|
258
|
+
|
|
250
259
|
A missing headless reply is read verbatim from stdin. Reopening restores the
|
|
251
260
|
compiled Captain conversation, engagement stack, nested child boundary,
|
|
252
261
|
stable-player ledger, and absolute working directory without replaying a
|
|
@@ -257,13 +266,78 @@ competing front end fails closed instead of forking the history.
|
|
|
257
266
|
An ordinary reopen reads current config and any opening `--with` fragments,
|
|
258
267
|
projects them to the stored catalog and player roster, and requires the stored
|
|
259
268
|
role bindings plus every structural setting to remain exact. Compatible
|
|
260
|
-
current `model` and `
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
269
|
+
current `model`, `effort`, and optional `fastMode` settings apply to the next
|
|
270
|
+
call. Boolean `false` explicitly resets model or effort to the provider
|
|
271
|
+
default, but `fastMode: false` is a literal disabled request; omission selects
|
|
272
|
+
the fast-mode provider default or inherits the player value at a role binding.
|
|
273
|
+
The retained provider token is never silently replaced by a fresh conversation
|
|
274
|
+
if a requested setting is not supported
|
|
264
275
|
([[playbook-cli-22](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-cli.md#playbook-cli-22)],
|
|
265
276
|
[DR-032](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/032-explicit-roles-session-players.md)).
|
|
266
277
|
|
|
278
|
+
### Following replay history
|
|
279
|
+
|
|
280
|
+
Beside each `<session-id>.json` manifest, both front ends tee every observed
|
|
281
|
+
host record in order to `<session-id>.records.jsonl`. Each complete line is a
|
|
282
|
+
version-1 envelope with a writer-assigned sequence contiguous from `1`, the
|
|
283
|
+
opaque record, and an optional local playbook role where the trace establishes
|
|
284
|
+
one unambiguously. The stream is a mode-`0600` regular non-symlink file inside
|
|
285
|
+
the private sessions directory. Readers consume only the complete
|
|
286
|
+
newline-terminated prefix; a final partial line is not presented as a record.
|
|
287
|
+
|
|
288
|
+
The replay projection recursively removes provider `resumeToken` fields and
|
|
289
|
+
string-valued `resume` selections while preserving `resume: false`. It is
|
|
290
|
+
therefore useful for following and presentation, but it cannot resume an agent
|
|
291
|
+
conversation and does not replace the private canonical manifest. External
|
|
292
|
+
hosts can follow this stream without taking the writer lease through the
|
|
293
|
+
published [`@sublang/playbook/session-store`
|
|
294
|
+
facade](embedding.md#sharing-the-cli-session-store).
|
|
295
|
+
|
|
296
|
+
Streams are unbounded in this version: neither front end prunes them, and
|
|
297
|
+
retention remains tied to the deferred session-deletion policy. Removing
|
|
298
|
+
provider credentials does not make the remaining replay content non-sensitive;
|
|
299
|
+
protect the prompts, replies, tool calls, events, and timestamps it contains as
|
|
300
|
+
sensitive session data.
|
|
301
|
+
|
|
302
|
+
Replay recording is fail-soft after the canonical session lease is valid. If
|
|
303
|
+
initialization, sanitization, append, repair, publication synchronization, or a
|
|
304
|
+
checkpoint fails, recording stops for that lease without changing the agent
|
|
305
|
+
turn, durable session settlement, reply, or exit outcome. The headless command
|
|
306
|
+
attempts this warning once on stderr:
|
|
307
|
+
|
|
308
|
+
```text
|
|
309
|
+
playbook run: warning: replay history for session "<session-id>" may be incomplete; recording has stopped
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The interactive child instead presents one Captain status with the same
|
|
313
|
+
`warning: replay history ...` text and writes no raw stderr diagnostic. A later
|
|
314
|
+
lease gets its own warning only if its replay writer independently becomes
|
|
315
|
+
incomplete. The public facade emits no warning; an embedding host decides how
|
|
316
|
+
to present the `incomplete` status it receives
|
|
317
|
+
([[playbook-cli-84](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-cli.md#playbook-cli-84)]).
|
|
318
|
+
|
|
319
|
+
### Reconciling possible repository effects
|
|
320
|
+
|
|
321
|
+
For each governed player call, Playbook records a Git baseline before the call
|
|
322
|
+
and a durable receipt afterward. CODE and DECIDE commit arms, and REVIEW's
|
|
323
|
+
Coder commit arm, accept a commit only when the receipt proves exactly one
|
|
324
|
+
descendant commit with no residual repository change; REVIEW's Reviewer calls
|
|
325
|
+
and DECIDE's proposal calls require the repository to remain exact. The
|
|
326
|
+
player's prose, including any `Commit:` line, is presentation rather than
|
|
327
|
+
proof.
|
|
328
|
+
|
|
329
|
+
If interruption, missing semantic evidence, concurrent work, or an ambiguous
|
|
330
|
+
repository delta prevents those facts from agreeing, the workflow parks
|
|
331
|
+
without replaying the player. Captain reports whether a change was observed or
|
|
332
|
+
could not be excluded, with the available baseline, after-HEAD, and proven
|
|
333
|
+
commit identity but no repository paths. While parked, ask Captain either to
|
|
334
|
+
retry reconciliation from the retained evidence or to abandon the unresolved
|
|
335
|
+
attempt. Reconciliation may complete the saved evidence or restore an exact
|
|
336
|
+
deferred Boss-question checkpoint, but it starts no replacement player call;
|
|
337
|
+
abandonment disposes the complete engagement without claiming an authored
|
|
338
|
+
workflow outcome. The same restricted recovery survives process restart
|
|
339
|
+
([DR-040](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/040-outcome-authority-effect-reconciliation.md)).
|
|
340
|
+
|
|
267
341
|
### Recovering an uncertain turn
|
|
268
342
|
|
|
269
343
|
Before model work, the runner takes one exclusive session lease and writes an
|
|
@@ -277,14 +351,28 @@ playbook run --session 4f2c0000-0000-4000-8000-000000009ab1 --discard-uncertain
|
|
|
277
351
|
```
|
|
278
352
|
|
|
279
353
|
Retry reads no input and reuses the byte-exact recorded turn and its exact
|
|
280
|
-
attempted Captain, player, and per-role model
|
|
281
|
-
cannot retune that attempt, and retry may duplicate external
|
|
354
|
+
attempted Captain, player, and per-role model, effort, and fast-mode settings;
|
|
355
|
+
current config cannot retune that attempt, and retry may duplicate external
|
|
356
|
+
effects. Discard
|
|
282
357
|
reads no input and runs no model: it restores the exact prior settled boundary,
|
|
283
358
|
or deletes a never-settled fresh session, while abandoning the attempted work.
|
|
284
359
|
An interrupted interactive turn uses the same uncertain record and is
|
|
285
|
-
recovered with these headless commands.
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
360
|
+
recovered with these headless commands. Current sessions use Captain-session
|
|
361
|
+
record schema 6. Records from the removed direct v6 runner and released record
|
|
362
|
+
schema 2 have incompatible player identity; Playbook 9 record schema 3, the
|
|
363
|
+
historical schema-4 retention shape, and both pre-release schema-5 shapes
|
|
364
|
+
predate the canonical schema-6 record boundary; the earlier schema-5 shape also
|
|
365
|
+
lacks `unresolvedEffects` and cannot prove whether governed work may replay.
|
|
366
|
+
Explicit selection rejects
|
|
367
|
+
all of them before registry construction or governed work with the applicable
|
|
368
|
+
cutover explanation. Implicit `--continue` reports and skips each fully
|
|
369
|
+
validated nonresumable record with its session id, path, applicable reason, and
|
|
370
|
+
an archive-or-remove remedy while leaving the file intact. Fresh-session
|
|
371
|
+
discovery likewise leaves and reports nonresumable, malformed, unsafe, or
|
|
372
|
+
unknown-schema files. A fully validated nonresumable record participates in
|
|
373
|
+
settled same-directory predecessor ordering: it declines adoption only when it
|
|
374
|
+
is newest, while an older or different-directory record does not block a newer
|
|
375
|
+
resumable predecessor. A record whose directory or order cannot be validated
|
|
376
|
+
publishes an empty fresh boundary without falling through. Those invalid
|
|
377
|
+
records still fail closed when explicitly selected or encountered by
|
|
378
|
+
`--continue`; no path converts or restores them.
|
package/docs/configuration.md
CHANGED
|
@@ -4,22 +4,35 @@
|
|
|
4
4
|
# Configuring agents
|
|
5
5
|
|
|
6
6
|
Fresh launches and ordinary reopens read one config at
|
|
7
|
-
`${
|
|
7
|
+
`${SPEX_HOME:-$HOME/.spex}/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.
|
|
10
10
|
|
|
11
|
+
On the first launching command after upgrading Playbook, it moves a config from the
|
|
12
|
+
former `${XDG_CONFIG_HOME:-$HOME/.config}/playbook/playbook.config.yaml` path
|
|
13
|
+
when the canonical path is absent. The one-time move preserves bytes and
|
|
14
|
+
permissions and leaves no compatibility alias, so running an older Spex host
|
|
15
|
+
afterward could seed a second file at the former path.
|
|
16
|
+
|
|
17
|
+
The current guard rejects relocation when a legacy relative `sessions` value
|
|
18
|
+
or relative filesystem `playbooks.<id>.from` would resolve differently below
|
|
19
|
+
the new directory. It leaves the former file unchanged and names every
|
|
20
|
+
target-preserving absolute replacement. Apply those replacements and retry;
|
|
21
|
+
Playbook does not rewrite the user-authored file.
|
|
22
|
+
|
|
11
23
|
```sh
|
|
12
|
-
$EDITOR "${
|
|
24
|
+
$EDITOR "${SPEX_HOME:-$HOME/.spex}/playbook/playbook.config.yaml"
|
|
13
25
|
```
|
|
14
26
|
|
|
15
27
|
## Anatomy
|
|
16
28
|
|
|
17
29
|
The config is top-level (no `config:` wrapper): a `captain` agent, one flat
|
|
18
30
|
`players` map of stable Captain-session agents, a `playbooks` map of enabled
|
|
19
|
-
workflows and their explicit role bindings,
|
|
20
|
-
`notifications` / `theme`. The Captain runs
|
|
21
|
-
writes the replies you see in the Captain
|
|
22
|
-
|
|
31
|
+
workflows and their explicit role bindings, an optional `sessions` storage
|
|
32
|
+
locator, and optional `layout` / `notifications` / `theme`. The Captain runs
|
|
33
|
+
hidden control and judge calls and writes the replies you see in the Captain
|
|
34
|
+
pane or on headless stdout. The three presentation fields apply only to
|
|
35
|
+
interactive tmux; headless runs ignore them.
|
|
23
36
|
|
|
24
37
|
A **role** is local to a playbook artifact: CODE's `coder` and REVIEW's `coder`
|
|
25
38
|
have the same semantic name but remain separate declarations. A **player** is
|
|
@@ -29,11 +42,12 @@ names, nesting, and ancestry never infer a binding.
|
|
|
29
42
|
|
|
30
43
|
Each `captain` or `players.<player-id>` value is either an adapter shorthand
|
|
31
44
|
(`claude`, `codex`) or a block carrying that agent's own `adapter`, `model`,
|
|
32
|
-
`effort`, `instruction`, and `permissions`. Settings are inline per
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
45
|
+
`effort`, `fastMode`, `instruction`, and `permissions`. Settings are inline per
|
|
46
|
+
stable agent
|
|
47
|
+
([DR-021](https://github.com/sublang-ai/playbook/blob/main/specs/decisions/021-inline-agent-settings.md)).
|
|
48
|
+
Dots in a player ID are literal characters, not YAML hierarchy. Other adapter
|
|
49
|
+
IDs pass through to `tmux-play` with a warning because `playbook` cannot
|
|
50
|
+
preflight their auth.
|
|
37
51
|
|
|
38
52
|
Within a `playbooks.<id>` block, `from` (the registry module), `command` (an
|
|
39
53
|
optional slash-command override), and `roles` are launcher-owned; every other
|
|
@@ -41,34 +55,35 @@ key is that playbook's option slice. Every manifest role must be present
|
|
|
41
55
|
exactly once. The launcher injects the rest — you do not write host wiring by
|
|
42
56
|
hand.
|
|
43
57
|
|
|
44
|
-
The seeded config runs the stable Coder player on
|
|
45
|
-
stable Reviewer player on
|
|
58
|
+
The seeded config runs the stable Coder player on GPT-5.6 Sol with fast mode
|
|
59
|
+
enabled and the stable Reviewer player on Claude Opus 5:
|
|
46
60
|
|
|
47
61
|
```yaml
|
|
48
62
|
captain:
|
|
49
63
|
adapter: claude
|
|
50
|
-
model: claude-opus-
|
|
64
|
+
model: claude-opus-5
|
|
51
65
|
effort: high
|
|
52
66
|
permissions:
|
|
53
67
|
mode: auto # protected auto mode for the Claude Captain
|
|
54
68
|
|
|
55
69
|
players:
|
|
56
70
|
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
71
|
adapter: codex
|
|
65
|
-
model: gpt-5.
|
|
66
|
-
effort:
|
|
72
|
+
model: gpt-5.6-sol
|
|
73
|
+
effort: ultra
|
|
74
|
+
fastMode: true
|
|
67
75
|
permissions:
|
|
68
76
|
mode: auto
|
|
69
77
|
writablePaths:
|
|
70
78
|
- .git # allow git metadata writes under Codex auto mode
|
|
71
79
|
|
|
80
|
+
dev.reviewer:
|
|
81
|
+
adapter: claude
|
|
82
|
+
model: claude-opus-5
|
|
83
|
+
effort: xhigh
|
|
84
|
+
permissions:
|
|
85
|
+
mode: auto # protected auto mode for the Claude Reviewer
|
|
86
|
+
|
|
72
87
|
playbooks:
|
|
73
88
|
code:
|
|
74
89
|
from: '@sublang/playbook/code/registry'
|
|
@@ -104,21 +119,26 @@ roles:
|
|
|
104
119
|
coder: dev.coder
|
|
105
120
|
```
|
|
106
121
|
|
|
107
|
-
Use a block to override only that role invocation's model or
|
|
122
|
+
Use a block to override only that role invocation's model, effort, or fast
|
|
123
|
+
mode:
|
|
108
124
|
|
|
109
125
|
```yaml
|
|
110
126
|
roles:
|
|
111
127
|
coder:
|
|
112
128
|
player: dev.coder
|
|
113
|
-
model:
|
|
129
|
+
model: gpt-5.6-sol
|
|
114
130
|
effort: false # explicitly reset to this provider's default
|
|
131
|
+
fastMode: false # literal disabled request, not a default sentinel
|
|
115
132
|
```
|
|
116
133
|
|
|
117
|
-
Omitting
|
|
118
|
-
boolean `false`
|
|
119
|
-
resumed conversation cannot accidentally retain an earlier selection.
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
Omitting any override inherits that player's top-level default. For `model`
|
|
135
|
+
and `effort`, boolean `false` selects the provider default explicitly, so a
|
|
136
|
+
resumed conversation cannot accidentally retain an earlier selection. For
|
|
137
|
+
`fastMode`, `false` is a literal request to disable fast mode; omitting the
|
|
138
|
+
top-level setting selects the provider default. A present fast-mode boolean is
|
|
139
|
+
accepted only for adapters Cligent reports as supporting it. A role binding
|
|
140
|
+
cannot override adapter, instruction, permissions, workspace, or tool posture;
|
|
141
|
+
those define the stable player envelope.
|
|
122
142
|
|
|
123
143
|
## Sharing, isolation, and concurrency
|
|
124
144
|
|
|
@@ -136,9 +156,9 @@ second top-level player and change only its binding:
|
|
|
136
156
|
```yaml
|
|
137
157
|
players:
|
|
138
158
|
review.coder:
|
|
139
|
-
adapter:
|
|
140
|
-
model:
|
|
141
|
-
effort:
|
|
159
|
+
adapter: codex
|
|
160
|
+
model: gpt-5.6-sol
|
|
161
|
+
effort: ultra
|
|
142
162
|
|
|
143
163
|
playbooks:
|
|
144
164
|
review:
|
|
@@ -183,8 +203,9 @@ playbook run --with fast-lineup.yaml "/code implement the approved change"
|
|
|
183
203
|
# fast-lineup.yaml — retune the shared Coder; nothing is written back.
|
|
184
204
|
players:
|
|
185
205
|
dev.coder:
|
|
186
|
-
model:
|
|
206
|
+
model: gpt-5.6-sol
|
|
187
207
|
effort: medium
|
|
208
|
+
fastMode: false
|
|
188
209
|
```
|
|
189
210
|
|
|
190
211
|
Fragments merge into the agent block rather than replacing it, so
|
|
@@ -207,9 +228,37 @@ The global file is never modified, and `--with` is not forwarded to
|
|
|
207
228
|
Overlays apply when creating a fresh session and as current-config input for a
|
|
208
229
|
compatible ordinary reopen. A selected session keeps its stored catalog,
|
|
209
230
|
player roster, role bindings, adapter, instruction, permissions, and working
|
|
210
|
-
directory; only model and
|
|
211
|
-
complete
|
|
212
|
-
|
|
231
|
+
directory; only model, effort, and fast mode may change. The next call reapplies
|
|
232
|
+
both complete model and effort selections and the optional effective fast-mode
|
|
233
|
+
boolean. An uncertain retry accepts no tuning overlay and uses the exact
|
|
234
|
+
attempted settings already stored with that turn.
|
|
235
|
+
|
|
236
|
+
## Session storage
|
|
237
|
+
|
|
238
|
+
Both front ends select canonical session manifests and write replay streams in
|
|
239
|
+
one directory, where external hosts may keep their own sidecars too. Set the
|
|
240
|
+
optional top-level `sessions` key to move that shared store:
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
sessions: ./state/playbook-sessions
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The value must be a nonempty filesystem path. When the key is absent, the
|
|
247
|
+
directory is
|
|
248
|
+
`${XDG_STATE_HOME:-$HOME/.local/state}/playbook/sessions`. An absolute path is
|
|
249
|
+
used as given; `~` and `~/...` expand from the home directory, while `~user`
|
|
250
|
+
is rejected. Every other value, including a bare relative path such as the one
|
|
251
|
+
above, resolves against the primary config file's directory rather than the
|
|
252
|
+
invocation directory. A `sessions` value in a `--with` overlay replaces the
|
|
253
|
+
primary value, with later overlays winning.
|
|
254
|
+
|
|
255
|
+
Launch validates that the resolved path can serve as the mode-`0700`, real,
|
|
256
|
+
non-symlink session store before selecting a record or starting agent work and
|
|
257
|
+
fails closed when it cannot. The non-launching `playbook --list` command still
|
|
258
|
+
validates the locator's syntax but does not inspect that directory's filesystem
|
|
259
|
+
usability. The resolved locator is launch configuration only: it never enters
|
|
260
|
+
a persisted structural or execution projection
|
|
261
|
+
([[playbook-cli-78](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-cli.md#playbook-cli-78)]).
|
|
213
262
|
|
|
214
263
|
## Durable shared configuration
|
|
215
264
|
|
|
@@ -223,9 +272,9 @@ public UUID. Presentation-only fields are inert headlessly.
|
|
|
223
272
|
An ordinary reopen reads current config and opening overlays, but first
|
|
224
273
|
projects them to the stored playbooks and referenced players. An unrelated new
|
|
225
274
|
entry cannot enter or invalidate the session. Structural drift fails closed;
|
|
226
|
-
compatible model or
|
|
227
|
-
record, shell, runtime-snapshot, and trace schemas are rejected
|
|
228
|
-
having role or player identity guessed.
|
|
275
|
+
compatible model, effort, or fast-mode changes apply on the next provider
|
|
276
|
+
call. Legacy record, shell, runtime-snapshot, and trace schemas are rejected
|
|
277
|
+
rather than having role or player identity guessed.
|
|
229
278
|
|
|
230
279
|
## External playbooks
|
|
231
280
|
|
package/docs/embedding.md
CHANGED
|
@@ -37,7 +37,9 @@ depends on) rather than relying on it resolving through the package's
|
|
|
37
37
|
tree, which pnpm's strict linking will not allow.
|
|
38
38
|
|
|
39
39
|
```ts
|
|
40
|
-
import createPlaybookRuntime
|
|
40
|
+
import createPlaybookRuntime, {
|
|
41
|
+
type ReviewPlaybookHostCapabilities,
|
|
42
|
+
} from '@sublang/playbook/review/playbook';
|
|
41
43
|
import type {
|
|
42
44
|
CaptainCallOptions,
|
|
43
45
|
CaptainResult,
|
|
@@ -144,9 +146,21 @@ const ports: PlaybookPorts = {
|
|
|
144
146
|
},
|
|
145
147
|
};
|
|
146
148
|
|
|
147
|
-
const runtime = createPlaybookRuntime({});
|
|
148
|
-
|
|
149
149
|
const playbookSessionId = randomUUID();
|
|
150
|
+
|
|
151
|
+
// Schema-3 artifacts keep persisted configured options separate from live
|
|
152
|
+
// current-host authority. Build these capabilities only after acquiring the
|
|
153
|
+
// session lease and resolving the canonical Git worktree. Their authority
|
|
154
|
+
// must name this playbook/session/working directory and their repository and
|
|
155
|
+
// effect-ledger operations must stay live; never put them in configuration,
|
|
156
|
+
// machine input, or a persisted snapshot.
|
|
157
|
+
declare const hostCapabilities: ReviewPlaybookHostCapabilities;
|
|
158
|
+
|
|
159
|
+
const runtime = createPlaybookRuntime({
|
|
160
|
+
configuredOptions: {},
|
|
161
|
+
hostCapabilities,
|
|
162
|
+
});
|
|
163
|
+
|
|
150
164
|
await runtime.init({
|
|
151
165
|
sessionId: playbookSessionId,
|
|
152
166
|
playbookId: 'review',
|
|
@@ -165,7 +179,7 @@ await runtime.dispose();
|
|
|
165
179
|
|
|
166
180
|
## Sessions and traces
|
|
167
181
|
|
|
168
|
-
Every init-to-dispose lifecycle is one playbook session. Schema-
|
|
182
|
+
Every init-to-dispose lifecycle is one playbook session. Schema-4
|
|
169
183
|
`playbook.trace` telemetry carries that immutable ID plus a contiguous
|
|
170
184
|
sequence across exact Boss input, judge/player calls, FSM transitions, visible
|
|
171
185
|
Captain work, nested playbook calls, status, settlement, and disposal. A
|
|
@@ -184,15 +198,115 @@ sequential call lane across every frame that names them, while distinct IDs
|
|
|
184
198
|
remain isolated. Child return, frame disposal, and a later root engagement do
|
|
185
199
|
not clear the session ledger.
|
|
186
200
|
|
|
187
|
-
Runtime snapshots are schema
|
|
188
|
-
role-local, while the composing shell
|
|
189
|
-
|
|
190
|
-
|
|
201
|
+
Runtime and complete shell snapshots are schema 4. Their role-resume
|
|
202
|
+
projection remains role-local, while the composing shell persists the stable
|
|
203
|
+
player ledger, every frame's exact role bindings, and the host's authoritative
|
|
204
|
+
effect-ledger mirror. The bundled CLI wraps that shell state in Captain
|
|
205
|
+
session-record schema 6. Do not restore an earlier snapshot or session record
|
|
206
|
+
by guessing identity or effect evidence. This includes both pre-release
|
|
207
|
+
schema-5 record shapes; the earlier one predates required `unresolvedEffects`,
|
|
208
|
+
and neither is a canonical schema-6 boundary. Explicit selection rejects them,
|
|
209
|
+
while fresh discovery reports and skips them. A fully validated nonresumable
|
|
210
|
+
record participates in settled same-directory ordering and declines adoption
|
|
211
|
+
only when it is newest; an older or different-directory record does not block a
|
|
212
|
+
newer resumable predecessor. An unvalidatable record leaves ordering unproved,
|
|
213
|
+
so discovery publishes an empty target without falling through. On a compatible
|
|
214
|
+
restore, rebuild
|
|
191
215
|
`promptIdentity` from the current model selection (or adapter for an explicit
|
|
192
|
-
provider-default selection)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
216
|
+
provider-default selection) and rebuild live host capabilities under the
|
|
217
|
+
current lease, so neither invocation identity nor repository authority comes
|
|
218
|
+
from stale machine state. Trace data, tokens, repository projections, and
|
|
219
|
+
capability functions never enter Boss-visible status text or configured
|
|
220
|
+
options. Because trace observers do receive opaque resume tokens, persisted
|
|
221
|
+
traces should be protected as sensitive data.
|
|
222
|
+
|
|
223
|
+
## Sharing the CLI session store
|
|
224
|
+
|
|
225
|
+
An external host that needs the CLI's canonical session validation and
|
|
226
|
+
token-free replay format can use the narrow, semver-stable
|
|
227
|
+
`@sublang/playbook/session-store` facade. It shares the CLI's private store and
|
|
228
|
+
validators by construction but exposes no canonical manifest, snapshot,
|
|
229
|
+
provider credential, effect ledger, recovery operation, or turn-lifecycle
|
|
230
|
+
operation:
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import {
|
|
234
|
+
defaultSessionsDir,
|
|
235
|
+
openSessionStore,
|
|
236
|
+
} from '@sublang/playbook/session-store';
|
|
237
|
+
|
|
238
|
+
const store = openSessionStore(defaultSessionsDir());
|
|
239
|
+
const { sessions, skipped } = await store.list();
|
|
240
|
+
|
|
241
|
+
const sessionId = sessions[0]?.sessionId;
|
|
242
|
+
if (sessionId !== undefined) {
|
|
243
|
+
const summary = await store.read(sessionId);
|
|
244
|
+
console.log(summary.sessionId, summary.state, summary.cwd);
|
|
245
|
+
|
|
246
|
+
const first = await store.readStream(sessionId);
|
|
247
|
+
const next = await store.readStream(sessionId, {
|
|
248
|
+
afterSeq: first.lastReadableSeq,
|
|
249
|
+
});
|
|
250
|
+
console.log(next.entries, skipped);
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`list()` reports valid summaries and separately reports skipped canonical
|
|
255
|
+
manifests with their validation or cutover reason. A summary has exactly
|
|
256
|
+
`schemaVersion`, `sessionId`, `state`, `cwd`, and `updatedAt`. A lease-free
|
|
257
|
+
`readStream()` returns complete envelopes and `lastReadableSeq` only: it makes
|
|
258
|
+
no claim that another process has durably checkpointed the observed bytes or
|
|
259
|
+
that its live writer remains complete. An absent stream reads as empty, and
|
|
260
|
+
acquiring its lease does not require a manifest; only `read()` requires a
|
|
261
|
+
canonical session summary. Pass an absolute path to `openSessionStore()` when
|
|
262
|
+
using a directory other than the environment-derived default.
|
|
263
|
+
|
|
264
|
+
Writing requires the one exclusive session lease. The writer assigns envelope
|
|
265
|
+
version and sequence, serializes overlapping appends in invocation order, and
|
|
266
|
+
strips provider resume credentials from every accepted record:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
const lease = await store.acquire(
|
|
270
|
+
'4f2c0000-0000-4000-8000-000000009ab1',
|
|
271
|
+
);
|
|
272
|
+
try {
|
|
273
|
+
await lease.append({ type: 'host_notice', message: 'attached' });
|
|
274
|
+
const status = lease.streamStatus();
|
|
275
|
+
console.log(status);
|
|
276
|
+
if (status.lastReadableSeq !== null) {
|
|
277
|
+
const replay = await lease.readStream();
|
|
278
|
+
console.log(replay.lastReadableSeq, replay.lastDurableSeq);
|
|
279
|
+
}
|
|
280
|
+
} finally {
|
|
281
|
+
const finalStatus = await lease.release();
|
|
282
|
+
console.log(finalStatus);
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`streamStatus()` synchronously returns the current live status. If initialization
|
|
287
|
+
could not establish a trustworthy whole-stream boundary, it returns
|
|
288
|
+
`{ lastReadableSeq: null, lastDurableSeq: null, incomplete: true }`, and
|
|
289
|
+
`lease.readStream()` rejects rather than return partial history.
|
|
290
|
+
An `append()` suppressed before release by either unavailable initialization or
|
|
291
|
+
a numeric incomplete latch resolves `undefined` without recording the supplied
|
|
292
|
+
record, so fulfillment alone does not prove persistence.
|
|
293
|
+
|
|
294
|
+
Always release a successfully acquired lease. `release()` closes append
|
|
295
|
+
admission, drains earlier appends, attempts the final checkpoint, retires the
|
|
296
|
+
lease, and returns the final `lastReadableSeq`, `lastDurableSeq`, and
|
|
297
|
+
`incomplete` status. A replay initialization failure reports unavailable null
|
|
298
|
+
boundaries; a later sanitization, repair, or persistence failure latches
|
|
299
|
+
numeric `incomplete` status. Either state suppresses later replay work on that
|
|
300
|
+
lease and remains isolated from canonical session lifecycle work. The facade
|
|
301
|
+
writes no warning to stdout or stderr; the embedding host owns any presentation
|
|
302
|
+
of that status.
|
|
303
|
+
|
|
304
|
+
For control flow, a missing canonical manifest from `read()` uses
|
|
305
|
+
`Error.code === 'PLAYBOOK_SESSION_NOT_FOUND'`, and a competing live or foreign
|
|
306
|
+
lease uses `Error.code === 'PLAYBOOK_SESSION_LEASE_ACTIVE'`. Do not match error
|
|
307
|
+
messages or assume those codes for malformed input, unsafe storage, an
|
|
308
|
+
indeterminate owner probe, or another storage failure
|
|
309
|
+
([[playbook-cli-73](https://github.com/sublang-ai/playbook/blob/main/specs/packages/playbook-cli.md#playbook-cli-73)]).
|
|
196
310
|
|
|
197
311
|
See
|
|
198
312
|
[`code.playbook.test.ts`](https://github.com/sublang-ai/playbook/blob/main/reference/sdlc/code.playbook/code.playbook.test.ts)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sublang/playbook",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Composable XState v5 playbook runtime with compiled Captain, CODE, REVIEW, and DECIDE workflows driven by GEARS specs.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
"src/runtime.ts",
|
|
29
29
|
"src/runtime.js",
|
|
30
30
|
"src/runtime.d.ts",
|
|
31
|
+
"src/accepted-outcome.ts",
|
|
32
|
+
"src/accepted-outcome.js",
|
|
33
|
+
"src/accepted-outcome.d.ts",
|
|
31
34
|
"src/xstate-runtime.ts",
|
|
32
35
|
"src/xstate-runtime.js",
|
|
33
36
|
"src/xstate-runtime.d.ts",
|
|
@@ -64,15 +67,19 @@
|
|
|
64
67
|
"reference/sdlc/code.playbook/playbook-captain.ts",
|
|
65
68
|
"reference/sdlc/code.playbook/playbook-captain.js",
|
|
66
69
|
"reference/sdlc/code.playbook/playbook-captain.d.ts",
|
|
70
|
+
"reference/sdlc/code.playbook/session-store.js",
|
|
71
|
+
"reference/sdlc/code.playbook/session-store.d.ts",
|
|
67
72
|
"reference/sdlc/code.playbook/code.gears.md",
|
|
68
73
|
"reference/sdlc/code.playbook/playbook.config.template.yaml",
|
|
69
74
|
"reference/sdlc/code.playbook/bin/playbook.js",
|
|
70
75
|
"reference/sdlc/code.playbook/bin/launch-config.js",
|
|
71
76
|
"reference/sdlc/code.playbook/bin/run.js",
|
|
72
77
|
"reference/sdlc/code.playbook/bin/interactive-session.js",
|
|
78
|
+
"reference/sdlc/code.playbook/bin/replay-observer.js",
|
|
73
79
|
"reference/sdlc/code.playbook/bin/session-store.js",
|
|
74
80
|
"reference/sdlc/code.playbook/bin/provision.js",
|
|
75
81
|
"reference/sdlc/code.playbook/bin/adapter-sdk.js",
|
|
82
|
+
"reference/sdlc/code.playbook/bin/repository-effects.js",
|
|
76
83
|
"reference/sdlc/review.playbook/review.gears.md",
|
|
77
84
|
"reference/sdlc/review.playbook/review.fsm.ts",
|
|
78
85
|
"reference/sdlc/review.playbook/review.fsm.js",
|
|
@@ -123,6 +130,10 @@
|
|
|
123
130
|
"types": "./reference/sdlc/code.playbook/playbook-captain.d.ts",
|
|
124
131
|
"default": "./reference/sdlc/code.playbook/playbook-captain.js"
|
|
125
132
|
},
|
|
133
|
+
"./session-store": {
|
|
134
|
+
"types": "./reference/sdlc/code.playbook/session-store.d.ts",
|
|
135
|
+
"default": "./reference/sdlc/code.playbook/session-store.js"
|
|
136
|
+
},
|
|
126
137
|
"./slc/*": "./slc/*",
|
|
127
138
|
"./review/playbook": {
|
|
128
139
|
"types": "./reference/sdlc/review.playbook/review.playbook.d.ts",
|
|
@@ -154,8 +165,8 @@
|
|
|
154
165
|
"provenance": true
|
|
155
166
|
},
|
|
156
167
|
"dependencies": {
|
|
157
|
-
"@sublang/cligent": "^0.
|
|
158
|
-
"@sublang/spex": "^
|
|
168
|
+
"@sublang/cligent": "^0.24.0",
|
|
169
|
+
"@sublang/spex": "^3.0.0",
|
|
159
170
|
"p-queue": "^9.3.1",
|
|
160
171
|
"xstate": "^5.19.4",
|
|
161
172
|
"yaml": "^2.9.0"
|