@sideboard-ai/core 0.1.57 → 0.1.59

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 (39) hide show
  1. package/dist/{agents-2YYWW723.js → agents-B2723EOF.js} +4 -4
  2. package/dist/{agents-AQFEFKBL.js → agents-EADRAAPG.js} +4 -4
  3. package/dist/{app-settings-2LQNRTBE.js → app-settings-TBHTJWLQ.js} +1 -1
  4. package/dist/{app-settings-73DI4B6T.js → app-settings-YBNZ4XSR.js} +1 -1
  5. package/dist/{chunk-5DMYULLC.js → chunk-2P2UK7E7.js} +2 -2
  6. package/dist/{chunk-7LNGIP3X.js → chunk-73AT5K4A.js} +15 -3
  7. package/dist/{chunk-DIOF73S2.js → chunk-75QR74KM.js} +7 -2
  8. package/dist/{chunk-EBWEKG52.js → chunk-CHGOMFTA.js} +3 -3
  9. package/dist/{chunk-C4BCC5X5.js → chunk-FGNBTFRD.js} +7 -2
  10. package/dist/{chunk-H6GGDLYS.js → chunk-JB2H7E7V.js} +1 -1
  11. package/dist/{chunk-BXJ76RHF.js → chunk-MBAL5FE6.js} +4 -4
  12. package/dist/{chunk-XOU6HNQJ.js → chunk-MFGGIRUA.js} +39 -13
  13. package/dist/{chunk-S42XDFKF.js → chunk-MLAST5BB.js} +3 -3
  14. package/dist/{chunk-C3J4GDW4.js → chunk-MX7UH5AT.js} +76 -60
  15. package/dist/{chunk-DQJ5D42H.js → chunk-NTYRBRE7.js} +44 -13
  16. package/dist/{chunk-DZFH2KLT.js → chunk-P7EQUFB6.js} +39 -13
  17. package/dist/{chunk-V2DUTUNC.js → chunk-QJBC4BRK.js} +2 -2
  18. package/dist/{chunk-ZNM4MAN4.js → chunk-RIWUU7FO.js} +15 -3
  19. package/dist/{chunk-UA5NDAHL.js → chunk-XWPKLRB3.js} +44 -13
  20. package/dist/{chunk-7F454EE2.js → chunk-ZXDOI6IH.js} +76 -53
  21. package/dist/{connected-teams-ONC4666A.js → connected-teams-MKIYKOYA.js} +2 -2
  22. package/dist/{connected-teams-2ANNZCP5.js → connected-teams-RSL4VB3X.js} +2 -2
  23. package/dist/{coordinator-prompt-RBKUNRPR.js → coordinator-prompt-4P23VVFC.js} +4 -4
  24. package/dist/{coordinator-prompt-ICF36NUQ.js → coordinator-prompt-LNWHZ64D.js} +4 -4
  25. package/dist/{global-workspace-667XLBW6.js → global-workspace-BHT4XUAA.js} +5 -5
  26. package/dist/{global-workspace-S7VLWPWG.js → global-workspace-TMMAVRVW.js} +5 -5
  27. package/dist/index.cjs +303 -115
  28. package/dist/index.d.cts +15 -6
  29. package/dist/index.d.ts +15 -6
  30. package/dist/index.js +157 -64
  31. package/dist/mcp/run-stdio.cjs +303 -126
  32. package/dist/mcp/run-stdio.js +156 -68
  33. package/dist/{run-ZJKYHXGN.js → run-GPSVV5OH.js} +1 -1
  34. package/dist/{run-H3IMNOYN.js → run-HZTBWGQR.js} +1 -1
  35. package/dist/{workspaces-FPJJXXAE.js → workspaces-3GO3EDQG.js} +6 -6
  36. package/dist/{workspaces-LYIDE2VR.js → workspaces-GFPGDGCS.js} +6 -6
  37. package/dist/{worktree-5KEQWSAF.js → worktree-3L2G6PCM.js} +2 -2
  38. package/dist/{worktree-RWGL7FUV.js → worktree-GBLHEFHR.js} +2 -2
  39. package/package.json +1 -1
