Short roadmap for Effect cleanup in packages/opencode.
Current patterns and examples live in guide.md. Error
boundary migration details live in
error-boundaries-plan.md. Test migration rules live in
test/EFFECT_TEST_MIGRATION.md.
Older deep-dive notes in this directory may still be useful, but treat
this roadmap and the guide as the current entry points.
This is a planning map, not a verified inventory. Before starting a task,
re-run a targeted git grep from current dev and update this file if
the inventory changed.
P0 ERR + RENDER + HTTP
Make expected failures typed, render them well, and stop relying on
generic HTTP error guesswork.
P1 TEST
Convert touched tests to the ideal Effect test patterns from the guide.
P2 RF
Move mutable runtime flags into typed runtime/config services.
P3 GLOBAL
Make global paths explicit and remove import-time side effects.
P4 INST + BRIDGE
Remove ambient Instance coupling while keeping Promise/callback interop.
P5 PROC + FS
Replace raw process/filesystem edges with typed Effect services.
P6 OA
Shrink OpenAPI compatibility shims as source schemas improve.
ERR Typed errors — replace legacy NamedError.create(...) and
Effect.die(...) for expected service failures with
Schema.TaggedErrorClass errors on the Effect error channel.
Shrinks: NamedError usage.RENDER User-visible error rendering — preserve structured typed-error
details at CLI, HTTP, and tool boundaries.
Shrinks: opaque Error: Name rendering.HTTP HTTP route cleanup — make route errors explicit instead of
relying on generic middleware to guess status/body from error names.
Shrinks: middleware/error.ts
and route-level compatibility shims.TEST Effect test migration — use testEffect, it.live, and
it.instance with explicit layers.
Shrinks: Promise-style tests, sleeps, mutable global test flags.RF RuntimeFlags / Flag deletion — move mutable
Flag reads into typed runtime/config
services.
Shrinks: flag.ts,
test/fixture/flag.ts.GLOBAL Global paths / import side effects — make global path state
explicit and testable instead of mutable module state.
Shrinks: global.ts import-time side
effects, mutable Global.Path overrides, and its Flag dependency.INST Instance context — keep project context explicit through Effect refs
and bridge boundaries.BRIDGE Promise/callback interop — keep bridge helpers, but reduce
legacy ALS coupling.
Shrinks: ad hoc Promise/callback re-entry code.PROC AppProcess migration — prefer AppProcess.Service over raw
process wrappers.
Shrinks: direct spawn callsites and legacy process helpers.FS FSUtil migration — prefer FSUtil.Service over raw
filesystem APIs.
Shrinks: direct fs / Bun.file service callsites where inappropriate.RT Runtime/facade cleanup — remove service-local makeRuntime
facades when not intentional.
Shrinks: async facade exports around services and
run-service.ts usage.OA OpenAPI compatibility — tighten source schemas instead of
post-processing generated OpenAPI.
Shrinks: schema workaround blocks in
public.ts.This should be the next big cleanup theme. The codebase is moving toward typed Effect failures, but the user-facing boundaries still leak old shapes and sometimes collapse rich errors into opaque strings.
NamedError.create(...) or
collapse to Effect.die(...). The storage/worktree/provider-auth
conversions are done; an inventory sweep is needed for the rest.NotFound, provider auth) can now be
removed, but the middleware overall has not shrunk.Schema.TaggedErrorClass.Error union and include it in method return types.Effect.die(...) is reserved for defects: bugs, impossible states,
violated invariants, or final unknown-boundary fallbacks.Effect.gen / Effect.fn, use yield* new MyError(...) for
direct expected failures.HttpApiError, or
route-specific error schemas.RENDER-1 CLI tagged config error rendering (#27256, tests #27257).ERR-1 storage/storage.ts typed
NotFoundError (#27265) and removal of the server defect fallback
(#27287).ERR-2 worktree/index.ts typed
errors (#27296).ERR-3 provider/auth.ts typed
validation/oauth errors (#27301).HTTP-1 Unknown-500 details no longer leaked (#27251); follow-up
to stop exposing named defects (#27471).HTTP-2 Audit one route group for explicit error contracts and
decide which mappings stay inline vs. shared helper.ERR-4 Sweep remaining NamedError.create(...) and
Effect.die(...) callsites for expected failures — re-run git
grep to build a current inventory.RENDER-2 Audit CLI and TUI surfaces for any remaining opaque
Error: Name rendering of typed errors.When touching tests, migrate them toward the ideal patterns in
test/EFFECT_TEST_MIGRATION.md:
testEffect(...) with explicit layers.it.instance(...) for service tests that need an instance.it.live(...) for real timers, filesystem mtimes, child
processes, git, locks, or other live integration behavior.process.env or mutable globals after layers are built.RuntimeFlags.layer(...), for
behavior changes.Recently completed:
RF-1 Reference reads routed through runtime flags (#27318).RF-2 Plan-mode prompt read routed through runtime flags (#27320).RF-3 Event-system reads routed through runtime flags (#27323).RF-4 Workspaces reads routed through runtime flags for session
(#27335), sync (#27336), and control-plane (#27337).refactor(task): use runtime flag for background subagents,
refactor(flags): remove background subagents flag).Remaining cleanup:
Flag.* reads — many CLI/TUI/config/observability
callsites still import flag.ts.
Decide per-callsite whether to route through RuntimeFlags, accept
as legitimate env/config boundary, or migrate to typed Config.test/fixture/flag.ts once
tests no longer mutate Flag.flag.ts once no packages
import it.global.ts is real connective tissue, not
just cosmetic ugliness. It currently mixes path calculation, import-time
directory creation, Flock setup, mutable exported Path state, and a
Flag dependency.
Problems to reduce:
Global.Path by mutating exported module state.Global.Path directly instead of the Effect service.Global.make() still reads mutable Flag.KIRINCODE_CONFIG_DIR.Next PR candidates:
Global.Path test overrides with explicit test
layers or scoped helpers.Flock setup behind an explicit init
boundary where possible.Flag dependency from global path resolution.Instance context migration is complete for the legacy sync shim. Promise and callback interop continues through effect/bridge.ts.
Current rules:
InstanceRef, WorkspaceRef, InstanceState, or explicit arguments.EffectBridge or explicit context arguments.PROC / FS — continue AppProcess and FSUtil migrations as
focused PRs when touching relevant files.RT — remove service-local runtime facades only when they are not an
intentional boundary.OA — shrink public.ts
by tightening source schemas one workaround at a time.fetch → HttpClient — migrate raw fetch callsites when the caller is
already effectful or being effectified.Tools — remaining tool cleanup is narrow: webfetch HTML extraction
and shell raw stream/promise edges.