Agentic orchestrator for parallel coding agents — plans tasks, spawns agents, and autonomously handles CI fixes, merge conflicts, and code reviews.
Go to file
Harsh Batheja 95fbecc379
refactor(cli): remove lifecycle-worker subprocess, poll in-process (#1186)
* refactor(cli): remove lifecycle-worker subprocess model, run polling in-process

Replaces the per-project `ao lifecycle-worker` subprocess with an in-process
polling loop managed inside `lifecycle-service`. All registered projects are
now polled from the single long-lived `ao start` process.

- Drops the `lifecycle-worker` command and its registration.
- Rewrites `lifecycle-service` around a `Map<projectId, ActiveLoop>`,
  with SIGINT/SIGTERM/beforeExit graceful shutdown.
- Removes PID-file coordination (PID file, log file, status, etc.) —
  these only existed to track subprocess state.
- Per-project error isolation is preserved: the core lifecycle manager's
  `pollAll()` already catches per-cycle errors, and stop failures in one
  project can't prevent others from stopping.
- Updates `start`/`spawn` callers and tests to drop the PID/logFile shape.
- Adds `lifecycle-service.test.ts` covering idempotency, unknown projects,
  error isolation across projects, and graceful stop-all.

Closes #1185

* fix(cli): address bugbot review on lifecycle-service in-process refactor

- `ao spawn` / `ao batch-spawn` no longer call `ensureLifecycleWorker`.
  That call used to start `setInterval` polling in the one-shot spawn
  process, which (a) kept the CLI alive forever after the session spawned
  and (b) duplicated polling already running in `ao start`. Replaced with
  a `warnIfAONotRunning()` helper that checks `running.json` and prints a
  hint if the orchestrator isn't up.
- `ao stop` no longer calls `stopLifecycleWorker`. That call always ran
  against a fresh in-memory map (stop is a separate process from start),
  so it always returned false and printed "Lifecycle worker not running"
  misleadingly. SIGTERM to the `ao start` PID already triggers the shared
  shutdown handler in `lifecycle-service`, which stops every loop.
- Drop duplicated shutdown closure inside `registerSignalsOnce` — signal
  handlers now reference `stopAllLifecycleWorkers` directly.
- Update tests accordingly: spawn.test.ts mocks `running-state.getRunning`,
  start.test.ts drops `stopLifecycleWorker` expectations.

* fix(cli): drop SIGINT/SIGTERM listeners from lifecycle-service

Installing listeners for those signals removes Node.js's default
"exit on signal" behavior (per Node docs: "its default behavior will
be removed — Node.js will no longer exit"). Since the registered
listener doesn't call process.exit(), the `ao start` process would
hang on SIGTERM with the setInterval timer keeping the event loop
alive forever — effectively breaking `ao stop`.

Default signal handling terminates the process cleanly; the OS
reclaims the interval timer and dashboard child. `stopAllLifecycleWorkers`
stays exported for callers that want explicit cleanup before exit.

* fix(cli): project-scoped spawn warning + flush lifecycle health on exit

Addresses reviewer feedback on PR #1186:

- `warnIfAONotRunning` now takes a projectId and warns not only when no
  AO is running, but also when the running instance isn't polling the
  target project (e.g. `ao start A` then `ao spawn` in B left users
  silent about the fact that B wasn't being polled).
- `running.json` now records only the project this `ao start` actually
  polls, not every project in config. Previously this list was a lie —
  `ensureLifecycleWorker` is called for the selected project only.
- `ao start` installs SIGINT/SIGTERM handlers that call
  `stopAllLifecycleWorkers()` (flushing per-project "stopped" health
  state) and then `process.exit()`. Installing the handler safely
  requires an explicit exit because SIGINT/SIGTERM listeners remove
  Node's default exit behavior.

* fix(cli): remove dead stopLifecycleWorker, add missing test mock

Addresses bugbot comments on PR #1186:

- Delete `stopLifecycleWorker` from `lifecycle-service.ts`. It was only
  called from `ao stop` in the old subprocess model; in the in-process
  model, SIGTERM to the `ao start` pid + the shutdown handler in
  `start.ts` covers cleanup. No production caller remains.
- Add `stopAllLifecycleWorkers: vi.fn()` to `start.test.ts`'s
  `lifecycle-service.js` mock. Without it, `vi.mock` replaced the module
  and the named import resolved to undefined; the shutdown handler's
  try/catch would silently swallow the resulting TypeError, hiding any
  regression in how shutdown is wired.
- Update `lifecycle-service.test.ts` to drop references to the removed
  export (one test removed, one repurposed as a no-op smoke test for
  `stopAllLifecycleWorkers` against an empty active map).
2026-04-14 17:23:33 +05:30
.changeset chore: bump all package versions to 0.2.5 (#1190) 2026-04-13 05:47:08 +05:30
.cursor fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
.github chore: bump all package versions to 0.2.5 (#1190) 2026-04-13 05:47:08 +05:30
.husky feat: implement comprehensive security audit and secret leak prevention (#67) 2026-02-16 10:33:50 +05:30
.issue-assets fix(web): make PR title clickable on /prs page (#1146) 2026-04-12 08:43:53 +05:30
artifacts fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
changelog fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
docs Merge pull request #1104 from ComposioHQ/feat/issue-1045 2026-04-11 10:22:22 +05:30
examples Update examples readme: Linear branchName vs feat/<id> when spawning 2026-04-02 22:17:28 +02:00
openclaw-plugin refactor: remove --decompose feature entirely 2026-04-10 13:02:52 +05:30
packages refactor(cli): remove lifecycle-worker subprocess, poll in-process (#1186) 2026-04-14 17:23:33 +05:30
scripts Merge pull request #882 from DNX/feat/linear-spawn-branch-name 2026-04-11 14:45:57 +05:30
skills/agent-orchestrator fix: merge main and address review findings for prompt-driven spawn 2026-04-11 21:44:57 +05:30
tests/integration fix: added GraphQL batch PRfeat: add GraphQL batch PR enrichment for orchestrator polling enrichment for orchestrator polling (fixes #608) (#637) 2026-03-30 00:31:04 +05:30
.eslintignore fix: added GraphQL batch PRfeat: add GraphQL batch PR enrichment for orchestrator polling enrichment for orchestrator polling (fixes #608) (#637) 2026-03-30 00:31:04 +05:30
.gitignore style(design): design review fixes + fresh Warm Terminal design system (#927) 2026-04-11 16:30:03 +05:30
.gitignore-template feat: OpenCode session lifecycle and CLI controls (#315) 2026-03-08 09:55:44 +05:30
.gitleaks.toml feat: implement comprehensive security audit and secret leak prevention (#67) 2026-02-16 10:33:50 +05:30
.npmrc feat: publish to npm under @composio scope (#32) 2026-02-15 04:28:57 +05:30
.prettierignore chore: add ESLint, Prettier, CI workflow, and comprehensive CLAUDE.md conventions 2026-02-13 18:01:52 +05:30
.prettierrc chore: add ESLint, Prettier, CI workflow, and comprehensive CLAUDE.md conventions 2026-02-13 18:01:52 +05:30
AGENTS.md fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
ARCHITECTURE.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
CLAUDE.md style(design): design review fixes + fresh Warm Terminal design system (#927) 2026-04-11 16:30:03 +05:30
CONTRIBUTING.md fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
DESIGN.md style(design): design review fixes + fresh Warm Terminal design system (#927) 2026-04-11 16:30:03 +05:30
LICENSE feat: publish to npm under @composio scope (#32) 2026-02-15 04:28:57 +05:30
README.md fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
SECURITY.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
SETUP.md Merge pull request #882 from DNX/feat/linear-spawn-branch-name 2026-04-11 14:45:57 +05:30
TROUBLESHOOTING.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
agent-orchestrator.yaml.example add plugin spec and update docs 2026-03-31 04:02:25 +05:30
eslint.config.js Merge main into chore/remove-mobile-app - resolve conflicts 2026-03-30 18:06:08 +05:30
package.json fix: merge upstream main and resolve conflicts for cursor agent 2026-04-10 11:48:27 +05:30
pnpm-lock.yaml Merge pull request #914 from fireddd/ci/coverage-report-913 2026-04-13 02:34:09 +05:30
pnpm-workspace.yaml chore: remove React Native/Expo mobile app 2026-03-25 12:00:59 +05:30
test-ao-config.yaml feat: seamless onboarding with enhanced documentation (#66) 2026-02-16 22:22:13 +05:30
test-ao-config2.yaml feat: seamless onboarding with enhanced documentation (#66) 2026-02-16 22:22:13 +05:30
tsconfig.base.json fix: scope node types to node packages 2026-04-13 18:25:21 +05:30
tsconfig.node.json fix: scope node types to node packages 2026-04-13 18:25:21 +05:30

README.md

Agent Orchestrator — The Orchestration Layer for Parallel AI Agents

Agent Orchestrator banner

Spawn parallel AI coding agents, each in its own git worktree. Agents autonomously fix CI failures, address review comments, and open PRs — you supervise from one dashboard.

GitHub stars
npm version
License: MIT
PRs merged
Tests
Discord


Agent Orchestrator manages fleets of AI coding agents working in parallel on your codebase. Each agent gets its own git worktree, its own branch, and its own PR. When CI fails, the agent fixes it. When reviewers leave comments, the agent addresses them. You only get pulled in when human judgment is needed.

Agent-agnostic (Claude Code, Codex, Aider) · Runtime-agnostic (tmux, Docker) · Tracker-agnostic (GitHub, Linear)

See it in action

Agent Orchestrator demo — AI agents building their own orchestrator

Watch the Demo on X


The Self-Improving AI System That Built Itself

Read the Full Article on X

Quick Start

Prerequisites: Node.js 20+, Git 2.25+, tmux, gh CLI. Install tmux via brew install tmux (macOS) or sudo apt install tmux (Linux).

Install

npm install -g @aoagents/ao
Permission denied? Install from source?

If npm install -g fails with EACCES, prefix with sudo or fix your npm permissions.

To install from source (for contributors):

git clone https://github.com/ComposioHQ/agent-orchestrator.git
cd agent-orchestrator && bash scripts/setup.sh

Start

Point it at any repo — it clones, configures, and launches the dashboard in one command:

ao start https://github.com/your-org/your-repo

Or from inside an existing local repo:

cd ~/your-project && ao start

That's it. The dashboard opens at http://localhost:3000 and the orchestrator agent starts managing your project.

Add more projects

ao start ~/path/to/another-repo

How It Works

  1. You startao start launches the dashboard and an orchestrator agent
  2. Orchestrator spawns workers — each issue gets its own agent in an isolated git worktree
  3. Agents work autonomously — they read code, write tests, create PRs
  4. Reactions handle feedback — CI failures and review comments are automatically routed back to the agent
  5. You review and merge — you only get pulled in when human judgment is needed

The orchestrator agent uses the AO CLI internally to manage sessions. You don't need to learn or use the CLI — the dashboard and orchestrator handle everything.

Configuration

ao start auto-generates agent-orchestrator.yaml with sensible defaults. You can edit it afterwards to customize behavior:

# agent-orchestrator.yaml
# Runtime data is auto-derived under ~/.agent-orchestrator/{hash}-{projectId}/
port: 3000

defaults:
  runtime: tmux
  agent: claude-code
  workspace: worktree
  notifiers: [desktop]

projects:
  my-app:
    repo: owner/my-app
    path: ~/my-app
    defaultBranch: main
    sessionPrefix: app

reactions:
  ci-failed:
    auto: true
    action: send-to-agent
    retries: 2
  changes-requested:
    auto: true
    action: send-to-agent
    escalateAfter: 30m
  approved-and-green:
    auto: false # flip to true for auto-merge
    action: notify

CI fails → agent gets the logs and fixes it. Reviewer requests changes → agent addresses them. PR approved with green CI → you get a notification to merge.

See agent-orchestrator.yaml.example for the full reference, or run ao config-help for the complete schema.

Plugin Architecture

Seven plugin slots. Lifecycle stays in core.

Slot Default Alternatives
Runtime tmux process
Agent claude-code codex, aider, cursor, opencode
Workspace worktree clone
Tracker github linear, gitlab
SCM github gitlab
Notifier desktop slack, discord, composio, webhook, openclaw
Terminal iterm2 web

All interfaces defined in packages/core/src/types.ts. A plugin implements one interface and exports a PluginModule. That's it.

Why Agent Orchestrator?

Running one AI agent in a terminal is easy. Running 30 across different issues, branches, and PRs is a coordination problem.

Without orchestration, you manually: create branches, start agents, check if they're stuck, read CI failures, forward review comments, track which PRs are ready to merge, clean up when done.

With Agent Orchestrator, you: ao start and walk away. The system handles isolation, feedback routing, and status tracking. You review PRs and make decisions — the rest is automated.

Documentation

Doc What it covers
Setup Guide Detailed installation, configuration, and troubleshooting
CLI Reference All ao commands (mostly used by the orchestrator agent)
Examples Config templates (GitHub, Linear, multi-project, auto-merge)
Development Guide Architecture, conventions, plugin pattern
Contributing How to contribute, build plugins, PR process

Development

pnpm install && pnpm build    # Install and build all packages
pnpm test                      # Run tests (3,288 test cases)
pnpm dev                       # Start web dashboard dev server

See docs/DEVELOPMENT.md for code conventions and architecture details.

Contributing

Contributions welcome. The plugin system makes it straightforward to add support for new agents, runtimes, trackers, and notification channels. Every plugin is an implementation of a TypeScript interface — see CONTRIBUTING.md and the Development Guide for the pattern.

License

MIT