Parent
#32
What to build
The daemon gets an Effect composition root, and the agent runtime is the first service to move into
it. server/daemon.ts builds a Layer; the agent runtime is resolved from context instead of being
threaded by hand through eight files and roughly twenty call sites (cli.ts → daemon.ts →
ServerOptions → StartTrackedRunOptions → DispatchEnv → startRun → buildAgentStepEffect).
Two concrete outcomes beyond deleting plumbing:
- The adapter becomes selectable from
factory.config.ts. Today "pluggable adapter" is a claim
the code does not support: there is one production implementation, chosen by a hardcoded
opencodeAdapter default in two separate places, with no config surface at all.
DispatchEnv loses a field. That bag exists to carry environment down a recursive dispatch
chain; every field removed from it is one less thing a child run has to inherit explicitly.
The agent runtime goes first because its plumbing is the worst in the codebase — it proves the
pattern on the strongest case before #37 applies it to the remaining singletons.
Scope boundary, and it matters: server/http.ts's route handlers and sseStream stay plain
functions over Request/Response/ReadableStream. They read already-constructed services; they
do not become Effects. D22 is reaffirmed, not reopened.
ADRs to update as part of this ticket — both already carry the decision, so this is confirming the
text matches what shipped, and amending it if implementation forced a different shape:
docs/adr/0009-imperative-workflows-effect-boundary.md §5 and the 2026-09-18 status note in
docs/adr/0004-server-dispatch.md. The seam itself is docs/adr/0012-agent-runtime-seam.md §4.
Acceptance criteria
Blocked by
Parent
#32
What to build
The daemon gets an Effect composition root, and the agent runtime is the first service to move into
it.
server/daemon.tsbuilds aLayer; the agent runtime is resolved from context instead of beingthreaded by hand through eight files and roughly twenty call sites (
cli.ts→daemon.ts→ServerOptions→StartTrackedRunOptions→DispatchEnv→startRun→buildAgentStepEffect).Two concrete outcomes beyond deleting plumbing:
factory.config.ts. Today "pluggable adapter" is a claimthe code does not support: there is one production implementation, chosen by a hardcoded
opencodeAdapterdefault in two separate places, with no config surface at all.DispatchEnvloses a field. That bag exists to carry environment down a recursive dispatchchain; every field removed from it is one less thing a child run has to inherit explicitly.
The agent runtime goes first because its plumbing is the worst in the codebase — it proves the
pattern on the strongest case before #37 applies it to the remaining singletons.
Scope boundary, and it matters:
server/http.ts's route handlers andsseStreamstay plainfunctions over
Request/Response/ReadableStream. They read already-constructed services; theydo not become Effects. D22 is reaffirmed, not reopened.
ADRs to update as part of this ticket — both already carry the decision, so this is confirming the
text matches what shipped, and amending it if implementation forced a different shape:
docs/adr/0009-imperative-workflows-effect-boundary.md§5 and the 2026-09-18 status note indocs/adr/0004-server-dispatch.md. The seam itself isdocs/adr/0012-agent-runtime-seam.md§4.Acceptance criteria
Context.Serviceresolved from context, not a value passed through interfacesadapteris gone as a pass-through field fromStartTrackedRunOptions,DispatchEnv,ServerOptionsand the run/step optionsfactory.config.ts, with opencode as the default when unsetserver/http.ts's route handlers and SSE stream are still plain functions, not Effectsbun run checkpassesBlocked by