Files
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
ci / test (push) Waiting to run
ci / lint-and-format (push) Waiting to run
ci / build (push) Waiting to run
ci / dev-startup (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
gitleaks / gitleaks (push) Waiting to run
Markdown Links / Relative Markdown Links (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Quality (Extended) / Homepage Build (PR smoke) (push) Waiting to run
Quality (Extended) / Comment-only diff guard (push) Waiting to run
Quality (Extended) / Format + Type Safety Ratchet (push) Waiting to run
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Waiting to run
Quality (Extended) / Develop Gate (lint) (push) Waiting to run
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00
..

@elizaos/plugin-agent-orchestrator

npm version CI License: MIT

The canonical orchestration plugin for elizaOS task agents. Spawns local coding agents (elizaos, pi-agent, opencode, codex, claude) through Agent Client Protocol transports, routes their output back through the runtime so the main agent decides what to do, and bundles workspace lifecycle, GitHub PR integration, task share, and supporting services in a single package.

Naming: this plugin is not the same thing as @elizaos/plugin-acp. That package is Shaw's ACP gateway client (IDE bridge over a remote ACP gateway). @elizaos/plugin-agent-orchestrator is the task backend that runs coding agents as subprocesses on the same host as the runtime.

Vocabulary: the work items this plugin manages (OrchestratorTaskRecord, orchestrator_tasks) are coding tasks — always qualify them as such in prose and UI, never the bare word "task" (which is reserved for the core runtime Task primitive). A coding task has no cron/recurrence; scheduling belongs to the trigger layer, not here. See docs/automation-glossary.md.

What it does

The plugin combines three concerns:

  1. Spawn coding agents via ACP. The default path embeds ACP JSON-RPC session management in this plugin and talks directly to an ACP-compatible agent process; the legacy path can still shell out to acpx when ELIZA_ACP_TRANSPORT=cli.
  2. Route sub-agent terminal events (task_complete, error, blocked) and swarm coordination events back into the runtime as synthetic inbound messages addressed to the task room, worktree room, or original roomId/userId/messageId. The main agent's normal action layer then decides whether to REPLY to the user, SEND_TO_AGENT to push the sub-agent further, ask the task creator a question, or coordinate with other agents. See docs/sub-agent-routing.md.
  3. Coordinate workspace lifecycle (clone, branch, commit, push, PR open) and GitHub issue management for repo-hosted tasks.

Installation

npm install @elizaos/plugin-agent-orchestrator

Native TypeScript ACP is the default transport. Set the default coding agent with ELIZA_ACP_DEFAULT_AGENT (elizaos, pi-agent, or opencode are the primary supported defaults):

export ELIZA_ACP_TRANSPORT=native
export ELIZA_ACP_DEFAULT_AGENT=elizaos
export ELIZA_ELIZAOS_ACP_COMMAND="eliza-code-acp"
export ELIZA_PI_AGENT_ACP_COMMAND="pi-agent"
export ELIZA_CODEX_ACP_COMMAND="npx -y @zed-industries/codex-acp@0.14.0"
export ELIZA_CLAUDE_ACP_COMMAND="npx -y @agentclientprotocol/claude-agent-acp@0.34.0"

Authenticate the underlying agent you plan to use before spawning sessions. Native Codex and Claude defaults use npx, so pin or replace those commands in production if you do not want runtime downloads.

The legacy command-wrapper path remains available for compatibility:

npm install -g acpx@latest
export ELIZA_ACP_TRANSPORT=cli

Adapter packaging decision: this release does not vendor the Codex or Claude ACP adapter packages. Native transport is the default; Codex and Claude use pinned npx commands unless deployment config overrides them. OpenCode is the exception: the package prefers the bundled OpenCode shim when available, then falls back to opencode acp.

coding-agent-adapters is a runtime registry/API dependency used by this plugin's agent inventory and routes; it is not a bundled Codex or Claude ACP adapter executable.

Quick start

import agentOrchestratorPlugin from "@elizaos/plugin-agent-orchestrator";

export default {
  plugins: [agentOrchestratorPlugin],
};

Action surface

All actions are virtual sub-operations of the single TASKS parent action, promoted via promoteSubactionsToActions with the TASKS_ prefix.

Promoted action Sub-operation Purpose
TASKS_CREATE create One-shot: spawn + prompt + return. Captures origin metadata for routing.
TASKS_SPAWN_AGENT spawn_agent Start a long-lived ACP coding-agent session. Returns active session info.
TASKS_SEND send Send a follow-up prompt to a running session (SEND_TO_AGENT simile).
TASKS_STOP_AGENT stop_agent Cooperatively cancel + close a session.
TASKS_LIST_AGENTS list_agents List active and persisted sessions.
TASKS_CANCEL cancel Cancel an in-flight task while preserving history.
TASKS_HISTORY history Retrieve past task sessions.
TASKS_CONTROL control Lifecycle control: pause/resume/stop/continue/archive/reopen.
TASKS_SHARE share Share a task session.
TASKS_PROVISION_WORKSPACE provision_workspace Clone repo, create git worktree for a task.
TASKS_SUBMIT_WORKSPACE submit_workspace Commit, push, open PR for a workspace.
TASKS_MANAGE_ISSUES manage_issues GitHub issue create/list/get/update/comment/close/reopen/add_labels.
TASKS_ARCHIVE archive Archive a completed coding task.
TASKS_REOPEN reopen Reopen an archived task.

Providers

  • AVAILABLE_AGENTS — adapter inventory + raw session list.
  • ACTIVE_SUB_AGENTS — cache-stable view of currently-routed sub-agent sessions; sorted by sessionId, structural fields only (no timestamps, no message excerpts), so the planner-visible block stays cached across status flips.
  • ACTIVE_WORKSPACE_CONTEXT — live workspace/session state.
  • CODING_AGENT_EXAMPLES — structured action call examples.
  • CODING_SESSION_CHANGES — real git changeset for "show me the diff" queries.

Services

  • AcpService — ACP subprocess lifecycle, session state, event emission, and transport selection. Registers under ACP_SUBPROCESS_SERVICE.
  • OrchestratorTaskService — durable task store, sub-agent lifecycle API, event bridge from ACP to task records. Registers under ORCHESTRATOR_TASK_SERVICE.
  • SubAgentRouter — subscribes to AcpService.onSessionEvent, posts terminal-event synthetic memories to runtime.messageService.handleMessage. Registers under ACPX_SUB_AGENT_ROUTER. Per-session round-trip cap (ACPX_SUB_AGENT_ROUND_TRIP_CAP, default 32) force-stops runaway loops. Disable with ACPX_SUB_AGENT_ROUTER_DISABLED=1.
  • CodingWorkspaceService — git workspace lifecycle helpers. Registers under CODING_WORKSPACE_SERVICE.
import { AcpService, SubAgentRouter } from "@elizaos/plugin-agent-orchestrator";

const acp = runtime.getService("ACP_SUBPROCESS_SERVICE") as AcpService;

const { sessionId } = await acp.spawnSession({
  agentType: "codex",
  workdir: "/tmp/my-task",
  approvalPreset: "permissive",
  metadata: {
    roomId: message.roomId,
    userId: message.entityId,
    messageId: message.id,
    label: "fix bug 42",
  },
});

const result = await acp.sendPrompt(sessionId, "what is 7 + 8?");
console.log(result.finalText);     // "15"
console.log(result.stopReason);    // "end_turn"
console.log(result.durationMs);    // 4864

Subscribing to events

acp.onSessionEvent((sessionId, eventName, data) => {
  // eventName: "ready" | "message" | "tool_running" | "task_complete" | "stopped" | "error" | "blocked" | "login_required" | "reconnected"
  // data shape depends on eventName, see SessionEventName in src/services/types.ts
});

The task_complete event:

{ response: string, durationMs: number, stopReason: "end_turn" | "error" | string }

You usually don't subscribe directly — SubAgentRouter already does, and routes terminal events into the runtime. Subscribe only if you need raw access (e.g. dashboards).

Configuration

All configuration is via environment variables. Use ELIZA_ACP_TRANSPORT=native for the embedded TypeScript ACP client and ELIZA_ACP_TRANSPORT=cli only when you deliberately want the existing acpx wrapper.

Variable Default Purpose
ELIZA_ACP_TRANSPORT native Transport mode. Accepted values include native/direct and cli/acpx.
ELIZA_ACP_CLI acpx ACPX executable name or absolute path for the CLI transport.
ELIZA_ACP_DEFAULT_AGENT elizaos Default agent type. Primary choices: elizaos, pi-agent, opencode.
ELIZA_ELIZAOS_ACP_COMMAND eliza-code-acp Native elizaOS ACP command.
ELIZA_PI_AGENT_ACP_COMMAND pi-agent Native Pi Agent ACP command.
ELIZA_CODEX_ACP_COMMAND npx -y @zed-industries/codex-acp@0.14.0 Native Codex ACP command.
ELIZA_CODEX_ACP_SANDBOX_MODE / ELIZA_CODEX_SANDBOX_MODE unset Optional Codex ACP sandbox_mode override: read-only, workspace-write, or danger-full-access.
ELIZA_CODEX_ACP_NO_LANDLOCK_SANDBOX_MODE danger-full-access Codex ACP sandbox mode used when Linux Landlock is unavailable.
ELIZA_CODEX_ACP_APPROVAL_POLICY / ELIZA_CODEX_APPROVAL_POLICY never for no-Landlock fallback, otherwise unset Optional Codex ACP approval_policy override.
ELIZA_CODEX_ACP_LANDLOCK / ELIZA_CODEX_LANDLOCK auto-detect Force Landlock detection for containers/tests: 1/true or 0/false.
ELIZA_CLAUDE_ACP_COMMAND npx -y @agentclientprotocol/claude-agent-acp@0.34.0 Native Claude ACP command.
ELIZA_OPENCODE_ACP_COMMAND bundled shim or opencode acp Native OpenCode ACP command override.
ELIZA_ACP_DEFAULT_APPROVAL autonomous Approval preset (read-only, auto, permissive, autonomous, full-access).
ELIZA_ACP_PROMPT_TIMEOUT_MS / ACPX_DEFAULT_TIMEOUT_MS 300000 (5m) Per-prompt timeout.
ELIZA_ACP_STATE_DIR ~/.eliza/plugin-acp Where to persist session state when no runtime DB.
ACPX_DEFAULT_CWD runtime cwd Base directory for spawned agent workdirs.
ELIZA_ACP_MAX_SESSIONS 8 Concurrent session cap.
ACPX_SUB_AGENT_ROUTER_DISABLED unset Set to 1 to keep the router service registered but unbound (test/staging).
ACPX_SUB_AGENT_ROUND_TRIP_CAP 32 Per-session inject cap before force-stop to prevent ping-pong loops.
ACPX_PROGRESS_MODE / ELIZA_SUB_AGENT_PROGRESS_MODE compact Sub-agent progress UX: compact delays and edits one status message, threaded preserves per-task threads, silent disables visible progress.
ACPX_PROGRESS_DELAY_MS / ELIZA_SUB_AGENT_PROGRESS_DELAY_MS 15000 Delay before the first visible progress message, so short tasks only show the final answer.
ACPX_PROGRESS_REACTIONS / ELIZA_SUB_AGENT_PROGRESS_REACTIONS unset Set to 1 to add progress reactions in threaded mode.

Native transport status

Native transport is an ACP JSON-RPC client. It currently handles initialize, session/new, session/prompt, cooperative session/cancel, session/close, file reads/writes scoped to the session workspace, permission requests, and basic terminal requests from the agent.

Use the CLI transport only when you need the existing acpx command wrapper semantics.

GitHub credentials

Every GitHub-touching capability needs a credential before it can act. Without one, the operation fails with a clean error naming both accepted settings (ensureGitHubClient in src/services/workspace-github.ts).

Which capabilities need a token:

Capability What breaks without a token
TASKS_MANAGE_ISSUES create / list / get / update / comment / close / reopen / add-labels on GitHub issues (src/services/workspace-github.ts).
TASKS_SUBMIT_WORKSPACE authenticated commit / push / open-PR against the remote (src/services/workspace-service.tsworkspace-git-ops.ts).

Read-only actions (spawn, provision-workspace against a public repo) do not require a token; anything that writes to GitHub does.

Two ways to supply the credential:

  1. Personal access token (PAT) — set GITHUB_TOKEN. Read at act-time via runtime.getSetting("GITHUB_TOKEN"), so it can be stored per-agent in the vault/settings and rotated without a restart. This is the path a live multi-tenant deployment uses: the agent acts as its own bot account with zero GITHUB_* in process env.
  2. OAuth device flow — set GITHUB_OAUTH_CLIENT_ID (via getSetting) and the server-side GITHUB_OAUTH_CLIENT_SECRET (read directly from process env, deliberately kept out of the plugin getSetting allowlist). On first GitHub access the agent surfaces a device-code prompt (verification URI + user code) through an immediate, user-visible channel and polls until the user completes login. The flow requires an authPromptCallback wired to a live chat path — a buffered action callback is unsafe because the flow blocks on user consent.

When both are present, GITHUB_TOKEN wins.

Multi-tenant safety — prefer vault/settings over process env. A GITHUB_TOKEN placed in the host process environment is visible to every agent sharing that host, so on a shared/cloud deployment one tenant's token would act on behalf of all of them. Store the token per-agent in the runtime settings/vault instead, where runtime.getSetting("GITHUB_TOKEN") scopes it to the single agent. The service does fall back to process.env.GITHUB_TOKEN for the git push/PR path, but that fallback is a single-tenant/local-dev convenience — do not rely on it on a shared host.

Persistence

Session state is persisted with a tiered backend:

  1. If runtime.databaseAdapter exposes SQL methods, sessions live in the acp_sessions table.
  2. Otherwise, JSON file at $ELIZA_ACP_STATE_DIR/sessions.json (atomic writes via temp+rename).
  3. Last resort: in-memory Map (warns that sessions won't survive restart).

End-to-end smoke tests

These live smokes ship with the repo:

# Native AcpService against Codex ACP. No global acpx is required; the default
# native Codex command is `npx -y @zed-industries/codex-acp@0.14.0`.
# Authenticate Codex first.
bun run build
RUN_LIVE_NATIVE_ACP=1 bun run test:e2e:native

# Native ACP smoke through Vitest (gated):
RUN_LIVE_NATIVE_ACP=1 bun run test -- __tests__/live/native-acp-smoke.live.test.ts

# Legacy CLI transport smoke against installed acpx + codex:
npm install -g acpx@latest
ELIZA_ACP_TRANSPORT=cli node tests/e2e/acp-codex-smoke.mjs

# Legacy full router loop through acpx (vitest, gated):
RUN_LIVE_ACPX=1 ELIZA_ACP_TRANSPORT=cli bun run test -- __tests__/live/sub-agent-router.live.test.ts

live-native-acp-smoke.mjs exercises the default native path by spawning a real Codex ACP session through npx -y @zed-industries/codex-acp@0.14.0, sending "what is 7 + 8?", and verifying task_complete fires with response "15". The Vitest wrapper is skipped unless RUN_LIVE_NATIVE_ACP=1 is set; when enabled, it requires NATIVE ACP SMOKE PASSED.

acp-codex-smoke.mjs and __tests__/live/sub-agent-router.live.test.ts exercise the legacy acpx CLI transport. They require ELIZA_ACP_TRANSPORT=cli and an installed/authenticated acpx + Codex environment.

live-native-acp-smoke.mjs sets ELIZA_ACP_TRANSPORT=native, starts a native ACP adapter over stdio, sends a tiny math prompt, and verifies the prompt response ended with stopReason: "end_turn" and final text containing 15. Optional providers require explicit commands:

RUN_LIVE_NATIVE_ACP=1 LIVE_NATIVE_ACP_AGENT=claude ELIZA_CLAUDE_ACP_COMMAND="npx -y @agentclientprotocol/claude-agent-acp@0.34.0" node tests/e2e/live-native-acp-smoke.mjs
RUN_LIVE_NATIVE_ACP=1 LIVE_NATIVE_ACP_AGENT=opencode ELIZA_OPENCODE_ACP_COMMAND="opencode acp" node tests/e2e/live-native-acp-smoke.mjs

The native smoke skips successfully when RUN_LIVE_NATIVE_ACP is unset, when an optional provider command is not configured, or when the adapter reports missing authentication/credentials. Use RUN_LIVE_NATIVE_ACP=1 bun run test -- __tests__/live/native-acp-smoke.live.test.ts to run the same smoke through Vitest.

Native transport is covered by unit tests under __tests__/unit/acp-native-transport.test.ts and by the gated live smoke above.

Package scripts

Script Purpose
bun run build / bun run build:ts Build Node ESM, CJS, and declaration outputs.
bun run dev Rebuild in watch mode.
bun run typecheck Run TypeScript without emitting files.
bun run test Run the plugin vitest suite.
bun run test:unit Run unit tests only.
bun run test:e2e:manual Run the manual acp-codex-smoke.mjs smoke against installed/authenticated acpx + Codex.
bun run test:e2e:native Run the gated native ACP smoke using the configured native agent command.
bun run test:watch Run the vitest suite in watch mode.
bun run lint:check Run Biome checks without writing changes.
bun run lint Run Biome checks with write/unsafe fixes.
bun run format:check Check formatting.
bun run format Write formatting changes.
bun run clean Remove local build/cache outputs.

Status

2.0.3-beta.14 — package. ACP subprocess sessions are the only task-agent spawn path. The native ACP client is the default (ELIZA_ACP_TRANSPORT=native).

Contributing

PRs welcome. Run npm run typecheck && npm test before opening.

License

MIT. See LICENSE.