opensymphony 2.8.2

A Rust implementation of the OpenAI Symphony orchestration design
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# AGENTS.md

## Mission

Build OpenSymphony as a Rust implementation of the Symphony service specification using OpenHands agent-server for execution and FrankenTUI for the optional terminal UI.

This repository is an orchestrator. It is not a chat app, not a general workflow engine, and not a thin wrapper around OpenHands.

## Authority order

When sources disagree, use this order:

1. upstream `openai/symphony` `SPEC.md`
2. pinned OpenHands SDK agent-server docs and the wire-contract notes in `docs/websocket-runtime.md`
3. this repository's `docs/`
4. the task file currently being implemented
5. local code comments and tests

Do not silently invent behavior when the upstream spec or chosen integration contract is explicit.

## Hard invariants

### Orchestration

- The Rust orchestrator is the sole authority over scheduling state.
- Workers report events and outcomes to the orchestrator.
- No background task may mutate scheduling state except through orchestrator-owned commands or messages.
- Tracker polling remains required even though agent runtime updates use WebSockets.

### Workspace safety

- Every issue maps to exactly one sanitized workspace key.
- Workspace paths must remain inside the configured workspace root.
- The agent runtime must execute with `cwd == issue_workspace_path`.
- Never run agent code in the orchestrator repository root, temp root, or an unsanitized path.

### OpenHands integration

- Target the SDK agent-server HTTP and WebSocket contract.
- Do not implement against `openhands serve`.
- Do not implement against the web-app Socket.IO protocol.
- Operations are REST. Runtime streaming is WebSocket.
- The WebSocket readiness barrier is the first `ConversationStateUpdateEvent`.
- Always reconcile events after WebSocket readiness and after reconnect.
- Harness interrupts for OpenHands-backed runs use
  `POST /api/conversations/{conversation_id}/interrupt` as the primary
  mid-turn stop request. Use `POST /api/conversations/{conversation_id}/pause`
  only as an older-server fallback when `/interrupt` is unavailable, and record
  that fallback in diagnostics. Report acknowledgement only after
  attach/reconcile observes a stopped state such as `paused`, or after the
  configured timeout path records a timeout diagnostic.
- One OpenHands conversation is reused per issue by default.
- A fresh conversation gets the full workflow prompt. A resumed conversation gets continuation guidance only.
- Local MVP uses one local agent-server subprocess shared across issues, not one server per issue.
- Local MVP does not require Docker per workspace.
- OpenHands subscription credentials are feature-gated behind
  `openhands-subscription-credentials`. In `openai_subscription` mode, workflow
  config stores environment-variable names and credential-bootstrap metadata
  (`auth_directory_env`, `auth_method`, `open_browser`, `force_login`), while the
  conversation request resolves only the short-lived access token reference and
  optional account identity header. Do not persist raw OAuth tokens, refresh
  material, or resolved account identifiers in manifests or debug output.

### Tracker contract

- The orchestrator reads Linear directly.
- Tracker writes are done by agent-side GraphQL helpers and checked-in query assets unless a future operator API explicitly documents otherwise.
- Scheduler correctness must not depend on agent-side tracker writes succeeding.

### UI separation

- FrankenTUI is optional.
- The daemon must remain correct without any UI attached.
- The UI consumes the control-plane snapshot and event stream only.
- UI code must not reach into orchestrator internals directly.
- Graph-visualization work (knowledge graph, task graph arrows) iterates
  against the shared fixtures and desktop `?fixtures` workbench described in
  `docs/graph-view.md` ("Graph visualization workbench"). Do not recreate
  ad-hoc demo data; extend `packages/graph/src/viz-fixture.ts` and
  `packages/api-client/src/graph-viz-demo.ts` instead, and keep the scene
  math covered by `packages/ui-core/__tests__/knowledge-graph-scene.test.ts`
  (including the THREE.js projection-parity test).

### CLI surface

- `opensymphony run` is the real local orchestrator entrypoint.
- `opensymphony daemon` is demo-only and exists for smoke tests or UI-focused development.
- When documenting, validating, or operating the system, prefer `opensymphony run` unless the task is specifically about the demo control-plane publisher.
- `opensymphony app` and the visible alias `opensymphony desktop` are the
  lazy desktop bundle installer/launcher path. They must remain separate from
  the execution-plane `opensymphony run` entrypoint.