@@ -2,17 +2,17 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-XOU6HNQJ.js";
5
+ } from "./chunk-MFGGIRUA.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
- } from "./chunk-C4BCC5X5.js";
8
+ } from "./chunk-FGNBTFRD.js";
9
9
  import {
10
10
  globalAgentCwd,
11
11
  sideboardReposDir
12
12
  } from "./chunk-7MV3RXSC.js";
13
13
 
14
14
  // src/orchestrator/coordinator-prompt.ts
15
- import { mkdirSync, writeFileSync } from "fs";
15
+ import { mkdirSync, readFileSync, writeFileSync } from "fs";
16
16
  import { join } from "path";
17
17
  function formatWorkspaceInventory(workspaces) {
18
18
  if (workspaces.length === 0) return "(no registered workspaces)";
@@ -53,7 +53,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
53
53
  "Workspaces:",
54
54
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
55
55
  "Worktree threads (chats):",
56
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort)",
56
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort). If you are Codex, do not set agent=codex (nested Codex deadlocks)",
57
57
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
58
58
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
59
59
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
@@ -65,7 +65,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
65
65
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
66
66
  "Inspect / review / PRs:",
67
67
  "- get_diff \u2014 compact diff summary",
68
- '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review."); then wait_for_turn / get_turn_result on the returned id',
68
+ '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
69
69
  "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
70
70
  "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
