@danieljvdm/dev-kit 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +155 -99
  2. package/dev-kit.example.jsonc +4 -3
  3. package/package.json +1 -1
  4. package/schema/dev-kit.schema.json +19 -42
  5. package/skills/build-effect-apis/SKILL.md +13 -31
  6. package/skills/build-effect-apis/references/verification.md +3 -3
  7. package/skills/dev-kit/SKILL.md +115 -222
  8. package/skills/effect-atom-state/SKILL.md +97 -0
  9. package/skills/effect-atom-state/agents/openai.yaml +4 -0
  10. package/skills/effect-atom-state/references/effect-atom-workflows.md +180 -0
  11. package/skills/open-pull-request/SKILL.md +62 -23
  12. package/src/bin/dev-kit.ts +21 -0
  13. package/src/catalog.ts +39 -15
  14. package/src/effect-source.ts +70 -4
  15. package/src/global-cache.ts +304 -0
  16. package/src/index.ts +6 -6
  17. package/src/manifest.ts +28 -29
  18. package/src/oxlint.js +23 -0
  19. package/src/oxlint.ts +37 -1
  20. package/src/path-digest.ts +0 -13
  21. package/src/project-package.ts +127 -12
  22. package/src/project-state.ts +3 -0
  23. package/src/scaffold.ts +79 -0
  24. package/src/sync.ts +100 -173
  25. package/src/vite-plus-workflow.ts +82 -0
  26. package/src/vite-plus.js +8 -1
  27. package/src/vite-plus.ts +15 -1
  28. package/src/worktrunk-config.ts +88 -0
  29. package/templates/vite-plus/github-actions-check.yml +0 -2
  30. package/templates/worktrunk/wt.toml +27 -0
  31. package/src/vite-plus-quality.ts +0 -148
  32. /package/skills/{build-effect-apis → effect-atom-state}/references/effect-atom-client.md +0 -0
  33. /package/skills/{build-effect-apis → effect-atom-state}/references/effect-atom-lifecycle.md +0 -0
  34. /package/skills/{build-effect-apis → effect-atom-state}/references/effect-atom-testing.md +0 -0
  35. /package/skills/{build-effect-apis → effect-atom-state}/references/tanstack-start.md +0 -0
@@ -1,24 +1,21 @@
1
1
  ---
2
2
  name: dev-kit
3
- description: Dev-kit operations for projects that configure dev-kit.jsonc, sync portable skills, run plan/apply or automatic postinstalls, perform locked CI checks, maintain dev-kit.lock.json, resolve ownership conflicts, patch managed ignores, or enable Effect TypeScript-Go.
3
+ description: Dev-kit operations for projects that configure dev-kit.jsonc, sync portable skills, run plan/apply or automatic postinstalls, perform locked CI checks, maintain dev-kit.lock.json, resolve ownership conflicts, or enable Effect TypeScript-Go.
4
4
  ---
5
5
 
6
6
  # Dev Kit
7
7
 
8
8
  Treat `dev-kit.jsonc` as desired state, `dev-kit.lock.json` as the committed
9
- resolution, and `.dev-kit/state.json` as local ownership receipts.
9
+ resolution, and `.dev-kit/state.json` as local ownership receipts. Deep
10
+ reference — catalog maintenance, package-skill discovery rules, preset
11
+ internals — lives in the package README
12
+ (`node_modules/@danieljvdm/dev-kit/README.md`).
10
13
 
11
14
  Use the high-level commands for routine changes: `dev-kit init`, `dev-kit add
12
15
  <skill...>`, `dev-kit remove <skill...>`, `dev-kit list --all`, `dev-kit search
13
16
  <words...>`, and `dev-kit info <skill>`. Add and remove apply immediately unless
14
17
  passed `--no-apply`; `dev-kit sync` applies an already-edited manifest.
15
18
 
16
- For distro maintenance, use `dev-kit catalog add <repository>` to inspect and
17
- approve upstream skills, `catalog list`/`catalog info` to review provenance,
18
- `catalog remove <source-or-skill>` to revoke approval, and `catalog verify` in
19
- CI. Pass repeated `--skill` flags or `--all` outside a terminal. Approval always
20
- stores explicit skill names and exact commit/content digests.
21
-
22
19
  ## Apply loop
