@sublang/playbook 18.0.0 → 18.1.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 CHANGED
@@ -32,8 +32,9 @@ Run `playbook` for an interactive tmux UI powered by [cligent](https://github.co
32
32
  Out of the box, Playbook includes **CODE** for implementation, **REVIEW** for commit-based review and fixes, **DECIDE** for independently proposed and reviewed specification decisions, **DEV** for repository-aware planning of a development request, **BRANCH** for checking out a new branch for a GitHub issue, **PR** for publishing, checking, and merging that branch through a pull request, and **INSPECT** for explaining supplied material or a running interface without changing the repository.
33
33
  CODE and DECIDE call REVIEW as a nested playbook; DEV calls CODE, or DECIDE and then CODE, and wraps them in BRANCH and PR when the request names a GitHub issue or asks for a pull request.
34
34
 
35
- The shared starter config selects one adapter for the Captain and all players
36
- from locally visible credentials: Claude first, then Codex. If neither is
35
+ The shared starter config selects the Captain's and players' adapter from
36
+ locally visible credentials: Claude first, then Codex, and where both are
37
+ configured only `dev.reviewer` seeds on Codex. If neither is
37
38
  configured, it seeds Claude and prints a notice. CODE, REVIEW, DECIDE, BRANCH, and PR bind
38
39
  their local roles explicitly to `dev.coder` and `dev.reviewer`, so nested and later
39
40
  engagements share a conversation only where their bindings name the same
@@ -51,7 +52,7 @@ If an SDK is missing or older than cligent supports, Playbook prints the pinned
51
52
  Prerequisites:
52
53
 
53
54
  - Node.js >= 20.6.0
54
- - Credentials for the configured adapter: authenticated [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) or `ANTHROPIC_API_KEY` for Claude; authenticated [Codex CLI](https://github.com/openai/codex) or `OPENAI_API_KEY` for Codex
55
+ - Credentials for the configured adapter: authenticated [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) or `ANTHROPIC_API_KEY` / `CLAUDE_CODE_OAUTH_TOKEN` for Claude; authenticated [Codex CLI](https://github.com/openai/codex) or `OPENAI_API_KEY` / `CODEX_ACCESS_TOKEN` for Codex
55
56
  - [GitHub CLI](https://cli.github.com/) (`gh`) authenticated for the repository's GitHub remote, for `/branch`, `/pr`, and `/dev` requests that name an issue or ask for a pull request
56
57
 
57
58
  Interactive `playbook` additionally needs tmux 3.3 or newer and [`glow`](https://github.com/charmbracelet/glow#installation) on `PATH`; headless `playbook run` does not.
@@ -64,16 +64,23 @@ one; see [Modules supplied at launch](#modules-supplied-at-launch). Every
64
64
  manifest role must be present exactly once. The launcher injects the rest — you do not write host wiring by
65
65
  hand.
66
66
 
67
- The launcher seeds one adapter for the Captain and all stable players from
68
- locally visible credentials: Claude first, then Codex. It uses Claude Opus 5.5
69
- for Claude or GPT-6 Sol for Codex, with Captain and Coder at `high` effort
70
- and Reviewer and Analyst at `xhigh`. If neither adapter is configured, it
71
- seeds Claude and prints a notice. Credentials do not prove SDK availability
72
- or remaining quota; launch still checks the configured adapter. Existing
73
- configs are left unchanged.
67
+ The launcher seeds the Captain and all stable players from locally visible
68
+ credentials (an API key in the environment, or `~/.claude` / `~/.codex`):
74
69
 
75
- The Claude default is shown below. A Codex seed also adds
76
- `permissions.writablePaths: ['.git']` to each agent:
70
+ | Credentials | Seeded agents |
71
+ | --- | --- |
72
+ | Claude only, or neither | every agent on Claude Opus 5.5 (with a notice when neither is configured) |
73
+ | Codex only | every agent on GPT-6 Sol |
74
+ | both | `dev.reviewer` on GPT-6 Sol, every other agent on Claude Opus 5.5 |
75
+
76
+ Captain, Coder, and Inspector run at `high` effort and Reviewer and Analyst at
77
+ `xhigh`. Credentials do not prove SDK availability or remaining quota; launch
78
+ still checks the configured adapter. Existing configs are left unchanged.
79
+ Embedding hosts seed the same agent settings through
80
+ `seedConfigText({ env, homeDir })` from `@sublang/playbook/seed-config`.
81
+
82
+ The Claude default is shown below. Each Codex agent also carries
83
+ `permissions.writablePaths: ['.git']`:
77
84
 
78
85
  ```yaml
79
86
  captain:
@@ -273,9 +280,12 @@ It may not finish the specialist’s task or invent a decision; discarding work
273
280
  Preparation has a 150-second limit.
274
281
 
275
282
  Adapter readiness is intentionally light: `claude` is ready with local
276
- Claude Code auth or `ANTHROPIC_API_KEY`; `codex` with local Codex CLI
277
- auth or `OPENAI_API_KEY`. A known adapter that is not ready blocks the
278
- launch and prints the help text.
283
+ Claude Code auth, `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, or
284
+ `CLAUDE_CODE_OAUTH_TOKEN`; `codex` with local Codex CLI auth,
285
+ `OPENAI_API_KEY`, `CODEX_API_KEY`, or `CODEX_ACCESS_TOKEN`. Only presence
286
+ counts; no token is checked. A known adapter that is not ready blocks the
287
+ launch and prints the help text. The same check picks the starter config's
288
+ lineup.
279
289
 
280
290
  ## Skills across agents
281
291
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sublang/playbook",
3
- "version": "18.0.0",
3
+ "version": "18.1.0",
4
4
  "type": "module",
5
5
  "description": "Composable XState v5 playbook runtime with compiled Captain, CODE, REVIEW, DECIDE, DEV, BRANCH, PR, and INSPECT workflows driven by GEARS specs.",
6
6
  "license": "Apache-2.0",
@@ -83,6 +83,8 @@
83
83
  "reference/sdlc/code.playbook/host-capabilities.d.ts",
84
84
  "reference/sdlc/code.playbook/machine-identity.js",
85
85
  "reference/sdlc/code.playbook/machine-identity.d.ts",
86
+ "reference/sdlc/code.playbook/seed-config.js",
87
+ "reference/sdlc/code.playbook/seed-config.d.ts",
86
88
  "reference/sdlc/code.playbook/code.gears.md",
87
89
  "reference/sdlc/code.playbook/playbook.config.template.yaml",
88
90
  "reference/sdlc/code.playbook/bin/playbook.js",
@@ -212,6 +214,10 @@
212
214
  "types": "./reference/sdlc/code.playbook/machine-identity.d.ts",
213
215
  "default": "./reference/sdlc/code.playbook/machine-identity.js"
214
216
  },
217
+ "./seed-config": {
218
+ "types": "./reference/sdlc/code.playbook/seed-config.d.ts",
219
+ "default": "./reference/sdlc/code.playbook/seed-config.js"
220
+ },
215
221
  "./slc/*": "./slc/*",
216
222
  "./review/playbook": {
217
223
  "types": "./reference/sdlc/review.playbook/review.playbook.d.ts",
@@ -276,6 +282,7 @@
276
282
  "test:acceptance": "node scripts/run-live-acceptance.mjs",
277
283
  "smoke:release": "node scripts/release-smoke.mjs",
278
284
  "check:links": "node scripts/check-links.mjs",
285
+ "prepush": "bash scripts/prepush.sh",
279
286
  "playbook": "node reference/sdlc/code.playbook/bin/playbook.js"
280
287
  },
281
288
  "publishConfig": {
@@ -283,7 +290,7 @@
283
290
  "provenance": true
284
291
  },
285
292
  "dependencies": {
286
- "@sublang/cligent": "^0.36.0",
293
+ "@sublang/cligent": "^0.36.1",
287
294
  "@sublang/spex": "^3.0.0",
288
295
  "p-queue": "^9.3.1",
289
296
  "xstate": "^5.19.4",
@@ -10,14 +10,14 @@ Roles:
10
10
 
11
11
  The caller supplies a coding request together with any relevant context.
12
12
 
13
- A new coding intent follows either one direct implementation phase or an IR sequence consisting of a new-IR phase followed by one phase for each IR task.
13
+ A new change intent, including standalone documentation or status maintenance that does not implement an identified unfinished IR task, follows either one direct implementation phase or an IR sequence consisting of a new-IR phase followed by one phase for each IR task.
14
14
  An existing IR follows one IR-task phase for each remaining unfinished task, starting with its next unfinished task.
15
15
  Each completed phase ends with one new Coder commit (owned by `code`).
16
16
  After each `code`-owned commit, Captain shall call the `review` playbook and wait until it passes with no unsettled findings.
17
17
  Playbook `review` owns every review round and every review-fix commit.
18
18
  Do not rewrite any existing commit.
19
19
 
20
- When `review` passes a direct implementation phase, `code` is complete.
20
+ When `review` passes a direct phase, `code` is complete.
21
21
  When `review` passes a new IR or a nonfinal IR-task phase, Captain shall continue with the next unfinished IR-task phase.
22
22
  When `review` passes the final IR-task phase, `code` is complete.
23
23
  When `review` returns an authored abort or failure, or a terminal result that does not establish that the supplied scope was evaluated with no unsettled findings, `code` shall start no further phase and shall report the failure and the last `code`-owned commit to its caller.
@@ -29,15 +29,18 @@ At the start of the first phase, Captain shall relay to Coder the complete calle
29
29
  > Run results: <run-results>
30
30
 
31
31
  ```markdown
32
- First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.
32
+ First determine whether the request starts a new change intent or continues an existing IR with unfinished work.
33
33
  If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.
34
34
 
35
- For a new coding intent, assess whether it can be completed well in one commit.
35
+ Treat standalone documentation or status maintenance that does not implement an identified unfinished IR task as a new change intent, even when it refers to an IR with no unfinished task.
36
+ Do not invent or reopen an IR task, claim unperformed work complete, or infer an owner decision not supplied by the caller.
37
+
38
+ For a new change intent, assess whether it can be completed well in one commit.
36
39
  If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
37
40
  If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.
38
41
  Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.
39
42
 
40
- For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
43
+ For an existing IR with unfinished work, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
41
44
  Do not implement a later task in this phase.
42
45
  Mark the IR's progress and deliverables when relevant.
43
46
  After implementing an IR task, identify it and state whether any IR task still has unfinished Coder work; if so identify the next unfinished task, otherwise state this was the final IR task's Coder work.
@@ -1438,23 +1438,36 @@ export function adaptersFromComposedConfig(config) {
1438
1438
  return [...adapters];
1439
1439
  }
1440
1440
 
1441
+ // DR-097: each agent's documented environment forms, any one of which, or the
1442
+ // agent's sign-in folder, counts it as ready. No value is read.
1443
+ const CREDENTIAL_FORMS = {
1444
+ claude: {
1445
+ names: ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "CLAUDE_CODE_OAUTH_TOKEN"],
1446
+ folder: ".claude",
1447
+ },
1448
+ codex: {
1449
+ names: ["OPENAI_API_KEY", "CODEX_API_KEY", "CODEX_ACCESS_TOKEN"],
1450
+ folder: ".codex",
1451
+ },
1452
+ };
1453
+
1441
1454
  export function checkReadiness(adapters, env = process.env, home = homedir()) {
1442
1455
  const failingAdapters = [];
1443
1456
  const unknownAdapters = [];
1444
1457
  for (const adapter of adapters) {
1445
- if (adapter === "claude") {
1446
- if (!env.ANTHROPIC_API_KEY && !existsSync(join(home, ".claude"))) {
1447
- failingAdapters.push(adapter);
1448
- }
1458
+ const forms = Object.hasOwn(CREDENTIAL_FORMS, adapter)
1459
+ ? CREDENTIAL_FORMS[adapter]
1460
+ : undefined;
1461
+ if (!forms) {
1462
+ unknownAdapters.push(adapter);
1449
1463
  continue;
1450
1464
  }
1451
- if (adapter === "codex") {
1452
- if (!env.OPENAI_API_KEY && !existsSync(join(home, ".codex"))) {
1453
- failingAdapters.push(adapter);
1454
- }
1455
- continue;
1465
+ if (
1466
+ !forms.names.some((name) => env[name]) &&
1467
+ !existsSync(join(home, forms.folder))
1468
+ ) {
1469
+ failingAdapters.push(adapter);
1456
1470
  }
1457
- unknownAdapters.push(adapter);
1458
1471
  }
1459
1472
  return { failingAdapters, unknownAdapters };
1460
1473
  }
@@ -1651,9 +1664,14 @@ const SEED_LINEUP = Object.freeze([
1651
1664
  Object.freeze({ adapter: "codex", model: "gpt-6-sol" }),
1652
1665
  ]);
1653
1666
 
1667
+ // DR-096: where both adapters are ready, this player alone takes the
1668
+ // second row, so review comes from a different provider than the work.
1669
+ const SECOND_ADAPTER_PLAYER = "dev.reviewer";
1670
+
1654
1671
  /**
1655
1672
  * PBCLI-11: the lineup a seed would write here, and whether anything
1656
- * actually probed ready.
1673
+ * actually probed ready. `reviewer` is the row `dev.reviewer` takes;
1674
+ * every other agent takes `lineup`.
1657
1675
  *
1658
1676
  * Only the credential check participates. The SDK probe constructs an
1659
1677
  * adapter and awaits `isAvailable()`, which reads whatever happens to
@@ -1666,7 +1684,12 @@ export function selectSeedLineup(env = process.env, home = homedir()) {
1666
1684
  (entry) =>
1667
1685
  checkReadiness([entry.adapter], env, home).failingAdapters.length === 0,
1668
1686
  );
1669
- return { lineup: ready[0] ?? SEED_LINEUP[0], anyReady: ready.length > 0 };
1687
+ const lineup = ready[0] ?? SEED_LINEUP[0];
1688
+ return {
1689
+ lineup,
1690
+ reviewer: ready.length > 1 ? ready[1] : lineup,
1691
+ anyReady: ready.length > 0,
1692
+ };
1670
1693
  }
1671
1694
 
1672
1695
  /**
@@ -1675,9 +1698,7 @@ export function selectSeedLineup(env = process.env, home = homedir()) {
1675
1698
  * byte copy it always was. A different adapter rewrites the agent
1676
1699
  * scalars in place, which the Document API carries comments through.
1677
1700
  */
1678
- function seedTextForLineup(templatePath, lineup) {
1679
- const template = readFileSync(templatePath, "utf8");
1680
- if (lineup.adapter === SEED_LINEUP[0].adapter) return template;
1701
+ function seedTextForLineup(template, { lineup, reviewer }) {
1681
1702
  const doc = parseYamlDocument(template);
1682
1703
  const players = doc.getIn(["players"]);
1683
1704
  const agentPaths = [
@@ -1687,18 +1708,35 @@ function seedTextForLineup(templatePath, lineup) {
1687
1708
  String(pair.key),
1688
1709
  ]),
1689
1710
  ];
1711
+ let changed = false;
1690
1712
  for (const path of agentPaths) {
1691
- doc.setIn([...path, "adapter"], lineup.adapter);
1692
- doc.setIn([...path, "model"], lineup.model);
1713
+ const entry = path[1] === SECOND_ADAPTER_PLAYER ? reviewer : lineup;
1714
+ if (entry.adapter === SEED_LINEUP[0].adapter) continue;
1715
+ changed = true;
1716
+ doc.setIn([...path, "adapter"], entry.adapter);
1717
+ doc.setIn([...path, "model"], entry.model);
1693
1718
  // A codex agent writes git metadata under its sandbox; claude's
1694
1719
  // auto mode needs no grant, so the key exists for one adapter only.
1695
- if (lineup.adapter === "codex") {
1696
- doc.setIn([...path, "permissions", "writablePaths"], [".git"]);
1697
- } else {
1698
- doc.deleteIn([...path, "permissions", "writablePaths"]);
1699
- }
1720
+ doc.setIn([...path, "permissions", "writablePaths"], [".git"]);
1700
1721
  }
1701
- return String(doc);
1722
+ return changed ? String(doc) : template;
1723
+ }
1724
+
1725
+ /**
1726
+ * PBCLI-100: the starter text a seed writes under this environment and
1727
+ * home. The public `seed-config` facade and the launcher both call it,
1728
+ * so every host seeding through it selects the same agent settings.
1729
+ */
1730
+ export function seedConfigText(
1731
+ templatePath,
1732
+ env = process.env,
1733
+ homeDir = env.HOME ?? homedir(),
1734
+ ) {
1735
+ const selection = selectSeedLineup(env, homeDir);
1736
+ return {
1737
+ text: seedTextForLineup(readFileSync(templatePath, "utf8"), selection),
1738
+ anyReady: selection.anyReady,
1739
+ };
1702
1740
  }
1703
1741
 
1704
1742
  function seedUserConfigIfMissing(
@@ -1710,21 +1748,13 @@ function seedUserConfigIfMissing(
1710
1748
  ) {
1711
1749
  if (existsSync(userConfigPath)) return;
1712
1750
  mkdirSync(dirname(userConfigPath), { recursive: true });
1713
- const { lineup, anyReady } = selectSeedLineup(env, homeDir);
1714
- if (lineup.adapter === SEED_LINEUP[0].adapter && anyReady) {
1715
- // Unchanged default path: one exclusive create of the template bytes.
1716
- copyFileSync(templatePath, userConfigPath, constants.COPYFILE_EXCL);
1717
- } else {
1718
- // Still one exclusive create, so two seeding calls cannot disagree.
1719
- writeFileSync(userConfigPath, seedTextForLineup(templatePath, lineup), {
1720
- encoding: "utf8",
1721
- flag: "wx",
1722
- });
1723
- }
1751
+ const { text, anyReady } = seedConfigText(templatePath, env, homeDir);
1752
+ // One exclusive create, so two seeding calls cannot disagree.
1753
+ writeFileSync(userConfigPath, text, { encoding: "utf8", flag: "wx" });
1724
1754
  onNotice(`playbook: created config at ${userConfigPath}\n`);
1725
1755
  if (!anyReady) {
1726
1756
  onNotice(
1727
- `playbook: no adapter probed ready; seeded ${lineup.adapter}\n`,
1757
+ `playbook: no adapter probed ready; seeded ${SEED_LINEUP[0].adapter}\n`,
1728
1758
  );
1729
1759
  }
1730
1760
  }
@@ -993,9 +993,9 @@ function helpText({
993
993
  "",
994
994
  "Adapter setup:",
995
995
  " claude: npm install -g @anthropic-ai/claude-agent-sdk, then run",
996
- " Claude Code once or set ANTHROPIC_API_KEY.",
996
+ " Claude Code once or set ANTHROPIC_API_KEY (or CLAUDE_CODE_OAUTH_TOKEN).",
997
997
  " codex: npm install -g @openai/codex-sdk, then run Codex CLI once",
998
- " or set OPENAI_API_KEY.",
998
+ " or set OPENAI_API_KEY (or CODEX_API_KEY, CODEX_ACCESS_TOKEN).",
999
999
  " Each SDK is an optional peer dependency, so you install only the",
1000
1000
  " vendors your config actually names.",
1001
1001
  "",
@@ -14,15 +14,18 @@ const REVIEW_PLAYBOOK_ID = 'review';
14
14
  // Prompts and result contracts (verbatim from code.gears.md)
15
15
  // ---------------------------------------------------------------------------
16
16
  const FIRST_PHASE_PROMPT = [
17
- 'First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.',
17
+ 'First determine whether the request starts a new change intent or continues an existing IR with unfinished work.',
18
18
  'If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.',
19
19
  '',
20
- 'For a new coding intent, assess whether it can be completed well in one commit.',
20
+ 'Treat standalone documentation or status maintenance that does not implement an identified unfinished IR task as a new change intent, even when it refers to an IR with no unfinished task.',
21
+ 'Do not invent or reopen an IR task, claim unperformed work complete, or infer an owner decision not supplied by the caller.',
22
+ '',
23
+ 'For a new change intent, assess whether it can be completed well in one commit.',
21
24
  'If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.',
22
25
  'If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.',
23
26
  'Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.',
24
27
  '',
25
- 'For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
28
+ 'For an existing IR with unfinished work, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
26
29
  'Do not implement a later task in this phase.',
27
30
  "Mark the IR's progress and deliverables when relevant.",
28
31
  "After implementing an IR task, identify it and state whether any IR task still has unfinished Coder work; if so identify the next unfinished task, otherwise state this was the final IR task's Coder work.",
@@ -86,8 +89,8 @@ const REVIEW_IR_TASK_PHASE_TEMPLATE = [
86
89
  ].join('\n');
87
90
  const NEEDS_BOSS_REPLY_DESCRIPTION = "The acting agent's prose surfaces a clarifying question for Boss that the agent cannot answer alone. Output shall include `question: <verbatim question text from the acting agent's prose>`.";
88
91
  const FIRST_PHASE_RESULT = {
89
- directCommit: "Coder completed the new coding intent as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.",
90
- irCommit: "Coder decomposed the new coding intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.",
92
+ directCommit: "Coder completed the new change intent, including standalone documentation or status maintenance that does not implement an identified unfinished IR task (even when it refers to an IR with no unfinished task), as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.",
93
+ irCommit: "Coder decomposed the new change intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.",
91
94
  moreTasks: "Coder continued an existing IR, implemented exactly its next unfinished task, made its one new commit, and at least one IR task remains unfinished; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.",
92
95
  finalTask: "Coder continued an existing IR, implemented its final unfinished task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.",
93
96
  needsBossReply: NEEDS_BOSS_REPLY_DESCRIPTION,
@@ -99,8 +102,8 @@ const IR_TASK_PHASE_RESULT = {
99
102
  };
100
103
  const STATE_DESCRIPTIONS = {
101
104
  ready: 'Waiting for a coding request.',
102
- firstPhase: 'Coder runs the first coding phase: a direct implementation, a new IR, or the next task of an existing IR.',
103
- reviewNewIntentPhase: 'REVIEW examines the commit of the direct implementation or new-IR phase.',
105
+ firstPhase: 'Coder runs the first phase: a direct change, a new IR, or an existing IR\'s next unfinished task.',
106
+ reviewNewIntentPhase: 'REVIEW examines the commit of the direct or new-IR phase.',
104
107
  irTaskPhase: "Coder implements the identified IR's next unfinished task.",
105
108
  reviewIrTaskPhase: 'REVIEW examines the commit of the IR-task phase.',
106
109
  awaitBossReply: "Waiting for Boss to answer the acting agent's question.",
@@ -251,15 +251,18 @@ export type CodeEvent =
251
251
  // ---------------------------------------------------------------------------
252
252
 
253
253
  const FIRST_PHASE_PROMPT = [
254
- 'First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.',
254
+ 'First determine whether the request starts a new change intent or continues an existing IR with unfinished work.',
255
255
  'If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.',
256
256
  '',
257
- 'For a new coding intent, assess whether it can be completed well in one commit.',
257
+ 'Treat standalone documentation or status maintenance that does not implement an identified unfinished IR task as a new change intent, even when it refers to an IR with no unfinished task.',
258
+ 'Do not invent or reopen an IR task, claim unperformed work complete, or infer an owner decision not supplied by the caller.',
259
+ '',
260
+ 'For a new change intent, assess whether it can be completed well in one commit.',
258
261
  'If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.',
259
262
  'If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.',
260
263
  'Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.',
261
264
  '',
262
- 'For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
265
+ 'For an existing IR with unfinished work, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.',
263
266
  'Do not implement a later task in this phase.',
264
267
  "Mark the IR's progress and deliverables when relevant.",
265
268
  "After implementing an IR task, identify it and state whether any IR task still has unfinished Coder work; if so identify the next unfinished task, otherwise state this was the final IR task's Coder work.",
@@ -330,9 +333,9 @@ const NEEDS_BOSS_REPLY_DESCRIPTION =
330
333
 
331
334
  const FIRST_PHASE_RESULT = {
332
335
  directCommit:
333
- "Coder completed the new coding intent as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.",
336
+ "Coder completed the new change intent, including standalone documentation or status maintenance that does not implement an identified unfinished IR task (even when it refers to an IR with no unfinished task), as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.",
334
337
  irCommit:
335
- "Coder decomposed the new coding intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.",
338
+ "Coder decomposed the new change intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.",
336
339
  moreTasks:
337
340
  "Coder continued an existing IR, implemented exactly its next unfinished task, made its one new commit, and at least one IR task remains unfinished; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.",
338
341
  finalTask:
@@ -351,9 +354,9 @@ const IR_TASK_PHASE_RESULT = {
351
354
  const STATE_DESCRIPTIONS = {
352
355
  ready: 'Waiting for a coding request.',
353
356
  firstPhase:
354
- 'Coder runs the first coding phase: a direct implementation, a new IR, or the next task of an existing IR.',
357
+ 'Coder runs the first phase: a direct change, a new IR, or an existing IR\'s next unfinished task.',
355
358
  reviewNewIntentPhase:
356
- 'REVIEW examines the commit of the direct implementation or new-IR phase.',
359
+ 'REVIEW examines the commit of the direct or new-IR phase.',
357
360
  irTaskPhase: "Coder implements the identified IR's next unfinished task.",
358
361
  reviewIrTaskPhase: 'REVIEW examines the commit of the IR-task phase.',
359
362
  awaitBossReply: "Waiting for Boss to answer the acting agent's question.",
@@ -17,15 +17,18 @@ When the request may continue an existing IR that it does not identify unambiguo
17
17
 
18
18
  When the first coding phase begins for the caller's coding request and any relevant context, Captain shall prompt Coder:
19
19
 
20
- > First determine whether the coding request starts a new coding intent or continues an existing IR with unfinished work.
20
+ > First determine whether the request starts a new change intent or continues an existing IR with unfinished work.
21
21
  > If the request may continue an existing IR but does not identify it unambiguously, ask Boss before changing files.
22
22
  >
23
- > For a new coding intent, assess whether it can be completed well in one commit.
23
+ > Treat standalone documentation or status maintenance that does not implement an identified unfinished IR task as a new change intent, even when it refers to an IR with no unfinished task.
24
+ > Do not invent or reopen an IR task, claim unperformed work complete, or infer an owner decision not supplied by the caller.
25
+ >
26
+ > For a new change intent, assess whether it can be completed well in one commit.
24
27
  > If it can, implement and test it, update the affected specs, and ensure @specs/map.md remains accurate.
25
28
  > If it cannot, decompose it into tasks sized to exactly one commit each, add a new IR under @specs/intents, and do not implement any IR task in this phase.
26
29
  > Plan affected spec updates before, with, or after their corresponding code changes, either as standalone IR tasks or as explicit work within related tasks.
27
30
  >
28
- > For an existing IR, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
31
+ > For an existing IR with unfinished work, read the identified IR and implement exactly its next unfinished task, including corresponding tests or specs if any.
29
32
  > Do not implement a later task in this phase.
30
33
  > Mark the IR's progress and deliverables when relevant.
31
34
  > After implementing an IR task, identify it and state whether any IR task still has unfinished Coder work; if so identify the next unfinished task, otherwise state this was the final IR task's Coder work.
@@ -49,8 +52,8 @@ When the first coding phase begins for the caller's coding request and any relev
49
52
  > > Run results: <run-results>
50
53
 
51
54
  Results:
52
- - `directCommit`: Coder completed the new coding intent as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
53
- - `irCommit`: Coder decomposed the new coding intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.
55
+ - `directCommit`: Coder completed the new change intent, including standalone documentation or status maintenance that does not implement an identified unfinished IR task (even when it refers to an IR with no unfinished task), as one direct implementation phase and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>` and `latestCommit: <commit identity>`.
56
+ - `irCommit`: Coder decomposed the new change intent into a new IR, implemented no IR task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, and `irNumber` identifying the created IR.
54
57
  - `moreTasks`: Coder continued an existing IR, implemented exactly its next unfinished task, made its one new commit, and at least one IR task remains unfinished; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
55
58
  - `finalTask`: Coder continued an existing IR, implemented its final unfinished task, and made its one new commit; Coder's result affirmatively supports this outcome, and no fixed presentation format of the reply is required. Output shall include `coderOutput: <verbatim final text>`, `latestCommit: <commit identity>`, `irNumber` identifying the continued IR, and `irTask` naming the implemented task.
56
59
 
@@ -58,7 +61,7 @@ Results:
58
61
 
59
62
  Captain waits until `review` passes with no unsettled findings; playbook `review` owns every review round and every review-fix commit, and no existing commit is rewritten.
60
63
 
61
- When a direct implementation or new-IR phase ends with its one new `code`-owned commit, Captain shall call playbook `review`:
64
+ When a direct or new-IR phase ends with its one new `code`-owned commit, Captain shall call playbook `review`:
62
65
 
63
66
  > > Original intent: <caller-input>
64
67
  > > Review scope: the commit <code-commit> from this coding phase and its resulting repository state.
@@ -69,7 +72,7 @@ On each successful nested REVIEW, Captain shall freeze the previous phase review
69
72
  CODE scope commit and evaluated revision remain distinct because REVIEW may create fix commits.
70
73
  No caller option, player prose or repository status text supplies this record.
71
74
  The record survives permitted restoration and the current task's Boss-answer continuation, and a fresh run or explicit Boss interruption clears it.
72
- When `review` passes a direct implementation phase, `code` is complete and returns to its caller the exact last `code`-owned commit, the exact final evaluated repository revision, and the fact that every phase's review passed with no unsettled findings.
75
+ When `review` passes a direct phase, `code` is complete and returns to its caller the exact last `code`-owned commit, the exact final evaluated repository revision, and the fact that every phase's review passed with no unsettled findings.
73
76
  When `review` passes a new-IR phase, Captain continues with the next unfinished IR-task phase.
74
77
  When `review` returns an authored abort or failure, or a terminal result that does not establish that the supplied scope was evaluated with no unsettled findings, `code` starts no further phase and reports the failure and the last `code`-owned commit to its caller.
75
78
  When the nested `review` call fails outside that authored result contract, `code` parks as failed and retains the control-plane error instead of reporting an authored review outcome.
@@ -86,7 +86,7 @@ const runtimeSpec = {
86
86
  "roleStates": {
87
87
  "firstPhase": {
88
88
  "role": "coder",
89
- "label": "Coder runs the first coding phase: a direct implementation, a new IR, or the next task of an existing IR."
89
+ "label": "Coder runs the first phase: a direct change, a new IR, or an existing IR's next unfinished task."
90
90
  },
91
91
  "irTaskPhase": {
92
92
  "role": "coder",
@@ -123,7 +123,7 @@ const runtimeSpec = {
123
123
  "roleStates": {
124
124
  "firstPhase": {
125
125
  "role": "coder",
126
- "label": "Coder runs the first coding phase: a direct implementation, a new IR, or the next task of an existing IR."
126
+ "label": "Coder runs the first phase: a direct change, a new IR, or an existing IR's next unfinished task."
127
127
  },
128
128
  "irTaskPhase": {
129
129
  "role": "coder",
@@ -0,0 +1,12 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ export interface SeedConfigOptions {
5
+ readonly env?: NodeJS.ProcessEnv;
6
+ readonly homeDir?: string;
7
+ }
8
+ export interface SeedConfigText {
9
+ readonly text: string;
10
+ readonly anyReady: boolean;
11
+ }
12
+ export declare function seedConfigText(options?: SeedConfigOptions): SeedConfigText;
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2026 SubLang International <https://sublang.ai>
3
+
4
+ // DR-096: the public `@sublang/playbook/seed-config` facade. The text is
5
+ // the launcher's own seed (playbook-cli-11); this module only fixes the
6
+ // bundled template and narrows the accepted options (playbook-cli-100).
7
+
8
+ import { fileURLToPath } from 'node:url';
9
+ import { seedConfigText as seedText } from './bin/launch-config.js';
10
+
11
+ const TEMPLATE_PATH = fileURLToPath(
12
+ new URL('./playbook.config.template.yaml', import.meta.url),
13
+ );
14
+
15
+ export function seedConfigText(options = {}) {
16
+ const env = options.env ?? process.env;
17
+ return seedText(
18
+ TEMPLATE_PATH,
19
+ env,
20
+ ...(options.homeDir !== undefined ? [options.homeDir] : []),
21
+ );
22
+ }