Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2196e60
tui: strip terminal colour codes from agent replies; indent wrapped n…
crossben Sep 25, 2026
37f3415
tui: scroll long answers with the mouse wheel and arrow keys
crossben Sep 25, 2026
dc01d47
tui: show a resize hint in windows smaller than 60x12
crossben Sep 25, 2026
1d8a17b
docs: design spec for git-free parallel do and benchmark
crossben Sep 26, 2026
96e9eb8
router: direct API classifier
crossben Sep 26, 2026
1a459b5
worktree: add Isolator interface and a copy isolator for plain folders
crossben Sep 26, 2026
7741ecf
router: history-aware agent resolution
crossben Sep 26, 2026
5b742dd
llm/agent/config: report token usage and config-priced cost for API a…
crossben Sep 26, 2026
8b6b50f
Merge router v2: direct API classifier + history-aware routing
crossben Sep 26, 2026
fc54617
docs: spec for the self-updater
crossben Sep 26, 2026
45fd73c
update: check GitHub Releases and replace the binary in place
crossben Sep 26, 2026
baee299
cli: offer updates on launch and add `orchestra update`
crossben Sep 26, 2026
910f00c
docs: document updating and the updater's release-asset contract
crossben Sep 26, 2026
646d854
Merge self-updater: launch check + orchestra update
crossben Sep 26, 2026
6afd439
do --parallel, benchmark: run outside git repositories
crossben Sep 26, 2026
3e92473
docs: parallel and benchmark work in plain folders
crossben Sep 26, 2026
5dd3b41
engine/memory: sum usage across attempts and persist tokens/cost
crossben Sep 26, 2026
23f25b5
cli: default version to dev so local builds never self-update
crossben Sep 26, 2026
7e9b107
Merge git-free do --parallel and benchmark (copy isolator)
crossben Sep 26, 2026
cf781c0
fsdiff: fingerprint oversized files so unchanged ones don't diff
crossben Sep 26, 2026
6ecf849
history/benchmark/tui: show tokens and cost
crossben Sep 26, 2026
dd6d4c3
docs: document API-agent token tracking and price fields
crossben Sep 26, 2026
84b08d7
Merge token and cost tracking for API agents
crossben Sep 26, 2026
9406dbc
docs: AGENTS.md and plan.md for router v2, git-free parallel, usage, …
crossben Sep 26, 2026
f8940cb
parallel: extract shared wave logic from do --parallel
crossben Sep 26, 2026
eb3416b
tui: /parallel runs in the dashboard chat
crossben Sep 26, 2026
4885395
Merge /parallel runs in the dashboard
crossben Sep 26, 2026
94ea4ba
tui: record token usage for /parallel tasks
crossben Sep 26, 2026
6a5ddab
worktree: serialise Manager.Add and Cleanup
crossben Sep 26, 2026
6829bbf
docs: dashboard /parallel and internal/parallel
crossben Sep 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ Binary is at `bin/orchestra` (gitignored).
- `cmd/orchestra/` — Cobra CLI (main.go + one file per subcommand: run, do, plan, dashboard, agents, etc.)
- `internal/engine/` — the core supervised loop (dispatch → validate → retry → review). Every front door (`run`, shell, `do`) drives this.
- `internal/agent/` — Agent interface + registry. This is the extension point for adding new agents.
- `internal/router/` — AI routing: classifies intent → picks agent. Uses a CLI agent now; API planned.
- `internal/router/` — AI routing: classifies intent → picks agent. CLI classifier by default; optional direct-API classifier (`router.classifier`); history-aware agent resolution via the `History` interface.
- `internal/planner/` — decomposes requests into ordered steps with `depends_on` for parallelism.
- `internal/scheduler/` — bounded-concurrency DAG runner for parallel worktrees.
- `internal/worktree/` — git worktree isolation (branch per task, merge + conflict detection).
- `internal/scheduler/` — bounded-concurrency DAG runner for parallel isolated tasks.
- `internal/parallel/` — shared plan → waves → isolated task logic (`Graph`, `BaseGuard`, `RunStep`) used by `do --parallel` and the dashboard's `/parallel`.
- `internal/worktree/` — task isolation behind the `Isolator` interface: `worktree.New(dir)` picks git worktrees in a repository (branch per task, merge + conflict detection) or a `CopyIsolator` in plain folders (temp copy per task, all-or-nothing merge, conflict if a touched file changed in the source).
- `internal/validate/` — build → lint → test pipeline, auto-detects toolchain, stops on first failure.
- `internal/config/` — YAML config + built-in agent defaults + toolchain auto-detection.
- `internal/memory/` — SQLite history at `~/.orchestra/orchestra.db` (never in the repo tree).
- `internal/memory/` — SQLite history at `~/.orchestra/orchestra.db` (never in the repo tree): runs, diffs, benchmarks, tokens/cost, and the per-directory agent scores the router uses.
- `internal/update/` — self-updater: checks GitHub Releases (throttled to once per 24h), verifies `checksums.txt`, swaps the binary in place. Relies on the GoReleaser archive name template — see docs/RELEASING.md.
- `internal/tui/` — Bubble Tea dashboard: Chat (live run panel + file-by-file review), Changes, History, Agents, Benchmarks, Logs. One file per concern (chat, live, review, views, chrome, theme, table).
- `internal/ui/` — terminal styling (gradients, spinners, diffs). TTY-aware.
- `internal/shell/` — interactive chat REPL.
Expand Down Expand Up @@ -75,7 +77,8 @@ dispatch → validate → retry (self-correct) → review (accept/reject)
Git is optional. Inside a repository, diffs and rejects use git and the tree must start clean
(reject does `git restore`). Outside one — like opencode or claude — the engine snapshots the
directory first (`internal/fsdiff`), diffs against that snapshot, and restores from it on reject;
accept just keeps the files. `--parallel` and `benchmark` still require a repository (worktrees).
accept just keeps the files. `--parallel` and `benchmark` work in both: worktrees inside a repository,
per-task directory copies (`worktree.CopyIsolator`) outside one.