23
20
 
24
21
  1. Establish the Git root. Read project agent instructions, the current
@@ -33,14 +30,12 @@ stores explicit skill names and exact commit/content digests.
33
30
  requested creative or advisory skills even when they have no mechanical
34
31
  dependency signal.
35
32
  3. Choose the narrowest useful set. Prefer focused external skills over a
36
- generic umbrella when they cover the repository's work. Select an umbrella
37
- or external source family only when its full breadth is intentionally useful;
38
- never select one merely because one member or product matches. Explain any
39
- uncertain inclusion before applying it. Distinguish separately triggered
40
- skills from lazy `references/` bundled inside one skill: unused reference
41
- folders cost repository space but are not loaded into agent context unless
42
- the skill routes to them. A multi-product repository can therefore justify
43
- an umbrella while still excluding unrelated top-level skills.
33
+ generic umbrella; select an umbrella or source family only when its full
34
+ breadth is intentionally useful, never because one member matches. Explain
35
+ any uncertain inclusion before applying it. Unused `references/` folders
36
+ inside a selected skill cost repository space, not agent context, so a
37
+ multi-product repository can justify an umbrella while still excluding
38
+ unrelated top-level skills.
44
39
  4. Update `dev-kit.jsonc`. Preserve JSONC comments and validate against the
45
40
  package schema. Finish with each desired resource represented once and every
46
41
  external selection supported by repository evidence or an explicit request.
@@ -51,126 +46,108 @@ stores explicit skill names and exact commit/content digests.
51
46
  6. Resolve conflicts, then run `dev-kit apply`. Commit the manifest and
52
47
  regenerated `dev-kit.lock.json`; keep `.dev-kit/` local. Finish when a second
53
48
  plan reports only unchanged resources and setup tasks.
54
- 7. Use `dev-kit apply` in the package lifecycle so intentional dependency
55
- upgrades regenerate owned outputs and `dev-kit.lock.json`. For strict CI,
56
- either disable lifecycle scripts before `dev-kit apply --locked`, or run the
57
- normal lifecycle and require the tracked working tree to remain clean. Never
58
- run an unlocked apply before locked verification. Finish when a clean install
59
- converges from the committed manifest and lock.
60
49
 
61
50
  ## Manifest
62
51
 
63
52
  Use skill names or family names in `include`; subtract selections with
64
- `exclude`. Built-in families such as `effect` are intentional bundles. An
65
- external source ID is also a family, but expands to every approved skill from
66
- that source, so prefer individually relevant external skills. Include this
67
- skill as `dev-kit` when project agents should carry the toolkit procedure.
68
-
69
- Select skills bundled inside installed packages with the exact
70
- `<package>#<skill>` selector. The selector stays package-qualified in the
71
- manifest, lock, and CLI listings, and the installed output keeps that identity:
72
- the copied directory is named by flattening the package name (drop `@`, turn
73
- every other non-alphanumeric run into one dash) and appending the skill name,
74
- so `@tanstack/table-core#core` installs as `tanstack-table-core-core`. The
75
- copied `SKILL.md` frontmatter `name:` is rewritten to the same install name;
76
- everything else is verbatim. Symlink-mode targets still point at
77
- `node_modules`, so their frontmatter keeps the upstream bare name. Two selected
78
- skills that flatten to the same install name are rejected before any output
79
- changes.
53
+ `exclude`. Built-in families such as `effect` are intentional bundles. Include
54
+ this skill as `dev-kit` when project agents should carry the toolkit
55
+ procedure. Skills bundled inside installed packages need the exact
56
+ `<package>#<skill>` selector; the copied output flattens that identity into
57
+ one directory name (`@tanstack/table-core#core` → `tanstack-table-core-core`)
58
+ and rewrites the copied frontmatter `name:` to match.
80
59
 
