ADR 022 — Orchestrator bootstrap factory and daemon boundaries
Status
Accepted (2026-04-01)
Context
Multiple surfaces (vox-mcp, vox dei / CLI, vox live, Ludus HUD) each constructed an Orchestrator by calling repo_scoped_orchestrator_parts plus Orchestrator::with_groups. That duplicated logic and risked subtle divergence (repository id, memory shard paths, affinity groups).
Separately, vox-orchestrator-d remains the RPC process for Mens-shaped AI flows (ai.generate, ai.review, ai.plan.*) with stable method ids in vox-cli dei_daemon.rs. It is not defined as the host for the full Orchestrator type today.
Mesh distribution uses per-process Orchestrator instances with Turso-backed coordination when mens is enabled; see Mens coordination and Unified orchestration.
Decision
- Bootstrap SSOT: Expose
vox_orchestrator::build_repo_scoped_orchestratorandbuild_repo_scoped_orchestrator_for_repositoryreturningRepoScopedOrchestratorBuild(repository, scopedconfig,orchestrator). All first-party embedders use this factory. vox-orchestrator-dboundary: Keepvox-orchestrator-dfocused on DeI RPC / AI routing and Orchestrator operations. MCP behaves as a thin client for many task/agent lifecycle slices.- Trust-conditioned gates: Optional
trust_gate_relax_*config relaxes Socrates enforce, completion grounding enforce, and strict scope when Codexagent_reliabilityexceeds a configurable floor, reusing the same Laplace scores as reputation routing. - Merged Authority: The legacy
vox-dei-dhas been merged intovox-orchestrator-dto unify the AI plane and Coordination plane. - Authority model (Phase B/IPC transition): adopt a split-plane transition model until broad RPC parity exists: daemon-aligned RPC can own task + agent lifecycle slices under explicit MCP env flags, while MCP remains authoritative for VCS/context/event/session surfaces still backed by embedded stores. Promote to full thin MCP only after those stores gain explicit daemon contracts.
Consequences
- New orchestrator embedders should call the bootstrap module only; avoid re-copying
repo_scoped_orchestrator_parts+with_groupsat new call sites. - Parity tests can assert repeated builds yield identical
repository_idand memory paths. - A future daemon would reuse
RepoScopedOrchestratorBuildinternally; MCP would switch to IPC/HTTP without changing routing semantics.
Phase B (optional) — single-process orchestrator owner
When product requirements justify fixing cold-start and gravity (one RAM image shared by many MCP attach/detach cycles), implement a long-lived process that:
- Done: Binary
vox-orchestrator-d(crates/vox-orchestrator[[bin]]) callsbuild_repo_scoped_orchestrator, optionalOrchestrator::init_dbviavox_db::connect_canonical_optional, listens onVOX_ORCHESTRATOR_DAEMON_SOCKET, and spawns the same long-lived sidecars as MCP when config/DB apply:mesh_federation_poll::spawn_populi_federation_poller,a2a::spawn_populi_remote_result_poller/a2a::spawn_populi_remote_worker_poller,orchestrator_event_log::spawn_orchestrator_event_log_sink, and (when Codex is attached)clarification_db_inbox_poll::spawn_clarification_db_inbox_poller.vox-mcpdelegates those entry points to the samevox-orchestratormodules (it still ownsServerStateand the full MCP tool surface). - Done: TCP or stdio newline
DispatchRequest/DispatchPayload::Resultplane; method ids invox_protocol::orch_daemon_method(orch.ping,orch.status,orch.task_status,orch.spawn_agent,orch.agent_ids). - Partial:
vox-mcpcallsServerState::probe_external_orchestrator_daemon_if_configuredwhenVOX_ORCHESTRATOR_DAEMON_SOCKETpoints at a TCP peer (stdio skipped);orch.pingrepository_idis compared to the embed’s repo (WARN / optional ERROR viaVOX_MCP_ORCHESTRATOR_DAEMON_REPOSITORY_ID_STRICT). Optional per-toolVOX_MCP_ORCHESTRATOR_{TASK_STATUS,START,STATUS_TOOL}_RPCflags (or umbrellaVOX_MCP_ORCHESTRATOR_RPC_READS) forward aligned read RPC:task_status→orch.task_status;vox_orchestrator_start→orch.status+orch.agent_ids;vox_orchestrator_status→ attach daemonorch.statusJSON in the status payload. Optional write pilots (VOX_MCP_ORCHESTRATOR_RPC_WRITES, with per-slice overrides for task/agent writes) route submit/complete/fail/cancel/reorder/drain/rebalance/spawn/retire/pause/resume to daemon methods when aligned. The in-processOrchestratorremains default for VCS/context/event/session surfaces pending explicit contracts.
Links
crates/vox-orchestrator/src/bootstrap.rscrates/vox-orchestrator/src/orch_daemon/mod.rs— TCP RPC +OrchDaemonClientcrates/vox-orchestrator/src/mesh_federation_poll.rs— shared Populi federation poll loop (MCP + daemon)crates/vox-orchestrator/src/mcp_tools/dei_tools/orchestrator_snapshot.rs—VOX_ORCHESTRATOR_EVENT_LOGJSONL sinkcrates/vox-orchestrator/src/clarification_db_inbox_poll.rs— Codex clarification inbox draincrates/vox-orchestrator/src/bin/vox_orchestrator_d.rs—vox-orchestrator-dbinarycrates/vox-cli/src/dei_daemon.rs- Orphan surface inventory —
vox-orchestratorstaging crate vsvox-orchestratorSSOT