@sublang/playbook 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +243 -193
  2. package/package.json +52 -17
  3. package/reference/sdlc/captain.md +102 -0
  4. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +227 -0
  5. package/reference/sdlc/captain.playbook/captain.fsm.js +628 -0
  6. package/reference/sdlc/captain.playbook/captain.fsm.ts +851 -0
  7. package/reference/sdlc/captain.playbook/captain.gears.md +60 -0
  8. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +23 -0
  9. package/reference/sdlc/captain.playbook/captain.playbook.js +1053 -0
  10. package/reference/sdlc/captain.playbook/captain.playbook.ts +1144 -0
  11. package/reference/sdlc/code.playbook/bin/playbook.js +580 -0
  12. package/reference/sdlc/code.playbook/bin/run.js +893 -0
  13. package/reference/sdlc/code.playbook/code.fsm.d.ts +11 -4
  14. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +2 -2
  15. package/reference/sdlc/code.playbook/code.fsm.introspect.js +1 -1
  16. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +6 -6
  17. package/reference/sdlc/code.playbook/code.fsm.js +334 -102
  18. package/reference/sdlc/code.playbook/code.fsm.ts +470 -182
  19. package/reference/sdlc/code.playbook/code.gears.md +11 -10
  20. package/reference/sdlc/code.playbook/code.playbook.d.ts +18 -9
  21. package/reference/sdlc/code.playbook/code.playbook.js +1098 -202
  22. package/reference/sdlc/code.playbook/code.playbook.ts +1440 -258
  23. package/reference/sdlc/code.playbook/code.registry.d.ts +17 -5
  24. package/reference/sdlc/code.playbook/code.registry.js +49 -34
  25. package/reference/sdlc/code.playbook/code.registry.ts +75 -41
  26. package/reference/sdlc/code.playbook/playbook-captain.d.ts +16 -8
  27. package/reference/sdlc/code.playbook/playbook-captain.js +1005 -240
  28. package/reference/sdlc/code.playbook/playbook-captain.ts +1310 -301
  29. package/reference/sdlc/code.playbook/playbook.config.template.yaml +68 -0
  30. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +396 -0
  31. package/reference/sdlc/discuss.playbook/discuss.fsm.js +2066 -0
  32. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +2464 -0
  33. package/reference/sdlc/discuss.playbook/discuss.gears.md +251 -0
  34. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +113 -0
  35. package/reference/sdlc/discuss.playbook/discuss.playbook.js +1514 -0
  36. package/reference/sdlc/discuss.playbook/discuss.playbook.ts +1926 -0
  37. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +58 -0
  38. package/reference/sdlc/discuss.playbook/discuss.registry.js +97 -0
  39. package/reference/sdlc/discuss.playbook/discuss.registry.ts +153 -0
  40. package/slc/gears2fsm.md +557 -57
  41. package/slc/link.md +1097 -80
  42. package/slc/optimize.md +88 -0
  43. package/slc/text2gears.md +247 -5
  44. package/src/runtime.d.ts +145 -3
  45. package/src/runtime.ts +200 -2
  46. package/src/xstate-runtime.d.ts +94 -0
  47. package/src/xstate-runtime.js +1247 -0
  48. package/src/xstate-runtime.ts +1802 -0
  49. package/reference/sdlc/code.playbook/bin/playbook-code.js +0 -487
  50. package/reference/sdlc/code.playbook/code.tmux-play.d.ts +0 -4
  51. package/reference/sdlc/code.playbook/code.tmux-play.js +0 -11
  52. package/reference/sdlc/code.playbook/code.tmux-play.ts +0 -29
  53. package/reference/sdlc/code.playbook/playbook-code.config.template.yaml +0 -72
  54. package/reference/sdlc/code.playbook/tmux-play.config.yaml +0 -55
  55. package/reference/sdlc/code.playbook/tmux-play.production.config.yaml +0 -38