81
60
  ```jsonc
82
61
  {
83
62
  "$schema": "./node_modules/@danieljvdm/dev-kit/schema/dev-kit.schema.json",
84
63
  "include": ["dev-kit", "effect"],
85
- "exclude": [],
86
64
  "setup": {
87
65
  "agentInstructions": { "enabled": true },
88
66
  "claudeInstructions": { "enabled": true },
89
67
  "vitePlus": {
90
68
  "hooks": { "enabled": true },
91
- "quality": {
92
- "workflow": { "enabled": true },
93
- },
69
+ "workflow": { "enabled": true },
70
+ },
71
+ "worktrunk": {
72
+ "config": { "enabled": true },
94
73
  },
95
74
  },
96
75
  "targets": {
97
76
  "agents": { "enabled": true, "mode": "copy" },
98
77
  "claude": { "enabled": true, "mode": "symlink" },
99
- "opencode": { "enabled": false, "mode": "symlink" },
100
78
  },
101
79
  }
102
80
  ```
103
81
 
104
82
  Prefer a copied `.agents/skills` target as the project-local source of truth;
105
83
  use symlinks for additional harness discovery paths. Keep every target path
106
- project-relative and separate from the manifest, lock, state, and process-lock
107
- paths.
108
-
109
- Enable `setup.agentInstructions` to manage marked sections in a project-root
110
- `AGENTS.md` while preserving handwritten project guidance. The Dev Kit section
111
- points agents back to this skill. When `vite-plus` is a declared direct
112
- dependency, dev-kit synthesizes repository-specific Vite+ guidance inside its
113
- own section instead of importing Vite+'s generic `AGENTS.md`. Preserve the
114
- useful unified-toolchain overview, help and documentation entry points, and
115
- `vp env doctor` troubleshooting without duplicating generic commands that can
116
- contradict the repository policy. Treat duplicate, overlapping, reversed, or
117
- unmatched managed markers as a conflict rather than guessing which content Dev
118
- Kit owns; remove a legacy owned Vite+ section during migration.
119
- When `effect` is a declared direct dependency and the installed package ships a
120
- regular `node_modules/effect/AGENTS.md` file, the managed section also directs
121
- agents to read that version-matched guide completely and use
122
- `node_modules/effect/src` for gaps. Omit the pointer when the package is absent,
123
- transitive, or too old to ship the guide; never generate a dangling path.
124
- The managed section also publishes the repository's command authority. Direct
125
- Vite+ projects must use `vp` built-ins and `vp run <task>`; projects using the
126
- recommended Vite+ factory use `vp run check` for the complete
127
- format/lint/test/typecheck suite and `vp run typecheck` for the Effect-patched
128
- compiler. Non-Vite+ projects run
129
- existing root quality scripts through `bun run`; package-manager metadata and
130
- lockfiles affect dependency-install guidance only. Never substitute another
84
+ project-relative and separate from the manifest, lock, and state paths.
85
+
86
+ ## Managed instructions
87
+
88
+ `setup.agentInstructions` manages marked sections in the project-root
89
+ `AGENTS.md` and preserves handwritten content around them; edit only outside
90
+ the markers. The section points agents at this skill, renders the repository's
91
+ command policy from live evidence (a direct `vite-plus` dependency makes `vp`
92
+ the only front door; otherwise Bun runs declared root scripts), and adds the
93
+ Effect guide pointer when the installed `effect` package ships one. Treat
94
+ duplicate, overlapping, reversed, or unmatched managed markers as a conflict
95
+ rather than guessing which content Dev Kit owns. Never substitute another
131
96
  script runner or call raw `tsc`, test, lint, or format binaries when a project
132
97
  command exists.
133
- Enable `setup.claudeInstructions` when Claude Code should consume the same
134
- project-root instructions; it manages `CLAUDE.md` as a relative symlink to the
135
- section-managed file or to an existing regular `AGENTS.md`. Preserve
136
- conflicting paths; when disabled, dev-kit removes only unchanged marked
137
- sections recorded in local ownership state and leaves handwritten content in
138
- place.
139
-
140
- Enable `setup.vitePlus.hooks` when an installed direct `vite-plus` dependency
141
- should manage Git hooks. Each apply checks the local `.vite-hooks/_` dispatcher,
142
- its internal `.gitignore`, the portable `.vite-hooks/pre-commit` hook, and
143
- `core.hooksPath`, then runs the project-local `vp config --no-agent` when they
144
- need convergence. This recreates ignored dispatchers in linked worktrees.
145
- Preserve other hook managers; Dev Kit
146
- refuses to replace an unrelated `core.hooksPath`. Use `VITE_GIT_HOOKS=0` or
147
- `HUSKY=0` to skip hook setup for an invocation.
98
+
99
+ `setup.claudeInstructions` manages `CLAUDE.md` as a relative symlink to
100
+ `AGENTS.md`. Disabling either task removes only unchanged managed content and
101
+ leaves handwritten content in place.
102
+
103
+ ## Vite+ setup
148
104
 
