effect
Skill23 starsChanged 11 days agoMITView on GitHub
Apply Effect v4 conventions for services, layers, tagged errors, boundary runners, resources, retries, deadlines, HTTP, and tests. Use when writing or reviewing TypeScript that imports effect, adds a service or error class, chooses where to run a program, bounds external I/O, or tests Effect code.
We split this skill into the rules it gives an agent
2 rules. 0 are common, 0 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 14 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 16
Run programs only at boundaries, through the repo's runner and one ManagedRuntime per process (NodeRuntime.runMain for Node entrypoints).
- Very specific: line 54
Read config with Config inside the layer that needs it.
“Common” is measured: kept by at least 6 in 10 of the 14 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Effect v4
Assumes Effect v4 (the effect@4.0.x line, including its release candidates). Effect 3 differs in names and modules (Context.Tag, Effect.catchAll, @effect/platform); do not mix the two. Read the installed version before using an API you have not seen in the repo, and follow the repo's AGENTS.md where it differs from this skill: a repo rule or a documented exception wins.
Repo facts (from AGENTS.md): pinned Effect version and how bumps land, import policy (deep imports, effect/unstable/* barrels), boundary runners and the shared ManagedRuntime, the house error file, Effect lint gates, test runner and helpers, check and test commands.
Boundaries
A boundary is where a Promise or process exit is the contract: an HTTP or route handler, a framework load or action, a Durable Object method, a queue or workflow step body, an extension or CLI entrypoint. Everything else returns an Effect under its own name and composes with yield*.
- Run programs only at boundaries, through the repo's runner and one
ManagedRuntimeper process (NodeRuntime.runMainfor Node entrypoints). NoEffect.runPromise/runSync/runForkin domain code outside tests. - No
fooEffecttwin, no Promise wrapper lifted back withEffect.promise, no runner's Promise re-entered as an Effect. - Browser code may import pure modules (
Schema,Option,Data,Result) but never runs a program that needs services. - Deep imports (
import * as Effect from "effect/Effect") unless the repo says otherwise. Keep every package on the same exact Effect version; bump it in its own change.
Errors
- One class per expected failure, owned by the package that raises it.
Schema.TaggedErrorwhen the error crosses a serialization boundary (wire, RPC, journal);Data.TaggedErroris fine in-process if the repo allows it. TypecauseasSchema.Defect(). - Class name,
_tag, wirecode, andcatchTagargument are one identifier, unique across everything a consumer can see. The compiler cannot catch a duplicate tag; use the repo's check if it has one. - Derive
messageon the class; never author it at the call site.
class OrderNotFound extends Schema.TaggedError<OrderNotFound>()("OrderNotFound", {
id: Schema.String,
}) {
override get message() {
return `order ${this.id} not found`;
}
}
const load = Effect.fn("loadOrder")(function* (id: string) {
const row = yield* findOrder(id);
if (!row) return yield* new OrderNotFound({ id });
return row;
});- Narrow with
Effect.catchTag/catchTags, never by comparing acodeor message string. - Lift a Promise API with
Effect.tryPromise({ try, catch: (cause) => new SpecificError({ cause }) }). Never a zero-argcatch, never one generic catch-all class. An unmapped throw stays a defect. - Decode an error of unknown shape (RPC envelope, stored JSON, step failure) with a
Schema.Unionof the classes that operation admits, and derive the type from that schema. Never guess a class. - The public wire shape is an explicit projection (
{ code, message }plus any public fields). Never encode the error class itself: that emitsname,message, and nestedcause. - Defects (bugs, missing config, broken bindings, failed setup) stay defects. Do not wrap setup or pure factories in
Effect.try, and do notEffect.catchDefect/catchCausethem into a domain error. The boundary runner reports and sanitizes them. - Retry policy lives where the retry happens (a
whileguard naming tags); errors carry no retryable flag.
Services and resources
- A service is a
Context.Serviceclass with a concrete shape (class Db extends Context.Service<Db, DbShape>()("Db") {}). Dependencies travel inRand are supplied byLayerat the composition root. Tags expose shapes, not fallible Effects that produce shapes. - No
deps = liveDepsparameter bags or module singletons. Build clients, pools, and connections in a scoped layer withEffect.acquireReleaseso they close on shutdown and interruption. - On serverless runtimes (Workers), request-scoped I/O never lives in a memoized layer.
- Read config with
Configinside the layer that needs it; missing required config is a startup defect.
Functional core
- Pure calculation (scoring, state transitions, diffing, decoding) stays synchronous and outside
Effect.gen. Do not wrap a pure decision in an Effect. - Inside programs read time and randomness through
ClockandRandom, neverDate.now(),new Date(),Math.random(), or ambientcrypto.randomUUID(). In durable workflows, read time through the workflow's journaled step before branching. - Brand entity IDs at ingress with
Schema.brand(orBrand.nominaloutside schemas). UseData.Classfor in-memory equality; keep wire and journal values plain JSON.
State machines
Effect v4 has no state-machine module. Follow eng-state-machine for the design; this is how its parts map to Effect.
decideis plain TypeScript with noEffect,Clock, or service. If the repo provides a machine kernel (see its repo facts), use that kernel'sdecide. Otherwise match on both dimensions so a missing (state, command) pair is a type error: an outerMatch.exhaustiveover the state union with an inner one over theSchema.TaggedUnionof commands, or one match over a union of pairs. Matching commands alone only proves every command has a handler.- Decode the stored status at the boundary with
Schema.Literals([...states]), so an unknown value never reachesdecide, unless the kernel'sdecidealready rejects unknown states as data. decidereturns a rejection as data. The write turns it into the owning package's tagged error; do not makedecidefail in the error channel.- The write is one
Effect.fninside the repo's transaction: lock or read,decide, guarded update, outbox row. Read time and ids fromClockand the id service and pass them todecide. A guarded update that misses fails with a conflict tag the caller retries (Effect.retry({ while: (e) => e._tag === "...Conflict", times })); a miss under a row lock is a defect. - An in-memory machine (session, connection, worker) serializes moves with
SynchronizedRef.modifyEffectand publishes states withSubscriptionRef.changes. Multi-step processes that wait on time or events belong in the repo's workflow engine, not in an entity machine.
IO
- Trace service boundaries with
Effect.fn("operationName")(function* () {...}); add dynamic attributes withEffect.annotateCurrentSpan. Private helpers stay untraced. - Outbound HTTP uses
HttpClientwithFetchHttpClient.layer(the module path depends on the installed v4 build:effect/httporeffect/unstable/http/*; follow existing imports). Scope the response. No rawfetchwithAbortSignal.timeout,Promise.racetimers, or hand-rolled in-flight promise sets. - Give external I/O one total deadline covering setup, retries, retry delays, and body consumption:
Effect.timeoutaround the whole retried operation, andEffect.retry({ while: isTransient, times, schedule: Schedule.exponential(...).pipe(Schedule.jittered) })inside it. - Concurrency is
Effect.all/Effect.forEachwith explicit{ concurrency }, neverPromise.allinsideEffect.gen. Long-lived consumers useStream,Queue, andFiber/FiberSet, not ad hoc timers. - Scope child work to its request, document, or connection. Interruption must join bounded cleanup before release; lift fallible finalizers with
Effect.tryPromiseandEffect.orDiean unrecoverable release failure.
Testing
- Provide test layers (
Effect.provide(TestLayer),Effect.provideService) instead of stubbing globals orvi.mock(). Pure core functions get plain synchronous tests. - Time:
TestClockfromeffect/testing; fork the program, thenTestClock.adjust. - Assert the failure
_tagor code and the resulting state, not merely that something failed. - For boundary or resource-lifetime changes, add one test proving cancellation or cleanup (release order, stalled cleanup, no late writes), not just the success path. Signal readiness from the operation under test, not a sleep.
- Durable step ids and their journal shapes are a persisted contract: a rename or changed result shape under the same id breaks in-flight runs and replay. Give a changed step a new id.
Review checklist
rg -n 'Effect\.(runPromise|runSync|runFork)' --glob '!**/*.test.ts' <paths>finds only boundary runners.rg -n 'catchDefect|Date\.now\(\)|Math\.random\(\)' <changed paths>finds nothing inside Effect programs.- Each function returns its own Effect with the narrow union of tagged errors it can raise.
- A state real data can reach stays modeled: a nullable column decodes with
Schema.NullOr, a count over a cap is a tagged failure. NotorDie, not an invented?? 0default. An aggregate over zero rows returning its defined empty value is fine. - The repo's Effect gate, type check, and focused tests pass (commands in AGENTS.md).
Other versions14 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 14
- XiaomiMiMo/MiMo-Code★ 14ksame name
- supabase/cli★ 2.4ksame name
- rjdellecese/confect★ 380same name
- kitlangton/skills★ 326same name
- akitaonrails/my-skills★ 283same name
- mezotv/notra★ 256same name
- usenotra/notra★ 256same name
- getsentry/skillet★ 13same name
- itsyasirkhandev/skills★ 4same name
- timmo001/notes★ 2same name
4 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
Used alongsideProjects with it also use humanizer, vercel-react-best-practices and 2 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
Microsoft AzureSkillhumanizer
Tone enforcement patterns for external-facing community responses
Also in 3 projects that use this
VercelSkillvercel-react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Also in 3 projects that use this
GoogleSkillgrill-me
A relentless interview to sharpen a plan or design.
Also in 3 projects that use this
GoogleSkillcode-review
Adversarial systems, concurrency, memory-model, and architecture code review protocol. Use this skill whenever asked to review code, PRs, diffs, or branches in Filament.
Also in 3 projects that use this
In this repository31 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- agents-correctSkill
- agents-create-verification-skillSkill
- agents-reflectSkill
- agents-swarmSkill
- alchemy-infraSkill
- comms-howSkill
- comms-impactSkill
- comms-interrogateSkill
- comms-technical-writingSkill
- comms-unslopSkill
- comms-whySkill
- effect-boundary-validationSkill
- effect-seam-migrationSkill
- eng-agent-dx-cli-scaleSkill
- eng-benchmark-checklistSkill
- eng-blast-radiusSkill
- eng-change-checklistSkill
- eng-cutover-verificationSkill
- eng-state-machineSkill
- eng-tddSkill
- eng-testingSkill
- gh-ci-triageSkill
- gh-pr-commit-reviewSkill
- gh-pr-feedback-loopSkill
- nix-darwinSkill
- sentry-bugfixSkill
- sentry-perfSkill
- svelte-shadcnSkill
- svelte-ui-deliverySkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

