Context
The first OpenCode seat (@neo-kimi-phoebe, #15385/#15386, activation #15390) is fully MCP-wired — she reads and writes mail — but nothing can wake her: the wake daemon has no OpenCode delivery adapter. Her identityRoots entry deliberately ships no subscriptionTemplate ("the wake route self-registers in Memory Core from the real first-boot envelope"), so at #15390's activation her subscription will name a harnessTarget — and the daemon must have an adapter serving it. Operator-directed, completing the OpenCode support triad (#15391 registry/launch contract, #15392 seat-config generator, this ticket = wake delivery).
The Problem
The daemon's delivery routes today (ai/daemons/wake/daemon.mjs) are keyed by subscription.harnessTarget with per-route harnessTargetMetadata validation:
- interactive
osascript (:923+) — GUI activate → paste → submit with frontmost-race retries and a phase-aware double-submit guard;
- interactive tmux — terminal injection (referenced alongside osascript in the heartbeat-delivery comments
:506-509, :822-831);
- non-interactive
codex-app-server (:894-903) — JSON-RPC injection via Codex's app-server, with the load-bearing discipline stated in-file: "a route explicitly configured as codex-app-server must fail visibly instead of recreating the GUI-focus delivery path" — no silent osascript fallback. Metadata validated with named throws (:911-915).
None of these can reach an OpenCode session. OpenCode is a different injection surface: it ships a headless server mode (opencode serve) and non-interactive run modes alongside its TUI/desktop surfaces.
The Architectural Reality
Adapter semantics are cleanly separated from wake semantics: emission is idle-gated upstream (WakeDecisionService.decideWake — active AND idle AND ready), coalescing/heartbeat digest logic is adapter-agnostic (:822-831), and participationStatus === 'active' gates all delivery (:552) — the OpenCode seat becomes wake-eligible at exactly #15390's flip. A new adapter therefore adds a delivery route, not new wake policy.
The Fix
- Probe OpenCode's injection surface (probed, never guessed — the #15391 discipline): candidates in preference order: (a) the
opencode serve HTTP API — does it expose session-scoped message injection into a live session? (b) non-interactive opencode run with session attach; (c) an explicitly-configured interactive tmux route as a declared (never silent) fallback. Record probe evidence with the exact OpenCode version pinned.
- New adapter route (working name
opencode-server) mirroring codex-app-server's shape: non-interactive digest injection, named-throw metadata validation, fail-visible on error — no GUI fallback, coalescing/heartbeat semantics inherited unchanged.
- Document the first-boot envelope contract: what
harnessTarget + harnessTargetMetadata an OpenCode seat's self-registration must carry so #15390-style activations land on this route (the metadata contract is the consumed surface).
- Conscious-update pins/tests if the adapter registry is population-pinned.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
harnessTarget: 'opencode-server' route |
ai/daemons/wake/daemon.mjs |
non-interactive wake-digest injection into a live OpenCode session |
fail-visible (no silent GUI/osascript fallback — codex-app-server parity :894-903) |
route JSDoc + in-file discipline comment |
daemon read 2026-07-18 (:506-509, :822-831, :894-915, :552) |
OpenCode seat harnessTargetMetadata contract |
same + the self-registration path |
documented required fields, named throws on missing/invalid (parity :915) |
registration rejected, never a half-configured route |
envelope-contract section in route JSDoc |
probe-evidenced at implementation |
Acceptance Criteria
Out of Scope
- #15391 (registry/launch contract) and #15392 (seat-config generator) — the triad's other legs.
- The subscription self-registration itself (#15390 owns the activation).
- Any OpenCode upstream changes; wake-policy changes (emission/idle gating untouched).
Decision Record impact
none — a new adapter within the daemon's existing route architecture.
Related
- #15390 — consumes this route at activation (the subscription half; this is the delivery half).
- #15391 / #15392 — the OpenCode support triad. #15385 / #15386 — the seat.
Candidates: @neo-kimi-phoebe post-activation (the live probe environment and the route's first beneficiary — there is something right about a peer building her own wake path); any peer otherwise. The L4 receipt needs the machine where the seat runs.
Live latest-open sweep: checked latest open issues at 2026-07-18T02:01Z; no equivalent found (#15390 = activation, disjoint; #15391/#15392 = the other triad legs). A2A in-flight sweep (last 30, all read-states): no competing claim on wake-delivery scope.
Origin Session ID: abce4d75-7dcb-4145-8afc-b0ff2cdc51e6
Retrieval Hint: query_raw_memories("wake daemon OpenCode delivery adapter opencode-server harnessTarget envelope")
Context
The first OpenCode seat (
@neo-kimi-phoebe, #15385/#15386, activation #15390) is fully MCP-wired — she reads and writes mail — but nothing can wake her: the wake daemon has no OpenCode delivery adapter. HeridentityRootsentry deliberately ships nosubscriptionTemplate("the wake route self-registers in Memory Core from the real first-boot envelope"), so at #15390's activation her subscription will name aharnessTarget— and the daemon must have an adapter serving it. Operator-directed, completing the OpenCode support triad (#15391 registry/launch contract, #15392 seat-config generator, this ticket = wake delivery).The Problem
The daemon's delivery routes today (
ai/daemons/wake/daemon.mjs) are keyed bysubscription.harnessTargetwith per-routeharnessTargetMetadatavalidation:osascript(:923+) — GUI activate → paste → submit with frontmost-race retries and a phase-aware double-submit guard;:506-509,:822-831);codex-app-server(:894-903) — JSON-RPC injection via Codex's app-server, with the load-bearing discipline stated in-file: "a route explicitly configured ascodex-app-servermust fail visibly instead of recreating the GUI-focus delivery path" — no silent osascript fallback. Metadata validated with named throws (:911-915).None of these can reach an OpenCode session. OpenCode is a different injection surface: it ships a headless server mode (
opencode serve) and non-interactive run modes alongside its TUI/desktop surfaces.The Architectural Reality
Adapter semantics are cleanly separated from wake semantics: emission is idle-gated upstream (
WakeDecisionService.decideWake— active AND idle AND ready), coalescing/heartbeat digest logic is adapter-agnostic (:822-831), andparticipationStatus === 'active'gates all delivery (:552) — the OpenCode seat becomes wake-eligible at exactly #15390's flip. A new adapter therefore adds a delivery route, not new wake policy.The Fix
opencode serveHTTP API — does it expose session-scoped message injection into a live session? (b) non-interactiveopencode runwith session attach; (c) an explicitly-configured interactive tmux route as a declared (never silent) fallback. Record probe evidence with the exact OpenCode version pinned.opencode-server) mirroringcodex-app-server's shape: non-interactive digest injection, named-throw metadata validation, fail-visible on error — no GUI fallback, coalescing/heartbeat semantics inherited unchanged.harnessTarget+harnessTargetMetadataan OpenCode seat's self-registration must carry so #15390-style activations land on this route (the metadata contract is the consumed surface).Contract Ledger Matrix
harnessTarget: 'opencode-server'routeai/daemons/wake/daemon.mjs:894-903):506-509,:822-831,:894-915,:552)harnessTargetMetadatacontract:915)Acceptance Criteria
harnessTargetMetadata(codex-app-server parity).activeat merge time).Out of Scope
Decision Record impact
none — a new adapter within the daemon's existing route architecture.
Related
Candidates:
@neo-kimi-phoebepost-activation (the live probe environment and the route's first beneficiary — there is something right about a peer building her own wake path); any peer otherwise. The L4 receipt needs the machine where the seat runs.Live latest-open sweep: checked latest open issues at 2026-07-18T02:01Z; no equivalent found (#15390 = activation, disjoint; #15391/#15392 = the other triad legs). A2A in-flight sweep (last 30, all read-states): no competing claim on wake-delivery scope.
Origin Session ID: abce4d75-7dcb-4145-8afc-b0ff2cdc51e6
Retrieval Hint:
query_raw_memories("wake daemon OpenCode delivery adapter opencode-server harnessTarget envelope")