149
105
  The repository always owns `vite.config.ts`. Compose
150
- `createRecommendedVitePlusConfig` from `@danieljvdm/dev-kit/vite-plus` there;
151
- Dev Kit never adopts, rewrites, or removes the config. The factory provides
152
- matching Oxlint/Oxfmt ignores, staged checks, and separate `check` and pure
153
- `typecheck` Vite tasks. Add repository/framework-generated paths through its
154
- `ignorePatterns` option, including any harness target paths that override the
155
- manifest defaults. Workspace mode accepts explicit package directories with
156
- pure `typecheck` scripts and generates cached, dependency-ordered,
157
- bounded-concurrency filters. Spread the returned top-level config before local
158
- options; spread a returned nested block before overriding that block, and merge
159
- nested collections such as `lint.rules` so the recommended rules remain active.
160
-
161
- Enable `setup.vitePlus.quality.workflow` to own only
162
- `.github/workflows/check.yml`. It requires direct Dev Kit, compatible Vite+,
163
- Effect, Effect TypeScript-Go, and native TypeScript dependencies with
164
- `setup.effectTsgo.enabled`. Preserve unowned workflows and adopt only an exact
165
- rendered match. Consumers may configure `workflow.beforeChecks` and
166
- `workflow.typecheck`; treat these commands as trusted manifest input.
167
-
168
- The workflow must use one frozen, script-suppressed install, then locked Dev Kit
169
- convergence before preparation or checks. Set up Bun from the consumer's
170
- `packageManager` or `engines.bun` declaration before Vite+ setup. Follow the
171
- maintained `setup-bun` major tag, name an explicit `setup-vp` release because
172
- its `v1` tag is frozen, and let Vite+ resolve the consumer's compatible locked
173
- version.
106
+ `createRecommendedVitePlusConfig` from `@danieljvdm/dev-kit/vite-plus` there,
107
+ adding repository/framework-generated paths (and any overridden harness target
108
+ paths) through `ignorePatterns`. Spread the returned top-level config before
109
+ local options, spread a returned nested block before overriding it, and merge
110
+ nested collections such as `lint.rules` so the recommended rules stay active.
111
+ The factory provides matching Oxlint/Oxfmt ignores, staged checks, and
112
+ separate `check` and pure `typecheck` tasks; standalone Oxc projects import
113
+ `recommendedOxlintConfig`/`recommendedOxfmtConfig` directly.
114
+
115
+ Run the Effect-patched compiler separately with `vp run typecheck`; neither
116
+ Oxlint's bundled `tsgolint` nor Vite+'s native lint path uses the Effect patch,
117
+ and Vite+ 0.2.6 does not execute the preset's JavaScript-plugin rules — use
118
+ standalone Oxlint when `effect/*` or
119
+ `stylistic/padding-line-between-statements` must be enforced. The `effect`
120
+ plugin's scope-sensitive rules stay consumer-scoped: enable them per path in
121
+ Effect-owned code, with exceptions for tests and host boundaries.
122
+
123
+ `setup.vitePlus.hooks` converges the Git-ignored `.vite-hooks/_` dispatcher by
124
+ running the project-local `vp config --no-agent`, recreating it in linked
125
+ worktrees. It requires a direct `vite-plus` dependency, refuses to replace an
126
+ unrelated `core.hooksPath`, and is skipped per invocation with
127
+ `VITE_GIT_HOOKS=0` or `HUSKY=0`.
128
+
129
+ ## Scaffolds
130
+
131
+ `setup.vitePlus.workflow` and `setup.worktrunk.config` are create-only
132
+ scaffolds: apply writes the file only when it is missing, records nothing in
133
+ the lock, and never reads, updates, or removes an existing file — the
134
+ repository owns it from creation and edits it directly. When the shipped
135
+ template improves, diff the repository's file against the installed template
136
+ under `node_modules/@danieljvdm/dev-kit/templates/` and merge what fits.
137
+
138
+ - `setup.vitePlus.workflow` scaffolds `.github/workflows/check.yml`. It
139
+ requires direct Dev Kit, compatible Vite+, Effect, Effect TypeScript-Go, and
140
+ native TypeScript dependencies with `setup.effectTsgo.enabled`. Add
141
+ preparation steps or a custom typecheck command by editing the YAML.
142
+ - `setup.worktrunk.config` scaffolds `.config/wt.toml`: a
143
+ copy-ignored-then-install pre-start pipeline, a full-validation pre-merge
144
+ hook, and a commented per-worktree dev-server block to enable deliberately.
145
+ Hook commands render for the repository's runner — `vp` with a direct
146
+ `vite-plus` dependency, otherwise the detected package manager's install
147
+ command with `bun run check` from a declared root `check` script. Keep
148
+ user-level Worktrunk settings such as worktree-path templates out of the
149
+ project config; each user approves the hooks once with
150
+ `wt config approvals add`.
174
151
 
