LearnNewsExamplesServices
Frontmatter
id13860
titleOrchestrator container-health self-healing daemon
stateClosed
labels
epicaiarchitecturemodel-experience
assignees[]
createdAtJun 22, 2026, 1:49 PM
updatedAt3:21 PM
githubUrlhttps://github.com/neomjs/neo/issues/13860
authorneo-opus-grace
commentsCount7
parentIssuenull
subIssues
13861 Container-health daemon design/ADR: actuator + heal-safety + detect
13914 Cloud-deployment observability MCP tool (logs, health, recovery-runs)
subIssuesCompleted2
subIssuesTotal2
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[x] 13881 [recovery-daemon] Typed diagnosis→recovery contract + recovery-run ledger (C4)
closedAtJun 24, 2026, 6:19 PM

Orchestrator container-health self-healing daemon

Closed v13.1.0/archive-v13-1-0-chunk-5 epicaiarchitecturemodel-experience
neo-opus-grace
neo-opus-grace commented on Jun 22, 2026, 1:49 PM

Problem scope

A deployed Agent OS runs as a multi-container stack (Memory Core, Knowledge Base, the local model server, vector store, orchestrator). The OS has no deployment-wide health → heal → escalate loop:

  • The orchestrator's existing watchdogs (remConsolidationLivenessWatchdog, embedDrainLivenessWatchdog, the lease watchdogs) are per-task liveness — they watch the orchestrator's own work, not sibling-container health.
  • ProcessSupervisorService supervises in-process spawned children (PID-level), not sibling containers.
  • The container runtime's restart: unless-stopped only fires on exit — an unhealthy-but-running container (a degraded service whose probe trips while it is still functionally serving) is never auto-restarted.

So a deployment can degrade — resource contention, a probe-failing-but-functional container, or config-drift where an intended env override silently isn't applied — and nothing detects it, heals it, or even alerts. It stays degraded until a human notices and intervenes by hand. For a self-evolving Agent OS, that is a missing immune function.

Intended solution

A new orchestrator child service — ContainerHealthService, sibling to ProcessSupervisorService under ai/daemons/orchestrator/services/ — extending supervision from in-process children to sibling containers, running a bounded health loop:

Detect — periodically collect real per-container signals (memory %, CPU load, container-health state, and env-var/config correctness) across the deployment's services. Decide on resource/contention reality, not a single health probe: a service's probe can legitimately false-fail (e.g. a model-dependent canary while the model is saturated) while the service is functionally serving — so a probe trip alone must not trigger a restart of a working container.

Act (tiered, bounded) — restart (transient fault) → throttle / shed load (contention) → escalate-with-diagnosis (config-drift needing a redeploy: page, don't loop). Rate-limited, N-attempt-capped, lifecycle-only actions (config/restart, never arbitrary code — the two-worlds safety boundary), reversible.

The actuator (greenfield — no container-control precedent in ai/). For the orchestrator (itself a container) to restart a sibling, it needs a container-runtime handle. That privilege is powerful, so safety must live in a constrained action set (restart + a few known config tweaks, nothing else), not unrestricted runtime access. This is the design-first decision.

Placement — inside the orchestrator container (accepted single-point-of-failure: if the orchestrator dies, no heal — a pragmatic floor, not a flaw).

Decomposition (design-first; subs linked natively, added incrementally)

The actuator + heal-safety bounds + the false-positive-safe detect model are a design/ADR sub that gates the implementation subs (cross-family review mandatory). Implementation then decomposes into detect (the container-health model), act (the bounded actuator), and deploy (actuator wiring) — filed and linked as the design lands, so this body never hardcodes a stale sub-list.

Avoided traps

  • Restart-on-probe-fail — restarting a functionally-working container because a health probe tripped = self-inflicted outage. Decide on resource reality + multiple signals, not a single probe.
  • Over-privileged actuator — a runtime handle grants total container control; safety is the constrained action set, not the access.
  • Resilience mistaken for a config/model problem — a deployment can be correctly configured and still degrade under contention; this is a heal gap, not a config/model swap.
  • Healer thrash — an unbounded heal loop can make an incident worse than the fault; rate-limit + N-cap + escalate-on-repeat.

Decision Record impact

Required — new subsystem + a privileged actuator; the ADR is produced by the design/ADR sub.

Precedents (codebase)

ProcessSupervisorService (in-process supervision — the structural analog), remConsolidationLivenessWatchdog / embedDrainLivenessWatchdog (the liveness-watchdog pattern — task-liveness, generalized here to container-health), HealthService (the health-probe / detect-signal source).

Related

#13839 (alarm dispatcher for a watchdog — the escalation pattern), #13435 (in-container healthcheck decoupling — a detect-signal surface), #13624 / #13755 (orchestrator watchdog epics — per-task; this is container-health).

Origin Session ID

2439c28b-245e-425a-85a7-ca7ee4aa0336

tobiu
tobiu Jun 24, 2026, 6:19 PM

detached the live-probe ticket from this epic. closing it, since the implementation is done.

  • 2026-06-25T23:05:24Z @neo-opus-vega cross-referenced by #14024
  • 2026-06-25T23:09:35Z @neo-gpt cross-referenced by #14025
  • 2026-06-25T23:10:55Z @neo-opus-vega cross-referenced by #14026
  • 2026-06-27T03:13:15Z @neo-opus-grace cross-referenced by PR #14194