@@ -0,0 +1,68 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ # Generic `playbook` launcher config.
5
+ # Top-level host fields only — no `config:` wrapper, no top-level `players`.
6
+ # The launcher injects captain.from and the namespaced <id>-<role> host
7
+ # players, then launches cligent's tmux-play under the Playbook Captain shell.
8
+
9
+ # Reusable agent settings. A profile id must not be an adapter shorthand
10
+ # (claude, codex). Reference a profile by id from captain / players below.
11
+ # Profile ids name the underlying agent/model (e.g. claude-opus,
12
+ # codex-gpt) so they read distinctly from the captain / coder / reviewer
13
+ # player roles that reference them.
14
+ # Every seeded agent runs in cligent's protected auto mode
15
+ # (permissions.mode: auto): claude maps it to permissionMode auto, codex to
16
+ # on-request + auto_review. Codex roles also grant writablePaths: ['.git']
17
+ # so commit turns can write git metadata under the codex sandbox.
18
+ profiles:
19
+ claude-opus:
20
+ adapter: claude
21
+ model: claude-opus-4-8
22
+ reasoningEffort: high
23
+ permissions:
24
+ mode: auto
25
+ claude-opus-1m:
26
+ adapter: claude
27
+ model: claude-opus-4-8[1m]
28
+ reasoningEffort: xhigh
29
+ permissions:
30
+ mode: auto
31
+ codex-gpt:
32
+ adapter: codex
33
+ model: gpt-5.5
34
+ reasoningEffort: xhigh
35
+ permissions:
36
+ mode: auto
37
+ writablePaths: ['.git']
38
+
39
+ # The Captain/Judge agent: a profile id, an adapter shorthand, or a full
40
+ # tmux-play agent block (which may carry a `profile:` key).
41
+ captain: claude-opus
42
+
43
+ # Host notifications. Omitting turn_aborted resolves it to off.
44
+ notifications:
45
+ player_finished: bell
46
+ turn_finished: desktop
47
+
48
+ # Enabled playbooks. Each is loaded from its explicit `from` module; the
49
+ # `<id>` key must equal that module's manifest id. `from`, `command`, and
50
+ # `players` are launcher-owned; every other key (e.g. CODE's `committer`)
51
+ # is that playbook's option slice.
52
+ playbooks:
53
+ code:
54
+ from: "@sublang/playbook/code/registry"
55
+ players:
56
+ coder: claude-opus-1m
57
+ reviewer: codex-gpt
58
+ committer: coder
59
+
60
+ # The DISCUSS playbook: two agents converge on spec items or decision
61
+ # records. `committer` picks which player runs Committer commits
62
+ # (default: host).
63
+ # discuss:
64
+ # from: "@sublang/playbook/discuss/registry"
65
+ # players:
66
+ # host: claude-opus
67
+ # participant: codex-gpt
68
+ # committer: host
@@ -0,0 +1,396 @@
1
+ type Player = 'Host' | 'Participant' | 'Committer';
2
+ type ReviewScope = 'specItems' | 'decisionRecords' | 'mixed';
3
+ type JumpableStateId = 'ready' | 'initialProposalRound' | 'reconciliationRound' | 'hostWritesAgreement' | 'commitInitialChanges' | 'reviewSpecInitialCommit' | 'reviewSpecHostChanges' | 'reviewDrInitialCommit' | 'reviewDrHostChanges' | 'reviewMixedInitialCommit' | 'reviewMixedHostChanges' | 'hostAddressesFindings' | 'participantAddressesRebuttals' | 'commitReviewedChanges' | 'failed';
4
+ type ResumableStateId = 'askHostInitial' | 'askParticipantInitial' | 'hostInitialRound' | 'participantInitialRound' | Exclude<JumpableStateId, 'ready' | 'initialProposalRound' | 'reconciliationRound' | 'failed'>;
5
+ export interface PendingBossQuestion {
6
+ questionId: ResumableStateId;
7
+ resumeStateId: ResumableStateId;
8
+ sourceItem: string;
9
+ player: Player;
10
+ question: string;
11
+ }
12
+ type PendingBossQuestions = Partial<Record<ResumableStateId, PendingBossQuestion>>;
13
+ type BossReplies = Partial<Record<ResumableStateId, string>>;
14
+ type PendingBossQuestionParams = Omit<PendingBossQuestion, 'questionId'>;
15
+ export interface DiscussContext {
16
+ hostPlayer?: string;
17
+ participantPlayer?: string;
18
+ committerPlayer?: string;
19
+ topic?: string;
20
+ hostLlm?: string;
21
+ participantLlm?: string;
22
+ hostProposal?: string;
23
+ participantProposal?: string;
24
+ agreement?: string;
25
+ latestChanges?: string;
26
+ reviewScope?: ReviewScope;
27
+ reviewItems?: string;
28
+ rebuttals?: string;
29
+ lastResult?: PlayerOutput;
30
+ lastError?: unknown;
31
+ pendingBossQuestions?: PendingBossQuestions;
32
+ bossReplies?: BossReplies;
33
+ stagedHostResult?: PlayerOutput;
34
+ stagedParticipantResult?: PlayerOutput;
35
+ }
36
+ export type DiscussEvent = {
37
+ type: 'START_DISCUSSION';
38
+ topic: string;
39
+ hostLlm?: string;
40
+ participantLlm?: string;
41
+ } | {
42
+ type: 'START_REVIEW';
43
+ latestChanges: string;
44
+ reviewScope: ReviewScope;
45
+ rebuttals?: string;
46
+ } | {
47
+ type: 'BOSS_INTERRUPT';
48
+ targetId: JumpableStateId;
49
+ } | {
50
+ type: 'BOSS_REPLY';
51
+ questionId?: ResumableStateId;
52
+ answer: string;
53
+ };
54
+ export interface DiscussInput {
55
+ host?: string;
56
+ participant?: string;
57
+ committer?: string;
58
+ }
59
+ export interface PlayerInput {
60
+ stateId: ResumableStateId;
61
+ sourceItem: string;
62
+ prompt: string;
63
+ result: Record<string, string>;
64
+ player: Player;
65
+ topic?: string;
66
+ hostLlm?: string;
67
+ participantLlm?: string;
68
+ hostProposal?: string;
69
+ participantProposal?: string;
70
+ agreement?: string;
71
+ latestChanges?: string;
72
+ reviewScope?: ReviewScope;
73
+ reviewItems?: string;
74
+ rebuttals?: string;
75
+ hostPlayer?: string;
76
+ participantPlayer?: string;
77
+ committerPlayer?: string;
78
+ pendingBossQuestion?: PendingBossQuestion;
79
+ bossReply?: string;
80
+ }
81
+ type AdditionalPlayerFields = {
82
+ proposal?: string;
83
+ agreement?: string;
84
+ latestChanges?: string;
85
+ reviewScope?: ReviewScope;
86
+ reviewItems?: string;
87
+ rebuttals?: string;
88
+ question?: string;
89
+ readonly [key: string]: unknown;
90
+ };
91
+ export type PlayerOutput = ({
92
+ guard: 'proposalMade';
93
+ proposal: string;
94
+ } & AdditionalPlayerFields) | ({
95
+ guard: 'endedInitialDiscussion';
96
+ agreement?: string;
97
+ } & AdditionalPlayerFields) | ({
98
+ guard: 'wroteChanges';
99
+ latestChanges: string;
100
+ reviewScope: ReviewScope;
101
+ } & AdditionalPlayerFields) | ({
102
+ guard: 'committed';
103
+ latestChanges?: string;
104
+ reviewScope?: ReviewScope;
105
+ } & AdditionalPlayerFields) | ({
106
+ guard: 'noFindings';
107
+ } & AdditionalPlayerFields) | ({
108
+ guard: 'findingsRaised';
109
+ reviewItems: string;
110
+ } & AdditionalPlayerFields) | ({
111
+ guard: 'changesMade';
112
+ latestChanges?: string;
113
+ reviewScope?: ReviewScope;
114
+ } & AdditionalPlayerFields) | ({
115
+ guard: 'rebuttalsRaised';
116
+ rebuttals: string;
117
+ } & AdditionalPlayerFields) | ({
118
+ guard: 'rebuttalsAddressed';
119
+ rebuttals?: string;
120
+ } & AdditionalPlayerFields) | ({
121
+ guard: 'needsBossReply';
122
+ question: string;
123
+ } & AdditionalPlayerFields);
124
+ type DiscussActionName = 'copyStartDiscussion' | 'copyStartReview' | 'rememberHostProposal' | 'rememberParticipantProposal' | 'rememberAgreement' | 'rememberWrittenChanges' | 'rememberCommittedChanges' | 'rememberReviewFindings' | 'rememberHostReviewResponse' | 'rememberParticipantRebuttalResponse' | 'rememberCaptainResult' | 'rememberCaptainError' | 'rememberMalformedCaptainOutput' | 'rememberMalformedBossReply' | 'setPendingBossQuestion' | 'rememberBossReply' | 'clearBranchBossReplyContext' | 'clearParallelRoundContext' | 'clearBossReplyContext';
125
+ declare function bossInterrupts(ids: readonly JumpableStateId[], actions?: DiscussActionName | DiscussActionName[]): any[];
126
+ declare function resumableStates(ids: readonly string[]): any[];
127
+ export declare const discussMachine: import("xstate").StateMachine<DiscussContext, {
128
+ type: "START_DISCUSSION";
129
+ topic: string;
130
+ hostLlm?: string;
131
+ participantLlm?: string;
132
+ } | {
133
+ type: "START_REVIEW";
134
+ latestChanges: string;
135
+ reviewScope: ReviewScope;
136
+ rebuttals?: string;
137
+ } | {
138
+ type: "BOSS_INTERRUPT";
139
+ targetId: JumpableStateId;
140
+ } | {
141
+ type: "BOSS_REPLY";
142
+ questionId?: ResumableStateId;
143
+ answer: string;
144
+ }, {
145
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>> | undefined;
146
+ }, {
147
+ src: "player";
148
+ logic: import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>;
149
+ id: string | undefined;
150
+ }, {
151
+ type: "copyStartDiscussion";
152
+ params: import("xstate").NonReducibleUnknown;
153
+ } | {
154
+ type: "copyStartReview";
155
+ params: import("xstate").NonReducibleUnknown;
156
+ } | {
157
+ type: "rememberHostProposal";
158
+ params: import("xstate").NonReducibleUnknown;
159
+ } | {
160
+ type: "rememberParticipantProposal";
161
+ params: import("xstate").NonReducibleUnknown;
162
+ } | {
163
+ type: "rememberAgreement";
164
+ params: import("xstate").NonReducibleUnknown;
165
+ } | {
166
+ type: "rememberWrittenChanges";
167
+ params: import("xstate").NonReducibleUnknown;
168
+ } | {
169
+ type: "rememberCommittedChanges";
170
+ params: import("xstate").NonReducibleUnknown;
171
+ } | {
172
+ type: "rememberReviewFindings";
173
+ params: import("xstate").NonReducibleUnknown;
174
+ } | {
175
+ type: "rememberHostReviewResponse";
176
+ params: import("xstate").NonReducibleUnknown;
177
+ } | {
178
+ type: "rememberParticipantRebuttalResponse";
179
+ params: import("xstate").NonReducibleUnknown;
180
+ } | {
181
+ type: "rememberCaptainResult";
182
+ params: import("xstate").NonReducibleUnknown;
183
+ } | {
184
+ type: "rememberCaptainError";
185
+ params: import("xstate").NonReducibleUnknown;
186
+ } | {
187
+ type: "rememberMalformedCaptainOutput";
188
+ params: import("xstate").NonReducibleUnknown;
189
+ } | {
190
+ type: "rememberMalformedBossReply";
191
+ params: import("xstate").NonReducibleUnknown;
192
+ } | {
193
+ type: "setPendingBossQuestion";
194
+ params: PendingBossQuestionParams;
195
+ } | {
196
+ type: "rememberBossReply";
197
+ params: import("xstate").NonReducibleUnknown;
198
+ } | {
199
+ type: "clearBranchBossReplyContext";
200
+ params: {
201
+ stateId: ResumableStateId;
202
+ };
203
+ } | {
204
+ type: "clearParallelRoundContext";
205
+ params: import("xstate").NonReducibleUnknown;
206
+ } | {
207
+ type: "clearBossReplyContext";
208
+ params: import("xstate").NonReducibleUnknown;
209
+ } | {
210
+ type: "stageHostResult";
211
+ params: import("xstate").NonReducibleUnknown;
212
+ } | {
213
+ type: "stageParticipantResult";
214
+ params: import("xstate").NonReducibleUnknown;
215
+ } | {
216
+ type: "promoteInitialResults";
217
+ params: import("xstate").NonReducibleUnknown;
218
+ } | {
219
+ type: "promoteReconciliationResults";
220
+ params: import("xstate").NonReducibleUnknown;
221
+ }, {
222
+ type: "noFindings";
223
+ params: unknown;
224
+ } | {
225
+ type: "committed";
226
+ params: unknown;
227
+ } | {
228
+ type: "proposalMade";
229
+ params: unknown;
230
+ } | {
231
+ type: "endedInitialDiscussion";
232
+ params: unknown;
233
+ } | {
234
+ type: "wroteChanges";
235
+ params: unknown;
236
+ } | {
237
+ type: "findingsRaised";
238
+ params: unknown;
239
+ } | {
240
+ type: "changesMade";
241
+ params: unknown;
242
+ } | {
243
+ type: "rebuttalsRaised";
244
+ params: unknown;
245
+ } | {
246
+ type: "rebuttalsAddressed";
247
+ params: unknown;
248
+ } | {
249
+ type: "needsBossReplyWithQuestion";
250
+ params: unknown;
251
+ } | {
252
+ type: "needsBossReplyWithoutQuestion";
253
+ params: unknown;
254
+ } | {
255
+ type: "emptyBossReply";
256
+ params: unknown;
257
+ } | {
258
+ type: "bothEndedInitialDiscussion";
259
+ params: unknown;
260
+ } | {
261
+ type: "specReview";
262
+ params: unknown;
263
+ } | {
264
+ type: "drReview";
265
+ params: unknown;
266
+ } | {
267
+ type: "mixedReview";
268
+ params: unknown;
269
+ }, never, "done" | "failed" | "ready" | "awaitBossReply" | "hostWritesAgreement" | "commitInitialChanges" | "reviewSpecInitialCommit" | "reviewSpecHostChanges" | "reviewDrInitialCommit" | "reviewDrHostChanges" | "reviewMixedInitialCommit" | "reviewMixedHostChanges" | "hostAddressesFindings" | "participantAddressesRebuttals" | "commitReviewedChanges" | {
270
+ initialProposalRound: {
271
+ host: "working" | "waiting" | "complete";
272
+ participant: "working" | "waiting" | "complete";
273
+ };
274
+ } | {
275
+ reconciliationRound: {
276
+ host: "working" | "waiting" | "complete";
277
+ participant: "working" | "waiting" | "complete";
278
+ };
279
+ }, string, DiscussInput, import("xstate").NonReducibleUnknown, import("xstate").EventObject, import("xstate").MetaObject, {
280
+ id: "discuss";
281
+ states: {
282
+ readonly ready: {
283
+ id: "ready";
284
+ };
285
+ readonly initialProposalRound: {
286
+ id: "initialProposalRound";
287
+ states: {
288
+ readonly host: {
289
+ id: "initialProposalHost";
290
+ states: {
291
+ readonly working: {
292
+ id: "askHostInitial";
293
+ };
294
+ readonly waiting: {
295
+ id: "waitHostInitialReply";
296
+ };
297
+ readonly complete: {
298
+ id: "hostInitialProposalComplete";
299
+ };
300
+ };
301
+ };
302
+ readonly participant: {
303
+ id: "initialProposalParticipant";
304
+ states: {
305
+ readonly working: {
306
+ id: "askParticipantInitial";
307
+ };
308
+ readonly waiting: {
309
+ id: "waitParticipantInitialReply";
310
+ };
311
+ readonly complete: {
312
+ id: "participantInitialProposalComplete";
313
+ };
314
+ };
315
+ };
316
+ };
317
+ };
318
+ readonly reconciliationRound: {
319
+ id: "reconciliationRound";
320
+ states: {
321
+ readonly host: {
322
+ id: "reconciliationHost";
323
+ states: {
324
+ readonly working: {
325
+ id: "hostInitialRound";
326
+ };
327
+ readonly waiting: {
328
+ id: "waitHostReconciliationReply";
329
+ };
330
+ readonly complete: {
331
+ id: "hostReconciliationComplete";
332
+ };
333
+ };
334
+ };
335
+ readonly participant: {
336
+ id: "reconciliationParticipant";
337
+ states: {
338
+ readonly working: {
339
+ id: "participantInitialRound";
340
+ };
341
+ readonly waiting: {
342
+ id: "waitParticipantReconciliationReply";
343
+ };
344
+ readonly complete: {
345
+ id: "participantReconciliationComplete";
346
+ };
347
+ };
348
+ };
349
+ };
350
+ };
351
+ readonly hostWritesAgreement: {
352
+ id: "hostWritesAgreement";
353
+ };
354
+ readonly commitInitialChanges: {
355
+ id: "commitInitialChanges";
356
+ };
357
+ readonly reviewSpecInitialCommit: {
358
+ id: "reviewSpecInitialCommit";
359
+ };
360
+ readonly reviewSpecHostChanges: {
361
+ id: "reviewSpecHostChanges";
362
+ };
363
+ readonly reviewDrInitialCommit: {
364
+ id: "reviewDrInitialCommit";
365
+ };
366
+ readonly reviewDrHostChanges: {
367
+ id: "reviewDrHostChanges";
368
+ };
369
+ readonly reviewMixedInitialCommit: {
370
+ id: "reviewMixedInitialCommit";
371
+ };
372
+ readonly reviewMixedHostChanges: {
373
+ id: "reviewMixedHostChanges";
374
+ };
375
+ readonly hostAddressesFindings: {
376
+ id: "hostAddressesFindings";
377
+ };
378
+ readonly participantAddressesRebuttals: {
379
+ id: "participantAddressesRebuttals";
380
+ };
381
+ readonly commitReviewedChanges: {
382
+ id: "commitReviewedChanges";
383
+ };
384
+ readonly awaitBossReply: {
385
+ id: "awaitBossReply";
386
+ };
387
+ readonly failed: {
388
+ id: "failed";
389
+ };
390
+ readonly done: {
391
+ id: "done";
392
+ };
393
+ };
394
+ }>;
395
+ export { bossInterrupts, resumableStates };
396
+ export default discussMachine;