175
152
  ## Ownership and conflicts
176
153
 
@@ -190,17 +167,10 @@ Preserve a conflicting path and inspect it:
190
167
  Retain `.dev-kit/state.json` across routine applies and branch changes so its
191
168
  receipts can update or remove previously applied outputs safely.
192
169
 
193
- ## Project plumbing
194
-
195
- Run `dev-kit gitignore` to add `.repos/` and `.dev-kit/` additively. Preview with
196
- `dev-kit gitignore --dry-run`. Treat `.repos/<source-id>` as the reserved source
197
- checkout root.
170
+ ## Lifecycle
198
171
 
199
- Require Bun 1.3 or newer wherever Dev Kit runs. The published `dev-kit`
200
- executable uses Bun directly and rejects Node execution; keep Bun available to
201
- package lifecycle scripts and locked CI verification.
202
-
203
- For one lifecycle entry point, configure:
172
+ Run `dev-kit gitignore` to add `.repos/` and `.dev-kit/` additively
173
+ (`--dry-run` to preview). For one lifecycle entry point, configure:
204
174
 
205
175
  ```jsonc
206
176
  {
@@ -210,117 +180,40 @@ For one lifecycle entry point, configure:
210
180
  }
211
181
  ```
212
182
 
213
- This intentionally refreshes the committed lock and owned outputs when the
214
- package manager installs a new Dev Kit or selected package-skill version.
215
- Review and commit those changes with the dependency update. Keep
216
- `dev-kit apply --locked` as a verification command, not the normal local
217
- lifecycle; in CI, run it only before any unlocked apply. Invoke locked consumer
218
- verification as
183
+ This intentionally refreshes the committed lock and owned outputs when an
184
+ installed Dev Kit or selected package-skill version changes; review and commit
185
+ those changes with the dependency update. Keep `dev-kit apply --locked` as a
186
+ verification command, never the local lifecycle, and never run an unlocked
187
+ apply before locked verification. Invoke locked consumer verification as
219
188
  `bun ./node_modules/@danieljvdm/dev-kit/bin/dev-kit.mjs apply --locked` so a
220
189
  package script named `dev-kit` cannot shadow the executable.
221
190
 
