AO

Projects

Every per-project field in agent-orchestrator.yaml — agents, workspace, tracker, reactions, per-role overrides, and more.

The projects key is a map of project IDs to project configs. Each entry tells AO which repo to watch, which agents to use, and how to isolate work. AO spawns one agent session per issue per project — running them in parallel, each in its own git worktree with its own PR.

projects:
  my-app:          # project ID — used in session names and dashboard
    repo: org/my-app
    path: ~/projects/my-app

Project IDs must match ^[a-zA-Z0-9_-]+$ (letters, numbers, hyphens, underscores — no dots or slashes).

Required fields

Two fields must be present for a functional project:

FieldTypeDescription
pathstringAbsolute path to the local checkout. ~ expands to $HOME.
repostringGitHub/GitLab repository in owner/repo format. Used by the SCM and tracker plugins to open PRs and fetch issues.

Without repo, AO cannot create PRs or listen for issues. Without path, AO cannot find the codebase to create worktrees.

All project fields

name

Type: string Default: project ID

Human-readable display name shown in the dashboard. Defaults to the map key if not set.

name: My App

repo

Type: string Default: none

The GitHub or GitLab repository in owner/repo format. AO infers whether to use the github or gitlab SCM/tracker plugins from this value (and from explicit scm.plugin / tracker.plugin if set).

repo: acme-org/my-app

defaultBranch

Type: string Default: "main"

The branch agents create feature branches off of and target for PRs.

defaultBranch: main

sessionPrefix

Type: string — must match [a-zA-Z0-9_-]+ Default: derived from path basename

