Imported from yovanoc/effect-cdp (
AGENTS.md). Install upstream withnpx skills add yovanoc/effect-cdp. Copyright stays with the author.
effect-cdp
Vendored Repositories
This project vendors external repositories under @repos/
- Use vendored repositories as read-only reference material when working with related libraries
- Prefer examples and patterns from the vendored source code over generated guesses or web search results
- Do not edit files under @repos/ unless explicitly asked
- Do not import from @repos/ - application code should continue importing from normal package dependencies
When writing Effect code, inspect @.repos/effect/ for examples of idiomatic usage, tests, module structure, and API design. Treat it as the source of truth for Effect patterns.
always read @.repos/effect/LLMS.md before writing any Effect code.
Effect
- Effectful wrappers must use
Effect.fnUntracedunless spans are required. UseEffect.fnwhen spans are needed. Do not write(...args) => Effect.gen(function* () { ... }). - An
Effect.fnUntracedthat only doesreturn yield* effectis not allowed. Write the direct effect expression instead of wrapping it in a generator. - Outside generators, yieldables must be converted with
.asEffect()before piping. - All streaming implementations, including SSE and WebSockets, must use Effect
Stream. SSE must useeffect/unstable/encoding/Ssefor framing. WebSockets must use first party Effect socket abstractions. - Final live layers (
Rpc.toLayer, service layers, middleware layers) must be typed asLayer.Layer<ProvidedServices>. Intermediate and test-exported layers must infer naturally. UseLayer.orDieonly on final live compositions whose remaining errors are truly unrecoverable. - Never use
Effect.orDie. Handle typed errors explicitly withEffect.catchTagorEffect.catchTags, thenEffect.dieonly when the failure is genuinely unrecoverable. - Do not use the global
Errorclass in app code. UseSchema.TaggedErrorwith a_tagdiscriminator. Reuse an existing tagged error when one already fits. - Do not probe errors with checks like
if ("_tag" in error). That is an anti pattern. All app errors must already beSchema.TaggedErrorvalues with a typed_tag, so match on the typed error channel instead. - Yield services from context inside effect bodies. Do not pass service instances as function arguments.
- Services must expose typed errors, not defects.
- Services must expose typed errors only for actionable failures that callers can handle. If a tagged error has a
reasonfield, it must useSchema.Literals(...)with PascalCase values. - Non actionable failures must not be exposed as typed errors. Catch them at the service definition with
Effect.catchTagorEffect.catchTagsandEffect.die, or let existing defects propagate naturally. - Do not invent generic typed errors like
XFailed,InternalError, orUnknownError. When a failure is actionable, define a specificSchema.TaggedErrorfor it. - Do not erase error channels with
unknowninEffect<A, unknown>,Cause<unknown>, orExit<A, unknown>. Keep expected errors precisely typed so callers can safely pattern match on_tag. - When turning Effect causes into user visible or event payload text, use
Cause.pretty(...). Do not add bespokexFailureToMessagestyle helpers. If an error needs a better message than its_tagor existing fields provide, define that message on the tagged error itself. - Do not use
Schema.Unknownin app code or AI output schemas. Use explicitSchema.Structshapes orSchema.Json.
Architecture
- Prefer referentially transparent and pure functions.
- Immutability is required unless code is truly performance critical, which is rare.
- Default props, params, and collections to readonly shapes such as
readonlyproperties andReadonlyArray. - Prefer Effect collection modules such as
Arrayfor immutable collection transforms. - For repeated or complex nested immutable updates, use Effect
Optic. - Prefer flat directory structures. Each module should have its own directory with its files directly inside it instead of extra nesting layers.
- Follow DDD style colocation. Define domain modules inside the directory for that domain, export them there, and import them from that domain location instead of creating global shared domain modules.
- Entity IDs are branded with
Schema.brandin the owning RPC module. Construct branded IDs withEntityId.makeUnsafe(). Never cast withas EntityId. - No barrel
index.tsfiles. Import from the defining module. - Do not use optional properties when every consumer passes the value. Reserve them for generic primitive level modules.
- Pipeable values must use
.pipe(...). Non pipeable values must use Effectpipe()andflow(). Do not write nested application likef(g(x)). - Named schemas must add
.annotate({ identifier: "MySchemaName" }).
Observability
- Do not add manual logging or log annotations for error paths. OTEL spans already capture failures and context.
- Tracing must use
Effect.withSpanorEffect.fn. - Logging is only for domain level informational events like startup or sync progress.
Testing
- Non autogenerated code must maintain at least 80 percent test coverage.
- Coverage is a floor, not a goal. Write high value tests only, and do not add low value, redundant, or superfluous tests just to increase coverage.
- Tests use production composition. Mock only true external boundaries by swapping the boundary layer.
- Prefer regression tests, user path tests, and business logic tests that prevent future breakage.
- For bug fixes, add a regression test when practical.
- Prefer behavior and contract tests over implementation detail tests.
- Tests must be deterministic. Do not rely on arbitrary sleeps, timing races, or uncontrolled external state.
- For time dependent Effect tests, use
TestClockand advance logical time withTestClock.adjust(...)orTestClock.setTime(...)instead of waiting on wall clock time. - Use live time only for true external timing boundaries that
TestClockcannot control. - Do not test what TypeScript already proves, such as simple invalid argument types, unless the code relies on complex type level behavior in reusable library style code.
- Do not test behavior that third party libraries already guarantee unless the repo adds meaningful integration logic on top.
Analysis Methodology
When working in this codebase:
- Explore first — Before implementing, search existing patterns with grep/ast-grep
- Check vendored source — Always inspect
.repos/effect/for idiomatic Effect patterns; never invent APIs - Read actual source — Never guess API names; read the real exports from
src/index.ts - Verify with types — Run
bun run ts:checkafter any change