222
- ## Effect source checkout
223
-
224
- Enable the source task when agents should have canonical source matching the
225
- installed Effect package:
226
-
227
- ```jsonc
228
- {
229
- "setup": {
230
- "effectSource": { "enabled": true },
231
- },
232
- }
233
- ```
234
-
235
- The task reads the exact installed `effect` version and converges the ignored
236
- `.repos/effect` checkout on the corresponding `effect@<version>` tag. It skips
237
- CI, preserves a dirty or unrelated destination, and never deletes the checkout
238
- when disabled. Use `dev-kit effect sync --dry-run` for focused diagnosis.
239
-
240
- Override `packageName`, `path`, or `repository` only for a compatible Effect
241
- distribution or a deliberate mirror.
242
-
243
- ## Effect TypeScript-Go
244
-
245
- Enable the setup task in the same manifest:
246
-
247
- ```jsonc
248
- {
249
- "setup": {
250
- "effectTsgo": { "enabled": true },
251
- },
252
- }
253
- ```
254
-
255
- Install the exact `@effect/tsgo` and native `typescript` versions required by
256
- the installed dev-kit. Point `tsconfig.json` at
257
- `./node_modules/@effect/tsgo/schema.json` and configure the
258
- `@effect/language-service` compiler plugin with Dev Kit's exported
259
- `recommendedEffectTsgoPlugin` profile: warnings for
260
- `anyUnknownInErrorContext` and `unsafeEffectTypeAssertion`; suggestions for
261
- `instanceOfSchema`, `nestedEffectGenYield`, `newSchemaClass`, and
262
- `preferSchemaTypeProperty`; plus a `src/**/*.ts` override that warns on
263
- `nodeBuiltinImport` and suggests `preferSchemaOverJson`. Copy the exact JSON
264
- profile from the README into JSON tsconfigs. In monorepos, child
191
+ ## Effect setup tasks
192
+
193
+ `setup.effectSource` converges the ignored `.repos/effect` checkout on the
194
+ `effect@<version>` tag matching the installed package. It skips CI, preserves
195
+ a dirty or unrelated destination, and never deletes the checkout when
196
+ disabled. Diagnose with `dev-kit effect sync --dry-run`; override
197
+ `packageName`, `path`, or `repository` only for a compatible Effect
198
+ distribution.
199
+
200
+ `setup.effectTsgo` validates and patches the project-local native TypeScript
201
+ compiler. Install the exact `@effect/tsgo` and `typescript` versions required
202
+ by the installed dev-kit, point `tsconfig.json` at
203
+ `./node_modules/@effect/tsgo/schema.json`, and configure the
204
+ `@effect/language-service` plugin with the `recommendedEffectTsgoPlugin`
205
+ profile copy the exact JSON from the package README. In monorepos, child
265
206
  `compilerOptions.plugins` arrays replace rather than merge the root array, so
266
- workspace configs must inherit the root plugin without redeclaring it and the
267
- source override must be relative to the config that contains it. `dev-kit plan`
268
- validates the local dependencies; `dev-kit apply` patches once and then
269
- converges.
270
-
271
- Use `dev-kit tsgo patch --dry-run` for focused diagnosis. Use `--force` only
272
- after the user accepts a potentially commit-incompatible TypeScript binary.
273
-
274
- ## Oxlint and Oxfmt configurations
275
-
276
- Use Dev Kit's composable factory in Vite+ projects:
277
-
278
- ```ts
279
- import { createRecommendedVitePlusConfig } from "@danieljvdm/dev-kit/vite-plus";
280
- import { defineConfig } from "vite-plus";
281
-
282
- export default defineConfig(
283
- createRecommendedVitePlusConfig({
284
- ignorePatterns: ["src/routeTree.gen.ts"],
285
- }),
286
- );
287
- ```
288
-
289
- The factory composes the canonical Oxlint/Oxfmt objects, excludes tracked skill
290
- copies plus symlinked harness targets from both tools, and accepts additional
291
- project-owned ignores. Standalone `oxlint.config.ts` uses
292
- `extends: [recommendedOxlintConfig]`; standalone `oxfmt.config.ts` spreads
293
- `recommendedOxfmtConfig`. The shared lint preset enables `typeAware` for
294
- semantic lint rules but leaves `typeCheck` disabled. Effect TypeScript-Go
295
- projects must run the patched native compiler separately with
296
- `vp run typecheck` after `vp fmt --check`, `vp lint`, and `vp test`; Oxlint's
297
- bundled `tsgolint` does not use the Effect patch.
298
-
299
- The Oxlint preset enables the fixable
300
- `stylistic/padding-line-between-statements` rule. It keeps adjacent variable
301
- declarations grouped, requires a blank line before the next logical statement,
302
- and separates every `return` statement from the preceding statement.
303
-
304
- Vite+ 0.2.6 forwards the preset's JavaScript-plugin declarations but its native
305
- Oxlint path does not register or execute their rules. Treat native rules and
306
- Oxfmt as active through `vp`, and use standalone Oxlint when the `effect/*` or
307
- `stylistic/padding-line-between-statements` rules must be enforced. Re-enable a
308
- Vite+ execution assertion when a supported release adds JS-plugin execution.
309
-
310
- The Oxlint preset registers Dev Kit's shared Effect plugin as `effect`, but
311
- does not enable its scope-sensitive rules globally. Effect projects should
312
- enable rules such as `effect/no-effect-run`, `effect/no-unsafe-promise`, and
313
- `effect/no-untyped-throw` only in Effect-owned code, with explicit exceptions
314
- for tests and host boundaries. The stricter `effect/no-async-workflow`,
315
- `effect/no-promise-atom-mode`, and `effect/no-sync-boundary-decode` rules also
316
- need consumer-owned scopes. Keep repository-specific paths and platform rules
317
- in the consuming project.
207
+ workspace configs must inherit the root plugin without redeclaring it, and the
208
+ `src/**/*.ts` override must be relative to the config that contains it.
209
+ Diagnose with `dev-kit tsgo patch --dry-run`; use `--force` only after the
210
+ user accepts a potentially commit-incompatible TypeScript binary.
318
211
 