Short prefix used in tmux session names and worktree directory names. AO auto-derives one from the project directory basename using the following rules (see /docs/configuration/storage#session-prefix for details):

  • 4 chars or fewer: used as-is (lowercased)
  • CamelCase: uppercase initials — PyTorchpt
  • kebab/snake case: first letter of each word — agent-orchestratorao
  • Single long word: first 3 chars — integratorint

Set this explicitly when two projects would otherwise derive the same prefix:

sessionPrefix: app1

agent

Type: string Default: defaults.agent (built-in: claude-code)

The AI agent plugin to use for this project. Overrides defaults.agent.

agent: codex

Available built-in values: claude-code, codex, aider, opencode.

runtime

Type: string Default: defaults.runtime (built-in: tmux)

Where agent processes run. tmux gives you persistent sessions you can attach to from any terminal. process is lighter but sessions are lost if AO restarts.

runtime: tmux

workspace

Type: string Default: defaults.workspace (built-in: worktree)

How code is isolated per session. worktree uses git worktree add on your existing clone — fast and disk-efficient. clone does a full git clone — slower but completely independent.

workspace: worktree

tracker

Type: object Default: inferred from repo

Issue tracker configuration. When repo is set, AO infers github or gitlab automatically. Override by setting plugin:

tracker:
  plugin: linear
  teamId: "ENG"

For external tracker plugins, specify package (npm) or path (local) instead of plugin:

tracker:
  package: "@acme/ao-plugin-tracker-jira"

Built-in tracker values: github, linear, gitlab.

Extra keys under tracker (trackerConfig)

The tracker schema is open (passthrough) — any extra keys you provide are forwarded to the tracker plugin as its config. Common fields vary by plugin:

GitHub tracker:

tracker:
  plugin: github
  labels: [agent, automated]
  assignee: octocat
  milestone: "Q1 2025"

GitLab tracker:

tracker:
  plugin: gitlab
  host: https://gitlab.example.com
  labels: [agent]

Linear tracker:

tracker:
  plugin: linear
  teamId: "ENG"
  priority: 2

Check each tracker plugin's documentation for the full list of supported keys.

scm

Type: object Default: inferred from repo

Source control management configuration. AO infers github or gitlab from the repo value if omitted.

scm:
  plugin: github

Webhook acceleration (optional): Instead of polling every 30 seconds, configure a webhook to receive instant CI and review events:

scm:
  plugin: github
  webhook:
    enabled: true
    path: /api/webhooks/github
    secretEnvVar: GITHUB_WEBHOOK_SECRET
    signatureHeader: x-hub-signature-256
    eventHeader: x-github-event
    deliveryHeader: x-github-delivery
    maxBodyBytes: 1048576

Set GITHUB_WEBHOOK_SECRET in your environment. Point the GitHub webhook at http://your-host:3000/api/webhooks/github.

Type: string[] Default: none

Files or directories to symlink from the project root into each workspace. Useful for .env files and agent config directories that agents need but that should not be committed or duplicated.

symlinks:
  - .env
  - .claude

Paths are relative to path. AO logs a warning and skips symlinks that do not exist.

postCreate

Type: string[] Default: none

Shell commands to run inside the workspace after it is created, before the agent starts. If any command fails, AO logs the error and does not start the agent.

postCreate:
  - "pnpm install"
  - "cp .env.example .env"

agentConfig

Type: object Default: {}

Agent-specific settings applied to all agents for this project.

agentConfig.permissions

Type: "permissionless" | "default" | "auto-edit" | "suggest" Default: "permissionless"

Controls how strictly the agent asks for permission before making changes. The legacy value "skip" is accepted and treated as "permissionless".

ValueBehavior
permissionlessAgent makes all edits and runs commands without prompting
defaultAgent uses the tool's own built-in permission behavior
auto-editAgent auto-approves file edits but asks for other actions
suggestAgent only suggests changes, never applies them
agentConfig:
  permissions: permissionless

agentConfig.model

Type: string Default: agent's built-in default

Override the model the agent uses. Accepted values depend on the agent:

agentConfig:
  model: claude-sonnet-4-5

For Claude Code: claude-opus-4, claude-sonnet-4-5, claude-haiku-3-5, etc. For Codex: any model string supported by the Codex CLI.

agentConfig.orchestratorModel

Type: string Default: same as model

When using multi-agent mode, the model used specifically by the orchestrator agent. Lets you run a capable model for planning and a faster one for worker tasks.

agentConfig:
  model: claude-haiku-3-5
  orchestratorModel: claude-opus-4

orchestrator

Type: object Default: none

Per-role config overrides for the orchestrator agent. This is a headline feature of multi-agent mode — it lets you assign a different agent or model to the orchestrator role without changing the global agent setting.

orchestrator:
  agent: claude-code
  agentConfig:
    model: claude-opus-4

See Per-role agent overrides for a full walkthrough of setting up orchestrator/worker role splits.

Fields available under orchestrator:

FieldTypeDescription
agentstringAgent plugin name for this role
agentConfig.permissionsenumPermission mode for this role (same values as top-level)
agentConfig.modelstringModel override for this role
agentConfig.orchestratorModelstringNested orchestrator model (advanced)

worker

Type: object Default: none

Per-role config overrides for worker agents. Same shape as orchestrator. Use this to run a faster or cheaper model for routine coding tasks:

worker:
  agent: codex
  agentConfig:
    model: gpt-4o
    permissions: permissionless

agentRules

Type: string Default: none

Inline instructions included in every agent prompt for this project (Layer 3 of the three-layer prompt system). Written as a multi-line YAML string. This is the fastest way to add project-specific rules:

agentRules: |
  Always run the test suite before pushing: `pnpm test`.
  Use conventional commits: feat:, fix:, chore:, etc.
  Never modify package.json directly — use pnpm add/remove.
  Target Node.js 20+. Do not use CommonJS require().

agentRulesFile

Type: string Default: none

Path to a Markdown rules file, relative to path. Use this when your rules are long or you want to version-control them separately:

agentRulesFile: .agent-rules.md

If both agentRules and agentRulesFile are set, both are included in the prompt.

orchestratorRules

Type: string Default: none

Rules applied only to the orchestrator agent. Same multi-line string format as agentRules. Useful for giving the orchestrator specific decomposition or delegation instructions:

orchestratorRules: |
  Break each issue into at most 3 sub-tasks.
  Delegate implementation to workers; review their output before merging.

opencodeIssueSessionStrategy

Type: "reuse" | "delete" | "ignore" Default: none

Only relevant when agent: opencode. Controls what AO does when an existing OpenCode session is found for the same issue on re-spawn:

ValueBehavior
reuseAttach to the existing session and continue
deleteDelete the old session and start fresh
ignoreLeave the old session running and create a new one

orchestratorSessionStrategy

Type: "reuse" | "delete" | "ignore" | "delete-new" | "ignore-new" | "kill-previous" Default: none

Controls what AO does when an existing orchestrator session is found for the same issue. Useful for recovering from restarts without losing work.

ValueBehavior
reuseAttach to the existing orchestrator session
deleteDelete the old session, start a new one
ignoreLeave the old session, start a second one alongside it
delete-newDelete any new session if one is found (keep old)
ignore-newIgnore any new session if one is found
kill-previousKill the previous session before starting the new one

reactions

Type: Record<string, partial ReactionConfig> Default: none

Per-project overrides for reaction settings. Keys correspond to the global reactions keys. Only the fields you specify are overridden — everything else falls through to the global reaction config.

reactions:
  approved-and-green:
    auto: true       # auto-merge enabled for this project only
  ci-failed:
    retries: 5       # more retries than the global default

See Reactions for the full list of reaction events and available fields.

Complete example

projects:
  my-app:
    name: My App
    repo: acme-org/my-app
    path: ~/projects/my-app
    defaultBranch: main
    sessionPrefix: app

    agent: claude-code
    runtime: tmux
    workspace: worktree

    tracker:
      plugin: github
      labels: [agent, automated]
      assignee: octocat

    scm:
      plugin: github
      webhook:
        enabled: true
        path: /api/webhooks/github
        secretEnvVar: GITHUB_WEBHOOK_SECRET

    symlinks:
      - .env
      - .claude

    postCreate:
      - "pnpm install"
      - "cp .env.example .env"

    agentConfig:
      permissions: permissionless
      model: claude-sonnet-4-5

    orchestrator:
      agent: claude-code
      agentConfig:
        model: claude-opus-4

    worker:
      agentConfig:
        model: claude-haiku-3-5

    agentRules: |
      Run `pnpm test` before every commit.
      Use conventional commits (feat:, fix:, chore:, etc.).
      Never push directly to main.

    agentRulesFile: .agent-rules.md

    orchestratorRules: |
      Break large issues into at most 3 sub-tasks.

    reactions:
      approved-and-green:
        auto: true
      ci-failed:
        retries: 5

Common failure modes

"Project ID must match [a-zA-Z0-9_-]+" — the project map key contains a dot, slash, or other special character. Rename org.my-app to org-my-app or my-app.

Duplicate map key silently collapsed — if you list the same project ID twice in YAML, standard YAML parsers keep only the last definition. AO will run with the second entry and silently drop the first. Use unique keys.

"Duplicate session prefix detected" — two projects auto-derive the same prefix from their directory basenames (e.g. both ~/work/api and ~/personal/api produce prefix api). Add an explicit sessionPrefix to at least one of them to resolve the conflict — AO prints a suggested fix in the error message.

"Duplicate project ID detected" — two project paths share the same directory basename. AO uses the basename as an internal project ID for storage paths. Rename one of the directories, or set sessionPrefix explicitly (which resolves the storage collision).

Missing GITHUB_TOKEN / GITLAB_TOKEN — the SCM and tracker plugins require an auth token in the environment. Without it, issue fetch and PR creation will fail at spawn time with an authentication error.

postCreate command fails — AO logs the error and skips starting the agent. Check that all dependencies (e.g. pnpm) are available on $PATH and that any referenced files (e.g. .env.example) exist.