Agentic orchestrator for parallel coding agents — plans tasks, spawns agents, and autonomously handles CI fixes, merge conflicts, and code reviews.
Go to file
Harshit Singh Bhandari 9ffb1bb6e6
feat(core): enrich events with PR title, description, and URL (#1326)
* fix: serialize ao start and stop numbered orchestrators (#1306)

* fix: restore dead orchestrators on start (#1306)

* fix: harden startup lock handling (#1306)

* feat(core): enrich events with PR title, description, and URL

Adds PR and issue context to all event payloads sent to notifiers.
External consumers (Telegram, Discord, n8n) can now display meaningful
information without making additional API calls.

Changes:
- Add buildEventContext() helper to extract PR/issue context from session
- Enrich all createEvent() calls with context data (pr, issueId, issueTitle, branch)
- Store issueTitle in session metadata during spawn
- Add issueTitle field to SessionMetadata interface
- Update executeReaction() to accept session for context access
- Add tests for event enrichment

The context includes:
- pr: { url, title, number, branch } when PR exists
- issueId: issue identifier
- issueTitle: issue title (from tracker during spawn)
- branch: session branch name

Events before PR creation gracefully omit PR fields (pr: null).
Existing webhook consumers that ignore unknown fields are unaffected.

Closes #1226

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(core): address review comments for event enrichment

- Add issueTitle to readMetadata/writeMetadata for proper persistence
- Create ReactionSessionContext type for type-safe system events
- Replace unsafe `as unknown as Session` cast with proper union type
- Add end-to-end test verifying issueTitle persistence during spawn

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix(cli): include lock file path in startup lock error message

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address review feedback — fd safety, kill-all resilience, issueTitle restore

- Restore try/catch/finally in tryAcquire for fd leak prevention
- Wrap stop command's sm.list()+kill in try/catch so dashboard shutdown
  always runs even on session listing failure
- Add per-iteration error handling in kill-all loop with partial failure
  reporting (spinner.warn for mixed results)
- Unify allSessionPrefixes derivation between start and stop commands
- Propagate issueTitle through archive restore path
- Add clarifying comments on agentInfo.summary fallback and intentional
  prNumber/prUrl duplication in event data
- Add ora warn mock for stop tests
- Update changeset to minor (event enrichment is a feature) and add CLI
  changeset for stop resilience
- Add tests for kill-all error mid-loop and issueTitle archive restore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address harsh-batheja review — title/summary split, lock grace, context namespace

- Separate PR title from agent summary in EventContext: title is null
  until enrichment cache populates; summary is a distinct field so
  webhook consumers never confuse the task summary for a PR title.
- Restore UNPARSEABLE_LOCK_GRACE_MS (5s mtime grace) and
  isStaleUnparseableLock lost during merge conflict resolution —
  prevents lockfile-steal race when process A just created the file
  but hasn't written metadata yet.
- Fix orchestrator sort: extract numeric suffix instead of
  localeCompare so -10 sorts after -2, not before.
- Namespace context under data.context instead of spreading into data
  to prevent field collisions with reaction-specific keys.
- Add schemaVersion: 2 to all enriched events so consumers can
  migrate away from top-level prNumber/prUrl (kept for compat,
  marked for removal in v3).
- Update event enrichment tests for nested context structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve merge conflicts — use formatReviewCommentsMessage, fix batch enrichment mock

- Replace formatAutomatedCommentsMessage with upstream's formatReviewCommentsMessage
  for automated review comment dispatch (fixes type mismatch with ReviewComment[])
- Make createMockSCM's enrichSessionsPRBatch dynamically resolve from individual
  method mocks so test overrides (e.g. getPRState("closed")) propagate correctly
- Add explicit enrichSessionsPRBatch to merge-conflict-tracking test to avoid
  unexpected getMergeability calls from the dynamic mock
- Remove all debug console.log statements added during troubleshooting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: wire up maybeDispatchCIFailureDetails and record dispatch hash on transition

The function was defined but never called after merge conflict resolution
dropped the call site. Added it back to the Promise.allSettled alongside
maybeDispatchReviewBacklog and maybeDispatchMergeConflicts.

Also updated the transition-reaction early-return to record the dispatch
hash, since the transition path now enriches the CI message with detailed
check info from the batch cache — preventing duplicate sends on subsequent
polls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: remove stale duplicate test from rebase

Removes the orphaned numbered-orchestrator restoration test left over
from feat/1226 history. Upstream's canonical model test (same name,
expects "app-orchestrator" via ensureOrchestrator) supersedes it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: remove misleading CLI CHANGELOG entry

The "Restore the most recently active dead orchestrator on ao start"
entry described upstream's ensureOrchestrator behavior (#1487), not
work contributed by this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs(changeset): correct scope and drop stale CLI changeset

- Rewrite the @aoagents/ao-core changeset to describe only what feat/1226
  contributes: event enrichment with schemaVersion: 2, issueTitle
  persistence, executeReaction refactor, maybeDispatchCIFailureDetails,
  and bugbot-comments enrichment. Drop the false claims about adding
  spawn-target and format-automated-comments (those modules came from
  upstream PRs #1330 and #1334).
- Delete stop-kill-all-resilience.md — its claims (kill-all loop,
  fd-safety in tryAcquire, allSessionPrefixes unify) are no longer
  in the branch after the rebase took upstream's canonical stop logic.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-01 15:19:09 +05:30
.changeset feat(core): enrich events with PR title, description, and URL (#1326) 2026-05-01 15:19:09 +05:30
.cursor chore: rename @composio scope to @aoagents across all packages 2026-04-09 15:59:33 +00:00
.github refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +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 chore: rename @composio scope to @aoagents across all packages 2026-04-09 15:59:33 +00:00
changelog chore: rename @composio scope to @aoagents across all packages 2026-04-09 15:59:33 +00:00
completions add zsh completion support for ao (#1374) 2026-04-24 03:48:25 +05:30
docs feat(plugin): implement kimicode agent plugin (#1390) 2026-05-01 14:11:30 +05:30
examples feat: add $schema support to agent-orchestrator.yaml (#1373) 2026-04-26 19:42:45 +05:30
handoff/pr-1466 refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +05:30
openclaw-plugin refactor: remove --decompose feature entirely 2026-04-10 13:02:52 +05:30
packages feat(core): enrich events with PR title, description, and URL (#1326) 2026-05-01 15:19:09 +05:30
schema feat: add $schema support to agent-orchestrator.yaml (#1373) 2026-04-26 19:42:45 +05:30
scripts refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +05:30
skills feat(plugin): implement kimicode agent plugin (#1390) 2026-05-01 14:11:30 +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
website feat(website): integration PR for #1274 docs + #1047 landing (#1301) 2026-04-26 22:49:11 +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 feat(website): integration PR for #1274 docs + #1047 landing (#1301) 2026-04-26 22:49:11 +05:30
.gitleaks.toml refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +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 refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +05:30
ARCHITECTURE.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
CLAUDE.md refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +05:30
CONTRIBUTING.md docs: add working principles to contributor docs 2026-04-18 00:32:10 +05:30
DESIGN.md refactor(core): storage redesign — projectId-based paths, JSON metadata (#1466) 2026-04-28 17:55:53 +05:30
LICENSE feat: publish to npm under @composio scope (#32) 2026-02-15 04:28:57 +05:30
README.md feat(plugin): implement kimicode agent plugin (#1390) 2026-05-01 14:11:30 +05:30
SECURITY.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
SETUP.md feat(cli): filter terminated sessions from ao session ls / ao status by default (#1340) 2026-04-20 13:05:34 +05:30
TROUBLESHOOTING.md fix: migrate to hash-based project isolation architecture 2026-02-18 00:19:55 +05:30
agent-orchestrator.yaml.example feat(plugin): implement kimicode agent plugin (#1390) 2026-05-01 14:11:30 +05:30
eslint.config.js fix: clear stale Next.js cache on version upgrade (#1022) 2026-05-01 12:23:51 +05:30
package.json fix(deps): bump vulnerable dependencies so pnpm audit passes cleanly (#1338) 2026-04-26 17:01:07 +05:30
pnpm-lock.yaml feat(plugin): implement kimicode agent plugin (#1390) 2026-05-01 14:11:30 +05:30
pnpm-workspace.yaml chore: remove React Native/Expo mobile app 2026-03-25 12:00:59 +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

Zsh Completion

Generate the completion file from the installed CLI:

mkdir -p ~/.zsh/completions
ao completion zsh > ~/.zsh/completions/_ao

Then make sure the directory is on your fpath before compinit runs:

fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit
compinit

For Oh My Zsh, install the same generated file into a custom plugin directory and add ao to your plugin list:

mkdir -p "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ao"
ao completion zsh > "${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ao/_ao"

If you are contributing from a source checkout, you can also symlink the repo copy at completions/_ao.

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
$schema: https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/main/schema/config.schema.json
# 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.

Keep the $schema line so editors can autocomplete and validate against schema/config.schema.json.

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

Remote Access

AO keeps your Mac awake while running, so you can access the dashboard remotely (e.g., via Tailscale from your phone) without the machine going to sleep.

How it works: On macOS, AO automatically holds an idle-sleep prevention assertion using caffeinate. When AO exits, the assertion is released.

# agent-orchestrator.yaml
$schema: https://raw.githubusercontent.com/ComposioHQ/agent-orchestrator/main/schema/config.schema.json
power:
  preventIdleSleep: true  # Default on macOS, no-op on Linux

Set to false if you want to allow idle sleep while AO runs.

Lid-close limitation: macOS enforces lid-close sleep at the hardware level — no userspace assertion can override it. If you need remote access while traveling with the lid closed, use clamshell mode (external power + display + input device).

Plugin Architecture

Seven plugin slots. Lifecycle stays in core.

Slot Default Alternatives
Runtime tmux process
Agent claude-code codex, aider, cursor, opencode, kimicode
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