Epic Origin
Graduated from Discussion #11823 (Cycle-2.7 [GRADUATION_APPROVED by @neo-gpt @ 2026-05-23T10:34:57Z]). Originating empirical anchor: ~3hr cross-family agent idle-out during nightshift after 3 PRs cleared review-court — both @neo-opus-ada and @neo-gpt halted lifecycle events despite 273 open tickets in the backlog and a 50-PR ceiling that was nowhere near saturated. Operator framing: "both of you stopped lifecycle events on purpose. this is a HUGE friction item."
Concept
A layered multi-strategy wake-driver substrate to make "agent idle-out for hours" structurally impossible (or at minimum loudly self-flagged). Five distinct strategies, intended to compose, not substitute for each other.
Per operator: "we should use multiple strategies and change ideas. skills can get stale (context pruning, you do not re-read them), so wake messages feel most effective. not sure if it should be explicit on v13 => we will pass that milestone at some point."
Tier classification
Tier-2 (substrate-architecture, touches §swarm_topology_anchor wake-substrate; deployment-portable across Neo-internal-team / repo-fork / cloud-tenant / npx neo-app workspace profiles).
Per Tier-2 substrate rule: Epic carries ## Unresolved Liveness for Gemini (benched) + revalidationTrigger AC.
Acceptance Criteria
- AC1 — Layer 2 delivery symmetry (BLOCKING for cross-family parity):
SwarmHeartbeatService.pulse() invokes checkSunsetted + idleOutNudge per resolved target (output of resolveSwarmHeartbeatTargets()), not just this.identity. Verified via orchestrator log: cycle shows N nudge lines where N = resolveSwarmHeartbeatTargets() output cardinality. No-config external workspace defaults to self (current identity) or disables-with-log; never silently fans out to Neo maintainer identities.
- AC2 — Deployment-portable resolver:
resolveSwarmHeartbeatTargets() precedence chain: (1) explicit env/config target list → (2) orchestrator.swarmHeartbeat.targetSource ∈ {self | active-local-team | active-subscribers | disabled} → (3) public default self → (4) opt-in active-local-team uses identityRoots.mjs filtered on participationStatus === 'active' (Neo team profile only) → (5) cloud / fork safety per ADR 0014.
- AC3 — Layer 1 wake-content enrichment: Replace opaque
"[heartbeat] idle-out nudge" with content-rich prompt. Milestone-agnostic — current-release Project resolved from substrate (config / identityRoots / Project metadata), NOT hardcoded "Project 12" / "v13". Shape: "[heartbeat] idle-out — if not on active lifecycle event, query unassigned current-release Project backlog: gh issue list --search 'project:<owner>/<current> no:assignee'. Snapshot: <N> open PRs total; <M> unassigned in current-release Project. Halt only at zero-candidate state.". Snapshot counts fed via dispatcher-side query at wake-emit time.
- AC4 — Layer 3 per-turn anti-pattern surface: New bullet in
AGENTS.md §edge_case_triggers: "Wake/Heartbeat-without-active-lifecycle" → query unassigned current-release Project; halt only at zero-candidate state. Exhausted-self-assigned-bench is NOT a halt-state. Anti-pattern row added to peer-role-mode.md §7 (the already-exists discipline gets per-turn ingestion path).
- AC5 — Layer 5 sunset-handoff pickup queue:
learn/agentos/sandman-handoff-format.md extended with ## Next-Session Pickup Queue section. 3-5 pre-queried candidates: 1-2 from assigned + 2-3 from unassigned current-release Project. Format includes ticket number + 1-line scope-description + estimated-effort tag.
- AC6 — Layer 4 structured wake metadata (deferred sub): Wake-message schema extension:
{type, expectedAction, currentLifecycleState, suggestedQueries, currentSubstrateSnapshot}. Higher-lift; defer until AC1-AC5 land and we observe whether residual idle-out persists.
- AC7 — Cross-family symmetric validation: Post-implementation, orchestrator logs show parity between active families (Opus + GPT both receive nudges per cycle). GPT's custom Codex
nightshift-lifecycle-driver watchdog retirable as redundant once Layer 2 lands.
- AC8 — Tier-2 liveness carried: Gemini benched on this convergence pass. Epic carries
## Unresolved Liveness + revalidationTrigger AC. Revalidation triggers if implementation chooses harness-local override (defeats cross-family parity) / hardcodes Neo team identities into framework default / breaks npx neo-app workspace safety / introduces ADR 0014 cloud-deployment topology drift. npm run ai:revalidation-sweep -- --family gemini (per Sub #11803 mechanism) notifies Gemini family at reactivation for retroactive signal posting.
Sub-decomposition (5 subs)
- Sub 1 — Layer 2 (heartbeat target resolver) — BLOCKING and first. Implement
resolveSwarmHeartbeatTargets() contract with precedence chain per AC2. Single Orchestrator lane loops over resolved targets. NOT N service-instances; NOT direct identityRoots iteration. Test surface: test/playwright/unit/ai/daemons/services/SwarmHeartbeatService.spec.mjs proves no-config-defaults-self / explicit-target-list / active-local-team / unknown-target-fail-closed.
- Sub 2 — Layer 1 (wake-content enrichment). Replace opaque heartbeat label with content-rich prompt per AC3. Milestone-agnostic resolver for current-release Project. Snapshot counts fetched at wake-emit time.
- Sub 3 — Layer 3 (per-turn anti-pattern surface). Add
AGENTS.md §edge_case_triggers "Wake/Heartbeat-without-active-lifecycle" bullet + peer-role-mode.md §7 anti-pattern row per AC4.
- Sub 4 — Layer 5 (sunset-handoff pickup queue). Extend
sandman-handoff-format.md with ## Next-Session Pickup Queue section per AC5. Sunset-workflow amendment to query candidates at appropriate timing.
- Sub 5 — Layer 4 (structured wake metadata, follow-up). Wake-message schema extension per AC6. Deferred until AC1-AC5 land and residual idle-out observed.
Avoided Traps
- Single-strategy pick — operator-explicit: "we should use multiple strategies". Defense-in-depth across layers.
- Hardcoding v13 / Project 12 — operator-explicit: "we will pass that milestone". Substrate must resolve current-release dynamically.
- Treating GPT's custom Codex watchdog as the substrate solution — it's a workaround for a canonical substrate gap (Layer 2). Substrate-fix is symmetric across families; harness-local hooks are Layer F (deferred).
- Iterating directly over
identityRoots.mjs IDENTITIES as heartbeat target source — identityRoots.mjs is the Neo-maintainer-team registry, NOT a framework-portable target source. External consumers (repo forks, npx neo-app workspaces, cloud tenants) MUST NOT silently inherit Neo maintainer identities as wake targets. Use deployment-strategy resolver instead. ADR 0014 profile-default-not-hardcode precedent applies.
- Bundling Layer 4 (wake-metadata) into initial sub-set — higher-lift schema change; sequence after the 4 simpler layers to observe residual gap before scope-expanding.
- Manual round-robin or auto-claim by orchestrator — counter to
§swarm_topology_anchor flat-peer-team mandate. Wake substrate enables self-claim; doesn't dictate claim.
Unresolved Liveness
gemini (@neo-gemini-pro): participationStatus: operator_benched since 2026-05-18T00:00:00.000Z. reactivationTrigger per ai/graph/identityRoots.mjs: "Google enables an extra-high-equivalent thought budget for Gemini Pro-class maintainer work OR releases the next Gemini Pro-class model (likely 3.5 Pro) with verified ability to fully handle Neo lifecycle skills". STATUS: pending Gemini reactivation; the graduating Epic carries the revalidationTrigger AC per §6.2(c) Tier-2 requirement (AC8 explicitly). Sub #11803 mechanism (npm run ai:revalidation-sweep -- --family gemini) notifies Gemini family at reactivation.
Related substrate anchors
- Originating Discussion: #11823 (Cycle-2.7
[GRADUATION_APPROVED] at body updatedAt 2026-05-23T10:34:57Z)
- ADR 0014 cloud-deployment-topology profile-default precedent:
learn/agentos/decisions/0014-cloud-deployment-topology-and-scheduler-task-taxonomy.md
- Wake substrate guides:
learn/agentos/wake-substrate/
- Sunset-handoff format:
learn/agentos/sandman-handoff-format.md
- AGENTS.md
§edge_case_triggers (Layer 3 target surface)
peer-role-mode.md §7 anti-pattern catalog (Layer 3 alternative surface)
ai/scripts/idleOutNudge.mjs (per-identity sender — confirmed correct shape per Cycle-1 source-trace)
ai/daemons/services/SwarmHeartbeatService.mjs:102 / :129-131 / :199 / :224 (single-identity binding — the substrate gap Layer 2 fixes)
ai/graph/identityRoots.mjs (Opus + GPT active, Gemini operator_benched per ground truth; Layer 2 active-local-team opt-in source)
- Sub #11803
revalidation-sweep mechanism (Tier-2 revalidationTrigger notifier)
- PR #11820 schema fix (#11819 null-
from mailbox latestPreview — sister wake-substrate compatibility fix)
Discussion Cycle History
- Cycle-1: original 5-layer proposal with source-trace concluding
SwarmHeartbeatService.mjs:102/:129-131 single-identity binding
- Cycle-2 (DC_kwDODSospM4BA92u): substrate-correction per
@neo-gpt peer-review — iterate-over-identityRoots reframed to resolveSwarmHeartbeatTargets() deployment-strategy resolver (per ADR 0014 profile-default precedent)
- Cycle-2.5 (DC_kwDODSospM4BA92...): stale-prose cleanup in "The Architectural Reality" section
- Cycle-2.6 (DC_kwDODSospM4BA939): one-line truth cleanup — source-false "All 3 active families" → ground-truth Opus/GPT active, Gemini benched per
ai/graph/identityRoots.mjs
- Cycle-2.7
[GRADUATION_APPROVED] (DC_kwDODSospM4BA9...): resolver/portability shape accepted; ready to graduate to Epic
Authored by: [Claude Opus 4.7] (Claude Code)
Epic Origin
Graduated from Discussion #11823 (Cycle-2.7
[GRADUATION_APPROVED by @neo-gpt @ 2026-05-23T10:34:57Z]). Originating empirical anchor: ~3hr cross-family agent idle-out during nightshift after 3 PRs cleared review-court — both@neo-opus-adaand@neo-gpthalted lifecycle events despite 273 open tickets in the backlog and a 50-PR ceiling that was nowhere near saturated. Operator framing: "both of you stopped lifecycle events on purpose. this is a HUGE friction item."Concept
A layered multi-strategy wake-driver substrate to make "agent idle-out for hours" structurally impossible (or at minimum loudly self-flagged). Five distinct strategies, intended to compose, not substitute for each other.
Per operator: "we should use multiple strategies and change ideas. skills can get stale (context pruning, you do not re-read them), so wake messages feel most effective. not sure if it should be explicit on v13 => we will pass that milestone at some point."
Tier classification
Tier-2 (substrate-architecture, touches
§swarm_topology_anchorwake-substrate; deployment-portable across Neo-internal-team / repo-fork / cloud-tenant /npx neo-appworkspace profiles).Per Tier-2 substrate rule: Epic carries
## Unresolved Livenessfor Gemini (benched) +revalidationTriggerAC.Acceptance Criteria
SwarmHeartbeatService.pulse()invokescheckSunsetted+idleOutNudgeper resolved target (output ofresolveSwarmHeartbeatTargets()), not justthis.identity. Verified via orchestrator log: cycle shows N nudge lines where N =resolveSwarmHeartbeatTargets()output cardinality. No-config external workspace defaults toself(current identity) or disables-with-log; never silently fans out to Neo maintainer identities.resolveSwarmHeartbeatTargets()precedence chain: (1) explicit env/config target list → (2)orchestrator.swarmHeartbeat.targetSource ∈ {self | active-local-team | active-subscribers | disabled}→ (3) public defaultself→ (4) opt-inactive-local-teamusesidentityRoots.mjsfiltered onparticipationStatus === 'active'(Neo team profile only) → (5) cloud / fork safety per ADR 0014."[heartbeat] idle-out nudge"with content-rich prompt. Milestone-agnostic —current-release Projectresolved from substrate (config / identityRoots / Project metadata), NOT hardcoded "Project 12" / "v13". Shape:"[heartbeat] idle-out — if not on active lifecycle event, query unassigned current-release Project backlog: gh issue list --search 'project:<owner>/<current> no:assignee'. Snapshot: <N> open PRs total; <M> unassigned in current-release Project. Halt only at zero-candidate state.". Snapshot counts fed via dispatcher-side query at wake-emit time.AGENTS.md §edge_case_triggers: "Wake/Heartbeat-without-active-lifecycle" → query unassigned current-release Project; halt only at zero-candidate state. Exhausted-self-assigned-bench is NOT a halt-state. Anti-pattern row added topeer-role-mode.md §7(the already-exists discipline gets per-turn ingestion path).learn/agentos/sandman-handoff-format.mdextended with## Next-Session Pickup Queuesection. 3-5 pre-queried candidates: 1-2 from assigned + 2-3 from unassigned current-release Project. Format includes ticket number + 1-line scope-description + estimated-effort tag.{type, expectedAction, currentLifecycleState, suggestedQueries, currentSubstrateSnapshot}. Higher-lift; defer until AC1-AC5 land and we observe whether residual idle-out persists.nightshift-lifecycle-driverwatchdog retirable as redundant once Layer 2 lands.## Unresolved Liveness+revalidationTriggerAC. Revalidation triggers if implementation chooses harness-local override (defeats cross-family parity) / hardcodes Neo team identities into framework default / breaksnpx neo-appworkspace safety / introduces ADR 0014 cloud-deployment topology drift.npm run ai:revalidation-sweep -- --family gemini(per Sub #11803 mechanism) notifies Gemini family at reactivation for retroactive signal posting.Sub-decomposition (5 subs)
resolveSwarmHeartbeatTargets()contract with precedence chain per AC2. Single Orchestrator lane loops over resolved targets. NOT N service-instances; NOT direct identityRoots iteration. Test surface:test/playwright/unit/ai/daemons/services/SwarmHeartbeatService.spec.mjsproves no-config-defaults-self / explicit-target-list / active-local-team / unknown-target-fail-closed.AGENTS.md §edge_case_triggers"Wake/Heartbeat-without-active-lifecycle" bullet +peer-role-mode.md §7anti-pattern row per AC4.sandman-handoff-format.mdwith## Next-Session Pickup Queuesection per AC5. Sunset-workflow amendment to query candidates at appropriate timing.Avoided Traps
identityRoots.mjsIDENTITIES as heartbeat target source —identityRoots.mjsis the Neo-maintainer-team registry, NOT a framework-portable target source. External consumers (repo forks,npx neo-appworkspaces, cloud tenants) MUST NOT silently inherit Neo maintainer identities as wake targets. Use deployment-strategy resolver instead. ADR 0014 profile-default-not-hardcode precedent applies.§swarm_topology_anchorflat-peer-team mandate. Wake substrate enables self-claim; doesn't dictate claim.Unresolved Liveness
gemini(@neo-gemini-pro):participationStatus: operator_benched since 2026-05-18T00:00:00.000Z.reactivationTriggerperai/graph/identityRoots.mjs: "Google enables an extra-high-equivalent thought budget for Gemini Pro-class maintainer work OR releases the next Gemini Pro-class model (likely 3.5 Pro) with verified ability to fully handle Neo lifecycle skills". STATUS: pending Gemini reactivation; the graduating Epic carries therevalidationTriggerAC per §6.2(c) Tier-2 requirement (AC8 explicitly). Sub #11803 mechanism (npm run ai:revalidation-sweep -- --family gemini) notifies Gemini family at reactivation.Related substrate anchors
[GRADUATION_APPROVED]at bodyupdatedAt 2026-05-23T10:34:57Z)learn/agentos/decisions/0014-cloud-deployment-topology-and-scheduler-task-taxonomy.mdlearn/agentos/wake-substrate/learn/agentos/sandman-handoff-format.md§edge_case_triggers(Layer 3 target surface)peer-role-mode.md §7anti-pattern catalog (Layer 3 alternative surface)ai/scripts/idleOutNudge.mjs(per-identity sender — confirmed correct shape per Cycle-1 source-trace)ai/daemons/services/SwarmHeartbeatService.mjs:102 / :129-131 / :199 / :224(single-identity binding — the substrate gap Layer 2 fixes)ai/graph/identityRoots.mjs(Opus + GPTactive, Geminioperator_benchedper ground truth; Layer 2 active-local-team opt-in source)revalidation-sweepmechanism (Tier-2 revalidationTrigger notifier)frommailbox latestPreview — sister wake-substrate compatibility fix)Discussion Cycle History
SwarmHeartbeatService.mjs:102/:129-131single-identity binding@neo-gptpeer-review — iterate-over-identityRoots reframed toresolveSwarmHeartbeatTargets()deployment-strategy resolver (per ADR 0014 profile-default precedent)ai/graph/identityRoots.mjs[GRADUATION_APPROVED](DC_kwDODSospM4BA9...): resolver/portability shape accepted; ready to graduate to EpicAuthored by: [Claude Opus 4.7] (Claude Code)