- The desktop launcher caches verified bundles under
  `~/.opensymphony/desktop/<version>/` and uses a bundle manifest containing
  version, platform, architecture, relative executable path, and executable
  SHA-256 checksum. Local materialization must not add Tauri, npm, or platform
  desktop build dependencies to the default Cargo install.
- `opensymphony memory export-okf --visibility public|private [--output DIR]`
  exports a directory OKF bundle. Public export skips private concepts, runs
  public redaction checks through OKF lint, stages output before promotion, and
  requires the output directory to be new or empty.
- `opensymphony memory import-okf <bundle-root> [--force]` imports a
  repo-contained, non-overlapping directory OKF bundle into the configured
  memory root while preserving unknown concept types and frontmatter fields. It
  preflights target conflicts before copying and does not overwrite existing
  Markdown files unless `--force` is supplied. Import is not transactional after
  preflight: a write or reindex failure can leave already-copied Markdown files,
  so document recovery guidance in `docs/memory.md` when changing this path.

## Design rules

### Keep boundaries explicit

Preferred crate and trait boundaries:

- `opensymphony-domain`
- `opensymphony-workflow`
- `opensymphony-workspace`
- `opensymphony-linear`
- `opensymphony-openhands`
- `opensymphony-codex`
- `opensymphony-orchestrator`
- `opensymphony-control`
- `opensymphony-cli`
- `opensymphony-tui`
- `opensymphony-testkit`

Add new crates only when there is a clear ownership boundary.

OpenSymphony publishes as a single `opensymphony` crate. The `crates/opensymphony-*`
directories are internal source-module boundaries, not independently packaged
Cargo crates. They should be included from the root crate with `#[path = ...]`
module declarations and should not have their own `Cargo.toml` files or appear
as `[workspace].members` unless the user explicitly approves splitting the
project into multiple published packages.

### Prefer actor ownership over shared locks

The orchestrator should own mutable runtime state in one async task.

Use channels and message passing for worker reports, retries, and control-plane publication.

Avoid spreading `Arc<Mutex<...>>` through the daemon.

### Keep the WebSocket client resilient

The runtime client must:

- connect after conversation creation
- wait for readiness
- reconcile the REST event backlog
- deduplicate by event ID
- preserve timestamp order
- reconnect with bounded exponential backoff
- refresh cached state after reconnect

### Keep harness capability discovery public

- Public harness metadata belongs in `opensymphony-gateway-schema::capability::HarnessCapability` and the `/api/v1/capabilities` response.
- Use stable harness kind strings such as `openhands_agent_server`, `codex_app_server`, and `rust_native`; do not expose private adapter type names to clients.
- Concrete harness adapters should implement the domain `HarnessAdapter` capability boundary and keep OpenHands, Codex, or future in-process protocol details inside their adapter modules.
- Future or experimental harnesses may be advertised as unavailable capability entries, but their feature gaps must be explicit.
- When changing harness capability discovery, update gateway schema round-trip tests, the gateway capabilities endpoint test, adapter-boundary tests, and `docs/harness-adapter-compatibility.md`.

The local Codex app-server harness uses the `opensymphony_codex` internal module
boundary and is advertised as an available local stdio capability. Keep Codex
app-server launch, JSON-RPC lifecycle, event-normalization, generated-contract,
and benchmark evidence documented in `docs/codex-app-server-harness.md`. The old
`codex-app-server-prototype` Cargo feature has been removed; local stdio harness
capability must stay available in normal builds. Do not advertise hosted worker
pools, remote routing, or loopback WebSocket as production-ready until those
paths have their own hardening evidence.

### Preserve forward compatibility

OpenHands event schemas can evolve. Implement:

- typed decoding for known high-value events
- raw JSON retention for unknown events
- compatibility tests against the pinned version
- version notes in `docs/sources.md`

### Keep OKF memory compatibility local to memory

OKF bundle parsing, legacy capsule mapping, bundle-relative path validation, and
unknown frontmatter preservation belong in `opensymphony-memory`. Keep the
logical bundle layout and migration model documented in `docs/memory.md` and
`docs/specs/okf-memory-spec.md`. Do not move the durable `.opensymphony/memory/` store
to the final OKF layout unless a task explicitly includes that migration.

