Spawn parallel AI coding agents. Each gets its own worktree.
They fix CI, address reviews, and merge PRs — autonomously.
A Rust port of Agent Orchestrator — a tool that lets AI coding agents (Claude Code, Codex, Aider…) work autonomously on GitHub issues inside isolated git worktrees, reacting to CI failures and code reviews without human intervention. ao-rs is faster, leaner, and adds features the original doesn't have.
Left sidebar groups sessions under their Orchestrator → Project. Lanes (Working / Pending / Review / Merged) update live via SSE.
| ao-rs | ao-ts | |
|---|---|---|
| Startup | 8 ms | 556 ms — 69× slower |
| Memory | 10 MB | 97 MB — 9.7× more |
| Install | 12 MB single binary | 85 MB node_modules |
→ Full benchmark results, feature diff, and plugin comparison: BENCHMARKING.md
| Feature | Description |
|---|---|
| Monthly cost ledger | ~/.ao-rs/cost-ledger/YYYY-MM.yaml — permanent per-session cost backup that survives session deletion |
ao-rs status --cost |
Cost column (tokens + USD) in the status table — ao-ts has no equivalent CLI flag |
| Embedded REST + SSE API | axum server built into the single binary — ao-ts requires a separate Next.js server process |
| Agent rules injection | Structured 6-step dev lifecycle (UNDERSTAND/PLAN/IMPLEMENT/VERIFY/REVIEW/DELIVER) injected as agent system prompt |
| MergeFailed parking loop | Mergeable ↔ MergeFailed retry with configurable budget — ao-ts has no merge-retry state |
| Single binary | cargo install and go — no Node.js, no npm, no runtime dependencies |
graph TB
orch["🤖 Orchestrator\n(ao-rs orchestrator spawn)"]
subgraph skills["ai-devkit Skills (injected into every agent)"]
direction LR
sk1["dev-lifecycle\n8-phase SDLC"]
sk2["memory\nknowledge search"]
sk3["verify · tdd\nquality gates"]
end
subgraph workers["Parallel Agent Sessions (each in an isolated git worktree)"]
direction LR
w1["Claude Code\nissue #1"]
w2["Cursor\nissue #2"]
w3["Codex · Aider\nissue #N"]
end
orch -->|"spawn"| workers
skills -.->|"loaded at launch"| workers
w1 -->|"opens PR"| loop
w2 -->|"opens PR"| loop
w3 -->|"opens PR"| loop
subgraph loop["⚡ Lifecycle Loop (ao-rs watch — polls every 5s)"]
direction LR
ci{"CI?"}
rev{"Review?"}
ci -->|"passes"| rev
end
loop -->|"CI failed → send logs"| w1
loop -->|"CI failed → send logs"| w2
loop -->|"changes requested"| w3
rev -->|"approved + green"| merge["Auto-Merge"]
merge --> done["✓ Done"]
style orch fill:#16a34a,color:#fff,stroke:none
style done fill:#5c64b5,color:#fff,stroke:none
style merge fill:#16a34a,color:#fff,stroke:none
ao-rs orchestrator spawn— an AI orchestrator reads your issue backlog and spawns worker agents in parallel, one per issue- Any agent type — Claude Code, Cursor, Codex, or Aider; configured per-project in
ao-rs.yaml - ai-devkit skills loaded at launch —
dev-lifecycle(8-phase SDLC),memory(persistent knowledge search/store across sessions),verify+tdd(quality gates). Runao-rs startto install them. - Each worker gets its own isolated git worktree, tmux session, and agent process — they can't interfere with each other
ao-rs watch— polls every 5s across all sessions: runtime liveness, agent activity, GitHub PR/CI/review state- Reactions close the loop — CI fails? Each agent gets its own logs. Changes requested? That agent addresses them. Approved + green? Auto-merge fires per session.
- You get notified — only when human judgment is needed (stuck agent, exhausted retries, merge conflicts)
Prerequisites: Rust 1.89+ · tmux ·
ghCLI (authenticated) ·claude
# Install from crates.io
cargo install ao-rs
# Or build from source
git clone https://github.com/duonghb53/ao-rs
cd ao-rs
cargo install --path crates/ao-cli
# Verify the environment (checks git, gh, tmux, claude on PATH + GitHub auth)
ao-rs doctor
# Initialize a project (generates ao-rs.yaml)
cd /path/to/your/project
ao-rs start
# Spawn an agent on a GitHub issue
ao-rs spawn --issue 42
# Or with a free-form task
ao-rs spawn --task "fix the failing tests"
# Watch the lifecycle loop
ao-rs watch
# Open the embedded React dashboard in a browser
ao-rs dashboard --open
# Check status
ao-rs status --cost --pr
# Clean up worktrees after sessions merge
ao-rs pruneFor a complete walkthrough see docs/user-guide.md.
ao-rs start generates ao-rs.yaml in your project directory. No config file = no reactions, stdout-only notifications.
reactions:
ci-failed:
action: send-to-agent
message: "CI failed. Read the logs, fix the issue, and push again."
retries: 3
escalate_after: 3 # escalate after 3 failed attempts
changes-requested:
action: send-to-agent
retries: 2
escalate_after: 30m # or escalate after a duration
approved-and-green:
action: auto-merge
priority: info
agent-stuck:
action: notify
threshold: 10m
priority: warning
notification_routing:
urgent: [stdout, ntfy, desktop, discord]
action: [stdout, ntfy]
warning: [stdout, desktop]
info: [stdout]Environment variables
| Variable | Purpose |
|---|---|
AO_NTFY_TOPIC |
ntfy.sh topic for push notifications |
AO_NTFY_URL |
Custom ntfy server (default: https://ntfy.sh) |
AO_DISCORD_WEBHOOK_URL |
Discord webhook URL |
AO_SLACK_WEBHOOK_URL |
Slack incoming webhook URL |
RUST_LOG |
Log level (default: warn,ao_core=info) |
Full config reference: docs/config.md
ao-rs dashboard serves the embedded React UI at / and a REST + SSE API under /api/:
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/sessions |
List all sessions (JSON) |
GET |
/api/sessions/:id |
Get session by id or prefix |
POST |
/api/sessions/:id/message |
Send message to agent |
POST |
/api/sessions/:id/kill |
Kill session runtime |
POST |
/api/sessions/:id/restore |
Restore terminated session |
GET |
/api/orchestrators |
List orchestrator sessions |
POST |
/api/orchestrators |
Spawn a new orchestrator |
GET |
/api/issues |
Aggregate open issues across projects |
GET |
/api/events |
SSE stream of lifecycle events |
ao-rs dashboard --port 3000 --open
curl http://localhost:3000/api/sessions | jq
curl -N http://localhost:3000/api/events # SSE streamstateDiagram-v2
[*] --> spawning
spawning --> working : agent active
working --> pr_open : PR created
working --> stuck : idle > threshold
stuck --> working : agent resumes
pr_open --> ci_failed
pr_open --> review_pending
pr_open --> approved
ci_failed --> working : agent fixes
review_pending --> changes_requested
changes_requested --> working : agent addresses
approved --> mergeable : CI green
mergeable --> merged : auto-merge
mergeable --> merge_failed : merge error
merge_failed --> mergeable : retry (budget)
merged --> [*]
See docs/state-machine.md for the full transition table.
ao-rs/
├── crates/
│ ├── ao-core/ # Types, traits, state machine, reaction engine, cost ledger
│ ├── ao-cli/ # `ao-rs` binary (clap)
│ ├── ao-dashboard/ # REST API + SSE server (axum)
│ ├── ao-desktop/ # Dashboard web UI (Vite + React)
│ └── plugins/
│ ├── runtime-tmux/ # Tmux session management
│ ├── agent-claude-code/ # Claude Code adapter + JSONL cost parser
│ ├── agent-cursor/ # Cursor IDE adapter
│ ├── agent-aider/ # Aider adapter
│ ├── agent-codex/ # Codex adapter
│ ├── workspace-worktree/ # Git worktree isolation
│ ├── scm-github/ # GitHub PRs via `gh` CLI
│ ├── scm-gitlab/ # GitLab MRs via REST API
│ ├── tracker-github/ # GitHub Issues via `gh` CLI
│ ├── notifier-stdout/ # Terminal output (always on)
│ ├── notifier-ntfy/ # ntfy.sh push notifications
│ ├── notifier-desktop/ # Native OS notifications
│ └── notifier-discord/ # Discord webhook
├── scripts/
│ └── benchmark.sh # Performance comparison vs ao-ts
└── docs/ # Architecture, state machine, reactions, CLI ref, plugin spec
Plugin system — 6 trait slots
| Slot | Trait | Implementations |
|---|---|---|
| Runtime | Runtime |
tmux, process |
| Agent | Agent |
Claude Code, Cursor, Aider, Codex |
| Workspace | Workspace |
git worktree |
| SCM | Scm |
GitHub, GitLab |
| Tracker | Tracker |
GitHub Issues |
| Notifier | Notifier |
stdout, ntfy, desktop, discord |
- Shell-out over libraries —
git,tmux,ghare subprocesses, not Rust crate bindings - Disk is the source of truth — no in-memory cache; every read walks
~/.ao-rs/sessions/ - Trait objects at plugin boundaries — keeps the binary clean, lets tests use mocks
- One crate per plugin — clear dependency graph, fast incremental builds
- Never port file-by-file — read TS for intent, write idiomatic Rust
cargo build --workspace # Build all crates
cargo t --workspace # Run tests via nextest (fast + isolated)
cargo test --doc --workspace # Run doctests
cargo clippy --workspace --tests -- -D warnings # Lint
cargo fmt --all -- --check # Format check
# Run benchmarks against ao-ts
./scripts/benchmark.sh ~/study/agent-orchestratorNote on CPU usage: tests run via
cargo nextest(aliased ascargo t). Cap threads on laptops:cargo t --workspace --test-threads=2
| Document | Content |
|---|---|
| user-guide.md | Step-by-step walkthrough of all CLI commands and workflows |
| architecture.md | Crate structure, disk layout, design principles |
| state-machine.md | 18-state lifecycle, PR transitions, stuck detection |
| reactions.md | Reaction engine, notification routing, escalation |
| cli-reference.md | All CLI subcommands with flags and examples |
| config.md | Full config file reference |
| plugin-spec.md | Plugin trait contracts, how to add a plugin |
- Core lifecycle + state machine
- Reaction engine + SCM integration (GitHub + GitLab)
- Notification routing: stdout, ntfy, desktop, discord
- Dashboard REST API + SSE
- Per-session cost tracking + monthly ledger
- Web dashboard UI (React + Vite, Orchestrator → Projects hierarchy)
- Additional agent plugins: Cursor, Aider, Codex
-
ao-rs orchestrator— meta-agent that spawns and monitors workers - Publish to crates.io
- Tauri desktop app wrapper (planned)
MIT © 2026 Ha Duong
