@sublang/playbook 4.0.0 → 6.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 (73) hide show
  1. package/README.md +69 -122
  2. package/docs/assets/playbook-venn.svg +13 -0
  3. package/docs/cli.md +43 -26
  4. package/docs/configuration.md +63 -18
  5. package/docs/embedding.md +24 -16
  6. package/package.json +43 -22
  7. package/reference/sdlc/captain.md +70 -83
  8. package/reference/sdlc/captain.playbook/captain.fsm.d.ts +127 -142
  9. package/reference/sdlc/captain.playbook/captain.fsm.js +349 -470
  10. package/reference/sdlc/captain.playbook/captain.fsm.ts +535 -598
  11. package/reference/sdlc/captain.playbook/captain.gears.md +37 -41
  12. package/reference/sdlc/captain.playbook/captain.playbook.d.ts +90 -15
  13. package/reference/sdlc/captain.playbook/captain.playbook.js +466 -976
  14. package/reference/sdlc/captain.playbook/captain.playbook.ts +698 -1001
  15. package/reference/sdlc/code.md +55 -97
  16. package/reference/sdlc/code.playbook/code.fsm.d.ts +229 -94
  17. package/reference/sdlc/code.playbook/code.fsm.introspect.d.ts +26 -44
  18. package/reference/sdlc/code.playbook/code.fsm.introspect.js +61 -66
  19. package/reference/sdlc/code.playbook/code.fsm.introspect.ts +100 -149
  20. package/reference/sdlc/code.playbook/code.fsm.js +587 -1347
  21. package/reference/sdlc/code.playbook/code.fsm.ts +809 -1650
  22. package/reference/sdlc/code.playbook/code.gears.md +51 -263
  23. package/reference/sdlc/code.playbook/code.playbook.d.ts +8 -47
  24. package/reference/sdlc/code.playbook/code.playbook.js +69 -639
  25. package/reference/sdlc/code.playbook/code.playbook.ts +90 -850
  26. package/reference/sdlc/code.playbook/code.registry.d.ts +9 -25
  27. package/reference/sdlc/code.playbook/code.registry.js +20 -78
  28. package/reference/sdlc/code.playbook/code.registry.ts +58 -122
  29. package/reference/sdlc/code.playbook/playbook-captain.d.ts +2 -0
  30. package/reference/sdlc/code.playbook/playbook-captain.js +1877 -251
  31. package/reference/sdlc/code.playbook/playbook-captain.ts +2385 -352
  32. package/reference/sdlc/code.playbook/playbook.config.template.yaml +33 -22
  33. package/reference/sdlc/decide.md +54 -0
  34. package/reference/sdlc/decide.playbook/decide.fsm.d.ts +261 -0
  35. package/reference/sdlc/decide.playbook/decide.fsm.js +894 -0
  36. package/reference/sdlc/decide.playbook/decide.fsm.ts +1152 -0
  37. package/reference/sdlc/decide.playbook/decide.gears.md +88 -0
  38. package/reference/sdlc/decide.playbook/decide.playbook.d.ts +67 -0
  39. package/reference/sdlc/{discuss.playbook/discuss.playbook.js → decide.playbook/decide.playbook.js} +511 -370
  40. package/reference/sdlc/{discuss.playbook/discuss.playbook.ts → decide.playbook/decide.playbook.ts} +616 -451
  41. package/reference/sdlc/decide.playbook/decide.registry.d.ts +41 -0
  42. package/reference/sdlc/decide.playbook/decide.registry.js +60 -0
  43. package/reference/sdlc/decide.playbook/decide.registry.ts +125 -0
  44. package/reference/sdlc/review.md +81 -0
  45. package/reference/sdlc/review.playbook/review.fsm.d.ts +183 -0
  46. package/reference/sdlc/review.playbook/review.fsm.js +524 -0
  47. package/reference/sdlc/review.playbook/review.fsm.ts +652 -0
  48. package/reference/sdlc/review.playbook/review.gears.md +112 -0
  49. package/reference/sdlc/review.playbook/review.playbook.d.ts +12 -0
  50. package/reference/sdlc/review.playbook/review.playbook.js +112 -0
  51. package/reference/sdlc/review.playbook/review.playbook.ts +201 -0
  52. package/reference/sdlc/review.playbook/review.registry.d.ts +43 -0
  53. package/reference/sdlc/review.playbook/review.registry.js +73 -0
  54. package/reference/sdlc/review.playbook/review.registry.ts +138 -0
  55. package/slc/gears2fsm.md +67 -6
  56. package/slc/link.md +339 -25
  57. package/slc/text2gears.md +22 -2
  58. package/src/runtime.d.ts +36 -1
  59. package/src/runtime.ts +59 -0
  60. package/src/xstate-playbook-runtime.d.ts +96 -7
  61. package/src/xstate-playbook-runtime.js +1018 -49
  62. package/src/xstate-playbook-runtime.ts +1283 -59
  63. package/src/xstate-runtime.js +25 -0
  64. package/src/xstate-runtime.ts +51 -0
  65. package/reference/sdlc/discuss.md +0 -93
  66. package/reference/sdlc/discuss.playbook/discuss.fsm.d.ts +0 -396
  67. package/reference/sdlc/discuss.playbook/discuss.fsm.js +0 -2067
  68. package/reference/sdlc/discuss.playbook/discuss.fsm.ts +0 -2465
  69. package/reference/sdlc/discuss.playbook/discuss.gears.md +0 -258
  70. package/reference/sdlc/discuss.playbook/discuss.playbook.d.ts +0 -113
  71. package/reference/sdlc/discuss.playbook/discuss.registry.d.ts +0 -58
  72. package/reference/sdlc/discuss.playbook/discuss.registry.js +0 -97
  73. package/reference/sdlc/discuss.playbook/discuss.registry.ts +0 -153
