Repository navigation
Add effect skill layered on Effect's own skills - #172
Merged
Merged
Conversation
Effect v4 is at 4.0.0-rc.117 and npm `latest` is still 3.22.2. The v4 npm tarball ships AGENTS.md and ai-docs/, and the Effect team's effect-ts/skills repo is already in the pinned nix-skills index. Its `effect-ts` skill only points at that AGENTS.md. So this follows the ste100 layer-not-fork pattern: pin the upstream skills and write a thin local skill that holds only what upstream lacks. What the layer adds: - A gate on the installed major version. v3 code and v4 code do not compile against each other, and the v3 tarball ships no agent docs. Upstream effect-ts starts with `pnpm add effect@rc`, which in a v3 project (effect-playground is one) is an unrequested major upgrade. - The effect-playground Rust translation table, with a v4 column. - The v3/v4 traps found by typechecking effect-playground against rc.117: Schema.Date keeps its name with a different meaning (v3 string->Date is now DateFromString, and v4 Schema.Date rejects the string at runtime); Schedule.intersect -> Schedule.max takes an array and cannot be piped; Cause guards moved to cause.reasons; and the misleading TS2379 "add undefined" cascade under exactOptionalPropertyTypes. Each v4 entry was resolved against migration/v3-to-v4.md on Effect-TS/effect main. The entries marked "checked" were also typechecked and run against rc.117, including a v4 port of lesson 06's backoff (5 attempts transient, 1 permanent, same as v3). One name written from memory, Schema.TaggedErrorClass, turned out not to exist. That is why CLAUDE.md now says to verify version claims with a typecheck against the real package. Specific changes: - lib/skills-sh.nix: pin effect-ts and effect-v3-to-v4 (effect-ts/skills @ 2309e6f, which is also upstream HEAD) - home-manager/modules/tools/agent-skills.nix: deploy both, plus the repo skill `effect` - tools/agents/skills/effect/SKILL.md: the layer - CLAUDE.md: "look inside the package before writing a skill for a library" lesson Not verified here: this sandbox has no nix, so statix, deadnix and flake evaluation are left to CI. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
Topcoat (tokio-rs/topcoat, 0.8.1, MSRV 1.98) is a server-rendered Rust web framework. create-epoch-app (Rhys Sullivan) is a full-stack Effect starter: Effect + Convex + Next.js + effect-atom. Put side by side, they are the Rust and Effect versions of one app, so the new `topcoat` skill carries the pairing table and `effect` hands off to it. Topcoat follows the same pattern as `effect`, with its docs in a different place. The guides are embedded in the published crates, so after a build they sit in ~/.cargo/registry/src/*/topcoat-<ver>/docs/. The AGENTS.md index is only in the repo, and main had already changed 13 guide files in the nine days after v0.8.1. So the skill reads the crate at the Cargo.lock version and the index at the matching tag. The pairing's main row was checked on both sides, not taken from the docs. Asking for a missing dependency: - Effect: the service stays in R, and runPromise gives TS2345 (rc.117). - Topcoat: app_context::<Missing>(cx) compiles, then panics on each request that reaches it. The server catches the panic, returns 500 and keeps serving other routes (probe crate on crates.io 0.8.1, rustc 1.98.1). The two share a design rule (epoch-app's "yield* the dependency, don't pass it", Topcoat's "functions, not middlewares") but check it at different times. The skill states that as the tradeoff to name. create-epoch-app: I reviewed it and pinned nothing from it. It is a template with Cursor .mdc rules, on Effect ^3.19.8, and was last committed 2026-01-11. Its dependency rule went into `effect`. The skill records two rules not to import unchanged: - effect-primitives: prefers v3 names that v4 renames, and prefers Chunk/HashMap by default with no benchmark behind it. - never-use-as-any: bans `unknown`, which Schema decoding takes as input by design. Rhys Sullivan's effect-client-wrapper skill is pinned from rhyssullivan/skills. It is v3-shaped, so `effect` says to keep the pattern and translate the code on v4. Correction: the previous commit put a rule into `effect` that I had not verified: a Data.TaggedError payload field cannot be named `cause`. The rule came from a comment in effect-playground's lesson 06. It is false on 3.22.2 and rc.117. Renaming lesson 06's field to `readonly cause` typechecks under the playground's own tsconfig and passes its 6 tests. The skill now says so, and CLAUDE.md extends the lesson: a trusted source needs the same check as memory. Specific changes: - tools/agents/skills/topcoat/SKILL.md: new layer skill - tools/agents/skills/effect/SKILL.md: drop the false `cause` rule; add the yield* dependency rule; add hand-offs to effect-client-wrapper and topcoat; add a note on the reference projects - lib/skills-sh.nix: pin effect-client-wrapper (rhyssullivan/skills @ ab3a455, upstream HEAD) - home-manager/modules/tools/agent-skills.nix: deploy topcoat and effect-client-wrapper - CLAUDE.md: extend the "look inside the package" lesson Not verified here: nix is not installed in this sandbox, so statix, deadnix and flake evaluation are left to CI. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
Contributor
⊕ Entity-level changesCLAUDE.md
home-manager/modules/tools/agent-skills.nix
lib/skills-sh.nix
tools/agents/skills/effect/SKILL.md
tools/agents/skills/topcoat/SKILL.md
Summary: 19 added, 6 modified across 5 files (1 added orphan, 1 modified orphan) functions and classes, not lines · sem |
A question about whether the self-hosted Ghost server replaces Convex showed the pairing table left that open. It doesn't. Ghost provisions disposable Postgres databases; Convex is an application backend with server functions, auth and live queries. Ghost does match create-epoch-app's convex-test: a cheap TEMPLATE fork per test run. Added that as its own row, with the three reasons (one shared role, unverified TLS, disposable by design) that keep Ghost out of the persistent-store role. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
alycda
added this pull request to stack #174
September 22, 2026 19:55
Two conflicts: - lib/skills-sh.nix: main dropped this branch's mkSkill helper (which read nix-skills' per-letter data shards) and now goes through agents.nix's public overlay. Took main's file and re-added this branch's three skills in its style: github.effect-ts.skills.effect-ts, github.effect-ts.skills.effect-v3-to-v4 and github.rhyssullivan.skills.effect-client-wrapper. All three are in the locked index (agents.nix 0b4d80e) at the revs the branch was written against: effect-ts/skills 2309e6f and rhyssullivan/skills ab3a455. - CLAUDE.md: only the "Last updated" footer conflicted. Kept both sides, newest first. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
effect 4.0.0 went out on 2026-10-01; npm `latest` is now 4.0.5, and
the `rc` tag has stayed at 4.0.0-rc.118 since 2026-09-28. The locked
index still has effect-ts/skills at 2309e6f, written during the RC.
Both of its skills now give wrong instructions:
- effect-ts says `pnpm add effect@rc`, which installs rc.118, older
than every stable 4.0.x.
- effect-v3-to-v4 says to use `effect/unstable/*` imports where the
reference maps to them. GA removed those paths with no compatibility
exports.
Upstream 155c50c ("docs: align Effect skills with v4 GA", 2026-10-09)
fixes both. It is not in the index yet, so `nix flake update
nix-skills` cannot be relied on to pick it up. This pins it by hand,
the way main pins supabase-postgres-best-practices.
Asked for: effect-ts. Also done: effect-v3-to-v4. Same repo, one fetch,
and leaving the migration skill at 2309e6f would keep the removed
paths in it.
The hash was computed without nix, which this sandbox lacks: a NAR
serialization of `git archive 155c50c`, hashed with sha256. The same
method reproduced the index's hash for 2309e6f and main's supabase pin
exactly, so the method is checked against two known values; the result
itself still needs a real fetch (`nix flake prefetch
github:effect-ts/skills/155c50c`) or CI to confirm.
Neither skill has symlinks, and each SKILL.md `name` matches its deploy
directory, so plain subdirectories of the source work, with no builder.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
Effect 4.0.0 went out on 2026-10-01 (npm `latest` is 4.0.5, `prev` is 3.22.3, `rc` has stayed at rc.118). The skill was written while v4 was a release candidate, and three of its statements turned around. - The new-project row said npm `latest` is v3 and v4 is a release candidate. Now v4 is the default and v3 needs a stated reason. A resolved -rc/-beta version gets its own row: it is a pre-GA build with the old import paths. - The version gate named `effect@rc` as the accidental major upgrade. Now it is `effect@latest`. Before writing that, I tested which commands cross the major in a project pinned to ^3.22.2 (npm 10 and pnpm 10): a bare `npm install effect` or `pnpm add effect` keeps the ^3 range; only `effect@latest` rewrites it to ^4. The skill says exactly that rather than "never install effect". - A new trap: GA moved `effect/unstable/*` modules to plain paths (`effect/unstable/http` -> `effect/http`) with no compatibility exports. On 4.0.5 the old path fails with TS2307. The note that stability is now a JSDoc tag was checked against the 4.0.5 source: 6894 `@stability stable`, 5595 `unstable`, 271 `experimental`. Re-checked against 4.0.5 (item 5), using the same probes as rc.117: - Every v4 name in the Rust table and the trap list typechecks. That covers more than the four entries marked "checked" before. - Schema.Date still rejects an ISO string at runtime, and DateFromString decodes it. - The lesson-06 backoff port still makes 5 attempts (transient) and 1 (permanent). - A `readonly cause` payload field still compiles. - `ParseResult` and `Schema.Schema.Encoded` are still gone. - effect-playground still gives the same 71 typecheck errors as on rc.117. - topcoat's missing-service row now names both codes it produces, on 4.0.5 as on rc.117: TS2345, or TS2379 under exactOptionalPropertyTypes. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
The lesson on library skills still quoted effect-ts's first step as `pnpm add effect@rc`. That was true at 2309e6f; the pin is now 155c50c, which says `pnpm add effect@latest`, and skills-sh.nix and the effect skill were updated in 19200b5 while this file was not. CLAUDE.md is always loaded, so the stale line told every agent the external skill installs the RC, when in a v3 project it installs v4 - the exact upgrade the version gate exists to stop. Also: "stale at each release candidate" -> "at each release", since v4 is GA. Found by /code-review (finding 1). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
Step 0's ls had a second glob, topcoat-*<ver>/macro/docs, which is the repository layout (crates/<crate>/macro/docs). In the cargo registry each macro crate is its own package, topcoat-<crate>-macro-<ver>/docs, which the first glob already matches. So the second glob never matched, 2>/dev/null hid that, and the skill described two layouts for one set of files. Checked against the registry after building topcoat 0.8.1: the one glob finds 8 docs directories, including topcoat-router-<ver>/docs, which the prose had not mentioned at all; it does now. Found by /code-review (finding 8). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
The skill told agents to search the migration reference using the recipes in effect-v3-to-v4. Those recipes grep .repos/effect/migration/v3-to-v4.md, a clone that only the migration skill's setup step creates. In an ordinary v4 project an agent following the pointer gets "No such file" from rg, and the cheapest next move is the guess the paragraph forbids. Now the paragraph says to search node_modules/effect/src first. Then it gives the reference's own fetch: a sparse, blobless clone of just migration/ into the same .repos/effect path, so upstream's recipes also work afterwards. The package does not ship the reference (checked in 4.0.5). The commands were run as written: 6.5 MB on disk, and the rg recipe returns `Effect.catchAll` -> `Effect.catch`. Found by /code-review (finding 9). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Effect v4 is at 4.0.0-rc.117 and npm
latestis still 3.22.2. The v4npm tarball ships AGENTS.md and ai-docs/, and the Effect team's
effect-ts/skills repo is already in the pinned nix-skills index.
Its
effect-tsskill only points at that AGENTS.md. So this followsthe ste100 layer-not-fork pattern: pin the upstream skills and write a
thin local skill that holds only what upstream lacks.
What the layer adds:
compile against each other, and the v3 tarball ships no agent docs.
Upstream effect-ts starts with
pnpm add effect@rc, which in a v3project (effect-playground is one) is an unrequested major upgrade.
rc.117: Schema.Date keeps its name with a different meaning
(v3 string->Date is now DateFromString, and v4 Schema.Date rejects
the string at runtime); Schedule.intersect -> Schedule.max takes an
array and cannot be piped; Cause guards moved to cause.reasons; and
the misleading TS2379 "add undefined" cascade under
exactOptionalPropertyTypes.
Each v4 entry was resolved against migration/v3-to-v4.md on
Effect-TS/effect main. The entries marked "checked" were also
typechecked and run against rc.117, including a v4 port of lesson
06's backoff (5 attempts transient, 1 permanent, same as v3). One name
written from memory, Schema.TaggedErrorClass, turned out not to exist.
That is why CLAUDE.md now says to verify version claims with a
typecheck against the real package.
Specific changes:
(effect-ts/skills @ 2309e6f, which is also upstream HEAD)
repo skill
effectlibrary" lesson
Not verified here: this sandbox has no nix, so statix, deadnix and
flake evaluation are left to CI.
Co-Authored-By: Claude Opus 5.5 [email protected]
Claude-Session: https://claude.ai/code/session_01Tw8tuRUyKtkcjmN4upeawF