29 KiB
@elizaos/plugin-agent-orchestrator
Canonical elizaOS plugin for spawning and orchestrating coding sub-agents via the Agent Client Protocol (ACP), with workspace lifecycle, GitHub integration, task history, and runtime-driven sub-agent routing.
Purpose / role
This plugin adds a full coding-agent orchestration surface to any Eliza agent. It spawns local coding agents (elizaos, pi-agent, opencode, codex, claude) as ACP subprocesses, routes their terminal events back into the elizaOS runtime as synthetic inbound messages, and manages the git workspace and GitHub issue lifecycle that accompanies repo-hosted coding tasks.
Loaded by name: @elizaos/plugin-agent-orchestrator. Not default-enabled —
add it explicitly in the agent's plugin list. Services and actions are only
registered when isLocalCodeExecutionAllowed() AND terminal support is detected;
on sandboxed or store-distributed runtimes the plugin registers a single stub
action that surfaces a clean error.
Plugin surface
Actions (from tasksAction via promoteSubactionsToActions)
All are sub-operations of the single TASKS parent action:
| Sub-action name | Promoted action | Purpose |
|---|---|---|
create |
TASKS_CREATE |
One-shot: spawn + prompt + return. Records origin metadata for routing. |
spawn_agent |
TASKS_SPAWN_AGENT |
Start a long-lived ACP coding-agent session. Returns active session info. |
send |
TASKS_SEND |
Send a follow-up prompt to a running session. (SEND_TO_AGENT is a simile.) |
stop_agent |
TASKS_STOP_AGENT |
Cooperatively cancel and close a session. |
list_agents |
TASKS_LIST_AGENTS |
List active and persisted sessions. |
cancel |
TASKS_CANCEL |
Cancel an in-flight task, preserve history. |
history |
TASKS_HISTORY |
Retrieve past task sessions. |
control |
TASKS_CONTROL |
Lifecycle control: pause/resume/stop/continue/archive/reopen. |
share |
TASKS_SHARE |
Share a task session. |
provision_workspace |
TASKS_PROVISION_WORKSPACE |
Clone repo, create git worktree for a task. |
submit_workspace |
TASKS_SUBMIT_WORKSPACE |
Commit, push, open PR for a workspace. |
manage_issues |
TASKS_MANAGE_ISSUES |
GitHub issue create/list/get/update/comment/close/reopen/add_labels. |
archive |
TASKS_ARCHIVE |
Archive a completed coding task. |
reopen |
TASKS_REOPEN |
Reopen an archived task. |
Providers
| Name | Purpose |
|---|---|
AVAILABLE_AGENTS |
Adapter inventory + raw ACP session list |
ACTIVE_SUB_AGENTS |
Cache-stable view of active routed sessions (structural fields only, no timestamps) |
ACTIVE_WORKSPACE_CONTEXT |
Live workspace/session state for the planner |
CODING_AGENT_EXAMPLES |
Structured action-call examples injected into planner context |
CODING_SESSION_CHANGES |
Real git changeset for "show me the diff" queries |
Services
| Class | serviceType |
Purpose |
|---|---|---|
AcpService |
ACP_SUBPROCESS_SERVICE |
ACP subprocess lifecycle, session state, event emission, transport selection |
OrchestratorTaskService |
ORCHESTRATOR_TASK_SERVICE |
Durable task store, sub-agent lifecycle API, event bridge from ACP to task records |
SubAgentRouter |
ACPX_SUB_AGENT_ROUTER |
Subscribes to AcpService events, routes terminal events into the runtime as synthetic memories |
CodingWorkspaceService |
CODING_WORKSPACE_SERVICE |
Git workspace lifecycle (clone, branch, commit, push, PR) |
Evaluator
subAgentCompletionResponseEvaluator—ResponseHandlerEvaluatorthat fires when atask_completeevent is received via a synthetic sub-agent memory; synthesizes a planner-ready completion summary turn.
HTTP routes (registered via register-routes.ts side-effect)
All under the elizaOS runtime HTTP server:
| Path prefix | Handler | Purpose |
|---|---|---|
/api/orchestrator/* |
handleOrchestratorRoutes |
Durable task CRUD, lifecycle, event log, usage rollup |
/api/coding-agents/* |
handleAgentRoutes |
ACP session CRUD: list, spawn, get, send, stop, output |
/api/coding-agents/:id/credentials/* |
handleBridgeRoutes |
Credential bridge (request + long-poll redemption) for spawned sub-agents |
/api/coding-agents/:id/{parent-context,memory,active-workspaces} |
handleParentContextRoutes |
Read-only parent-context bridge: memory, workspace state |
/api/workspace/* |
handleWorkspaceRoutes |
Git workspace: provision, status, commit, push, PR, delete |
/api/issues/* |
handleIssueRoutes |
GitHub issue CRUD (separate from manage_issues action) |
/api/task-agents/* |
(aliased to /api/coding-agents/*) |
Legacy path alias |
Events
- Listens to
EventType.MESSAGE_RECEIVED(forwarding live user messages to the active sub-agent for the same roomId). - Emits
TASK_AUDIT_EVENTto persist append-only audit log entries. - Wraps
runtime.sendMessageToTargetto redirect planner replies into the per-task thread when thread support is available.
Device × backend × auth-mode support matrix
Coding-agent orchestration is gated per device by the same pure classifier the
runtime uses (classifyTerminalSupport / detectOrchestratorTerminalSupport in
services/terminal-capabilities.ts). The checked-in source of truth is
ORCHESTRATOR_DEVICE_SUPPORT_MATRIX (services/orchestrator-device-support-matrix.ts),
computed through that classifier so it cannot silently drift from the gate — a
gating change that affects any documented profile fails this package's tests
(orchestrator-device-support-matrix.test.ts). Do not hand-edit the matrix to
disagree with the classifier; change the classifier and let the matrix follow.
See issue #9146.
| Device profile | Supported? | Reason | Coding backends |
|---|---|---|---|
| Desktop / server (Node, non-store) | ✅ | — | all 5 |
| Android direct/AOSP local-yolo (staged shell) | ✅ | — | all 5 |
| iOS (vanilla mobile runtime) | ❌ | vanilla_mobile |
none — stub action only |
| Store build (sandboxed distribution) | ❌ | store_build |
none — stub action only |
| Android Play/store build (not local-yolo) | ❌ | not_local_yolo |
none — stub action only |
Classifier precedence: store_build > vanilla_mobile (iOS) > not_local_yolo
(Android non-yolo) > missing staged shell. When a device is supported every
backend below is reachable; when unsupported only the stub action registers
(see "Gated by isLocalCodeExecutionAllowed() AND terminal support" below).
Topology decision (#9146): local coding-agent subprocess execution is a
host capability, not a per-client guarantee. Desktop/server Node runtimes and
Android direct/AOSP local-yolo builds may run the orchestrator locally. iOS,
Android Play/store, Mac App Store, and other sandboxed/store builds do not spawn
local coding CLIs; they should operate as remote controllers for a desktop/cloud
host orchestrator via the shared /api/orchestrator/* and
/api/coding-agents/* HTTP surfaces. Account selection, subscription token
materialization, and API-key dropping happen on that host, so web, desktop, and
Capacitor mobile clients all observe the same selected-account behavior when
they call the host APIs. Voice is in scope as an input modality: a voice turn
creates or messages the same orchestrator task/session, and the completion is
narrated by the normal task transcript/progress path rather than by a separate
voice-only scheduler.
Backend → auth-mode reach (ORCHESTRATOR_BACKEND_AUTH, mirroring
AGENT_PROVIDER_CANDIDATES in
packages/app-core/src/services/coding-account-bridge.ts; subscription is
preferred over API key):
| Backend | Auth modes (preferred → fallback) |
|---|---|
elizaos |
runtime-routed |
pi-agent |
runtime-routed |
claude |
anthropic-subscription → anthropic-api |
codex |
openai-codex → openai-api |
opencode |
cerebras-api |
Layout
plugins/plugin-agent-orchestrator/
src/
index.ts Plugin factory (createAgentOrchestratorPlugin),
progress hook (registerProgressHook), exports
register-routes.ts Side-effect: registers HTTP routes with the runtime
setup-routes.ts Route wiring helpers
actions/
tasks.ts TASKS parent action + all sub-action runners
common.ts Shared action helpers (getAcpService, labelFor, etc.)
elizaos-capability.ts elizaOS-specific capability action
sandbox-stub.ts Stub actions for sandboxed/no-terminal runtimes
providers/
available-agents.ts AVAILABLE_AGENTS provider
active-sub-agents.ts ACTIVE_SUB_AGENTS provider
active-workspace-context.ts ACTIVE_WORKSPACE_CONTEXT provider
action-examples.ts CODING_AGENT_EXAMPLES provider
coding-session-changes.ts CODING_SESSION_CHANGES provider
evaluators/
sub-agent-completion.ts ResponseHandlerEvaluator for task_complete events
services/
acp-service.ts AcpService — subprocess lifecycle, session store,
transport selection (native vs cli)
acp-native-transport.ts NativeAcpClient (ACP JSON-RPC over stdio)
sub-agent-router.ts SubAgentRouter service — terminal event → synthetic memory
orchestrator-task-service.ts OrchestratorTaskService — durable task lifecycle
orchestrator-task-store.ts Task persistence (DB or JSON file)
orchestrator-task-mapper.ts DTOs: TaskThreadDto, TaskThreadDetailDto
orchestrator-task-types.ts Type definitions for durable tasks
workspace-service.ts CodingWorkspaceService — delegates to sub-modules
workspace-lifecycle.ts GC, scratch dir cleanup
workspace-git-ops.ts Status, commit, push, PR creation
workspace-github.ts GitHub issue management, OAuth, PAT auth
workspace-types.ts Shared workspace type definitions
workspace-diff.ts Git diff utilities for workspace
session-store.ts AcpSessionStore / RuntimeDbSessionStore /
FileSessionStore / InMemorySessionStore
types.ts AgentType, SessionStatus, SessionEventName,
SpawnOptions, SessionInfo, etc.
config-env.ts Reads all env vars into a typed config object
task-agent-routing.ts Adapter/workdir resolution for spawn routing
task-agent-frameworks.ts Framework state helpers
task-policy.ts ACL: requireTaskAgentAccess
terminal-capabilities.ts detectOrchestratorTerminalSupport
skill-manifest.ts Skill manifest generation
skill-recommender.ts Skill recommendation service
ansi-utils.ts ANSI escape stripping for terminal output
spawn-trajectory.ts Trajectory capture for spawned sessions
trajectory-context.ts Trajectory context helpers
trajectory-feedback.ts Trajectory feedback processing
parent-agent-broker.ts Parent-agent context broker
parent-agent-dispatch.ts Dispatch helpers for parent-agent context
skill-lifeops-context-broker.ts LifeOps context broker for skills
agent-name-assignment.ts Agent name assignment helpers
audit.ts Audit log utilities (TASK_AUDIT_EVENT)
coding-account-selection.ts Account/credential selection for spawned agents
goal-llm-verifier.ts LLM-based goal verification for task completion
goal-prompt.ts Goal prompt construction helpers
interruption-decider.ts Decides whether to interrupt a running sub-agent
json-model-output.ts Structured JSON output helpers for model calls
opencode-config.ts OpenCode-specific ACP configuration
repo-input.ts Repository input parsing and validation
session-event-queue.ts Per-session event queue for ordered delivery
smithers-task-executor.ts TaskStepExecutor impl — drives ACP turns per step
smithers-task-integration.ts Integration layer; gates smithers via ELIZA_ORCHESTRATOR_SMITHERS
smithers-task-runner.ts High-level smithers task runner (provision→turn→submit loop)
smithers-task-types.ts Types for the smithers task execution model
spend-allowance.ts Per-session spend allowance / budget enforcement
ssrf-guard.ts SSRF protection for outbound URL fetches
sub-agent-identity.ts Sub-agent identity and credential helpers
sub-agent-inbox.ts Per-session message inbox for the interruption decider
workdir-validation.ts Working directory validation and sandboxing
api/
routes.ts Top-level route dispatcher
agent-routes.ts /api/coding-agents/* handlers
orchestrator-routes.ts /api/orchestrator/* handlers
bridge-routes.ts /api/coding-agents/:id/credentials/* handlers
parent-context-routes.ts /api/coding-agents/:id/{parent-context,memory,active-workspaces} handlers
workspace-routes.ts /api/workspace/* handlers
issue-routes.ts /api/issues/* handlers (GitHub issue CRUD)
route-utils.ts parseBody, sendJson, sendError, RouteContext
index.ts Re-export barrel (ESM root)
index.node.ts Node-specific entry
Commands
bun run --cwd plugins/plugin-agent-orchestrator build # Build Node ESM + CJS + .d.ts
bun run --cwd plugins/plugin-agent-orchestrator build:ts # TypeScript-only build
bun run --cwd plugins/plugin-agent-orchestrator dev # Watch mode rebuild
bun run --cwd plugins/plugin-agent-orchestrator typecheck # Type-check without emit
bun run --cwd plugins/plugin-agent-orchestrator test # Run vitest suite
bun run --cwd plugins/plugin-agent-orchestrator test:unit # Unit tests only
bun run --cwd plugins/plugin-agent-orchestrator test:watch # Vitest watch mode
bun run --cwd plugins/plugin-agent-orchestrator test:e2e:manual # acpx+codex smoke (requires installed acpx)
bun run --cwd plugins/plugin-agent-orchestrator test:e2e:multi-account # Multi-account smoke test
bun run --cwd plugins/plugin-agent-orchestrator lint # Biome check + write
bun run --cwd plugins/plugin-agent-orchestrator lint:check # Biome check only
bun run --cwd plugins/plugin-agent-orchestrator format # Biome format + write
bun run --cwd plugins/plugin-agent-orchestrator format:check # Biome format check only
bun run --cwd plugins/plugin-agent-orchestrator clean # Remove dist/.turbo/tsconfig artifacts
Config / env vars
All are optional unless noted. Read by src/services/config-env.ts and
src/services/acp-service.ts.
GitHub credentials gate every GitHub-writing capability (TASKS_MANAGE_ISSUES,
TASKS_SUBMIT_WORKSPACE commit/push/PR). Supply a PAT via GITHUB_TOKEN or run the
OAuth device flow via GITHUB_OAUTH_CLIENT_ID. Both are read per-agent through
runtime.getSetting in src/services/workspace-github.ts, so store the token in the
vault/settings, not process env — a process-env GITHUB_TOKEN leaks to every agent
on a shared/multi-tenant host, whereas getSetting scopes it to one agent. Full setup:
README → "GitHub credentials".
| Variable | Default | Purpose |
|---|---|---|
GITHUB_TOKEN |
unset | PAT for GitHub-writing capabilities (issues, push, PR). Read via runtime.getSetting — store per-agent in vault/settings, not process env (multi-tenant leak). Wins over device flow when both set. |
GITHUB_OAUTH_CLIENT_ID |
unset | OAuth device flow client id (read via getSetting); used when no GITHUB_TOKEN. Requires a live authPromptCallback to surface the device-code prompt. |
GITHUB_OAUTH_CLIENT_SECRET |
unset | Server-side OAuth secret for the device flow. Read directly from process env by design — deliberately kept out of the plugin getSetting allowlist. |
ELIZA_ACP_TRANSPORT |
native |
Transport: native (embedded JSON-RPC) or cli/acpx (legacy shell wrapper) |
ELIZA_ACP_CLI |
acpx |
Path/command for the CLI transport |
ELIZA_ACP_DEFAULT_AGENT |
elizaos |
Default agent type: elizaos, pi-agent, opencode |
ELIZA_DEFAULT_AGENT_TYPE |
elizaos |
Compatibility alias for ELIZA_ACP_DEFAULT_AGENT |
ELIZA_AGENT_SELECTION_STRATEGY |
fixed |
Adapter selection policy: fixed or dynamic |
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 |
ELIZA_ACP_MAX_SESSIONS |
8 |
Concurrent session cap |
ELIZA_ACP_SYSTEM_SESSION_HEADROOM |
2 |
Reserved concurrent slots for short-lived system spawns (the #8898 read-only verifier), counted separately from ELIZA_ACP_MAX_SESSIONS so validation never deadlocks behind the worker cap |
ELIZA_MAX_SPAWNS_PER_ORIGIN |
3 |
Max sub-agent spawns per root user message before relaying the best captured result instead of re-spawning (bounds the weak-model re-spawn loop) |
ELIZA_ACP_STATE_DIR |
~/.eliza/plugin-acp |
Session state persistence dir when no runtime DB |
ELIZA_ACP_SESSION_STORE_BACKEND |
unset | Override session store backend (db, file, or memory) |
ELIZA_ACP_MCP_SERVERS |
unset | JSON list of MCP servers to pass to spawned sub-agents |
ELIZA_MAX_CONCURRENT_SPAWNS |
unset | Cap on simultaneous spawn operations |
ELIZA_WORKSPACE_DIR |
unset | Default workspace root for provisioned coding workspaces |
ELIZA_CODING_DIRECTORY |
unset | Preferred directory for new coding tasks |
TASK_AGENT_WORKDIR_ROOTS |
unset | Colon-separated list of allowed workdir roots |
TASK_AGENT_WORKDIR_ROUTES |
unset | JSON routing rules mapping task labels to workdirs |
ELIZA_ORCHESTRATOR_SMITHERS |
1 (enabled) |
Set to 0 to disable the smithers task execution path and fall back to direct prompt |
ELIZA_ORCHESTRATOR_AUTO_GOAL_VERIFY |
unset | Enable LLM-based goal verification on task completion |
ELIZA_REQUIRE_GOAL_CONTRACT |
1 (enabled) |
Auto-generate 3-5 measurable default acceptance criteria for a criteria-free, non-trivial task so the verifier always fires. Set to 0 to keep criteria-free tasks criteria-free (prior behavior). |
SMITHERS_DB_PROVIDER |
unset | Database provider for smithers task storage |
SMITHERS_DB_URL |
unset | Database URL for smithers task storage |
SMITHERS_DB_DATA_DIR |
unset | Data directory for smithers file-backed storage |
ELIZA_SCRATCH_RETENTION |
unset | How long to retain scratch workspace dirs |
ELIZA_SCRATCH_DECISION_TTL_MS |
unset | TTL for scratch workspace GC decisions |
ELIZAOS_CLOUD_API_KEY / ELIZAOS_CLOUD_URL |
unset | Owner Cloud creds. Broker-first (#14118): NOT forwarded to sub-agents by default — a child reaches Cloud via the parent broker (apps.create / containers.create, spend-gated). Set ELIZA_FORWARD_CLOUD_KEY_TO_SUBAGENTS=1 to restore raw forwarding. |
ELIZA_FORWARD_CLOUD_KEY_TO_SUBAGENTS |
unset (OFF) | Opt IN to forwarding the owner's raw ELIZAOS_CLOUD* creds into every child env. Default OFF; broker-first is preferred. A structured warning logs when active. |
ACPX_DEFAULT_TIMEOUT_MS |
300000 |
Per-prompt timeout in ms |
ACPX_APPROVE_ALL |
false |
When true, defaults sessions to approve-all preset |
ACPX_NO_TERMINAL |
true |
Pass --no-terminal so agents use ACP events, not terminal UI |
ACPX_DEFAULT_CWD |
runtime cwd | Default working directory for ACP sessions |
ACPX_FORMAT |
json |
ACP event format for the legacy CLI transport |
ACPX_SUB_AGENT_ROUTER_DISABLED |
unset | Set to 1 to keep SubAgentRouter registered but unbound |
ACPX_SUB_AGENT_ROUND_TRIP_CAP |
32 |
Per-session inject cap; force-stops ping-pong loops |
ACPX_PROGRESS_MODE / ELIZA_SUB_AGENT_PROGRESS_MODE |
compact |
Progress UX: compact, threaded, or silent |
ACPX_PROGRESS_DELAY_MS / ELIZA_SUB_AGENT_PROGRESS_DELAY_MS |
15000 |
Delay before first progress post (ms) |
ACPX_PROGRESS_REACTIONS / ELIZA_SUB_AGENT_PROGRESS_REACTIONS |
unset | Set to 1 for emoji reactions in threaded mode |
ACP_AUDIT_LOG_PATH |
~/.eliza/acp-audit.log |
Append-only audit log path |
ELIZA_MODEL_GATEWAY_URL |
unset | Model-gateway mode (#11536 E2): OpenAI/Anthropic-compatible base URL a spawned sub-agent is pointed at. ON only when both this and _TOKEN are set. |
ELIZA_MODEL_GATEWAY_TOKEN |
unset | Gateway credential injected into the sub-agent (as OPENAI_API_KEY/ANTHROPIC_API_KEY) in place of raw provider keys. In lease mode this is the parent-only, mint-capable token — never forwarded to the child. |
ELIZA_MODEL_GATEWAY_LEASE_URL |
unset | Broker lease endpoint (#11536 E2 residual). When set (with gateway mode on), each spawn mints a per-spawn, TTL-bound, revocable lease (POST → { token, expiresAt, leaseId }; revoke POST <url>/<leaseId>/revoke) and the child gets the leased token, not the static one. Unset ⇒ static-token fallback. |
ELIZA_MODEL_GATEWAY_STRICT |
unset | 1/true fails a spawn closed rather than hand a sub-agent a static long-lived gateway token when a lease broker is expected but absent or the mint fails. |
How to extend
Add a new sub-action to TASKS:
- Add the sub-operation name to the
tasksschema insrc/actions/tasks.ts. - Implement a runner function that receives
(runtime, message, state, opts, cb). - Register it in the
switchblock oftasksAction.handler. - Export the standalone action alias from
src/index.tsif external callers need it.
Add a provider:
- Create
src/providers/<name>.tsimplementingProviderfrom@elizaos/core. - Import and add it to
orchestratorProvidersinsrc/index.ts.
Add a service:
- Extend
Servicefrom@elizaos/coreinsrc/services/<name>.ts. - Add it to
orchestratorServicesinsrc/index.ts. - Add it to the eager-start list in
init()if it must be available before the first message.
Add an HTTP route:
- Create or extend a handler module in
src/api/. - Wire it into the dispatcher in
src/api/routes.ts→handleCodingAgentRoutes.
Conventions / gotchas
- Node-only.
package.jsoneliza.platforms=["node"]. The plugin spawns child processes and usesnode:child_process; it cannot run in a browser runtime or mobile. - Gated by
isLocalCodeExecutionAllowed()AND terminal support.detectOrchestratorTerminalSupport()returns false in sandboxed/store-distributed contexts. In those cases the plugin registers only the stub action; services and providers are skipped entirely. - Service eager-start.
init()defers service startup viasetTimeout(0)then callsruntime.getServiceLoadPromisefor each service type. Without this, the first TASKS call hitsruntime.getService()before services are registered. sendMessageToTargetwrap. The progress hook wrapsruntime.sendMessageToTargetto redirect planner replies into the per-task thread. The wrapper is removed indispose(). A__orchestratorSendWrappedmarker prevents double-wrapping.- Session persistence is tiered.
RuntimeDbSessionStore→FileSessionStore→InMemorySessionStore. The in-memory fallback logs a warning and sessions don't survive restart. - Smithers task path. By default (
ELIZA_ORCHESTRATOR_SMITHERSnot0), task execution goes through the smithers runner (smithers-task-runner.ts), which drives a structured provision→turn→submit loop. SetELIZA_ORCHESTRATOR_SMITHERS=0to revert to the direct prompt path. ACPX_SUB_AGENT_ROUND_TRIP_CAP(default 32) force-stops runaway sub-agent loops. Lower it in test environments.coding-agent-adaptersis the adapter registry/API dependency, not a bundled executable. The Codex and Claude CLI adapters are consumed via pinnednpxcommands unless deployment config overrides them.git-workspace-serviceis a peer dependency (version0.4.5). It must be installed alongside this plugin.- Workspace ACP auto-provisioning requires proven OS supervision. Linux
hosts use util-linux
flockfor exclusion and GNUtimeoutfor build-process-group termination. When either is unavailable, the service skips the workspace build and falls back toELIZA_ELIZAOS_ACP_COMMAND. Do not replace this fail-closed boundary with PID/mtime stale-lock reclamation or direct-child-only timeout handling (#16169). - Route registration side-effect.
register-routes.tsis re-exported ascodingAgentRouteRegistrationfromindex.tsto prevent Bun's tree-shaker from dropping it. Do not convert it back to a bare side-effect import. - See the root
AGENTS.mdfor repo-wide rules (logger-only, ESM, architecture commandments, naming).
⛔ NON-NEGOTIABLE — evidence, trajectories & real end-to-end tests
The binding, repo-wide standard is AGENTS.md. Read it. Nothing in this package is done until it is proven done — a reviewer must confirm it works without reading the code, from the artifacts you attach. This applies to every feature, fix, refactor, and chore here. "Tests pass" is not proof; "CI is green" is not proof.
- Record AND read model trajectories. Capture the actual inputs and outputs of the model
from a live LLM — not the deterministic proxy, not a mock: the prompt, the
providers/context, the raw model output, every tool/action call, and the result. Then open
the trajectory and review it by hand. A captured-but-unread trajectory is not evidence
(
packages/scenario-runner/bin/eliza-scenarios run <scenario> --report <out>). - Real, full-featured E2E — no larp. Every feature ships detailed end-to-end tests that drive the real path end to end. Not the happy "front door" only: cover error paths, edge/empty/invalid input, concurrency, roles/permissions, and adversarial input. A test that asserts against a mock/stub/fixture standing in for the thing under test does not count. If the real model/device/chain/connector/account is hard to reach, make it reachable — that is the work, not an excuse to mock. If the existing tests here are shallow or mocked, fixing them is part of your change.
- Screenshots + logs at every phase, plus a complete walkthrough video/run-through of
the entire feature or view, start to finish (
bun run test:e2e:record). - Manually review every artifact the change touches — never just the green check: client
logs (console + network), server logs (
[ClassName] …), the model trajectories in and out, before/after full-page screenshots, and the domain artifacts listed below for this package. - No residuals. No shortcuts. The goal is not "done" — it is everything done. Clear every blocker by the hard path: build the real architecture, stand up the real model/device/service, actually test it. Never leave a TODO, a stub, a stepping-stone, or a "follow-up." When unsure, research thoroughly, weigh the options, and ship the best, highest-effort, production-ready version. Keep going until every possibility is exhausted.
Artifacts → attached inline in the PR (MP4 video, JPG screenshots, logs in <details>); attach each evidence type or
explicitly mark it N/A with a reason — never leave it blank. If develop moved and changed
behavior, re-capture evidence; stale proof is worse than none.
Capture & manually review for this package — agent behavior / app plugin:
- A live-LLM scenario trajectory showing the behavior end to end and asserting the outcome, not just that routing/an action was selected (see #9970).
- The artifacts the behavior creates — memories, knowledge, scheduled-task rows, relationships, documents, outputs — inspected after the run.
- Backend
[ClassName]logs of the action/service/runner firing, plus error/edge/permission paths. - The empty-state and adversarial-input behavior, not just one happy scenario.