From tenequm-skills
Guides Effect-TS v3 and v4 development with correct API tables, version detection, and links to primary docs for building, debugging, and reviewing Effect code.
How this skill is triggered — by the user, by Claude, or both
Slash command
/tenequm-skills:effect-tsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Effect is a TypeScript library for building production-grade software with typed errors, structured concurrency, dependency injection, and built-in observability.
CHANGELOG.mdLICENSE.txtevals/evals.jsonreferences/cli.mdreferences/concurrency.mdreferences/configuration.mdreferences/core-patterns.mdreferences/datetime.mdreferences/dependency-injection.mdreferences/distributed.mdreferences/effect-ai.mdreferences/error-modeling.mdreferences/graph.mdreferences/http.mdreferences/llm-corrections.mdreferences/migration-async.mdreferences/migration-v4.mdreferences/observability.mdreferences/optics.mdreferences/resource-management.mdEffect is a TypeScript library for building production-grade software with typed errors, structured concurrency, dependency injection, and built-in observability.
Before writing Effect code, detect which version the user is on:
# Check installed version
cat package.json | grep '"effect"'
Context.Service, Effect.catch, Effect.forkChild, Schema.TaggedErrorClassContext.Tag, Effect.catchAll, Effect.fork, Data.TaggedErrorNote: v4 beta briefly used a
ServiceMapmodule, renamed back toContexton 2026-04-07 (PR #1961). If you seeServiceMap.*in any doc or older beta code, it is the currentContext.*. Both v3 and v4 importContextfrom"effect"; the exports inside differ (Context.Servicein v4 vsContext.Tagin v3).
Prefer v4 for new projects - it's where Effect is going. In an existing codebase, match the installed version: don't rewrite v3 code in v4 syntax unless asked. If the version is genuinely unclear, default to v4 and say so. v4 is still in beta, so pin an exact version (4.0.0-beta.x) and expect occasional API churn.
v4 (primary):
v3 (for existing codebases):
Both versions:
LLM outputs frequently contain incorrect Effect APIs. Verify every API against the reference docs before using it.
Common hallucinations (both versions):
| Wrong (AI often generates) | Correct |
|---|---|
Effect.cachedWithTTL(...) | Cache.make({ capacity, timeToLive, lookup }) |
Effect.cachedInvalidateWithTTL(...) | cache.invalidate(key) / cache.invalidateAll() |
Effect.mapError(effect, fn) | Effect.mapError(fn) in pipe, or use Effect.catchTag |
import { Schema } from "@effect/schema" | import { Schema } from "effect" (v3.10+ and all v4) |
import { JSONSchema } from "@effect/schema" | import { JSONSchema } from "effect" (v3.10+) |
| JSON Schema Draft 2020-12 | Effect Schema generates Draft-07 |
| "thread-local storage" | "fiber-local storage" via FiberRef (v3) / Context.Reference (v4) |
| fibers are "cancelled" | fibers are "interrupted" |
| all queues have back-pressure | only bounded queues; sliding/dropping do not |
new MyError("message") | new MyError({ message: "..." }) (Schema errors take objects) |
v3-specific hallucinations:
| Wrong | Correct (v3) |
|---|---|
Effect.Service (function call) | class Foo extends Effect.Service<Foo>()("id", {}) |
Effect.match(effect, { ... }) | Effect.match(effect, { onSuccess, onFailure }) |
Effect.provide(layer1, layer2) | Effect.provide(Layer.merge(layer1, layer2)) |
v4-specific hallucinations (AI may mix v3/v4):
| Wrong (v3 API used in v4 code) | Correct (v4) |
|---|---|
Context.Tag("X") (v3 shape) | Context.Service<X>(id) or class syntax |
ServiceMap.Service / ServiceMap.Reference | Renamed back to Context.Service / Context.Reference on 2026-04-07 |
Effect.catchAll(fn) | Effect.catch(fn) |
Effect.fork(effect) | Effect.forkChild(effect) |
Effect.forkDaemon(effect) | Effect.forkDetach(effect) |
Data.TaggedError | Schema.TaggedErrorClass |
FiberRef.get(ref) | yield* References.X (a Context.Reference) |
yield* ref (Ref as Effect) | yield* Ref.get(ref) (Ref is no longer an Effect) |
yield* fiber (Fiber as Effect) | yield* Fiber.join(fiber) (Fiber is no longer Effect) |
Logger.Default / Logger.Live | Logger.layer (v4 naming convention) |
Schema.TaggedError | Schema.TaggedErrorClass |
Schema.makeUnsafe(input) | Schema.make(input) (throws SchemaError); also instance methods schema.makeOption(...), schema.makeEffect(...) |
ParseResult (from "effect") | SchemaIssue module + SchemaError class; narrow with Schema.isSchemaError |
HttpApiEndpoint.get(n, p).pipe(HttpApiEndpoint.setPath(...), setPayload(...), setSuccess(...)) | HttpApiEndpoint.get(n, p, { params, query, payload, success, error }) (object-option form) |
Otlp.layer({ url, serviceName }) | OtlpTracer.layer({ url, resource: { serviceName } }) + OtlpSerialization.layerJson + FetchHttpClient.layer |
import { HttpApi } from "@effect/platform" (v4) | import { HttpApi } from "effect/unstable/httpapi" |
| HttpApi endpoint schema errors are typed errors by default | In current v4 betas they default to defects unless transformed |
Read references/llm-corrections.md for the exhaustive corrections table.
Read only the reference files relevant to your task:
references/error-modeling.mdreferences/dependency-injection.mdLayerMap) → references/dependency-injection.mdManagedRuntime) → references/dependency-injection.mdreferences/retry-scheduling.mdreferences/concurrency.mdreferences/concurrency.mdExecutionPlan) → references/effect-ai.md / references/retry-scheduling.mdreferences/streams.mdreferences/streams.mdreferences/concurrency.mdreferences/resource-management.mdreferences/resource-management.mdRcRef/RcMap) → references/resource-management.mdreferences/schema.mdBrand) → references/schema.mdreferences/observability.mdreferences/http.mdreferences/http.md (covers both client and server)references/http.mdreferences/effect-ai.mdreferences/configuration.mdreferences/sql.mdreferences/cli.mdreferences/rpc.mdreferences/distributed.mdTx*) → references/stm.mdreferences/datetime.mdreferences/optics.mdreferences/graph.mdMatch) → references/core-patterns.mdPool) → references/resource-management.mdreferences/concurrency.mdreferences/testing.mdreferences/testing.mdreferences/migration-async.mdreferences/migration-v4.mdreferences/core-patterns.mdreferences/llm-corrections.mdpackage.json before writing any codeEffect valuesEffect.gen for sequential logic, pipelines for simple transforms. In v4, prefer Effect.fn("name") for named functionsE channel; treat bugs as defectsScope when opening/closing things (files, connections, etc.)NodeRuntime.runMain or ManagedRuntime)Start with these ~20 functions (the official recommended set):
Creating effects: Effect.succeed, Effect.fail, Effect.sync, Effect.tryPromise
Composition: Effect.gen (+ Effect.fn in v4), Effect.andThen, Effect.map, Effect.tap, Effect.all
Running: Effect.runPromise, NodeRuntime.runMain (preferred for entry points)
Error handling: Effect.catchTag, Effect.catch (v4) / Effect.catchAll (v3), Effect.orDie
Resources: Effect.acquireRelease, Effect.acquireUseRelease, Effect.scoped
Dependencies: Effect.provide, Effect.provideService
Key modules: Effect, Schema, Layer, Option, Result (v4) / Either (v3), Array, Match
DI (v4): Context.Service, Context.Reference, Layer.effect, Effect.fn("name")
DI (v3): Context.Tag, Context.Reference
Always use barrel imports from "effect":
import { Context, Effect, Schema, Layer, Option, Stream } from "effect"
For companion packages, import from the package name. v3 and v4 differ here:
// v4 (recommended) - platform transports still separate, but HttpApi / observability
// moved under effect/unstable/*
import { NodeRuntime } from "@effect/platform-node"
import { FetchHttpClient } from "effect/unstable/http"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiBuilder, HttpApiScalar } from "effect/unstable/httpapi"
import { OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability"
// v3 (stable) companion packages
import { NodeRuntime } from "@effect/platform-node"
import { HttpClient } from "@effect/platform"
import { NodeSdk } from "@effect/opentelemetry"
Avoid deep module imports (effect/Effect) unless your bundler requires it for tree-shaking.
Effect.gen (imperative) for multi-step logic; pipelines for transformsEffect.fn("name") instead of bare Effect.gen for named functions; use Effect.fnUntraced for internal helpers that don't need a span/stack-frameEffect.runPromise / Effect.runSync inside library code - only at program edgesNodeRuntime.runMain for CLI/server entry points (handles SIGINT gracefully)ManagedRuntime when integrating Effect into non-Effect frameworks (Hono, Express, etc.)return yield* when raising an error in a generator (ensures TS understands control flow)Effect.map((x) => fn(x)) not Effect.map(fn) (generics get erased)Effect<A, E, R> shape when it helps design decisionsBefore outputting Effect code, verify:
"effect" (not @effect/schema, @effect/io, etc.)E; unexpected failures are defectsrun* is called only at program edges, not inside library codeacquireRelease are wrapped in Effect.scopedR requirements)yield* (not yield without *)return yield* patternnpx claudepluginhub tenequm/skillsExpert guidance for nontrivial Effect-TS work: services/layers, typed errors, Schema/JSONSchema, Config, runtime/concurrency, @effect/vitest, @effect/ai, @effect/sql, or @prb/effect-next.
Provides expert guidance on Effect-TS patterns including services, layers, error handling, service composition, and refactoring code with 'effect' imports. Covers Effect + Next.js integration.
Provides best practices and reference files for Effect-TS: typed errors, services/layers, Schema validation, fiber concurrency, Stream/Sink, and migration from Promises/fp-ts/neverthrow.