symphony-orchestrator 0.2.4 → 0.2.6

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
@@ -7,9 +7,13 @@ its own repository-owned Runtime Contract under `.symphony/`.
7
7
 
8
8
  ## Prerequisites
9
9
 
10
- - GitHub CLI: `gh`
11
- - A GitHub personal access token available as `GITHUB_TOKEN` or `GH_TOKEN`
12
10
  - `codex` CLI available on `PATH` when running real agent sessions
11
+ - For the default GitHub Tracker: GitHub CLI `gh` and a GitHub personal access token available as
12
+ `GITHUB_TOKEN` or `GH_TOKEN`
13
+ - For the minibeads Local Issue Tracker: the `mb` CLI and a local issue store in the Workspace
14
+ Repository
15
+ - For the Compozy-backed Local Issue Tracker: a Compozy PRD Run directory under
16
+ `.compozy/tasks/<task_name>/` in the Workspace Repository
13
17
 
14
18
  ## Install
15
19
 
@@ -48,9 +52,47 @@ Environment files:
48
52
  /workspaces/
49
53
  ```
50
54
 
51
- Edit `.symphony/settings.json` to set the GitHub owner, Workspace Repository name, GitHub Project
52
- number, GitHub Project states, and runtime commands. Runtime Settings reference secrets by environment
53
- variable name; secret values belong only in the Local Environment:
55
+ Edit `.symphony/settings.json` to choose an Issue Tracker, set tracker-specific fields, configure
56
+ status states, and set runtime commands. Runtime Settings reference secrets by environment variable
57
+ name; secret values belong only in the Local Environment.
58
+
59
+ ### Default Terminal Console
60
+
61
+ Run `symphony` from the Workspace Repository root to start the default read-first Terminal Console.
62
+ It is the foreground surface for normal local orchestration and renders Runtime State snapshots for
63
+ active work, retrying work, task attention, Readiness Gaps, Ordered Queue progress, Logs progress, Agent Worktree details,
64
+ and Task Branch context.
65
+ Compozy PRD Run progress appears when Compozy tracking is selected.
66
+
67
+ The Terminal Console is safe to keep open while Symphony runs. Its MVP safe local aids are limited to
68
+ refreshing the latest in-memory Runtime State snapshot, navigating and filtering tabs, opening focused Terminal Console settings with `s`, starting or reusing the loopback Web Dashboard with `w`, and inspecting validated local paths such as the Workspace Repository or Runtime Home.
69
+
70
+ The `s` settings surface persists Terminal Console theme in ignored Runtime Home state and persists the
71
+ Web Dashboard port by updating only Runtime Settings `server.port`. It is not a general Runtime
72
+ Settings editor and does not edit `server.host`, tracker, Git, agent, Harness, Sandbox, queue, or
73
+ lifecycle settings. The `w` action starts or reuses a compatible loopback Web Dashboard for the current
74
+ Workspace Repository and Runtime Home, then shows the dashboard URL. If the configured port is occupied
75
+ by an incompatible listener, Symphony reports a conflict instead of attaching to it. Settings and `w` do not retry tasks, pause or resume dispatch, update tracker status, merge or push Task Branches, open pull requests, or otherwise mutate task lifecycle state.
76
+
77
+ Use Web Dashboard mode when browser-level inspection is more useful:
78
+
79
+ ```sh
80
+ symphony --web --port 8080
81
+ ```
82
+
83
+ The Web Dashboard keeps using the Live Dashboard Connection as a Runtime State stream. It is not a
84
+ Terminal Console command channel. Terminal Console V1 dashboard controls are loopback-only; non-loopback
85
+ Web Dashboard access remains an explicit Runtime Settings choice and continues to require the
86
+ server-generated local dashboard auth token for Runtime State HTTP and Live Dashboard Connection access.
87
+
88
+ For a non-interactive check, use `symphony --once`; it prints terminal output and exits without
89
+ starting the foreground Terminal Console loop.
90
+
91
+ ### Issue Tracker Selection
92
+
93
+ GitHub is the default Issue Tracker. It uses GitHub Issues as issue records and GitHub Projects
94
+ status values as dispatch state. Omitted `tracker.kind` values are treated as `"github"`, but new
95
+ Workspace Repositories should set it explicitly:
54
96
 
55
97
  ```json
56
98
  {
@@ -64,37 +106,215 @@ variable name; secret values belong only in the Local Environment:
64
106
  }
65
107
  ```
66
108
 
67
- Choose the Codex model and reasoning effort in the same file. If omitted, Symphony uses `gpt-5.5`
68
- with `medium` reasoning:
109
+ Choose minibeads when you want issue records to live in repository-owned Local Issue Files and you do
110
+ not want Symphony issue dispatch or tracker status updates to require GitHub API access. minibeads is
111
+ first-class when explicitly selected, but it is not a migration requirement for existing GitHub
112
+ Tracker users:
69
113
 
70
114
  ```json