319
212
  ## Current boundary
320
213
 
321
214
  Manage skill outputs, the `setup.agentInstructions` marked sections, the
322
215
  `setup.claudeInstructions` link, the `setup.vitePlus.hooks` dispatcher, the
323
- opt-in `setup.vitePlus.quality.workflow`, the `setup.effectSource` checkout,
324
- and the explicit `setup.effectTsgo` task. `vite.config.ts`, dependency, and
325
- `tsconfig.json` contributions remain deliberate user-owned edits. Compose the
326
- Vite+ factory or lower-level Oxlint/Oxfmt exports locally.
216
+ `setup.effectSource` checkout, and the explicit `setup.effectTsgo` task. The
217
+ `setup.vitePlus.workflow` and `setup.worktrunk.config` scaffolds belong to the
218
+ repository once created. `vite.config.ts`, dependency, and `tsconfig.json`
219
+ contributions remain deliberate user-owned edits.
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: effect-atom-state
3
+ description: Manage client-side state and server data in React with Effect Atom, which fills the role TanStack/React Query, SWR, Zustand, Redux, or Jotai play in other stacks — use this skill instead of reaching for those libraries or hand-rolled useEffect fetching whenever a component needs shared state, data fetching, caching, mutations, or optimistic updates. Also use when reading or dispatching atoms (useAtomValue, useAtomSet, useAtom), refactoring promise chains or useState-held server state into atom workflows, choosing reactivity keys and invalidation, deriving AtomHttpApi or HttpApiClient clients from a shared contract, deciding where the Effect→Promise boundary sits, or wiring RegistryProvider and SSR with TanStack Start.
4
+ ---
5
+
6
+ # Effect Atom State
7
+
8
+ Effect Atom is the client-state and server-data layer in an Effect repository:
9
+ the role other stacks give TanStack Query, SWR, Zustand, Redux, or Jotai.
10
+ Every need that would reach for one of those libraries — or for hand-rolled
11
+ `useEffect` fetching — is atom work; never introduce a second state or query
12
+ library beside it.
13
+
14
+ Business logic stays in Effect for as long as possible. Components read
15
+ `AsyncResult` values and dispatch actions; workflows, optimistic updates, and
16
+ cache invalidation live in atoms, not in promise chains at the React boundary.
17
+
18
+ Effect Atom APIs are version-sensitive. Read the target repository's manifests
19
+ and lockfile, inspect its existing imports, and confirm exact signatures from
20
+ the installed `effect` and `@effect/atom-react` declarations before editing.
21
+ In current Effect v4 betas the atom modules live in
22
+ `effect/unstable/reactivity` and the React hooks in `@effect/atom-react`.
23
+
24
+ ## Build the client state graph
25
+
26
+ 1. Inventory the existing `RegistryProvider`, runtime factories,
27
+ `AtomHttpApi.Service` clients, query atoms and families, mutation and
28
+ workflow atoms, reactivity-key constructors, state atoms, and promise-mode
29
+ dispatch sites. Finish when every consumer of the affected state is
30
+ identified.
31
+ 2. Read [effect-atom-client.md](references/effect-atom-client.md), then derive
32
+ one `AtomHttpApi.Service` per contract, stable query atoms or families,
33
+ mutation atoms, and one reactivity-key vocabulary. For non-React Effect
34
+ code, use the direct `HttpApiClient` branch. Finish when consumers call the
35
+ shared contract rather than redefining wire types or using ad hoc `fetch`
36
+ for declared endpoints.
37
+ 3. Read [effect-atom-workflows.md](references/effect-atom-workflows.md), then
38
+ express every multi-step action — mutate then invalidate, optimistic echo
39
+ then rollback — as an `Atom.fn` effect composing other atoms through the fn
40
+ context. Finish when no component or route chains `.then`/`.catch` on a
41
+ dispatch and no `useState` holds state a workflow atom must own.
42
+ 4. Read [effect-atom-lifecycle.md](references/effect-atom-lifecycle.md) when
43
+ changing registry scope, atom identity, retention, freshness, polling,
44
+ cancellation, or aggregate stability.
45
+ 5. Read [effect-atom-testing.md](references/effect-atom-testing.md), then give
46
+ changed atom behavior deterministic coverage below React first, with a
47
+ deterministic HTTP layer so request encoding, invalidation, and lifecycle
48
+ remain observable. Run the repository's format, lint, typecheck, and test
49
+ commands. Finish when changed queries, mutations, invalidation, and
50
+ workflow atoms have deterministic tests and every repository check passes.
51
+
52
+ ## Optional branches
53
+
54
+ - Read [tanstack-start.md](references/tanstack-start.md) when the client is
55
+ TanStack Start, SSR, hydration, `ClientOnly`, loaders, server functions, or a
56
+ proxied separate API.
57
+ - Use the `$build-effect-apis` skill when the change reaches the contract or
58
+ server: shared `HttpApiEndpoint`/`HttpApiGroup` definitions, handlers,
59
+ middleware, or runtime assembly.
60
+
61
+ ## Keep the Promise boundary logic-free
62
+
63
+ The Effect→Promise boundary sits at the outermost edge and carries no logic.
64
+
65
+ - Return a promise-mode dispatch (`useAtomSet(action, { mode: "promise" })`)
66
+ bare to a leaf component whose contract is promise-shaped — a pending
67
+ button, a composer that owns its in-flight state. A `.then` or `.catch`
68
+ chain in a component or route is a violation: move that logic into the
69
+ action's Effect.
70
+ - Express multi-step workflows as `Atom.fn` effects composing other atoms
71
+ through the fn context: `get.setResult` awaits another fn atom, `get.set`
72
+ writes state atoms. Reads through the fn context callable are untracked, so
73
+ mutating a state atom from inside the effect cannot re-trigger the workflow.
74
+ - Declare cross-query invalidation as reactivity keys on the mutation; never
75
+ chain a manual refresh at a call site. When several `AtomHttpApi` services
76
+ share one Atom runtime, one `Reactivity` instance spans them, so a mutation
77
+ on one client invalidates another client's query keys.
78
+ - Keep optimistic UI state in `Atom.family` state atoms keyed by the entity,
79
+ not `useState`, so the workflow atom that writes it owns its lifecycle.
80
+ - Genuine view state — controlled inputs, open/closed toggles, reconciling
81
+ optimistic rows against rendered props — stays in React; do not force it
82
+ into Effect.
83
+
84
+ A repository may reinforce the boundary with a lint warning on `then` scoped
85
+ to component and route modules, with a documented local suppression for a
86
+ genuinely promise-shaped contract, but the boundary reasoning remains the
87
+ source of truth.
88
+
89
+ ## Boundary rules
90
+
91
+ - Let client data modules own API services, query identity, cache policy,
92
+ invalidation keys, mutation atoms, and workflow atoms.
93
+ - Let workflow atoms own orchestration, optimistic echo, rollback, and
94
+ cross-query invalidation.
95
+ - Let UI action owners own navigation, toasts, form reset, and presentation
96
+ derived from `AsyncResult` state.
97
+ - Let React own view state that no atom needs to write.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Effect Atom State"
3
+ short_description: "Manage Effect Atom client state and React integration"
4
+ default_prompt: "Use $effect-atom-state to move this component's client state and workflows into Effect Atom."