effect-ts — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited effect-ts (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Effect 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 aServiceMapmodule, 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 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 | Since PR #2057 (2026-04-20) 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.mdreferences/retry-scheduling.mdreferences/concurrency.mdreferences/concurrency.mdExecutionPlan) → references/effect-ai.md / references/retry-scheduling.mdreferences/streams.mdreferences/resource-management.mdreferences/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.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* pattern~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.