diff --git a/Cargo.lock b/Cargo.lock
index 33ba4022f..e6fa472ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2506,7 +2506,7 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "opensymphony"
-version = "2.11.3"
+version = "3.0.0"
dependencies = [
"agent-client-protocol",
"agent-client-protocol-schema",
diff --git a/Cargo.toml b/Cargo.toml
index 958b607a1..52a1d6b8f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -83,7 +83,7 @@ edition = "2024"
license = "MIT"
repository = "https://github.com/kumanday/OpenSymphony"
rust-version = "1.97.1"
-version = "2.11.3"
+version = "3.0.0"
[workspace.lints.rust]
rust_2018_idioms = { level = "warn", priority = -1 }
diff --git a/README.md b/README.md
index a9bbfd405..9a81de415 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# OpenSymphony
-OpenSymphony is a Rust implementation of the [OpenAI Symphony](https://github.com/openai/symphony) specification for orchestrating AI coding agents. It connects to [Linear](https://linear.app) for issue tracking and can run issues through either the managed [OpenHands](https://github.com/OpenHands/OpenHands) agent-server or the local Codex app-server harness.
+OpenSymphony is a Rust implementation of the [OpenAI Symphony](https://github.com/openai/symphony) specification for orchestrating AI coding agents. It connects to [Linear](https://linear.app) for issue tracking and runs issues through the managed [OpenHands](https://github.com/OpenHands/OpenHands) agent-server, the local Codex app-server, or a local ACP v1 agent.

@@ -10,18 +10,19 @@ OpenSymphony automates software development workflows by:
1. **Polling Linear** for issues in active states (Todo, In Progress, etc.)
2. **Creating isolated workspaces** for each issue with lifecycle hooks
-3. **Dispatching AI agents** via OpenHands or Codex to work on issues autonomously
+3. **Dispatching AI agents** through OpenHands, Codex, or a configured ACP profile
4. **Managing retries, reconciliation, and cleanup** based on issue state changes
5. **Providing a desktop operator dashboard** for task graph, run detail, and memory navigation
### Key Features
- **Hierarchy-aware scheduling**: Parent issues wait for sub-issues to complete
-- **WebSocket-first runtime**: Real-time agent updates with REST reconciliation
+- **Multi-repository projects**: Repository-bound sub-issues run in their own checkouts; an unlabeled parent checks their merged work
+- **Live runtime updates**: OpenHands uses WebSocket with REST reconciliation; Codex and ACP use local stdio
- **Per-issue workspaces**: Deterministic, isolated directories with lifecycle hooks
-- **GraphQL-only Linear integration**: Agent-side Linear reads and writes through checked-in helper/query assets
+- **GraphQL-only Linear integration**: The scheduler polls Linear; agent-side writes use checked-in helper/query assets
- **Dependency-aware Task Graph**: Shows dispatchable work, roadmap backlog, and selected-task critical paths
-- **Harness selection**: Default OpenHands agent-server execution, plus local Codex app-server support for ChatGPT subscription-backed runs
+- **Harness selection**: OpenHands, local Codex app-server, or a configured ACP v1 stdio agent
- **Code Graph**: Tree-sitter-backed symbols, diagnostics, and source-cited structural context for agents
- **Operational Knowledge Graph**: Builds agent-queriable and human-navigable memory from completed work
@@ -29,6 +30,11 @@ OpenSymphony `1.0.0` is the compatibility boundary for the GraphQL-only Linear
rewrite. See [Migration Guide](docs/migration-1.0.0.md) if you are upgrading an
older setup.
+Version 3.0.0 adds explicit multi-repository project routing and production
+ACP worker profiles. Existing single-repository workflows remain available.
+See the [3.0 upgrade guide](docs/migration-3.0.0.md) before selecting a new
+routing mode or harness.
+
Packaging note: crates.io exposes a single public package, `opensymphony`.
Internally, the repo still keeps clear subsystem boundaries under
`crates/opensymphony-*`, but those directories are now internal module trees,
@@ -216,6 +222,15 @@ cd /path/to/target-repo
opensymphony run
```
+For a central configuration in another location, pass
+`--config /absolute/path/to/config.yaml` to `opensymphony run`.
+The default single-repository workflow needs no multi-repository labels.
+For a project spanning several repositories, follow the
+[multi-repository guide](docs/multi-repository.md). To run a local ACP agent,
+follow the [ACP harness guide](docs/acp.md). Repository routing and harness
+selection are independent: an ACP profile can run a child bound to one
+repository in a multi-repository project.
+
For real-time monitoring while the orchestrator is running, run the TUI in a separate terminal window:
```bash
opensymphony tui
@@ -335,10 +350,11 @@ flowchart TB
orchestrator["Orchestrator Scheduler"]
workspace["Workspace Manager"]
control["Gateway + Control API
GET /healthz, /api/v1/snapshot, /api/v1/capabilities"]
- runtime["Harness Runtime Client
OpenHands REST/WebSocket or Codex stdio"]
+ runtime["Harness Runtime Client"]
linear_read["Linear Read Adapter"]
+ routing["Repository binding and parent integration"]
- orchestrator --> workspace
+ orchestrator --> routing --> workspace
orchestrator --> runtime
orchestrator --> linear_read
orchestrator --> control
@@ -357,13 +373,19 @@ flowchart TB
linear["Linear"]
openhands["OpenHands Agent-Server"]
codex["Codex App-Server"]
+ acp["Local ACP v1 agent"]
+ config["Central project set and harness profiles"]
operator --> control
+ config --> routing
+ config --> runtime
workspace --> issue_ws
runtime --> openhands
runtime --> codex
+ runtime --> acp
openhands --> agent
codex --> agent
+ acp --> agent
linear_read -->|read issues| linear
graphql -->|agent-side writes| linear
```
@@ -517,11 +539,14 @@ OPENSYMPHONY_LIVE_OPENHANDS=1 ./scripts/live_e2e.sh
- [Architecture](docs/architecture.md) - High-level design and component interactions
- [Configuration](docs/configuration.md) - Target repo bootstrap and runtime config
+- [Multi-repository projects](docs/multi-repository.md) - Repository labels, parent integration, and rollout
+- [ACP harness](docs/acp.md) - Local agent profiles, operator requests, and recovery
- [Deployment Modes](docs/deployment-modes.md) - Local vs hosted deployment
- [Installer and Distribution Strategy](docs/installer-and-distribution.md) - Future signed installer shape and DuckDB packaging boundaries
- [Operations](docs/operations.md) - Doctor, rehydration, diagnostics, and local ops
- [Testing](docs/testing-and-operations.md) - Test strategy and validation layers
- [Migration Guide](docs/migration-1.0.0.md) - Breaking changes and upgrade steps for 1.0.0
+- [3.0 upgrade guide](docs/migration-3.0.0.md) - Moving from single-repository workflows and selecting ACP
- [AGENTS.md](AGENTS.md) - Repository guidelines for coding agents
- [Development Guide](docs/DEVELOPMENT.md) - Contributing and development details
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index c27a7aaf2..96de2095a 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -1,6 +1,6 @@
{
"name": "@opensymphony/desktop",
- "version": "2.11.3",
+ "version": "3.0.0",
"description": "OpenSymphony Tauri desktop app shell",
"type": "module",
"private": true,
diff --git a/apps/desktop/src-tauri/Cargo.lock b/apps/desktop/src-tauri/Cargo.lock
index f62ccc9ff..a525103c5 100644
--- a/apps/desktop/src-tauri/Cargo.lock
+++ b/apps/desktop/src-tauri/Cargo.lock
@@ -2501,7 +2501,7 @@ dependencies = [
[[package]]
name = "opensymphony-desktop"
-version = "2.11.3"
+version = "3.0.0"
dependencies = [
"chrono",
"directories",
diff --git a/apps/desktop/src-tauri/Cargo.toml b/apps/desktop/src-tauri/Cargo.toml
index 112985ebd..1b81df017 100644
--- a/apps/desktop/src-tauri/Cargo.toml
+++ b/apps/desktop/src-tauri/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "opensymphony-desktop"
-version = "2.11.3"
+version = "3.0.0"
description = "OpenSymphony Tauri desktop application shell"
license = "MIT"
homepage = "https://opensymphony.dev"
diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json
index 2a3b03542..45cb9cf91 100644
--- a/apps/desktop/src-tauri/tauri.conf.json
+++ b/apps/desktop/src-tauri/tauri.conf.json
@@ -1,7 +1,7 @@
{
"productName": "OpenSymphony",
"mainBinaryName": "OpenSymphony",
- "version": "2.11.3",
+ "version": "3.0.0",
"identifier": "dev.opensymphony.app",
"build": {
"beforeDevCommand": "npm run dev",
diff --git a/docs/acp.md b/docs/acp.md
index cb42eaeb8..70c24d987 100644
--- a/docs/acp.md
+++ b/docs/acp.md
@@ -5,7 +5,94 @@ visibility: public
last_memory_sync: 2026-09-22T11:51:20.924956+00:00
---
-# Acp
+# ACP harness
+
+ACP is a way to run an agent that speaks Agent Client Protocol v1 over a local
+stdio process. OpenSymphony still owns issue scheduling, workspaces, retries,
+and operator decisions. The agent process works inside the issue's checkout.
+ACP is an execution choice: it can run a single-repository issue or a child in
+a [multi-repository project](multi-repository.md).
+
+```mermaid
+sequenceDiagram
+ participant S as OpenSymphony scheduler
+ participant H as ACP session host
+ participant A as Local ACP agent
+ participant O as Operator client
+ S->>H: Start turn in the issue checkout
+ H->>A: initialize, session/new, session/prompt
+ A-->>H: Updates and optional permission request
+ H-->>S: Bound run events and pending request
+ S-->>O: Run detail and request options
+ O->>S: Answer for the current run
+ S->>H: Deliver bound answer
+ H->>A: ACP callback response
+ A-->>H: Prompt result
+ H-->>S: Outcome and retained session state
+```
+
+## Configure a local agent
+
+Install the agent's CLI and complete its own login first. Then add a named
+profile to the selected central config. This excerpt assumes the rest of the
+instance and tracker configuration already exists:
+
+```yaml
+routing:
+ harness: acp
+ harness_profile: cursor
+acp:
+ profiles:
+ cursor:
+ command: /absolute/path/to/agent
+ args: [acp]
+ transport: stdio
+ protocol_versions: [1]
+ permissions:
+ mode: operator
+```
+
+`routing.harness_profile` chooses a profile ID; the ID is not a vendor switch
+in the scheduler. Use an absolute executable path and literal arguments. If
+the agent needs environment credentials, map target names to source variable
+names under `env_refs`; do not put values in the file or arguments. Omit
+`auth` when the CLI's existing login is sufficient. An explicit `auth.method_id`
+must be advertised by the agent.
+
+With `permissions.mode: operator`, a live TUI, web, or desktop client must be
+available to answer permission requests. `deny` selects an offered one-time
+rejection; `allow_once` selects an offered one-time approval for a trusted
+unattended profile. Unsupported options are cancelled rather than guessed.
+See [ACP profile configuration](configuration.md#acp-stdio-profiles) for session
+model/mode/options, host services, MCP attachments, deadlines, and extension
+registration.
+
+Run `opensymphony run --config ` after selecting the profile. A profile
+preflight checks the executable and configuration; the live session negotiates
+authentication, persistence, modes, options, and optional methods. Inspect
+`/api/v1/capabilities` and the active run detail before offering an operation
+to an operator. A profile entry alone does not mean that an optional method is
+available.
+
+## Sessions, recovery, and vendor support
+
+The session host retains an idle agent process for compatible later turns.
+Recovery loads or resumes a known session only when the peer advertised the
+method. If a prompt might have been submitted before a disconnect, the run is
+fenced for reconciliation; OpenSymphony does not resend that prompt blindly.
+Cancel acknowledgement follows a matching stopped prompt result. The
+[operations guide](operations.md#acp-client-validation-and-limits) describes
+limits and recovery diagnostics.
+
+The [live qualification report](acp-live-qualification.md) records tracked
+issue runs through pinned Cursor and Devin CLIs. Both advertised
+`session/load`; neither advertised `session/resume` in that qualification.
+Cursor's registered plan and todo methods are limited to its observed pinned
+version. Generic ACP v1 profiles do not inherit those vendor methods.
+
+ACP agents are local processes with trusted host access. Choose the executable,
+credentials, and permission policy accordingly. The process runs with its
+current directory set to the issue workspace.
diff --git a/docs/architecture.md b/docs/architecture.md
index 1c3dc1a3e..823f11ec3 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -2,14 +2,17 @@
## 1. Objective
-Implement the Symphony orchestration model in Rust while using OpenHands as the
-execution substrate and FrankenTUI as an optional operator client.
+Implement the Symphony orchestration model in Rust. The scheduler can use the
+OpenHands agent-server, the local Codex app-server, or a configured local ACP
+v1 agent for execution. FrankenTUI is an optional operator client.
The system must preserve these boundaries:
- the orchestrator is the source of truth for scheduling state
- the tracker is polled and reconciled by the orchestrator
-- each issue executes in its own workspace
+- each repository-bound work issue executes in its own checkout
+- a multi-repository parent uses a separate integration workspace after its
+ children merge
- `WORKFLOW.md` remains the repo-owned policy and prompt contract
- UI is optional and must not affect correctness
@@ -43,7 +46,7 @@ OpenSymphony is split into five layers:
2. Configuration layer
- typed workflow/config loader
- env and path resolution
- - OpenHands extension config
+ - project sets, repository inventory, and harness profiles
3. Coordination layer
- orchestrator actor
- retry queue
@@ -54,6 +57,7 @@ OpenSymphony is split into five layers:
- OpenHands REST client
- OpenHands WebSocket runtime stream
- local Codex app-server stdio adapter
+ - local ACP v1 stdio session host
- issue session runner
5. Observability layer
- structured logs
@@ -67,6 +71,10 @@ Packaging distinction:
- the `crates/opensymphony-*` directories are internal module trees compiled
into that one package
+Start with the [multi-repository guide](multi-repository.md) for issue binding
+and parent integration, or the [ACP guide](acp.md) for local agent setup and
+operator requests. The two choices are independent.
+
## 3. Main decisions
### 3.1 Rust owns orchestration
@@ -92,7 +100,7 @@ including when a subtree no longer requires merge evidence. Reopening or
recovering nonterminal work invalidates its durable success receipt before
batched launch preparation.
-Repository routing is also orchestrator-owned: terminal child metadata carries
+Repository routing is also orchestrator-owned: repository-bound child metadata carries
one alias, the central inventory resolves it to a canonical provider identity,
and the scheduler persists that identity plus its config and inventory
generations before claiming work. Project associations are validation scope,
@@ -247,7 +255,7 @@ The completed cleanup intent remains in orchestrator state after the parent root
is removed and seeds automatic-capture completion after daemon restart, so a
terminal parent is not routed and captured again without first reopening.
-### 3.2 OpenHands is the execution adapter
+### 3.2 OpenHands adapter
OpenHands provides:
@@ -260,7 +268,7 @@ OpenHands provides:
OpenSymphony does not reimplement an agent loop.
-### 3.3 WebSocket-first, not WebSocket-only
+### 3.3 OpenHands uses WebSocket and REST
REST is still required for:
@@ -271,7 +279,7 @@ REST is still required for:
- reconnect reconciliation
- restart recovery
-### 3.4 One local server, many workspaces
+### 3.4 One local OpenHands server, many workspaces
The local supervised topology runs one OpenHands server for the daemon while
passing a distinct `working_dir` per issue.
@@ -370,7 +378,7 @@ relations, attachments, project content/status updates, and introspection.
## 5. Process model
-Local MVP process graph:
+Local process graph when an OpenHands route is selected:
```text
opensymphony run
@@ -380,16 +388,21 @@ opensymphony run
├─ openhands REST client
├─ openhands WebSocket client
├─ optional Codex app-server stdio worker
+ ├─ optional ACP v1 stdio session host
├─ gateway API
├─ control-plane compatibility API
└─ local server supervisor
└─ python -m openhands.agent_server
```
+An ACP-only or Codex-only run does not launch the OpenHands server.
+
The scheduler attaches a `HarnessRouteDecision` to each worker start request.
The default route remains `openhands_agent_server`. Workflow `routing.harness`
or the `OPENSYMPHONY_HARNESS` environment override can select the local
-`codex_app_server` route when that harness is available and can start runs.
+`codex_app_server` or `acp` route when configured and available. ACP also
+requires a named `routing.harness_profile`; the scheduler binds the selected
+profile to each prepared run.
Route decisions are emitted as `routing.decision` runtime audit events so dry-run
previews and real dispatches show the selected harness, model, and model
profile.
diff --git a/docs/configuration.md b/docs/configuration.md
index bde506435..31578de62 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -3,6 +3,11 @@
This document covers target-repo bootstrap, generated files, and the runtime
configuration that `opensymphony run` expects.
+For a first multi-repository setup, read [multi-repository projects](multi-repository.md)
+before the field reference below. For a local ACP agent, start with the
+[ACP harness guide](acp.md). Repository routing and harness selection are
+independent choices in the same selected config.
+
Operator projections expose project and repository identity through safe
aliases, canonical IDs, and safe remote fingerprints. Credential-bearing
remote URLs and raw credential values are excluded.
diff --git a/docs/migration-3.0.0.md b/docs/migration-3.0.0.md
new file mode 100644
index 000000000..26bb738ee
--- /dev/null
+++ b/docs/migration-3.0.0.md
@@ -0,0 +1,61 @@
+# Upgrading to OpenSymphony 3.0.0
+
+OpenSymphony 3.0.0 adds multi-repository project routing and local ACP v1
+worker profiles. Both are explicit choices. An existing single-repository
+workflow can continue with `legacy_single` routing and its current harness.
+
+## Before upgrading
+
+1. Stop `opensymphony run` and keep the existing `WORKFLOW.md`, `config.yaml`,
+ workspace root, and memory store until the new run has been checked.
+2. Install 3.0.0 with Rust 1.97.1 or newer. Run `opensymphony doctor` in the
+ target repository to check its local prerequisites.
+3. If you want a central configuration, run the read-only migration preflight,
+ review its findings, and then apply the migration:
+
+ ```bash
+ opensymphony migrate preflight --repo /path/to/target-repo \
+ --output /absolute/path/to/config.yaml
+ opensymphony migrate apply --repo /path/to/target-repo \
+ --output /absolute/path/to/config.yaml
+ ```
+
+ The generated central config starts with the compatible single-repository
+ route. Run `opensymphony run --config /absolute/path/to/config.yaml` to
+ select it explicitly. [Configuration migration](configuration.md#configuration-migration)
+ describes the backup, activation marker, and rollback checks.
+
+## Enable multi-repository routing
+
+Add an active project set, repository inventory, credentials, and review
+profiles to the central config. Set `routing.mode: project_set` only after
+every implementation sub-issue has exactly one valid `repo:` label and
+its parent has no repository label. Keep repository-specific instructions in each
+checkout and integration instructions in the project set. Follow the
+[multi-repository guide](multi-repository.md) for the run flow and the
+[configuration model](configuration.md#central-configuration) for the full
+schema.
+
+Before enabling a non-production project set, pass the
+[hermetic and disposable live gate](multi-repository-rollout.md) at the same
+clean commit and selected config hash. That gate leaves production activation
+to a separate operator decision.
+
+## Select an ACP agent
+
+ACP changes execution, not repository binding. Install and sign in to a local
+ACP v1 CLI, configure a named stdio profile, and select it with
+`routing.harness: acp` and `routing.harness_profile`. The
+[ACP guide](acp.md) shows a profile and explains operator permission handling.
+The negotiated live session determines optional features such as persistence,
+model choices, and vendor extensions.
+
+## Roll back a migrated configuration
+
+Stop the strict-config instance first. `opensymphony migrate rollback --config
+/absolute/path/to/config.yaml` restores the backed-up legacy files only when
+the strict-run marker is absent and the migrated memory catalog has not changed
+since migration. Preserve the state, workspaces, manifests, and receipts for
+any run that has not reached a terminal state. See
+[migration recovery](configuration.md#configuration-migration) for the
+specific refusal conditions.
diff --git a/docs/multi-repository-rollout.md b/docs/multi-repository-rollout.md
index 3fe009957..ff24eab77 100644
--- a/docs/multi-repository-rollout.md
+++ b/docs/multi-repository-rollout.md
@@ -1,5 +1,9 @@
# Multi-repository release gate and isolated rollout
+This is the validation procedure for the
+[multi-repository project guide](multi-repository.md). Start there for issue
+labels, repository inventory, and parent integration.
+
Strict multi-repository routing stays disabled for production projects until the
hermetic gate and one disposable non-production run pass at the same immutable
commit, with each selected central config identified by its SHA-256.
diff --git a/docs/multi-repository.md b/docs/multi-repository.md
new file mode 100644
index 000000000..e8e97ed76
--- /dev/null
+++ b/docs/multi-repository.md
@@ -0,0 +1,94 @@
+# Multi-repository projects
+
+OpenSymphony can run one Linear project across several source repositories.
+Each implementation sub-issue names one repository with a `repo:` label.
+Its parent has no repository label: it waits for the sub-issues to merge, then
+checks their combined result in a separate integration workspace.
+
+The single-repository setup still works. Multi-repository routing is an explicit
+choice in the central configuration, and each project set lists the projects
+and repositories it may use. [Configuration](configuration.md) defines the
+complete file format and [migration](migration-3.0.0.md) covers existing
+installations.
+
+For example, a project with a `core` repository and a `web` repository can
+have a core child labeled `repo:core`, a web child labeled `repo:web`, and an
+unlabeled parent that checks their merged work together. The aliases come
+from the central repository inventory.
+
+```mermaid
+flowchart LR
+ L["Linear project and issue hierarchy"] --> R["OpenSymphony scheduler"]
+ C["Central project set and repository inventory"] --> R
+ R -->|"repo:core"| A["Child checkout: core"]
+ R -->|"repo:web"| B["Child checkout: web"]
+ A --> M["Verified child merges"]
+ B --> M
+ M --> P["Parent integration workspace"]
+ P --> V{"Integration checks pass?"}
+ V -->|yes| D["Capture memory and release workspaces"]
+ V -->|repair needed| F["One affected-repository repair PR"]
+ F --> P
+```
+
+## Set up a project set
+
+1. Give the instance its own state and workspace roots in the central config.
+ Select `routing.mode: project_set`, an `active_project_set`, and a tracker
+ profile.
+2. Add each Linear project under `linear_projects` with its provider project
+ ID and allowed repository aliases. Add each repository once under
+ `repositories`, with its canonical provider ID, remote, target branch,
+ checkout credential reference, review profile, and contained instruction
+ path. The [configuration model](specs/multi-repo-orchestration-spec.md#8-configuration-model)
+ shows how these sections fit together. Keep credential values in environment
+ variables referenced by `credentials`.
+3. Label every implementation sub-issue with exactly one managed
+ `repo:` label. Use an alias allowed by its Linear project. Leave
+ parent issues unlabeled. A missing, duplicate, unknown, or out-of-scope
+ binding is shown as a routing blocker; OpenSymphony does not choose a
+ repository from the current directory.
+4. Put repository-specific instructions in each checkout's configured file,
+ such as `AGENTS.md`. Put instructions for checking the combined result in
+ the project set's `integration_instructions` file. The parent sees each
+ repository's instructions in a separate section.
+
+Start the configured instance with `opensymphony run --config `. The
+selected config's hash appears in startup diagnostics and its first
+control-plane event.
+
+For an existing single-repository installation, run `opensymphony migrate
+preflight --repo ` before `migrate apply`. Review the generated central
+config and keep `legacy_single` until the repository inventory, labels, and
+project set are ready. Migration does not enable `project_set` by itself.
+
+## What happens during a run
+
+OpenSymphony resolves an issue's repository binding before it creates a
+workspace. A child runs in a verified checkout of its bound repository. The
+scheduler records the selected config and repository inventory generations so
+recovery cannot silently move an in-flight issue to another repository. A
+binding change stops the old worker and prepares a new generation.
+
+When all children have provider-confirmed merges, the parent uses retained
+child generations to prepare contained worktrees. It runs the configured
+integration checks, can open a repair PR in one affected repository, and then
+refreshes and verifies the combined result. Terminal cleanup waits for memory
+capture and releases worktrees and leases from the leaves upward. The
+[workspace lifecycle](workspace-and-lifecycle.md) explains the ownership and
+recovery rules in detail.
+
+## Roll out safely
+
+Strict multi-repository routing remains an explicit operator choice. Before
+enabling it for a project set, run the [hermetic release gate and disposable
+live rollout](multi-repository-rollout.md) at one clean commit and record the
+selected config hash. The live gate exercises child PRs, a failed check and
+same-PR repair, parent verification and repair, and complete teardown in a
+non-production project set. Production activation requires a separate
+operator decision.
+
+The desktop and web task graphs show the repository binding and parent
+blockers. Run detail shows the selected repository, checkout generation,
+integration state, and repair evidence. The gateway exposes the same facts
+without credential-bearing remote URLs.
diff --git a/docs/operations.md b/docs/operations.md
index c5e47354f..318e030f1 100644
--- a/docs/operations.md
+++ b/docs/operations.md
@@ -1,5 +1,10 @@
# Operations
+For first-time multi-repository setup, use the
+[multi-repository guide](multi-repository.md). For a local ACP agent, use the
+[ACP harness guide](acp.md). This page covers the detailed commands and
+failure handling after the route is configured.
+
This document covers the current local operator workflow for OpenSymphony.
Run detail and TUI projections expose sanitized repository, target commit,
diff --git a/docs/release.md b/docs/release.md
index 126867ce1..62844977a 100644
--- a/docs/release.md
+++ b/docs/release.md
@@ -160,6 +160,40 @@ last_memory_sync: 2026-07-04T03:35:18.210566+00:00
- COE-615
+
+## 3.0.0 multi-repository and ACP release boundary
+
+Version 3.0.0 includes explicit `project_set` routing and a production local
+ACP v1 worker route. Existing `legacy_single` routing remains available. The
+[multi-repository guide](multi-repository.md), [ACP guide](acp.md), and
+[3.0 upgrade guide](migration-3.0.0.md) explain selection and recovery for
+operators new to these paths.
+
+Before shipping the multi-repository route for a project set, run
+`scripts/hermetic_multi_repo_lifecycle.sh` against the selected config at a
+clean commit, then run the opt-in disposable live gate. Record the same commit
+and selected config SHA-256 in both artifacts, verify exact-head CI, and check
+that teardown left no disposable resources. The procedure and bounded rollout
+conditions are in [multi-repository rollout](multi-repository-rollout.md).
+
+Before claiming an ACP vendor profile is qualified, check the executable
+version and login, then run the authenticated tracked-issue and restoration
+tests in [ACP live qualification](acp-live-qualification.md). Profile preflight
+alone does not prove authentication or optional protocol support. The pinned
+Cursor and Devin runs qualified `session/load`; neither advertised
+`session/resume` in that run.
+
+Keep the root crate, desktop package, Tauri metadata, and both Cargo lockfiles
+at `3.0.0`. The root `package-lock.json` must record the desktop package at
+the same version. Run the default bundled-mode Clippy and tests, frontend
+build, and the desktop parity guard before tagging or publishing:
+
+```bash
+npm run package:release --workspace=@opensymphony/desktop -- --dry-run
+```
+
+The dry run checks desktop version parity without writing release assets.
+
## 2.11 Rust toolchain boundary
OpenSymphony 2.11.0 requires Rust 1.97.1 for the root CLI and desktop crate and
diff --git a/package-lock.json b/package-lock.json
index d13c177b7..0ff608d82 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,7 +23,7 @@
},
"apps/desktop": {
"name": "@opensymphony/desktop",
- "version": "2.11.3",
+ "version": "3.0.0",
"dependencies": {
"@opensymphony/api-client": "*",
"@opensymphony/gateway-schema": "*",