If you change validation or retry logic, you change all three entry points. The engine is the product — not the CLI or the TUI.

Expand Down Expand Up @@ -124,9 +127,11 @@ Live runs: the dashboard calls `engine.Produce` with `OnEvent` (attempt / agent-

These are not interchangeable with other TUI frameworks. Tests are headless (`tui_test.go` renders views without a TTY by injecting `WindowSizeMsg`); end-to-end chat tests drive the real worker with fake-agent shell scripts.

## Router is CLI-based
## Router

The AI router (`internal/router/`) classifies intent by dispatching to an agent in query mode (e.g. `claude -p`), not by calling an LLM API itself. It inherits agent CLI quirks: needs `--dangerously-skip-permissions`, uses the same `runner` package, and the classification latency is whatever the agent takes. Since `APIAgent` also implements `Querier`, an api-type agent can serve as the router's classifier today; a dedicated direct-API classifier inside `internal/router` remains planned but unimplemented.
By default the AI router (`internal/router/`) classifies intent by dispatching to an agent in query mode (e.g. `claude -p`). That inherits agent CLI quirks: needs `--dangerously-skip-permissions`, uses the same `runner` package, and the classification latency is whatever the agent takes. Setting `router.classifier: {provider, model}` switches classification to `APIClassifier`, one direct `llm.Provider` call (falls back to the CLI classifier if the key is missing); `router.agent` still answers questions.

Agent resolution: AI suggestion → history pick (`History` interface, implemented by `memory.Store`: Laplace-smoothed accept rate over runs + benchmarks in this directory, ≥3 samples, strict winner) → static `router.routes` → default agent → first healthy. The router never imports memory.

## Gitignored directories

Expand Down
72 changes: 62 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
Orchestra dispatches coding-agent CLIs (Claude Code, OpenCode, Mimo, …) through one **supervised**
interface. You just chat: it **answers plain questions, routes coding tasks to the best agent**, validates
every result (build → lint → test), lets the agent fix its own failures, and keeps nothing without your `y`.
It can **decompose a big request into steps** — running independent ones **in parallel across isolated git
worktrees** — remembers every run, and can **benchmark agents** against each other.
It can **decompose a big request into steps** — running independent ones **in parallel, each isolated in
its own git worktree (or folder copy outside a repo)** — remembers every run, and can **benchmark agents**
against each other.

```sh
# install (Linux/macOS) — prebuilt binary
Expand Down Expand Up @@ -67,7 +68,9 @@ orchestra (claude) › /exit
```

The **AI router** is on by default: plain questions are answered inline, coding tasks auto-route to the
best agent (with a printed reason). Overrides: `@<name> <task>` forces an agent; `/route off` switches to
best agent (with a printed reason). The agent is chosen by: the AI's own suggestion → the agent with the
best track record in this directory (accepted runs + benchmark wins, once there are ≥3 outcomes; e.g.
`claude: 8/10 accepted in this dir`) → `router.routes` → `default_agent`. Overrides: `@<name> <task>` forces an agent; `/route off` switches to
a fixed active agent (`/agent <name>`). Shell commands: `/agents`, `/route [on|off]`, `/agent`, `/help`, `/exit`.
Each accepted turn is committed, so the tree stays clean and every turn's diff shows only its own changes.

Expand All @@ -90,8 +93,9 @@ orchestra do "build user authentication" # plan → approve → run each ste
`do` commits each accepted step and **halts at the first rejected step** (prior steps stay committed).

**Parallel** (`--parallel`): the planner marks which steps are independent; Orchestra runs each ready
step concurrently in its own **git worktree**, then you review + merge each result before the next
dependency wave unlocks:
step concurrently in its own **git worktree** (or, in a folder that isn't a git repository, its own
**temporary copy of the folder**), then you review + merge each result before the next dependency wave
unlocks:

```sh
orchestra do --parallel --jobs 4 "build the API, the CLI, and the docs"
Expand All @@ -102,6 +106,12 @@ branch is merged into the base with **conflict detection** (a conflicting merge
dependents are skipped); rejected branches are discarded. The base working tree is never touched during
execution — all work happens in isolated worktrees.

Outside a git repository the copies are made with the same ignore rules as snapshot diffs (dependency and
build directories such as `node_modules`, `vendor`, `dist` are not copied), and an accepted step's files are
written back only if none of them changed in your folder since the step started — otherwise the step is
reported as a conflict and **nothing** of it is written. The check is per file: two steps editing the same
file conflict even if they touched different lines. Copies are deleted when the run ends.

### Memory & history

Every run is recorded in `~/.orchestra/orchestra.db` (outside your repo, so it never dirties the tree):
Expand Down Expand Up @@ -130,6 +140,25 @@ diff, validation badges, and the failing check's output if there is one. `[` / `
shows all files, `↑↓` scrolls, then `y` accepts (commits in a git repo) or `n` rejects (reverts). With the
AI router enabled, each message is routed to the best agent, and plain questions are answered inline.

**Parallel runs.** Start a message with `/parallel` (or `/par`) to run it like `orchestra do --parallel`:

```text
/parallel add a login page, a signup page, and tests for both
```

The default agent plans the request into steps with dependencies, then each **wave** of independent steps
runs concurrently (up to 4 at a time), every step in its own isolated tree — a git worktree inside a
repository, a folder copy in a plain folder — so nothing touches your files yet. The run panel becomes a
**task list**: one row per step with its status (queued, running, validating, retrying, done, failed),
agent, attempt, elapsed time and last output line. `↑↓` / `j k` select a task, `enter` or `tab` expands
its full output, `esc` collapses (and `esc` on the list cancels the run). When a wave finishes, every step
that changed something opens in the same review screen, headed `wave i/N · task k/M`: `y` merges it into
your folder, `n` discards it. A merge conflict with work already merged is reported and counts as a
rejection; failed steps are shown with their error and skipped, and steps that depend on a rejected or
failed one are skipped too. Then the next wave starts. `ctrl+c` mid-run cancels every task, removes every
isolated tree and undoes any stray write into your folder before quitting. Each step is recorded in
History like a single run.

The other tabs:

- **Changes**: every diff you accepted or rejected. Reopen any of them with `enter`, even after a restart.
Expand All @@ -143,7 +172,8 @@ Colors adapt to light and dark terminals.

### Benchmark agents

Run the **same task through every agent** (each isolated in its own worktree, in parallel) and rank them:
Run the **same task through every agent** (each isolated in its own worktree — or folder copy outside a
git repository — in parallel) and rank them:

```sh
orchestra benchmark "add input validation to the login form"
Expand Down Expand Up @@ -198,6 +228,18 @@ go build -o bin/orchestra ./cmd/orchestra
./bin/orchestra init # write a starter orchestra.yaml
```

## Updating

Release builds check GitHub for a newer version at most once a day when started in an interactive
terminal, and ask `Download and install now? [Y/n]`. On yes, Orchestra downloads the archive for your
platform, verifies its SHA-256 against the release's `checksums.txt`, replaces its own executable, and
exits — relaunch to use the new version. Run `orchestra update` to check on demand (`--check` to only
report, `-y` to skip the prompt).

The check never runs in pipes, scripts or CI (`CI` set), for dev/snapshot builds, or when
`ORCHESTRA_NO_UPDATE_CHECK=1`. Installed via Homebrew/Scoop or into a directory you can't write to?
Update the same way you installed instead.

## Configuration

Orchestra works with no config (built-in defaults for the common agents). To customize, `orchestra init`
Expand Down Expand Up @@ -226,6 +268,14 @@ router:
plan: claude
implement: opencode
review: claude
# Optional: classify with a cheap hosted model over HTTP instead of spawning the
# router agent's CLI. Used only when the key env var is set; otherwise Orchestra
# quietly falls back to `agent` above (which still answers plain questions).
# classifier:
# provider: anthropic # openai (default) | anthropic
# model: claude-haiku-4-5
# api_base: "" # optional endpoint override
# api_key_env: "" # optional; defaults to ANTHROPIC_API_KEY / OPENAI_API_KEY

agents:
- name: claude
Expand All @@ -244,8 +294,8 @@ agents:
```

> **`dir_flag`** tells Orchestra how to pass an agent its working directory. Most CLIs honor the process
> cwd, but some (e.g. opencode) don't — set `dir_flag` so parallel worktrees stay isolated. Orchestra
> also guards the base tree: if an agent writes outside its worktree anyway, the stray changes are
> cwd, but some (e.g. opencode) don't — set `dir_flag` so parallel worktrees (and folder copies) stay
> isolated. Orchestra also guards the base tree: if an agent writes outside its worktree anyway, the stray changes are
> discarded before merge so one misbehaving agent can't break the wave.

A config file overrides defaults and adds agents; matching names replace the built-in entry.
Expand All @@ -263,6 +313,7 @@ A config file overrides defaults and adds agents; matching names replace the bui
| `orchestra history` | recent runs + preferred agent |
| `orchestra agents` | list agents; `--probe` live-tests each can actually run |
| `orchestra init` | write a starter `orchestra.yaml` |
| `orchestra update` | install the latest release; `--check` only reports, `-y` skips the prompt |

`run` flags: `--agent`, `--test`, `--retries`, `--timeout`, `--force`. `do`: `--agent`, `--yes`, `--parallel`, `--jobs`. Global: `--dir`.

Expand All @@ -277,10 +328,11 @@ internal/llm HTTP LLM providers (openai-compatible, anthropic) behind on
internal/patch extract changes from model replies and apply them safely
internal/ui terminal styling: gradient banner, spinners, colored diffs (TTY-aware)
internal/tui Bubble Tea dashboard: agents / history / benchmarks (read-only monitor)
internal/router AI routing: Classifier (CLI now, API later) → Decision, 3-tier fallback
internal/router AI routing: Classifier (agent CLI or direct API) → Decision, tiered fallback
internal/planner decompose a request into ordered steps (+ depends_on for parallel)
internal/scheduler bounded-concurrency runner + DAG waves (cycle/blocked detection)
internal/worktree git-worktree isolation: branch per task, merge + conflict detection
internal/parallel shared parallel workflow pieces (step graph, base-tree guard, quiet per-task run) ← do --parallel, dashboard /parallel
internal/worktree task isolation: git worktrees in a repo, folder copies elsewhere; merge + conflict detection
internal/engine supervised pipeline (dispatch → validate → retry → review) + headless mode ← run/shell/do
internal/shell interactive chat REPL
internal/memory SQLite run history + preferred-agent hint (~/.orchestra)
Expand Down
Loading
Loading