### Keep memory code intelligence AST-first and fallback-safe

`memory.context --include-code-intel` uses the Tree-sitter provider first for
supported requested Rust paths, then falls back to `CodebaseAnalyzer` for
unsupported languages, parser diagnostics, oversized files, and empty-path
repository summaries. Mixed supported and unsupported requests should keep both
AST evidence and fallback trace visibility without changing the public
`memory.context` contract. The memory MCP server may expose read-only
`code.ast.status`, `code.ast.outline`, `code.ast.symbols`,
`code.ast.references`, `code.ast.query`, `code.ast.context`, and
`code.ast.diagnostics` tools only when `code_intel.enabled` and
`code_intel.ast.enabled` are true. These tools are evidence APIs, not edit APIs:
keep path containment, file/match/capture limits, parser/query-pack/source
citations, and trace output intact. `code.ast.query` is local read-only by
default and becomes admin-gated whenever a memory admin token is configured.
The rendered code-intelligence provider trait and provider artifact types live in
`opensymphony_code_intel`; memory keeps its legacy `CodeIntelIndex` and
`CodeIntelArtifact` compatibility surface as an adapter around the provider
contract and converts provider errors for `memory.context`, but AST/composite
providers must not import memory internals.

### Separate Symphony hooks from OpenHands hooks

Symphony workspace hooks:

- `after_create`
- `before_run`
- `after_run`
- `before_remove`

These are owned by OpenSymphony.

OpenHands hook configuration such as `pre_tool_use` is a separate, optional agent runtime feature. Do not conflate them.

## Local safety posture

The local MVP is a trusted-environment mode.

- Expect host filesystem access.
- Expect host process execution.
- Do not overstate isolation.
- Harden later for hosted mode with remote or container-backed workspaces.
- Document risky defaults clearly in `README.md` and `docs/operations.md`.

## Coding standards

- Rust stable toolchain
- `cargo fmt` clean
- `clippy` clean under repo lints
- explicit error enums with context
- structured logs, not ad hoc print-only debugging
- `tokio` cancellation handled deliberately
- serde models for all external payloads
- integration code isolated inside `opensymphony-openhands`
- no direct OpenHands protocol types leaking into orchestrator core types

### Developer build acceleration

DuckDB is bundled by default so `cargo install opensymphony`, release builds,
and normal user builds do not require a separate system DuckDB installation.
For iterative OpenSymphony development on this macOS/Homebrew environment,
prefer the system-linked DuckDB aliases. They use the pinned Homebrew DuckDB
installation, currently DuckDB `1.5.3`, and avoid both bundled source
compilation and per-workspace download caches:

```bash
cargo check-system-duckdb
cargo test-system-duckdb
cargo test-system-duckdb --test memory
cargo clippy-system-duckdb
```

If system DuckDB is unavailable, fall back to the downloaded prebuilt aliases:

```bash
cargo check-dev
cargo test-dev
cargo clippy-dev
```

The system aliases set `DUCKDB_LIB_DIR`, `DUCKDB_INCLUDE_DIR`, and
`DYLD_LIBRARY_PATH` for the aliased command. The fallback aliases set
`DUCKDB_DOWNLOAD_LIB=1` for the aliased command. Both alias families run Cargo
with `--no-default-features --features duckdb-prebuilt`. `cargo fmt` is
unaffected because it does not compile dependencies. If a fallback command must
override `CARGO_TARGET_DIR`, use the default target directory or an absolute
path. Because the system aliases link whatever Homebrew exposes at
`/opt/homebrew/opt/duckdb`, verify `duckdb --version` is still the expected
`1.5.3` after any Homebrew upgrade or unpin before trusting system-linked test
results. Before release-sensitive, packaging, or dependency changes, also run the
default bundled-mode validation commands such as
`cargo clippy --all-targets -- -D warnings` and `cargo test`.

## Required tests by subsystem

### Workflow and config

- front matter parsing
- strict template rendering failure modes
- env indirection
- extension namespace validation
- path normalization

### Workspace

- identifier sanitization
- containment checks
- hook timeout handling
- create and reuse semantics
- terminal cleanup behavior

### OpenHands runtime