71
115
  {
72
- "codex": {
73
- "command": "codex exec",
74
- "model": "gpt-5.5",
75
- "reasoningEffort": "medium"
116
+ "tracker": {
117
+ "kind": "minibeads",
118
+ "root": ".beads",
119
+ "command": "mb"
76
120
  }
77
121
  }
78
122
  ```
79
123
 
80
- PI is not a prerequisite. If you have the `pi` CLI installed and authenticated, you can use it as an
81
- Agent Harness instead of Codex for selected Stage Agents. Define an `agents.pi` harness and point each
82
- stage that should use PI at that harness with `harness`:
124
+ `tracker.root` is resolved from the Workspace Repository root and defaults to `.beads`.
125
+ `tracker.command` defaults to `mb`; set it only when the executable name or path differs in your
126
+ environment. Symphony runs minibeads commands from the Workspace Repository root and treats Local
127
+ Issue Files as repository-owned user data.
128
+
129
+ Choose the Compozy-backed Local Issue Tracker when you want Symphony to run a Compozy PRD Run from
130
+ `.compozy/tasks/<task_name>/` as one user-facing work item. This tracker is opt-in with
131
+ `tracker.kind = "compozy_tasks"`; GitHub remains the default Issue Tracker when the field is omitted
132
+ or set to `"github"`:
83
133
 
84
134
  ```json
85
135
  {
86
- "agents": {
136
+ "tracker": {
137
+ "kind": "compozy_tasks",
138
+ "compozy": {
139
+ "root": ".compozy/tasks",
140
+ "maxTaskStepRetries": 2
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ `tracker.compozy.root` is resolved from the Workspace Repository root and defaults to
147
+ `.compozy/tasks`. Each direct child directory, such as `.compozy/tasks/compozy-tasks-run-integration/`,
148
+ is treated as one Compozy PRD Run. The `task_NN.md` files inside that directory are Compozy Task Steps
149
+ in the same Agent Worktree and Task Branch; they are not separate Symphony issues. When
150
+ present, `_prd.md` and `_techspec.md` are included in each task-step Agent Prompt.
151
+
152
+ Symphony persists Compozy Task Step progress in task file frontmatter. During a run, task steps move
153
+ through statuses such as `pending`, `in_progress`, `completed`, `failed`, and `skipped`, with retry
154
+ metadata recorded alongside the status. `tracker.compozy.maxTaskStepRetries` controls how many times
155
+ Symphony retries a failed task step before recording the failed or skipped state and advancing to the
156
+ next runnable task step. Runtime State, the Terminal Console, and the Web Dashboard show the selected
157
+ tracker kind, Compozy PRD Run identifier, current task step, completed count, failed count, skipped
158
+ count, and total count when Compozy tracking is selected.
159
+
160
+ Compozy tracking has four related status layers:
161
+
162
+ | Layer | Runtime State field or source | What it answers |
163
+ | --- | --- | --- |
164
+ | Compozy Task Step progress | `current_step`, `completed`, `failed`, `skipped`, `total` from `task_NN.md` frontmatter | Which ordered step is selected and how many steps are terminal. |
165
+ | Compozy PRD Run lifecycle | `lifecycle_state` | What phase the whole run is in from the operator perspective. |
166
+ | Dispatch state | `dispatch_state` and `stage_agent` | Which configured tracker status and Stage Agent routing state Symphony is using. |
167
+ | Compozy PR Readiness | `pr_readiness`, `handoff_status`, and `reason` | Whether the completed run is eligible for one aggregate Batch Pull Request or why it is not. |
168
+
169
+ Runtime State, the Terminal Console, and the Web Dashboard render these layers from the same
170
+ `compozy_progress` payload. The Terminal Console and Web Dashboard use compact labels such as
171
+ `Lifecycle`, `Dispatch state`, `Stage agent`, `PR readiness`, `Handoff`, and `Reason`, but those
172
+ labels do not merge the layers. Compozy Task Step progress remains the source for current-step and
173
+ count truth; lifecycle and readiness explain the run around that progress.
174
+
175
+ Compozy PRD Run lifecycle meanings:
176
+
177
+ | Lifecycle state | Meaning |
178
+ | --- | --- |
179
+ | `pending` | The run exists but has not entered active Stage Agent work. |
180
+ | `in_planning` | Planner-stage work is active. |
181
+ | `in_execution` | Engineer-stage work or active task-step execution is in progress. |
182
+ | `in_review` | Reviewer-stage work is active. |
183
+ | `blocked` | Symphony needs operator attention and the run is not progressing normally. |
184
+ | `completed` | The run completed successfully from the lifecycle perspective. |
185
+ | `failed` | The run ended with failed work and is not ready for a Batch Pull Request. |
186
+ | `skipped` | The run ended with skipped work and is not ready for a Batch Pull Request. |
187
+ | `not_pr_ready` | The run is stopped or terminal but cannot open a Batch Pull Request; this is the not-PR-ready lifecycle and `Reason` explains why. |
188
+ | `pr_handoff` | Batch Pull Request handoff for the aggregate Batch Pull Request is attempting, completed, or failed. |
189
+
190
+ PR readiness is separate from both lifecycle and task-step counts:
191
+
192
+ | PR readiness | Meaning |
193
+ | --- | --- |
194
+ | `disabled` | The Pull Request Policy does not enable automatic Batch Pull Requests. |
195
+ | `not_ready` | The run is in the not-ready outcome for a Batch Pull Request; `Reason` describes the broad blocker. |
196
+ | `ready` | The run completed successfully and is eligible for one aggregate Batch Pull Request. |
197
+ | `handoff_attempting` | Symphony is attempting the Batch Pull Request handoff. |
198
+ | `handoff_completed` | Symphony opened, completed, or reused the aggregate Batch Pull Request. |
199
+ | `handoff_failed` | Batch Pull Request handoff failed and may be retried after the cause is fixed. |
200
+
201
+ Representative Compozy PRD Run examples:
202
+
203
+ | Scenario | Task-step progress | `lifecycle_state` | `dispatch_state` / `stage_agent` | `pr_readiness` / `handoff_status` | Operator meaning |
204
+ | --- | --- | --- | --- | --- | --- |
205
+ | Review active | Current Compozy Task Step and counts still come from task files. | `in_review` | `In review` / `reviewer` | `not_ready` / none | Reviewer work is active; the run is not ready for Batch Pull Request handoff. |
206
+ | Retrying execution | The current step remains selected while retry context is visible in Runtime State. | `in_execution` | Current configured run state / `engineer` | `not_ready` / none | Retry does not create a new lifecycle value; `Reason` explains the retry. |
207
+ | Blocked attention | Counts may show failed, skipped, or unavailable task-step progress. | `blocked` | `Human attention` / current Stage Agent when known | `not_ready` / none | Operator action is required before normal progress or handoff can continue. |
208
+ | Failed or skipped terminal | Task-step truth shows failed or skipped terminal work. | `failed` or `skipped` | Terminal configured run state | `not_ready` / none | Terminal progress is visible, but it is not Batch Pull Request-ready. |
209
+ | Completed and batch-ready | All task steps completed and final integration is safe. | `completed` | `Done` / current Stage Agent when known | `ready` / none | The Compozy PRD Run is eligible for one aggregate Batch Pull Request when the Pull Request Policy enables batch handoff. |
210
+ | Completed with pull requests disabled | All task steps completed and final integration is safe. | `completed` | `Done` / current Stage Agent when known | `disabled` / none | The run completed, but automatic Batch Pull Requests are disabled by Pull Request Policy. |
211
+ | Handoff failure | The completed run entered aggregate Batch Pull Request handoff. | `pr_handoff` | `Done` / current Stage Agent when known | `handoff_failed` / `handoff_failed` | The run is in handoff phase, and the failed handoff is a readiness outcome with a `Reason`, not successful review readiness. |
212
+
213
+ Terminal task-step progress does not imply Batch Pull Request readiness. A run with failed, skipped,
214
+ blocked, or otherwise terminal Compozy Task Steps remains `not_ready` unless the Compozy PRD Run
215
+ completed successfully, final integration is safe, and the Pull Request Policy allows handoff.
216
+ In `batch` Pull Request Mode, Compozy tracking preserves aggregate Batch Pull Request behavior:
217
+ Symphony never opens one pull request per Compozy Task Step. At most one Batch Pull Request is
218
+ eligible for the completed Compozy PRD Run, using the Loop-Start Branch as the pull-request head.
219
+ If the completed Compozy Task Steps move the run into another configured Stage Agent state, Symphony
220
+ dispatches that next Stage Agent with completed-run context first. Pull request handoff happens only
221
+ after there is no configured next Stage Agent.
222
+
223
+ When the selected Issue Tracker is `tracker.kind = "compozy_tasks"`, `--queue` accepts bare Compozy
224
+ PRD Run slugs from `.compozy/tasks/<task_name>/`:
225
+
226
+ ```sh
227
+ symphony --queue compozy-tasks-run-integration,queue-docs-refresh
228
+ ```
229
+
230
+ Symphony keeps those queue identifiers as typed in Runtime State and uses the same raw sequence when
231
+ deciding whether a restart resumes an Ordered Queue. Restarting with canonical selectors such as
232
+ `compozy:compozy-tasks-run-integration,compozy:queue-docs-refresh` starts a different queue run than
233
+ the bare-slug command above, even though dispatch resolves both forms to the same Compozy PRD Runs.
234
+
235
+ The bare-slug shortcut is only for `--queue` with the Compozy-backed Issue Tracker. If GitHub or
236
+ minibeads tracking is selected, a bare Compozy slug in `--queue` is reported as a startup Readiness
237
+ Gap; use GitHub identifiers such as `20` or `#20`, minibeads identifiers such as `mb-20`, or switch
238
+ Runtime Settings to `tracker.kind = "compozy_tasks"`. Canonical Compozy queue selectors such as
239
+ `--queue compozy:compozy-tasks-run-integration` remain accepted for compatibility, but a single
240
+ Compozy queue must use either bare slugs or canonical selectors, not both.
241
+
242
+ Where selector-based flows outside the `--queue` shortcut support Compozy tracking, use the stable
243
+ identifier form `compozy:<task_name>`. For example, `.compozy/tasks/compozy-tasks-run-integration/`
244
+ is selected as `compozy:compozy-tasks-run-integration` in Manual Task Merge flows.
245
+
246
+ Define execution backends under `harnesses` and logical agent roles under `agents`. Harnesses own
247
+ provider commands and loop capability. Logical agents select a Harness and may override model,
248
+ reasoning, and timeout fields for planner, engineer, or reviewer work:
249
+
250
+ ```json
251
+ {
252
+ "harnesses": {
87
253
  "codex": {
88
254
  "kind": "codex",
89
255
  "command": "codex exec",
90
- "model": "gpt-5.5",
91
- "reasoningEffort": "medium"
256
+ "loop": {
257
+ "enabled": true,
258
+ "command": "/goal"
259
+ }
260
+ },
261
+ "claude": {
262
+ "kind": "claude",
263
+ "command": "claude -p --model <model> --output-format stream-json",
264
+ "loop": {
265
+ "enabled": false,
266
+ "command": ""
267
+ }
268
+ },
269
+ "cursor": {
270
+ "kind": "cursor",
271
+ "command": "cursor-agent -p --model <model> --output-format stream-json",
272
+ "loop": {
273
+ "enabled": false,
274
+ "command": ""
275
+ }
276
+ },
277
+ "cursor-force": {
278
+ "kind": "cursor",
279
+ "command": "cursor-agent -p --force --model <model> --output-format stream-json",
280
+ "loop": {
281
+ "enabled": false,
282
+ "command": ""
283
+ }
92
284
  },
93
285
  "pi": {
94
286
  "kind": "pi",
95
287
  "command": "pi --model <model> --thinking <reasoning> --print --no-session",
96
- "model": "openai/gpt-5.5",
97
- "reasoningEffort": "medium"
288
+ "loop": {
289
+ "enabled": false,
290
+ "command": ""
291
+ }
292
+ }
293
+ },
294
+ "agents": {
295
+ "planner": {
296
+ "harness": "codex",
297
+ "model": "gpt-5.5",
298
+ "reasoningEffort": "medium",
299
+ "turnTimeoutMs": 3600000,
300
+ "readTimeoutMs": 5000,
301
+ "stallTimeoutMs": 300000
302
+ },
303
+ "engineer": {
304
+ "harness": "claude",
305
+ "model": "opus-4.7",
306
+ "reasoningEffort": "xhigh",
307
+ "turnTimeoutMs": 3600000,
308
+ "readTimeoutMs": 5000,
309
+ "stallTimeoutMs": 300000
310
+ },
311
+ "reviewer": {
312
+ "harness": "pi",
313
+ "model": "openai-codex/gpt-5.5",
314
+ "reasoningEffort": "high",
315
+ "turnTimeoutMs": 3600000,
316
+ "readTimeoutMs": 5000,
317
+ "stallTimeoutMs": 300000
98
318
  }
99
319
  },
100
320
  "stageAgents": {
@@ -102,24 +322,96 @@ stage that should use PI at that harness with `harness`:
102
322
  "stages": [
103
323
  {
104
324
  "states": ["Todo", "To-Do", "In progress", "In Progress"],
105
- "agent": "engineer",
106
- "harness": "pi"
325
+ "agent": "engineer"
107
326
  }
108
327
  ]
109
328
  }
110
329
  }
111
330
  ```
112
331
 
113
- When the `agents` object is present, each configured Stage Agent should select an existing Agent
114
- Harness with `harness` unless its `agent` name also matches a harness name. PI readiness checks require
115
- the `pi` executable on `PATH` and provider authentication for the configured model.
332
+ PI, Claude, and Cursor are not prerequisites for Codex-only dispatch. Symphony validates install and
333
+ authentication readiness only for Harnesses selected by enabled Stage Agent routes. A selected PI
334
+ Harness requires the `pi` executable on `PATH` and provider authentication for the configured model. A
335
+ selected Claude Harness requires the `claude` executable and Claude Code authentication, such as
336
+ `ANTHROPIC_API_KEY` or Claude's configured login state. A selected Cursor Harness requires the
337
+ `cursor-agent` executable and a successful `cursor-agent status` check, using either browser login or
338
+ `CURSOR_API_KEY`. Use the non-`--force` Cursor Harness for review-first operation; select the
339
+ `cursor-force` Harness only when the `Workspace Repository` operator intentionally wants Cursor to
340
+ write directly during that role. Runtime Settings must reference only environment variable names,
341
+ never secret values.
342
+
343
+ To assign Cursor to any Logical Agent, set `agents.<name>.harness` to `cursor` or `cursor-force`.
344
+ Keep `stageAgents.stages[]` routing by Logical Agent name rather than placing provider fields on the
345
+ stage itself.
346
+
347
+ Legacy settings that place Harness definitions under `agents.*`, such as `agents.pi.kind`, are
348
+ migration input. When the new Runtime Settings shape is in use, Symphony reports a blocking Readiness
349
+ Gap that tells you to move execution fields into `harnesses.*` and keep `agents.*` for logical agent
350
+ definitions. Stage-level `stageAgents.stages[].harness` is also legacy input; move Harness selection to
351
+ `agents.<logical-agent>.harness`.
116
352
 
117
353
  If setup is incomplete, the Terminal Console still starts and prints Readiness Gaps with remediation
118
354
  steps. Dispatch remains disabled until those gaps are resolved.
119
355
 
356
+ ### Optional Docker Sandbox
357
+
358
+ Sandboxing is a repository-level Runtime Settings boundary for Workspace Repositories that should run
359
+ agent work through Docker instead of direct host Agent Harness execution. It is optional and disabled
360
+ by default. Docker is the only supported sandbox type in V1:
361
+
362
+ ```json
363
+ {
364
+ "sandbox": {
365
+ "enabled": false,
366
+ "type": "docker",
367
+ "image": "ghcr.io/your-org/symphony-agent:latest",
368
+ "bootstrapCommands": [],
369
+ "persistent": true,
370
+ "networkEnabled": false,
371
+ "cpuLimit": 2,
372
+ "memoryMb": 4096
373
+ }
374
+ }
375
+ ```
376
+
377
+ Set `sandbox.enabled` to `true` only after replacing `sandbox.image` with the Docker image for the
378
+ Workspace Repository. When sandboxing is enabled, Symphony treats the Sandbox as required for agent
379
+ execution in that repository. Missing required settings, unsupported `sandbox.type` values, Docker
380
+ availability problems, or unhealthy sandbox state are Readiness Gaps and block dispatch; Symphony does
381
+ not silently fall back to host execution.
382
+
383
+ `sandbox.bootstrapCommands` is a list of non-empty shell commands that run only when Symphony creates
384
+ or recreates the Agent Worktree-scoped Docker container. V1 requires `sandbox.persistent: true` so
385
+ restarts of the same work item can reuse the named container without sharing it with concurrent Agent
386
+ Worktrees. `sandbox.networkEnabled` makes network access explicit, and `sandbox.cpuLimit` /
387
+ `sandbox.memoryMb` must be positive integers.
388
+
389
+ Runtime State snapshots include the running-work fields `sandbox_enabled`, `sandbox_provider`, and
390
+ `sandbox_reuse_outcome`. The reuse outcome is one of `created`, `reused`, or `recreated`; these
391
+ fields are the V1 visibility surface for confirming whether a sandboxed run used a fresh, warm, or
392
+ refreshed container.
393
+
394
+ For the GitHub Tracker, readiness includes the configured owner, Workspace Repository name, GitHub
395
+ Project number, status field, and token environment variable. For Local Issue Tracker runs,
396
+ GitHub owner, repo, Project, and token settings are not required. The local tracker readiness checks
397
+ include tracker-specific local files and commands:
398
+
399
+ - `tracker.minibeads.command`: install minibeads or update `tracker.command` so Symphony can run the
400
+ configured command.
401
+ - `tracker.minibeads.store`: create the local issue store at `tracker.root` or update `tracker.root`
402
+ to the existing minibeads store.
403
+ - `tracker.compozy.root`: create the Compozy tasks root at `tracker.compozy.root` or update the
404
+ setting to the existing `.compozy/tasks` directory.
405
+ - `tracker.compozy.tasks`: add at least one valid `.compozy/tasks/<task_name>/task_NN.md` file with
406
+ task-step frontmatter.
407
+
120
408
  ## Project Status Workflow
121
409
 
122
- Symphony moves the configured GitHub Projects `Status` field as work progresses:
410
+ Symphony moves the selected Issue Tracker status as work progresses. With the GitHub Tracker, this is
411
+ the configured GitHub Projects `Status` field. With the minibeads Local Issue Tracker, Symphony maps
412
+ the same Runtime Settings state names to minibeads statuses and writes them through `mb`. With the
413
+ Compozy-backed Local Issue Tracker, the Compozy PRD Run is the work item and Symphony records
414
+ task-step status in each `task_NN.md` file's frontmatter:
123
415
 
124
416
  - `startStatus`: applied before launching an agent, default `In progress`.
125
417
  - `reviewStatus`: applied after the agent exits successfully, default `In review`.
@@ -146,6 +438,7 @@ Configure these in `.symphony/settings.json`:
146
438
 
147
439
  The token needs GitHub Projects write access for status moves and status option creation. If
148
440
  `reviewStatus` is not listed in `activeStates`, completed issues stop being picked up on later polls.
441
+ The token requirement applies to GitHub Tracker runs only.
149
442
 
150
443
  ## Stage Agents
151
444
 
@@ -239,24 +532,96 @@ skill files and does not include Stage Skill Load in Stage Goal Context. Missing
239
532
  duplicate skill identifiers are Readiness Gaps; Symphony checks all configured stages before
240
533
  dispatch, resolving Workspace Repository skills before Codex Home skills.
241
534
 
242
- Rendered Agent Prompts include GitHub issue comments as issue context in addition to the issue body.
535
+ Rendered Agent Prompts include issue comments as issue context when the selected Issue Tracker
536
+ provides comments. minibeads Local Issue Tracker comments are not included in V1. Compozy-backed
537
+ Local Issue Tracker prompts include the current Compozy Task Step plus `_prd.md` and `_techspec.md`
538
+ from the same Compozy PRD Run when those files exist.
243
539
 
244
- Set `goal.enabled` to `true` on a specific stage to enable Stage Goal Handoff for that stage only.
245
- When enabled, Symphony sends `/goal` with deterministic Stage Goal Context before the normal Agent
246
- Prompt. Stage Goal Context includes issue identifier, title, description, comments, URL, current
247
- GitHub Project status, labels, priority when present, blocker references when present, attempt, and
248
- stage agent name. It omits issue creation and update timestamps.
540
+ Set `goal.enabled` to `true` on a specific stage to allow Stage Goal Handoff for that stage only.
541
+ The selected Harness decides whether a loop command is actually sent. The Bootstrap default Codex
542
+ Harness has `loop.enabled: true` and `loop.command: "/goal"`, so Codex receives `/goal` with
543
+ deterministic Stage Goal Context before the normal Agent Prompt. The Bootstrap default Claude, Cursor,
544
+ and PI Harnesses have loop disabled, so those Harnesses run the normal prompt even when a stage has
545
+ `goal.enabled: true`. Stage Goal Context includes issue identifier, title, description, comments, URL,
546
+ current tracker status, labels, priority when present, blocker references when present,
547
+ attempt, and stage agent name. It omits issue creation and update timestamps.
249
548
 
250
- Stage Goal Handoff requires Codex goals in `~/.codex/config.toml`:
549
+ Codex loop handoff requires a Codex command that accepts the configured Harness loop command from
550
+ standard input. For Codex goals, enable goals in `~/.codex/config.toml`:
251
551
 
252
552
  ```toml
253
553
  [features]
254
554
  goals = true
255
555
  ```
256
556
 
257
- If a stage enables goal handoff but Codex goals are not enabled, Symphony reports a Readiness Gap.
258
- Goal Usage reported by Codex is stored in Runtime State for running, retrying, and attention-needed
259
- task details when available; missing or unparseable Goal Usage does not fail a task.
557
+ If a selected loop-enabled Codex Harness cannot accept the configured loop command, Symphony reports a
558
+ Readiness Gap. Goal Usage reported by Codex is stored in Runtime State for running, retrying, and
559
+ attention-needed task details when available; missing or unparseable Goal Usage does not fail a task.
560
+ If a selected loop-enabled Cursor Harness cannot accept the configured loop command from standard
561
+ input, Symphony reports a Cursor loop Readiness Gap. Cursor `stream-json` activity updates the same
562
+ running-task Runtime State fields used by other Harnesses, while raw stdout and stderr logs remain
563
+ available as diagnostics.
564
+
565
+ Goal Loop is separate from Stage Goal Handoff. Stage Goal Handoff is launch-time prompt handoff;
566
+ Goal Loop is Runtime-owned Stage Agent behavior that can stop as Goal met, Needs attention, or
567
+ Budget exhausted. Goal met requires deterministic evidence, so Goal Usage, agent exit `0`, changed
568
+ files, or model confidence alone does not count as completion evidence.
569
+
570
+ Enable Goal Loop per stage with `goalLoop`. Bootstrap does not add Goal Loop defaults; omitting the
571
+ block keeps existing stage behavior unchanged. The `goalLoop.evidence` block configures the Goal
572
+ Loop Evidence Command. The evidence command is an argv array, runs from the configured working
573
+ directory, receives the same structured input on stdin and through the Context Command temp-file path
574
+ convention, and should print a concise, secret-free evidence summary:
575
+
576
+ ```json
577
+ {
578
+ "stageAgents": {
579
+ "enabled": true,
580
+ "root": ".symphony/agents",
581
+ "stages": [
582
+ {
583
+ "states": ["Todo", "To-Do", "In progress", "In Progress"],
584
+ "agent": "engineer",
585
+ "successStatus": "In review",
586
+ "retryStatus": "To-Do",
587
+ "goalLoop": {
588
+ "enabled": true,
589
+ "evidence": {
590
+ "command": ["pnpm", "test"],
591
+ "cwd": "agentWorktree",
592
+ "timeoutMs": 120000,
593
+ "maxOutputBytes": 8192
594
+ },
595
+ "budget": {
596
+ "maxTurns": 4,
597
+ "maxRuntimeMs": 3600000,
598
+ "maxTokens": 200000
599
+ }
600
+ }
601
+ }
602
+ ]
603
+ }
604
+ }
605
+ ```
606
+
607
+ The evidence command contract is intentionally narrow. A zero exit code with bounded stdout is
608
+ successful deterministic evidence. Missing commands, timeouts, non-zero exits, invalid output, or
609
+ missing deterministic evidence retry the same task with missing-evidence guidance while the
610
+ configured budget allows another attempt; once the loop cannot continue, the stop outcome is Needs
611
+ attention or Budget exhausted instead of Goal met.
612
+
613
+ Runtime State exposes Goal Loop State as top-level `goal_loops[]` entries with `issue_id`,
614
+ `issue_identifier`, `run_id`, `goal`, `state`, `stage_agent`, `harness_name`, `harness_kind`,
615
+ `attempt_count`, `budget`, `latest_evidence`, `stop_outcome`, `stop_reason`, `next_action`,
616
+ `diagnostics_path`, and `updated_at`. The Goal Loop Stop Outcome is `goal_met`, `needs_attention`, or
617
+ `budget_exhausted`. The Terminal Console and Web Dashboard read that same Runtime State projection
618
+ near Goal Usage and Context Status, including stopped Goal met, Needs attention, and Budget
619
+ exhausted outcomes.
620
+
621
+ Goal Loop does not own delivery authority. Stage Commit, Stage Push, Task Branch Integration, merge,
622
+ pull request creation, auto-merge, and tracker status transitions stay governed by the existing
623
+ Runtime Contract and run only through the existing completion and delivery lifecycle after Goal met
624
+ evidence succeeds.
260
625
 
261
626
  Stage commits run after an agent exits successfully and before Symphony moves the issue to the
262
627
  stage's `successStatus`. Set `commit.enabled` per stage to control which transitions create commits;
@@ -325,9 +690,10 @@ The `title` and `body` fields are deterministic templates. They support `<head_b
325
690
 
326
691
  ## GitHub Token Permissions
327
692
 
328
- Symphony Orchestrator reads GitHub Issues and GitHub Projects. Use a **personal access token (classic)**
329
- when the GitHub Project is owned by a user account, such as `@your-user's Kanban`. GitHub
330
- fine-grained personal access tokens currently cannot access Projects owned by a user account.
693
+ This section applies to the GitHub Tracker. Symphony Orchestrator reads GitHub Issues and GitHub
694
+ Projects when `tracker.kind` is `"github"`. Use a **personal access token (classic)** when the
695
+ GitHub Project is owned by a user account, such as `@your-user's Kanban`. GitHub fine-grained
696
+ personal access tokens currently cannot access Projects owned by a user account.
331
697
 
332
698
  Recommended classic PAT scopes:
333
699
 
@@ -364,8 +730,12 @@ Symphony still reports Workspace Repository or GitHub Project access gaps, remov
364
730
  - `apps/backend`: OCaml service, workflow loader, GitHub tracker boundary, workspace manager, HTTP
365
731
  state API, CLI, and tests.
366
732
  - `apps/frontend`: ReScript React/Vite dashboard that consumes the backend state API.
733
+ - `apps/tui`: reusable OCaml terminal UI toolkit packaged with Dune/opam as
734
+ `symphony-orchestrator-tui`. Its
735
+ `@symphony-orchestrator/tui` package.json is a private pnpm workspace label, not the publishing
736
+ target.
367
737
  - `.github/ISSUE_TEMPLATE`: issue template for work items Symphony can dispatch.
368
- - `.github/project-tracking.md`: required GitHub Project setup and workflow notes.
738
+ - `.github/project-tracking.md`: GitHub Tracker setup and workflow notes.
369
739
  - `WORKFLOW.example.md`: legacy/developer fixture for the earlier root workflow format.
370
740
  - `bin/symphony.js`: npm `bin` launcher that runs a packaged platform binary or the local dune
371
741
  executable in Product Repository development.
@@ -376,14 +746,16 @@ Product Repository development is separate from Workspace Repository operation.
376
746
  actual orchestration belong in the Workspace Repository where `symphony init` is run; this source
377
747
  repository keeps code, tests, packaging scripts, fixtures, and documentation.
378
748
 
379
- Product Repository development requires `pnpm` 10.x and an OCaml toolchain with `opam`, `dune`,
380
- `cmdliner`, `yojson`, and `alcotest`. The local scripts run OCaml commands through `opam exec`, so
381
- make sure the active opam switch has the required packages installed.
749
+ Product Repository development requires `pnpm` 10.x and an OCaml toolchain with `opam`, OCaml
750
+ `>= 5.1`, Dune `>= 3.19`, `cmdliner`, `yojson`, `alcotest`, the local `apps/tui` package, `uutf`,
751
+ and `toffee`. The local scripts run OCaml commands through `opam exec`, so make sure the active opam
752
+ switch has the required packages installed.
382
753
 
383
754
  Install dependencies:
384
755
 
385
756
  ```sh
386
757
  pnpm install
758
+ opam install . ./apps/tui --deps-only --with-test --yes
387
759
  ```
388
760
 
389
761
  Run the backend test suite:
@@ -392,6 +764,12 @@ Run the backend test suite:
392
764
  pnpm test
393
765
  ```
394
766
 
767
+ Run documentation validation:
768
+
769
+ ```sh
770
+ pnpm docs:test
771
+ ```
772
+
395
773
  Run frontend live-state tests:
396
774
 
397
775
  ```sh
@@ -429,9 +807,13 @@ pnpm backend:dev
429
807
 
430
808
  The backend serves:
431
809
 
432
- - Terminal Console/API root: `http://127.0.0.1:8080/`
810
+ - Backend/API root: `http://127.0.0.1:8080/`
433
811
  - Runtime state JSON: `http://127.0.0.1:8080/api/v1/state`
434
- - Tailscale/LAN access: `http://<machine-ip>:8080/` because the backend binds to `0.0.0.0`.
812
+
813
+ The backend binds to `127.0.0.1` by default. To expose the Web Dashboard on Tailscale or a LAN,
814
+ set `"server": {"host": "0.0.0.0", "port": 8080}` in `.symphony/settings.json`; non-loopback
815
+ binds print a one-time `symphony_auth` URL token and require that token for Runtime State HTTP and
816
+ Live Dashboard Connection access.
435
817
 
436
818
  Start the Web Dashboard dev server in another terminal:
437
819
 
@@ -458,6 +840,7 @@ symphony --web --port 8080
458
840
  ```sh
459
841
  pnpm install
460
842
  pnpm test
843
+ pnpm docs:test
461
844
  pnpm frontend:test
462
845
  pnpm frontend:build
463
846
  pnpm backend:build
@@ -474,8 +857,10 @@ opam exec -- dune exec symphony -- init
474
857
  opam exec -- dune exec symphony -- --web --port 8080
475
858
  ```
476
859
 
477
- If no GitHub token is configured, the runtime still starts, but readiness gaps report the missing
478
- token and live issue dispatch is disabled.
860
+ If no GitHub token is configured for the GitHub Tracker, the runtime still starts, but readiness
861
+ gaps report the missing token and live issue dispatch is disabled. For Local Issue Tracker runs,
862
+ dispatch does not require a GitHub token; unresolved minibeads command or local issue store gaps, or
863
+ missing Compozy PRD Run task files, disable dispatch instead.
479
864
 
480
865
  ## Package Distribution
481
866