--- name: effect-v4-module-index description: The routing map for Effect v4 core — every module in one table, what it is, when to reach for it, and where to read it in the vendored source. Use FIRST when asking "what module do I reach for", "does Effect have a Sink/Pool/Trie/pattern-matcher", "what is Sink/Channel/Deferred/RcMap for", "where does X live in the source", or before designing ANY capability (the contract-inventory gate greps this map's territory). Opens with a routing-by-task table for the ones people miss by name — spawning a subprocess, a TTL cache with in-flight de-duplication, writing to stdout from a library. Rows route; they do not teach — patterns live in the other effect-v4-* skills, and the source is the authority on signatures and semantics. --- # Effect v4 module index Every module of `effect@4` core, one row each: **what it is**, **when to reach for it**. This skill exists so the other skills can stop explaining what things are and spend their space on patterns — and so no one designs a capability core already ships (the `effect-v4-planning` contract-inventory gate). **Where things live.** Every row's source is the vendored tree's `packages/effect/src/.ts` (testing modules under `src/testing/`, the namespace modules below under `src//`; resolve the tree root via `effect-v4-source-lookup`). The vendored submodule is pinned to the installed `effect` release and is the authority on existence, signatures, and — read alongside a probe — semantics (`effect-v4-source-lookup` owns the evidence ladder). It is also the **style oracle**: before building anything module-shaped, read how core writes the analogous module. **Stability split.** A module's stability is an annotation, not a separate import path — every module in core imports as `effect/` or `effect//` alike. The namespace modules below (`ai`, `cli`, `http`, `http-api`, `sql`, and the rest of the table under "The unstable-stability namespaces"), `Arbitrary` and `testing/TestSchema` carry `@stability unstable`: the API may break in a minor release. A few symbols in otherwise-stable modules carry the tag too (the network-address schemas in `Schema`, for one), and so does any API that exposes a third-party dependency's types. `@stability experimental` is the weaker still — it may break across patch versions. An API with no tag follows strict semver. Read the tag in the vendored source before building on an API (`grep -n "@stability" $SRC/packages/effect/src/.ts`), and keep unstable ones behind one seam of your own so a minor release has a single place to fix. ## Routing by task The module tables below are keyed by *name*. These rows are keyed by what you were about to go build, because each one has been reached for by its task phrasing and missed on its module name. | You want to… | Reach for | Note | | --- | --- | --- | | **spawn a subprocess / run a command / shell out** | `effect/process` — `ChildProcess` (command values) + `ChildProcessSpawner` (the service) | NOT `cli`'s `Command`, which is the CLI *declaration*. Core declares the contract and ships **no layer**: require `ChildProcessSpawner` in `R`, let the app provide `NodeServices.layer`. Never hand-roll `node:child_process`. | | **cache an effectful lookup with a TTL and in-flight de-duplication** | core `Cache` — `Cache.makeWith(lookup, { capacity, timeToLive })`, or `Cache.make` for a fixed TTL | Already does both jobs: it "shares an in-progress lookup when multiple callers request the same missing key" (`Cache.ts:4`) and expires by `timeToLive` (`Cache.ts:116`). Do not build a promise-map de-duplicator beside it — but read the two `Cache` sharp corners below before choosing a TTL. | | **write to stdout/stderr, or read argv/stdin, from a library** | core `Stdio` — require `Stdio` in `R` | `Stdio.layerTest(impl)` (`Stdio.ts:152`) takes a `Partial` and lets you echo-test the output **with no platform package installed**. The real implementation still comes from `@effect/platform-*` at the app edge. Do not `console.log` from library code to dodge the wiring. | ## Core modules | Module | What it is | When to reach for it | | --- | --- | --- | | `Array` | helpers over JS arrays, readonly and non-empty arrays (map/sort/group/split/reduce) | transforming, grouping, or combining array-shaped collections immutably | | `BigDecimal` | arbitrary-precision decimal (bigint digits + scale) with arithmetic and formatting | exact decimal math for money/quantities where `number` rounding fails | | `BigInt` | helpers over native `bigint`: arithmetic, comparison, safe parsing to `Option` | working with `bigint` values and needing safe parse/aggregate/order | | `Boolean` | helpers over `boolean`: logical ops, lazy branching, ordering, reducing | combining booleans or choosing between lazy branches | | `Brand` | compile-time nominal tags on structurally-identical values, optionally validating | keeping `Positive`/`UserId`-style values from mixing without runtime cost | | `ByteSize` | a branded non-negative `bigint` byte count (`ByteSize.ts:30`) with unit constructors (`bytes`, `kilobytes`/`kibibytes` … `quettabytes`), `fromInput`/`fromInputUnsafe` over `ByteSize.Input = ByteSize \| bigint \| number \| string`, `toBigInt`/`toNumber` (Option)/`toNumberUnsafe`, `sum`/`subtract`/`times`/`divide`, `Order`/`Equivalence`/`between`/`clamp`, `format` | any byte quantity — it **replaces `FileSystem.Size`/`SizeInput`**, which do not exist: `File.Info.size` and `blksize` are `ByteSize` (`FileSystem.ts:962-963`), `FileSystem.stream`'s `bytesToRead`/`offset` are `ByteSize.Input` (`:324-326`), `File.seek` takes a `bigint` and returns one (`:863`), `read`/`write` return `number`, `readAlloc`/`truncate` take `number` (`:866-867`). Reach for `ByteSize.toNumberUnsafe(info.size)` at a `Buffer` boundary, never `Number(info.size)` spelled by hand | | `Cache` | concurrent cache of Effect lookup results with capacity/TTL and in-flight sharing (`make` = fixed TTL, `makeWith` = per-entry TTL from the `Exit`) | memoizing an effectful lookup by key with dedupe/expiry — this is the whole feature; do not hand-roll an in-flight promise map | | `Cause` | full structured failure record: typed errors, defects, interruptions, annotations | inspecting or formatting why an Effect failed without collapsing it | | `Channel` | low-level bidirectional streaming primitive underlying Stream and Sink | implementing custom stream operators; app code uses Stream/Sink instead | | `ChannelSchema` | schema encode/decode adapters wrapping a Channel's typed boundaries | crossing a channel boundary with schema-typed input/output | | `Chunk` | immutable ordered collection optimized for append/prepend/concat | building/transforming sequences without mutating the original | | `Clock` | service for reading current time (ms/nanos) and sleeping | time/sleep access you want to fake in tests via a service | | `Combiner` | strategy interface `combine(a,b)` for merging two same-type values (no identity) | passing a reusable merge rule; use `Reducer` if you need an empty value | | `Config` | declarative descriptions of config values decoded from a ConfigProvider | reading/validating typed configuration keys with defaults and fallbacks | | `ConfigProvider` | data sources (env, objects, .env, dirs) that feed raw values to Config | supplying or composing where `Config` reads its raw values from | | `Console` | Effect wrapper over console (log/group/count/table/timer) as a swappable service | logging/console side effects you want swappable in tests | | `Context` | typed map of service implementations keyed by Service/Reference | building or reading the service environment `R` of effects | | `Cron` | recurring calendar schedule from cron expressions or field constraints | matching dates or computing next/previous scheduled occurrences | | `Crypto` | platform-independent crypto service contract: secure random bytes/numbers/shuffle, UUIDv4+v7, and a **one-shot** `digest` over `SHA-1/256/384/512` — **and nothing else** (no HMAC, no signing, no key derivation, no incremental hashing; `Crypto.ts:75-153`) | secure random/UUID/hashing of a value already in memory; contract, platform layer provides implementation. For HMAC, signing, or hashing a stream, `node:crypto` or a platform package — see the sharp corner below | | `Data` | constructors for immutable value classes, tagged classes/unions, typed errors | defining `_tag`-carrying domain values and errors with structural equality | | `DateTime` | absolute instants plus optional time-zone-aware date-times and arithmetic | zone-aware timestamps, date math, and formatting | | `Deferred` | one-time set-once async variable many fibers can await | cross-fiber coordination on a single result/signal | | `Differ` | interface to compute/combine/apply patches describing value changes | modeling incremental patch-based updates to a value | | `Duration` | immutable time span (finite or infinite) for delays/timeouts/TTL | expressing delays, timeouts, intervals, or TTLs | | `Effect` | core `Effect` type and the main API for building/running workflows | creating, composing, recovering, or running effectful programs | | `Effectable` | internal: prototype builder + base class to make custom values act as Effects | rarely — making a domain value yieldable in `Effect.gen` | | `Encoding` | Base64/Base64Url/hex encode/decode between strings, UTF-8, and bytes | converting to/from Base64/hex with `Result`-typed decode errors | | `Equal` | structural equality (`equals`) plus the Equal interface, guards, adapters | comparing values structurally or implementing custom equality | | `Equivalence` | reusable `Equivalence` equality predicates and combinators | defining/combining custom same-type equality for a purpose | | `ErrorReporter` | forwards non-interruption `Cause`s to a callback for logging/monitoring | routing Effect failures to external error-tracking systems | | `ExecutionPlan` | ordered fallback steps (context/layer + retries) tried until success | declaring fallback providers/retry tiers for effects or streams | | `Exit` | `Exit` value form of a finished Effect (success or `Cause` failure) | inspecting/matching a completed Effect result synchronously as data | | `Fiber` | handle to a forked effect: await/join/interrupt, current fiber access | managing forked concurrent work and its lifecycle | | `FiberHandle` | scope-bound holder of at most one fiber, replacing/interrupting prior | tracking a single swappable background fiber tied to a scope | | `FiberMap` | scope-bound map of fibers keyed by K, auto-removed on completion | managing keyed background fibers under one scope | | `FiberSet` | scope-bound set of many fibers, all interrupted when scope closes | managing a dynamic group of background fibers under one scope | | `FileSystem` | portable file system service (read/write/stream/glob/watch), fails `PlatformError`; sizes are `ByteSize` (see that row), and `File.seek` before the start of the file fails `BadArgument` and leaves the cursor unchanged (`FileSystem.ts:861-863`; the Node implementation is `@effect/platform-node-shared`, which the vendored tree does not carry — `effect-v4-source-lookup` says where to read it) | file IO; contract, platform layer provides implementation | | `Filter` | composable check returning `Result` (pass/fail) that can also narrow/transform | selective matching/recovery where a predicate must also refine or transform | | `Formatter` | renders arbitrary JS values to readable strings with redaction/cycle handling | formatting values for logs, diagnostics, or error messages | | `Function` | core composition helpers: `pipe`, `flow`, `dual`, identity/const/memoize | composing functions or writing dual direct/pipe APIs | | `Graph` | immutable indexed node+edge graph carrying user data on both, mutated only inside a scoped window (`mutate(g, draft => …)`, or `beginMutation`/`endMutation`); directed-vs-undirected is a `Kind` type parameter. 95 exports — `dfs`/`bfs`/`topo`/`externals` walkers, the named algorithms (`dijkstra`, `bellmanFord`, `floydWarshall`, `astar`, `isAcyclic`, `isBipartite`, `connectedComponents`, `stronglyConnectedComponents`), graph set algebra (`compose`, `intersection`, `difference`, `symmetricDifference`, `complement`, `sum`), and `toMermaid` / `toGraphViz` emitters returning a diagram `string` | any graph problem — **do not hand-roll shortest path, topological sort, cycle detection, or SCCs beside it.** `Kind` gates the algorithms at the type level: `topo`/`stronglyConnectedComponents` take `"directed"` only, `isBipartite`/`connectedComponents` `"undirected"` only, so pick the constructor for the analysis you need (`stronglyConnectedComponents` also throws `GraphError` on an undirected graph at runtime). Reach for `toMermaid` whenever you want a diagram of anything you can model as nodes and edges | | `Hash` | computes non-cryptographic structural hashes; interface for custom hash | implementing custom hashing for Equal-based collections | | `HashMap` | immutable key/value map (HAMT) keyed by structural equality | need immutable map with object/structural keys | | `HashRing` | weighted consistent-hashing ring keyed by `PrimaryKey` | routing keys/shards to nodes with minimal remapping | | `HashSet` | immutable set of unique values by Equal/Hash | need immutable set with structural-equality membership | | `HKT` | type-level: `TypeLambda`/`Kind` higher-kinded encoding | only when authoring generic type classes; agents skip | | `Inspectable` | internal: log/inspect formatting protocol for Effect values | implementing custom log/console/JSON rendering; rarely needed | | `Iterable` | lazy combinators over any `[Symbol.iterator]` value | transform/search/group iterables without materializing arrays | | `JsonPatch` | computes/applies deterministic RFC6902 add/remove/replace patches | diffing two JSON docs or replaying JSON changes | | `JsonPointer` | RFC6901 token escape/unescape helpers | escaping `~`/`/` in JSON Pointer path segments | | `JsonSchema` | normalize/convert JSON Schema & OpenAPI dialect documents | converting between Draft-07/2020-12/OpenAPI schemas, `$ref` resolution. **Generation lives in `Schema`**: `Schema.toJsonSchemaDocument` (2020-12; `includeAnnotationKey` admits custom keys) then `JsonSchema.toDocumentDraft07` to lower. **The lowering carries unknown and custom keywords through as opaque values**, in place — so an annotation admitted at 2020-12 reaches draft-07 unchanged, and there is nothing to re-graft — the failure to guard against is publishing a key you assumed could not escape. The `$defs` pool maps key-for-key, and annotations move with their node across the coordinate moves (`prefixItems[i]`→`items[i]`, trailing `items`→`additionalItems`). Filtering is the caller's job, upstream of the lowering. Probe evidence: `@effected/schemastore`'s `__test__/annotation-carrying.test.ts`, which asserts on raw core output. | | `Latch` | reusable open/closed fiber coordination primitive | gating fibers until an explicit open/release signal | | `Layer` | describes acquiring/wiring services with deps and errors | constructing and composing service dependencies | | `LayerMap` | keyed cache of scoped layer-built service contexts | per-tenant/per-region resource families built on demand | | `LayerRef` | refreshable single layer-built context with invalidation | share one scoped layer resource, rebuild on invalidate | | `Logger` | loggers, formatters, console/file routing, install layers | configuring/customizing how log events are emitted | | `LogLevel` | log-level types, ordering, threshold/enabled helpers | comparing or checking log severities | | `ManagedRuntime` | runs many effects against services built once from a Layer | bridging Effect to promise/callback/sync entry points | | `Match` | ordered pattern matcher (`Match.type`/`Match.value`) | pattern-matching on tags, shapes, predicates, literals | | `Metric` | counters/gauges/histograms/frequencies/summaries/timers, attached to effects via `Effect.track` | metering an operation — boundaries only; see `effect-v4-observability`. NB there is no `Metric.tagged`/`taggedWithLabels`; attributes are `Metric.withAttributes` | | `MutableHashMap` | in-place map mixing native and Equal/Hash keys | fast mutable map needing structural-key lookup | | `MutableHashSet` | in-place unique set built on MutableHashMap | fast mutable set with structural-equality members | | `MutableList` | in-place ordered list; append/prepend, drain from front | buffering values and draining FIFO in place | | `MutableRef` | synchronous in-place single-value reference | non-effectful mutable cell (vs `Ref`) | | `Newtype` | compile-time-only branded wrappers over a carrier type | distinguishing same-shape values (e.g. two string ids) | | `NonEmptyIterable` | type-level: `Iterable` branded as having ≥1 element | typing guaranteed-non-empty iterables; rarely imported directly | | `Number` | helpers over `number`: parse, math, compare, clamp, aggregate | numeric parsing, safe division, ordering, range checks | | `Optic` | lens/prism/optional focus for immutable read/update | reading/updating nested immutable structures without mutation | | `Option` | present/absent value `Some`/`None`, plus `Option.gen` | modeling optional values instead of null/undefined | | `Order` | comparison functions for ordered values | sorting, min/max, ranges, ordered structures | | `Ordering` | the `-1/0/1` comparison result plus combinators | working with the output of an `Order` comparison | | `PartitionedSemaphore` | concurrency limiter over shared permits grouped by key | fair bounded concurrency across independent key groups | | `Path` | path ops service (join/normalize/parse/resolve); POSIX `Path.layer` built in | path manipulation; contract, platform layer provides (POSIX layer in core) | | `Pipeable` | internal: `.pipe(...)` method-chaining interface | only when authoring a pipeable data type; agents skip | | `PlatformError` | normalized platform error model (`BadArgument`/`SystemError` reasons) | typing/handling FileSystem/Terminal/subprocess/host IO failures | | `Pool` | shares scoped resources borrowed across fibers | pooling connections/clients with TTL and invalidation | | `Predicate` | runtime guards and refinements with combinators | type guards, tag/shape checks, composing predicates — never hand-write `isString`/object guards (NB: no `isRecord` on the v4 line; the record-ish guards are `isObject`/`isReadonlyObject`/`isObjectOrArray`) | | `PrimaryKey` | protocol exposing a stable string identifier | giving a value a stable string key (requests, ring nodes) | | `PubSub` | broadcast hub; each subscriber gets every message | fan-out messaging where subscribers don't compete | | `Pull` | internal: one low-level stream pull step (value/error/done) | only when writing custom Stream/Channel internals; agents skip | | `Queue` | async fiber-to-fiber queue; one consumer per value | backpressured/bounded work handoff between fibers | | `Random` | pseudo-random generator exposed as a replaceable Effect service | need effectful/seeded random numbers, shuffles, or deterministic test randomness | | `RcMap` | reference-counted map of scoped resources keyed, released when idle/unused | sharing per-key clients/connections/sessions with lifecycle, not general caching | | `RcRef` | reference-counted handle sharing one scoped resource across borrowers | share a single lazily-acquired resource; finalize when last borrower leaves | | `Record` | immutable helpers over plain string/symbol-keyed object dictionaries | working with `{}` dictionaries functionally: map/filter/merge/lookup without mutation | | `Redactable` | protocol for context-aware alternate representations of sensitive objects | building a type that masks itself in logs/traces/serialization | | `Redacted` | wrapper hiding a value in string/JSON/inspect output while retaining it | carry secrets/tokens through code without leaking them in diagnostics | | `Reducer` | `Combiner` plus an initial value and fold-an-iterable operation | fold many values into one with an identity/empty case | | `Ref` | fiber-safe mutable cell with effectful get/set/update/modify | hold shared mutable state that composes with Effect concurrency | | `References` | built-in `Context.Reference` runtime keys — logging, tracing, stack frames, loggers | read or override runtime diagnostic settings for an effect. **No concurrency key exists** despite the module's own header prose claiming one — concurrency is a per-call `{ concurrency }` option | | `RegExp` | native `RegExp` constructor, guard, and literal-escaping helper | build patterns from data-driven text or narrow `unknown` to RegExp | | `Request` | typed request value describing one data-load with error/requirements | define a batchable/cacheable data query for `Effect.request` | | `RequestResolver` | resolver that batches, groups, and completes pending `Request` entries | implement backend batching/dedup/caching behind `Effect.request` | | `Resource` | refreshable scoped value caching last acquisition, auto/manual refresh | cache a scoped value that must refresh on schedule or on demand | | `Result` | plain `Success`/`Failure` data holding an already-computed outcome | represent a settled success-or-error value without running effects (v4's Either successor) | | `Runtime` | low-level `makeRunMain` for turning an Effect into a process entry point | writing a platform runner; app code uses platform-provided runners instead | | `Schedule` | policy stepping inputs into outputs plus delays for retry/repeat/pace | decide when/how often to retry, repeat, or pace an effect | | `Scheduler` | controls how runnable fiber tasks are queued, dispatched, and yielded | internal/advanced: tune or disable fiber scheduling and yields — usually skip | | `Schema` | validate/decode/encode data shapes with codecs, classes, refinements | the primary entry point for any schema, codec, or data validation | | `SchemaAST` | runtime tree representation of schemas (nodes, checks, annotations) | advanced machinery: inspect/build/rewrite schema ASTs programmatically | | `Schema.SchemaError` | the error a schema decode/encode fails with: a `SchemaIssue` tree plus a formatted `message`. **Not a module** — it is a class exported from `Schema.ts` (`Schema.ts:1176`), so `import … from "effect/SchemaError"` fails to resolve; there is no `src/SchemaError.ts` and no `./SchemaError` export. Import it as `Schema.SchemaError` | catching/normalizing schema failures at a boundary — `Effect.catchTag("SchemaError", …)`. v4 exposes no `Schema` for the issue tree, so it rides in a domain error as `Schema.Defect()` | | `SchemaGetter` | one-way optional-in/optional-out conversions used inside transformations | consumer-facing when authoring a custom decode/encode direction | | `SchemaIssue` | describes and formats decode/encode/check failures with location | consumer-facing: inspect or format schema validation errors | | `SchemaParser` | runs a schema against values (decode/encode/validate) in many result styles | consumer-facing: execute a schema returning Effect/Exit/Option/Result/sync | | `SchemaRepresentation` | JSON-serializable descriptions of schemas plus TS-codegen | machinery: serialize schemas, convert to/from JSON Schema, generate code | | `SchemaTransformation` | two-way encode/decode conversions connecting two representations | consumer-facing when building a custom bidirectional codec | | `Scope` | lifetime boundary collecting finalizers run with an `Exit` on close | directly create/fork/close scopes; most code uses `Effect.scoped`/`Layer` | | `ScopedCache` | cache whose entries own scopes, releasing resources on eviction | cache resource-backed values with per-entry cleanup and expiry | | `ScopedRef` | current value plus the scope owning it; swaps acquire/release atomically | hold a swappable resource handle (client/connection) with clean replacement | | `Semaphore` | permit pool limiting concurrent access to a shared resource | bound concurrency around an effect via acquire/release of permits | | `Sink` | stream consumer folding/collecting a `Stream`'s output into one result | terminating a Stream: collect, fold, count, or search its elements | | `Stdio` | argv and stdin/stdout/stderr of the CURRENT process as an Effect service | standard-IO access (not spawning); contract, platform layer provides — but core ships `Stdio.layerTest(Partial)` for echo-testing without one | | `Stream` | effectful source emitting many values over time with error/requirements | model pull-based/streaming data: queues, callbacks, files, paginated sources | | `String` | pipe-friendly helpers over TypeScript `string` values | functional string ops: trim/case/slice/replace/Option-returning search | | `Struct` | immutable helpers over plain TypeScript objects (pick/omit/rename) | transform object shapes functionally and derive comparisons | | `SubscriptionRef` | `Ref` that publishes every committed change as a `changes` stream | hold state others must observe reactively over time | | `Symbol` | runtime predicate narrowing `unknown` to a primitive `symbol` | guarding an `unknown` before using it as a symbol key/discriminant | | `SynchronizedRef` | `Ref` whose updates run one-at-a-time, safe for effectful transitions | serialize state updates when the next value is computed by an effect | | `Take` | stored representation of one stream pull: batch, failure, or done | low-level stream plumbing: inspecting buffered pull results | | `Terminal` | interactive terminal service (size, line/key input, output) | terminal capabilities; contract, platform layer provides | | `Tracer` | low-level span/tracing model and tracer service | define/inspect spans or a custom tracer; usually via higher-level tracing APIs | | `Trie` | immutable string-keyed prefix tree for prefix/longest-match lookup | autocomplete, route tables, dictionaries, prefix-based key lookup | | `Tuple` | immutable helpers over fixed-length arrays preserving element positions | build/transform positional tuples and derive tuple comparisons | | `TxChunk` | transactional `Chunk` stored in a `TxRef` | STM-family: atomic sequence/buffer updates within a transaction | | `TxDeferred` | write-once transactional cell completing to a `Result`, retrying readers | STM-family: coordinate/await a one-shot value across transactions | | `TxHashMap` | transactional `HashMap` in a `TxRef` | STM-family: atomic keyed registry/counter/index updates | | `TxHashSet` | transactional `HashSet` in a `TxRef` | STM-family: atomic set membership changes alongside other state | | `TxPriorityQueue` | transactional priority queue ordered by an `Order`, retrying take/peek | STM-family: ordered coordination queue with transactional waiting | | `TxPubSub` | transactional publish/subscribe hub over `TxQueue` subscribers | STM-family: broadcast values atomically within transactions | | `TxQueue` | transactional queue with enqueue/dequeue handles, retrying when blocked | STM-family: coordinate producers/consumers within transactions | | `TxReentrantLock` | transactional reentrant read/write lock tracked by fiber | STM-family: shared/exclusive locking that composes in transactions | | `TxRef` | core transactional reference journaled and committed via `Effect.tx` | STM-family: the base transactional cell all Tx collections build on | | `TxSemaphore` | transactional fixed-capacity permit pool in a `TxRef` | STM-family: permit acquisition that commits with other transactional state | | `TxSubscriptionRef` | transactional `Ref` publishing committed changes to subscribers | STM-family: observable transactional state with current-value replay | | `Types` | compile-time-only utility types (tuples, unions, variance, mutability) | type-level plumbing — no runtime; agents skip unless authoring types | | `UndefinedOr` | helpers for plain `A \| undefined` values | handle optionality with `undefined` without wrapping in `Option` | | `Unify` | type-level unification protocol collapsing unions to public data types | maintainer/advanced type plumbing — skip | | `Utils` | internal generator machinery behind `Effect.gen`/HKT | internal — skip | | `testing/TestClock` | controllable `Clock` service driving virtual time | make sleep/timeout/schedule/retry tests deterministic by advancing time | | `testing/TestConsole` | test `Console` capturing log/error calls in memory | assert on console output deterministically in tests | | `testing/TestSchema` | assertions for one schema: `new TestSchema.Asserts(schema)` with `make`, `decoding()` / `encoding()` (`succeed`/`fail` as Promises, `succeedEffect`/`failEffect` as lazy Effects), `arbitrary()` and `verifyRoundTrip` / `verifyRoundTripEffect`; the property checks run `Arbitrary.checkEffect`. `@stability unstable` | testing that a schema constructs, decodes, encodes and round-trips correctly. The `Effect`-suffixed forms use the calling fiber's services, so they compose inside `it.effect`. **There is no `testing/FastCheck`** — there is no fast-check bridge; property generation is `Arbitrary` | ## The unstable-stability namespaces (`effect/`) Breaking changes allowed in minors; the `@stability unstable` annotation is what marks these, not a separate import path — they import exactly like any other core module. These namespaces are where the consolidated core put functionality that ships as separate packages nowhere else: HTTP, RPC, cluster, SQL, CLI and the rest live here, and the only packages outside `effect` are platform-, provider- or technology-specific *implementations* (`@effect/platform-*`, `@effect/sql-*`, `@effect/ai-*`, `@effect/opentelemetry`, `@effect/vitest`). See `effect-v4-services-layers` for the require-in-`R`-never-own-a-backend rule that follows from it. | Namespace | What it is | When to reach for it | | --- | --- | --- | | `ai` | provider-neutral AI: `LanguageModel`, `Chat`, `Tool`/`Toolkit`, MCP schema/server | building AI features against a provider-agnostic surface (`@effect/ai-*` provides) | | `arbitrary` | the native property-testing engine, one module `Arbitrary`: `schema`, `Constant`, `map`/`filter`/`filterMap`/`flatMap`/`all`, `sampleEffect`, `checkEffect`, `formatCheckFailure`, `CheckOptions` | deriving generators from a Schema for `it.prop`/`it.effect.prop`, or running a property outside vitest — replaced `effect/testing/FastCheck` and `Schema.toArbitrary`. It has **no** `oneof`/`constantFrom`; choice and collections are Schemas — see `effect-v4-schema/references/11-generation-and-tooling.md` for the one collection combinator (`Arbitrary.array`) that does exist independent of Schema. Traps and translations → `effect-v4-testing`, surface → `effect-v4-schema/references/11-generation-and-tooling.md` | | `cli` | the v4 CLI framework: `Command`, `Flag`, `Argument`, `Prompt`, completions | building a command-line tool — see `effect-v4-cli` | | `cluster` | entity sharding runtime: `Sharding`, `Entity`, runners, message storage | distributing stateful entities across machines | | `devtools` | client/server wiring an Effect runtime to the devtools tracer | connecting a program to Effect devtools | | `encoding` | channel codecs: `Msgpack`, `Ndjson`, `Sse` | framing streams as NDJSON/MsgPack/server-sent events | | `eventlog` | typed, replicated (optionally encrypted) event journal with SQL backends | event-sourced state that syncs/replicates | | `http` | HTTP client + server: `HttpClient`, `FetchHttpClient`, router, middleware | any HTTP work — clients (see runtimes precedent) or servers. Branching on a client failure: see the `reason` trap below; MIME lookup is `http/Mime` (`getType`/`getExtension`/`getAllExtensions`) — there is no `mime` npm dependency | | `net` | `IpInterface`, `IpNetwork`, `NetAddress` — pure, canonical IPv4/IPv6 addresses and CIDR prefixes (three modules) | parsing/normalizing an address or network prefix without a third-party `ipaddr`-style library | | `http-api` | schema-first declarative HTTP APIs with OpenAPI/Swagger output | defining a typed HTTP API contract shared by server and client | | `observability` | OTLP + Prometheus exporters for traces/metrics/logs | exporting telemetry without the `@effect/opentelemetry` SDK | | `persistence` | `KeyValueStore` (memory/fs/SQL), `PersistedCache`/`PersistedQueue`, `RateLimiter` | durable KV, request-level durable caching, rate limiting | | `process` | `ChildProcess` Command values + `ChildProcessSpawner` service | spawning subprocesses (`@effected/git` is the house example; require in `R`) | | `reactivity` | atom-based reactive state (`Atom`, `AtomRegistry`, hydration) | framework-facing reactive state (`@effect/atom-*` binds it) | | `rpc` | schema-backed RPC: groups, client/server, serialization, worker transport | typed request/response between processes without hand-rolling HTTP | | `schema` | `Model` (DB-vs-JSON variant models) + `VariantSchema` | one model with per-context variants (insert/update/json) | | `socket` | `Socket` + `SocketServer` contracts | raw bidirectional connections | | `sql` | the SQL core: `SqlClient`, `Statement`, `Migrator`, models/resolvers | any SQL — drivers live in `@effect/sql-*` (`@effected/store` is the house example) | | `workflow` | durable workflows: `Workflow`, `Activity`, durable clock/deferred/queue | long-running resumable multi-step operations (application tier — see roadmap note) | | `workers` | `Worker`/`WorkerRunner`/`Transferable` for worker threads | offloading work to browser/Node/Bun workers | ## Sharp corners the index surfaced (not covered elsewhere) - `Queue` is `Queue` in v4 — it carries an error channel and can `fail`/`done`, not just hold values. - `Optic` is in core (there is no `@effect/optic` to install) and is Schema-aware. - Transactional state is the `Tx*` family: `TxRef` + `Effect.tx`, with a core module per collection. There is no `STM`/`TRef`/`TMap`/`TQueue`. - Runtime knobs (concurrency, logging, tracing settings) live in `References` as `Context.Reference` keys; scheduling internals in `Scheduler`. - `UndefinedOr` exists for `A | undefined` ergonomics — not every optional needs `Option`. - Testing utilities live in core under `effect/testing/*` — no separate test-support package. - **"Core has `Crypto`" is a dependency decision, so read the shape first.** The contract covers secure random (`randomBytes`, `random`, `randomInt`, `randomShuffle`), UUIDv4/v7 and SHA **digests** (`"SHA-1" | "SHA-256" | "SHA-384" | "SHA-512"`, `Crypto.ts:40`, `Crypto.ts:78-154`) — and stops there. There is **no HMAC, no signing, no key derivation, no `subtle`-style surface**. A design that reads the module name and concludes "hashing is handled" is right; one that concludes "crypto is handled" and then needs an HMAC (request signing, a SigV4-style derivation, a webhook signature) discovers mid-implementation that it must reach for `node:crypto` or a platform package after all — after the tier and peer decisions were already made on the wrong premise. - **`Crypto.digest` is one-shot, and that is a second dependency decision.** The signature is `digest(algorithm, data: Uint8Array)` (`Crypto.ts:100-103`) — it takes the whole payload at once and there is **no incremental/streaming form**, no `update`/`digest` accumulator pair. So hashing a file, a tarball or any input without a known upper bound means buffering all of it in memory to use this API, where `node:crypto`'s `createHash(...).update(chunk)` walks a stream at constant cost. Digesting a key, a token or a short manifest is a fit; digesting an artifact is not. In the kit this is exactly why `github-actions`' `Artifact` and `PackageManagerInstaller` stay on `node:crypto` — both fold a `Stream` chunk-by-chunk on purpose. - **Core `Cache` is interrupt-clean, unlike `Effect.cached`.** Interrupting the only awaiter **discards** the in-flight entry and the next `get` re-runs the lookup; concurrent gets still de-dupe to one lookup. So the `Effect.cached` poisoning trap (a memoized `Exit` carrying an interrupt, permanently outside the declared error channel) does **not** transfer here. Probed with a poisoning control that fired. - **…but a default-TTL `Cache` memoizes a FAILED lookup for the process lifetime.** `defaultTimeToLive` is `Duration.infinity` (`Cache.ts:323`), and the cache "stores successful **and failed** lookup results" (`Cache.ts:4`). One transient network blip is therefore permanent. Wherever failures are transient, make the TTL exit-dependent — the `timeToLive` option takes `(exit, key)` for exactly this (`Cache.ts:198`; the same two-argument shape on the cache's own field at `Cache.ts:116`). Note `Cache.make`'s `timeToLive` is a plain `Duration.Input` with no exit access (`Cache.ts:298`) — the exit-dependent form requires `makeWith`: ```ts Cache.makeWith(lookup, { capacity: 1000, timeToLive: (exit) => (Exit.isSuccess(exit) ? "1 hour" : Duration.zero), }) ``` - `HttpClientRequest.bearerToken` accepts a **`Redacted` directly** (`token: string | Redacted.Redacted`, `http/HttpClientRequest.ts:396`; `basicAuth` likewise). A runtime token flows into request construction with **no declassification step at all** — which is what lets a package keep its secret-handling seam to one module instead of granting every request builder an exception to it. Do not reach for `Redacted.value` here. ## How the skills divide the territory This index routes. For patterns: `effect-v4-idioms` (errors, resources, fibers), `effect-v4-schema` (everything Schema), `effect-v4-services-layers` (Context/Layer discipline), `effect-v4-testing` (the test idioms), `effect-v4-observability` (spans/logs/metrics), `effect-v4-cli` (`cli`), `effect-v4-source-lookup` (how to verify any row here against the source). ### `HttpClientError`: the `reason` tags are not the type names A client failure is one `HttpClientError` whose top-level `_tag` is always `"HttpClientError"`, so branch on `error.reason._tag`. The values are the trap. The reason type is declared in two layers, and **both layer names are themselves unions, so neither ever appears as a `_tag`** (verified against `http/HttpClientError.ts:277,285,293`): ```ts export type RequestError = TransportError | EncodeError | InvalidUrlError export type ResponseError = StatusCodeError | DecodeError | EmptyBodyError export type HttpClientErrorReason = RequestError | ResponseError ``` So `error.reason._tag` is exactly one of **six** values: `"TransportError"`, `"EncodeError"`, `"InvalidUrlError"`, `"StatusCodeError"`, `"DecodeError"`, `"EmptyBodyError"`. A retry policy written `error.reason._tag === "ResponseError"` (or `=== "RequestError"`) **never matches**, so it silently retries nothing — a live-looking branch that is dead code, and green tests will not catch it. What makes the wrong guess feel confirmed: `ResponseError` *is* a real tagged class elsewhere, at `http/HttpServerError.ts:197`. Same name, different module, and it is a server error rather than a client one. Timeouts are separate again — `Cause.isTimeoutError`, not a `reason`.