@@ -20,7 +20,7 @@
20
20
  # Every seeded agent runs in cligent's protected auto mode
21
21
  # (permissions.mode: auto): claude maps it to permissionMode auto, codex to
22
22
  # on-request + auto_review. Codex roles also grant writablePaths: ['.git']
23
- # so commit turns can write git metadata under the codex sandbox.
23
+ # so they can inspect and work with repository metadata under the sandbox.
24
24
 
25
25
  # The Captain/Judge agent.
26
26
  # Captain routing/adjudication calls run tool-free. Claude enforces that at
@@ -40,11 +40,25 @@ notifications:
40
40
 
41
41
  # Enabled playbooks. Each is loaded from its explicit `from` module; the
42
42
  # `<id>` key must equal that module's manifest id. `from`, `command`, and
43
- # `players` are launcher-owned; every other key (e.g. CODE's `committer`)
44
- # is that playbook's option slice.
43
+ # `players` are launcher-owned; every other key is that playbook's option
44
+ # slice.
45
+ #
46
+ # Nested calls map roles by exact id. CODE and DECIDE call REVIEW with the
47
+ # same `coder` and `reviewer` ids, so those child roles continue the nearest
48
+ # ancestor sessions. A standalone REVIEW uses its own bindings below.
45
49
  playbooks:
46
50
  code:
47
51
  from: "@sublang/playbook/code/registry"
52
+ players:
53
+ coder:
54
+ adapter: claude
55
+ model: claude-opus-4-8[1m]
56
+ effort: xhigh
57
+ permissions:
58
+ mode: auto
59
+
60
+ review:
61
+ from: "@sublang/playbook/review/registry"
48
62
  players:
49
63
  coder:
50
64
  adapter: claude
@@ -59,26 +73,23 @@ playbooks:
59
73
  permissions:
60
74
  mode: auto
61
75
  writablePaths: ['.git']
62
- committer: coder
63
76
 
64
- # The DISCUSS playbook: two agents converge on spec items or decision
65
- # records. `committer` picks which player runs Committer commits
66
- # (default: host).
67
- # discuss:
68
- # from: "@sublang/playbook/discuss/registry"
69
- # players:
70
- # host:
71
- # adapter: claude
72
- # model: claude-opus-4-8
73
- # permissions:
74
- # mode: auto
75
- # participant:
76
- # adapter: codex
77
- # model: gpt-5.5
78
- # permissions:
79
- # mode: auto
80
- # writablePaths: ['.git']
81
- # committer: host
77
+ decide:
78
+ 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: ['.git']
82
93
 
83
94
  # Non-interactive `playbook run` defaults (optional). Each value is an
84
95
  # agent string <adapter>[:<model>][@<effort>]; `player` is the catch-all
