# AGENTS.md: Effect (TypeScript)

## Commands
`pnpm check` (tsc) · `pnpm lint` · `pnpm test` (`@effect/vitest`) · check `package.json` for the `effect` version and follow that version's docs.

## Rules
- Business logic returns `Effect<A, E, R>`; don't mix in raw `async/await` + `try/catch` in core modules. Convert at the edges with `Effect.tryPromise({ try, catch })`.
- Write effects with `Effect.gen(function* () { const x = yield* ... })` for readability; use `pipe` for short combinator chains.
- Errors are typed values: define them with `Data.TaggedError("NotFound")<{ id: string }>` (or `Schema.TaggedError`) and handle with `Effect.catchTag`/`catchTags`. Reserve defects (`Effect.die`) for bugs, not expected failures.
- Dependencies are services: `class Db extends Context.Tag("Db")<Db, {...}>() {}` (or `Effect.Service`), provided via `Layer`s composed in one place (`MainLive`). No module-level singletons or hidden globals.
- Validate all external input (HTTP, env, files, queues) with `Schema` (`Schema.decodeUnknown`); read config with `Config` instead of `process.env`.
- Resources use `Effect.acquireRelease` / `Scope` so connections and handles always close.
- Concurrency is explicit: `Effect.all(xs, { concurrency: 5 })`, `Effect.forEach` with a bound; use `Effect.timeout` and `Schedule` for retries with backoff.
- Run effects only at the program edge (`Effect.runPromise`, `NodeRuntime.runMain`, or the platform HTTP server). Never call `runPromise`/`runSync` inside library code.
- Log with `Effect.log*` and add spans with `Effect.withSpan` for tracing.

## Tests
Use `it.effect` from `@effect/vitest`, provide test Layers instead of mocking modules, and use `TestClock` for time.

## Done
Typecheck, lint and tests pass with no `any` and no unhandled error channels (`E` is `never` at the entrypoint).