71
71
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -83,7 +83,9 @@ function coordinatorTurnReminder(opts) {
83
83
  "- You oversee Sideboard worktree agents. You are not yourself checked out in a project worktree.",
84
84
  "- This cwd is a synthetic empty home (not a git repo). Emptiness here is expected \u2014 it is not a problem to fix.",
85
85
  "- Registered workspaces / child threads are the fleet you manage via Sideboard MCP.",
86
- `- Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
86
+ `- YOUR orchestration thread id is ${opts.parentId}`,
87
+ `- Always pass parentThreadId="${opts.parentId}" on create_thread (never invent or reuse another uuid).`,
88
+ `- Or omit parentThreadId \u2014 Sideboard MCP already binds children to ${opts.parentId}.`,
87
89
  goal ? `- Goal / title: ${goal}` : null,
88
90
  accountDefaultsPlaybookLine(),
89
91
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
@@ -92,10 +94,33 @@ function coordinatorTurnReminder(opts) {
92
94
  "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
93
95
  ].filter(Boolean).join("\n");
94
96
  }
95
- function ensureGlobalCoordinatorCwd() {
97
+ function ensureGlobalCoordinatorCwd(opts) {
96
98
  const dir = globalAgentCwd();
97
- mkdirSync(dir, { recursive: true });
99
+ try {
100
+ mkdirSync(dir, { recursive: true });
101
+ } catch {
102
+ return dir;
103
+ }
98
104
  const reposDir = sideboardReposDir();
105
+ let orchId = opts?.orchestratorThreadId?.trim() || "";
106
+ if (!orchId) {
107
+ try {
108
+ const existing = readFileSync(join(dir, "AGENTS.md"), "utf8");
109
+ const m = existing.match(
110
+ /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
111
+ );
112
+ if (m?.[1]) orchId = m[1];
113
+ } catch {
114
+ }
115
+ }
116
+ const parentBlock = orchId ? [
117
+ "",
118
+ `## This chat's id`,
119
+ "",
120
+ `YOUR orchestration thread id is \`${orchId}\`.`,
121
+ `On every create_thread, pass parentThreadId="${orchId}" \u2014 or omit parentThreadId (Sideboard binds it automatically).`,
122
+ "Never invent a uuid and never reuse an id from an earlier conversation."
123
+ ] : [];
99
124
  const body = [
100
125
  "# Sideboard Orchestration",
101
126
  "",
@@ -105,6 +130,7 @@ function ensureGlobalCoordinatorCwd() {
105
130
  "Repos from `list_workspaces` and threads from `list_threads` are the fleet you orchestrate.",
106
131
  'For status questions ("what\'s going on?"), use `list_threads` / `list_workspaces` \u2014 never diagnose this synthetic home as a broken worktree.',
107
132
  "Bash is fine for inspecting **child worktree** / registered-repo paths, and for greenfield repo setup under the Sideboard repos directory \u2014 not for treating this home as the project.",
133
+ ...parentBlock,
108
134
  "",
109
135
  COORDINATOR_TOOL_PLAYBOOK,
110
136
  "",
@@ -112,16 +138,21 @@ function ensureGlobalCoordinatorCwd() {
112
138
  "",
113
139
  coordinatorGreenfieldPlaybook(reposDir),
114
140
  "",
115
- "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered) and `parentThreadId` for children.",
141
+ "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
142
+ orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
116
143
  "Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
144
+ "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
117
145
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn.",
118
146
  "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
119
147
  "Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
120
148
  ].join("\n");
121
- writeFileSync(join(dir, "CLAUDE.md"), `${body}
149
+ try {
150
+ writeFileSync(join(dir, "CLAUDE.md"), `${body}
122
151
  `, "utf8");
123
- writeFileSync(join(dir, "AGENTS.md"), `${body}
152
+ writeFileSync(join(dir, "AGENTS.md"), `${body}
124
153
  `, "utf8");
154
+ } catch {
155
+ }
125
156
  return dir;
126
157
  }
127
158
  function coordinatorSystemPrompt(opts) {
@@ -141,12 +172,12 @@ function coordinatorSystemPrompt(opts) {
141
172
  COORDINATOR_TOOL_PLAYBOOK,
142
173
  accountDefaultsPlaybookLine(),
143
174
  coordinatorGreenfieldPlaybook(reposDir),
144
- "When creating threads, pass the correct repoPath for the target workspace and parentThreadId for children.",
175
+ "When creating threads, pass the correct repoPath for the target workspace.",
176
+ `YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit parentThreadId (Sideboard binds it). Never invent a uuid.`,
145
177
  "Omit agent/model on create_thread unless you need to override Account defaults.",
146
178
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Never target upstream. Never open PRs from the orchestrator.",
147
179
  "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
148
180
  `Goal: ${opts.goal}`,
149
- `Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
150
181
  "Registered workspaces:",
151
182
  formatWorkspaceInventory(opts.workspaces)
152
183
  ].join("\n");
@@ -11,7 +11,7 @@ import {
11
11
  gh,
12
12
  git,
13
13
  resolveGhAuthToken
14
- } from "./chunk-7LNGIP3X.js";
14
+ } from "./chunk-73AT5K4A.js";
15
15
 
16
16
  // src/git/worktree.ts
17
17
  import { existsSync, readdirSync } from "fs";
@@ -1258,12 +1258,16 @@ async function ensureGhPreferOrigin(cwd) {
1258
1258
  const hasAlt = Boolean(await slugFromGitRemote(cwd, "upstream")) || Boolean(await slugFromGitRemote(cwd, "github"));
1259
1259
  if (!hasAlt) return;
1260
1260
  const view = await gh(["repo", "set-default", "--view"], cwd, {
1261
- reject: false
1261
+ reject: false,
1262
+ timeoutMs: 15e3
1262
1263
  });
1263
1264
  const current = `${view.stdout}
1264
1265
  ${view.stderr}`;
1265
1266
  if (view.exitCode === 0 && current.includes(originSlug)) return;
1266
- await gh(["repo", "set-default", "origin"], cwd, { reject: false });
1267
+ await gh(["repo", "set-default", "origin"], cwd, {
1268
+ reject: false,
1269
+ timeoutMs: 15e3
1270
+ });
1267
1271
  }
1268
1272
  async function originGhRepoEnv(cwd) {
1269
1273
  await ensureGhPreferOrigin(cwd);
@@ -1809,20 +1813,42 @@ async function createThreadWorktree(opts) {
1809
1813
  throw new Error(`Worktree already exists at ${worktreePath}`);
1810
1814
  }
1811
1815
  await ensureGhPreferOrigin(opts.repoPath);
1812
- await git(["fetch", "origin", "--prune"], opts.repoPath, { reject: false });
1813
- if (!isLocalPrFetchBranch(opts.sourceRef) && !opts.sourceRef.startsWith("origin/") && !opts.sourceRef.startsWith("refs/")) {
1814
- await git(["fetch", "origin", opts.sourceRef], opts.repoPath, {
1815
- reject: false
1816
+ let startPoint = null;
1817
+ try {
1818
+ startPoint = await resolveWorktreeStartPoint(opts.repoPath, opts.sourceRef);
1819
+ } catch {
1820
+ startPoint = null;
1821
+ }
1822
+ if (!isLocalPrFetchBranch(opts.sourceRef)) {
1823
+ const fetchTimeoutMs = startPoint ? 12e3 : 45e3;
1824
+ await git(["fetch", "origin", "--prune"], opts.repoPath, {
1825
+ reject: false,
1826
+ timeoutMs: fetchTimeoutMs
1816
1827
  });
1828
+ if (!opts.sourceRef.startsWith("origin/") && !opts.sourceRef.startsWith("refs/")) {
1829
+ await git(["fetch", "origin", opts.sourceRef], opts.repoPath, {
1830
+ reject: false,
1831
+ timeoutMs: fetchTimeoutMs
1832
+ });
1833
+ }
1834
+ try {
1835
+ startPoint = await resolveWorktreeStartPoint(
1836
+ opts.repoPath,
1837
+ opts.sourceRef
1838
+ );
1839
+ } catch (err) {
1840
+ if (!startPoint) throw err;
1841
+ }
1842
+ }
1843
+ if (!startPoint) {
1844
+ throw new Error(
1845
+ `Invalid git reference: ${opts.sourceRef} (and fetch did not resolve it)`
1846
+ );
1817
1847
  }
1818
- const startPoint = await resolveWorktreeStartPoint(
1819
- opts.repoPath,
1820
- opts.sourceRef
1821
- );
1822
1848
  const add = await git(
1823
1849
  ["worktree", "add", "-b", branchName, worktreePath, startPoint],
1824
1850
  opts.repoPath,
1825
- { reject: false }
1851
+ { reject: false, timeoutMs: 6e4 }
1826
1852
  );
1827
1853
  if (add.exitCode !== 0) {
1828
1854
  const err = `${add.stderr}
@@ -1833,7 +1859,7 @@ ${add.stdout}`;
1833
1859
  const retry = await git(
1834
1860
  ["worktree", "add", "-b", alt, worktreePath, startPoint],
1835
1861
  opts.repoPath,
1836
- { reject: false }
1862
+ { reject: false, timeoutMs: 6e4 }
1837
1863
  );
1838
1864
  if (retry.exitCode === 0) {
1839
1865
  branchName = alt;
@@ -2,11 +2,11 @@
2
2
 
3
3
  import {
4
4
  isGlobalRepoPath
5
- } from "./chunk-EBWEKG52.js";
5
+ } from "./chunk-CHGOMFTA.js";
6
6
  import {
7
7
  ensureGhPreferOrigin,
8
8
  resolveRepoRoot
9
- } from "./chunk-XOU6HNQJ.js";
9
+ } from "./chunk-MFGGIRUA.js";
10
10
  import {
11
11
  appDataDir
12
12
  } from "./chunk-7MV3RXSC.js";
@@ -43,7 +43,8 @@ async function run(file, args, opts) {
43
43
  const result = await execa(file, args, {
44
44
  cwd: opts?.cwd,
45
45
  env: { ...process.env, ...opts?.env },
46
- reject: opts?.reject ?? true
46
+ reject: opts?.reject ?? true,
47
+ ...opts?.timeoutMs != null ? { timeout: opts.timeoutMs } : {}
47
48
  });
48
49
  return {
49
50
  stdout: result.stdout ?? "",
@@ -73,11 +74,22 @@ async function git(args, cwd, opts) {
73
74
  return run("git", [...prefix, ...args], {
74
75
  cwd,
75
76
  reject: opts?.reject,
76
- env: opts?.env
77
+ timeoutMs: opts?.timeoutMs,
78
+ // Never block forever on a credential/SSH prompt inside MCP / Electron.
79
+ env: {
80
+ GIT_TERMINAL_PROMPT: "0",
81
+ GIT_ASKPASS: process.env.GIT_ASKPASS || "echo",
82
+ GIT_SSH_COMMAND: process.env.GIT_SSH_COMMAND || "ssh -o BatchMode=yes -o ConnectTimeout=15",
83
+ ...opts?.env
84
+ }
77
85
  });
78
86
  }
79
87
  async function gh(args, cwd, opts) {
80
- return run("gh", args, { cwd, reject: opts?.reject });
88
+ return run("gh", args, {
89
+ cwd,
90
+ reject: opts?.reject,
91
+ timeoutMs: opts?.timeoutMs
92
+ });
81
93
  }
82
94
  async function resolveGhAuthToken(cwd) {
83
95
  const result = await gh(["auth", "token"], cwd, { reject: false });
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  resolveThreadDefaults
3
- } from "./chunk-DIOF73S2.js";
3
+ } from "./chunk-75QR74KM.js";
4
4
  import {
5
5
  resolveGithubRepoSlug
6
- } from "./chunk-DZFH2KLT.js";
6
+ } from "./chunk-P7EQUFB6.js";
7
7
  import {
8
8
  globalAgentCwd,
9
9
  sideboardReposDir
10
10
  } from "./chunk-M37RITA6.js";
11
11
 
12
12
  // src/orchestrator/coordinator-prompt.ts
13
- import { mkdirSync, writeFileSync } from "fs";
13
+ import { mkdirSync, readFileSync, writeFileSync } from "fs";
14
14
  import { join } from "path";
15
15
  function formatWorkspaceInventory(workspaces) {
16
16
  if (workspaces.length === 0) return "(no registered workspaces)";
@@ -51,7 +51,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
51
51
  "Workspaces:",
52
52
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
53
53
  "Worktree threads (chats):",
54
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort)",
54
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort). If you are Codex, do not set agent=codex (nested Codex deadlocks)",
55
55
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
56
56
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
57
57
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
@@ -63,7 +63,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
63
63
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
64
64
  "Inspect / review / PRs:",
65
65
  "- get_diff \u2014 compact diff summary",
66
- '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review."); then wait_for_turn / get_turn_result on the returned id',
66
+ '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
67
67
  "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
68
68
  "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
69
69
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -81,7 +81,9 @@ function coordinatorTurnReminder(opts) {
81
81
  "- You oversee Sideboard worktree agents. You are not yourself checked out in a project worktree.",
82
82
  "- This cwd is a synthetic empty home (not a git repo). Emptiness here is expected \u2014 it is not a problem to fix.",
83
83
  "- Registered workspaces / child threads are the fleet you manage via Sideboard MCP.",
84
- `- Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
84
+ `- YOUR orchestration thread id is ${opts.parentId}`,
85
+ `- Always pass parentThreadId="${opts.parentId}" on create_thread (never invent or reuse another uuid).`,
86
+ `- Or omit parentThreadId \u2014 Sideboard MCP already binds children to ${opts.parentId}.`,
85
87
  goal ? `- Goal / title: ${goal}` : null,
86
88
  accountDefaultsPlaybookLine(),
87
89
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
@@ -90,10 +92,33 @@ function coordinatorTurnReminder(opts) {
90
92
  "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
91
93
  ].filter(Boolean).join("\n");
92
94
  }
93
- function ensureGlobalCoordinatorCwd() {
95
+ function ensureGlobalCoordinatorCwd(opts) {
94
96
  const dir = globalAgentCwd();
95
- mkdirSync(dir, { recursive: true });
97
+ try {
98
+ mkdirSync(dir, { recursive: true });
99
+ } catch {
100
+ return dir;
101
+ }
96
102
  const reposDir = sideboardReposDir();
103
+ let orchId = opts?.orchestratorThreadId?.trim() || "";
104
+ if (!orchId) {
105
+ try {
106
+ const existing = readFileSync(join(dir, "AGENTS.md"), "utf8");
107
+ const m = existing.match(
108
+ /YOUR orchestration thread id is `([0-9a-f-]{36})`/i
109
+ );
110
+ if (m?.[1]) orchId = m[1];
111
+ } catch {
112
+ }
113
+ }
114
+ const parentBlock = orchId ? [
115
+ "",
116
+ `## This chat's id`,
117
+ "",
118
+ `YOUR orchestration thread id is \`${orchId}\`.`,
119
+ `On every create_thread, pass parentThreadId="${orchId}" \u2014 or omit parentThreadId (Sideboard binds it automatically).`,
120
+ "Never invent a uuid and never reuse an id from an earlier conversation."
121
+ ] : [];
97
122
  const body = [
98
123
  "# Sideboard Orchestration",
99
124
  "",
@@ -103,6 +128,7 @@ function ensureGlobalCoordinatorCwd() {
103
128
  "Repos from `list_workspaces` and threads from `list_threads` are the fleet you orchestrate.",
104
129
  'For status questions ("what\'s going on?"), use `list_threads` / `list_workspaces` \u2014 never diagnose this synthetic home as a broken worktree.',
105
130
  "Bash is fine for inspecting **child worktree** / registered-repo paths, and for greenfield repo setup under the Sideboard repos directory \u2014 not for treating this home as the project.",
131
+ ...parentBlock,
106
132
  "",
107
133
  COORDINATOR_TOOL_PLAYBOOK,
108
134
  "",
@@ -110,16 +136,21 @@ function ensureGlobalCoordinatorCwd() {
110
136
  "",
111
137
  coordinatorGreenfieldPlaybook(reposDir),
112
138
  "",
113
- "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered) and `parentThreadId` for children.",
139
+ "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
140
+ orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
114
141
  "Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
142
+ "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
115
143
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn.",
116
144
  "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
117
145
  "Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
118
146
  ].join("\n");
119
- writeFileSync(join(dir, "CLAUDE.md"), `${body}
147
+ try {
148
+ writeFileSync(join(dir, "CLAUDE.md"), `${body}
120
149
  `, "utf8");
121
- writeFileSync(join(dir, "AGENTS.md"), `${body}
150
+ writeFileSync(join(dir, "AGENTS.md"), `${body}
122
151
  `, "utf8");
152
+ } catch {
153
+ }
123
154
  return dir;
124
155
  }
125
156
  function coordinatorSystemPrompt(opts) {
@@ -139,12 +170,12 @@ function coordinatorSystemPrompt(opts) {
139
170
  COORDINATOR_TOOL_PLAYBOOK,
140
171
  accountDefaultsPlaybookLine(),
141
172
  coordinatorGreenfieldPlaybook(reposDir),
142
- "When creating threads, pass the correct repoPath for the target workspace and parentThreadId for children.",
173
+ "When creating threads, pass the correct repoPath for the target workspace.",
174
+ `YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit parentThreadId (Sideboard binds it). Never invent a uuid.`,
143
175
  "Omit agent/model on create_thread unless you need to override Account defaults.",
144
176
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Never target upstream. Never open PRs from the orchestrator.",
145
177
  "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
146
178
  `Goal: ${opts.goal}`,
147
- `Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
148
179
  "Registered workspaces:",
149
180
  formatWorkspaceInventory(opts.workspaces)
150
181
  ].join("\n");