Skip to content
Effect Days 2026 Get your ticket

effect

4.0.0-rc.115

Patch Changes

  • #8196 657254b Thanks @gcanti! - Optimize schema initialization while preserving custom constructor options.

  • #8190 f9ef0e9 Thanks @javascript-unsafe! - Omit response bodies for statuses 204, 205, and 304 in HttpServerResponse.toWeb and the Bun/Deno HTTP adapters, preventing invalid Web responses and hung requests. Cancel omitted raw ReadableStream bodies, and finalize request resources without starting omitted Effect streams.

  • #8187 4f73f9e Thanks @tim-smart! - Parameterize persistence lookup keys in both SQL backing stores’ getMany queries.

4.0.0-rc.114

Patch Changes

  • #8177 3ff4952 Thanks @tim-smart! - Allow Effect.cachedWithTTL to compute the TTL from each completed Exit, so successes and failures can use different cache durations.

  • #8164 6d55555 Thanks @sam-goodwin! - Keep Node and Bun file stats usable when optional numeric metadata exceeds the safe integer range by returning Option.none() for those fields.

  • #8162 716e0c0 Thanks @tim-smart! - Fix published declarations referencing symbols stripped as @internal, which broke consumers compiling with skipLibCheck: false. Effectable.d.ts now uses the public Effect.TypeId, Match.d.ts no longer aliases an internal Contextual type, Schema.d.ts ships the AnnotationSchemaConstraint alias it references, and the CLI’s toFlagDoc helper is marked internal so it no longer leaks Param.getParamMetadata.

  • #8160 d4e4ad5 Thanks @gcanti! - Fix SchemaRepresentation.toCodeDocument generating invalid TypeScript for optional tuple elements containing unions or nested readonly tuples. Optional element types are now parenthesized, for example readonly [(string | number)?] instead of readonly [string | number?]. Generated runtime schemas are unchanged.

  • #8158 b1988f4 Thanks @gcanti! - Fix SchemaRepresentation.toCodeDocument dropping Struct fields named __proto__ from generated schemas. These fields now use computed keys, such as Schema.Struct({ ["__proto__"]: Schema.String }), so the generated schema validates them correctly.

  • #8169 482b7d7 Thanks @gcanti! - Improve SchemaRepresentation.fromJsonSchemaDocument and fromJsonSchemaMultiDocument:

    • Import { not: {} } as Schema.Never (#8137).

    • Import closed records with one patternProperties entry, additionalProperties: false, and no declared or required properties when patterns: "apply" is enabled. These were previously rejected.

      {
      "type": "object",
      "patternProperties": { "^a": { "type": "number" } },
      "additionalProperties": false
      }
      Schema.Record(
      Schema.String.check(Schema.isPattern(/^a/)),
      Schema.Finite
      )
    • Reject open patterned objects with patterns: "apply" instead of generating incompatible TypeScript index signatures.

      {
      "type": "object",
      "patternProperties": { "^a": { "type": "number" } },
      "additionalProperties": true
      }

      Import now explains that the generated TypeScript index signatures would give incorrect types to unmatched keys, and reports the source path. The same applies when additionalProperties is omitted or {}. Patterns can still be combined with a closed object in allOf when the result has a finite set of keys. Use patterns: "ignore" only if you intend to discard the pattern and its value constraints.

    • Reject references inside a subschema with its own $id instead of potentially resolving against the wrong definitions. Resolve or flatten these references before importing. A $id on the document root remains supported.

      {
      "$id": "https://example.com/root",
      "$defs": { "Value": { "type": "string" } },
      "type": "object",
      "properties": {
      "child": {
      "$id": "child",
      "$defs": { "Value": { "type": "number" } },
      "$ref": "#/$defs/Value"
      }
      }
      }

      Here child refers to the nested numeric Value, not the root string Value. Import now reports that references inside a subschema with its own $id are unsupported instead of incorrectly using the root definition.

    • Explain import failures using JSON Schema keyword names, the reason for rejection, and the source path. Reference errors distinguish missing definitions, unsupported reference formats, and circular aliases. Pattern errors explain how to opt in for trusted schemas or explicitly discard the constraints.

  • #8162 716e0c0 Thanks @tim-smart! - Rename Schema.Annotations.ToArbitrary.Constraint to Schema.Annotations.ToArbitrary.FilterConstraint.

    Code that refers to the previous type name should update its type annotations to use FilterConstraint.

  • #8181 9941e6d Thanks @Ishkirat-Singh! - Make message optional for Prompt.Select and Prompt.MultiSelect. When omitted, prompts display only the choices and submission shows a tick followed by the selected titles. Prompt.AutoComplete still requires a message.

4.0.0-rc.113

Patch Changes

  • #7738 49e3901 Thanks @kitlangton! - Retain completed tool approval results in non-streaming responses so Chat records them and does not replay approved tools on later turns.

  • #7483 b945ded Thanks @tim-smart! - Align runtime type IDs with their module paths. Effect markers now omit legacy grouping prefixes and the unstable path segment, while OpenTelemetry spans use the OtelTracer module path. Custom implementations that copy these marker strings must adopt the corrected IDs.

  • #8014 d6422f4 Thanks @kitlangton! - Fix Effect.all to retain errors and required services from every branch of a union of record inputs.

  • #8095 5a80204 Thanks @gcanti! - Fix Arbitrary.schema to respect applicable index signatures when generating and shrinking object properties, including fixed fields in Schema.StructWithRest and overlapping records.

    Combine compatible string, number, and bigint constraints during generation so cases such as a String field constrained by a NonEmptyString record remain productive at size zero. Other intersections are validated and may exhaust the discard budget.

  • #7796 53511ef Thanks @kitlangton! - Fix Schema.ArrayEnsure to preserve array-valued element branches and outer-array encoding cardinality.

  • #8067 79ae49f Thanks @purwasadr! - Fix AtomRpc.query returning never for RPCs whose middleware declares service requires. The return-type conditional now infers all six Rpc type parameters, matching mutation and every utility in Rpc.

  • #7463 0d083ba Thanks @tim-smart! - Remove the mime runtime dependency. The new effect/unstable/http/Mime module provides top-level lookup functions backed by a vendored standard MIME registry.

  • #7477 be0f822 Thanks @candrewlee14! - Allow sockets to use browser, Bun, and Node WebSocket implementations without consumer casts. Platform constructors now support typed opening-handshake headers where available.

  • #7587 debe8fd Thanks @kitlangton! - Fix Cache.invalidateWhen and ScopedCache.invalidateWhen deleting a replacement entry while waiting for an earlier lookup.

  • #7585 a8588f9 Thanks @kitlangton! - Fix interruption of Cache.refresh for a missing key removing a newer value written by Cache.set.

  • #7596 f17eb0a Thanks @kitlangton! - Fix Cache.refresh and ScopedCache.refresh exceeding capacity when an existing key is evicted while its refresh is in progress. Publishing the refreshed entry now evicts older entries as needed, releasing their resources in ScopedCache.

  • #7595 f30cbfe Thanks @kitlangton! - Fix Cache.refresh for an initially missing key deleting a newer cached value when the refresh completes with zero time to live.

  • #7614 78cc9c0 Thanks @kitlangton! - Prevent Cache from retaining synchronously interrupted lookups.

  • #7563 ccbdbd5 Thanks @alvarosevilla95! - Respect custom HTTP header redaction when recording server span attributes.

  • #7254 a63dcbf Thanks @gcanti! - Add the experimental Schema-first effect/unstable/arbitrary/Arbitrary module for native generation without fast-check. Arbitrary.schema derives an opaque arbitrary from the decoded Schema Type, Arbitrary.sampleEffect provides interruptible sampling with typed exhaustion, and Arbitrary.checkEffect returns structured property results. The initial implementation supports bounded discards, shrinking, replay, and recursive and mutually recursive Schemas. SampleError and Exhausted include the effective seed so discarded runs remain reproducible even when the caller did not provide one. Arbitrary.isArbitrary identifies values through the module’s nominal protocol. Numeric constraints retain NaN when it is accepted by their supported Order.Number bounds. Union derivation validates oneOf exclusivity and isolates lazy cross-member shrinking from unrelated random generation. Object derivation keeps optional-property selection constructive when candidate fields have different recursive costs. Struct, Record, JSON-object, and record-shaped Arbitrary.all outputs periodically use a null prototype as an edge case, preserving that prototype throughout shrinking and replay without perturbing structural PRNG choices. The change adds 0.01–0.03 KB gzip to representative Arbitrary fixtures and leaves production-only bundle sentinels unchanged.

    Add Arbitrary.map, Arbitrary.flatMap, Arbitrary.filter, Arbitrary.filterMap, and Arbitrary.all for composing derived Arbitraries without exposing a second catalog of primitive constructors. Filtering remains bounded and promotes valid shrink descendants through rejected nodes. maxShrinks bounds every inspected shrink candidate, including candidates rejected before property evaluation, while retaining the best shrunk input found when the budget is exhausted. flatMap provides deterministic dependent generation, source-first shrinking, post-source PRNG checkpoints, and one shared residual recursion budget. all combines tuples, iterables, and records with a shared budget, randomized internal generation order, stable output shape, and independent member shrinking. Arbitrary values implement Pipeable for composition with data-last combinators.

    Add the experimental Schema arbitraryConstraint and toCodecArbitrary annotations and their Schema.Annotations.ToArbitrary types. Declarations can provide a Schema Link optimized for generation, while filters can contribute native semantic constraints. The callback receives decoded type parameters and normalized constraints. The compiler owns efficient representations for common built-ins, including JSON, RegExp, URL, Date, byte arrays, ReadonlyMap, and ReadonlySet. Effect-specific HashMap, HashSet, Chunk, Graph, BigDecimal, and date-time declarations keep local generation Links, while declarations with productive canonical codecs require no arbitrary-specific annotation. Schema.isUniqueKey provides key-based Map uniqueness for explicit array representations.

    The same ownership policy applies to formatter and equivalence derivation: implementations for common declarations live in their compiler, while domain-specific and dynamically constructed declarations retain local annotations. Declarations whose intrinsic Equal implementation already matches their Schema equivalence need no annotation or compiler special case. This keeps unused common callbacks out of production Schema bundles.

    Against the previous layout, schema-toArbitrary decreases from 36.68 KB to 33.24 KB gzip and arbitrary-combinators decreases from 37.16 KB to 33.70 KB. schema-toFormatter increases from 18.92 KB to 19.49 KB and schema-toEquivalence increases from 19.05 KB to 19.39 KB because callers that explicitly derive these capabilities now retain the common declaration handlers. Generic production fixtures remain unchanged; an equivalence-specific production fixture using common declarations decreases from 20.75 KB to 20.48 KB, while declarations whose intrinsic equality is sufficient decrease from 23.42 KB to 23.34 KB. An Arbitrary-specific production fixture using common declarations decreases from 20.35 KB to 19.61 KB, while one using the locally annotated BigDecimal and date-time declarations increases from 18.34 KB to 23.01 KB. The complete 31-scenario native Arbitrary comparison reports no statistically classified runtime regression; the five moved BigDecimal and date-time scenarios remain within measurement noise.

    Add SchemaGetter.forbiddenEncoding, a reusable getter for the encode side of decode-only Schema transformations.

    Remove the fast-check bridge from the effect package, including Schema.toArbitrary and effect/testing/FastCheck. Replace the legacy Schema.Annotations.ToArbitrary callback contract with the native Schema-first types. The effect package no longer depends on fast-check.

    Migrate TestSchema.Asserts.verifyLosslessTransformation and TestSchema.Asserts.arbitrary().verifyGeneration to the native runner. Both methods now accept native check options directly, bound unsuccessful generation, and include the shrunk input and replay token in property failures.

    Use the Arbitrary runner for all @effect/vitest property tests. Property inputs may combine Schemas and Arbitraries, and are composed directly with Arbitrary.all; check options are available through arbitrary. Raw fast-check arbitraries and the fastCheck options object are no longer supported. As with the previous fast-check adapter, thrown exceptions, defects, and typed failures from a property are shrinkable falsifications; Effect interruption remains an interruption.

    Optimize constructive regular-expression generation by caching feasible lengths on the compiled pattern, computing sequence-suffix feasibility once, and precomputing character-class metadata. Seeded generation, shrinking, and replay remain unchanged.

    Optimize BigDecimal.Order and BigDecimal.Equivalence with a shared hybrid comparator. Ordinary scale differences use cached, bounded coefficient alignment, while large differences are compared without materializing their decimal zeroes. BigDecimal.make now rejects scales that are not safe integers.

    Before its removal, the materialized fast-check bridge fixture schema-toArbitrary-materialized-fast-check.ts measured 79.00 KB minified and gzipped.

    Representative runtime measurements against corresponding hand-written fast-check 4.9.0 arbitraries are shown below. Values are median latency on Node 24.12.0 and Apple M3; lower is better. Both implementations validate the same output domains, although their generation distributions are not identical. Native speedup is fast-check latency divided by Native latency, so higher is better.

    Scenariofast-checkNativeNative speedup
    32 recursive samples150 µs103 µs1.45x
    128 optional Struct samples244 µs86.0 µs2.84x
    128 constrained strings742 µs49.7 µs14.86x
    RegExp derivation and first sample13.4 ms30.8 µs429.02x
    64 RegExp strings595 µs919 µs0.64x
    RegExp failure and shrinking168 µs88.2 µs1.91x
    128 bounded numbers68.9 µs21.8 µs3.18x
    128 Uint8Array samples98.3 µs74.4 µs1.32x
    128 BigDecimal samples66.6 µs56.3 µs1.18x
    128 DateTime.Utc samples71.2 µs50.5 µs1.42x
    128 named time zones52.2 µs27.9 µs1.85x
    128 time zones63.7 µs33.8 µs1.89x
    128 zoned date-times130 µs112 µs1.16x
    32 samples through Schema filter65.9 µs49.4 µs1.33x
    32 unique arrays156 µs132 µs1.18x
    128 literal samples40.0 µs3.70 µs10.78x
    128 mapped samples59.0 µs14.1 µs4.21x
    128 samples through passing filter58.9 µs13.9 µs4.23x
    32 samples through selective filter66.1 µs42.9 µs1.54x
    128 filterMap samples75.7 µs31.5 µs2.40x
    Filtered failure and shrinking12.7 µs7.71 µs1.66x
    128 all tuple samples43.5 µs18.5 µs2.35x
    128 all record samples81.0 µs30.4 µs2.66x
    128 dependent flatMap samples125 µs67.2 µs1.86x
    flatMap failure and shrinking20.1 µs6.71 µs2.99x
    Replay flatMap shrink path14.3 µs6.57 µs2.17x
    Passing property, 100 runs42.3 µs27.1 µs1.56x
    TestSchema, 100 generations44.5 µs35.9 µs1.24x
    First failure plus one shrink8.77 µs1.30 µs6.75x
    Replay recorded failure6.35 µs1.19 µs5.36x

    Cold recursive derivation is not included because the native fixture constructs and compiles a Schema, while the fast-check fixture constructs a hand-written arbitrary; it is not a like-for-like warm-generator comparison.

    Add a guide for the native module and a migration guide from the fast-check bridge published in effect@4.0.0-rc.109.

  • #7822 b845b18 Thanks @tim-smart! - Add Stream.catchDefect and Channel.catchDefect for recovering from defects without catching typed failures or interruptions.

  • #7657 381b794 Thanks @kitlangton! - Remove Channel.runDone; use Channel.runDrain to consume all output and return the completion value.

  • #7989 4ffcaf4 Thanks @kitlangton! - Preserve astral Unicode escapes and following arguments in ChildProcess.make and ChildProcess.prefix template literals.

  • #8018 ba2fd82 Thanks @tim-smart! - Wait for Node child process groups to exit during scoped release and kill.

    After signalling a process group, both operations now wait for its leader and descendants. Without forceKillAfter, the wait is limited to one second and never escalates. With forceKillAfter, the group receives SIGKILL at the deadline, followed by a final wait of up to one second. Native timers keep escalation working under a TestClock, and cleanup no longer depends on stdio closing.

    exitCode and isRunning remain tied to the leader’s exit, and a leader that already exited successfully still leaves its group untouched. Process group checks count zombies, so cleanup may wait for the full bound under a non-reaping PID 1.

  • #7617 02be94c Thanks @kitlangton! - Fix Chunk concatenation to preserve sliced elements.

  • #7453 115d8c2 Thanks @gcanti! - Rename the built-in Config constructors to PascalCase and rename Config.mapOrFail to Config.mapEffect. Config.Array and Config.Record now construct configs directly, with overloads for pathless options or a path followed by options, while their specialized schemas and the other built-in schemas are kept internal.

    This is a breaking naming cleanup for the Effect 4 release candidate. It makes casing consistently identify typed config constructors, aligns effectful mapping with the rest of the library, and prevents implementation schemas from expanding the public Config interface.

  • #8020 1452635 Thanks @kitlangton! - Ensure Effect.acquireUseRelease releases an acquired resource and Effect.useSpan ends its span when the use callback throws before returning an effect. The thrown exception remains a defect, but no longer skips cleanup.

  • #8087 77f85fe Thanks @tim-smart! - use new instantiation for streams

  • #7802 a3f2b31 Thanks @kitlangton! - Preserve flags and nested commands when completing a CLI subcommand through its alias.

  • #7804 310f8d3 Thanks @kitlangton! - Include inherited shared flags in descendant CLI completions.

  • #8086 291d616 Thanks @MaxFreedomPollard! - Allow = in values parsed by Primitive.keyValuePair, Flag.keyValuePair, and Param.keyValuePair in effect/unstable/cli.

  • #7687 48dbbb2 Thanks @kitlangton! - Allow optional alternative CLI flags.

  • #8121 b43bfd6 Thanks @tim-smart! - Rename CLI constructors to PascalCase, aligning scalar names with Schema and Config. This is a breaking change; parsing behavior is unchanged.

    In Primitive, Param, Flag, and Argument, capitalize existing constructor names, with these exceptions:

    PreviousNewModules
    integerIntAll four
    floatFiniteAll four
    noneNeverAll four
    choiceLiteralsParam, Flag, Argument

    Primitive.choice becomes Primitive.Choice; choiceWithValue becomes ChoiceWithValue where available.

    In Prompt, capitalize control constructors except textString, integerInt, and floatNumber. Rename public types IntegerOptionsIntOptions and FloatOptionsNumberOptions. Shared TextOptions is unchanged. Prompt.Number retains its existing parser, without a finite-number restriction.

    In GlobalFlag, rename actionAction and settingSetting. Factories and combinators, including Command.make and Prompt.succeed, keep their names.

    Update public _tag matches and completion descriptors:

    • Primitive: "Integer""Int", "Float""Finite", "None""Never".
    • Completions.FlagType and Completions.ArgumentType: "Integer""Int", "Float""Finite".

    Sentinels still always fail; their internal parameter name is now "__never__". Help labels and completion scripts are unchanged.

  • #7685 1c89c78 Thanks @kitlangton! - Fix defaulted variadic arguments when omitted.

  • #8059 9bbe1a5 Thanks @kitlangton! - Fix CLI wizard handling of negative numbers and other flag values beginning with -.

  • #7489 dd99ab0 Thanks @tim-smart! - Cluster no longer retains fiber ids for every local teardown.

    Transient persisted interrupts are now classified from live teardown state (entity, shard, singleton, entity type, and node shutdown) instead of a process-lifetime set of fiber ids. The registry is bounded by in-flight teardowns and returns to baseline after entity reap storms.

  • #7939 8f397ed Thanks @kitlangton! - Fix Reply.Reply codecs to require client services when decoding and server services when encoding.

  • #7485 d7ae6b6 Thanks @tim-smart! - Transient routing states for persisted cluster messages no longer surface as errors.

    If an entity moves runners or is shut down before replying, the caller keeps waiting for the reply via message storage while the entity moves. If the local runner is shutting down while a caller is waiting, the call is interrupted instead of failing with EntityNotAssignedToRunner: the request is already durable and will be served under the next owner.

    Durable workflows treat such an interrupt as an abandoned run attempt: the run stops with nothing persisted, without running compensations or resuming the parent, ready to replay on the replacement runner.

  • #7933 8cf1203 Thanks @kitlangton! - Fix saved curried Context.get calls incorrectly inferring their required service as unknown.

  • #8064 87654c5 Thanks @Avaq! - Fix the CookiesError tag in effect/unstable/http from CookieError to CookiesError to match the class name.

  • #7621 f05ae0b Thanks @kitlangton! - Apply DateTime calendar parts without intermediate overflow.

  • #7884 436f5eb Thanks @kitlangton! - Fix ConfigProvider.fromDotEnvContents variable expansion to preserve replacement tokens such as $& in referenced values.

  • #7840 d8ff960 Thanks @kitlangton! - Fix DurableClock.sleep to preserve explicit 0 and 0n in-memory thresholds.

  • #7941 8766475 Thanks @kitlangton! - Require schema encoding services when DurableDeferred.into records an exit.

  • #7750 b64f406 Thanks @kitlangton! - Update dynamic tools to advertise replacement parameter schemas after setParameters.

  • #7572 4697aaa Thanks @tim-smart! - Align CLI help tables by terminal display width for wide, emoji, combining, and zero-width graphemes.

  • #7588 cec6c2d Thanks @tim-smart! - Route tool call parameter validation failures through the tool’s failureMode and drop ToolParameterValidationError.toolParams.

  • #7643 9956f0e Thanks @tim-smart! - Reduce memory usage in Effect primitives and fibers.

    Breaking: context-derived Fiber fields now live under fiber.cache. The currentScheduler, currentSpan, currentLogLevel, currentStackFrame, and currentPreventYield fields are now scheduler, span, logLevel, stackFrame, and preventYield. Access minimumLogLevel and maxOpsBeforeYield through cache as well.

  • #7650 5c7eed0 Thanks @tim-smart! - Reduce HTTP server allocation churn when tracing is not configured and for requests that complete synchronously.

  • #7649 183c2ea Thanks @tim-smart! - Reduce per-request RPC server allocations.

  • #7772 1e92dbd Thanks @tim-smart! - Improve HTTP server throughput by reducing routing, request handling, response construction, and body encoding overhead. Add Effect.withFiberSucceed for synchronously computing successful values from the current fiber. Copy pooled byte views by their exact range when exposing ArrayBuffer values.

  • #7956 4eb0fa7 Thanks @tim-smart! - Reduce HTTP server overhead: complete freshly created header maps in place in HttpServerResponse.setHeader and setHeaders, compare static route prefixes with a prepared startsWith, map HttpApi schema errors eagerly for completed decoder results, and implement Effect.cached as a dedicated one-time memo without time-to-live machinery.

  • #7426 534b8b9 Thanks @tim-smart! - Replace @effect/sql-pg’s pg runtime with a native PostgreSQL client. PgConnection and PgPool now handle connection setup, binary queries, prepared statements, pipelining, streaming, notifications, cancellation, and custom codecs. PgConnection.listen and PgClient.listen return scoped notification dequeues after PostgreSQL confirms the subscription. PgClient uses the native stack, and the legacy fromPool, fromClient, and makeWith constructors are removed.

    Breaking changes

    • fromPool, fromClient, and makeWith are removed. Use make for a pool or makeClient for one connection.
    • PgClient.listen returns a scoped Effect<Dequeue<string>, SqlError, Scope> instead of a Stream. Acquisition completes after PostgreSQL confirms LISTEN, so notifications sent after it returns cannot be missed.
    • PgClientConfig.types now accepts a PgTypes.Registry instead of pg.CustomTypesConfig. Plain object parameters are no longer inferred as JSON; wrap them with sql.json.
    • Query strings must contain one statement. PostgreSQL’s extended protocol rejects multi-statement strings.
    • Results use the native binary codecs. In particular, int8 decodes to bigint, date to a string, timestamps to Unix epoch milliseconds, and bytea or unknown OIDs to Uint8Array. executeRaw returns the native PgConnection.Result shape rather than pg.Result.
    • Named prepared statements are enabled by default. Set prepare: false when using a pooler that cannot preserve prepared statements between queries. Statement.unprepared and Statement.valuesUnprepared use unnamed extended queries without adding entries to the prepared-statement cache.

    Inferred parameters stay permissive: strings bind untyped so the backend derives the type from the statement, and safe integers beyond the int4 range bind as int8.

    Add Pool.reserve for exclusive access to a concurrent pool item, and fix waiter wakeups and capacity replacement after invalidation.

  • #7514 b76a1cf Thanks @tim-smart! - Add Socket.upgrade, for upgrading tcp sockets using STARTTLS

  • #7568 acc1e53 Thanks @tim-smart! - Normalize core service and runtime identities under their owning module namespaces.

  • #8001 4950a91 Thanks @kitlangton! - Fix Effect.fnUntracedEager to pass the original function arguments to each transform after the current effect, matching Effect.fn and Effect.fnUntraced.

  • #8005 c020987 Thanks @kitlangton! - Fix Effect.updateServiceScoped cleanup when an inner service provider has already completed. Closing the scope now preserves the service’s absence instead of failing with a missing-service defect.

  • #8007 abe95d1 Thanks @kitlangton! - Preserve the original cause in Effect.catchReason and Effect.catchReasons when no nested reason matches and no fallback is provided.

  • #7915 027ceb9 Thanks @kitlangton! - Fix Effectable.Class evaluation by delegating to its abstract asEffect() method. The method is called on the instance for each execution, preserving current receiver state and provided services.

  • #7907 3d203b7 Thanks @KhraksMamtsov! - Add Effectable.Mixin to insert the Effect prototype into an existing class inheritance chain. The returned abstract class requires an asEffect method and derives its Effect type from that method through polymorphic this.

  • #8009 a29b8f4 Thanks @kitlangton! - Fix the onError and onSyncError argument tuple types in Effect.effectify to include only caller inputs, excluding the synthesized callback. Mapper annotations that expected a callback slot must use the caller-input tuple instead. Runtime behavior is unchanged.

  • #7902 ce4aa65 Thanks @kitlangton! - Fix EntityProxyServer handler layers to include client-side codec service requirements.

  • #7889 a8ea807 Thanks @kitlangton! - Honor the entity layer’s disableFatalDefects option in Entity.makeTestClient. When enabled, a handler defect no longer fails other pending calls to the same entity ID. The failing call still reports its defect; omitted or false options retain fatal-defect behavior.

  • #7862 a3ebb7f Thanks @kitlangton! - Retry EventLogRemote writes and change streams when authentication returns Forbidden.

  • #7842 473bd81 Thanks @kitlangton! - Return one empty chunk when ChunkedMessage.split receives an empty Uint8Array.

  • #7525 53843f6 Thanks @fubhy! - Add ByteSize module and use it across the ecosystem

  • #8115 c5eca65 Thanks @tim-smart! - Calculate HttpBody.file, HttpBody.fileFromInfo, and HttpClientRequest.bodyFile content lengths with exact bigint arithmetic and EOF clamping.

  • #7784 d6f9eba Thanks @kitlangton! - Ensure ExecutionPlan.captureRequirements provides captured services to effectful while predicates.

  • #7460 8d1e97a Thanks @tim-smart! - Fix contextual typing for Match tag and discriminator handler maps when handlers use Effect.fn or Effect.fnUntraced.

  • #8070 b28ab48 Thanks @tim-smart! - Fix parallel child workflows inside activities to dispatch before suspending, release activity resources during durable waits, and resume reliably when children complete during cleanup.

  • #7677 9960708 Thanks @kitlangton! - Set duplex for raw Web stream request bodies in FetchHttpClient.

  • #7615 8ac53b6 Thanks @kitlangton! - Fix FiberMap losing track of fibers started under the same key by a replaced fiber’s synchronous finalizer, ensuring they are interrupted when the map’s scope closes.

  • #7967 84ad49a Thanks @kitlangton! - Preserve an already registered fiber when FiberHandle or FiberMap registers it again with onlyIfMissing: true, instead of interrupting it and clearing the entry.

  • #8083 72cfa24 Thanks @nikelborm! - Exposed the platform specific pretty loggers separately.

  • #7788 95c2581 Thanks @kitlangton! - Fix FileSystem.sink to retain its default write flag when flag is undefined.

  • #8074 d5c7cd2 Thanks @nikelborm! - Removed unused stderr option from Logger.consolePretty signature

  • #7965 fe4fed1 Thanks @kitlangton! - Match AtomHttpApi query and mutation success types to the generated HTTP client, including SSE, binary streams, and header-wrapped responses. Stream transport, decoding, and SSE errors now appear in the stream’s error channel instead of never, so code that assumed a failure-free stream may need to handle them. Runtime and serialization behavior are unchanged.

  • #7959 d150a64 Thanks @kitlangton! - Fix AtomHttpApi query and mutation dispatch for top-level API groups.

  • #7961 05b1e80 Thanks @kitlangton! - Honor explicit timeToLive: 0 and timeToLive: 0n in AtomRpc and AtomHttpApi queries. Zero now opts out of the registry’s default idle retention, matching other zero-duration inputs, so an unmounted query can be disposed and fetched again on remount. Omitting timeToLive still uses the registry default.

  • #7963 414dc90 Thanks @kitlangton! - Fix AtomRpc mutation and query atoms to include client middleware errors in their result error types.

  • #7740 3f51acd Thanks @kitlangton! - Forward Atom.withFallback writes to the primary atom.

  • #7693 d68ff05 Thanks @kitlangton! - Fix HttpMiddleware.cors to preserve Origin and other required Vary dimensions.

  • #8140 f3cf1e6 Thanks @gcanti! - Fix Types.DeepMutable to preserve built-in objects, Effect data types, and other objects with methods or symbol-keyed properties while recursively making arrays, tuples, maps, sets, and plain records mutable.

  • #7695 6525771 Thanks @kitlangton! - Use body status and encoding defaults in HttpApiSchema.encodeToWithHeaders.

  • #8110 4ab4e83 Thanks @tim-smart! - Prevent precision loss in Node/Bun filesystem operations and HttpPlatform file responses.

  • #8111 f7f1d78 Thanks @tim-smart! - Clamp HttpPlatform file response ranges to the file size so Content-Length matches the bytes available. Oversized reads stop at EOF, and offsets at or past EOF return an empty body with Content-Length 0. Apply the same clamping to the default Web file response implementation.

  • #7699 47b358a Thanks @kitlangton! - Fix HttpApiClient decoding form-urlencoded responses.

  • #7705 45ffa72 Thanks @kitlangton! - Run registered pre-response handlers before HttpApiTest returns responses.

  • #7701 6232650 Thanks @kitlangton! - Fix HttpApiClient.urlBuilder dropping base URL pathnames.

  • #7661 4b73e1b Thanks @kitlangton! - Add JsonPointer.parseUriFragment and JsonPointer.formatUriFragment for converting RFC 6901 URI fragments, and use them to preserve percent-encoded definition names in exported JSON Schema references. JSON Schema compilation now rejects malformed local definition references returned by toJsonSchema hooks. Such hooks must percent-encode characters that URI fragments do not permit, for example % as %25 and # as %23.

  • #7675 284050c Thanks @kitlangton! - Normalize MIME type parameters and whitespace in Mime.getAllExtensions.

  • #8108 c85fc0b Thanks @tim-smart! - On Node and Deno, FileSystem.File.seek now rejects negative resulting positions with a BadArgument platform error, leaving the cursor unchanged. Its return type is now Effect<bigint, PlatformError>.

  • #8148 7999b07 Thanks @tim-smart! - Preserve the response Content-Type when compressing file, raw, stream, and byte-array responses on Node, Bun, Deno, and the web platform, including headers overridden after body construction.

  • #7703 7d455f5 Thanks @kitlangton! - Apply endpoint OpenAPI overrides and transforms after schema generation.

  • #8057 d681c2e Thanks @kitlangton! - Fix Prompt.date carrying typed digits into the next field when pressing Tab, including when navigation wraps.

  • #7742 84d2a47 Thanks @kitlangton! - Prevent Reactivity.query cleanup from failing when keys are repeated.

  • #7659 ed74b18 Thanks @kitlangton! - Preserve pending leftovers when a Sink.flatMap continuation completes without consuming input.

  • #7671 2245997 Thanks @kitlangton! - Preserve SSE events with mixed line endings.

  • #7691 d386979 Thanks @kitlangton! - Ignore Range headers on non-GET requests in HttpStaticServer.

  • #8109 fc9fedf Thanks @tim-smart! - Parse HttpStaticServer byte range integers exactly, including values above Number.MAX_SAFE_INTEGER. Oversized starts now return 416 with Content-Range instead of falling back to 200. Oversized ends clamp to the last byte, and oversized suffixes return the whole file as 206.

  • #7697 7750dbe Thanks @kitlangton! - Fix HttpApiBuilder ignoring the status annotation on a HttpApiSchema.WithHeaders wrapper around a streaming success, which defected when the wrapper and inner statuses differed.

  • #7667 fc91af6 Thanks @kitlangton! - Fix Toml.parse rejecting child tables in separate array-of-tables entries.

  • #8106 39b9738 Thanks @tim-smart! - Fix tool result serialization to select the codec using isFailure and preserve encodedResult through Response.AllParts round trips.

    Add Tool.failureResultSchema(tool) and Tool.ExecutionFailure to handle user failures, AiError, and denied or interrupted calls consistently. Also export HttpRequestDetails and HttpResponseDetails from AiError; the Response exports remain available.

    Breaking changes

    • Stored results must match the selected schema. With success Schema.Number and failure Schema.NumberFromString, migrate failed results from 404 to "404".
    • Response.ToolResultPart returns Schema.Codec instead of Schema.decodeTo. Update annotations that depend on the old type.
    • Tool.FailureResult and Tool.Result, including their encoded variants, now include Tool.ExecutionFailure in both failure modes. Handle it when narrowing failed results.
  • #8132 88093b5 Thanks @LeonardoTrapani! - Fix activity count leaks when workflow activity acquisition is interrupted, which could block later workflow suspension.

  • #7669 d14c463 Thanks @kitlangton! - Fix folded YAML scalars to preserve paragraph and indentation breaks.

  • #7872 d473bd3 Thanks @kitlangton! - Preserve defined falsy Error causes (0, false, "", null, 0n, and NaN) in Formatter.format output. Missing and explicitly undefined causes remain omitted.

  • #7451 84864bc Thanks @gcanti! - Fix equivalence derivation for schema class APIs by adopting the equivalence of their declared fields. Class declarations previously fell back to Equal.equals, which also compared runtime properties outside the schema and could make field-equivalent class instances compare as unequal.

  • #7920 e2ae724 Thanks @kitlangton! - Fix Graph.bellmanFord reporting a negative cycle as affecting a target across an impassable, positive-infinite-weight edge. Targets separated from the cycle by such edges now retain their finite shortest path or remain unreachable, while targets reachable from the cycle through finite-weight edges still report an error.

  • #7625 f921ed3 Thanks @kitlangton! - Prevent HashMap iterators from exposing mutable internal collision entries.

  • #7886 1df933d Thanks @kitlangton! - Fix HashRing.getShards skipping an eligible node at the first ring position when other nodes have reached their allocation quota.

  • #7629 829aff9 Thanks @kitlangton! - Compare header names case-insensitively in Headers.isRedactedName.

  • #7627 aa0aba3 Thanks @kitlangton! - Fix Headers.redact and Headers.isRedactedName skipping matches when a redaction pattern is a global or sticky regular expression.

  • #7945 a71140f Thanks @kitlangton! - Constrain the data-first HttpClient.catch(client, recover) overload to recover with HttpClientResponse values, matching the data-last overload. Callbacks returning other success types are now rejected; use Effect.catch on the result of client.execute(request) to recover to arbitrary values.

  • #7922 0276a27 Thanks @kitlangton! - Fix HttpClient.followRedirects bypassing response-level recovery when request preprocessing fails.

  • #8131 10d2c98 Thanks @gcanti! - Fix HttpClientResponse.schemaJson and HttpClientResponse.schemaNoBody to apply parse options when decoding response schemas.

  • #7679 c86c999 Thanks @kitlangton! - Close request scopes for streaming HEAD responses.

  • #7681 975f758 Thanks @kitlangton! - Preserve Content-Length headers in HttpServerResponse.fromWeb.

  • #7689 2a3a478 Thanks @kitlangton! - Normalize router prefixes before removing them from handler request URLs.

  • #7898 1e6e206 Thanks @kitlangton! - Fix HttpRunner HTTP and WebSocket client URLs adding an extra leading slash to slash-prefixed paths. Insert the address/path separator only when it is missing, preserving intentional leading and interior slashes.

    This path correction is normally masked by router normalization, but prevents route misses for non-root paths when duplicate-slash normalization is disabled. Applications that compensate for the extra slash may need to remove that compensation. Router defaults and shared trailing-slash handling are unchanged.

  • #7927 fa6027b Thanks @tim-smart! - Reduce cold start cost of HttpRouter and HttpEffect web handlers.

    • HttpServerRespondable no longer imports Schema to detect schema errors, which removes the Schema modules from bundles that do not otherwise use them (about 23% of a minimal HttpRouter bundle).
    • HttpRouter.toWebHandler, HttpEffect.toWebHandlerLayer and HttpEffect.toWebHandlerLayerWith now build the layer immediately instead of on the first request. A failed build never surfaces as an unhandled rejection; every request rejects with the build error instead.
  • #7561 7616f73 Thanks @jensdev! - Fix HttpApiMiddleware-declared errors being duplicated and mis-encoded.

  • #7954 fc668b6 Thanks @fitchmultz! - Allow generated HttpApiClient methods and AtomHttpApi queries and mutations to accept native SSE decode options per call through the request’s sseOptions field.

  • #7994 d425c8c Thanks @tim-smart! - Prevent unencodable atom values from aborting dehydration of the rest of an atom registry.

  • #7935 ce120f4 Thanks @kitlangton! - Fix Layer.tapError and Layer.tapCause to require observers that accept the source layer’s complete error type.

  • #7983 248201f Thanks @kitlangton! - Honor captureStackTrace in both forms of Layer.withSpan. Layer construction diagnostics previously reported a location inside Layer.ts instead of the withSpan call site, and ignored captureStackTrace: false or a supplied lazy stack.

  • #7937 e80d397 Thanks @kitlangton! - Preserve resource acquisition errors on LayerMap.Service when preload: true is set. The yielded service instance and its get, contextEffect, and contextEffectOption accessors now retain the resource error type because a resource can fail when reacquired, even if preloading succeeded.

    Consumers that assumed these accessors had a never error must handle the resource error. Runtime behavior is unchanged.

  • #7874 f1a941d Thanks @kitlangton! - Fix Logger.toFile dropping the remainder of a log batch when a successful file write writes only part of the buffer. File logging now uses the complete-write contract; write errors continue to be ignored.

  • #7814 73bc3a1 Thanks @kitlangton! - Fix McpServer HTTP resource templates failing to resolve.

  • #7816 b628bb1 Thanks @kitlangton! - Fix McpServer.registerPrompt callback types to use decoded prompt parameters.

  • #7495 6e3ae7b Thanks @IMax153! - McpServer no longer sends null or array tool results as structuredContent, which MCP requires to be a JSON object.

  • #7835 e891247 Thanks @kitlangton! - Remove queued control envelopes when clearing an address from in-memory message storage.

  • #7993 53e6c73 Thanks @kitlangton! - Ensure metrics with equal attributes share a series regardless of attribute insertion order.

  • #7991 1579d6f Thanks @kitlangton! - Fix metrics reused across different MetricRegistry services to read and update the active registry while preserving each registry’s values when revisited.

  • #7665 d3c6b73 Thanks @kitlangton! - Fix Model.FieldOption to preserve omitted variants.

  • #7987 4a59c6a Thanks @kitlangton! - Add Multipart.isStreamPart to recognize only a text Field or streamed File, while preserving Multipart.isPart for all branded multipart parts, including PersistedFile values.

  • #7519 145d8e1 Thanks @gcanti! - Fix Schema.mutable to preserve array and tuple metadata and reject node-level encodings.

  • #7776 f74282c Thanks @kitlangton! - Preserve values added to an empty MutableList by prependAll when appending more values.

  • #7571 0a38623 Thanks @tim-smart! - Export the Random.Random service interface and Metric.MetricRegistry type so custom service implementations can be annotated without accessing Context.Reference phantom types.

  • #7524 0a08ae0 Thanks @fubhy! - Add NetAddress under effect/unstable/net for MAC, IP, internet socket, and Unix socket addresses, with checked parsing, schemas, equality, canonical string serialization, and URL formatting. Companion modules IpInterface and IpNetwork represent IP interfaces and CIDR networks.

    HTTP and socket servers now expose NetAddress.SocketAddress. Replace TCP hostname access with NetAddress.formatIp(address.address) and use UnixPathAddress.path for Unix sockets. URL helpers bracket IPv6 addresses and reject scoped IPv6. Bun and Deno HTTP server layers can now fail with ServeError when listener address conversion fails.

    PostgreSQL inet values now use IpInterface; cidr values use IpNetwork and reject addresses with host bits set.

  • #7443 fa6a56b Thanks @youngspe! - Terminate the Stream.fromEventListener stream after one item if once: true.

  • #7510 d60c5d4 Thanks @gcanti! - Normalize numeric collection and batch counts across Stream, Channel, Sink, MutableList, RequestResolver, Queue, TxQueue, PubSub, and HashRing, preventing fractional, NaN, and non-positive counts from producing incorrect output, exceptions, waits for the wrong batch size, or non-terminating pulls.

  • #7910 07ffd25 Thanks @kitlangton! - Fix Number.remainder to preserve negative-zero dividends with ordinary finite divisors.

  • #7547 9b517ad Thanks @tim-smart! - Improve PersistedQueue reliability across SQL, Redis, and memory stores. Retry policy now lives on make(), attempts count on claim, retries follow a Schedule, and exhausted or undecodable elements are dead-lettered. Add retention cleanup, durable acknowledgement retries, storage schema fixes, local poll wakeups, and fixes for the memory take race and Redis dedup growth.

  • #7778 604b1c1 Thanks @kitlangton! - Ensure Optic.pick and Optic.omit delete focused optional fields omitted from a replacement.

  • #7780 ccc2e02 Thanks @kitlangton! - Fix Optic.optionalKey to splice tuple elements selected by string indices.

  • #7782 14d810a Thanks @kitlangton! - Fix Order.combineAll consuming one-shot iterables after the first comparison.

  • #7931 a9d1ee3 Thanks @tim-smart! - Fix disabled OTLP batching to skip empty exports and avoid resending buffered items.

  • #7929 a31adbe Thanks @tim-smart! - Speed up OtlpTracer span creation and export. Spans now allocate identifiers, attributes, and events lazily, and Encoding.randomHex produces flat strings for 16 and 32 character identifiers so serialization no longer flattens ropes.

  • #7584 7245f87 Thanks @kitlangton! - Fix PartitionedSemaphore leaving a new waiter suspended when a previously resumed waiter for the same partition is interrupted before its acquisition completes.

  • #7766 3a0828b Thanks @kitlangton! - Persist synchronous defects thrown by PersistedCache lookups.

  • #7604 cd83544 Thanks @kitlangton! - Keep Pool.reserve items out of shared circulation when other borrowers return or overlapping reservations close. Restore available slots only after the last reservation closes.

  • #8078 6550a07 Thanks @tim-smart! - Port HttpApiBuilder.handler from v3 to define reusable endpoint callbacks with inferred request, response, error, and service types.

  • #7663 6f090d4 Thanks @kitlangton! - Preserve schema classes when extracting their default VariantSchema variant.

  • #7760 b505c0d Thanks @kitlangton! - Preserve negative counter deltas in OTLP and OpenTelemetry metric exports.

  • #7478 186dd49 Thanks @gcanti! - Normalize numeric collection counts consistently across Array, Chunk, Iterable, and String, and make TupleOf fall back to Array for positive fractional lengths.

  • #8097 9f37e58 Thanks @tim-smart! - Keep the previous prompt frame visible until the next frame or submission is ready to display.

  • #7637 4446451 Thanks @kitlangton! - Preserve text parts and provider options when serializing prompts.

  • #7639 58be972 Thanks @kitlangton! - Preserve generated files when converting AI responses to prompts.

  • #7603 1320075 Thanks @kitlangton! - Fix capacity-one PubSub subscriber cursors after sliding past messages, including duplicate delivery and invalid state when unsubscribing from a slid message.

  • #7487 ba53b64 Thanks @tim-smart! - Redesign Socket around a scoped, pull-based reader with transport backpressure.

    Socket now exposes reader and writer. Client reader acquisition dials and yields a pull of non-empty batches: one buffer for TCP and one entry per WebSocket frame. TCP applies backpressure while paused; pausable WebSockets pause at highWaterMark (64 KiB by default) and resume after draining. Browser WebSockets cannot pause, so they can fail with SocketReadError at a configured highWaterMark. Writes await native drain signals and batch with cork / uncork where available.

    Breaking changes

    • Socket.run, Socket.runString, and Socket.runRaw are removed. Acquire socket.reader (or Socket.readerBytes / Socket.readerString) in a scope and pull in a loop. Code before the first pull replaces onOpen.
    • Socket.make now takes { reader, writer }. The writer acquisition is infallible and yields a Writer with write and writeAll; both operations can still fail with SocketError.
    • Every close fails the pull with SocketError wrapping SocketCloseError. The close-code predicates are removed; use Effect.retry around the scoped read loop to reconnect.
    • Socket.toChannel and Socket.toChannelString now read from the pull and fail on close. Socket.toStream is added for read-only consumption.
    • fromWebSocket drops the onInitialRun option; SendQueueCapacity is removed.
    • Accepted server sockets pause immediately. Their reader attaches to the existing connection and cannot reconnect after close.
  • #7806 f7490d4 Thanks @tim-smart! - Add Queue.flush and Queue.flushUnsafe for manually releasing pending takers, including after synchronous offers.

  • #7576 c8ea602 Thanks @kitlangton! - Fix Queue message duplication, capacity overruns, and consumer defects when a resumed producer synchronously uses the same queue. Zero-capacity queues now reserve each handed-off message for its consumer before resuming the producer.

  • #7498 62d82f4 Thanks @gjermundgaraba! - Allow SqlEventJournal to decode entry identifiers and payloads from SQL drivers that return BLOB values as ArrayBuffer.

  • #7644 a2c9e7c Thanks @gcanti! - Remove the redundant Graph.Proto interface. Use Graph.Graph<N, E, Graph.Kind> when accepting any immutable graph.

  • #7497 97dd022 Thanks @javascript-unsafe! - Treat NaN as a non-positive count in Stream.take.

  • #7864 f984ee8 Thanks @kitlangton! - Fix Random.nextBetween and Crypto.randomBetween returning their exclusive upper bound when floating-point arithmetic rounds up.

  • #7985 f1b2910 Thanks @kitlangton! - Report the exact remaining store lifetime in RateLimiter fixed-window resetAfter metadata when onExceeded is "delay", instead of rounding up to a whole window. Admission, returned delays, and remaining-token counts are unchanged.

  • #7516 a29e05a Thanks @kitlangton! - Fix RcMap and LayerMap cleanup after invalidating an actively borrowed entry and reacquiring the same key. The invalidated resource is released when its last borrower closes, even with infinite idle TTL, without removing the replacement entry. Old idle timers also leave replacement entries untouched.

  • #7605 1aa1d8b Thanks @kitlangton! - Fix RcMap entries getting stuck when the lookup function throws synchronously. Later borrowers now receive the defect, and unused entries are released according to their idle TTL instead of permanently consuming capacity.

  • #7598 bb99734 Thanks @kitlangton! - Keep RcRef closed when an in-flight acquisition finishes after its owning scope has closed. Release the late-acquired resource and interrupt waiting borrowers instead of making the resource available again.

  • #7586 222e7ca Thanks @kitlangton! - Prevent RcRef borrower cleanup from discarding replacement resources after invalidation or reopening a reference after its owner scope has closed.

  • #7565 797c9e3 Thanks @typedrat! - Type Cause.Reason#annotate as accepting a Context only.

  • #7461 b4d5398 Thanks @tim-smart! - Remove the MessagePack encoding and RPC serialization APIs together with the msgpackr dependency. Event-log persistence and remote messages now use SchemaBinary, and cluster transports use SchemaBinary unless NDJSON is selected explicitly.

  • #8143 c8349ed Thanks @gcanti! - Rename SchemaGetter.transformOrFail to SchemaGetter.transformEffect and SchemaTransformation.transformOrFail to SchemaTransformation.transformEffect. Replace calls to the old names with their transformEffect equivalents.

  • #8022 8426e5f Thanks @kitlangton! - Correct the Effect.repeatOrElse fallback type to expose the previous step’s Schedule.Metadata, matching the existing runtime value.

  • #7520 26e0085 Thanks @ebramanti! - Report recovered MCP toolkit failures and defects to configured ErrorReporters, including declared tool failures returned with isError: true.

  • #7583 1a86166 Thanks @kitlangton! - Fix RequestResolver.withCache retaining abandoned entries when a pending request is cancelled

  • #7613 0856631 Thanks @kitlangton! - Preserve completed results and propagate resolver failures from RequestResolver.persisted.

  • #7594 0af0985 Thanks @kitlangton! - Keep completed results in RequestResolver.withCache when a losing RequestResolver.race resolver is interrupted after the winner completes, avoiding repeated backend requests on subsequent equal lookups.

  • #7979 bc582c9 Thanks @kitlangton! - Preserve typed errors, defects, and interrupts from RequestResolver.fromEffectTagged handlers.

  • #7981 2c63f1e Thanks @kitlangton! - Fix RequestResolver.fromEffectTagged to consume handler results as an iterable, allowing arrays, iterators, and generators to resolve requests in order.

  • #8024 0d98213 Thanks @kitlangton! - Fix Types.RequiredKeys dropping named required keys on types with index signatures. Derived type annotations may need to include these keys.

  • #7496 ca6f0dc Thanks @nikhilsnayak! - Add HttpClientResponse.url, including query parameters and excluding the hash. When redirects are followed, it reports the final URL.

  • #7683 d8cc9ed Thanks @kitlangton! - Preserve zero and empty-string request IDs in JSON-RPC control messages.

  • #7930 42fd969 Thanks @tim-smart! - The default scheduler falls back to a microtask when setting a timer throws. Cloudflare Workers disallow timers in global scope, so an effect that yielded while running at module load failed with “Disallowed operation called within global scope”.

  • #7558 5641ad3 Thanks @gcanti! - Move the built-in schema revivers from Schema to SchemaRepresentation. Rename the reviver constructors to makeReviverDeclaration, makeReviverFilter, and makeReviverFilterGroup.

    Change Schema.toEncoderXml to fail with SchemaIssue.Issue directly instead of wrapping failures in SchemaError. Consumers that read error.issue should now use the error value itself.

  • #7641 629870d Thanks @kitlangton! - Preserve array-valued leaves when SchemaGetter.makeTreeRecord aggregates duplicate paths.

  • #7673 d592c14 Thanks @kitlangton! - Preserve leading U+FEFF characters in SchemaBinary string values when decoding.

  • #8131 10d2c98 Thanks @gcanti! - Align Schema construction and parsing semantics, simplify parse options, accept inherited declared fields, and move Union settings into a node-local options object.

    Breaking changes

    • Class.make, Class.makeOption, and Class.makeEffect now return an existing instance unchanged. This avoids duplicate initialization and makes the construction APIs consistent. Use new MyClass(input) when a distinct instance is required.

    • Literal(0) and Literal(-0) continue to accept either signed zero, but decoding and encoding now preserve the input sign. Add an explicit transformation when a canonical sign is required.

    • parseOptions annotations no longer affect parsing. Options passed when creating or calling a decoder, encoder, or constructor adapter now apply to the complete operation. Move operation-wide settings from annotations to the relevant parser API.

    • propertyOrder has been removed from ParseOptions because preserving input order required a separate, rarely used object reconstruction path. Schema parsing no longer guarantees that decoded object keys follow their input order. Remove the option and apply any required presentation or serialization order after parsing.

    • concurrency now applies only to product children: tuple elements, array elements, struct fields, record entries, and structs with rest. It follows Effect.forEach semantics, defaults to sequential execution, and applies independently at every nested product. Union candidates remain sequential because speculative candidate evaluation can run transformations that are not selected. Existing product parsing can keep the option. Replace code that relied on concurrent Union candidates with explicitly coordinated parser calls. With concurrent Record key transformations, completion order determines the retained value when transformed keys collide.

    • onExcessProperty: "preserve" has been removed because it allowed unvalidated values absent from the schema type to cross the parsing boundary. Model additional properties with Record or StructWithRest; "ignore" and "error" remain available.

    • Declared Struct fields may now be inherited and are copied to own properties in the output. Dynamic Record index signatures remain own-only, while finite literal record keys are declared and may be inherited. The __proto__ field remains own-only. Check ownership before parsing when every declared field must be own.

    • SchemaAST.Union.mode moved to SchemaAST.Union.options?.mode so node-local constructor settings live in one options object instead of special top-level fields. An absent value defaults to "anyOf". SchemaRepresentation.Union now serializes { options: { mode: "oneOf" } }; update direct AST access and regenerate or migrate persisted representation documents. The public Schema.Union(members, { mode }) call is unchanged.

  • #8147 53909a9 Thanks @gcanti! - JSON Schema generation now follows the canonical JSON codec more closely and leaves unmodeled object properties open by default, matching Effect decoding.

    Breaking changes

    Schema.ToJsonSchemaOptions.additionalProperties has been replaced by onExcessProperty:

    • Replace { additionalProperties: true } with { onExcessProperty: "ignore" }.
    • Replace { additionalProperties: false } with { onExcessProperty: "error" }.
    • Replace a schema-valued additionalProperties option with Schema.Record or Schema.StructWithRest.

    Schema.Enum now rejects non-finite numeric members. Schema.isMultipleOf now rejects zero and non-finite divisors, and normalizes negative divisors.

    Generation is more accurate for index signatures, empty structs, template literal alternatives, capitalized strings, and unique symbols. Conjunctive index keys remain open by default; onExcessProperty: "error" constrains them with propertyNames.

  • #7606 78a4269 Thanks @kitlangton! - Fix ScopedCache.invalidateAll discarding entries created by reentrant resource finalizers without releasing them. Entries are now removed before their finalizers run, so replacement resources remain cached and are released when the cache closes.

  • #7612 06c6307 Thanks @kitlangton! - Capture synchronous defects thrown by ScopedCache.refresh lookup callbacks.

  • #8026 0847c41 Thanks @kitlangton! - Fix Effect.annotateLogsScoped to restore or remove unchanged NaN annotations when the scope closes.

  • #8155 5a77084 Thanks @tim-smart! - Use branded interfaces for Reactivity, LanguageModel, EmbeddingModel, and Chat. Refer to each service’s same-name type instead of .Service or ["Service"]; custom implementations must include [TypeId]: TypeId.

  • #7913 96f99b3 Thanks @Hoishin! - Fix HttpRouter nested prefixed application order

  • #7906 7bb8781 Thanks @kitlangton! - Honor services explicitly supplied when registering cluster entities while retaining construction-context services as fallbacks.

  • #8114 4907e9b Thanks @tim-smart! - Skip optional stack capture when Error.stackTraceLimit is zero.

  • #8090 2a30248 Thanks @tim-smart! - Reduce the basic Effect bundle size by keeping cause deduplication local, making encoding lookup tables tree-shakeable, removing redundant cause field declarations, and simplifying primitive hash dispatch without changing hash values.

  • #7825 8364ddd Thanks @kitlangton! - Resume paused WebSockets after their readers take ownership.

  • #7827 ad67d8c Thanks @kitlangton! - Count buffered WebSocket text frames by their UTF-8 byte length when enforcing highWaterMark.

  • #7798 ec0c087 Thanks @kitlangton! - Emit CR-terminated lines from Stream.splitLines without pulling upstream again.

  • #7443 fa6a56b Thanks @youngspe! - Loosen Stream.addEventListener type parameter

  • #7844 a2c1ce6 Thanks @kitlangton! - Preserve callback error identity in SqlEventJournal.write and SqlEventJournal.withRemoteUncommited.

  • #7837 91e9af0 Thanks @kitlangton! - Preserve reply IDs in SQL-backed MessageStorage.unprocessedMessagesById reads.

  • #7635 7bd3f34 Thanks @kitlangton! - Fix placeholder numbering for cached fragments used in returning helpers.

  • #7493 ef16581 Thanks @utopyin! - Add Statement.SpanPropagationEnabled to scope driver span parenting under sql.execute for any SQL client. Disabled by default.

    import { Effect } from "effect"
    import { Statement } from "effect/unstable/sql"
    query.pipe(Effect.provideService(Statement.SpanPropagationEnabled, true))
  • #7633 1693a87 Thanks @kitlangton! - Fix SQL returning helpers to compile identifiers with dialect-specific escaping.

  • #7860 df3fc47 Thanks @kitlangton! - Ensure PostgreSQL shard acquisition and refresh return only the requested shards.

  • #7904 e11be41 Thanks @kitlangton! - Include the model’s decoding services in the public requirements of SqlModel.makeResolvers().insert, alongside its existing input-encoding services.

    This intentionally tightens compile-time checking: previously accepted callers must now provide the services already needed to decode inserted rows at runtime. Provide those services when executing the insert with SqlResolver.request. insertVoid still requires only input-encoding services, and service-free models need no changes. Runtime behavior is unchanged.

  • #7655 2e39e8b Thanks @kitlangton! - Fix Stream.rechunk failing on large source chunks.

  • #7538 11c5ee7 Thanks @gwagjiug! - Parse Content-Length metadata strictly across HTTP modules, ignoring malformed or unsafe values instead of coercing them.

  • #7522 1742d2f Thanks @gwagjiug! - Ignore Set-Cookie headers whose cookie names do not satisfy the RFC 6265 token syntax.

  • #7619 8efc70e Thanks @kitlangton! - Honor numeric property selectors in Struct selection and mapping utilities.

  • #7560 9642776 Thanks @gcanti! - Expose SchemaAST nodes, SchemaIssue nodes, SchemaGetter.Getter, and the SchemaTransformation models through structural instance interfaces instead of concrete class declarations. The constructors remain usable with new and instanceof, but their prototype is no longer part of the public TypeScript API. Replace type-level access through a constructor’s prototype with the corresponding named instance interface, such as SchemaGetter.Getter<T, E, R>.

    SchemaAST.Base is no longer exported. Use SchemaAST.AST when accepting any AST node, and use the SchemaAST.is* guards to narrow individual variants.

  • #7790 6680828 Thanks @kitlangton! - Fix the curried SynchronizedRef.modifySomeEffect overload to accept only the callback, matching its runtime behavior.

  • #7569 c34edcb Thanks @tim-smart! - Stop declaring SynchronizedRef as a subtype of Ref, preventing Ref combinators from accepting values that do not implement the required runtime representation.

  • #8012 7b2c5bd Thanks @kitlangton! - Preserve the source error type when a saved Effect.tapDefect operator is applied. The source error is now inferred from each application instead of when the operator is created. Runtime behavior is unchanged.

  • #7427 1a2ccee Thanks @tim-smart! - Use SchemaBinary as the default RPC serialization for TCP cluster connections, including configurable frame limits.

    Cluster payloads are encoded with the binary codec on the wire. When a persisted reply cannot be encoded for JSON storage, the defect fallback that storage records is now also the reply delivered to waiting callers, so live replies always match what was persisted.

    SchemaBinary codecs are memoized by schema identity and wire mode, so per-message codec requests reuse the derived codec instead of rebuilding it.

  • #8094 db995df Thanks @gcanti! - Separate template literal validation from transformed tuple parsing. TemplateLiteralParser now propagates its parts’ decoding and encoding service requirements.

    Breaking changes

    Schema.TemplateLiteral and SchemaAST.TemplateLiteral now throw during construction when a part contains an encoding, including inside unions and nested templates. This also rejects transformations whose decoded and encoded types are equal. Brands and supported checks without encodings remain valid.

    Use Schema.Literals([0, 1]) to describe bit spellings or Schema.Finite to describe finite numeric spellings. Use Schema.TemplateLiteralParser when you need to decode transformed parts into a tuple. Explicit Schema.toType or Schema.toEncoded projections can remove an encoding, but do not necessarily preserve the strings accepted by the old template. For example, a Finite part rejects the empty segment accepted by FiniteFromString.

    Schema.toEncoded(Schema.TemplateLiteralParser(...)) now validates the structure of the template instead of accepting any string. Use Schema.String when unrestricted strings are intended.

    When parser parts require services, provide those services to the corresponding decoding or encoding effect. These requirements were previously omitted from the parser’s types.

  • #7870 af0ccdd Thanks @kitlangton! - Fix TestSchema.Asserts.ast.fields.equals to compare ASTs for all own struct fields, including symbol and non-enumerable keys. Equivalent field schemas now compare equally regardless of schema instance identity, while differing ASTs and distinct symbol keys remain unequal.

  • #8127 addeaea Thanks @tim-smart! - dispatch websocket events directly

  • #7448 7704034 Thanks @candrewlee14! - Fix response tool part assignability after narrowing generic intersected tool records.

  • #7486 e72b12f Thanks @tim-smart! - Make automatic tool resolution interruption-safe for incomplete language model responses.

  • #7481 310dd9c Thanks @jpenilla! - Restore the Effect.timeout error message so TimeoutError includes the elapsed duration.

  • #8032 1c2afc1 Thanks @kitlangton! - Fix Effect.timeoutOrElse to finish interrupting the source before evaluating the fallback, preventing the source from winning after the timeout.

    Fallbacks now run in the caller fiber and inherit its interruptibility and supervision.

  • #8103 44f44ca Thanks @tim-smart! - Fix token-bucket retryAfter, delay and resetAfter in the memory and Redis stores. Timing now follows whole-token refill boundaries and accounts for elapsed time, including fractional token costs. Redis preserves signed fractional counts and keeps keys until capacity actually refills.

    RateLimiterStore.tokenBucket now returns [remaining, elapsedMillis] instead of remaining. Custom stores must return both values from the same atomic operation; see the tokenBucket docs for the contract. Returning [remaining, 0] keeps the old timing bug.

  • #7912 f43b9d6 Thanks @kitlangton! - Fix Tokenizer.truncate to account for token costs between messages.

  • #7748 56e72b3 Thanks @kitlangton! - Encode tool results with the schema for their known success or failure branch.

  • #8030 50ef80e Thanks @kitlangton! - Fix Effect.track(metric, mapper) to reject source errors the mapper cannot handle.

  • #7774 fc3b718 Thanks @kitlangton! - Preserve valued prefix nodes when removing a longer key from a Trie.

  • #8016 ee336d8 Thanks @kitlangton! - Correct the error types of Effect.try and Effect.tryPromise. Direct function forms retain Cause.UnknownError, while { try, catch } options use the error type returned by catch.

    Explicit two-generic direct calls, union-valued arguments, and generic aliases that combine the two forms no longer compile. Use { try, catch } with a real error mapper, or narrow a union before calling the constructor.

    Runtime behavior, callback arguments, and error mapping are unchanged.

  • #7924 d12f922 Thanks @kitlangton! - Correct Tuple.evolve result types when a transform may be undefined. The result now includes both the transformed and unchanged element types, matching the existing runtime behavior. Accepted inputs and runtime behavior are unchanged.

    Code relying on the previous, incorrect result type must handle both outcomes. For example, a number-to-string transform that may be absent now produces number | string, so callers assuming a number-only result must adjust.

  • #7553 46d8310 Thanks @tim-smart! - Move the Cookie, Cookies, Headers, and UrlParams schemas from effect/unstable/http to effect/Schema, including their record and JSON-field helper schemas.

  • #7623 59812fd Thanks @kitlangton! - Fix UrlParams.fromInput to stringify null values.

  • #7631 f9d0dec Thanks @kitlangton! - Prevent UrlParams.setAll from mutating reusable overrides.

  • #7855 4372c79 Thanks @gcanti! - Treat only unpadded decimal integers from 0 through 4294967294 as array indices in environment-backed configuration and bracket-path decoding. This preserves numeric-looking object keys and prevents out-of-range environment keys from producing impossible array lengths. Bracket paths that intend to address arrays must use [1] instead of [01].

  • #7551 81485ef Thanks @tim-smart! - Cluster shard-lock recovery no longer stalls behind a wedged reserved SQL connection.

    While lock storage is unhealthy, the empty liveness probe (refresh(address, [])) now runs on the shared pool instead of the reserved lock connection, so a hung reserved connection cannot block recovery. Failed probes are also logged as warnings instead of being silently swallowed.

  • #8028 bd393d6 Thanks @kitlangton! - Fix Effect.withErrorReporting to return an Effect instead of preserving input subtypes such as Exit, whose subtype-specific fields are not present on the wrapper.

  • #7570 0c95c04 Thanks @tim-smart! - Fix Worker.run hanging uninterruptibly when a worker dies before the ready handshake.

4.0.0-rc.112

Minor Changes

  • #7390 a5f78d3 Thanks @tim-smart! - Make RPC serialization schema-aware.

    Add codecFor to RPC serialization and client/server protocols so RPC and cluster network payloads use the transport’s schema codec. Framing, cluster storage, and existing built-in wire formats remain unchanged.

Patch Changes

  • #7411 20cb4f2 Thanks @altendky! - Add RcMap.getOption and LayerMap.contextEffectOption for atomically retaining entries only when they are already cached.

  • #7437 44675cb Thanks @wmaurer! - Add an optional description to AiError.AuthenticationError, rendered after the kind-based suggestion, and pass the provider’s own error text through it on HTTP 401 and 403, so authentication failures report what actually went wrong instead of only a category.

  • #7393 b6bf5e1 Thanks @wmaurer! - Fix Prompt.autoComplete swallowing j and k while typing a filter query.

  • #7401 0b9f780 Thanks @gjermundgaraba! - Retry transient EventLog remote write failures so pending local entries are synchronized after recovery.

  • #7384 150e92c Thanks @tim-smart! - Improve synchronous Schema decode and encode performance by preserving completed parser exits and using a direct loop for common struct parsers.

  • #7386 6740db2 Thanks @tim-smart! - Add Schema.TaggedUnion.matchOrElse for partial case matching with a typed fallback.

  • #7389 d57bba1 Thanks @tim-smart! - Improve SchemaError construction performance by skipping stack frame capture.

  • #7402 be75d5e Thanks @tim-smart! - Improve Pool acquisition and release performance. Pool now tracks usage incrementally, stores available items in an intrusive FIFO, and skips work for fixed and empty pools. This changes the public Pool.State and Pool.PoolItem interfaces.

  • #7402 be75d5e Thanks @tim-smart! - Add Pool.use, which borrows an item while an effect runs and returns it on any exit. Unlike Effect.scoped(Pool.get(pool)), it does not require a Scope.

  • #7402 be75d5e Thanks @tim-smart! - Reduce scoped resource acquisition allocations by storing the first Scope finalizer inline and allocating a Map only when a second is added. This changes the public Scope.State.Open interface.

  • #7424 02a5146 Thanks @tim-smart! - Skip remote event journal write callbacks when there are no uncommitted entries and return an Option indicating whether the callback ran.

  • #7312 15272a6 Thanks @godu! - Fix shell completion for choice values containing quotes, spaces, word-break characters, Unicode, and shell metacharacters.

    Bash now quotes candidates for readline, keeps choice values intact when reconstructing words, and supports Bash 3.2 without associative arrays. Fish and Zsh escape choices across both parsing rounds, and Fish hides value-taking flags after use without suppressing their value completions.

  • #7395 436f10d Thanks @wmaurer! - Fix Prompt.file swallowing j and k while typing a filter query.

  • #7406 058fb15 Thanks @gcanti! - Preserve finite string and unique symbol key unions in the return types of Array.groupBy and Iterable.groupBy.

    Previously, grouping widened finite keys to string or symbol, which lost known-key autocomplete and allowed access to keys that the selector could never produce. The new Record.ReadonlyRecord.GroupByResult keeps finite keys and marks their properties optional because any group may be absent at runtime, while open string and symbol selectors retain their existing record index signatures.

  • #7415 4d89bb8 Thanks @gcanti! - Reject unsupported JSON Schema references instead of resolving them by their final path segment, closes #7409.

  • #7420 480fb15 Thanks @gcanti! - Make JSON Schema dialect conversions preserve custom keywords, translate conditionals, contains, dependencies, identifiers, and tuples where representable, relocate local references after structural changes, and throw instead of silently changing unsupported constraints.

  • #7417 f77ec19 Thanks @Makisuo! - Defer built-in OpenAPI response generation until the documentation route is first requested, retrying after generation defects.

  • #7388 925b82a Thanks @ebramanti! - Fix MCP initialize rejected over the protocol version header

    McpServer.layerHttp validated the MCP-Protocol-Version header on every POST, including the initialize request. That header reports the version negotiated by an earlier initialize, so on a fresh connection a client can only send its own default. Whenever that default was not among the server’s registered protocols the initialize returned 400 and never reached version negotiation, even when the body offered a version the server supports.

    The header check now applies only to requests after initialization, where the specification requires it. An initialize negotiates from the version offered in its body, through the protocol registry, and reports the selected version in the response.

  • #7403 7455246 Thanks @hsyntax! - Add support for explicit cache breakpoints on the OpenAI responses API for GPT-5.6-or-later.

  • #7442 118124d Thanks @tim-smart! - Redact password prompt values from CLI wizard command output.

  • #7366 0dd7825 Thanks @tim-smart! - Add SchemaBinary, a compact schema-derived codec with streaming, optional fingerprints and dictionaries, and RPC support.

  • #7404 b722eca Thanks @gcanti! - Add a public StandardSchema module containing the vendored Standard Schema V1 specification and remove the direct dependency on @standard-schema/spec.

  • #7436 811d579 Thanks @gcanti! - Fix JSON Schema imports:

    • Type-specific keywords no longer imply a type. For example, minLength validates strings without rejecting non-string values.
    • Constraints next to const, enum, and $ref are now applied instead of being ignored.
    • Disjoint and linear union intersections are imported without a Cartesian expansion. Other overlapping union intersections fail with an explicit error.
    • References to definitions without unions no longer make otherwise linear intersections fail.
    • Imported oneOf schemas remain oneOf when exported again.
    • minItems is preserved when prefixItems does not fully enforce it.
  • #7382 043b587 Thanks @tim-smart! - Replace per-prompt prefix options with a context-based theme for CLI prompt symbols and colors.

  • #7373 8583727 Thanks @ChubbyDuck! - Drop unreachable concurrency guard in iteratorEagerImpl

  • #7429 d9d2cfc Thanks @gcanti! - Reject unsupported JSON Schema validation keywords and object or array const / enum values during import instead of silently weakening validation.

  • #7428 5c4b7a0 Thanks @ebramanti! - Return workflow execution IDs from generated RPC and HTTP discard endpoints.

4.0.0-rc.111

Patch Changes

  • #7311 0ce3b00 Thanks @fubhy! - Reject graph shortest-path calculations that overflow or underflow the finite number range.

  • #7352 d846331 Thanks @nikhilsnayak! - Preserve the Context.mapUnsafe accessor when code is compiled with loose object spread transforms.

  • #7300 f93616f Thanks @fubhy! - Fix graph index exhaustion, A* path consistency, snapshot validation, Mermaid line endings, and topological initials.

  • #7336 16bf1ef Thanks @gcanti! - Compact JSON Schema check constraints when they can be safely merged without keyword collisions.

  • #7360 d568968 Thanks @gcanti! - Add configurable schema representation reference policies and propagate them through JSON Schema and OpenAPI generation. By default, only schemas with resolved identifiers become references. Closes #7357.

  • #7304 bc06292 Thanks @fubhy! - Add graph snapshots, low-link connectivity analysis, bipartite matching, maximum flow, and minimum cut APIs.

  • #7364 e03ea90 Thanks @kitlangton! - Fix Deferred completion skipping waiters when an earlier waiter dies during resume. Completing a Deferred with an interrupt cause kills a suspended waiter synchronously inside its resume; the dying waiter’s await cleanup spliced the shared resumes array mid-iteration, so the next waiter was never resumed and hung forever. Completion now clears resumes before resuming waiters.

  • #7347 9b10fc8 Thanks @tim-smart! - Shut down the internal effects queue when ordered concurrent channel mapping closes.

  • #7335 770c6d0 Thanks @tim-smart! - Fix Effect.fn binding the final transform as the generator body when using the { self } overload.

  • #7344 7425bcb Thanks @tim-smart! - Ensure fiber observer cancellation during exit does not skip remaining observers.

  • #7301 563815a Thanks @fubhy! - Preserve depth-first traversal order with finite radii and validate A* heuristics for trivial paths.

  • #7350 1e83ca1 Thanks @tim-smart! - Align in-memory workflow interrupt finalization with the cluster workflow engine.

  • #7316 550a41a Thanks @tim-smart! - Update dependencies across the Effect workspace.

  • #7306 45d79c7 Thanks @fubhy! - Add bulk node and edge removal operations, and disallow graph mutations from callbacks that traverse or transform the same graph.

  • #7317 aac8584 Thanks @tim-smart! - Fix Match.value terminal combinators failing to typecheck when the input contains a generic type parameter.

    The fifth type argument of Matcher for value matchers is now ValueFlavor, and ValueMatcher has a seventh flavor argument; update hand-written annotations accordingly.

  • #7361 7f87022 Thanks @tim-smart! - Merge effect and finalizer failures during cleanup, preserving other failures alongside Cause.Done.

  • #7326 425457c Thanks @tim-smart! - Emit mixed struct and record schema types as intersections, preventing optional properties in open OpenAPI objects from conflicting with their index signature.

  • #7324 008c423 Thanks @tim-smart! - Allow path-level common parameters in OpenAPI generator input types.

  • #7359 4f6ae04 Thanks @gcanti! - Add dual standalone functions for reading and updating values through optics, closes #7299.

  • #7250 b6b63e1 Thanks @xianjianlf2! - Preserve JSON.rawJSON values when cloning cached OpenAPI specs.

  • #7351 92922ee Thanks @tim-smart! - Preserve unsafe in-memory workflow interrupts across replay.

  • #7328 859c02f Thanks @fubhy! - Keep graph caches consistent during bulk removals and validate graph kinds at runtime.

  • #7358 ffc8235 Thanks @tim-smart! - Bound framed RPC server HTTP response streams to 16 items by default, with a configurable buffer size or an unbounded opt-out.

  • #6324 a29eb70 Thanks @tim-smart! - Add scoped Redis pub/sub subscriptions that expose received messages through an Effect queue.

  • #7354 0be2303 Thanks @tim-smart! - Add support for server-originated RPC requests and notifications. Buffered JSON-RPC HTTP drops notifications until streaming responses are available.

  • #7349 b44636f Thanks @gcanti! - When canonical JSON derivation adds a transformation for a schema without a direct JSON representation, keep source checks and annotations on the source side. This prevents duplicate check execution and ensures generated JSON Schema documents describe only the encoded target, closes #7192.

  • #7337 b19ccc7 Thanks @gcanti! - Add Schema.JsonObject for readonly string-keyed records containing JSON-compatible values. This provides a canonical, reusable schema instead of requiring callers to repeatedly compose Schema.Record(Schema.String, Schema.Json).

  • #7330 ff98f0b Thanks @gcanti! - Preserve JSON Schema object keyword scopes when importing allOf intersections, including closed empty objects and required-only keys. Emit intersecting index signatures without weakening their constraints, and reject object scope intersections that cannot be represented faithfully.

  • #7363 a47cbf1 Thanks @tim-smart! - Add Match.fn for reusable matchers that select a value from multiple arguments.

  • #7362 39b55f8 Thanks @tim-smart! - Preserve encoded AI tool call parameters when automatic tool call resolution is disabled, and update Toolkit.handle to accept the encoded parameter type it decodes at runtime.

  • #7305 c6c49c9 Thanks @fubhy! - Fix mutable graph cache consistency and guard weighted pathfinding against inconsistent snapshots and numeric overflow.

  • #7342 bf23ba7 Thanks @misterclayt0n! - Forward every worker-runner client disconnect to the RPC server, not just the first one.

4.0.0-rc.110

Patch Changes

  • #7234 6eebd0a Thanks @lloydrichards! - MCP servers can now use the 2025-11-25 protocol, including sampling with tools and both form- and URL-based elicitation.

    Enable it by adding McpProtocol.v2025_11_25 to the server’s protocols option.

  • #7234 6eebd0a Thanks @lloydrichards! - MCP servers can now provide icons for server information, resources, resource templates, prompts, and tools using McpSchema.Icon.

    Each icon can specify its source URI, MIME type, supported sizes, and light or dark theme.

  • #7291 d10ceb0 Thanks @fubhy! - Include traversed edge indexes in graph shortest-path results.

  • #7291 d10ceb0 Thanks @fubhy! - Add deterministic, index-preserving Graph.minimumSpanningForest.

  • #7291 d10ceb0 Thanks @fubhy! - Add index-preserving transitive reduction for directed acyclic graphs.

  • #7261 189b003 Thanks @fubhy! - Add Graph.Snapshot and Graph.fromSnapshot for constructing immutable graphs with explicit node and edge indexes, and simplify Graph.Edge to a type-only structural interface.

  • #7261 189b003 Thanks @fubhy! - Add Schema.Graph for schema-based encoding and decoding of immutable directed and undirected graphs.

  • #7267 0a127b8 Thanks @tim-smart! - Allow customizing the prefix displayed by CLI prompts.

  • #7272 e491deb Thanks @fubhy! - Preserve scoped Graph mutation callback errors when the callback manually finalizes its mutable handle.

  • #7266 f99c508 Thanks @tim-smart! - Fix SQL persisted queue delivery on SQLite builds without SQLITE_ENABLE_UPDATE_DELETE_LIMIT.

  • #7199 7e3f07c Thanks @rekram1-node! - Fix Zsh completions for CLI commands with both positional arguments and subcommands.

  • #7274 a894fe1 Thanks @fubhy! - Ignore removed allocator history when comparing and hashing immutable Graph values with the same active indexed structure.

  • #7291 d10ceb0 Thanks @fubhy! - Add Graph.findCycle with exact node and edge witnesses.

  • #7294 7e9923b Thanks @tim-smart! - Add custom reviver support to HTTP JSON parsing APIs.

  • #7200 f064121 Thanks @mikearnaldi! - Support narrowing schedule input and output types with type guard predicates passed to Schedule.while.

  • #7291 d10ceb0 Thanks @fubhy! - Add index-preserving Graph.inducedSubgraph.

  • #7244 b660bf0 Thanks @AnnaSuSu! - Normalize unbounded PubSub replay capacities to positive integers.

  • #7293 f4fbe9c Thanks @tim-smart! - Support standalone Effect.forEach data-last usage

  • #7291 d10ceb0 Thanks @fubhy! - Add bounded lazy enumeration of simple paths and all tied shortest paths.

  • #7259 e811353 Thanks @fubhy! - Prevent graph edge reads from exposing internal edge records and reject non-finite A* heuristic values.

  • #7251 9761c3c Thanks @tim-smart! - Add Encoding.randomHex, a lightweight non-cryptographic generator that coerces lengths to unsigned 32-bit multiples of 8.

  • #7296 baa99fc Thanks @tim-smart! - Make unstable CLI boolean flags required when omitted, allowing optional, default, config, and prompt fallbacks to handle absence consistently.

  • #7246 7fd79b2 Thanks @tim-smart! - Add Effect.head for retrieving the first element of an iterable produced by an effect.

  • #7273 a82ffc0 Thanks @fubhy! - Validate Graph traversal radii, isolate traversal start configuration, and prioritize the first supplied DFS root.

  • #7291 d10ceb0 Thanks @fubhy! - Throw GraphError when a negative cycle affects a Bellman-Ford target, reserving Option.none() for unreachable paths.

  • #7248 4026e2d Thanks @tim-smart! - Improve tracing performance in span creation and HTTP middleware.

  • #7276 397bf1e Thanks @fubhy! - Deduplicate directed neighbor-node queries while preserving first edge occurrence order.

  • #7291 d10ceb0 Thanks @fubhy! - Add incident-edge, edges-between, and directed and undirected degree queries to Graph.

  • #7291 d10ceb0 Thanks @fubhy! - Add unweighted reachability, explicit weak and strong connectivity predicates, weak components, and tree detection to Graph.

4.0.0-rc.109

Patch Changes

  • #7219 a0743f2 Thanks @tim-smart! - Add SQL, HttpApi testing, and CLI schema examples to the published AI documentation.

  • #7241 17892e7 Thanks @tim-smart! - Use Context mapUnsafe in less call sites

  • #7240 4d8a230 Thanks @tim-smart! - Fix Effect.fromOption data-first inference for inline Option expressions.

  • #7216 f21f9c9 Thanks @tim-smart! - Add a HttpStatus module to effect/unstable/http that centralizes the mapping from HTTP status literal names to numeric codes and exports HttpStatus.fromLiteral. HttpApiSchema.status now consumes the new module.

  • #6829 18270dd Thanks @lloydrichards! - MCP servers now support the 2024-11-05 and 2025-03-26 RPC revisions through version-specific protocol adapters.

  • #7218 26db404 Thanks @tim-smart! - Run SQL PersistedQueue table creation through versioned migrations so future schema changes can be applied safely.

  • #7210 2670398 Thanks @tim-smart! - Preserve nanosecond precision when adjusting TestClock with large durations.

  • #7205 3702bed Thanks @tim-smart! - Remove the kubernetes-types dependency by vendoring the Kubernetes Pod declarations used by the cluster helpers and exporting them from effect/unstable/cluster/K8sTypes.

  • #7236 ccae60e Thanks @roninjin10! - Propagate a failed BEGIN or SAVEPOINT from SqlClient.withTransaction as a typed SqlError.

    makeWithTransaction wrapped the begin step together with the transaction body, so a failed BEGIN took the rollback branch. No transaction was active at that point, the ROLLBACK failed, and its Effect.orDie wrapper replaced the original typed error with a defect (cannot rollback - no transaction is active). Callers could no longer classify the failure as retryable. The path became reachable when the sqlite client started using BEGIN IMMEDIATE, which acquires a write lock and can fail with SQLITE_BUSY.

    Commit and rollback now run only after begin or savepoint succeeds. A failed begin or savepoint fails with its original SqlError, leaves the wrapped effect unexecuted, and still closes the acquired connection scope.

  • #7206 6ff5396 Thanks @tim-smart! - Bound cluster runner entity residency and storage reads.

    ShardingConfig gains two knobs:

    • maxResidentEntities (default 10_000): the maximum number of entities that can be resident on a runner at the same time. At the cap, the storage read loop stops admitting messages for new entity addresses (they stay in storage until a slot frees up) and volatile sends to new addresses fail with MailboxFull. Persisted sends still succeed. "unbounded" restores the previous behaviour and can only be set programmatically.
    • unprocessedMessageBatchSize (default 1024): the maximum number of unprocessed messages read from storage in a single poll.

    MessageStorage.unprocessedMessages accepts an optional { limit, addresses } argument, and only claims the messages it actually returns. The memory implementation now applies the same ten-minute claim window as SQL, so bounded reads advance past in-flight requests; resetting an address or shard makes its claimed messages immediately eligible again.

    The encoded driver contract replaces Encoded.resetAddress with the batched Encoded.resetAddresses operation. SqlMessageStorage.makeEncoded constructs the SQL encoded driver directly for custom storage composition.

    ClusterWorkflowEngine entities (workflows and the durable clock) now use a fixed ten-second idle time, so completed and suspended executions release their entity slots quickly. Their state is durable, so an evicted execution is rebuilt from storage when its next message arrives.

4.0.0-rc.108

Patch Changes

  • #6546 dfb173e Thanks @xianjianlf2! - Handle BigInt values safely and consistently across JSON diagnostics and logger formats.

  • #7174 005e090 Thanks @tim-smart! - Fix Queue.await failing with Cause.Done when registered before the queue ends.

  • #7180 c82c532 Thanks @gcanti! - Prioritize redacted representations in formatters and normalize text logger levels to uppercase.

  • #7193 22b579f Thanks @kitlangton! - Fix Deferred.await dying with a TypeError when a waiter is interrupted after the Deferred has been completed.

  • #7179 3e19539 Thanks @tim-smart! - Fix DurableDeferred.raceAll so a completed deferred can wake an active workflow without changing success-biased race semantics

  • #7189 08a3c74 Thanks @gcanti! - Fix HttpApi query decoding for array parameters with a single value.

  • #6550 eb0bae0 Thanks @xianjianlf2! - Return fresh OpenAPI specs from cached OpenApi.fromApi calls.

  • #7188 97b544d Thanks @gcanti! - Mark the internal ~sentinels Schema annotation as @internal so release declaration stripping removes it together with SchemaAST.Sentinel. This keeps the published declarations self-consistent for consumers that type-check dependencies with skipLibCheck: false.

  • #7158 4f6d131 Thanks @k3dom! - Improve Union candidate selection: a nested union member is dispatched by the sentinels common to all its members, and candidates whose sentinel the input contradicts are excluded.

  • #7178 fad4b7c Thanks @tim-smart! - Use Promise microtasks for synchronous Scheduler dispatch.

  • #7181 accf447 Thanks @gcanti! - Move SchemaError into the Schema module and remove the standalone SchemaError module.

  • #7195 31b27e4 Thanks @tim-smart! - Ensure discarded non-persisted cluster messages complete without waiting for the entity reply.

  • #7191 8458951 Thanks @Digifox03! - Fix HttpRouter.Middleware.layer to provide request error services for errors declared in handles, and expose global middleware errors from HttpRouter.toHttpEffect.

4.0.0-beta.107

Patch Changes

  • #7156 596f3f9 Thanks @tim-smart! - Terminate active multipart file streams when a parser limit is exceeded or the body ends unexpectedly, so file parts fail instead of hanging.

  • #7153 9611ed4 Thanks @rajanpanth! - Fix Duration’s Hash.symbol implementation to hash a canonical nanoseconds form instead of the raw internal Millis/Nanos representation. Two durations that Duration.equals/Equal.equals consider equal (e.g. Duration.seconds(5) and Duration.nanos(5_000_000_000n)) previously hashed differently, violating the Hash/Equal contract and silently breaking HashSet/HashMap lookups keyed by Duration.

  • #7166 8b91605 Thanks @CDVolvik! - Import migrations through a file URL in Migrator.fromFileSystem, so absolute Windows paths are accepted by the ESM loader.

    Previously the directory and file name were passed to import as a plain path. On Windows that produced a specifier such as D:\migrations\1_init.ts, which the ESM loader rejects with Only URLs with a scheme in: file, data, and node are supported.

    fromFileSystem now resolves the specifier through the Path service, so its type widens from Loader<FileSystem> to Loader<FileSystem | Path>. Callers that already provide an aggregate platform layer such as NodeServices.layer are unaffected; callers that provide FileSystem on its own now also need a Path layer, and on Windows it must be a platform-aware one rather than the POSIX Path.layer.

  • #7157 d901928 Thanks @tim-smart! - Add Channel.mkUint8Array and reuse it from Stream and multipart file collection. This also fixes quadratic buffering in File.contentEffect, improving collection of a 16 MiB chunked upload by approximately 90x.

  • #7149 b32bdef Thanks @gcanti! - Require explicit handling for regular expression pattern constraints translated from JSON Schema documents, with modes to apply trusted patterns or ignore their constraints.

4.0.0-beta.106

Patch Changes

  • #7110 2695168 Thanks @fubhy! - Ensure concurrent first RcRef borrowers share the same resource generation.

  • #7114 6310a8c Thanks @fubhy! - Report buffered worker send failures as WorkerError values.

  • #7117 c2071b1 Thanks @fubhy! - Make TxQueue.shutdown safe to call after a queue has already been interrupted.

  • #7119 7aff81a Thanks @fubhy! - Prevent SQL resolvers from invoking non-empty batch callbacks when every request fails encoding.

  • #7105 a1d4057 Thanks @tim-smart! - Add ConfigProvider.fromEnvRecord for building a provider from an explicit environment record.

  • #7111 abf77b0 Thanks @fubhy! - Preserve input fiber error types in Fiber.joinAll.

  • #7134 6c60375 Thanks @marbemac! - Fix cluster shutdown hangs by failing abandoned non-discard requests and stream chunk acknowledgements with EntityNotAssignedToRunner, including persisted requests sent after runner unregistration. This adds EntityNotAssignedToRunner to the typed error channel of entity clients and request-only EntityProxy RPC/HTTP endpoints; discard endpoints remain unchanged.

  • #7107 22f4897 Thanks @fubhy! - Preserve FormData bodies when converting client requests through HttpServerRequest.

  • #7120 615d1d5 Thanks @fubhy! - Fix SqlResolver.findById failing to complete duplicate requests when id encoding fails, which surfaced as a RequestResolver did not complete request defect instead of the underlying SchemaError.

  • #7131 3a86757 Thanks @fubhy! - Ignore MCP cancellation notifications for unknown request identifiers.

  • #7104 f4a9762 Thanks @gcanti! - Add Function.memoizeIdempotent and use it to avoid reprocessing canonical Schema ASTs, including optional and mutable property modifiers. Cache Config schema cursor AST compilation.

  • #7144 0bcf6ed Thanks @fubhy! - Stop multipart parsing after part count, part size, or field size limits are exceeded.

  • #7121 ba9cb63 Thanks @fubhy! - Prevent execution-plan event observer defects from changing attempt outcomes or leaving attempt events unpaired.

  • #7147 42c810d Thanks @tim-smart! - Release worker pool entries when an RPC worker’s receive loop fails.

  • #7148 1416ccd Thanks @gcanti! - Consolidate schema arbitrary derivation into Schema.toArbitrary, which now returns a Schema.Arbitrary factory that accepts the fast-check module. Remove Schema.toArbitraryLazy and arbitrary derivation reports.

  • #7109 08d0d39 Thanks @fubhy! - Fix RcRef leaking resources acquired before a failed acquisition.

  • #7146 548908a Thanks @gcanti! - Improve Schema representation identity, anonymous-reference eligibility, and JSON Schema alias finalization.

  • #6862 4b3460d Thanks @fubhy! - Ensure ScopedRef.set releases a replacement when the previous value’s finalizer defects.

  • #7060 d170596 Thanks @fubhy! - Preserve maxItems semantics when importing JSON Schema prefixItems.

  • #7116 aea89d0 Thanks @fubhy! - Keep span end times at zero when tracer timing is disabled.

  • #7124 deed5fb Thanks @fubhy! - Use a distinct AES-GCM initialization vector for each encrypted event log entry. EventLogEncryption.encrypt now returns each IV with its ciphertext, and encrypted event log clients and servers must be upgraded together because the WriteEntries wire shape changed.

4.0.0-beta.105

Patch Changes

  • #7087 0418564 Thanks @tim-smart! - Recognize tagged Config and RPC errors across duplicated effect package copies.

  • #6827 d334a85 Thanks @jaipaljadeja! - Add bounded 429 retries and custom response header names to HttpClient.withRateLimiter.

  • #7084 f0be855 Thanks @tim-smart! - Stop capturing definition-location stack frames in Context.Service.

  • #7090 b206fa5 Thanks @tim-smart! - Expose stdinIsTerminal and stdoutIsTerminal effects through the Stdio service.

  • #7093 b938c8a Thanks @gcanti! - Add the opt-in reportInput parse option for retaining rejected inputs in enumerable fields on value-bearing schema issues and including them in default formatted messages. Value-bearing issue constructors accept the rejected input and parse options directly, and Schema.Annotations.Issue now supports expected for default messages.

    Schema issues no longer format implicitly through Issue#toString. Use SchemaIssue.makeFormatterDefault() when a human-readable message is needed. The throwing and Promise-based adapters in SchemaParser now use the generic message "Schema validation failed" and expose the structured SchemaIssue.Issue as the error cause; consumers that previously read the formatted error message should inspect and explicitly format that cause instead.

    Schema.makeEffect now returns SchemaIssue.Issue failures instead of wrapping them in SchemaError, and Schema.withConstructorDefault accepts an Effect that fails with SchemaIssue.Issue. Fallible Optic operations return structured SchemaIssue.Issue failures, while schema failures from Schema.toIso and Schema.toDifferJsonPatch use the generic error message and preserve the issue in cause instead of formatting it internally.

  • #7097 8525f05 Thanks @tim-smart! - Add Cron.format for converting a Cron instance to a cron expression, with an option to include the seconds field.

4.0.0-beta.104

Minor Changes

  • #7076 0f721d4 Thanks @tim-smart! - Return the new file offset as a Size from File.seek.

Patch Changes

  • #6934 1001bcc Thanks @tim-smart! - httpapi: add typed response headers across handlers, generated clients (including HttpApiTest), streaming responses, and OpenAPI with HttpApiSchema.WithHeaders. Add HttpApiSchema.encodeToWithHeaders for folding response headers into domain types such as error classes. Explicit content-type and content-length values applied with HttpServerResponse.setHeader or setHeaders now override body-derived values.

  • #7044 993ba60 Thanks @fubhy! - Commit SQL event journal entries only after their write callback succeeds.

  • #6957 67faacd Thanks @fubhy! - Select Bash completions for the active positional argument.

  • #6941 b78acdf Thanks @fubhy! - Generate even and odd safe integers in Crypto random APIs.

  • #6965 fbb9ce5 Thanks @fubhy! - Correct the runtime tag spelling for CliError.UnknownSubcommand.

  • #6963 722ea48 Thanks @fubhy! - Exclude disabled choices from multi-select prompt selection and submission.

  • #7001 3058fd5 Thanks @fubhy! - Keep ordered SQL resolver results aligned when batched request encoding fails.

  • #6937 62d0575 Thanks @fubhy! - Fix the encoded output type of TestSchema.Encoding.encodeUnknownEffect.

  • #7014 99dd6b5 Thanks @tim-smart! - Add lightweight INI, YAML, and TOML parsers under effect/unstable/encoding and remove their runtime dependencies.

  • #7053 7963ce1 Thanks @fubhy! - Fix arbitrary generation for tuples with multiple optional elements.

  • #7047 af14e75 Thanks @fubhy! - Fix Tuple.pick return types to preserve the requested index order and duplicate indices.

  • #7066 24e22d2 Thanks @fubhy! - Close ResourceMap acquisition scopes when a lookup fails.

  • #7036 647d14e Thanks @fubhy! - Fix scoped reentrant lock finalizers releasing under the wrong fiber owner.

  • #6983 1434eec Thanks @fubhy! - Apply byte range and chunk size options to default Web file responses.

  • #7071 a5278b1 Thanks @fubhy! - Fix MCP sampling metadata optionality and validate it as an object.

  • #6946 6af04a5 Thanks @fubhy! - Defer memoized Layer state installation until Effect execution.

  • #6943 cb6c837 Thanks @fubhy! - Reject zero execution attempts in ExecutionPlan steps.

  • #7026 d44cead Thanks @tim-smart! - Add execution-plan lifecycle events via an optional onEvent handler on Effect.withExecutionPlan and Stream.withExecutionPlan.

    The handler receives an ExecutionPlan.Event, a tagged union of AttemptStart, AttemptSuccess, and AttemptFailure, allowing attempt outcomes to be observed from outside the effect for logging and metrics:

    import { Effect } from "effect"
    Effect.withExecutionPlan(program, plan, {
    onEvent: (event) => Effect.log("execution plan event", event)
    })

    Every AttemptStart is followed by exactly one terminal event. AttemptFailure carries the full failure Cause, so defects and interruption are reported as well as expected errors, and terminal events run like finalizers so they are emitted even when the attempt is interrupted. Event numbering matches ExecutionPlan.CurrentMetadata: attempt is cumulative across steps, while stepAttempt is 1-based within the current step.

  • #7077 88c7632 Thanks @tim-smart! - Rename Schedule.andThen and Schedule.andThenResult to Schedule.concat and Schedule.concatResult.

  • #6975 abcbb2a Thanks @fubhy! - Encode SSE events with empty data as dispatchable events.

  • #7037 8f63cce Thanks @fubhy! - Preserve OTLP metric delta checkpoints when an export fails.

  • #7057 d56dfcf Thanks @fubhy! - Fix the error type exposed by the curried Sink.catch overload.

  • #6947 a98cda9 Thanks @fubhy! - Check symbol-keyed properties in Match object patterns.

  • #6956 6704bb8 Thanks @fubhy! - Emit valid CSI sequences from the unstable CLI cursorTo helper.

  • #7008 6143de2 Thanks @tim-smart! - Prevent Bash completions from treating flag values as subcommands.

  • #7032 936b135 Thanks @marbemac! - Fix a @effect/cluster shutdown deadlock on single-runner topologies (e.g. single-node deployments and TestRunner), where Sharding.sendOutgoing retried EntityNotAssignedToRunner forever during teardown.

  • #6940 1bbae84 Thanks @fubhy! - Omit services removed by Context.addOrOmit from the returned context type.

  • #7065 d795ee7 Thanks @tim-smart! - Fix DevTools span requests to preserve their state when queued for sending.

  • #7016 0a82d88 Thanks @brandon-julio-t! - Normalize cluster durable clock wake-up timestamps to whole milliseconds.

  • #6945 9215bc5 Thanks @fubhy! - Preserve integral precision when parsing decimal nano and micro duration inputs

  • #7050 a1b5df2 Thanks @fubhy! - Include schedule errors in the error channel of Effect.schedule and Effect.scheduleFrom.

  • #7062 92a9ac5 Thanks @fubhy! - Fix the inspectable JSON identity of FiberSet.

  • #6959 6bde7f2 Thanks @fubhy! - Match Fish completions against the full nested command path.

  • #6951 a712131 Thanks @fubhy! - Use the supplied hash for HashMap.modifyHash insertions, updates, and removals.

  • #6989 2e6f760 Thanks @fubhy! - Support standard BodyInit values when reading converted client request bodies through HttpServerRequest.

  • #6986 aa05804 Thanks @fubhy! - Synchronize HTTP server response content headers when replacing the body.

  • #6944 badd3bf Thanks @fubhy! - Make Iterable.flatten stack safe across empty iterables.

  • #6968 02b0265 Thanks @fubhy! - Allow MCP tool calls to omit optional arguments.

  • #7033 3437e21 Thanks @fubhy! - Fix memory journal conflict detection skipping the first newer entry.

  • #7034 41a550d Thanks @fubhy! - Return the first unused remote sequence from the in-memory event journal.

  • #7042 17b5d50 Thanks @fubhy! - Relay entries imported into an in-memory event journal to other remotes.

  • #7074 96e5e95 Thanks @fubhy! - Preserve and update runner health in the in-memory cluster runner storage.

  • #7038 e4d589e Thanks @fubhy! - Clear in-memory message primary-key indexes when clearing an entity address.

  • #7005 ae4cf7b Thanks @fubhy! - Generate valid MSSQL upserts for multi-table persistence.

  • #6998 6ef5f1a Thanks @fubhy! - Decode split UTF-8 sequences correctly in NDJSON streams.

  • #6972 2235a29 Thanks @tim-smart! - Persist a serializable defect when a cluster reply cannot be encoded, preventing persisted entity callers from hanging.

  • #6962 b32f4cb Thanks @fubhy! - Support empty records and non-array iterables in Prompt.all.

  • #7023 7f4c095 Thanks @tim-smart! - Rename RateLimiter.makeSleep to RateLimiter.sleep and support self-first partially applied and uncurried usage.

  • #7041 5f3fb81 Thanks @fubhy! - End runner streams after emitting their terminal replies.

  • #7020 17f0b91 Thanks @gcanti! - Fix Schema.make to preserve existing nested Schema.Class instances, including in array fields, while recursively constructing plain class inputs provided at runtime inside unions. Constructor defaults remain scoped to structural field and element occurrences, with SchemaAST.Context.constructorDefault representing the single default link for each occurrence.

    Optimize Function.memoize to use a single WeakMap lookup for cached values. Its callback no longer accepts undefined as a return type because undefined represents a cache miss.

    The performance of the two array paths can be reproduced by saving the following program as scratchpad/schema-make-6890-benchmark.ts and running node scratchpad/schema-make-6890-benchmark.ts from the repository root:

    import { Schema } from "effect"
    import { performance } from "node:perf_hooks"
    class Row extends Schema.Class<Row>("Row")({ value: Schema.String }) {}
    class DirectTable extends Schema.Class<DirectTable>("DirectTable")({ rows: Schema.Array(Row) }) {}
    class UnionTable extends Schema.Class<UnionTable>("UnionTable")({ rows: Schema.Array(Schema.Union([Row])) }) {}
    const rows = Array.from({ length: 30_000 }, (_, value) => Row.make({ value: String(value) }))
    function benchmark(label: string, make: () => { readonly rows: ReadonlyArray<Row> }) {
    const samples: Array<number> = []
    for (let i = 0; i < 6; i++) {
    const start = performance.now()
    const result = make()
    samples.push(performance.now() - start)
    if (result.rows[0] !== rows[0] || result.rows.at(-1) !== rows.at(-1)) {
    throw new Error(`${label} did not preserve Row identity`)
    }
    }
    console.log(`${label}: ${samples.slice(1).map((n) => n.toFixed(3)).join(", ")} ms`)
    }
    benchmark("Array(Class)", () => DirectTable.make({ rows }))
    benchmark("Array(Union([Class]))", () => UnionTable.make({ rows }))

    Representative local results on Node 24.12.0 (six runs, with the first discarded):

    Array(Class): 0.639, 0.498, 0.447, 0.448, 0.451 ms
    Array(Union([Class])): 3.141, 2.195, 2.126, 2.108, 2.057 ms
  • #7055 0cdadd7 Thanks @fubhy! - Fix Stream.slidingSize to produce the same windows regardless of upstream chunk boundaries.

  • #6978 39b57d7 Thanks @fubhy! - Retain the last SSE event ID across dispatched events.

  • #6976 5a6a573 Thanks @fubhy! - Recognize and ignore a leading UTF-8 byte order mark in server-sent event streams.

  • #7048 59f5e99 Thanks @fubhy! - Ignore malformed retry directives when parsing server-sent event streams.

  • #7028 45379d6 Thanks @fubhy! - Fix Trie.insert to replace existing values without mutating the original trie or increasing its size.

  • #6973 1949439 Thanks @fubhy! - Separate the default VariantSchema cache from named variant entries.

  • #7072 e443403 Thanks @fubhy! - Keep MCP tool calls that return void successful.

  • #7000 03af7e8 Thanks @fubhy! - Close suspended workflow scopes after resumed completion.

  • #7027 130b28d Thanks @pawelblaszczyk5! - Prevent Effect.updateService and Effect.updateServiceScoped supertype widening

  • #6948 c987a12 Thanks @fubhy! - Honor numeric zero time-to-live values in Cache.make and ScopedCache.make.

  • #6974 4158562 Thanks @fubhy! - Handle accepted undefined fields during variant extraction.

  • #7013 306014a Thanks @tim-smart! - Fix several edge cases in the vendored FindMyWay router.

  • #6949 729a663 Thanks @fubhy! - Keep TestClock nanosecond access total after infinite adjustments.

  • #6997 caf84b6 Thanks @fubhy! - Isolate compiled SQL fragment caches by compiler instance.

  • #6960 ce067f7 Thanks @fubhy! - Mark omittable CLI flags and arguments as optional in structured help.

  • #7025 7a41f5a Thanks @pawelblaszczyk5! - Prevent Effect.provideServiceEffect supertype widening

  • #7056 781022a Thanks @fubhy! - Fix Map and Set equality allowing a right-side entry to match multiple left-side entries.

  • #7063 39f1297 Thanks @fubhy! - Preserve literal element types in Tuple.make.

  • #6955 2db266b Thanks @fubhy! - Include plain variant structs in the default variant union.

  • #6954 2141e28 Thanks @fubhy! - Preserve CRLF state across SSE input chunk boundaries.

  • #6950 3c5e429 Thanks @fubhy! - Preserve nanosecond precision for large TestClock wall-clock timestamps.

  • #6958 20ddc63 Thanks @fubhy! - Preserve hidden command metadata when adding subcommands or shared flags.

  • #6939 841b3ea Thanks @fubhy! - Preserve sibling provider input evidence when Config.all evaluates a failing child.

  • #6836 82a3fbf Thanks @mkdynamic! - Route provider-executed tool results into the assistant message in Prompt.fromResponseParts

  • #7003 eb9ee83 Thanks @fubhy! - Persist permanent entries in KVS setMany operations.

  • #7039 64dc7c7 Thanks @fubhy! - Fix failed ResourceRef rebuilds permanently blocking waiters.

  • #6971 84dc8ab Thanks @tim-smart! - Serialize concurrent nested SQL transactions to prevent savepoint collisions. Cross-dependent sibling nested transactions now deadlock instead of interleaving and risking silent data corruption.

  • #6952 b4463f4 Thanks @fubhy! - Register alternate flags used by Param.orElse and Param.orElseResult.

  • #6732 592dd36 Thanks @tim-smart! - Rename the Schema error constructors to align with their Data counterparts.

    • Schema.ErrorClass is now Schema.Error.
    • Schema.TaggedErrorClass is now Schema.TaggedError.
    • The JavaScript Error instance schema is now Schema.ErrorInstance.
    • Schema.ErrorReviver is now Schema.ErrorInstanceReviver.
  • #7068 85d2b44 Thanks @tim-smart! - Report retried RPC socket open failures through the onTransientError protocol hook and fail in-flight requests when the retry policy is exhausted.

  • #7006 32e4a69 Thanks @fubhy! - Scope custom persisted queue ID deduplication to each named queue.

  • #6938 13c5872 Thanks @fubhy! - Honor populated variables before dotenv expansion defaults in ConfigProvider.

  • #7040 3454cdb Thanks @fubhy! - Fix SynchronizedRef.getAndUpdateSome to update its backing ref.

  • #7018 e930804 Thanks @tim-smart! - Hold persisted cluster messages while entity layers are still registering, while retaining a bounded failure when registration never begins.

  • #6987 7f12d4b Thanks @fubhy! - Map WebSocket send exceptions and transform stream write rejections to typed SocketError failures.

  • #6977 181c9ef Thanks @fubhy! - Default empty Server-Sent Event types to message.

  • #7010 dd9f891 Thanks @tim-smart! - Rename Command.withHidden to Command.unlisted, along with the hidden command property which is now unlisted.

  • #7054 433fb81 Thanks @fubhy! - Fix the return type of Channel.runCount to expose its numeric result.

  • #7012 8459cdb Thanks @tim-smart! - Vendor the multipart parser as effect/unstable/http/MultipartParser, add the Node.js adapter at @effect/platform-node/NodeMultipartParser, and remove the external multipasta dependency.

  • #6953 6124ab3 Thanks @fubhy! - Reject truncated MessagePack frames at the end of a stream.

  • #6961 01bd954 Thanks @fubhy! - Preserve file and directory semantics in CLI completion descriptors.

  • #6990 ba2c3aa Thanks @fubhy! - Generate unique persisted paths for multipart files with duplicate filenames.

  • #7019 0a45ef3 Thanks @tim-smart! - Round Redis persistence TTLs up to whole milliseconds before passing them to integer-only expiration commands.

  • #7012 8459cdb Thanks @tim-smart! - Prevent malformed encoded multipart filenames from throwing during parsing.

  • #7029 eaa7e71 Thanks @fubhy! - Fix unencrypted event log conflict scanning to inspect the newer history suffix.

  • #6988 db4c2cc Thanks @fubhy! - Preserve lexical ordering in streaming template interpolation.

  • #6964 22f150a Thanks @fubhy! - Correct year, ordinal, and meridiem date-mask formatting.

  • #6966 90ffb08 Thanks @fubhy! - Preserve fractional leading zeros while editing float prompts.

  • #6982 d517692 Thanks @fubhy! - Reject NDJSON values without a JSON representation.

  • #6942 01af079 Thanks @fubhy! - Validate object-based DateTime instants before construction.

  • #6985 32a59e8 Thanks @fubhy! - Preserve original HTTP response bytes when reading response text first.

4.0.0-beta.103

Minor Changes

  • #6793 b2f95a9 Thanks @tim-smart! - Add Semaphore.takeIfAvailable for non-blocking manual permit acquisition.

  • #6693 aeba0c8 Thanks @lloydrichards! - Expose object-shaped Toolkit success schemas as MCP tool output schemas.

  • #6807 d0f1a22 Thanks @alecbuffi! - Separate wall-clock timestamps from monotonic elapsed time.

    Clock.Clock now requires monotonicTimeNanosUnsafe() and monotonicTimeNanos for measuring elapsed time. Custom Clock implementations must provide both members. The live clock’s currentTimeNanos now re-anchors its high-resolution Unix wall-clock timestamp when it drifts from Date.now(), while Effect.timed, duration metric tracking, and Sink.withDuration use monotonic time so wall-clock corrections do not distort elapsed durations.

Patch Changes

  • #6697 e56cd8f Thanks @schickling-assistant! - Add a configurable filter for HTTP client request and response header span attributes.

  • #6883 f77c120 Thanks @gcanti! - Add support for converting JSON Schema documents to Draft-04, preserve literal $ref values, $ref sibling constraints, not, readOnly, and writeOnly in Draft-07 conversions, correct the Draft-07 meta-schema URI, and prevent OpenAPI component-key collisions during conversion.

  • #6564 04fd44a Thanks @AVtheking! - Run shared-table SQL persistence expiration cleanup in indexed, bounded background batches.

  • #6911 b74333d Thanks @fubhy! - Update existing HashRing nodes when adding a value with the same primary key.

  • #6909 1c40b28 Thanks @AlfGoto! - Add DateTime.toEpochSeconds and DateTime.fromEpochSeconds for converting date-time values to and from Unix epoch seconds.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP tool handler defects now return a stable internal error without exposing defect details.

  • #6874 b3901d2 Thanks @fubhy! - Fix Equal.equals and Hash.hash to handle invalid dates and DataView values without throwing.

  • #6869 4a0984a Thanks @fubhy! - Fix SQL-backed Persistence getMany to preserve duplicate key positions.

  • #6868 fffd88b Thanks @fubhy! - Ensure clearing an empty Redis-backed persistence store succeeds.

  • #6903 f3f6c1e Thanks @fubhy! - Preserve equals signs in inline CLI option values after the first separator.

  • #6876 ef07642 Thanks @fubhy! - Fix Sink.reduceWhileArray applying its reducer more than once per input array.

  • #6802 f1bc827 Thanks @tim-smart! - Cap incomplete RPC frames buffered by the NDJSON and MessagePack streaming decoders, and close socket transports when the limit is exceeded.

  • #6693 aeba0c8 Thanks @lloydrichards! - RPC servers now suppress responses after a client cancels an in-flight request.

  • #6723 081f4d8 Thanks @tim-smart! - add platform literal to HttpPlatform

  • #6788 5287b24 Thanks @gcanti! - Refine the ConfigProvider interface so lookup absence uses undefined and path transformation is provider behavior.

    ConfigProvider.load and the lookup function accepted by ConfigProvider.make now return Node | undefined. Use undefined when a path does not exist and return the Node directly when it does.

    ConfigProvider now exposes mapInput as a capability. The exported ConfigProvider.mapInput combinator delegates to it, preserving transformation order and composition through orElse without requiring provider representation state.

  • #6863 13d31cf Thanks @fubhy! - Decode percent-encoded OTLP environment header values.

  • #6781 acee269 Thanks @gcanti! - Deduplicate equivalent fallback definitions when compiling JSON Schema, and reconstruct only definitions reachable from multi-document roots.

    Remove SchemaMultiDocument and fromSchemaMultiDocument; multi-document import and revival now return the ordered root schemas directly.

    Stop the OpenAPI generator from emitting component schemas that are not reachable from a generated root.

  • #6717 31170c1 Thanks @IMax153! - Document that CommandOptions.extendEnv defaults to false and that providing env without enabling it replaces the inherited child environment.

  • #6657 205ebc7 Thanks @tim-smart! - Use cancellable microtasks when dispatching yielded work from synchronous Effect runs.

  • #6661 ed0ebf8 Thanks @tim-smart! - Fix hydrated atoms with Atom.withReactivity to refresh after reactive mutations.

  • #6665 a3fd084 Thanks @tim-smart! - Fix HttpRouter.toWebHandler context inference for services provided by the application layer.

  • #6681 ee29ddf Thanks @tim-smart! - Add Web Stream interoperability for Channel and Sink, plus byte limiting and ArrayBuffer collection for Stream.

  • #6730 6086309 Thanks @tim-smart! - Support replaying initial WebSocket messages and normalize ArrayBuffer frames to Uint8Array.

  • #6763 4a57af2 Thanks @tim-smart! - Validate cookie names, domains, and paths before constructing or serializing cookies.

  • #6771 660875b Thanks @tim-smart! - Strip credential headers on cross-origin HTTP redirects and align redirected request methods with fetch.

  • #6777 8e7c706 Thanks @tim-smart! - Bound pending SSE decoder state with a configurable maximum event size.

  • #6772 5f63adb Thanks @tim-smart! - Reject empty, . and .. keys in file-backed key-value stores.

  • #6773 053bc42 Thanks @tim-smart! - Escape terminal control characters in unstable CLI error output.

  • #6898 c0a1534 Thanks @tim-smart! - Add HTTP response compression support. Node.js, Bun, and Deno use asynchronous node:zlib one-shot compression for byte-array bodies, preserving an exact Content-Length; stream and raw bodies remain streaming transforms.

  • #6859 f1e3a37 Thanks @fubhy! - Fix String.snakeToCamel and String.snakeToPascal to return an empty string for empty input.

  • #6746 cedb01a Thanks @fubhy! - Prefer explicit OTLP resource configuration over environment configuration.

  • #6677 1747440 Thanks @tim-smart! - Expose runtime schemas for AI prompt parts and message-specific part unions.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now advertise logging and honor each client’s selected log level when sending log notifications.

  • #6693 aeba0c8 Thanks @lloydrichards! - Preserve MCP sampling request preferences and response content.

  • #6878 b4f1ee2 Thanks @fubhy! - Fix Array index operations handling NaN and fractional indexes.

  • #6751 a4757f1 Thanks @tim-smart! - Fix Atom dependency tracking and re-entrant invalidation during batch rebuilds.

  • #6870 cd122b9 Thanks @fubhy! - Ensure BigInt.gcd and BigInt.lcm return non-negative values and handle zero operands in BigInt.lcm.

  • #6844 5de588b Thanks @fubhy! - Prevent an interrupted cache lookup from removing a newer value written with Cache.set.

  • #6879 3895b9c Thanks @fubhy! - Preserve failure annotations when mapping errors with Cause.map.

  • #6820 89ce5f3 Thanks @fubhy! - Fix ChannelSchema.decodeUnknown to accept unknown input chunks while keeping ChannelSchema.decode typed to the schema’s encoded input.

  • #6899 985de09 Thanks @fubhy! - Ensure Chunk.take and Chunk.drop produce valid chunks for fractional counts.

  • #6579 9800e3a Thanks @marbemac! - Scope cluster reply serialization failures and peer-delivered defects to their own request instead of the whole runner connection

  • #6800 4dc35f6 Thanks @tim-smart! - Fix persisted cluster stream recovery when SQL drivers return a null reply kind.

  • #6814 e8eb62b Thanks @gcanti! - Preserve provider input evidence when Config.orElse recovers a configuration failure.

  • #6873 ecd9993 Thanks @fubhy! - Propagate the FiberSet.runtime interruption option when registering managed fibers.

  • #6872 5ab9c08 Thanks @fubhy! - Fix Formatter.format handling of shared references and ensure Formatter.formatJson always returns valid JSON.

  • #6867 f5cf965 Thanks @fubhy! - Remove stale content-length headers when replacing an HTTP client request body with one of unknown length.

  • #6924 a94cbed Thanks @fubhy! - Ignore uniqueItems when set to false while importing JSON Schema documents.

  • #6871 9160ad7 Thanks @fubhy! - Fix LayerMap preload options so configured entries are acquired during construction.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP completion handlers now receive resolved argument context, and completion responses are limited to one hundred values.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now return protocol errors for invalid tool, prompt, completion, resource, and logging requests.

  • #6901 52494be Thanks @fubhy! - Prevent distinct metric attribute sets from sharing registry state.

  • #6822 5441c8e Thanks @fubhy! - Fix Metric.isMetric to recognize metrics using their current runtime brand.

  • #6821 c9b56ab Thanks @fubhy! - Fix Metric.linearBoundaries to space boundaries by the configured width.

  • #6847 8ef7257 Thanks @fubhy! - Fix MutableList.prepend on empty lists and handle non-positive toArrayN bounds.

  • #6865 1519406 Thanks @fubhy! - Fix OtlpResource to decode percent-encoded environment attributes and preserve bigint precision.

  • #6805 9716990 Thanks @tim-smart! - Prevent replay-enabled PubSubs from retaining values beyond each subscription’s replay window.

  • #6711 733f75b Thanks @andrskr! - Preserve serialization and retention metadata on reactive AtomRpc and AtomHttpApi queries.

  • #6855 48155c8 Thanks @fubhy! - Fix Schedule.during to recur until the configured duration has elapsed.

  • #6712 951d06b Thanks @gcanti! - Make Schema.isPattern deterministic for regular expressions with global or sticky flags.

  • #6782 d767b65 Thanks @gcanti! - SchemaRepresentation: generate references from encoded AST identity, suffix colliding identifiers instead of throwing, and preserve sharing across property-key context. This avoids false-positive duplicate identifier errors while keeping referentially distinct schemas addressable; generated fallback definitions now use the clearer Encoded suffix.

  • #6704 5d52d9d Thanks @gcanti! - Fix Union candidate selection for recovering middleware and suspended members.

  • #6848 f4151e1 Thanks @fubhy! - Keep the current ScopedRef resource alive when acquiring its replacement fails.

  • #6910 e02fbb6 Thanks @z4p5a9! - Fix Semaphore.withPermits leaking permits when interrupted between acquiring them and installing their release.

  • #6877 724ce09 Thanks @tim-smart! - Fix Stream.aggregateWithin and Stream.groupedWithin retaining fiber continuations on every schedule tick while upstream is idle.

  • #6889 dbe91f6 Thanks @tim-smart! - Fix Stream.withExecutionPlan retry limits resetting after partial stream emissions.

  • #6823 4c008d2 Thanks @fubhy! - Fix data-first dispatch for Stream.mapAccumArrayEffect.

  • #6900 b650832 Thanks @fubhy! - Ensure Stream.range emits the full range when the chunk size is zero.

  • #6849 b46c92f Thanks @fubhy! - Fix SubscriptionRef.getAndUpdateSome to return the current value when no update is selected.

  • #6808 5335797 Thanks @fubhy! - Fix SubscriptionRef.getAndUpdateEffect to execute the effectful update.

  • #6862 4b3460d Thanks @fubhy! - Fix Trie.longestPrefixOf returning a valued sibling that does not match the input key.

  • #6856 6301fd7 Thanks @fubhy! - Fix Trie to preserve entries whose value is undefined.

  • #6850 aebc5c6 Thanks @fubhy! - Fix TxPubSub.publishAll dropping values from one-shot iterables when a transaction retries.

  • #6851 52b2d7b Thanks @fubhy! - Ensure TxQueue.poll and TxQueue.clear complete a closing queue after draining its buffered items.

  • #6853 eec5744 Thanks @fubhy! - Fix TxQueue.offerAll to preserve one-shot iterables across transaction retries and repeated runs.

  • #6783 24e0e93 Thanks @tim-smart! - Propagate trace context through persisted cluster workflow requests.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now return standard JSON-RPC errors for malformed requests, unknown methods, and invalid parameters.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now enforce revision-specific JSON-RPC batch and protocol-version header requirements.

  • #6707 1a7ce81 Thanks @gcanti! - Mark Schema.UnknownFromJsonString as internal and remove its type-level interface. Use Schema.fromJsonString(Schema.Unknown) instead. Add reviver, callback or array replacer, and space options to Schema.fromJsonString, and make SchemaTransformation.fromJsonString a configurable factory.

  • #6828 48f22a7 Thanks @tim-smart! - Use layered storage for Context, making Context.add O(1) and eliminating per-request service map clones in the HTTP servers. Docgen now omits @internal option properties from generated signatures.

  • #6780 c96b7f6 Thanks @tim-smart! - Include typed tool output schemas in MCP tools/list responses.

  • #6733 6d2a942 Thanks @gcanti! - Avoid validating Schema.Class fields twice when decoding.

  • #6659 cc27b19 Thanks @tim-smart! - Preserve prototype accessors when code is compiled with loose object spread transforms.

  • #6912 8f9499f Thanks @gcanti! - Remove actual fields from every SchemaIssue variant, together with SchemaIssue.getActual, SchemaIssue.redact, and Schema.redact. Built-in formatters now use static messages that do not interpolate rejected input, while paths, AST metadata, union successes, and user-provided messages and annotations are preserved unchanged.

    Runtime performance was measured across the 16 Effect fixtures in the schema-benchmarks suite. These are the scenarios used for the cross-library comparison with Valibot and Zod. The paired HEAD-versus-main run classified 3 fixtures as improvements, 0 as regressions, and 13 as inconclusive. Negative changes are faster. Absolute library values are medians from the same cross-library run; means that the corresponding adapter does not expose that scenario.

    ScenarioEffect (ns/op)Valibot (ns/op)Zod (ns/op)HEAD vs mainClassification
    initialization-schema108191.3030549.81212715.66-0.92%inconclusive
    initialization-decoder109796.34+1.98%inconclusive
    validation-valid5221.805070.81+2.06%inconclusive
    validation-invalid1279.77234.92+0.59%inconclusive
    parsing-all-valid5144.585192.197176.19-3.79%inconclusive
    parsing-all-invalid7594.4915236.8237780.35-5.94%improvement
    parsing-first-valid5188.335135.75-1.49%inconclusive
    parsing-first-invalid1330.82243.64+1.01%inconclusive
    standard-all-valid5722.015200.053801.26-1.78%inconclusive
    standard-all-invalid12024.6515528.5030982.17-7.78%improvement
    standard-first-valid5655.33+3.84%inconclusive
    standard-first-invalid2001.69-4.56%inconclusive
    codec-typed-encode342.5939.29-7.62%inconclusive
    codec-typed-decode418.7850.14-10.89%improvement
    codec-unknown-encode328.38-5.55%inconclusive
    codec-unknown-decode347.35-5.25%inconclusive
  • #6692 3eeea73 Thanks @schickling-assistant! - Fix unstable CLI subcommands dropping operands after the -- end-of-options terminator.

  • #6625 0a532e5 Thanks @lloydrichards! - Add adapter-valued MCP server protocol declarations, route requests through the selected protocol before schema decoding, and add built-in support for MCP 2025-06-18.

  • #6864 f398149 Thanks @fubhy! - Honor HTTP-date Retry-After values when retrying OTLP exports.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP Streamable HTTP servers now validate content negotiation, session lifecycle, negotiated protocol versions, and browser Origins before dispatching requests.

  • #6824 ace903e Thanks @tim-smart! - Skip HTTP server span attribute collection when the span is not sampled.

  • #6814 e8eb62b Thanks @gcanti! - Refine Config loading and absence semantics. Config.schema now derives a provider loading policy from the encoded StringTree schema, materializes mixed-shape union members independently, and leaves separated scalar parsing to Config.Array and Config.Record. Schemas whose canonical StringTree encoding remains opaque, such as Schema.Any, Schema.Unknown, or Schema.Json, are rejected when the config is constructed; use a concrete shape or Schema.fromJsonString(Schema.Json) for scalar JSON. Missing or unavailable representations are decoded as undefined before Config.withDefault and Config.option decide absence. Partially supplied Config.all groups are rejected, successful values such as undefined and explicitly present empty structures are preserved, and the internal path prefix is removed from the public Config.parse signature.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now refresh roots after capable clients report that their root list changed.

  • #6828 48f22a7 Thanks @tim-smart! - Remove Context.mutate and Context.getReferenceUnsafe. Context updates now use overlays, and Context.get resolves reference defaults.

  • #6649 d48506d Thanks @gcanti! - Remove the keyValueCombiner option from Schema.Record and the corresponding SchemaAST.KeyValueCombiner and SchemaAST.IndexSignature.merge APIs. For transformed key collisions, sequential parsing keeps the later selected value, while concurrent parsing keeps the value applied last in completion order.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP servers now support session-scoped resource subscriptions on transports that can deliver server notifications and filter resource updates by each client’s subscribed URIs.

  • #6649 d48506d Thanks @gcanti! - Preserve untouched Result branches by identity in Result.map and Result.mapError.

  • #6649 d48506d Thanks @gcanti! - Improve Schema parsing, schema construction and adapter runtime performance while preserving current parsing behavior.

    Runtime performance

    The effect@beta, Valibot and Zod timing cases from open-circle/schema-benchmarks were reproduced as a dedicated runtimeperf suite. The table includes every case exposed by each upstream adapter; means that the adapter does not provide that benchmark.

    Effect main (45e781088) and the branch based on d775bf4b2 were compared with five paired processes per case, 150 ms measurement time and 50 ms warmup. The two initially inconclusive Effect cases were repeated with 15 paired processes, 500 ms measurement time and 150 ms warmup. Valibot and Zod values use five processes, 300 ms measurement time and 100 ms warmup. Environment: Node v24.12.0, macOS arm64, Apple M3.

    Zod parsing uses safeParse with { jitless: true }; its Standard Schema and codec cases use the corresponding native adapter APIs. All values are median microseconds per operation (µs/op), lower is better. Cross-library values are diagnostic because they are independent rather than paired measurements.

    ScenarioEffect mainEffect branchValibotZod 4Delta95% CIClassification
    Initialize schema137.28118.2340.24318.56-12.69%-21.02% to -5.35%improvement
    Initialize schema and decoder144.81130.50-10.88%-14.22% to -3.29%improvement
    Validate valid product8.4785.4155.63-35.18%-41.65% to -32.83%improvement
    Validate invalid product1.5161.3480.2431-11.59%-13.81% to -6.31%improvement
    Parse valid product, all errors8.3605.3665.227.16-36.28%-54.41% to -31.67%improvement
    Parse invalid product, all errors11.3029.10015.7041.58-19.42%-21.32% to -13.12%improvement
    Parse valid product, first error8.2015.2945.37-35.44%-37.75% to -34.59%improvement
    Parse invalid product, first error1.5101.3520.2572-10.51%-12.52% to -9.53%improvement
    Standard Schema valid, all errors9.2845.9355.353.83-35.96%-53.29% to -33.49%improvement
    Standard Schema invalid, all errors16.71815.20316.5132.85-11.31%-13.97% to -7.65%improvement
    Standard Schema valid, first error8.8895.843-34.17%-35.13% to -33.94%improvement
    Standard Schema invalid, first error2.4352.244-8.44%-12.76% to -4.82%improvement
    Typed codec encode0.46920.34200.0405-27.60%-32.35% to -22.50%improvement
    Typed codec decode0.51910.37620.0463-27.19%-34.75% to -22.71%improvement
    Unknown codec encode0.49100.3472-28.58%-30.42% to -27.59%improvement
    Unknown codec decode0.50610.3637-29.26%-29.82% to -21.70%improvement

    Overall Effect classification: 16 improvements and no regressions.

  • #6896 52262be Thanks @tim-smart! - Bind event-log read and write requests to the identities authenticated on their RPC connection.

  • #6735 1284aa1 Thanks @gcanti! - Fix three issues in the public Optic API:

    • Composed Iso and Prism setters no longer try to read a source value before writing.
    • Calling notUndefined on an Optional now returns an Optional, because writing can still fail.
    • The internal node property is no longer exposed by public optic types.
  • #6701 9867b9f Thanks @fubhy! - Removed explicit ./index entrypoints

  • #6875 979ce39 Thanks @fubhy! - Fix protobuf serialization of negative signed integers to use ten-byte two’s-complement varints.

  • #6696 b6d3e67 Thanks @tim-smart! - remove file descriptor type

  • #6860 adf6c6c Thanks @fubhy! - Honor custom split and strip regular expressions passed to String.noCase.

  • #6866 7314d60 Thanks @fubhy! - Fix partial file-backed HTTP bodies to report the selected byte range as their content length.

  • #6693 aeba0c8 Thanks @lloydrichards! - MCP HTTP servers now reject requests sent before initialization with the required lifecycle response.

  • #6759 1acbd8b Thanks @tim-smart! - Harden JSON-RPC wire message classification against inherited properties.

  • #6705 7bde6cc Thanks @tylergibbs1! - Restore the recursive option for FileSystem.watch, with non-recursive watching as the default.

  • #6798 a959a8b Thanks @tim-smart! - Namespace PostgreSQL advisory shard locks by the SqlRunnerStorage table prefix.

    This changes the advisory-lock protocol. PostgreSQL clusters using advisory locks require a full cluster stop before upgrading; a rolling deploy is unsafe because old and new runners use different lock keys and can both acquire the same shard.

4.0.0-beta.102

Patch Changes

  • #6563 b6392e1 Thanks @tim-smart! - unstable/reactivity Atom: add withEquality combinator for customizing how the registry detects value changes

  • #6574 7ed9450 Thanks @tim-smart! - unstable/http HttpClientRequest: add updateHeaders and removeHeader combinators for transforming or removing request headers, closes #6271

  • #6641 45762bd Thanks @tim-smart! - Add manual flushing to the OTLP exporters through a shared Flusher service exposed by each signal layer. The signal layer output types now include Flusher, and OtlpExporter.make requires it so custom exporters register unconditionally.

  • #6616 a6e8391 Thanks @tim-smart! - Add Tool.setNeedsApproval for replacing the approval policy of an existing tool.

  • 4ac7e8b Thanks @IMax153! - Add Effect.updateServiceScoped for updating a context service until the current scope closes, with customizable reset behavior.

  • #6593 4cd40f5 Thanks @tim-smart! - Fix Channel.mergeAll to propagate outer failures promptly and interrupt active inner channels.

  • #6610 6956bc0 Thanks @ebramanti! - Update McpServer.layerHttp to return 405 for unsupported HTTP methods, reject unsupported MCP-Protocol-Version headers with 400, and return an empty 202 for accepted notifications and responses.

  • #6608 0e50ec7 Thanks @gcanti! - Add Schema.Natural for non-negative safe integers and use canonical Schema.Int, Schema.Finite, and Schema.Natural schemas for numeric domain values across Effect, AI protocols, and OpenAPI patches.

    Update the date, date-time, file, time-zone, cluster, event-log, persistence, socket, SQL, and DevTools schemas to reject invalid non-finite or non-integer values where appropriate. Correct the decoded schema of Schema.NumberFromString, and allow Schema.DurationFromMillis and Schema.DurationFromNanos to represent negative durations.

  • #6599 9fcdade Thanks @tim-smart! - Interrupt in-flight stream pulls when closing an async iterator.

  • #6638 57367d5 Thanks @tim-smart! - Fix PartitionedSemaphore.take leaking partially acquired permits when interrupted.

  • #6615 35c445f Thanks @tim-smart! - Expose the tool call ID to AI tool handlers and Toolkit.WithHandler.handle wrappers.

  • #6561 c917bb9 Thanks @hsubra89! - Reject unexpected positional arguments left after command parsing, including values exceeding Argument.variadic maximum bounds.

  • #6613 bc1f358 Thanks @tim-smart! - Ignore duplicate chunk indexes when joining event log messages.

  • #6552 0e0c9d7 Thanks @xianjianlf2! - Fix a race where FiberHandle.clear could remove a newer fiber installed while the previous fiber was still interrupting.

  • #6598 73d40aa Thanks @tim-smart! - Fix LanguageModel.streamText to apply the configured concurrency limit to tool call resolution, including approval checks.

  • #6637 4f1e318 Thanks @tim-smart! - Fix Latch open/release resuming waiters that registered after a subsequent close.

    Latch.open and Latch.release schedule the waiter flush on the fiber’s dispatcher. Previously the flush drained whatever waiters existed at flush time, so a waiter that registered after the latch was closed again could be resumed by the stale flush. The waiters are now snapshotted at schedule time, so only waiters covered by an open/release call are resumed.

  • #6614 9d8d85c Thanks @tim-smart! - Fix histogram and summary maximum values for negative-only observations.

  • #6634 6079fda Thanks @fubhy! - Fix OTLP exporter shutdown to await in-flight and final buffered exports up to the configured shutdown timeout.

  • #6567 5101e92 Thanks @gcanti! - Add Record.assignProperty and safely handle dynamic record keys such as __proto__ and inherited property names.

  • #6592 d0b3265 Thanks @tim-smart! - Fix Stream.haltWhen to observe halt effects at pull boundaries for synchronous streams.

  • #6618 7a03c89 Thanks @tim-smart! - unstable/cluster: hash over-length SQL message deduplication keys to prevent message_id overflow, closes #6317.

    The composed request deduplication key (entityType/entityId/tag/primaryKey) can legally exceed the 255-character message_id column — the address columns alone allow 458 characters before the RPC primary key is appended. SqlMessageStorage now stores a SHA-256 digest (64 hex characters) of the composed key in the unique message_id column when the key exceeds 255 characters, so keys of any length work on PostgreSQL, MySQL, MSSQL, and SQLite. Keys that fit are stored as plaintext, byte-compatible with rows written by previous versions, so existing deployments keep deduplicating with no migration or schema change.

    SqlMessageStorage.layer/layerWith (and consequently SingleRunner.layer) now require Crypto.Crypto. The Node and Bun cluster convenience layers provide the platform Crypto implementation internally, so their requirements are unchanged.

  • #6577 cea1d9c Thanks @tim-smart! - ManagedRuntime: add Symbol.asyncDispose, enabling await using syntax

    import { Effect, Layer, ManagedRuntime } from "effect";
    await using runtime = ManagedRuntime.make(Layer.empty);
    await runtime.runPromise(Effect.log("Hello, world!"));
    // runtime is disposed automatically at the end of the scope
  • #6644 078e1f5 Thanks @gcanti! - Improve the performance of Array.dedupe, Array.union, Array.intersection, Array.difference, and Schema unique item validation by using hash-based equality lookup.

  • #6609 97bafea Thanks @tim-smart! - Allow embedding usage input tokens to be omitted during decoding, including after JSON serialization.

  • #6606 fab0ab8 Thanks @tim-smart! - Allow optional AI response fields to be omitted during decoding, including after JSON serialization.

  • #6607 c323d8b Thanks @ebramanti! - Prevent MCP tool failures from exposing Cause rendering, stack traces, and internal paths while preserving actionable validation messages.

  • #6576 6966353 Thanks @tim-smart! - Record: make fromIterableBy dual, allowing data-last usage in pipe

    import { pipe, Record } from "effect";
    const users = [
    { id: "2", name: "name2" },
    { id: "1", name: "name1" },
    ];
    pipe(
    users,
    Record.fromIterableBy((user) => user.id),
    );
  • #6622 0444004 Thanks @gcanti! - Remove the experimental SchemaUtils module and its getNativeClassSchema helper. The helper duplicated a composition already available through the primary Schema APIs and did not justify a separate public module.

  • #6653 028bbb3 Thanks @tim-smart! - Remove Effect.withConcurrency, the References.CurrentConcurrency reference backing it, and the "inherit" option from Types.Concurrency. Use an explicit number or "unbounded" concurrency value instead.

  • #6620 ff5d6e2 Thanks @gcanti! - Make Schema.Date reject invalid dates and remove the redundant Schema.DateValid, Schema.isDateValid, and Schema.isDateValidReviver APIs.

    Schema.DateFromString and Schema.DateFromMillis now fail decoding when their input would produce an invalid date.

    Remove Schema.Annotations.ToArbitrary.GenerationConstraint.valid; Schema.Date arbitraries now generate only valid dates by default.

  • #6575 1bfce93 Thanks @gcanti! - Schema: make schemas directly extendable as classes with static method support and remove Schema.asClass.

    Bottom and BottomLazy now include the class-compatible new signature, while BottomWithoutNew and BottomLazyWithoutNew expose the schema protocol without it for schema types that define a specialized construct signature.

    Example

    import { Schema } from "effect";
    class MyString extends Schema.String {
    static readonly decodeUnknownSync = Schema.decodeUnknownSync(this);
    }
    MyString.decodeUnknownSync("a"); // "a"
  • #6424 7ce815c Thanks @gcanti! - Refactor the SchemaRepresentation module to improve clarity and maintainability.

    The representation pipeline is now open and compiler-extensible. The same encoded-side representation is used for JSON persistence, runtime reconstruction, JSON Schema Draft 2020-12 compilation, TypeScript code generation, AI structured output, and HTTP / OpenAPI schemas.

    New representation model

    • Add RepresentationAnnotation and CheckRepresentationAnnotation, which identify declarations and checks with a stable id, JSON payload, and optional schema dependencies.
    • Preserve checks on every non-reference representation node instead of storing constraints in the previous closed meta unions.
    • Add compiler hooks for checks and declarations through SchemaRepresentation.ToJsonSchema and SchemaRepresentation.Generation.
    • Add SchemaMultiDocument, fromSchemaMultiDocument, and fromRepresentations so several live schemas and named definitions can be converted and reconstructed together. Explicit definitions are preserved even when no root references them.
    • Preserve shared structural nodes, annotated recursion, union member order, identifiers, reference siblings, and structural checks when projecting encoded schemas.

    Persistence and revivers

    • Add toJson, fromJson, toJsonMultiDocument, and fromJsonMultiDocument as the persistence boundary for representation documents.
    • Live representations store literal, enum, and property-name scalars as native values. JSON persistence encodes them as { type, value } tagged unions so their runtime types remain distinct across persistence formats, canonically encodes structural bigint and global symbol values, keeps JSON-valued annotations, and removes runtime-only callbacks and other non-JSON annotation values.
    • Replace the generic reviver callback with typed DeclarationReviver, FilterReviver, and FilterGroupReviver contracts. Add makeDeclarationReviver, makeFilterReviver, and makeFilterGroupReviver, which infer their payload type from payloadSchema.
    • Resolve acyclic references to concrete runtime schemas and reserve Schema.suspend wrappers for recursive back-edges. Acyclic alias chains may be normalized while preserving the outer reference identifier.
    • Export individual revivers for built-in declarations and checks from Schema. Consumers opt in to exactly the revivers accepted when reconstructing persisted documents:
      • declaration revivers: OptionReviver, ResultReviver, RedactedReviver, CauseReasonReviver, CauseReviver, ErrorReviver, ExitReviver, ReadonlyMapReviver, HashMapReviver, ReadonlySetReviver, HashSetReviver, ChunkReviver, RegExpReviver, URLReviver, DateReviver, DurationReviver, BigDecimalReviver, FileReviver, FormDataReviver, URLSearchParamsReviver, Uint8ArrayReviver, DateTimeUtcReviver, TimeZoneOffsetReviver, TimeZoneNamedReviver, TimeZoneReviver, DateTimeZonedReviver, JsonReviver, and MutableJsonReviver
      • check revivers: isTrimmedReviver, isPatternReviver, isStringFiniteReviver, isStringBigIntReviver, isStringSymbolReviver, isUUIDReviver, isGUIDReviver, isULIDReviver, isBase64Reviver, isBase64UrlReviver, isStartsWithReviver, isEndsWithReviver, isIncludesReviver, isUppercasedReviver, isLowercasedReviver, isCapitalizedReviver, isUncapitalizedReviver, isFiniteReviver, isGreaterThanReviver, isGreaterThanOrEqualToReviver, isLessThanReviver, isLessThanOrEqualToReviver, isBetweenReviver, isMultipleOfReviver, isIntReviver, isDateValidReviver, isGreaterThanDateReviver, isGreaterThanOrEqualToDateReviver, isLessThanDateReviver, isLessThanOrEqualToDateReviver, isBetweenDateReviver, isGreaterThanBigIntReviver, isGreaterThanOrEqualToBigIntReviver, isLessThanBigIntReviver, isLessThanOrEqualToBigIntReviver, isBetweenBigIntReviver, isMinLengthReviver, isMaxLengthReviver, isLengthBetweenReviver, isMinSizeReviver, isMaxSizeReviver, isSizeBetweenReviver, isMinPropertiesReviver, isMaxPropertiesReviver, isPropertiesLengthBetweenReviver, isPropertyNamesReviver, and isUniqueReviver
    • Validate reviver payloads with their payloadSchema, and report missing or duplicate reviver identifiers.

    JSON Schema and code generation

    • Compile JSON Schema from the canonical JSON codec and the encoded-side representation. Custom checks can contribute constraints through Annotations.Filter.toJsonSchema without modifying a central metadata registry.
    • Import JSON Schema directly as live schemas. The importer now supports shared definitions, aliases, recursion, reference siblings, and definitions that are not reachable from a root.
    • Add the named FromJsonSchemaOptions type for the importer onEnter callback.
    • Generate code from live toCode annotations on declarations and checks. Compiler callbacks receive generated type parameters or schema dependencies and can emit multiple import declarations.
    • Add import artifacts to CodeDocument and preserve all explicit definitions during multi-document code generation.
    • Reject distinct schemas that declare the same identifier instead of silently merging them or generating suffixed references.

    Canonical codecs and integrations

    • Preserve schema identifiers, property context, key encodings, and applicable checks while deriving canonical JSON codecs.
    • Treat Schema.Json and Schema.MutableJson as already canonical. JSON validation now rejects sparse arrays, and non-finite numbers decode only from the canonical strings "Infinity", "-Infinity", and "NaN" rather than raw non-finite numeric inputs.
    • Declarations without toCodecJson or toCodec now use JSON validation as their fallback instead of silently encoding to null. toCodecJson callbacks may return undefined when a declaration is already canonical.
    • Add Annotations.Declaration.toCodecStringTree; StringTree derivation now requires a declaration to provide a structural StringTree, JSON, or general codec instead of silently encoding an opaque declaration to undefined.
    • Update AI structured-output, HTTP schema, HttpApi OpenAPI, and OpenAPI generator integrations to consume the same canonical encoded representation and compiler hooks. Provider-specific structured-output transforms may remove unsupported JSON Schema keywords, while the Effect codec remains the validation authority.

    Breaking changes

    • Rename the low-level representation constructors:
      • SchemaRepresentation.fromAST -> SchemaRepresentation.toRepresentation
      • SchemaRepresentation.fromASTs -> SchemaRepresentation.toRepresentations
    • Replace SchemaRepresentation.toSchema with fromRepresentation, and add fromRepresentations for multi-root documents. Both reconstruction functions require { revivers: [...] }; no default reviver is installed implicitly.
    • Remove SchemaRepresentation.toSchemaDefaultReviver. Pass the required built-in revivers exported by Schema, or custom revivers created with the new constructors.
    • Replace DocumentFromJson and MultiDocumentFromJson with the toJson / fromJson and toJsonMultiDocument / fromJsonMultiDocument functions.
    • The persisted Document and MultiDocument format is incompatible with the previous format. Nodes now contain checks; encoded literal values, enum values, and property signature names use tagged { type, value } objects while decoded documents expose their native scalar values; declarations no longer contain encodedSchema; persisted opaque declarations and leaf filters require a { id, payload } representation identity; and checks no longer contain closed meta payloads. Regenerate stored documents from their source schemas with the new API, or migrate their shape before passing them to fromJson.
    • Replace the generic Reviver<T> function type with DeclarationReviver<P>, FilterReviver<P>, FilterGroupReviver<P>, CheckReviver<P>, Reviver<P>, and AnyReviver.
    • Remove the closed metadata types StringMeta, NumberMeta, BigIntMeta, ArraysMeta, ObjectsMeta, DateMeta, SizeMeta, DeclarationMeta, and Meta from SchemaRepresentation.
    • Remove the exported representation validation schemas and PrimitiveTree: $PrimitiveTree, $Annotations, $Null, $Undefined, $Void, $Never, $Unknown, $Any, $StringMeta, $String, $NumberMeta, $Number, $Boolean, $BigInt, $Symbol, $LiteralValue, $Literal, $UniqueSymbol, $ObjectKeyword, $Enum, $TemplateLiteral, $Element, $Arrays, $PropertySignature, $IndexSignature, $ObjectsMeta, $Objects, $Union, $Reference, $DateMeta, $SizeMeta, $DeclarationMeta, $Declaration, $Suspend, $Representation, $Document, and $MultiDocument.
    • Replace schema annotations as follows:
      • remove Annotations.Bottom.meta and Annotations.Filter.meta
      • remove Annotations.Declaration.typeConstructor; use representation
      • remove Annotations.Declaration.generation; use the toCode callback
      • add Annotations.Filter.representation, toJsonSchema, and toCode
      • add Annotations.Augment.contentSchema as a JSON-valued annotation
      • allow Annotations.Declaration.toCodecJson and toCodecStringTree to return undefined
    • Remove the top-level contentMediaType and contentSchema fields from SchemaRepresentation.String. Content metadata is now carried in ordinary annotations, and contentSchema is a JSON Schema value rather than a nested Effect representation.
    • Remove Schema.Annotations.BuiltInMetaDefinitions, BuiltInMeta, MetaDefinitions, and Meta. Custom checks should carry a representation identity and compiler callbacks instead of augmenting the metadata registry.
    • fromJsonSchemaDocument now returns Schema.Top instead of a representation Document. fromJsonSchemaMultiDocument now returns SchemaMultiDocument instead of MultiDocument; call fromSchemaMultiDocument when a representation multi-document is required.
    • toCodeDocument now accepts only a live MultiDocument; remove its reviver option. Reconstruct persisted documents first so revivers can restore runtime compiler callbacks.
    • Rename the generation field of Artifact values for symbols and enums to code. Declaration generation no longer has an Encoded output, and importDeclaration is replaced by importDeclarations on callback output.
    • Remove the exported sanitizeJavaScriptIdentifier, topologicalSort, and TopologicalSort helpers.
    • Negative zero no longer receives special representation handling. Do not rely on preserving its sign across JSON persistence or generated code, where it may be normalized to 0.
    • With { errors: "all" }, structural checks run only after their base array, object, or declaration parses successfully; they are no longer added to an already failing child parse.
  • #6646 7271a7f Thanks @gcanti! - Precompile union formatters and equivalences, select transformed union members using their decoded type, and allow deriving an equivalence for Never.

  • #6516 475fe5c Thanks @tim-smart! - Prevent SQL runner lock refreshes from hanging when reserved connections become unresponsive.

4.0.0-beta.101

Patch Changes

  • #6545 731bea1 Thanks @tim-smart! - Interrupt and await concurrent traversal workers when mapper or refill callbacks throw.

  • #6545 731bea1 Thanks @tim-smart! - Preserve current stack frame annotations on terminal root failures.

  • #6545 731bea1 Thanks @tim-smart! - Store interrupting fiber stack frames separately from interrupted target stack frames.

  • #6545 731bea1 Thanks @tim-smart! - Avoid allocating a scheduler dispatcher when runSyncExit completes without yielding.

  • #6545 731bea1 Thanks @tim-smart! - Make awaitAllChildren child selection linear in the number of fibers.

  • #6523 b35ed29 Thanks @gcanti! - Simplify the displayed Type, Encoded, and Iso types of required readonly Schema.Struct fields, closes #6521.

  • #6514 dd44624 Thanks @tim-smart! - Fix MutableList.filter leaving an invalid empty bucket when no values match.

  • #6545 731bea1 Thanks @tim-smart! - Deliver pending interrupts when interruptibleMask restores fiber interruptibility.

  • #6526 2bae1ac Thanks @tim-smart! - Fix HttpRouter.toWebHandler middleware inference to exclude request services supplied by the HTTP adapter.

4.0.0-beta.100

Patch Changes

  • #6501 c1288dd Thanks @gcanti! - Add a discriminants tuple to schemas augmented with Schema.toTaggedUnion and reject duplicate discriminant property keys.

  • #6475 2b58a3d Thanks @fubhy! - Normalize cron month and weekday aliases independently of the host locale.

  • #6492 6dc83f2 Thanks @gcanti! - Preserve nested class construction when applying constructor defaults, closes #6491.

  • #6476 c1e2fe0 Thanks @fubhy! - Add Cron day and weekday intersection semantics in inspection representations.

  • #6474 f3fbae8 Thanks @fubhy! - Validate Cron.make field constraints and treat weekday 7 as Sunday consistently with cron parsing.

  • #6472 e000f80 Thanks @fubhy! - Fix Cron.prev day-of-month rollover across shorter months and non-leap years.

  • #6471 f4ee765 Thanks @fubhy! - Fix Cron.prev weekday wrapping to always return a matching instant before the input.

  • #6477 510b55f Thanks @fubhy! - Make Cron equality and hashing include the optional timezone consistently.

  • #6433 31d3fc4 Thanks @coyaSONG! - Fix the published declaration for HttpEffect.appendPreResponseHandlerUnsafe.

  • #6487 875e618 Thanks @rvaccone! - Fix doubled Expected: Expected ... prefixes in CLI InvalidValue error messages, closes #6312.

  • #6496 688d46a Thanks @tim-smart! - Port Effect.reduce from Effect v3.

  • #6480 6ff5023 Thanks @fubhy! - Correct the diagnostic for cron step values above a field’s maximum.

  • #6484 c0333e7 Thanks @tim-smart! - Fix fiber self-interuption from inside a running operation

  • #6493 06e7e8c Thanks @tim-smart! - Make multipart errors respond with an HTTP status based on their reason and ignore them in the error reporter.

  • #6498 eb9b102 Thanks @thewilkybarkid! - Don’t create a table when it’s not needed

  • #6494 8b155da Thanks @tim-smart! - only interrupt cache lookup when all awaiters are gone

  • #6495 3a87335 Thanks @tim-smart! - clean up more references on fiber exit

4.0.0-beta.99

Patch Changes

  • #6397 8ce4795 Thanks @IMax153! - Add a scoped CliConfig service for customizing the built-in global flags used by CLI command runners.

    For example, provide an explicit list that omits GlobalFlag.LogLevel to remove the built-in --log-level flag:

    import { Effect } from "effect";
    import { CliConfig, Command, GlobalFlag } from "effect/unstable/cli";
    const program = Command.run(command, { version: "1.0.0" }).pipe(
    Effect.provide(
    CliConfig.layer({
    builtIns: [GlobalFlag.Help, GlobalFlag.Version, GlobalFlag.Completions],
    }),
    ),
    );
  • #6409 80b539f Thanks @IMax153! - Reintroduce interactive CLI wizard mode through the --wizard flag and Command.wizard.

  • #6394 88a54cc Thanks @lloydrichards! - add a radius option to Graph search configuration, allowing dfs, bfs, and dfsPostOrder traversals to limit returned nodes by edge distance from the configured start nodes. Traversals can also use direction: "undirected" to follow edges in either direction.

  • #6457 e6e6dba Thanks @fubhy! - Improve Graph.dijkstra and Graph.astar priority queue performance.

  • #6468 bfb203e Thanks @gcanti! - Distribute HttpApiBuilder handler requirements per service so request middleware layers can provide them, closes #6464.

  • #6389 2e9a34a Thanks @IMax153! - Report an error when a CLI flag, including --completions, is provided without its required value.

  • #6359 55d4eb3 Thanks @evermake! - - Fix Command.withSubcommands collapsing the inferred requirements type to never when given more than one subcommand

    • Export a Command.Services utility type to extract the required services from a Command
  • #6462 bddb010 Thanks @fubhy! - Fix immutable Graph equality and hashing to include future node and edge identifier allocation.

  • #6425 a328835 Thanks @fubhy! - Fix Graph.bellmanFord to detect reachable negative cycles when the source and target are the same node.

  • #6454 5560d05 Thanks @fubhy! - Fix standalone data-last Graph.getNode and Graph.getEdge inference.

  • #6418 8f6e3ad Thanks @fubhy! - Fix Graph.mapEdges and Graph.filterMapEdges to preserve Graph.Edge instances when transforming edge data.

  • #6426 46997fa Thanks @fubhy! - Reject NaN and -Infinity edge weights in Graph shortest-path algorithms.

  • #6461 9e6e12d Thanks @fubhy! - Fix mutable Graph equality and hashing to use reference identity while preserving structural semantics for immutable graphs.

  • #6456 3394b93 Thanks @fubhy! - Fix topological walkers silently completing with an incomplete order when a mutable graph becomes cyclic after walker creation.

  • #6460 febeabc Thanks @fubhy! - Restrict Graph.topo to directed graphs at the type level while retaining runtime validation for unsafe undirected inputs.

  • #6455 54161c9 Thanks @fubhy! - Fix Graph.Walker to create a fresh iterable for each direct iteration.

  • #6414 385f7a4 Thanks @fubhy! - Fix Graph.toGraphViz to quote DOT graph names and escape labels as literal text.

  • #6438 7eea4d0 Thanks @tim-smart! - Fix one-shot iterable handling in Array.rotate, Iterable.cartesian, and in-memory RunnerStorage acquisition

  • #6371 7543afe Thanks @polRk! - Tool: preserve the tool kind when cloning provider-defined and dynamic tools.

    Tool.addDependency, setParameters, setSuccess, setFailure, annotate, and annotateMerge previously rebuilt the tool as a user-defined tool, which flipped Tool.isProviderDefined to false, corrupted the provider id (e.g. anthropic.memory_20250818), and crashed Tool.getStrictMode. These operations now clone the tool while preserving its prototype, id, and kind. Provider-defined tools also now carry an empty annotations context so Tool.getStrictMode/annotate work on them. Closes #2615.

  • #6421 44b9cf3 Thanks @fubhy! - Preserve null edge data in Graph.floydWarshall costs.

  • #6438 7eea4d0 Thanks @tim-smart! - ensure one-shot iterables work with Fiber apis

  • #6420 0a8aa6a Thanks @fubhy! - Fix Graph.isAcyclic to detect cycles formed by parallel undirected edges.

  • #6417 c8d9fcf Thanks @fubhy! - Reject Graph mutation operations on mutable handles after Graph.endMutation finalizes them.

  • #6423 9ca7f9a Thanks @fubhy! - Fix Graph.isGraph narrowing for mutable and undirected graphs.

  • #6459 e7aca89 Thanks @fubhy! - Reject asynchronous Graph mutation callbacks and finalize scoped mutable handles when callbacks fail.

  • #6458 55d7560 Thanks @fubhy! - Fix undirected Graph equality and hashing to ignore stored edge endpoint orientation.

  • #6415 f809189 Thanks @fubhy! - Fix Graph.Walker iteration for receiver-sensitive iterables.

  • #6394 88a54cc Thanks @lloydrichards! - added graph set operations for combining and comparing graphs

    • Graph.make - creates a graph constructor for a dynamically selected graph kind
    • Graph.compose - composition of two graphs, merging nodes by identity
    • Graph.intersection - intersection of two graphs, keeping only common nodes and edges
    • Graph.difference - difference of two graphs, removing edges present in the second graph
    • Graph.symmetricDifference - symmetric difference of two graphs, keeping edges present in exactly one graph
  • #6395 0ebdbe7 Thanks @Chaoran-Huang! - Fix multipart parser limit violations being silently swallowed

  • #6419 7517d09 Thanks @fubhy! - Make the public Graph interfaces opaque by hiding internal mutable storage fields from their TypeScript surface.

  • #6390 212493b Thanks @alvarosevilla95! - Fix Redis script evaluation so transient SCRIPT LOAD failures are retried instead of being cached indefinitely.

  • #6394 88a54cc Thanks @lloydrichards! - add advanced graph set operations for deriving related graph structures

    • Graph.complement - complement over the existing node set, adding missing edges between distinct nodes
    • Graph.neighborhood - induced subgraph containing nodes within a radius of a node
    • Graph.sum - disjoint union of two graphs without merging equal node data
  • #6430 80ea8cb Thanks @fubhy! - Fix Graph BFS, topological sort, and DFS postorder iterators to skip nodes removed from a MutableGraph without recursive self-calls.

  • #6465 8df19f4 Thanks @gcanti! - Fix isInt32 to apply custom annotations only to its filter group.

4.0.0-beta.98

Patch Changes

  • #2587 989603b Thanks @gcanti! - Expose SchemaError as a public module and re-export Schema.isSchemaError.

    This gives consumers a stable import path and guard for schema failures without depending on the internal schema implementation, while preserving the existing Schema.SchemaError surface.

  • #2592 214c458 Thanks @gcanti! - Apply transformClient when building an individual HttpApi endpoint client, preserving the supplied client’s error and service channels.

  • #2598 a037273 Thanks @gcanti! - Preserve __proto__ group and endpoint identifiers in HTTP APIs, generated clients, and URL builders.

  • #2578 97fdaa9 Thanks @tim-smart! - Fix Atom.kvs async mode to retain its AsyncResult value shape after writes.

  • #2612 b24d248 Thanks @gptguy! - Fix replay of persisted DurableDeferred.raceAll results.

  • #2580 19c222c Thanks @gcanti! - Fix HttpApi authorization decoding.

    Previously, HttpApiBuilder.securityDecode removed the expected scheme length and one following character from the Authorization header without verifying either value. A Bearer decoder could therefore pass credentials from a different scheme such as Basic, accept a malformed header without a separating space, or retain leading spaces when more than one separator was present.

    The decoder now validates the declared scheme before returning credentials, matches it case-insensitively as required by RFC 9110 section 11.1, and consumes one or more separating spaces. Missing, malformed, or mismatched headers produce the existing empty credential value so security middleware can reject them consistently.

    Basic authentication previously split the decoded user-pass value at every colon, causing otherwise valid passwords containing : to be discarded. It now uses only the first colon as the separator and preserves the rest of the password, following RFC 7617 section 2.

  • #2581 eec85dd Thanks @gcanti! - Fix HttpApi client error decoding.

    Generated clients previously combined every error schema for a status into one union decoder. When schemas used different encodings, their declaration order could determine the decoded error instead of the response Content-Type; for example, a text decoder could accept a JSON response before the JSON decoder was tried.

    Error responses are now grouped and selected by normalized content type, matching buffered success responses. Normalization happens before grouping, so declarations that differ only by casing or parameters such as charset share one union decoder instead of making later schemas unreachable.

    No-content schemas are represented by a headerless alternative, allowing empty error responses without a Content-Type header to decode correctly. Unsupported content types preserve the existing combination of StatusCodeError and the response decoding failure.

  • #2605 0082f4f Thanks @gcanti! - Fix Number.remainder for very small and large values formatted in scientific notation.

  • #2611 8849052 Thanks @tim-smart! - Fix PersistedQueue to count schema decoding and malformed SQL payload failures as processing attempts.

  • #2500 c15e16a Thanks @hsubra89! - Fix Redis-backed PersistedQueue reset and failed-item handling.

  • #2602 01d00a3 Thanks @gcanti! - Fix a bug where decoding bracket paths from FormData or URLSearchParams could mutate inherited object prototypes.

  • #2588 8bd4589 Thanks @gcanti! - Fix SchemaAST.isJson to reject class instances and other non-record objects.

  • #2605 0082f4f Thanks @gcanti! - Fix JSON Schema allOf imports for tuple intersections and preserve primitive refinements when combining literal constraints.

  • #2604 6e08428 Thanks @gcanti! - Fix Schema.toFormatter and Schema.toEquivalence indexing for tuples with multiple post-rest elements.

  • #2603 388dcf9 Thanks @gcanti! - Fix union candidate selection and decoding order so that unions now:

    • consider matches from every sentinel key instead of dropping valid members after the first match;
    • reject ambiguous oneOf inputs when members with different sentinel keys both match;
    • preserve declared member order when combining discriminated members with non-discriminated fallbacks;
    • commit concurrent decoding results in declaration order instead of completion order.

    Reserved SSE failure event names with non-Cause data are now emitted as application events instead of producing a runtime defect.

  • #2609 2b7ce2b Thanks @tim-smart! - Fix SQL-backed persisted queues to refresh locks for actively acquired elements.

  • #2583 87bea7e Thanks @MrGovindan! - Fixed Clock.sleep handling of large durations

  • #2582 ce38dc3 Thanks @gcanti! - Harden HttpApi documentation HTML rendering.

    Scalar descriptions and CDN versions were interpolated without attribute-safe escaping. Embedded OpenAPI JSON in Scalar and Swagger also handled only the exact </script> sequence, not other valid script end-tag forms.

    Attribute values and CDN versions are now encoded for their contexts, and embedded JSON escapes < so it cannot close its script element.

  • #2591 a807cd1 Thanks @gcanti! - Keep HttpApi composition immutable.

    HttpApi.addHttpApi applied annotations from the added API by mutating its shared groups. It now creates annotated group copies, keeping the source API and independently annotated variants unchanged while preserving annotation precedence.

  • #2584 fd8a356 Thanks @gcanti! - Normalize HttpApi payload media types.

    Payload schemas were stored under their exact declared Content-Type, but the server lowercased the incoming header and removed its parameters before looking it up. For example, a schema declared as Application/Vnd.Effect+JSON; profile=declared was stored under that value, while the server looked for application/vnd.effect+json. This could produce a 415 response even when the generated client and server used the same API.

    The same mismatch allowed incompatible encodings for equivalent media types to bypass validation. Generated form-urlencoded requests also ignored custom content types and always used the default one.

    Payload maps now use normalized keys for matching and conflict checks, while each encoding keeps its declared content type. Generated requests and OpenAPI use the declared values, including every parameterized variant, and custom form-urlencoded content types are preserved.

  • #2476 c2a5edc Thanks @gcanti! - Improve unstable HttpApi type-level performance.

    The implementation now uses identifier-keyed maps and lighter structural constraints in several hot type-level paths. Generated group clients consume the concrete endpoint map directly instead of rebuilding it from the endpoint union.

    New Features

    • Add HttpApiBuilder.Handlers.handleAll, which registers an identifier-keyed batch of endpoint handlers for a group. Each entry can be either a handler function or { handler, options }, and the object can be supplied in multiple partial batches. Endpoint identifiers that were already handled are rejected across batches.
    • HttpApi.groups now preserves the concrete group type for each group identifier. For example, Api.groups.users is typed as the users group instead of the full group union.
    • HttpApiGroup.endpoints now preserves the concrete endpoint type for each endpoint identifier. For example, Group.endpoints.getUser is typed as the getUser endpoint instead of the full endpoint union.
    • HttpApiEndpoint values can now be extended as classes, matching the class-like runtime shape already used by HttpApi and HttpApiGroup.

    Measured Type-Level Performance

    Main/current comparisons use identical generated fixtures compiled once per revision with TypeScript 7.0.2. The recorded revisions are main at 97fdaa9c1f52 and the branch source at 5798fc5fafcd. The focused pre/post curves below were captured with the regular httpapi regression suite during development. The retained suite uses representative stress points instead of rerunning every point in those historical curves. All numbers are type-instantiation deltas over the corresponding shared baseline.

    Endpoint declaration costs now grow with a lower slope:

    endpointsmaincurrent
    104,5802,808
    5015,5009,168
    10029,15017,118
    500138,35080,718

    Class-like endpoint declarations are slightly cheaper than inline endpoint values in the same 500-endpoint fixture shape:

    fixtureinlineclass-like
    500 endpoints82,20771,850

    HttpApiBuilder fluent handler registration avoids the previous non-linear blow-up in the cross-ref comparison:

    fixturemaincurrent
    10 endpoints37,85611,582
    50 endpoints568,57663,702
    100 endpoints2,154,476182,852
    500 endpoints51,741,6763,296,052
    500 raw handlers51,734,1763,294,550

    In the recorded regular-suite measurements, handleAll remains the scalable alternative to the equivalent fluent chain:

    fixturefluenthandleAll
    10 endpoints11,5799,146
    50 endpoints63,69925,106
    100 endpoints182,84945,056
    500 endpoints3,296,049204,656
    500 eps, two batches3,296,049223,613

    Generated-client type production also improves for the hot method-building paths:

    fixturemaincurrent
    client methods, 500 endpoints245,795176,850
    top-level client methods, 500 endpoints243,651179,809
    client endpoint method, 500 endpoints56,73846,294
    client groups, 100 groups x 5 endpoints49,01925,893

    The following focused curves were captured immediately before and after each isolated type-level change.

    The focused Client.Group curve shows the improvement from consuming the identifier-keyed endpoint map directly:

    endpointsunion remappingendpoint map
    1012,44812,294
    5019,16918,935
    10027,57027,236
    50094,77093,636

    The focused Client.TopLevelMethods curve improves by reading endpoint identifiers directly from the endpoint union:

    endpointspre-changepost-change
    1012,53112,476
    5019,25219,197
    10027,65327,598
    50094,85394,798

    The focused HttpApiClient.endpoint selection curve improves by reading endpoint identifiers directly from the selected endpoint union:

    endpointspre-changepost-change
    107,6667,588
    508,7078,629
    10010,0089,930
    50020,40820,330

    The focused HttpApiBuilder.endpoint selection curve improves by reading endpoint identifiers directly from the selected endpoint union:

    endpointspre-changepost-change
    1012,82812,745
    5013,86913,786
    10015,17015,087
    50025,57025,487

    URL builder types now avoid repeatedly expanding the full API/group shape:

    fixturemaincurrent
    URL builder, 500 endpoints211,35691,610
    top-level URL builder, 500 endpoints210,72493,118
    builder endpoint, 500 endpoints62,89451,952

    Breaking Changes

    These changes affect unstable HttpApi type-level APIs and structural API, group, and endpoint types.

    Renamed Constraint Types

    • Broad structural constraint exports have been renamed to align with Schema.Constraint terminology: HttpApi.Any to HttpApi.Constraint, HttpApi.AnyWithProps to HttpApi.Top, HttpApiGroup.Any to HttpApiGroup.Constraint, HttpApiGroup.AnyWithProps to HttpApiGroup.Top, and HttpApiEndpoint.Any to HttpApiEndpoint.Constraint.
    • HttpApiEndpoint.AnyWithProps has been replaced by HttpApiEndpoint.Top, whose schema parameters are constrained to Schema.Top, including success and error schemas.
    • Type guards now expose the widened runtime-prop shapes: HttpApi.isHttpApi returns HttpApi.Top, HttpApiGroup.isHttpApiGroup returns HttpApiGroup.Top, and HttpApiEndpoint.isHttpApiEndpoint returns HttpApiEndpoint.Top.
    • HttpApiGroup.ApiGroup has been renamed to HttpApiGroup.Service.

    API, Group, And Endpoint Shapes

    • HttpApi.groups is now typed as an identifier-keyed group map instead of ReadonlyRecord<string, Groups>, and HttpApi tracks its group union invariantly. Dynamic string indexing must refine the key first or cast to a broad runtime record.
    • HttpApiGroup.endpoints is now typed as an identifier-keyed endpoint map instead of ReadonlyRecord<string, Endpoints>, and HttpApiGroup tracks its endpoint union invariantly. Dynamic string indexing must refine the key first or cast to a broad runtime record.
    • HttpApiEndpoint now exposes its stable key as identifier instead of name, aligning endpoints with APIs and groups and leaving name available for future class-based endpoint patterns.
    • HttpApiEndpoint values are now function objects instead of plain objects. Runtime checks such as typeof endpoint now return "function", and endpoint.name is the native function name. Use endpoint.identifier for the stable endpoint key.
    • Identifier helper types have been renamed from Name / WithName to Identifier / WithIdentifier; HttpApiGroup.Service now exposes identifier instead of name.

    Builder Handler Types

    • HttpApiBuilder.Handlers now tracks endpoints through an identifier-keyed endpoint map and a set of handled endpoint identifiers, instead of tracking the remaining endpoint union. Its public type parameters changed from Handlers<R, Endpoints> to Handlers<R, EndpointsByIdentifier, HandledIdentifiers>, and its phantom fields changed from _Endpoints to ~EndpointsByIdentifier / ~HandledIdentifiers.
    • The unused HttpApiBuilder.Handlers.Any helper type has been removed.
    • The exported HttpApiBuilder.HandlersTypeId symbol has been removed; Handlers now uses a private string type id.
    • Duplicate handle / handleRaw registrations for the same endpoint are rejected at the call site, and handleAll rejects endpoint identifiers that were already handled by an earlier batch. Missing endpoint handlers are still rejected by the final HttpApiBuilder.group return validation.

    Client Types

    • HttpApiClient.Client.Group now derives a client from a concrete group type: Client.Group<Group, E, R>. The previous group-union plus group-identifier form is no longer supported.
    • HttpApiClient.Client.TopLevelMethods now returns an identifier-keyed method record instead of a union of [identifier, method] tuples.
    • HttpApiClient.makeWith removes the default HttpClientError.HttpClientError from custom client error types in the returned Client, while preserving any additional custom client errors.

    Endpoint Helper Types

    • HttpApiEndpoint.HttpApiEndpoint now stores lightweight phantom metadata for middleware and request shapes: ~Middleware, ~MiddlewareServices, ~Request, and ~RequestRaw. Its type identifier field is now readonly [TypeId]: typeof TypeId.
    • HttpApiEndpoint.Constraint is now a lightweight structural endpoint constraint and does not extend Pipeable; values typed only as HttpApiEndpoint.Constraint do not expose .pipe.
    • HttpApiEndpoint.AddError has been removed; it was not used internally by the HttpApi implementation.
    • HttpApiEndpoint.Json and HttpApiEndpoint.StringTree have been removed in favor of the canonical Schema.toCodecJson and Schema.toCodecStringTree types.
    • Omitted request-part metadata now remains never instead of being wrapped as Schema.toCodecStringTree<never>; codec metadata is applied only when a params, query, payload, or headers schema is present.
    • Success metadata now applies Schema.toCodecJson only to buffered success schemas and preserves stream success schemas unchanged, including mixed buffered and streaming success arrays.
    • Handler request parts are now flattened with Struct.Simplify, improving displayed request types while reducing handler instantiations.
    • Endpoint helper types now read metadata fields directly instead of re-inferring all type parameters from the full HttpApiEndpoint interface. This affects helpers such as Identifier, Success, Error, Params, Query, Payload, Headers, Middleware, MiddlewareServices, Errors, ErrorServicesEncode, ErrorServicesDecode, Request, RequestRaw, ServerServices, and ClientServices.
    • HttpApiClient.Client.Method and related generated-client helpers now require endpoint types that satisfy HttpApiEndpoint.ConstraintRequest. Endpoint-like structural types must include the lightweight request metadata fields to be accepted.
  • #2585 5946da3 Thanks @gcanti! - Reuse HttpApi response schemas.

    HttpApiBuilder looked up cached response schemas by their source AST but stored them by the transformed AST, so the cache normally missed. It now uses the source AST consistently.

  • #2590 4ae0c5f Thanks @IMax153! - Cleanup internals of CLI package

  • #2607 5b2a0bc Thanks @tim-smart! - ensure WithTransaction wraps entire rpc handler

  • #2613 72ac585 Thanks @tim-smart! - Add HttpApiError.UnprocessableEntity and HttpApiError.UnprocessableEntityNoContent for status 422 responses.

  • #2594 5e8c1b8 Thanks @gcanti! - Reject unknown and duplicate HttpApi handler registrations with descriptive errors.

  • #2595 0f9c078 Thanks @gcanti! - Reject duplicate OpenAPI operations and operation identifiers, and reject incompatible security schemes that reuse a name.

4.0.0-beta.97

4.0.0-beta.96

Patch Changes

  • #2563 1503f45 Thanks @tim-smart! - update dependencies

  • #2566 57fe793 Thanks @tim-smart! - change rpc ids to string | number

  • #2561 0c2f78f Thanks @tim-smart! - Remove Schedule.elapsed.

  • #2561 0c2f78f Thanks @tim-smart! - Remove Schedule.tapInput and Schedule.tapOutput. Use Schedule.tap instead.

  • #2561 0c2f78f Thanks @tim-smart! - Update Schedule.addDelay and Schedule.modifyDelay to receive full schedule metadata instead of separate output and delay arguments.

  • #2562 97f29df Thanks @tim-smart! - use Sets to track atom relationships

4.0.0-beta.95

Patch Changes

  • #2542 a482442 Thanks @IGassmann! - Add Schema.DateFromMillis and SchemaTransformation.dateFromMillis for decoding millisecond timestamps into Date values.

  • #2559 fbefa85 Thanks @tim-smart! - fix activity retry policy

  • #2547 0b4a32f Thanks @fubhy! - Allow cron fields like 5/15 to expand from the starting value through the field maximum.

  • #2557 18a49e1 Thanks @fubhy! - Fix Schedule.cron when the test clock is adjusted to infinity.

  • #2560 266cb90 Thanks @gcanti! - Treat empty strings as missing values in built-in ConfigProviders by default.

    ConfigProvider.fromEnv, ConfigProvider.fromDotEnvContents, ConfigProvider.fromDotEnv, ConfigProvider.fromUnknown, and ConfigProvider.fromDir now treat literal empty strings as absent values when loaded as values, allowing Config.withDefault and Config.option to recover. Container discovery still reflects the source structure. Pass preserveEmptyStrings: true to restore the previous behavior.

    ConfigProvider.fromDotEnv({ expandVariables: true }) now expands variables consistently with ConfigProvider.fromDotEnvContents.

  • #2554 912f095 Thanks @tim-smart! - Add Schedule.upTo options for limiting schedules by duration and/or recurrence count.

  • #2556 a6718f9 Thanks @fubhy! - Fix cron parsing and scheduling edge cases for whitespace, Sunday 7, strict numeric tokens, explicit full day ranges, and month-constrained day-of-month / weekday matching.

  • #2551 bef5154 Thanks @tim-smart! - Remove the Schedule.both APIs and add Schedule.max for combining schedules by their slowest delay.

  • #2553 18e0564 Thanks @tim-smart! - Remove some Schedule APIs: collectInputs, collectOutputs, collectWhile, delays, reduce, satisfiesErrorType, satisfiesInputType, satisfiesOutputType, satisfiesServicesType, and unfold.

  • #2558 fb50f14 Thanks @tim-smart! - Remove the Schedule.either APIs and add Schedule.min for fastest-duration schedule composition.

4.0.0-beta.94

Patch Changes

  • #2538 95a0e9b Thanks @tim-smart! - fork memo map on nested builds

  • #2545 a0a3490 Thanks @marbemac! - Use registration context for cluster entities

  • #2524 f11ce73 Thanks @gcanti! - Fix HttpApi.make so it stores the API identifier and starts with an empty groups object instead of a Map. This makes empty APIs match the shape they have after groups are added.

  • #2546 ff30b6e Thanks @tim-smart! - Fix ClusterWorkflowEngine partial workflow clients colliding with full workflow clients.

  • #2523 1caab3c Thanks @rajzik! - Add glob to filesystem

  • #2541 aa80c47 Thanks @tim-smart! - add LayerRef module

  • #2539 c2ae4fc Thanks @gcanti! - Schema: add Schema.Decoder and Schema.Encoder, and accept simpler schema types in APIs that only decode, only encode, or only need the basic schema shape, closes #2536

  • #2545 a0a3490 Thanks @marbemac! - add Effect.setContext for fully replacing the fiber context

4.0.0-beta.93

Patch Changes

  • #2512 00652fe Thanks @gcanti! - Preserve content schema identifiers when emitting JSON Schema for Schema.fromJsonString.

    This keeps user-defined identifiers attached to the decoded JSON payload while giving the generated JSON string wrapper its own derived name, avoiding client codegen outputs where the payload type is renamed behind the transport wrapper.

  • #2492 6c58167 Thanks @maxprilutskiy! - Map HttpApi json defects to SchemaError

  • #2519 2bc5415 Thanks @tim-smart! - Fix structural equality for request-style values when structural hashes collide.

  • #2507 e11cccc Thanks @tim-smart! - ensure handler errors don’t cause httpapi security middleware to fallback

  • #2518 ba7e77e Thanks @tim-smart! - Move UrlParams.makeUrl to Url.make and return Url.UrlError for URL construction failures.

  • #2505 5713ee7 Thanks @KhraksMamtsov! - accept UrlParams.Input in some UrlParams apis

4.0.0-beta.92

Patch Changes

  • #2501 affdc13 Thanks @gcanti! - Fix excess property handling in schema-backed class constructors, closes #2499.

4.0.0-beta.91

Patch Changes

  • #2498 b135b25 Thanks @gcanti! - Fix Schedule.andThenResult to emit self outputs as Failure and other outputs as Success, closes #2497.

  • #2488 aaa21a3 Thanks @fubhy! - Fix String.camelCase and String.pascalCase handling of numeric word segments, and add String.configCase for configuration key casing.

  • #2485 3475ee6 Thanks @tim-smart! - fix RequestResolver interruption

4.0.0-beta.90

Patch Changes

  • #2483 d237fdf Thanks @tim-smart! - Fix Config.schema so missing array values are treated as missing data, allowing Config.withDefault to apply.

4.0.0-beta.89

Patch Changes

  • #2475 b7d46ab Thanks @tim-smart! - Update Schema.Void to model ignored void return values.

    Runtime parsing now accepts any present value and discards it as undefined. This matches TypeScript void return values, where callers do not observe the returned value. Use Schema.Undefined when the input must be exactly undefined.

  • #2479 7777e15 Thanks @tim-smart! - Add custom error callbacks to Effect.fromOption.

  • #2480 5376197 Thanks @tim-smart! - render causes in OtlpTracer exception events

4.0.0-beta.88

Patch Changes

  • #2472 911f1b8 Thanks @tim-smart! - Add adaptive consume and feedback operations to the unstable persistent RateLimiterStore API, including in-memory and Redis-backed bounded cooldown, learning, learned pacing, and expiry behavior for 429 Retry-After feedback.

  • #2457 8beeeea Thanks @P0lip! - Localize missing rpc method errors to the provided request id

  • #2428 c306fcf Thanks @MrGovindan! - Add isOpen to Latch to allow querying the latch’s open state

4.0.0-beta.87

Patch Changes

  • #2468 5a0c1a4 Thanks @gcanti! - Expose the original input schema on Schema.toType, Schema.toEncoded, Schema.toCodecJson, and Schema.toCodecStringTree results via the schema property. This aligns these schema wrappers with other wrappers that retain their source schema for type-level and runtime introspection.

  • #2466 1eea2ea Thanks @gcanti! - Use URL.canParse to validate URL string schema decoding before constructing a URL. This avoids relying on thrown exceptions for routine validation while preserving the same invalid URL issue and successful decode output.

4.0.0-beta.86

Patch Changes

  • #2462 0b5795a Thanks @tim-smart! - Add Statement.valuesUnprepared for returning unprepared SQL statement rows as arrays.

  • #2455 3e3a859 Thanks @fubhy! - Fix Cron.next skipping earlier matching days when the upcoming day-of-month does not exist in the current month.

  • #2454 7dbec24 Thanks @StarpTech! - Exclude response metadata from HTTP server span failures after response headers have been sent.

  • #2449 d8c00a1 Thanks @gcanti! - Fix Schema handling of encoded-side checks for container ASTs.

    Checks added after flip are now preserved as encodingChecks across Declaration, Arrays, Objects, and Union, even when rebuilding the AST does not change child nodes. toType now projects those checks consistently, and parsing applies encoded-side checks to the local encoded value when an encoding chain is present without allowing encoded-side parseOptions annotations to affect the current parser side.

  • #2446 85b6317 Thanks @IMax153! - Allow schemas provided to CLI flags / arguments to utilize the environment required by the CLI

  • #2452 6d0fda0 Thanks @gcanti! - Remove the keepDeclarations option from Schema.toCodecStringTree.

  • #2461 108a933 Thanks @tim-smart! - Fail RpcClient HTTP requests with a defect when the response stream closes before the request receives a terminal response.

  • #2442 7e1f455 Thanks @gcanti! - Improve Schema type-level performance by lazily computing schema views, specializing common struct projections, and using lighter schema constraints at API boundaries that do not need the full schema protocol.

    This also adds the Schema type-performance benchmark suite, introduces Schema.toCodecArrayFromSingle, preserves canonical StringTree array codecs, renames the arbitrary-generation annotation constraint for clarity, and updates affected codec, parser, channel, SQL, HTTP API, persistence, RPC, AI, OpenAPI, and workflow typings to match the refined Schema surface.

  • #2464 46b3e79 Thanks @tim-smart! - do not use performance.timeOrigin and calculate origins lazily

4.0.0-beta.85

Patch Changes

  • #2436 328d97c Thanks @MohanedMashaly! - change default operation in redis from LPUSH TO RPUSH

  • #2431 8441836 Thanks @gcanti! - Derive template literal arbitraries from encoded parts, closes #2414.

  • #2439 074e436 Thanks @gcanti! - Allow schema class .extend to accept a Struct and preserve checks from the extension schema, closes #2419.

  • #2444 c1dfd60 Thanks @bweis! - Avoid throwing when Error.stackTraceLimit is non-writable (frozen intrinsics / SES / deterministic sandboxes such as Temporal).

    Effect manipulates Error.stackTraceLimit in several internal spots to capture short or empty stack traces cheaply. In hardened environments where Error is frozen and stackTraceLimit is read-only, assigning to it throws, which broke Effect entirely. Stack-trace-limit manipulation is now best-effort and silently no-ops when the property cannot be modified, mirroring Node’s own internal guard. Behavior in normal (writable) environments is unchanged.

  • #2425 2ba316b Thanks @tim-smart! - Add Random.choice for selecting a random element from an iterable.

  • #2434 7ce7344 Thanks @gcanti! - Use semantic matching for TemplateLiteral parsing and index signature keys

    Replace regex-based TemplateLiteral parsing with backtracking segmentation over template literal parts, applying part checks during matching.

    Use schema membership when selecting Record index signature keys, including checked string, number, symbol, and TemplateLiteral parameters. Tighten valid index signature parameters on both type and encoded sides, and preserve key parameter semantics in codec transformations.

4.0.0-beta.84

Patch Changes

  • #2420 87f52ba Thanks @tim-smart! - Add Effect.transposeOption for converting an Option<Effect<A, E, R>> into an Effect<Option<A>, E, R>.

  • #2374 b8ee07f Thanks @gcanti! - Import unconstrained JSON Schema nodes as Schema.Json instead of Schema.Unknown.

  • #2407 867c0d7 Thanks @gcanti! - Normalize error behavior for Schema and SchemaParser boundary APIs.

    SchemaError now extends Data.TaggedError, so it is also a native Error. SchemaParser Promise APIs now reject an Error whose cause is the SchemaIssue.Issue for schema failures.

    Schema and SchemaParser Effect and Exit adapters now preserve full causes while mapping schema issue failures to their public error type. The is, asserts, Promise, Sync, Result, Option, make, and makeOption adapters now distinguish schema issues from non-schema causes. Schema-only failures are converted to the adapter’s normal representation (false, rejected or thrown schema error, Result.fail, or None), while non-schema causes throw or reject with an Error whose cause is the underlying Cause.

  • #2409 b93bc6c Thanks @tim-smart! - Fix Stream.runForEachWhile so it continues across chunk boundaries while the predicate returns true and stops when the predicate returns false.

  • #2424 57d387f Thanks @tim-smart! - Fix cluster workflow activity defect hydration

  • #2403 bacca41 Thanks @lloydrichards! - align ProcessInput.Input runtime field name with type definition on Prompt.custom

  • #2423 0f8ac79 Thanks @tim-smart! - RpcGroup.toHandlers is definition first

  • #2383 25b4482 Thanks @gcanti! - Fix config path composition and directory-backed lookup behavior.

    ConfigProvider.orElse now keeps each side’s own nested and mapInput behavior. Applying nested or mapInput to a combined provider now applies the same transformation to both sides.

    ConfigProvider path transformations now compose as a single path function. This makes nested and mapInput behave consistently with normal function composition.

    Config.nested now tracks the logical config path in Config itself instead of wrapping the provider. This keeps lookup paths and schema error paths aligned. The low-level Config.make constructor is no longer exported; use config constructors and combinators, or implement custom lookup behavior with ConfigProvider.make.

    ConfigProvider.fromDir now returns undefined when neither a file nor a directory exists at the requested path, so orElse can fall back instead of failing with SourceError.

  • #2415 9cf3a25 Thanks @gcanti! - Fix Effect.try thunk usage and Effect.tryPromise mapper and signal handling defects.

    Effect.try now supports passing a thunk directly, matching Effect.tryPromise. Thrown values from direct-thunk usage are mapped to Cause.UnknownError.

    When a promise handled by Effect.tryPromise rejected and the custom catch mapper threw while mapping that rejection, the effect could remain pending and produce an unhandled rejection. The mapper is now guarded consistently with the synchronous throw path, so a thrown mapper error becomes an Effect defect. The JSDoc for Effect.try and Effect.tryPromise was also corrected.

    Effect.tryPromise now also only creates an AbortController when the wrapped thunk declares an AbortSignal parameter.

  • #2417 8def767 Thanks @tim-smart! - deduplicate SqlResolver.findById requests

4.0.0-beta.83

Patch Changes

  • #2394 1f2e8ce Thanks @IMax153! - Fix published HttpApi declaration files by exporting schema metadata types referenced by public declarations.

4.0.0-beta.82

Patch Changes

  • #2391 193690b Thanks @IMax153! - Fix HttpApiEndpoint endpoint error inference when success schemas include streams.

4.0.0-beta.81

Patch Changes

  • #2387 93cb4f8 Thanks @gcanti! - Config.withDefault now only recovers from missing data for literal/union schemas. Invalid present values now propagate validation errors instead of using the default, closes #2384.

  • #2388 60341d9 Thanks @gcanti! - Config.withDefault no longer recovers from schema filter failures. A filter failure means a present value reached refinement checks, so using the default could hide invalid configuration values.

  • #2389 1105ab5 Thanks @gcanti! - Fix Schema.toTaggedUnion(...).isAnyOf narrowing for custom discriminant keys, closes #2386.

    Previously, the type predicate always extracted union members by _tag, even when toTaggedUnion was created with a different discriminant key. Runtime behavior already used the supplied key, so this aligns the type-level narrowing with the existing runtime behavior.

  • #2270 4500fbf Thanks @IMax153! - Add HTTP API streaming response support

4.0.0-beta.80

Patch Changes

  • #2205 d944330 Thanks @lloydrichards! - add support for merging external events into Prompt.custom render loops via an optional events dequeue and receive handler.

    The prompt races user input against events from the dequeue, allowing background events to trigger re-renders without waiting for a keypress:

    const eventQueue = yield * Queue.make<number>();
    const prompt = Prompt.custom(
    { count: 0 },
    Queue.asDequeue(eventQueue), // <-- provide the event queue as a dequeue to the prompt
    {
    render: (state) => Effect.succeed(`Count: ${state.count}`),
    process: (input, state) =>
    Effect.succeed(
    Match.value(input).pipe(
    // handle user input
    Match.tag("Input", () => Action.Submit({ value: state.count })),
    // handle external events from the queue
    Match.tag("Event", (input) =>
    Action.NextFrame({ state: { count: state.count + input.value } }),
    ),
    Match.exhaustive,
    ),
    ),
    clear: () => Effect.succeed(""),
    },
    );
  • #2369 f48659f Thanks @gcanti! - Round fractional durations symmetrically when normalizing to nanoseconds.

  • #2373 7652aaa Thanks @StarpTech! - Stream.fromReadableStream: swallow the reader.cancel() rejection in the finalizer. Cancelling the reader of an already-errored ReadableStream rejects with the stored error, which turned the typed onError failure into a defect.

  • #2371 98630b7 Thanks @gcanti! - Emit Schema.ObjectKeyword as an object-or-array JSON Schema union.

  • #2376 90ae23c Thanks @fubhy! - Add Graph.successors and Graph.predecessors, deprecate Graph.neighborsDirected, and fix graph algorithm edge cases around reversal, undirected edge queries, shortest-path weight validation, topological sort initials, and strongly connected components.

4.0.0-beta.79

Patch Changes

  • #2364 b9704dc Thanks @mikearnaldi! - Fix module-level side effects that defeated bundler tree-shaking.

    Bare top-level statements cannot be #__PURE__-annotated by the build, so bundlers must retain them and everything they reference, even in bundles that never use the code:

    • Option: the standalone Object.defineProperty(SomeProto, "valueOrUndefined", ...) statement anchored the whole Option proto chain into every bundle. It is now folded into the SomeProto initializer.
    • Headers: same pattern with Object.defineProperties(Proto, ...), folded into the initializer.
    • Logger: module-level process.stdout.isTTY property reads (potential getters, never droppable) moved inside consolePretty.
    • Utils: when internalCall was unused, its dropped binding left behind a retained initializer tail (standard/forced probe with computed property reads). The selection is now wrapped in a single pure-annotated call.

    A minimal Effect.succeed(123).pipe(Effect.runFork) bundle shrinks by ~1.3% gzipped; bundles that don’t use Option or Headers no longer pay for them.

  • #2339 a207113 Thanks @tim-smart! - Fix EntityManager defect restarts so in-flight requests are replayed instead of being dropped when the old entity scope is interrupted.

  • #2362 5e9b9e2 Thanks @fubhy! - Fix Graph traversal and shortest-path algorithms to traverse undirected edges independently of their stored source/target orientation.

  • #2366 7c128ae Thanks @IMax153! - Fix string seed encoding in Random.withSeed so short, trailing, and astral UTF-8 bytes affect deterministic streams.

  • #2352 0ada457 Thanks @alvarosevilla95! - Fix the Redis RateLimiterStore token-bucket failing with opaque errors under memory pressure: it now writes its keys with a TTL and guards against a missing refill timestamp.

  • #2359 d7cc5a2 Thanks @gcanti! - Fix Struct key renaming and Schema.encodeKeys to support symbol keys, and reject duplicate encoded keys.

  • #2365 aad63be Thanks @gcanti! - Fix Schema encoding so container-level checks are validated against the decoded value instead of the encoded output.

    Disallow adding checks directly to Schema.suspend(...); add the checks to the suspended schema instead.

    Fix StructWithRest so index signatures do not re-parse or overwrite fixed properties.

  • #2342 09809f6 Thanks @gcanti! - Use generic ordered constraints for schema arbitrary derivation.

    Range checks such as isGreaterThan, isLessThan, and isBetween now populate ctx.constraints.ordered instead of type-specific range fields on number, date, or bigint constraints. Custom toArbitrary annotations that read range constraints should migrate to ctx.constraints.ordered.

    This also fixes BigDecimal arbitrary generation by adapting decimal bounds to the generated scale, avoiding invalid fast-check bigint ranges for narrow decimal intervals.

  • #2368 2fddda5 Thanks @IMax153! - Encode HTTP API client path parameters when building request URLs.

  • #2348 5f21768 Thanks @gcanti! - Update Schema arbitrary derivation to use the new filter metadata, candidate generation, optional derivation reports, recursion-aware generation, and the renamed OrderedConstraint<T> model.

    Migration from the previous v4 API:

    • Replace filter annotations from toArbitraryConstraint: constraint to arbitrary: { constraint }. When a filter cannot be described as a constraint, use arbitrary: { candidate } to add a weighted source that is still checked by the filter.
    • Replace bucketed constraints with the flat Schema.Annotations.ToArbitrary.Constraint shape:
      • string.minLength, array.minLength, object property counts, collection sizes -> minLength
      • string.maxLength, array.maxLength, object property counts, collection sizes -> maxLength
      • string.patterns -> patterns
      • number.isInteger -> integer
      • number.noNaN -> noNaN
      • number.noDefaultInfinity -> noInfinity
      • date.noInvalidDate -> valid
      • array.comparator for uniqueness -> unique using Effect equality
      • ordered.min / minExcluded / max / maxExcluded -> ordered.minimum / exclusiveMinimum / maximum / exclusiveMaximum
    • In arbitrary hooks, read context.constraint instead of context.constraints. Replace context.isSuspend with context.recursion; when combining finite and recursive branches, pass context.recursion to fc.oneof with the finite branch first.
    • Generic declaration hooks now receive type parameters as { arbitrary, terminal }. Atomic declarations may still return a bare FastCheck.Arbitrary<T>, but generic declarations should return { arbitrary, terminal } when they can preserve a finite terminal branch.
    • Schema.toArbitrary(schema, { report: true }) now returns { value, report }; without { report: true }, it keeps returning the arbitrary directly. Schema.toArbitraryLazy always returns a lazy arbitrary.
  • #2343 f27003e Thanks @MohanedMashaly! - Add meta-var that shows log level and bash options in command line.

4.0.0-beta.78

Patch Changes

  • #2333 7836b8e Thanks @tim-smart! - Fix Schema.Defect JSON encoding for Error values whose message property is not a string.

  • #2329 35d49a3 Thanks @alvarosevilla95! - Retry Redis scripts after NOSCRIPT and declare the token bucket refill key

  • #2334 4093258 Thanks @tim-smart! - clean up otlp config

4.0.0-beta.77

Patch Changes

  • #2326 6e9a5ca Thanks @fubhy! - Prefer OTEL resource environment variables over explicit OtlpResource.fromConfig options.

  • #2325 302f398 Thanks @fubhy! - Add OTEL environment variable configuration for unstable OTLP observability.

4.0.0-beta.76

Patch Changes

  • #2320 016108a Thanks @gcanti! - Add Schema.isGUID and update Schema.isUUID to accept the RFC 9562 max UUID.

  • #2319 95c03d2 Thanks @fubhy! - Add support for configuring Scalar API reference pages with a custom fetch implementation.

  • #2318 07299a3 Thanks @gcanti! - Replace the Schema.Error and Schema.Defect schema constants with constructor functions, Schema.Error() and Schema.Defect().

    Unify Schema.ErrorWithStack into Schema.Error({ includeStack: true }) and Schema.DefectWithStack into Schema.Defect({ includeStack: true }).

    Error causes are encoded by default using the same JSON defect encoding semantics used by Schema.Defect; pass { excludeCause: true } to omit nested cause data.

    Equivalent Schema.Error and Schema.Defect options are canonicalized, so repeated constructor calls with the same option values reuse the same schema.

    Schema.Defect() now models defects as unknown values with a JSON encoded form. Error-shaped JSON objects with a string message decode to JavaScript Error values, so non-Error objects such as { message: "boom" } do not round-trip unchanged. Other non-Error values are normalized through JSON serialization, with non-JSON values falling back to Effect’s formatted string representation.

4.0.0-beta.75

Patch Changes

  • #2294 81b187c Thanks @mattiamanzati! - Align workflow tags with RPCs by changing Workflow.make to accept the tag as its first argument, exposing workflow tags as _tag, and supporting class MyWorkflow extends Workflow.make(...) {}.

  • #2312 ad4b535 Thanks @gcanti! - Validate Schema.StructWithRest fixed fields against rest index signatures at the type level so schemas cannot be constructed with incompatible decoded, encoded, or make shapes. This keeps StructWithRest types sound and updates the generated OpenAI conversation-items request schema to keep accepting arbitrary additional fields under the stricter validation.

  • #2314 a29c2e7 Thanks @gcanti! - Preserve Schema.Redacted options when roundtripping through schema representations. This keeps label validation and disallowJsonEncode behavior intact when schemas are revived from a representation or emitted through code generation.

  • #2298 1fdd9ae Thanks @gcanti! - Remove the Types.MergeRecord alias. Use Types.MergeLeft instead.

  • #2298 1fdd9ae Thanks @gcanti! - Align Schema adapter failures: Schema result, promise, and sync adapters now surface SchemaError, while SchemaParser result, promise, and sync adapters expose SchemaIssue.Issue. Mark SchemaParser option adapters as internal because their error details are discarded.

  • #2313 ffea4ec Thanks @MohanedMashaly! - Add -v alias for version flag

  • #2306 4255c9b Thanks @sam-goodwin! - Fix HttpApiSecurity bearer/http credential decoding

4.0.0-beta.74

Patch Changes

  • #2295 b1fc6a4 Thanks @jgoux! - Fix CLI parsing so command-local flags can override globals without breaking global flags before subcommands.

4.0.0-beta.73

Patch Changes

  • #2291 361ca30 Thanks @tim-smart! - Add HttpApiSecurity.http for passing custom schemes

  • #2289 b9598c6 Thanks @tim-smart! - make EntityResource lazy by default

4.0.0-beta.72

Patch Changes

  • #2287 73e67d1 Thanks @tim-smart! - Ensure ClusterWorkflowEngine routes durable clock wakeups and registered workflow deferred completions through the owning workflow’s shard group.

  • #2286 01d71ec Thanks @tim-smart! - Add default value support to Prompt.file.

  • #2285 fcd707e Thanks @tim-smart! - Add default value support to CLI integer prompts.

4.0.0-beta.71

Patch Changes

  • #2252 d8ac76b Thanks @tim-smart! - Added Schedule.tap, which allows observing full schedule metadata without altering schedule inputs or outputs.

  • #2261 2c3c00a Thanks @gcanti! - Add JSON Schema custom annotation passthrough option, closes #2260

  • #2269 3751e7c Thanks @gcanti! - Schema: reintroduce .value on Schema.Array and Schema.NonEmptyArray for consistency with other collection wrappers (Chunk, HashSet, etc.), closes #2268.

  • #2272 fc5f25b Thanks @gcanti! - Clarify that Data.$is(tag) only checks the _tag field, not the full structure, closes #2271.

  • #2257 7ccced4 Thanks @bwbuchanan! - Fixed the catch* combinators silently dropping unhandled error types

  • #2263 a2e1fe5 Thanks @patroza! - Use WeakMap for pendingBatches instead of Map, to allow GC to collect resolvers

  • #2266 4a4a36b Thanks @gcanti! - Fix schema arbitrary constraints for exclusive BigInt, Date, and integer number bounds.

  • #2249 d350292 Thanks @tim-smart! - allow encoding Redacted by default, and add option to disallow encoding

  • #2276 730afb6 Thanks @tim-smart! - Fix AtomRef notifications when a listener re-subscribes itself during notification.

  • #2250 df1b008 Thanks @tim-smart! - Fix Argument.variadic(argument) so it supports direct calls without options.

  • #2277 6d469d5 Thanks @tim-smart! - Fix string messages and annotations being double-quoted by simple and logfmt loggers.

4.0.0-beta.70

Patch Changes

  • #2228 af7782d Thanks @avallete! - Add Command.withHidden to hide subcommands from --help output, shell completions, and “did you mean?” suggestions, while keeping them fully invocable by exact name.

    Useful for experimental or internal subcommands that should be accepted but not advertised on the public CLI surface.

    import { Command } from "effect/unstable/cli";
    const experimental = Command.make("experimental").pipe(Command.withHidden);
    const root = Command.make("mycli").pipe(
    Command.withSubcommands([experimental]),
    );
  • #2244 7212d70 Thanks @tim-smart! - Fix TestClock adjustment when its layer is provided to programs run without an ambient Scope.

4.0.0-beta.69

Patch Changes

  • #2227 70ea04a Thanks @avallete! - Add Flag.withHidden (and Param.withHidden) to hide flags from --help output and shell completions while keeping them fully parseable on the command line.

    Useful for experimental, internal, or deprecated flags that should be accepted but not advertised, e.g. --experimental-foo, debug toggles, or escape hatches that are not yet committed to the public CLI surface.

    import { Flag } from "effect/unstable/cli";
    const experimental = Flag.boolean("experimental-foo").pipe(Flag.withHidden);
  • #2240 d0ea8b0 Thanks @tim-smart! - pass workflow parent on discard

  • #2237 a57674b Thanks @notkadez! - Fix Stream.scoped and Channel.scoped so pull effects run with the scoped resource scope.

  • #2239 59aa334 Thanks @tim-smart! - fix RpcWorker Protocol service key

  • #2242 8f4208e Thanks @tim-smart! - Accept .mjs and .mts migration files in SQL migrator loaders.

4.0.0-beta.68

Patch Changes

  • #2210 af8267f Thanks @tim-smart! - Add Stream.broadcastN for fixed-size stream broadcasts.

  • #2180 0176eaf Thanks @IMax153! - update Model uuid helpers

  • #2180 0176eaf Thanks @IMax153! - Add a platform-agnostic Crypto service for cryptographic random bytes, secure random generators, UUIDv4 / UUIDv7 generation, and digest operations. UUID generation should now use the Crypto service’s randomUUIDv4 or randomUUIDv7, which format bytes from the platform Crypto service; UUIDv7 also uses the Clock service timestamp. Random.nextUUIDv4 has been removed because the base Random service is not cryptographically secure.

  • #2221 f136bb7 Thanks @gcanti! - Change Schema.asserts and SchemaParser.asserts to assert a value directly with asserts(schema, input) and remove Schema.Codec.ToAsserts.

  • #2209 6f38f07 Thanks @tim-smart! - Fix Channel.decodeText corrupting UTF-8 characters split across chunk boundaries.

  • #2207 aec9c40 Thanks @tim-smart! - rename Model.Generated to Model.GeneratedByDb

4.0.0-beta.67

Patch Changes

  • #2185 a42ef66 Thanks @lloydrichards! - add rows to Terminal

  • #2111 35594f8 Thanks @thiagofelix! - Fix EntityProxyServer.layerHttpApi using path.entityId instead of params.entityId

  • #2201 8bddd62 Thanks @sjh9714! - Fix MutableList.filter and MutableList.remove length updates.

  • #2181 4be4c8d Thanks @zeyuri! - Fix workflow proxy RPC handlers to provide the context expected by RpcServer.

  • #2177 0c9d3ab Thanks @mikearnaldi! - Add forked memo maps so nested layer scopes can reuse parent allocations without leaking sibling-local layers. Update @effect/vitest to fork memo maps for nested it.layer suites, isolating sibling setup while preserving parent sharing.

  • #2206 b156acc Thanks @tim-smart! - add availableShardGroups to ShardingConfig, to ensure advisory locks do not conflict

  • #2184 d16c034 Thanks @gcanti! - Restore support for passing schema parse options when creating decode and encode helpers, closes #2174.

  • #2176 b559d68 Thanks @patroza! - Allow Schema decoding defaults to require Effect services.

    The Effect passed to Schema.withDecodingDefault, Schema.withDecodingDefaultKey, Schema.withDecodingDefaultType, and Schema.withDecodingDefaultTypeKey now accepts a context R in its third type parameter. The required services are propagated into the resulting schema’s DecodingServices. SchemaGetter.withDefault is widened in the same way.

  • #2113 a3de5d9 Thanks @patroza! - Allow Schema constructor and decoding defaults to fail with SchemaError.

    The Effect passed to Schema.withConstructorDefault, Schema.withDecodingDefault, Schema.withDecodingDefaultKey, Schema.withDecodingDefaultType, and Schema.withDecodingDefaultTypeKey now accepts SchemaError in its error channel. When a default fails, the parser unwraps the underlying SchemaIssue.Issue and propagates it as a parse failure with the surrounding path attached. This makes it easy to use another schema’s makeEffect / decode* as the default value.

  • #2172 7e6c12e Thanks @gcanti! - Rename SchemaParser.makeUnsafe to SchemaParser.make.

  • #2167 098167a Thanks @tim-smart! - update dependencies

4.0.0-beta.66

Patch Changes

  • #2163 ca2498e Thanks @tim-smart! - remove Effect.Yieldable

  • #2161 cd7d1fb Thanks @wking-io! - Fix request ID tracking in the RPC server HTTP protocol finalizer.

  • #2158 19a7033 Thanks @ColaFanta! - Change Type_<> implementation, from using Exclude<F, O | M> type util to keyof F as xx, this implementation keeps IDE provenance link. This enables clicking “Go to definition (F12)” in VSCode on an object made from Schema Struct jumps to the correct Struct field definition.

  • #2153 33d26b4 Thanks @Gabrola! - Allow HttpApiTest.groups to accept an optional baseUrl override while preserving the existing default of "http://localhost:3000".

  • #2160 856766b Thanks @tim-smart! - Remove the auto-incrementing suffix from HTTP server logger log span names.

  • #2164 079c7df Thanks @tim-smart! - Add the unstable workflow DurableQueue module.

4.0.0-beta.65

Patch Changes

  • #2148 6f11454 Thanks @tim-smart! - Add UniqueViolation as a new SQL error reason. Supported unique constraint violations now classify as UniqueViolation instead of the broader ConstraintError reason.

    This covers PostgreSQL, PGlite, MySQL, MSSQL, and the shared SQLite classification used by the SQLite-family clients. UniqueViolation.constraint contains the best available constraint, index, or key identifier and falls back to exactly "unknown" when no reliable identifier is available.

4.0.0-beta.64

Patch Changes

  • #2137 7d4877a Thanks @tim-smart! - Add optional soft delete column support to SqlModel repositories and resolvers.

4.0.0-beta.63

Patch Changes

  • #2136 7f927ff Thanks @tim-smart! - add HttpApiTest module

  • #2123 a696b3e Thanks @lewxdev! - add Effect.acquireDisposable

4.0.0-beta.62

Patch Changes

  • #2131 4ab4b90 Thanks @tim-smart! - Allow Kubernetes pod condition lastTransitionTime values to be null in K8sHttpClient schemas.

4.0.0-beta.61

Patch Changes

  • #2130 50790af Thanks @tim-smart! - Record fiber runtime start metrics when fibers are constructed so yielded fibers are only counted once.

  • #2120 71f7c3d Thanks @tim-smart! - Port Effect.firstSuccessOf from Effect v3.

  • #2122 aae8797 Thanks @tim-smart! - fix empty body decoding in HttpApiBuilder

4.0.0-beta.60

Patch Changes

  • #2115 f69d567 Thanks @tim-smart! - add Rpc.custom

  • #2119 7909c95 Thanks @gcanti! - Remove Inspectable.stringifyCircular and fix Formatter.formatJson so shared object references are preserved while only circular references are omitted.

  • bbb4dcc Thanks @tim-smart! - allow using Duration.Input with accessors

  • #2117 7af2207 Thanks @gcanti! - Add Schema.DurationFromString and SchemaTransformation.durationFromString, support "Infinity" and "-Infinity" in Duration.fromInput, and simplify config duration parsing around the shared schema codec, closes #2092.

  • #2116 848b40a Thanks @gcanti! - Add a Config.literals convenience constructor for Schema.Literals, closes #2091.

4.0.0-beta.59

Patch Changes

  • #2106 56837ea Thanks @IMax153! - Fix entity proxy RPC handlers to provide the context expected by RpcServer.

4.0.0-beta.58

Patch Changes

  • #2097 11993d4 Thanks @Leka74! - Add an exhaustive finalizer to the AsyncResult builder.

  • #2098 96c8b22 Thanks @tim-smart! - generate binary arrays from streams with less copying

  • #2098 96c8b22 Thanks @tim-smart! - improve http body consumption

4.0.0-beta.57

Patch Changes

  • #2085 a971f5c Thanks @tim-smart! - add Effect.abortSignal

  • #2088 8e110c5 Thanks @tim-smart! - ensure each sql client gets a unique transaction service

4.0.0-beta.56

4.0.0-beta.55

Patch Changes

  • #2081 42cc744 Thanks @gcanti! - Export the Schema.encodeKeys interface, closes #2070.

    Previously the interface was internal, so exporting a value whose inferred type referenced it triggered TypeScript error TS4023: Exported variable has or is using name 'encodeKeys' from external module ... but cannot be named, e.g.:

  • #2067 04855ce Thanks @mrazauskas! - fix isNullish() type predicate

4.0.0-beta.54

Patch Changes

  • #2078 e4b74f9 Thanks @tim-smart! - add Socket.make

  • #2075 4c72808 Thanks @tim-smart! - ensure workflow failures are not squashed by suspension interrupts

4.0.0-beta.53

Patch Changes

  • #2068 0768509 Thanks @tim-smart! - Fix AtomHttpApi query and mutation error inference to include endpoint middleware and client middleware errors, matching HttpApiClient behavior (including response-only mutation mode).

  • #2062 476aede Thanks @aldotestino! - Fix HttpIncomingMessage.schemaBodyJson to forward parse options via the parseOptions annotation key.

  • #2074 4f79c54 Thanks @tim-smart! - fix Latch.release

  • #2069 4be6a7c Thanks @mikearnaldi! - Fix TestClock.currentTimeNanosUnsafe() to floor fractional millisecond instants before converting them to BigInt.

  • #2065 88927eb Thanks @tim-smart! - add Effectable module

4.0.0-beta.52

Patch Changes

  • #2057 8e04bfc Thanks @tim-smart! - add HttpApiSchemaError for determining where a schema error originates from

  • #2055 cf3a311 Thanks @tim-smart! - ensure tagged enum _tag is correctly set

  • #2057 8e04bfc Thanks @tim-smart! - make HttpApi schema errors defects unless transformed

  • #2058 131fdd5 Thanks @tim-smart! - mcp http request with no session header is 404 response

4.0.0-beta.51

Patch Changes

  • #2049 778d2af Thanks @bohdanbirdie! - Add RpcSerialization.makeMsgPack for creating MessagePack serialization with custom msgpackr options. On Cloudflare Workers with allow_eval_during_startup (default for compatibility_date >= 2025-06-01), pass { useRecords: false } to prevent msgpackr’s JIT code generation via new Function(), which is blocked during request handling. Also fixes silent error swallowing in the msgPack decode path — non-incomplete errors are now rethrown instead of returning [].

  • #2010 4e24dcf Thanks @tim-smart! - process schema properties / elements concurrently

  • #2052 4b1c015 Thanks @gcanti! - Schema: expand FilterOutput and add FilterIssue for richer filter failures.

    The return type of a Schema.makeFilter predicate now supports two additional shapes:

    • { path, issue } where issue is string | SchemaIssue.Issue (previously only { path, message: string } was accepted). The issue arm lets you attach a fully-formed Issue at a nested path without manually constructing a Pointer.
    • ReadonlyArray<Schema.FilterIssue> to report several failures at once. An empty array is success, a single-element array is equivalent to returning that element, and multi-entry arrays are grouped into an Issue.Composite. This removes the need to import SchemaIssue and hand-build a Composite for multi-field validators.

    The single-failure shapes (undefined, true, false, string, SchemaIssue.Issue) are unchanged.

    Breaking: the object shape renamed from { path, message } to { path, issue }. Call sites that used the old shape must rename the field; the migration is mechanical.

    // before
    Schema.makeFilter((o) => ({ path: ["a"], message: "bad" }));
    // after
    Schema.makeFilter((o) => ({ path: ["a"], issue: "bad" }));

    Also renamed { path, message } to { path, issue } in the accepted return type of SchemaGetter.checkEffect.

  • #2047 454f8ad Thanks @gcanti! - Fix SchemaAST.isJson rejecting DAGs as cycles, closes #2021.

    The previous implementation marked every visited object in a single seen set and never removed it, so any value that referenced the same object through two different paths (a DAG, e.g. { x: shared, y: shared }) was treated as a cycle and returned false. Cycle detection now tracks only the current recursion path (popping on exit) and memoizes fully validated subtrees, so DAGs are accepted while true cycles are still rejected.

  • #2051 6754a0c Thanks @tim-smart! - disable sql traces for EventLog, RunnerStorage

  • #2053 90f7fd5 Thanks @tim-smart! - remove use of bigint literals

  • #2046 d7e1519 Thanks @gcanti! - Remove the options parameter from OpenApi.fromApi.

    The parameter only carried additionalProperties, but the function caches results in a WeakMap keyed solely on the api instance. Passing different options across calls for the same api was silently ignored, making the parameter order-dependent and effectively single-shot. No call sites were using it, so the signature is now simply fromApi(api).

  • #2044 72a8122 Thanks @tim-smart! - ensure envelope payloads are correctly encoded for notify path

4.0.0-beta.50

Patch Changes

  • #2038 07be594 Thanks @tim-smart! - add support for deferred responses in rpc

  • #2040 ae02433 Thanks @tim-smart! - require a option to make AtomRpc.query atoms serializatable

4.0.0-beta.49

Patch Changes

  • #2035 7d87873 Thanks @tim-smart! - Add support for common HTTP status string literals in HttpApiSchema.status (for example, HttpApiSchema.status("Created") resolves to status code 201).

  • #2036 c2f6f90 Thanks @tim-smart! - add RpcGroup.omit

  • #2034 216f13c Thanks @IMax153! - Fix issue with exported CLI Completions types

4.0.0-beta.48

Patch Changes

  • #2025 4da56ec Thanks @tim-smart! - update dependencies

  • #2029 a5e6f77 Thanks @tim-smart! - omit scope from HttpApi handlers

  • #2023 f1ba5b8 Thanks @tim-smart! - EventLog Identity string encodes to base 64

  • #2023 f1ba5b8 Thanks @tim-smart! - disable tracer propagation for otlp exporter

4.0.0-beta.47

Patch Changes

  • #2017 c584726 Thanks @gcanti! - Schema: add annotateEncoded function for annotating the encoded side of a schema.

  • #2013 86a91a4 Thanks @gcanti! - Schema: add withDecodingDefaultTypeKey / withDecodingDefaultType, closes #2012

  • #2018 131caf9 Thanks @gcanti! - Schema: allow Class constructors to accept void when all fields are optional, closes #2015.

  • #2016 c3615c8 Thanks @gcanti! - Schema: rename "~rebuild.out" to "Rebuild"

4.0.0-beta.46

Patch Changes

  • #2008 3a30b9e Thanks @tim-smart! - fix eventlog skipping entries

4.0.0-beta.45

Patch Changes

  • #1883 5c3af6d Thanks @tim-smart! - Add EventLogServerUnencrypted module

4.0.0-beta.44

Patch Changes

  • #1943 e3f0621 Thanks @gcanti! - Add DateFromString, BigIntFromString, BigDecimalFromString, TimeZoneNamedFromString, TimeZoneFromString, and DateTimeZonedFromString schemas, closes #1941.

  • #1996 5b476ab Thanks @gcanti! - Schema: add StringFromBase64, StringFromBase64Url, StringFromHex, and StringFromUriComponent schemas for decoding encoded strings into UTF-8 strings, closes #1995.

  • #1952 6b40e5a Thanks @tim-smart! - Effect.repeat now uses effect return value when using options

  • #1961 7bb5dce Thanks @IMax153! - Rename Atom’s Context type to AtomContext

  • #1975 3b09fb3 Thanks @tim-smart! - catch defects when building Entity handlers

  • #2000 2370410 Thanks @tim-smart! - fix cache constructor inference by moving the lookup option

  • #1928 dabc272 Thanks @tim-smart! - Add schema.makeEffect(input, options?) to Schema.Bottom and schema-backed classes, matching the existing constructor behavior exposed by makeUnsafe / makeOption while returning an Effect failure with Schema.SchemaError.

  • #1949 08b63c3 Thanks @tim-smart! - Update the unstable HTTP middleware logger to annotate only the request path in http.url instead of including the full URL (query / fragment), and add a regression test.

  • #1962 dfff04c Thanks @tim-smart! - Add KeyValueStore.layerSql to back key-value storage with a SQL database via SqlClient.

  • #1963 9baed9e Thanks @tim-smart! - Fix Unify.unify so Layer unions merge correctly, and add type tests covering Layer unification.

  • #2004 7846792 Thanks @tim-smart! - Fix Stream.toQueue types and implementation to return a Queue.Dequeue in both overloads and delegate to Channel.toQueueArray.

  • #1974 1556a24 Thanks @juliusmarminge! - Fix unstable CLI boolean flags so Flag.optional(Flag.boolean(...)) returns Option.none() when omitted, and support canonical --no-<flag> negation for boolean flags.

  • #1980 7c11bc2 Thanks @tim-smart! - fix Entity.keepAlive

  • #1929 b5ea591 Thanks @gcanti! - Simplify and align the default-value APIs.

    Schema.withConstructorDefault now accepts an Effect<T> instead of (o: Option<undefined>) => Option<T> | Effect<Option<T>>.

    Schema.withDecodingDefault / Schema.withDecodingDefaultKey now accept an Effect<T> instead of () => T, enabling effectful defaults.

    SchemaGetter.withDefault follows the same change, accepting Effect<T> instead of () => T.

  • #1966 0853afa Thanks @gcanti! - Reuse existing references when duplicate identifiers have the same representation, closes #1927.

  • #1942 ac845f3 Thanks @gcanti! - Fix ErrorClass and TaggedErrorClass toString to match native Error output format (e.g. E: my message instead of E({"message":"my message"})), closes #1940.

    Also fix prototype properties (e.g. name) being lost after .extend().

  • #1956 b80c462 Thanks @gcanti! - Add Schema.resolveAnnotationsKey API to retrieve the context (key-level) annotations from a schema, closes #1947.

    Also rename Schema.resolveInto to Schema.resolveAnnotations.

  • #2005 b3f535d Thanks @gcanti! - Fix Stream.splitLines to correctly handle standalone \r as a line terminator and flush the final unterminated line when the stream ends, closes #2002.

  • #1936 6fe2e93 Thanks @IMax153! - Fix Stream.groupedWithin dropping partial batches when the upstream ends or goes idle.

  • #1981 cda8004 Thanks @tim-smart! - add rpc ConnectionHooks

  • #1965 8335477 Thanks @tim-smart! - return resolvers directly from SqlModel.makeResolvers

  • #1960 8c836f9 Thanks @IMax153! - Add ChildProcessHandle.unref, returning an Effect that restores the child process reference when run.

  • #1984 718ff6f Thanks @jannabiforever! - Make Effect.retry with times argument to propagate the original error.

  • #1930 7eed84f Thanks @mikearnaldi! - Add Stream.service and Stream.serviceOption for accessing services as single-element streams.

  • #1935 5df46fe Thanks @gcanti! - Schema: add asClass API to turn any schema into a class with static method support.

    Example

    import { Schema } from "effect";
    class MyString extends Schema.asClass(Schema.String) {
    static readonly decodeUnknownSync = Schema.decodeUnknownSync(this);
    }
    MyString.decodeUnknownSync("a"); // "a"
  • #1958 82dd0f2 Thanks @gcanti! - Schema: add MissingSelfGeneric compile-time error for Class, TaggedClass, ErrorClass, and TaggedErrorClass when the Self type parameter is omitted.

  • #1957 03ae41e Thanks @gcanti! - Schema: remove "~annotate.in" type from Bottom interface, inlining it where needed

  • #1951 4677a0a Thanks @gcanti! - Rename Schema.makeUnsafe instance method back to Schema.make on all schemas and schema-backed classes.

    Also remove the static readonly make override from ShardId to avoid conflicting with the inherited schema make method. The module-level ShardId.make(group, id) function is still available.

  • #1999 87e1fc8 Thanks @tim-smart! - use NoInfer in Layer constructors to prevent type erasure

  • #1971 c1af1b7 Thanks @joepjoosten! - Allow unstable CLI fallback prompts to be created dynamically from an Effect.

  • #1961 7bb5dce Thanks @IMax153! - Rename the ServiceMap module to Context across exports, docs, and tests.

  • #1973 c8a877b Thanks @joepjoosten! - Underline the active label in CLI multi-select prompts and add a scratchpad example for manual verification.

  • #1967 7da961a Thanks @tim-smart! - clean up ShardId

4.0.0-beta.43

Patch Changes

  • #1904 2ae33d0 Thanks @juliusmarminge! - Fix JSON-RPC serialization for id values that are falsey but valid, including 0 and "", while still mapping null to Effect’s internal notification sentinel.

  • #1900 979811a Thanks @tim-smart! - Fix AI structured output schema generation for Schema.Class and Schema.ErrorClass by resolving top-level $ref entries before passing JSON Schema to providers and default codec transformers.

  • #1908 eb7dbef Thanks @tim-smart! - Fix stream requests in Entity.toLayerQueue

  • #1907 cf50eb4 Thanks @tim-smart! - add WorkflowEngine interruptUnsafe

  • #1903 1d046fe Thanks @kitlangton! - Add Layer.suspend as a lazy constructor for dynamically choosing a layer while preserving normal layer sharing.

4.0.0-beta.42

Patch Changes

  • #1897 924e216 Thanks @IMax153! - Append concrete choice values to CLI flag help descriptions so generated help shows valid command-line inputs.

  • #1894 80e7f0c Thanks @tim-smart! - Fix MutableList.appendAll / appendAllUnsafe so empty arrays are treated as a no-op instead of leaving behind an empty internal bucket.

  • #1895 f8328bf Thanks @tim-smart! - Changed socket close handling so all close codes are treated as errors by default unless closeCodeIsError is overridden.

  • #1899 66d1c06 Thanks @gcanti! - SchemaRepresentation: support anyOf/oneOf with sibling keywords in fromJsonSchemaMultiDocument

  • #1893 bee800b Thanks @gcanti! - Number.remainder: fix incorrect results for small floats in scientific notation (e.g. 1e-7).

  • #1898 8930441 Thanks @mikearnaldi! - Rename Effect.transaction to Effect.tx and Effect.retryTransaction to Effect.txRetry, remove Effect.transactionWith / Effect.withTxState, make nested Effect.tx calls compose into the active transaction, and make the public Tx* APIs establish atomic transactions without requiring Transaction in common usage.

4.0.0-beta.41

Patch Changes

  • #1881 36f5c21 Thanks @gcanti! - Added BigDecimal.sumAll and BigDecimal.multiplyAll for feature parity with Number and BigInt, closes #1880.

  • #1869 d8ce758 Thanks @gcanti! - Schema: collapse same-type literal branches in JSON Schema output into a single enum array, closes #1868.

    Before:

    {
    "anyOf": [
    { "type": "string", "enum": ["A"] },
    { "type": "string", "enum": ["B"] }
    ]
    }

    After:

    {
    "type": "string",
    "enum": ["A", "B"]
    }
  • #1879 11aab4c Thanks @tim-smart! - Highlight active option labels in Prompt.select and Prompt.multiSelect using cyan text so selection state is visible beyond the pointer / checkbox icon.

  • #1884 3bc1efb Thanks @tim-smart! - Fail RpcClient HTTP requests when the server response contains no RPC messages instead of leaving requests pending.

  • #1875 70e724e Thanks @IMax153! - Fix AI text method toolkit typing to support generic handler toolkits, preserve toolkit union inference, and keep response part narrowing by tool name.

  • #1876 738dee7 Thanks @tim-smart! - Track ManagedRuntime fibers in a scope

  • #1886 2111963 Thanks @tim-smart! - add ClusterSchema.WithTransaction annotation

  • #1877 198a553 Thanks @tim-smart! - allow Context.Key to be covariant

4.0.0-beta.40

Patch Changes

  • #1863 f62860f Thanks @tim-smart! - fix issues with metro bundler

  • #1866 973f281 Thanks @tim-smart! - add Stream.timeoutOrElse

4.0.0-beta.39

Patch Changes

  • #1844 f91fd3d Thanks @tim-smart! - Relax HttpApiClient.urlBuilder to accept HttpApi.Any instead of requiring HttpApi.AnyWithProps. This allows use in helpers generic over HttpApi.Any while preserving inferred URL builder types.

  • #1851 edaae9d Thanks @tim-smart! - Re-export additional core runtime references from effect/References, including logger and error reporter references.

  • #1856 b47db0b Thanks @gcanti! - Fix Struct utility return types (for example pick) to preserve the previous simplified shape instead of exposing raw utility types like Pick<T, K>, closes #1855.

  • #1849 82d3c8e Thanks @tim-smart! - Fix the Queue.takeN documentation example to end the queue before showing a partial batch.

  • #1848 7c22b31 Thanks @tim-smart! - Remove Schedule.compose in favor of Schedule.both, and update schedule examples to use Schedule.both.

4.0.0-beta.38

Patch Changes

  • #1842 f4dbe5b Thanks @gcanti! - Schema: rename MakeOptions.disableValidation to disableChecks. Apply constructor defaults when disableChecks is true, closes #1841.

  • #1837 a71a607 Thanks @kitlangton! - Fix HttpApiBuilder security middleware caching so separate handler builds do not reuse the first provided middleware implementation.

  • #1840 66a0494 Thanks @tim-smart! - Rename HttpApiClient request option withResponse to responseMode and add support for responseMode: "response-only" to return the raw HttpClientResponse without decoding.

  • #1838 5ef7218 Thanks @tim-smart! - Update HttpApiClient.urlBuilder to mirror client shape, and encode params/query via endpoint schemas before building URLs.

  • #1700 472d260 Thanks @tim-smart! - add useCodecs option to HttpClientEndpoint constructors

4.0.0-beta.37

Patch Changes

  • #1812 f7a0b71 Thanks @tim-smart! - Consolidate the SqlError changes to the new reason-based shape across effect and the SQL drivers, classifying native failures into structured reasons with Unknown fallback where native codes are unavailable.

  • #1816 1e223c3 Thanks @tim-smart! - unstable/http HttpClientRequest: add toWeb and fromWeb conversions for web Request objects

  • #1829 53740f4 Thanks @tim-smart! - Fix sql migrator lock handling to only treat duplicate migration-row inserts as a concurrent migration lock.

  • #1831 8c7cf89 Thanks @tim-smart! - Fix Schedule.fixed to run the next iteration immediately when the previous action takes longer than the configured interval.

  • #1833 b6b81a9 Thanks @tim-smart! - Fix Unify.unify so unions of Effect values collapse to a single unified Effect type again.

  • #1825 8f4c1f9 Thanks @skoshx! - Fix DevToolsClient not flushing final span events on teardown.

    The stream consumer was forkScoped, causing it to be interrupted before it could drain remaining queue items. Replaced with forkChild and Fiber.await in the finalizer so the stream drains naturally after the queue is failed.

  • #1824 f2479f9 Thanks @tim-smart! - Ignore unsupported Ctrl key combinations in interactive CLI prompts to avoid rendering control characters such as Ctrl+L form feed into prompt input.

  • #1819 c919921 Thanks @j! - HttpServerResponse: fix fromWeb to preserve Content-Type header when response has a body

    Previously, when converting a web Response to an HttpServerResponse via fromWeb, the Content-Type header was not passed to Body.stream(), causing it to default to application/octet-stream. This affected any code using HttpApp.fromWebHandler to wrap web handlers, as JSON responses would incorrectly have their Content-Type set to application/octet-stream instead of application/json.

  • #1821 7af90c2 Thanks @gcanti! - Schema: relax asserts and is constraints.

  • #1822 f3be185 Thanks @tim-smart! - improve runSync error when executing async effects

4.0.0-beta.36

Patch Changes

  • #1793 60fcbcc Thanks @tim-smart! - Ensure streamed tool results are emitted before the finish part so chat history includes tool outputs before stream termination.

  • #1762 0a60837 Thanks @kitlangton! - Allow unstable HttpApi middleware to declare multiple error schemas with arrays.

    Middleware errors now follow endpoint error behavior for response status resolution, client decoding, and generated API schemas.

  • #1805 49164d2 Thanks @tim-smart! - Fix Effect.cachedWithTTL and Effect.cachedInvalidateWithTTL to start TTL expiration when the cached value is produced instead of when computation starts.

  • #1808 334b6e4 Thanks @tim-smart! - Backport Cron.prev with reverse lookup tables and cron stepping logic, including DST-aware reverse traversal.

  • #1789 5700695 Thanks @mikearnaldi! - Fix Stream.scanEffect hanging and repeatedly emitting the initial state.

  • #1810 f8f4456 Thanks @tim-smart! - Support key-derived idleTimeToLive in LayerMap options (make, fromRecord, and LayerMap.Service) and add LayerMap tests for dynamic TTL behavior.

  • #1802 969d24f Thanks @kitlangton! - PubSub.publish and PubSub.publishAll now return false on shutdown instead of interrupting, matching Queue.offer semantics.

  • #1796 851eda0 Thanks @tim-smart! - Improve Prompt.file to support incremental filtering while typing, including backspace and ctrl-u handling.

  • #1806 8059c1c Thanks @tim-smart! - Fix a regression in PubSub.shutdown so shutting down a pubsub interrupts suspended subscribers (including takeAll) by ensuring subscriptions are scoped under the pubsub shutdown scope.

  • #1797 6f83295 Thanks @tim-smart! - Add `Ctrl-A` and `Ctrl-E` key handling for editable CLI text prompts to move the cursor to the beginning or end of the current input line.

  • #1633 65f7f57 Thanks @kitlangton! - Schema: add decodeUnknownResult / decodeResult and encodeUnknownResult / encodeResult helpers for synchronous Result-based parsing.

  • #1798 e7fabd2 Thanks @gcanti! - Schema: allow using Struct type helpers directly, e.g. Schema.Struct.Type<F> instead of Schema.Schema.Type<Schema.Struct<F>>.

  • #1794 89c3e98 Thanks @tim-smart! - Fix ai LanguageModel streaming finish parts so finish events are always emitted when a toolkit is provided.

  • #1785 53794ab Thanks @KhraksMamtsov! - add missing Equivalence.Date

4.0.0-beta.35

Patch Changes

  • #1782 9252b43 Thanks @gcanti! - Add Schema.ArrayEnsure.

  • #1784 7daf387 Thanks @gcanti! - Add Config.Success type utility, closes #1783.

  • #1778 e1664a3 Thanks @tim-smart! - Allow Effect.acquireRelease release finalizers to depend on the surrounding environment.

  • #1777 fdaa6e0 Thanks @tim-smart! - Remove an unreachable array branch in decodeJsonRpcRaw to simplify JSON-RPC decode logic without changing behavior.

  • #1774 19aa47e Thanks @tim-smart! - Align CLI help flag and global flag descriptions to a single column even when some flag names are very long.

  • #1780 c667dad Thanks @tim-smart! - Fix LanguageModel incremental prompt fallback to reliably retry with the full prompt when an incremental request fails with InvalidRequestError.

  • #1781 764d150 Thanks @gcanti! - Fix DateTime.makeUnsafe incorrectly appending “Z” to date strings containing “GMT”

  • #1772 3c27098 Thanks @tim-smart! - make Layer.mock work with Stream and Channel

4.0.0-beta.34

Patch Changes

  • #1758 f2f75ee Thanks @tim-smart! - Use a normal Map in ResponseIdTracker and clear it on divergence / reset instead of reallocating a WeakMap.

  • #1764 342fc4b Thanks @tim-smart! - Add unstable EmbeddingModel support across core and OpenAI providers.

    • Add the unstable EmbeddingModel module API surface in effect, including service, request, response, and provider types.
    • Implement the unstable EmbeddingModel runtime constructor in effect, with RequestResolver batching, embed / embedMany spans, provider error propagation, deterministic ordering, and empty-input embedMany fast-path behavior.
    • Add and align EmbeddingModel behavior tests in effect for embedding usage, batching, ordering, and error handling.
    • Add OpenAiEmbeddingModel in @effect/ai-openai, including model / make / layer constructors, config overrides, and provider output index validation with deterministic reordering.
    • Add OpenAI-compatible EmbeddingModel provider support in @effect/ai-openai-compat, including config overrides, layer constructors, and output index validation.
  • #1766 5d704ee Thanks @tim-smart! - Fix JSDoc wording for Effect.catch to consistently reference the current API name.

  • #1771 00add69 Thanks @tim-smart! - Add EmbeddingModel.ModelDimensions and require dimensions in embedding provider model constructors.

  • #1767 58217d3 Thanks @gcanti! - Add isMutableHashMap and isMutableHashSet, and align nominal guard implementations and tests across collections and transactional data types.

  • #1765 f4e2aba Thanks @tim-smart! - retry incremental prompt on invalid request

  • #1756 e3b44b6 Thanks @tim-smart! - add HttpApiMiddleware.layerSchemaErrorTransform

  • #1732 e1472b7 Thanks @KhraksMamtsov! - port Url module from v3

  • #1761 7686320 Thanks @gcanti! - Fix Tool.make type and runtime behavior when parameters is not provided.

4.0.0-beta.33

Patch Changes

  • #1754 571447d Thanks @tim-smart! - narrow types for Effect.retry/repeat while option

4.0.0-beta.32

Patch Changes

  • #1717 bf8fff8 Thanks @gcanti! - Schema: add OptionFromOptionalNullOr schema, closes #1707.

  • #1722 1af3ef3 Thanks @tim-smart! - Fix RpcSerialization.json decode so JSON array payloads are not wrapped in an extra outer array.

  • #1725 27fea0f Thanks @tim-smart! - Improve unstable HttpApi runtime failures for missing server middleware and missing group implementations.

    • HttpApiBuilder.applyMiddleware now resolves middleware services via Context.getUnsafe, so missing middleware fails with a clear “Service not found: ” error instead of an opaque is not a function TypeError.
    • HttpApiBuilder.layer now reports missing groups with actionable context (group identifier, service key, suggested HttpApiBuilder.group(…) call, and available group keys).
    • Added regression tests in packages/platform/node/test/HttpApi.test.ts covering:
      • addHttpApi + API-level middleware applied across merged groups
      • missing middleware service diagnostics
      • missing addHttpApi group layer diagnostics
  • #1727 2ad6c1b Thanks @tim-smart! - Make all built-in HttpApiError classes implement HttpServerRespondable, so they can be returned directly from plain HTTP server handlers outside of HttpApi.

  • #1739 398ac3e Thanks @tim-smart! - Use predicate-based dual dispatch for Stream.merge so data-last calls with optional options are handled correctly.

  • #1741 51fe22f Thanks @tim-smart! - Add Layer.tap, Layer.tapError, and Layer.tapCause APIs for effectful observation of layer success and failure without changing layer outputs.

  • #1740 4605db6 Thanks @tim-smart! - Refactor call sites with multiple Context mutations to use Context.mutate for batched updates.

  • #1750 f4de1b0 Thanks @gcanti! - Improve unstable AI structured output handling for empty tool params and add Tool.EmptyParams, closes #1749.

  • #1525 60214f2 Thanks @tim-smart! - use Option instead of undefined | A

  • #1747 c4b8b0f Thanks @tim-smart! - seperate scheduler dispatch from yield decisions

  • #1729 6d9393a Thanks @tim-smart! - add Context.mutate

  • #1753 6de4efe Thanks @tim-smart! - Add dtslint coverage for Stream.catchIf to lock in predicate and refinement inference behavior in both data-first and data-last forms.

  • #1716 4f969d1 Thanks @gcanti! - Remove unused effect/NullOr module.

  • #1721 6cc67c8 Thanks @IMax153! - Correct the type of the schema parameter accepted by the fileSchema methods in the CLI to be Schema.Decoder<A>

  • #1709 8531a22 Thanks @mikearnaldi! - Add module-level helpers for Semaphore, Latch, and extracted PartitionedSemaphore operations.

  • #1752 b226760 Thanks @tim-smart! - simplify SubscriptionRef

  • #1743 47a51ab Thanks @tim-smart! - default ws close codes to 1001 in case they are undefined

  • #1728 1521d02 Thanks @tim-smart! - add graceful shutdown to http servers

4.0.0-beta.31

Patch Changes

  • #1696 5a84853 Thanks @krzkaczor! - Add DurationObject to Duration.Input to support Temporal-style object input.

    Durations can now be created from objects with named unit properties like { hours: 1, minutes: 30 }, similar to Temporal.Duration.from(). Supported fields: weeks, days, hours, minutes, seconds, millis, micros, nanos.

  • #1705 6f23f0e Thanks @tim-smart! - Preserve message item ordering in the default logger when logging a Cause with message values.

  • #1711 654aaec Thanks @tim-smart! - Fix RpcGroup.toLayer and RpcGroup.toLayerHandler service requirement inference so handler dependencies are preserved for non-stream RPC handlers.

  • #1712 2958a42 Thanks @tim-smart! - Expose CLI completions as a public unstable module at effect/unstable/cli/Completions.

  • #1713 95d27a2 Thanks @tim-smart! - Make Layer.mock a dual API so it supports both Layer.mock(Service)(impl) and Layer.mock(Service, impl).

  • #1704 0fbaea8 Thanks @tim-smart! - Support toolkit unions in LanguageModel options.

  • #1701 21d5d5e Thanks @tim-smart! - wrap httpapi request context with HttpRouter.Request

  • #1696 5a84853 Thanks @krzkaczor! - allow assigning Temporal types to DateTime & Duration input

  • #1698 6e49959 Thanks @tim-smart! - Include toolkit tool handler requirements in AI generation API environment inference.

  • #1703 8f5805d Thanks @tim-smart! - Relax Ndjson byte-stream channel signatures to accept plain Uint8Array.

  • #1710 990df2c Thanks @gcanti! - Schema: toCodecJson now returns Codec<T, Json, RD, RE> instead of Codec<T, unknown, RD, RE>.

    Http: the json property on HttpIncomingMessage, HttpClientResponse, HttpServerRequest, and HttpServerResponse now returns Effect<Schema.Json, E> instead of Effect<unknown, E>.

4.0.0-beta.30

Patch Changes

  • #1675 c88e5b7 Thanks @gijsbartman! - Fix consolePretty ignoring explicit colors option in non-TTY environments.

    When colors is explicitly set to true, prettyLoggerTty was still gating it with processStdoutIsTTY check, making it impossible to enable colors in non-TTY environments like Vite dev server.

  • #1690 947d0e4 Thanks @gcanti! - Fix Cause.hasInterruptsOnly to return false for empty causes.

  • #1620 7517908 Thanks @kitlangton! - Fix TaggedUnion.match to use Unify for return types, allowing branches to return distinct Effect types that are properly merged.

  • #1680 a49ecd5 Thanks @KhraksMamtsov! - make HttpClientResponse pipeable

  • #1681 6993e33 Thanks @mikearnaldi! - Add an optional message field to Effect.ignore and Effect.ignoreCause for custom log output.

  • #1695 514f2a2 Thanks @gcanti! - Remove unused APIs from the Utils module.

  • #1644 3214b47 Thanks @patroza! - fix: update Service interface to use ‘this: void’ in ‘of’ method signatures

  • #1693 95ec5ed Thanks @tim-smart! - fix cli subcommand context

4.0.0-beta.29

Patch Changes

  • #1672 9d93adb Thanks @gcanti! - Add Newtype module.

  • #1677 b52721c Thanks @gcanti! - Fix Schema.isUUID so the version parameter is optional in its public signature.

  • #1667 a891c7b Thanks @tim-smart! - Preserve Atom.withReactivity(...) refresh behavior when registry initial values seed the wrapped atom.

  • #1678 ef26cdf Thanks @tim-smart! - Abort HTTP client requests when response streams are consumed only partially.

  • #1665 82fd3ed Thanks @tim-smart! - Remove placeholder fallback behavior from CLI prompt inputs now that default values are prefilled.

4.0.0-beta.28

Minor Changes

  • #1637 42bc7ce Thanks @tim-smart! - Add a new effect/unstable/http/HttpStaticServer module for static file serving with MIME resolution, directory index fallback, SPA fallback, and safe path resolution.

Patch Changes

  • #1659 ff533f2 Thanks @tim-smart! - Persist MCP HTTP session and protocol headers after initialize so follow-up JSON-RPC requests include MCP-Protocol-Version.

  • #1663 dc803ee Thanks @tim-smart! - Add HttpServerResponse.fromClientResponse for directly converting client responses into server responses.

  • #1657 d660b1c Thanks @tim-smart! - Add Ctrl-U line clearing support to editable CLI prompts.

  • #1645 93a05e3 Thanks @gijsbartman! - ensure transformed Atom’s don’t extend idle ttl

  • #1655 2a65cf6 Thanks @tim-smart! - Make AtomRpc.query and AtomHttpApi.query return serializable atoms by default when query results are schema-backed.

    The atom serialization key now uses each API’s built-in request schemas so dehydrated state can be keyed consistently across server and client.

  • #1662 a561a40 Thanks @tim-smart! - Add HttpServerRequest.toClientRequest for direct server-to-client request conversion.

  • #1648 29cd24d Thanks @gcanti! - Fix Types.VoidIfEmpty to correctly detect empty object types. Remove deprecated Types.MatchRecord in favor of the simplified implementation, closes #1647.

  • #1664 662a8e6 Thanks @tim-smart! - Add HttpServerRequest.fromClientRequest for direct client-request-backed server request conversion.

  • #1656 d2b52ba Thanks @tim-smart! - Persist MCP client capability context across HTTP requests by resolving initialized payloads through the standard Mcp-Session-Id HTTP header in McpServer.

    Adds a regression test that initializes an MCP HTTP client, verifies the MCP server echoes Mcp-Session-Id, and then checks a later tool call can still read McpServer.clientCapabilities.

  • #1639 407c3b4 Thanks @tim-smart! - Add Scheduler.PreventSchedulerYield and expose it via References so fibers can skip scheduler shouldYield checks when needed.

  • #1649 e741322 Thanks @tim-smart! - Set Schema.TaggedErrorClass instance name to the tag value, matching Data.TaggedError behavior.

  • #1646 5c75fa8 Thanks @tim-smart! - Simplify internal and documented request usage by passing request resolvers directly to Effect.request instead of wrapping them with Effect.succeed.

  • #1641 747177b Thanks @tim-smart! - Don’t transform Tool result schemas, as they aren’t sent to the providers as json schemas

  • #1636 326cd48 Thanks @tim-smart! - Add Cookies.expireCookie / expireCookieUnsafe and HttpServerResponse.expireCookie / expireCookieUnsafe for emitting expired cookies.

  • #1653 627e922 Thanks @tim-smart! - expose mcp client capabilities

  • #1660 662287e Thanks @tim-smart! - Add HttpServerResponse.toClientResponse for converting server responses into HttpClientResponse values.

4.0.0-beta.27

Patch Changes

  • #1621 903a839 Thanks @kitlangton! - unstable/http Headers: add removeMany combinator for removing multiple headers at once

  • #1622 91a0168 Thanks @tim-smart! - Add Model.BooleanSqlite, a model field schema that uses 0 | 1 encoding for database variants and plain boolean encoding for JSON variants.

  • #1631 c890f9a Thanks @gcanti! - unstable/httpapi HttpApiBuilder: fix void responses producing a non-empty body instead of Response.empty, closes #1628.

  • #1618 1e985f2 Thanks @tim-smart! - Default Effect.context() to Effect.context<never>() when no type parameter is provided.

4.0.0-beta.26

Patch Changes

  • #1603 fb21462 Thanks @tim-smart! - Add responseText to AiError.StructuredOutputError and populate it from LanguageModel.generateObject so failed structured output decodes include the full LLM text.

  • #1613 2ed26b1 Thanks @lucas-barake! - Add disableFatalDefects to RpcServer.layerHttp, RpcServer.toHttpEffect, and RpcServer.toHttpEffectWebsocket option types to match existing runtime support.

  • #1599 e832a57 Thanks @tim-smart! - add trait for customizing exit codes

  • #1611 7f01be7 Thanks @WebWalks! - Fixed the Error Type on AtomHttpApiClient (Server errors were being incorrectly reported, and we could not determine _tag to handle)

  • #1612 e965143 Thanks @tim-smart! - Expose the optional orElse fallback parameter in Effect.catchTags.

  • #1606 b9b80f1 Thanks @gcanti! - Schema: toJsonSchemaDocument now emits JSON Schema false for unannotated Never index signatures (including additionalProperties) instead of { not: {} }. Annotated Never still emits a schema object so metadata like description is preserved.

  • #1607 98252aa Thanks @gcanti! - Schema: improve Schema.Unknown / Schema.ObjectKeyword handling in toCodecJson and toCodecStringTree

  • #1616 56fbd94 Thanks @lucas-barake! - Add Atom.swr to effect/unstable/reactivity for staleTime-gated stale-while-revalidate reads, optional mount and window-focus revalidation, and forceful manual refresh.

  • #1600 3faa109 Thanks @tim-smart! - add args to Stdio service

  • #1610 692ecfe Thanks @kitlangton! - Refine unstable CLI parent/subcommand flag composition.

    • Add Command.withSharedFlags conflict validation against existing subcommands, including the withSubcommands(...).withSharedFlags(...) composition order.
    • Reorder Command type parameters to Command<Name, Input, ContextInput, E, R> for clearer parent-context modeling.
    • Make Command.withSubcommands input typing sound for downstream input-based combinators by reflecting that subcommand paths only carry parent context input.
  • #1604 1e70b72 Thanks @lucas-barake! - Fix unstable/sql/SqlSchema request input typing so findAll and findNonEmpty accept Request["Type"] instead of Request["Encoded"].

  • #1602 ecf0782 Thanks @tim-smart! - Replace the default HttpApi schema-validation error with HttpApiError.BadRequestNoContent.

4.0.0-beta.25

Patch Changes

  • #1597 fa17bb5 Thanks @tim-smart! - Fix Effect.forkScoped data-first typings to include Scope in requirements.

  • #1598 f46e5b5 Thanks @tim-smart! - compare transaction connections by reference

  • #1596 ce4767c Thanks @tim-smart! - improve HttpClient.withRateLimiter initial state tracking

  • #1594 c830a8b Thanks @tim-smart! - HttpClient.withRateLimiter adds delay from retry-after headers

4.0.0-beta.24

Patch Changes

  • #1586 a909e1c Thanks @gcanti! - Schema: add Chunk schema, closes #1585.

  • #1588 8814a4e Thanks @gcanti! - Fix Schema.toTaggedUnion discriminant detection for class-based schemas, including unique symbol tags, closes #1584.

  • #1591 3f942c5 Thanks @tim-smart! - Add HttpClient.withRateLimiter for integrating the RateLimiter service with HTTP clients, including optional response-header driven limit updates and automatic 429 retry behavior.

  • #1583 774ed59 Thanks @patroza! - feat: Support Reference classes

  • #1592 f54b8d3 Thanks @tim-smart! - Fix HttpApi.prefix so it updates endpoint path types the same way HttpApiGroup.prefix does.

4.0.0-beta.23

Patch Changes

  • #1561 5c73c41 Thanks @gcanti! - SchemaRepresentation: only create references for recursive/mutually recursive schemas and schemas with an identifier annotation, closes #1560.

4.0.0-beta.22

Patch Changes

  • #1578 0874332 Thanks @tim-smart! - Proxy function arity from Effect.fn APIs so wrapped functions preserve the original length value.

  • #1580 c592dcd Thanks @tim-smart! - simplify Filter by removing Args type parameter

  • #1575 1dbe28d Thanks @tim-smart! - fix Chat constructor types

  • #1581 564d730 Thanks @tim-smart! - fix Duration.toMillis regression

  • #1579 3cfadc4 Thanks @tim-smart! - Remove fiber-level keep-alive intervals and keep the process alive from Runtime.makeRunMain instead.

  • #1571 6634fd0 Thanks @tim-smart! - Add HttpApiClient.urlBuilder for type-safe endpoint URL construction from group + method/path keys.

  • #1573 d10dabe Thanks @tim-smart! - Expose a chunkSize option on Stream.fromIterable to control emitted chunk boundaries when constructing streams from iterables.

  • #1574 f82f549 Thanks @tim-smart! - Fix AI tool handler error typing so LanguageModel.generateText with a toolkit exposes wrapped AiError values rather than leaking raw AiErrorReason in the error channel.

  • #1577 78a3382 Thanks @tim-smart! - fix VariantSchema.Union

4.0.0-beta.21

Patch Changes

  • #1555 e691909 Thanks @tim-smart! - fix Stream.withSpan options

  • #1548 d5f413f Thanks @effect-bot! - Fix TxPubSub.publish and TxPubSub.publishAll overloads to require Effect.Transaction in their return environment.

  • #1557 139d152 Thanks @A386official! - Fix MCP resource template parameter names resolving as param0, param1 instead of actual names by checking isParam on the original schema before toCodecStringTree transformation.

  • #1547 947e3d4 Thanks @effect-bot! - Fix Schedule.reduce to persist state updates when the combine function returns a synchronous value.

  • #1545 84b2cce Thanks @effect-bot! - Fix TupleWithRest post-rest validation to check each tail index sequentially.

  • #1552 7f5305e Thanks @tim-smart! - Constrain HttpServerRequest.source to object and key server-side request weak caches by request.source so middleware request wrappers share the same cache entries.

  • #1556 9e6fd84 Thanks @tim-smart! - rename WorkflowEngine.layer

  • #1558 fdb8a4b Thanks @tim-smart! - Fix Workflow.executionId to use schema makeUnsafe instead of the removed .make API.

  • #1553 0f986ef Thanks @kaylynb! - Fix spans never having parent span

  • #1541 9355fc0 Thanks @tim-smart! - Add Effect.findFirst and Effect.findFirstFilter for short-circuiting effectful searches over iterables.

4.0.0-beta.20

Patch Changes

  • #1533 842a624 Thanks @tim-smart! - move ChildProcess apis into spawner service

  • #1536 4785eef Thanks @tim-smart! - add Context.Key type, used a base for Context.Service and Context.Reference

  • #1531 8fac95b Thanks @gcanti! - Revert Config.withDefault to v3 behavior, closes #1530.

    Make Config.withDefault accept an eager value instead of LazyArg, aligning with CLI module conventions.

  • #1535 12ee8e2 Thanks @tim-smart! - change default ErrorReporter severity to Info

  • #1529 e542c94 Thanks @tim-smart! - Add dedicated AiError metadata interfaces per reason so provider packages can safely augment metadata without conflicting module declarations.

  • #1531 8fac95b Thanks @gcanti! - Fix Config.withDefault type inference, closes #1530.

  • #1528 6f4ebd1 Thanks @tim-smart! - Add Model.ModelName and provide it from AI model constructors.

  • #1537 989d1cc Thanks @tim-smart! - Revert Effect.partition to Effect v3 behavior by accumulating failures from the effect error channel and never failing.

4.0.0-beta.19

4.0.0-beta.18

Minor Changes

  • #1515 01e31fd Thanks @mikearnaldi! - Add transactional STM modules: TxDeferred, TxPriorityQueue, TxPubSub, TxReentrantLock, TxSubscriptionRef.

    Refactor transaction model: remove Effect.atomic/Effect.atomicWith, add Effect.withTxState. All Tx operations now return Effect<A, E, Transaction> requiring explicit Effect.transaction(...) at boundaries.

    Expose TxPubSub.acquireSubscriber/releaseSubscriber for composable transaction boundaries. Fix TxSubscriptionRef.changes race condition ensuring current value is delivered first.

    Remove TxRandom module.

Patch Changes

  • #1518 0890aab Thanks @IMax153! - Fix Command.withGlobalFlags type inference when mixing GlobalFlag.action and GlobalFlag.setting.

    Setting service identifiers are now correctly removed from command requirements in mixed global flag arrays.

  • #1520 725260b Thanks @IMax153! - Ensure that OpenAI JSON schemas for tool calls and structured outputs are properly transformed

4.0.0-beta.17

Patch Changes

  • #1516 8f59c32 Thanks @gcanti! - Fix Schema.encodeKeys to encode non-remapped struct fields during encoding.

4.0.0-beta.16

Patch Changes

  • #1513 bf9096c Thanks @gcanti! - Add SchemaParser.makeOption and Schema.makeOption for constructing schema values as Option.

  • #1508 29f81ca Thanks @gcanti! - Schema: add OptionFromUndefinedOr and OptionFromNullishOr schemas.

  • #1498 68eb28c Thanks @kaylynb! - Fix OpenApi Multipart file upload schema generation

4.0.0-beta.15

Patch Changes

  • #1500 24ae609 Thanks @qadama831! - Unwrap _Success schema to enable field access.

  • #1486 0e3c059 Thanks @tim-smart! - Fix Stream.groupedWithin to stop emitting empty arrays when schedule ticks fire while upstream is idle.

  • #1503 e843b0a Thanks @tim-smart! - allow creating standalone http handlers from HttpApiEndpoints

  • #1499 f4389a2 Thanks @tim-smart! - fix atom node timeout cleanup

  • #1494 5b73de0 - Refine ExtractServices to omit tool handler requirements when automatic tool resolution is explicitly disabled through the disableToolCallResolution option.

  • #1496 595d2d6 Thanks @IMax153! - Refactor unstable CLI global flags to command-scoped declarations.

    Breaking changes

    • Remove GlobalFlag.add, GlobalFlag.remove, and GlobalFlag.clear
    • Add Command.withGlobalFlags(...) as the declaration API for command/subcommand scope
    • Change GlobalFlag.setting constructor to curried form which carries type-level identifier:
      • before: GlobalFlag.setting({ flag, ... })
      • after: GlobalFlag.setting("id")({ flag })
    • Change setting context identity to a stable type-level string:
      • effect/unstable/cli/GlobalFlag/${id}

    Behavior changes

    • Global flags are now scoped by command path (root-to-leaf declarations)
    • Out-of-scope global flags are rejected for the selected subcommand path
    • Help now renders only global flags active for the requested command path
    • Setting defaults are sourced from Flag combinators (optional, withDefault) rather than setting constructor defaults

4.0.0-beta.14

Patch Changes

  • #1471 c414700 Thanks @IMax153! - Make CLI global settings directly yieldable and simplify built-in names.

    GlobalFlag.setting now takes { flag, defaultValue } and returns a setting that is a Context.Reference, so handlers and Command.provide* effects can yield* global setting values directly.

    Built-in settings keep internal behavior in runWith (for example, --log-level still configures References.MinimumLogLevel) while also being readable as values.

    Also renamed built-in globals:

    • GlobalFlag.CompletionsFlag -> GlobalFlag.Completions
    • GlobalFlag.LogLevelFlag -> GlobalFlag.LogLevel
  • #1490 a30c969 Thanks @gcanti! - Fix OpenApi.fromApi preserving multiple response content types for one status code, closes #1485.

4.0.0-beta.13

Patch Changes

  • #1454 368f4c3 Thanks @lucas-barake! - Expose NoSuchElementError in the error type of stream-based Atom.make overloads.

  • #1469 db8a579 Thanks @tim-smart! - Update unstable schema variant helpers to use array-based arguments for FieldOnly, FieldExcept, and Union, aligning VariantSchema and Model with other v4 API shapes.

  • #1457 668b703 Thanks @tim-smart! - Run request resolver batch fibers with request services by using Effect.runForkWith, so resolver delay effects and runAll execution see the request service map.

  • #1461 d40e76b Thanks @mikearnaldi! - Fix Schedule.fixed double-executing the effect due to clock jitter.

    The elapsedSincePrevious > window check included sleep time from the previous step, so any timer imprecision (e.g. 1001ms for a 1000ms sleep) triggered an immediate zero-delay re-execution.

  • #1464 6e18cf8 Thanks @gcanti! - Use the identifier annotation as the expected message when available, closes #1458.

  • #1475 86062e8 Thanks @tim-smart! - Add a CI check job that runs pnpm ai-docgen and fails if it produces uncommitted changes.

  • #1448 c27ce75 Thanks @IMax153! - Refactor CLI built-in options to use Effect services with GlobalFlag

    Built-in CLI flags (--help, --version, --completions, --log-level) are now implemented as Effect services using Context.Reference. This provides:

    • Visibility: Built-in flags now appear in help output’s “GLOBAL FLAGS” section
    • Extensibility: Users can register custom global flags via GlobalFlag.add
    • Override capability: Built-in flag behavior can be replaced or disabled
    • Composability: Flags compose via Effect’s service system

    New GlobalFlag module exports:

    • Action<A> and Setting<A> types for different flag behaviors
    • Help, Version, Completions, LogLevel references for built-in flags
    • add, remove, clear functions for managing global flags

    Example:

    const app = Command.make("myapp");
    Command.run(app, { version: "1.0.0" }).pipe(
    GlobalFlag.add(CustomFlag, customFlagValue),
    );
  • #1468 e2d4fbf Thanks @lucas-barake! - Fix Rpc.ExtractProvides to use middleware service ID instead of constructor type.

  • #1465 114ab42 Thanks @lloydrichards! - tighten Schema on _meta fields in McpSchema; closes #1463

  • #1470 484caec Thanks @tim-smart! - Add Command.withAlias for unstable CLI commands, including subcommand parsing by alias and help output that renders aliases as name, alias in subcommand listings.

4.0.0-beta.12

Patch Changes

  • #1439 70a74e8 Thanks @gcanti! - Add Config.nested combinator to scope a config under a named prefix, closes #1437.

  • #1452 b5b6e10 Thanks @tim-smart! - make fiber keepAlive setInterval evaluation lazy

  • #1431 f5ce5a9 Thanks @tim-smart! - Add Random.nextBoolean for generating random boolean values.

  • #1450 a29eb70 Thanks @tim-smart! - use cause annotations for detecting client aborts

  • #1445 c7b36e5 Thanks @mattiamanzati! - Fix Graph.toMermaid to escape special characters using HTML entity codes per the Mermaid specification.

  • #1443 9381d6d Thanks @mikearnaldi! - Fix HttpClient.retryTransient autocomplete leaking Schedule internals by splitting the {...} | Schedule union into separate overloads.

  • #1444 88439f1 Thanks @gcanti! - Schema.encodeKeys: relax input constraint from Struct to schemas with fields so Schema.Class works, closes #1412.

  • #1438 e35307d Thanks @mikearnaldi! - Atom.searchParam: decode initial URL values correctly when a schema is provided

  • #1425 c7df4bc Thanks @candrewlee14! - Fix LanguageModel stripping of resolved approval artifacts across multi-round conversations.

    Previously, stripResolvedApprovals only ran when there were pending approvals in the current round. Stale artifacts from earlier rounds would leak to the provider, causing errors. The stripping now runs unconditionally.

    In streaming mode, pre-resolved tool results are also emitted as stream parts so Chat.streamText persists them to history, preventing re-resolution on subsequent rounds.

  • #1453 accaf3b Thanks @tim-smart! - allow mcp errors to be encoded correctly

  • #1440 3e1c270 Thanks @lloydrichards! - extend McpSchema to work with extensions

  • #1447 6cd81f7 Thanks @tim-smart! - remove all non-regional service usage

  • #1451 f222da3 Thanks @tim-smart! - Add Effect.annotateLogsScoped to apply log annotations for the current scope and automatically restore previous annotations when the scope closes.

  • #1434 61f901d Thanks @tim-smart! - Fix JSON-RPC serialization to return an object for non-batched requests while preserving array responses for true batch requests.

4.0.0-beta.11

Patch Changes

  • #1429 88659ed Thanks @tim-smart! - Add grouped subcommand support to Command.withSubcommands, including help output sections for named groups while keeping ungrouped commands under SUBCOMMANDS.

  • #1426 f2915e8 Thanks @tim-smart! - Add Effect.validate for validating collections while accumulating all failures, equivalent to the v3 Effect.validateAll behavior.

  • #1430 eb71ace Thanks @tim-smart! - Add Command.withExamples to attach concrete usage examples to CLI commands, expose them through HelpDoc.examples, and render them in the default help formatter.

  • #1415 2a16999 Thanks @mikearnaldi! - HashMap: compare HAMT bit positions as unsigned to preserve entry lookup when bit 31 is set

  • #1417 d42dd52 Thanks @mikearnaldi! - unstable/http Headers: hide inspectable prototype methods from for..in iteration to avoid invalid header names in runtime fetch polyfills

  • #1418 339adaf Thanks @mikearnaldi! - runtime: guard keepAlive setInterval / clearInterval so Effect.runPromise works in runtimes that block timer APIs

  • #1416 de19645 Thanks @mikearnaldi! - Queue.collect: stop duplicating drained messages by appending each batch once

  • #1413 9b1dc3b Thanks @gcanti! - Fix Schema.TupleWithRest incorrectly accepting inputs with missing post-rest elements, closes #1410.

  • #1409 e4cb2f5 Thanks @tim-smart! - add ErrorReporter module

  • #1427 8bced95 Thanks @tim-smart! - Add Command.annotate and Command.annotateMerge to unstable CLI commands, and include command annotations in HelpDoc so custom help formatters can access command metadata.

  • #1401 9431420 Thanks @tim-smart! - Add WorkflowEngine.layer, an in-memory layer for the unstable workflow engine.

  • #1428 948dca2 Thanks @tim-smart! - Add Command.withShortDescription and use short descriptions for CLI subcommand listings, with fallback to the full command description.

  • #1405 d18e327 Thanks @candrewlee14! - Strip resolved tool approval artifacts from prompt before sending to provider, preventing errors when providers reject pre-resolved approval requests.

  • #1424 ab512f7 Thanks @tim-smart! - expose more atom Node properties

4.0.0-beta.10

Patch Changes

  • #1396 371acab Thanks @gcanti! - Add unstable/encoding subpath export.

  • #1392 856d774 Thanks @tim-smart! - Fix a race in Semaphore.take where interruption could leak permits after a waiter was resumed.

  • #1388 b9e9202 Thanks @tim-smart! - Export Effect do notation APIs (Do, bindTo, bind, and let) from effect/Effect and add runtime and type-level coverage.

  • #1387 1d1a974 Thanks @tim-smart! - short circuit when Fiber.joinAll is called with an empty iterable

  • #1386 6bfe2a6 Thanks @tim-smart! - simplify http logger disabling

  • #1381 b12c811 Thanks @tim-smart! - Fix UrlParams.Input usage to accept interface-typed records in HTTP client and server helpers while keeping coercion constraints for url parameter values.

  • #1383 d17d98a Thanks @tim-smart! - Rename HttpClient.retryTransient option mode to retryOn and rename "both" to "errors-and-responses".

  • #1399 68c3c7c Thanks @tim-smart! - Add Random.shuffle to shuffle iterables with seeded randomness support.

4.0.0-beta.9

Patch Changes

  • #1376 3386557 Thanks @gcanti! - HttpApiEndpoint: relax params, query, and headers constraints to accept a full schema in addition to a record of fields.

  • #1379 b6666e3 Thanks @tim-smart! - Fix AtomHttpApi.query to forward v4 params / query request fields to HttpApiClient at runtime. Also align AtomHttpApi endpoint type inference with v4 HttpApiEndpoint params/query naming and add a regression test.

4.0.0-beta.8

Patch Changes

  • #1371 246e672 Thanks @IMax153! - Fix ChildProcess options type and implement PgMigrator

  • #1372 807dec0 Thanks @pawelblaszczyk5! - Remove superfluous error from SqlSchema.findAll signature

4.0.0-beta.7

Patch Changes

  • #1366 a2bda6d Thanks @tim-smart! - rename SqlSchema.findOne* apis

  • #1360 1f95a2b Thanks @tim-smart! - Add Schedule.jittered to randomize schedule delays between 80% and 120% of the original delay.

  • #1364 a8d5e79 Thanks @gcanti! - Schema: avoid eager resolution for type-level helpers, closes #1332

  • #1369 a5386ba Thanks @tim-smart! - align HttpClientRequest constructors with http method names

  • #1369 a5386ba Thanks @tim-smart! - remove body restriction for HttpClientRequest’s

  • #1358 06d8a03 Thanks @tim-smart! - Add LogLevel.isEnabled for checking a log level against References.MinimumLogLevel.

  • #1363 8caac76 Thanks @tim-smart! - rename DurationInput to Duration.Input

  • #1363 8caac76 Thanks @tim-smart! - DateTime.distance now returns a Duration

  • #1367 f9e883e Thanks @tim-smart! - refactor SqlSchema apis

  • #1363 8caac76 Thanks @tim-smart! - remove rpc client nesting to improve type performance

4.0.0-beta.6

Patch Changes

  • #1338 3247da2 Thanks @Leka74! - Add showOperationId to HttpApiScalar.ScalarConfig.

  • #1326 f205705 Thanks @gcanti! - Schema: add BigDecimal schema with comparison checks (isGreaterThanBigDecimal, isGreaterThanOrEqualToBigDecimal, isLessThanBigDecimal, isLessThanOrEqualToBigDecimal, isBetweenBigDecimal).

  • #1328 f35022c Thanks @gcanti! - Schema: add DateTimeZoned, TimeZoneOffset, TimeZoneNamed, and TimeZone schemas.

  • #1325 8622721 Thanks @KhraksMamtsov! - Make Data.Class, Data.TaggedClass, and Cause.YieldableError pipeable.

  • #1323 fc660ab Thanks @KhraksMamtsov! - Port Pipeable.Class from v3.

    class MyClass extends Pipeable.Class() {
    constructor(public a: number) {
    super();
    }
    methodA() {
    return this.a;
    }
    }
    console.log(new MyClass(2).pipe((x) => x.methodA())); // 2
    class A {
    constructor(public a: number) {}
    methodA() {
    return this.a;
    }
    }
    class B extends Pipeable.Class(A) {
    constructor(private b: string) {
    super(b.length);
    }
    methodB() {
    return [this.b, this.methodA()];
    }
    }
    console.log(new B("pipe").pipe((x) => x.methodB())); // ['pipe', 4]
  • #1337 f37dc33 Thanks @IMax153! - Encoding: consolidate effect/encoding sub-modules (Base64, Base64Url, Hex, EncodingError) into a top-level Encoding module. Functions are now prefixed: encodeBase64, decodeBase64, encodeHex, decodeHex, etc. The effect/encoding sub-path export is removed.

  • #1351 3662f32 Thanks @tim-smart! - add Schema.HashSet for decoding and encoding HashSet values.

  • #1336 a7d436f Thanks @mikearnaldi! - Extract Semaphore and Latch into their own modules.

    Semaphore.make / Semaphore.makeUnsafe replace Effect.makeSemaphore / Effect.makeSemaphoreUnsafe. Latch.make / Latch.makeUnsafe replace Effect.makeLatch / Effect.makeLatchUnsafe.

    Merge PartitionedSemaphore into Semaphore as Semaphore.Partitioned, Semaphore.makePartitioned, Semaphore.makePartitionedUnsafe.

  • #1345 6856a41 Thanks @tim-smart! - allocate less effects when reading a file

  • #1350 8c417d0 Thanks @tim-smart! - Add “Previously Known As” JSDoc migration notes for the Semaphore and Latch APIs extracted from Effect.

  • #1355 5419570 Thanks @tim-smart! - ensure non-middleware http errors are correctly handled

  • #1352 449c5ed Thanks @tim-smart! - Add Schema.HashMap for decoding and encoding HashMap values.

  • #1347 4b5ec12 Thanks @tim-smart! - use .toJSON for default .toString implementations

  • #1329 df87937 Thanks @gcanti! - Schema: extract shared dateTimeUtcFromString transformation for DateTimeUtc and DateTimeUtcFromString.

  • #1318 5dbfca8 Thanks @gcanti! - Schema: rename $ suffix to $ prefix for type-level identifiers that conflict with built-in names (Array$$Array, Record$$Record, ReadonlyMap$$ReadonlyMap, ReadonlySet$$ReadonlySet).

  • #1356 e629497 Thanks @tim-smart! - allow passing void for request constructors

  • #1348 981c991 Thanks @tim-smart! - Fix Schedule.andThenResult to initialize the right schedule only after the left schedule completes. This removes the extra immediate transition tick and correctly completes when the right schedule is finite.

  • #1320 1ca2ed6 Thanks @gcanti! - Struct: add Struct.Record constructor for creating records with the given keys and value.

  • #1342 45722bd Thanks @cevr! - Schema.TaggedErrorClass, Schema.Class, and Schema.ErrorClass constructors now allow omitting the props argument when all fields have constructor defaults (e.g. new MyError() instead of new MyError({})).

  • #1322 eb2a85e Thanks @tim-smart! - Add a requireServicesAt option to PersistedCache.make so lookup-service requirements can be configured like Cache.

4.0.0-beta.5

Patch Changes

  • #1317 f6e133e Thanks @tim-smart! - support tag unions in Effect.catchTag/Reason

  • #1314 e3893cc Thanks @zeyuri! - Fix Atom.serializable encode/decode for wire transfer.

    Use Schema.toCodecJson instead of Schema.encodeSync/Schema.decodeSync directly, so that encoded values are plain JSON objects that survive serialization roundtrips (JSON, seroval, etc.). Previously, AsyncResult.Schema encode produced instances with custom prototypes that were lost after wire transfer, causing decode to fail with “Expected AsyncResult” errors during SSR hydration.

  • #1315 a88e206 Thanks @tim-smart! - add Filter.reason api

  • #1314 e3893cc Thanks @zeyuri! - Port ReactHydration to effect-smol.

    Add Hydration module to effect/unstable/reactivity with dehydrate, hydrate, and toValues for SSR state serialization. Add HydrationBoundary React component to @effect/atom-react with two-phase hydration (new atoms in render, existing atoms after commit).

4.0.0-beta.4

Patch Changes

  • #1308 c5a18ef Thanks @tim-smart! - improve Schema.TaggedUnion .match auto completion

  • #1310 bc6b885 Thanks @tim-smart! - Add Schedule.duration, a one-shot schedule that waits for the provided duration and then completes.

4.0.0-beta.3

Patch Changes

  • #1303 3a0cf36 Thanks @tim-smart! - add Result.failVoid

  • #1307 c4da328 Thanks @tim-smart! - Add HttpClientRequest.bodyFormDataRecord and HttpBody.makeFormDataRecord helpers for creating multipart form bodies from plain records.

4.0.0-beta.2

Patch Changes

  • #1302 a22ce73 Thanks @tim-smart! - allow undefined for VariantSchema.Overridable input

  • #1299 ebdabf7 Thanks @tim-smart! - Port SqlSchema.findOne from effect v3 to return Option on empty results and add SqlSchema.single for the fail-on-empty behavior.

  • #1298 8f663bb Thanks @tim-smart! - Add Effect.catchNoSuchElement, a renamed port of v3 Effect.optionFromOptional that converts NoSuchElementError failures into Option.none.

4.0.0-beta.1

Patch Changes

  • #1293 0fecf70 Thanks @mikearnaldi! - Add Effect.filter support for synchronous Filter.Filter overloads and correctly handle non-effect Result return values at runtime.

  • #1294 709569e Thanks @tim-smart! - Fix Prompt.text and related text prompts to initialize from default values so users can edit the default input directly.

4.0.0-beta.0

Major Changes