@@ -0,0 +1,54 @@
1
+ <!-- SPDX-License-Identifier: Apache-2.0 -->
2
+ <!-- SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai> -->
3
+ <!-- AI agents: do not edit this file without human approval. -->
4
+
5
+ # Decide
6
+
7
+ Players:
8
+
9
+ - Coder
10
+ - Reviewer
11
+
12
+ The caller supplies the topic including any specific context.
13
+
14
+ When the caller gives a topic, Captain shall relay the complete topic in quotes (`>`) to Coder and Reviewer concurrently and independently.
15
+ Captain shall not wait for either proposal before requesting the other.
16
+ Captain shall give each player the following instruction:
17
+
18
+ ```markdown
19
+ Assess whether the topic is better expressed as a few spec items under @specs/packages/ or requires one or more DRs under @specs/decisions/.
20
+ Propose your design.
21
+ Keep your proposal coherent, focused, and concise.
22
+ Consult @specs/map.md for relevant context and @specs/meta.md for spec requirements, if needed.
23
+ Do not change any files.
24
+ ```
25
+
26
+ Neither player shall receive the other's proposal until both proposals are complete and Coder has committed Coder's own proposal.
27
+ A Boss interrupt during the parallel proposal pair shall restart the whole pair so both players receive the same new topic and remain independent.
28
+
29
+ When both proposals are complete, Captain shall then give Coder the following instruction:
30
+
31
+ ```markdown
32
+ Turn your proposal into the necessary spec items or DRs.
33
+ Follow @specs/meta.md and update @specs/map.md when needed.
34
+ Do not inspect or incorporate Reviewer's proposal before this commit.
35
+ Do not change code or implement the proposal.
36
+
37
+ Commit the result as one new commit, following @specs/packages/git.md.
38
+ Make the commit message explain concisely what changed and why.
39
+ Report it as exactly one final-response line beginning `Commit: `, followed only by the exact commit identity.
40
+ Coder is <coder-llm>; format the model token in conventional human form.
41
+ ```
42
+
43
+ After Coder commits, Captain shall call playbook `review`:
44
+
45
+ > Review the latest commit as a spec-design change against the initial intent.
46
+ > Compare it with your independent proposal and take the best of both.
47
+ > Make your suggestions.
48
+ >
49
+ > Initial intent: \<caller-topic\>.
50
+ > Coder's independent proposal: \<coder-proposal\>.
51
+
52
+ `decide` is complete when `review` returns the approved latest commit and the fact that no unsettled findings remain.
53
+ When `review` returns an authored abort or failure, or a terminal result that does not prove exact approval, `decide` shall report the failure and the last `decide`-owned commit to its caller.
54
+ When the nested `review` call fails outside that authored result contract, `decide` shall park as failed and retain the control-plane error instead of reporting an authored review outcome.
@@ -0,0 +1,261 @@
1
+ export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
2
+ readonly [key: string]: JsonValue;
3
+ };
4
+ type Player = 'Coder' | 'Reviewer';
5
+ type JumpableStateId = 'independentProposals';
6
+ type ResumableStateId = 'askCoderProposal' | 'askReviewerProposal' | 'commitCoderProposal';
7
+ export interface PendingBossQuestion {
8
+ questionId: ResumableStateId;
9
+ resumeStateId: ResumableStateId;
10
+ sourceItem: string;
11
+ player: Player;
12
+ question: string;
13
+ }
14
+ type PendingBossQuestions = Partial<Record<ResumableStateId, PendingBossQuestion>>;
15
+ type BossReplies = Partial<Record<ResumableStateId, string>>;
16
+ type PendingBossQuestionParams = Omit<PendingBossQuestion, 'questionId'>;
17
+ export interface ReviewSuccessOutput {
18
+ approvedCommit: 'latest';
19
+ noUnsettledFindings: true;
20
+ }
21
+ export interface DecideFailureOutput {
22
+ lastDecideCommit: string;
23
+ noUnsettledFindings: false;
24
+ reviewStatus: 'aborted' | 'error';
25
+ error?: {
26
+ name: string;
27
+ message: string;
28
+ };
29
+ }
30
+ export type DecideOutput = ReviewSuccessOutput | DecideFailureOutput;
31
+ interface ChildFailure {
32
+ status: 'aborted' | 'error';
33
+ playbookId: 'review';
34
+ error?: {
35
+ name: string;
36
+ message: string;
37
+ };
38
+ }
39
+ export interface DecideContext {
40
+ coderLlm: string;
41
+ callerTopic?: string;
42
+ coderProposal?: string;
43
+ reviewerProposal?: string;
44
+ latestCommit?: string;
45
+ reviewResult?: ReviewSuccessOutput;
46
+ reviewFailure?: ChildFailure;
47
+ lastResult?: PlayerOutput;
48
+ lastError?: unknown;
49
+ pendingBossQuestions?: PendingBossQuestions;
50
+ bossReplies?: BossReplies;
51
+ stagedCoderResult?: PlayerOutput;
52
+ stagedReviewerResult?: PlayerOutput;
53
+ }
54
+ export type DecideEvent = {
55
+ type: 'START_DECIDE';
56
+ callerTopic: string;
57
+ } | {
58
+ type: 'BOSS_INTERRUPT';
59
+ targetId: JumpableStateId;
60
+ bossIntent: string;
61
+ } | {
62
+ type: 'BOSS_REPLY';
63
+ questionId?: ResumableStateId;
64
+ answer: string;
65
+ };
66
+ export interface DecideInput {
67
+ coderLlm: string;
68
+ }
69
+ export interface PlayerInput {
70
+ stateId: ResumableStateId;
71
+ sourceItem: string;
72
+ prompt: string;
73
+ result: Record<string, string>;
74
+ player: Player;
75
+ callerTopic?: string;
76
+ coderLlm?: string;
77
+ pendingBossQuestion?: PendingBossQuestion;
78
+ bossReply?: string;
79
+ }
80
+ type AdditionalPlayerFields = {
81
+ coderProposal?: string;
82
+ reviewerProposal?: string;
83
+ coderOutput?: string;
84
+ latestCommit?: string;
85
+ question?: string;
86
+ readonly [key: string]: unknown;
87
+ };
88
+ export type PlayerOutput = ({
89
+ guard: 'proposed';
90
+ coderProposal: string;
91
+ } & AdditionalPlayerFields) | ({
92
+ guard: 'proposed';
93
+ reviewerProposal: string;
94
+ } & AdditionalPlayerFields) | ({
95
+ guard: 'committed';
96
+ coderOutput: string;
97
+ latestCommit: string;
98
+ } & AdditionalPlayerFields) | ({
99
+ guard: 'needsBossReply';
100
+ question: string;
101
+ } & AdditionalPlayerFields);
102
+ export interface PlaybookInput {
103
+ stateId: 'reviewCommit';
104
+ sourceItem: 'DECIDE-4';
105
+ playbookId: 'review';
106
+ text: string;
107
+ }
108
+ export declare const decideMachine: import("xstate").StateMachine<DecideContext, {
109
+ type: "START_DECIDE";
110
+ callerTopic: string;
111
+ } | {
112
+ type: "BOSS_INTERRUPT";
113
+ targetId: JumpableStateId;
114
+ bossIntent: string;
115
+ } | {
116
+ type: "BOSS_REPLY";
117
+ questionId?: ResumableStateId;
118
+ answer: string;
119
+ }, {
120
+ [x: string]: import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<JsonValue | undefined, PlaybookInput, import("xstate").EventObject>> | import("xstate").ActorRefFromLogic<import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>> | undefined;
121
+ }, {
122
+ src: "playbook";
123
+ logic: import("xstate").PromiseActorLogic<JsonValue | undefined, PlaybookInput, import("xstate").EventObject>;
124
+ id: string | undefined;
125
+ } | {
126
+ src: "player";
127
+ logic: import("xstate").PromiseActorLogic<PlayerOutput, PlayerInput, import("xstate").EventObject>;
128
+ id: string | undefined;
129
+ }, {
130
+ type: "rememberActorError";
131
+ params: import("xstate").NonReducibleUnknown;
132
+ } | {
133
+ type: "rememberBossReply";
134
+ params: import("xstate").NonReducibleUnknown;
135
+ } | {
136
+ type: "clearBossReplyContext";
137
+ params: import("xstate").NonReducibleUnknown;
138
+ } | {
139
+ type: "copyInterruptedTopic";
140
+ params: import("xstate").NonReducibleUnknown;
141
+ } | {
142
+ type: "copyStartTopic";
143
+ params: import("xstate").NonReducibleUnknown;
144
+ } | {
145
+ type: "stageCoderProposal";
146
+ params: import("xstate").NonReducibleUnknown;
147
+ } | {
148
+ type: "stageReviewerProposal";
149
+ params: import("xstate").NonReducibleUnknown;
150
+ } | {
151
+ type: "promoteProposals";
152
+ params: import("xstate").NonReducibleUnknown;
153
+ } | {
154
+ type: "rememberCommit";
155
+ params: import("xstate").NonReducibleUnknown;
156
+ } | {
157
+ type: "rememberReviewSuccess";
158
+ params: import("xstate").NonReducibleUnknown;
159
+ } | {
160
+ type: "rememberReviewFailure";
161
+ params: import("xstate").NonReducibleUnknown;
162
+ } | {
163
+ type: "rememberReviewProtocolFailure";
164
+ params: import("xstate").NonReducibleUnknown;
165
+ } | {
166
+ type: "rememberMalformedActorOutput";
167
+ params: import("xstate").NonReducibleUnknown;
168
+ } | {
169
+ type: "rememberMalformedBossReply";
170
+ params: import("xstate").NonReducibleUnknown;
171
+ } | {
172
+ type: "setPendingBossQuestion";
173
+ params: PendingBossQuestionParams;
174
+ } | {
175
+ type: "clearBranchBossReplyContext";
176
+ params: {
177
+ stateId: ResumableStateId;
178
+ };
179
+ } | {
180
+ type: "clearProposalRoundContext";
181
+ params: import("xstate").NonReducibleUnknown;
182
+ }, {
183
+ type: "authoredReviewFailure";
184
+ params: unknown;
185
+ } | {
186
+ type: "committed";
187
+ params: unknown;
188
+ } | {
189
+ type: "coderProposed";
190
+ params: unknown;
191
+ } | {
192
+ type: "reviewerProposed";
193
+ params: unknown;
194
+ } | {
195
+ type: "needsBossReplyWithQuestion";
196
+ params: unknown;
197
+ } | {
198
+ type: "needsBossReplyWithoutQuestion";
199
+ params: unknown;
200
+ } | {
201
+ type: "validReviewSuccess";
202
+ params: unknown;
203
+ }, never, "done" | "failed" | "awaitBossReply" | "ready" | "commitCoderProposal" | "reviewCommit" | "reportedReviewFailure" | {
204
+ independentProposals: {
205
+ coder: "complete" | "working" | "waiting";
206
+ reviewer: "complete" | "working" | "waiting";
207
+ };
208
+ }, string, DecideInput, ReviewSuccessOutput | DecideFailureOutput, import("xstate").EventObject, import("xstate").MetaObject, {
209
+ id: "decide";
210
+ states: {
211
+ readonly ready: {
212
+ id: "ready";
213
+ };
214
+ readonly independentProposals: {
215
+ id: "independentProposals";
216
+ states: {
217
+ readonly coder: {
218
+ states: {
219
+ readonly working: {
220
+ id: "askCoderProposal";
221
+ };
222
+ readonly waiting: {
223
+ id: "waitCoderProposalReply";
224
+ };
225
+ readonly complete: {};
226
+ };
227
+ };
228
+ readonly reviewer: {
229
+ states: {
230
+ readonly working: {
231
+ id: "askReviewerProposal";
232
+ };
233
+ readonly waiting: {
234
+ id: "waitReviewerProposalReply";
235
+ };
236
+ readonly complete: {};
237
+ };
238
+ };
239
+ };
240
+ };
241
+ readonly commitCoderProposal: {
242
+ id: "commitCoderProposal";
243
+ };
244
+ readonly awaitBossReply: {
245
+ id: "awaitBossReply";
246
+ };
247
+ readonly reviewCommit: {
248
+ id: "reviewCommit";
249
+ };
250
+ readonly failed: {
251
+ id: "failed";
252
+ };
253
+ readonly reportedReviewFailure: {
254
+ id: "reportedReviewFailure";
255
+ };
256
+ readonly done: {
257
+ id: "done";
258
+ };
259
+ };
260
+ }>;
261
+ export default decideMachine;