- conversation create payload
- event send and run trigger
- WebSocket readiness
- event reconciliation
- out-of-order event ordering
- reconnect and replay
- terminal `execution_status` detection
- conversation reuse and reset paths

### Orchestrator

- candidate sorting
- active vs terminal reconciliation
- bounded concurrency
- normal continuation retry
- failure backoff
- stall detection
- restart recovery

### Control plane and TUI

- snapshot derivation
- control-plane API serialization
- no daemon mutation from UI
- pane layout state
- log and event rendering

## Change-management rules

When changing behavior in any of these files, update the corresponding docs in the same change:

- `docs/architecture.md`
- `docs/configuration.md`
- `docs/openhands-agent-server.md`
- `docs/websocket-runtime.md`
- `docs/workspace-and-lifecycle.md`
- `docs/linear-and-tools.md`
- `docs/operations.md`
- `docs/testing-and-operations.md`

When changing milestones or task sequencing, update `docs/implementation-plan.md`.

When changing the pinned OpenHands assumptions, update `docs/sources.md`.

## File map

- `README.md`: project summary and implementation path
- `docs/architecture.md`: runtime architecture
- `docs/specs/symphony-spec-alignment.md`: upstream spec mapping
- `docs/openhands-agent-server.md`: agent-server integration choices
- `docs/codex-app-server-harness.md`: local Codex app-server stdio harness,
  launch contract, JSON-RPC lifecycle evidence, and benchmark results
- `docs/websocket-runtime.md`: wire contract and recovery behavior
- `docs/workspace-and-lifecycle.md`: workspace ownership and hooks
- `docs/linear-and-tools.md`: Linear integration and GraphQL helper assets
- `docs/memory.md`: project memory capture, DuckDB indexing, documentation sync,
  and archive guard design
- `docs/code-intelligence.md`: agent and operator workflow for AST-backed code
  intelligence
- `docs/ui-frankentui.md`: operator UI design
- `docs/repository-layout.md`: crate ownership
- `docs/deployment-modes.md`: local MVP and hosted follow-on
- `docs/installer-and-distribution.md`: future signed installer, component
  selection, update, and DuckDB runtime packaging strategy
- `docs/configuration.md`: target repo bootstrap and runtime config
- `docs/operations.md`: doctor, rehydration, diagnostics, packaging, and local ops
- `docs/testing-and-operations.md`: test strategy and validation layers
- `docs/tasks/`: issue-ready implementation work items

---

## AI PR Review Overlay

This repository uses an automated AI PR review system. The active provider is
recorded under `Automated AI PR review` in `WORKFLOW.md`: the OpenHands PR
Review plugin (current) or Codex code review (see
`docs/codex-code-review-setup.md`).

### How it works

- OpenHands provider: the `.github/workflows/ai-pr-review.yml` workflow runs
  on PR events using the OpenHands PR review plugin with repository-specific
  guidance
- Codex provider: the Codex GitHub integration reviews PRs on open and on an
  exact `@codex review` comment, applying the `## Review guidelines` guidance
  in the closest `AGENTS.md`
- Reviews focus on correctness, security, and maintainability
- The AI reviewer is **advisory only** and does not count as a human approval

### Repository-specific review guidance

The `.agents/skills/custom-codereview-guide.md` file contains project-specific rules:

- Async/concurrency safety (locks, cancellation, blocking operations)
- Error handling patterns (explicit enums, context-rich errors)
- Workspace safety (path containment, sanitization)
- WebSocket resilience (reconnect, reconciliation)
- State machine correctness
- Forward compatibility (serde patterns)
- Testing requirements

### Evidence requirements

Substantive PRs should include an `Evidence` section showing:
- Test output for behavior changes
- Benchmarks for performance changes
- Usage examples for new features
- Reproduction case and verification for bug fixes

### Triggering review

With the OpenHands provider, the AI review runs automatically on:
- PR opened (non-draft, same-repo)
- PR synchronized (new commits)
- PR marked ready for review
- `review-this` label added

To manually retrigger, add the `review-this` label.

With the Codex provider, the initial review runs automatically on PR open;
retrigger by posting a comment that is exactly `@codex review`. Never mention
`@codex` with any other text (it starts a cloud task billed to general Codex
usage, outside the orchestration), and never ask Codex to fix or push changes.