Context
This follow-up exists because PR #11008 merged the #11006 Orchestrator MVP in a shape that conflicts with the v13 architecture path the PR itself referenced.
PR #11008 added ai/scripts/orchestrator-daemon.mjs as a 455-line runtime owner for task definitions, singleton enforcement, state files, child-process adoption, scheduling intervals, sunset-handover polling, and summary / KB-sync task dispatch. That got the immediate MVP behavior out of bridge-daemon.mjs, but it also moved the real Orchestrator logic into ai/scripts/.
learn/agentos/v13-path.md defines a stricter M3 structure:
ai/scripts/orchestrator-daemon.mjs # Thin Node-process boot wrapper (PID file, lifecycle, error-isolation)
ai/daemons/Orchestrator.mjs # Neo class: schedules + runs tasks; per-task try/catch
ai/daemons/services/
├── SummarizationCoordinatorService.mjs # NEW: Piece C
├── DreamService.mjs (existing) # consumed by Orchestrator
├── SwarmHeartbeatService.mjs (existing) # consumed by Orchestrator
└── ... (existing decomposed services from #10013)
Operator feedback after the merge: the new script item conflicts with that path and turns the MVP into new technical debt. This ticket captures the repair instead of letting future Agent OS maintenance tasks accrete inside the script wrapper.
The Problem
The MVP preserved bridge-daemon focus, but the Orchestrator boundary is now inverted:
ai/scripts/orchestrator-daemon.mjs owns scheduling and task orchestration instead of only booting a Neo daemon class.
ai/daemons/Orchestrator.mjs does not exist yet, so M3's class boundary is not represented in code.
SummarizationCoordinatorService.mjs does not exist yet, so Piece C remains child-process dispatch around summarize-sessions.mjs rather than a daemon service boundary.
- Failure isolation is local to child-process callbacks and a broad
runMaintenanceCycle() try/catch, not the v13 path's per-task try/catch with a task-health envelope. HealthService.recordTaskOutcome(...) does not exist yet; the nearest precedent is HealthService.recordStartupSummarization(status, details=null) in ai/services/memory-core/HealthService.mjs.
- The longer the script wrapper owns this logic, the more likely DreamService, SwarmHeartbeatService, graph maintenance, and concept ingestion get appended to
ai/scripts/ instead of being scheduled by a real daemon class.
This is not a request to roll back #11008. It is the corrective M3 completion ticket: keep the useful MVP behavior, move its load-bearing logic to the proper substrate.
The Architectural Reality
learn/agentos/v13-path.md lines 93-104 define ai/scripts/orchestrator-daemon.mjs as the thin boot wrapper and ai/daemons/Orchestrator.mjs as the scheduler / task runner.
learn/agentos/v13-path.md lines 147-152 name M3 as Orchestrator.mjs plus the boot wrapper, with #11006 only as the MVP split.
- PR #11008 merged
ai/scripts/orchestrator-daemon.mjs with 455 lines of orchestration logic and added npm run ai:orchestrator as the external operator entrypoint.
- #11006 and #10813 are closed. They explain the MVP lineage, but neither should be reopened for this structural repair.
- #10449 tracks the prevention layer (
structural-pre-flight). This ticket is the repair layer for the concrete #11008 debt.
- Discussion #10447 is the earlier archaeological source for the same class of issue: daemon-shaped runtime logic accumulating under
ai/scripts/ because directory-choice discipline fired too late.
The Fix
Reshape #11008's MVP into the v13 M3 architecture without changing the operator-facing command:
- Add
ai/daemons/Orchestrator.mjs as a Neo class that owns task registration, cadence calculation, per-task execution, state updates, and task-failure isolation.
- Add
ai/daemons/services/SummarizationCoordinatorService.mjs for the Piece C summary trigger path, so summarization logic is no longer just a child-process branch inside the script wrapper.
- Reduce
ai/scripts/orchestrator-daemon.mjs to a thin Node-process boot wrapper: process-level lifecycle, PID file, error isolation, environment setup, and class instantiation.
- Preserve
npm run ai:orchestrator and the #11008 env contracts: NEO_ORCHESTRATOR_POLL_INTERVAL_MS, NEO_ORCHESTRATOR_SUMMARY_SWEEP_INTERVAL_MS, NEO_ORCHESTRATOR_KB_SYNC_INTERVAL_MS, and the compatibility alias NEO_SUMMARIZATION_SWEEP_INTERVAL_MS.
- Introduce the smallest daemon-task health surface needed for per-task outcomes. A
HealthService.recordTaskOutcome(taskName, status, details=null)-style method is in scope and should mirror the existing recordStartupSummarization(status, details=null) envelope rather than inventing a separate reporting shape.
- Rewrite the #11006 MVP note in
learn/agentos/v13-path.md from "future full class remains" to the new landed state once this ticket merges.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
npm run ai:orchestrator / ai:scripts operator entrypoint |
#11006, PR #11008, package.json |
Still starts the Orchestrator daemon; external command and env contracts remain compatible |
Manual npm run ai:summarize-sessions and npm run ai:sync-kb remain operator escape hatches |
learn/agentos/v13-path.md, operator notes if present |
Node syntax checks + wrapper unit tests |
ai/scripts/orchestrator-daemon.mjs |
learn/agentos/v13-path.md D3 structure |
Thin boot wrapper only: PID, lifecycle, process error isolation, class startup |
If daemon class fails to instantiate, log and exit non-zero without touching bridge-daemon behavior |
v13-path.md M3 section |
Static grep verifies no task scheduling logic remains in script |
ai/daemons/Orchestrator.mjs |
learn/agentos/v13-path.md D3 / M3 |
Neo class owns task scheduling, per-task try/catch, state, and health outcomes |
Individual task failure records an error and leaves other tasks eligible to run |
JSDoc / @summary on class and methods |
Unit tests for summary failure not blocking KB sync or later tasks |
| Orchestrator task health envelope |
HealthService.recordStartupSummarization(status, details=null) precedent |
Add recordTaskOutcome(taskName, status, details=null) or the smallest equivalent daemon-health method with the same status + details envelope |
If health substrate cannot be extended cleanly in this PR, document the blocker and keep per-task state file evidence |
JSDoc / @summary on new health method |
Unit tests assert success/failure outcomes are recorded per task |
SummarizationCoordinatorService.mjs |
#10813 Piece C, v13-path.md D3 structure |
Owns summary sweep / sunset-handover trigger coordination consumed by Orchestrator |
Manual summarization script stays available |
JSDoc / @summary |
Unit tests for sunset handover and interval sweep trigger shape |
Acceptance Criteria
Out of Scope
- Moving wake delivery into the Orchestrator.
bridge-daemon.mjs remains specialized for wake-event delivery.
- Completing M4 DreamService / Sandman / Golden Path scheduling. This ticket can add extension points, but it should not pull the full M4 migration into the repair PR.
- M2 common base MCP server work.
- M5
NEO_MC_PRIMARY retirement.
- Broad directory reshaping such as moving
bridge-daemon.mjs out of ai/scripts/; that remains tied to the structural-pre-flight / daemon-isolation lineage.
Avoided Traps
- Do not treat #11006 closure as M3 completion. It was an MVP split that moved work out of
bridge-daemon.mjs; it did not land the class structure promised by v13-path.
- Do not append more tasks to the script wrapper. That compounds the debt this ticket exists to remove.
- Do not reopen #10813 or #11006 for this. Both are closed lineage tickets; this repair needs its own review surface.
- Do not over-expand into all future daemon services. The repair should create the Orchestrator class boundary and migrate the existing #11008 summary / KB sync behavior first.
- Do not file a narrower companion MX ticket for this same prevention layer. #10449 already owns the broad
structural-pre-flight skill work; PR #11008 / #11009 should feed that epic as a second empirical anchor instead of splitting the graph into an ai/scripts/-only review rule.
Related
- Parent v13 epic: #9999
- Closed MVP ticket: #11006
- Merged MVP PR: #11008
- Closed summarization lineage: #10813
- Archaeological source: Discussion #10447
- Architectural source of authority:
learn/agentos/v13-path.md
- Prevention layer: #10449 — existing
structural-pre-flight epic graduated from Discussion #10447. PR #11008 / #11009 is a second empirical anchor for that broader skill, after the original bridge-daemon.mjs placement issue.
Origin Session ID: 20a824b0-29d1-4082-ae12-87705ec69c3f
Retrieval Hint: query_raw_memories(query="PR #11008 orchestrator-daemon script wrapper v13-path ai/daemons Orchestrator SummarizationCoordinatorService technical debt follow-up")
Context
This follow-up exists because PR #11008 merged the #11006 Orchestrator MVP in a shape that conflicts with the v13 architecture path the PR itself referenced.
PR #11008 added
ai/scripts/orchestrator-daemon.mjsas a 455-line runtime owner for task definitions, singleton enforcement, state files, child-process adoption, scheduling intervals, sunset-handover polling, and summary / KB-sync task dispatch. That got the immediate MVP behavior out ofbridge-daemon.mjs, but it also moved the real Orchestrator logic intoai/scripts/.learn/agentos/v13-path.mddefines a stricter M3 structure:Operator feedback after the merge: the new script item conflicts with that path and turns the MVP into new technical debt. This ticket captures the repair instead of letting future Agent OS maintenance tasks accrete inside the script wrapper.
The Problem
The MVP preserved bridge-daemon focus, but the Orchestrator boundary is now inverted:
ai/scripts/orchestrator-daemon.mjsowns scheduling and task orchestration instead of only booting a Neo daemon class.ai/daemons/Orchestrator.mjsdoes not exist yet, so M3's class boundary is not represented in code.SummarizationCoordinatorService.mjsdoes not exist yet, so Piece C remains child-process dispatch aroundsummarize-sessions.mjsrather than a daemon service boundary.runMaintenanceCycle()try/catch, not the v13 path's per-tasktry/catchwith a task-health envelope.HealthService.recordTaskOutcome(...)does not exist yet; the nearest precedent isHealthService.recordStartupSummarization(status, details=null)inai/services/memory-core/HealthService.mjs.ai/scripts/instead of being scheduled by a real daemon class.This is not a request to roll back #11008. It is the corrective M3 completion ticket: keep the useful MVP behavior, move its load-bearing logic to the proper substrate.
The Architectural Reality
learn/agentos/v13-path.mdlines 93-104 defineai/scripts/orchestrator-daemon.mjsas the thin boot wrapper andai/daemons/Orchestrator.mjsas the scheduler / task runner.learn/agentos/v13-path.mdlines 147-152 name M3 asOrchestrator.mjsplus the boot wrapper, with #11006 only as the MVP split.ai/scripts/orchestrator-daemon.mjswith 455 lines of orchestration logic and addednpm run ai:orchestratoras the external operator entrypoint.structural-pre-flight). This ticket is the repair layer for the concrete #11008 debt.ai/scripts/because directory-choice discipline fired too late.The Fix
Reshape #11008's MVP into the v13 M3 architecture without changing the operator-facing command:
ai/daemons/Orchestrator.mjsas a Neo class that owns task registration, cadence calculation, per-task execution, state updates, and task-failure isolation.ai/daemons/services/SummarizationCoordinatorService.mjsfor the Piece C summary trigger path, so summarization logic is no longer just a child-process branch inside the script wrapper.ai/scripts/orchestrator-daemon.mjsto a thin Node-process boot wrapper: process-level lifecycle, PID file, error isolation, environment setup, and class instantiation.npm run ai:orchestratorand the #11008 env contracts:NEO_ORCHESTRATOR_POLL_INTERVAL_MS,NEO_ORCHESTRATOR_SUMMARY_SWEEP_INTERVAL_MS,NEO_ORCHESTRATOR_KB_SYNC_INTERVAL_MS, and the compatibility aliasNEO_SUMMARIZATION_SWEEP_INTERVAL_MS.HealthService.recordTaskOutcome(taskName, status, details=null)-style method is in scope and should mirror the existingrecordStartupSummarization(status, details=null)envelope rather than inventing a separate reporting shape.learn/agentos/v13-path.mdfrom "future full class remains" to the new landed state once this ticket merges.Contract Ledger Matrix
npm run ai:orchestrator/ai:scriptsoperator entrypointpackage.jsonnpm run ai:summarize-sessionsandnpm run ai:sync-kbremain operator escape hatcheslearn/agentos/v13-path.md, operator notes if presentai/scripts/orchestrator-daemon.mjslearn/agentos/v13-path.mdD3 structurev13-path.mdM3 sectionai/daemons/Orchestrator.mjslearn/agentos/v13-path.mdD3 / M3@summaryon class and methodsHealthService.recordStartupSummarization(status, details=null)precedentrecordTaskOutcome(taskName, status, details=null)or the smallest equivalent daemon-health method with the same status + details envelope@summaryon new health methodSummarizationCoordinatorService.mjsv13-path.mdD3 structure@summaryAcceptance Criteria
ai/daemons/Orchestrator.mjsexists as a Neo class with JSDoc /@summarycoverage for the class and its load-bearing methods.ai/daemons/services/SummarizationCoordinatorService.mjsexists and owns the summary-trigger coordination currently embedded in the script wrapper.ai/scripts/orchestrator-daemon.mjsis reduced to a thin boot wrapper and no longer owns task definitions, cadence decisions, or task dispatch logic.npm run ai:orchestratorstill works and preserves all #11008 env var contracts and aliases.HealthService.recordTaskOutcome(taskName, status, details=null)is in scope and should mirror the existingrecordStartupSummarization(status, details=null)envelope inai/services/memory-core/HealthService.mjs.learn/agentos/v13-path.mdis updated so the M3 section no longer describes #11008's script-heavy MVP as the standing target once the class split lands.ai/scripts/as part of this repair; verify withrg "setInterval|scheduleTask|runMaintenanceCycle|buildTaskDefinitions" ai/scripts/orchestrator-daemon.mjsreturning no matches after the wrapper split.Out of Scope
bridge-daemon.mjsremains specialized for wake-event delivery.NEO_MC_PRIMARYretirement.bridge-daemon.mjsout ofai/scripts/; that remains tied to the structural-pre-flight / daemon-isolation lineage.Avoided Traps
bridge-daemon.mjs; it did not land the class structure promised by v13-path.structural-pre-flightskill work; PR #11008 / #11009 should feed that epic as a second empirical anchor instead of splitting the graph into anai/scripts/-only review rule.Related
learn/agentos/v13-path.mdstructural-pre-flightepic graduated from Discussion #10447. PR #11008 / #11009 is a second empirical anchor for that broader skill, after the originalbridge-daemon.mjsplacement issue.Origin Session ID: 20a824b0-29d1-4082-ae12-87705ec69c3f
Retrieval Hint:
query_raw_memories(query="PR #11008 orchestrator-daemon script wrapper v13-path ai/daemons Orchestrator SummarizationCoordinatorService technical debt follow-up")