Effect 4 reference projects (studied 2026-09-18)

These projects show Effect service, test, CLI, and lifecycle patterns. The study dates are 2026-09-18 and 2026-09-20. Versions below come from each linked repo’s lockfile or catalog on those dates. Current compatibility needs a fresh check. See current pins, the current reference machine packages/core/src/inspect-machine.ts, and lifecycles are machines20.

For the browser client, Alchemy resources, database, auth, and Worker tests, see Effect + Alchemy peer patterns.

Projects

RepoStarsEffectRuntimeWhy it matters to us
pingdotgg/t3code23k4.0.0-rc.115 (catalog)Node 24, pnpm 11, TS 7.0.2Same Effect, TS, and pnpm pins as rat-stack. Closest sibling. Heaviest @effect/vitest user (479 files).
anomalyco/opencode208k4.0.0-beta.83 (patched)BunArchitecture reference only. Older beta: still has ServiceMap.Service remnants and Schema.TaggedErrorClass. Do not copy API names from it.
tim-smart/lalph1304.0.0-beta.94Node, pnpm, tsgoEffect core maintainer’s CLI. Uses effect/unstable/cli, Context.Service + static layer, @effect/language-service. Closest shape to our CLI.
kitlangton/ghui1.1k4.0.0-beta.90BunKit’s TUI. Context.Service, Schema.TaggedError, @effect/language-service, oxlint + oxfmt.
alchemy-run/alchemy1.3kpeer >=4.0.0-rc.115NodeOur infra layer. Peer-depends on @effect/language-service ^0.87.
cevr/effect-machine72peer >=4.0.0-rc.112 <5anySchema-first state machines native to Effect. The Effect-world answer to XState.

Other Effect 4 adopters found via GitHub code search for effect/unstable imports: alchemy-run/distilled, MapleTechLabs/maple, tim-smart/receipts, tim-smart/dfx, kitlangton/motel, kitlangton/stack, leonitousconforti/the-moby-effect, crosshatch/crosshatch, anomalyco/effect-http-recorder, Effectful-Tech/clanka.

Shared patterns

XState 6 and @xstate/effect (verified 2026-09-18)

None of the reference apps use XState. t3code models lifecycle as decider, projector, and reactor. opencode uses a LayerNode graph. cevr/effect-machine is the community Effect-native machine. But XState itself now ships an Effect 4 bridge for v6, and it is the one that matters for this stack.

Upstream contribution filed (2026-09-18)

Issue https://github.com/statelyai/xstate/issues/5725 (Joel’s account, labelled agent-generated, no PR by decision). Patch gist https://gist.github.com/joelhooks/99d193172a03609e67b4ef5849e8bbb1. Watch the issue for maintainer response before touching the lint plugin again.

The public patch gist records the proposed changes against XState next at 0748e1b. It ports the oxlint plugin to TypeScript on @oxlint/plugins@^1.76.0 (same version as their pinned oxlint), repoints .oxlintrc.json, the lint fixture config, lint.test.ts, and two docs mentions, and corrects the README and docs/testing-and-errors.md claim that join fails with “the machine’s typed error”: a machine’s ErrorFrom is unknown, and docs/observing-actors.md now says so and recommends final states plus orDie or catchAll. Verified in their tree: manypkg check, frozen install with postinstall, lint.test.ts 2/2, pnpm lint, oxfmt --check. Lock diff is 9 lines, spliced by hand because a non-frozen pnpm install here strips every tarball: field their lock keeps. The public issue and patch above are the contribution record.

Barrel and subpath imports

Applied 2026-09-18 (second slice, all remaining gaps)

Sweep 2026-09-20

Joel asked for a library sweep. Bumped to the newest tag on each pinned line: effect, @effect/platform-node, @effect/vitest rc.115 to rc.116; alchemy beta.78 to beta.79; turbo 2.10.13 to 2.11.2; varlock 1.19.0 to 1.20.0; oxlint-tsgolint 7.0.2001 to 7.0.2002; @earendil-works/pi-coding-agent 0.85.1 to 0.86.1; @types/node 24.13.5 to 24.13.6 (staying on the Node 24 line; 26.x exists). Already latest: TypeScript 7.0.2, vitest 5.0.1, oxlint and @oxlint/plugins 1.83.0, ultracite 7.12.0, oxfmt 0.68.0, lefthook 2.1.14, xstate 6.0.0-alpha.58, @xstate/effect 0.1.0-alpha.2, @effect/tsgo 0.45.0. Gate green with no source change for rc.116. pnpm wrote the six @earendil-works/*@0.86.1 entries into minimumReleaseAgeExclude itself (“loose mode”); the dead beta.78 entries were removed by hand. capnp-es still wants TypeScript 5 or 6 under alchemy; pre-existing, ignored.

Two fence findings on the way:

The vendor script’s xstate pin still pointed at apps/cli/package.json after the machine moved to packages/core; it resolved xstate@undefined. Fixed, mirrors refreshed to rc.116 and beta.79.

Gaps in rat-stack against this bar (as found 2026-09-18, all now closed)

  1. No @effect/language-service. This is the single largest missing fence for “agents write good Effect”. Every reference project has it.
  2. No service or layer in the example. readFileStats yields FileSystem directly. Agents most often get Context.Service + Layer + Layer.mock wrong in v4, and the template shows none of it.
  3. Plain vitest, not @effect/vitest. @effect/vitest@4.0.0-rc.115 is already in the pnpm store via alchemy but not declared. No it.effect or it.layer example exists.
  4. Closed 2026-09-18. @xstate/effect@0.1.0-alpha.2 is vendored as vendor/xstate-effect-0.1.0-alpha.2.tgz (built from tag xstate@6.0.0-alpha.58, see vendor/README.md for the npm swap rule). apps/cli/src/inspect-machine.ts is the reference machine: setupEffect with a declared fromEffect actor, reading to inspected or unreadable, join plus Effect.orDie lifting the outcome back into the Effect error channel. Its oxlint rule is ported to scripts/oxlint-plugin-xstate-effect.ts on @oxlint/plugins@1.83.0 and wired as xstate-effect/no-inline-effect: error. Two things learned on the way: the machine context must be declared via types<Ctx>() or schemas.context, otherwise createMachine’s function-form context falls back to MachineContext and the output type collapses to any; and ErrorFrom of a machine is unknown, so join needs orDie (or an explicit catch) to keep a typed error channel. Also fixed on the way: Flag.Boolean in effect/unstable/cli rc.115 is required unless Flag.withDefault(false) is applied; the template’s --json flag was silently mandatory.
  5. Two Effect mirrors, one stale. .agent_sources/github.com/Effect-TS/effect is at rc.115 (correct). .agent-sources/effect (the pi-effect tool’s mirror) is at beta.99. .agent_sources/README.md still says rc.110. Effect’s own AGENTS.md warns against unrelated copies.
  6. node_modules/effect/AGENTS.md is not referenced. It ships in the package (409 lines), is always version-matched, and is what other Effect 4 migrations point agents at first.
  7. Vendor script pins by hand. t3code derives the ref from the catalog. Ours can derive it from packages/core/package.json.

Current compatibility check (2026-10-09)

The peer roster records current default-branch evidence. The September study and contribution links above keep their original versions.

Sources


Last changed 2026-10-09 in 3bab7b3. Source on GitHub. Change log.