@danieljvdm/dev-kit 0.11.3 → 0.13.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 (79) hide show
  1. package/README.md +111 -78
  2. package/dev-kit.example.jsonc +0 -4
  3. package/package.json +10 -6
  4. package/schema/dev-kit.schema.json +1 -46
  5. package/skills/build-effect-apis/SKILL.md +77 -0
  6. package/skills/build-effect-apis/agents/openai.yaml +4 -0
  7. package/skills/build-effect-apis/references/cloudflare-workers.md +71 -0
  8. package/skills/build-effect-apis/references/effect-atom-client.md +161 -0
  9. package/skills/build-effect-apis/references/effect-atom-lifecycle.md +78 -0
  10. package/skills/build-effect-apis/references/effect-atom-testing.md +74 -0
  11. package/skills/build-effect-apis/references/runtime-assembly.md +56 -0
  12. package/skills/build-effect-apis/references/server-and-middleware.md +174 -0
  13. package/skills/build-effect-apis/references/shared-contracts.md +108 -0
  14. package/skills/build-effect-apis/references/tanstack-start.md +86 -0
  15. package/skills/build-effect-apis/references/verification.md +50 -0
  16. package/skills/build-effect-clis/SKILL.md +61 -0
  17. package/skills/build-effect-clis/agents/openai.yaml +4 -0
  18. package/skills/build-effect-clis/references/command-design.md +93 -0
  19. package/skills/build-effect-clis/references/entrypoints-and-testing.md +59 -0
  20. package/skills/build-effect-clis/references/processes-and-platform.md +73 -0
  21. package/skills/dev-kit/SKILL.md +77 -48
  22. package/skills/effect-architecture-audit/SKILL.md +26 -0
  23. package/skills/effect-architecture-audit/agents/openai.yaml +4 -0
  24. package/skills/effect-architecture-audit/references/service-and-boundary-audit.md +150 -0
  25. package/skills/effect-ts/SKILL.md +21 -256
  26. package/skills/effect-ts/agents/openai.yaml +3 -3
  27. package/skills/testing/SKILL.md +5 -0
  28. package/src/catalog-manager.ts +16 -17
  29. package/src/catalog.ts +71 -16
  30. package/src/effect-source.ts +46 -24
  31. package/src/effect-tsgo.ts +86 -24
  32. package/src/gitignore.ts +5 -5
  33. package/src/index.ts +3 -6
  34. package/src/manifest.ts +0 -34
  35. package/src/node-symbolic-link.ts +2 -2
  36. package/src/oxfmt.js +5 -0
  37. package/src/oxfmt.ts +5 -0
  38. package/src/oxlint.js +5 -0
  39. package/src/oxlint.ts +5 -0
  40. package/src/package-skill-source.ts +51 -59
  41. package/src/path-digest.ts +7 -7
  42. package/src/project-package.ts +8 -7
  43. package/src/project-process-lock.ts +17 -12
  44. package/src/project-state.ts +1 -1
  45. package/src/skill-manager.ts +18 -16
  46. package/src/skill-selector.ts +12 -0
  47. package/src/sync.ts +181 -131
  48. package/src/tool-ignore-patterns.js +9 -0
  49. package/src/tool-ignore-patterns.ts +15 -0
  50. package/src/vendor.ts +67 -61
  51. package/src/vite-plus-dependency.ts +10 -11
  52. package/src/vite-plus-hooks.ts +24 -14
  53. package/src/vite-plus-quality.ts +21 -172
  54. package/src/vite-plus.js +81 -0
  55. package/src/vite-plus.ts +102 -0
  56. package/templates/AGENTS.md +1 -1
  57. package/skills/effect-ts/UPSTREAM.md +0 -28
  58. package/skills/effect-ts/references/atom-cache-lifecycle.md +0 -78
  59. package/skills/effect-ts/references/atom-http-and-invalidation.md +0 -97
  60. package/skills/effect-ts/references/atom-tanstack-start.md +0 -69
  61. package/skills/effect-ts/references/atom-testing.md +0 -67
  62. package/skills/effect-ts/references/audit-services.md +0 -144
  63. package/skills/effect-ts/references/features.md +0 -525
  64. package/skills/effect-ts/references/guide-atom-data-fetching.md +0 -44
  65. package/skills/effect-ts/references/guide-cli.md +0 -107
  66. package/skills/effect-ts/references/guide-datetime.md +0 -72
  67. package/skills/effect-ts/references/guide-effect.md +0 -440
  68. package/skills/effect-ts/references/guide-error-handling.md +0 -565
  69. package/skills/effect-ts/references/guide-http-boundaries.md +0 -55
  70. package/skills/effect-ts/references/guide-layers.md +0 -989
  71. package/skills/effect-ts/references/guide-observability.md +0 -746
  72. package/skills/effect-ts/references/guide-retries.md +0 -434
  73. package/skills/effect-ts/references/guide-schedule.md +0 -343
  74. package/skills/effect-ts/references/guide-schema.md +0 -664
  75. package/skills/effect-ts/references/guide-sql.md +0 -536
  76. package/skills/effect-ts/references/guide-testing.md +0 -532
  77. package/skills/effect-ts/references/guide-type-safety-and-boundaries.md +0 -131
  78. package/skills/effect-ts/references/version-and-source.md +0 -86
  79. package/templates/vite-plus/vite.config.ts +0 -22
package/README.md CHANGED
@@ -198,9 +198,11 @@ tool versions. A project-local process lock also prevents concurrent applies.
198
198
  ```
199
199
 
200
200
  - `dev-kit` installs guidance for operating the toolkit itself.
201
- - `effect` expands to the `effect-ts` umbrella, whose lazy references include
202
- Effect Atom HTTP data fetching and Effect DateTime guidance. The former
203
- `effect-atom-data-fetching` selector remains an alias for compatibility.
201
+ - `effect` expands to the package-guidance `effect-ts` bootstrap, the
202
+ opinionated `effect-architecture-audit`, `build-effect-apis` for shared HTTP
203
+ contracts and clients, and `build-effect-clis` for typed command-line
204
+ applications. The focused references cover Effect Atom, TanStack Start,
205
+ Cloudflare Workers, child processes, runtime entrypoints, and CLI testing.
204
206
  - Prefer individual external skills such as `workers-best-practices` and
205
207
  `wrangler`, selected after scanning the project for relevant technologies.
206
208
  - `serve-sim` selects the approved Evan Bacon simulator skill directly.
@@ -284,9 +286,44 @@ worktree converges its own copy during install while the project-owned
284
286
 
285
287
  ## Vite+ quality setup
286
288
 
287
- Vite+/Effect repositories opt into the canonical Vite config and GitHub Actions
289
+ The repository always owns `vite.config.ts`. Compose Dev Kit's quality defaults
290
+ from that project-owned config, then opt into the hardened GitHub Actions
288
291
  workflow independently:
289
292
 
293
+ ```ts
294
+ import { createRecommendedVitePlusConfig } from "@danieljvdm/dev-kit/vite-plus";
295
+ import { defineConfig } from "vite-plus";
296
+
297
+ const recommended = createRecommendedVitePlusConfig({
298
+ ignorePatterns: ["apps/api/worker-configuration.d.ts", "apps/web/src/routeTree.gen.ts"],
299
+ });
300
+
301
+ export default defineConfig({
302
+ ...recommended,
303
+ // Project-owned Vite, test, build, and framework options stay local.
304
+ server: { port: 5173 },
305
+ });
306
+ ```
307
+
308
+ Spread the returned top-level config before local options. When overriding a
309
+ `fmt`, `lint`, `run`, or `staged` block, spread that returned block as well so
310
+ its defaults remain composed. Merge nested collections too; for example, a
311
+ local lint rule block starts with `...recommended.lint.rules` before adding
312
+ repository-specific rules.
313
+
314
+ The factory configures `vp staged`, matching Oxlint/Oxfmt ignores for Dev Kit's
315
+ tool-owned paths, and separate `vp run check` and pure `vp run typecheck` tasks.
316
+ Project and framework-generated paths belong in `ignorePatterns` as shown;
317
+ custom harness target paths belong there too. Dev Kit does not grow a global
318
+ framework ignore list.
319
+
320
+ Vite+ 0.2.6 forwards JavaScript-plugin declarations into its effective lint
321
+ config but its bundled native Oxlint path does not register or execute those
322
+ rules. Native Oxlint rules and Oxfmt settings remain active; run standalone
323
+ Oxlint when enforcement of Dev Kit's `effect/*` or
324
+ `stylistic/padding-line-between-statements` rules is required. This limitation
325
+ can be removed once a supported Vite+ release executes configured JS plugins.
326
+
290
327
  ```jsonc
291
328
  {
292
329
  "include": ["dev-kit", "effect"],
@@ -295,7 +332,6 @@ workflow independently:
295
332
  "vitePlus": {
296
333
  "hooks": { "enabled": true },
297
334
  "quality": {
298
- "config": { "enabled": true },
299
335
  "workflow": { "enabled": true },
300
336
  },
301
337
  },
@@ -303,47 +339,28 @@ workflow independently:
303
339
  }
304
340
  ```
305
341
 
306
- `quality.config.enabled` owns `vite.config.ts`; `quality.workflow.enabled` owns
307
- `.github/workflows/check.yml`. Selecting one does not impose the other resource's
308
- config, scripts, or TypeScript topology. Both require direct
342
+ `quality.workflow.enabled` owns `.github/workflows/check.yml` but never reads,
343
+ rewrites, adopts, or removes `vite.config.ts`. Workflow setup requires direct
309
344
  `@danieljvdm/dev-kit`, `vite-plus`, `effect`, `@effect/tsgo`, and native
310
345
  TypeScript dependencies with `setup.effectTsgo.enabled`. The installed Vite+
311
346
  must satisfy Dev Kit's peer range.
312
347
 
313
- The managed Vite config composes the shared Oxfmt and Oxlint presets, configures
314
- `vp staged`, and defines separate `vp run check` and pure `vp run typecheck`
315
- tasks. It rejects conflicting root scripts. The default `single-project`
316
- strategy requires a root `tsconfig.json` without project references. Workspaces
317
- can instead select Vite Task orchestration explicitly:
348
+ Workspaces select bounded, dependency-ordered typechecking in their config:
318
349
 
319
- ```jsonc
320
- {
321
- "setup": {
322
- "effectTsgo": { "enabled": true },
323
- "vitePlus": {
324
- "quality": {
325
- "config": {
326
- "enabled": true,
327
- "typecheck": {
328
- "strategy": "workspace",
329
- "concurrency": 4,
330
- "packages": ["apps/web", "packages/core"],
331
- },
332
- },
333
- },
350
+ ```ts
351
+ export default defineConfig(
352
+ createRecommendedVitePlusConfig({
353
+ typecheck: {
354
+ strategy: "workspace",
355
+ concurrency: 4,
356
+ packages: ["apps/web", "packages/core"],
334
357
  },
335
- },
336
- }
358
+ }),
359
+ );
337
360
  ```
338
361
 
339
- Workspace mode requires `package.json#workspaces` and an explicit list of
340
- package directories with pure `typecheck` scripts. The generated task uses
341
- dependency order, caching, `--fail-if-no-match`, and bounded concurrency.
342
- Project-reference builds remain custom because their `.tsbuildinfo` inputs and
343
- outputs are repository-specific.
344
-
345
- Repositories with a custom Vite config can still adopt only the hardened CI
346
- workflow and declare repository-specific preparation and typecheck commands:
362
+ Each listed package must expose a pure `typecheck` script. Repositories can
363
+ also declare workflow-specific preparation and typecheck commands:
347
364
 
348
365
  ```jsonc
349
366
  {
@@ -370,16 +387,12 @@ workflow and declare repository-specific preparation and typecheck commands:
370
387
  }
371
388
  ```
372
389
 
373
- Workflow-only setup does not validate or take ownership of the Vite config,
374
- scripts, or TypeScript topology. It performs one frozen, script-suppressed
375
- install, runs `dev-kit apply --locked`, and only then runs custom preparation,
376
- formatting, linting, tests, and typechecking. Its default typecheck command is
377
- `vp run typecheck`; `workflow.typecheck` replaces it. Vite+ maps install flags
378
- to the detected package manager. The template installs the consumer's declared
379
- Bun version, follows the maintained `setup-bun@v2` tag, and names the current
380
- `setup-vp` release because that action's `v1` tag is frozen. Existing
381
- workflows remain user-owned until their rendered content matches exactly—Dev
382
- Kit never merges YAML. See the primary
390
+ The workflow performs one frozen, script-suppressed install, runs
391
+ `dev-kit apply --locked`, and only then runs preparation, formatting, linting,
392
+ tests, and typechecking. Its default typecheck command is `vp run typecheck`;
393
+ `workflow.typecheck` replaces it. Existing workflows remain user-owned until
394
+ their rendered content matches exactly—Dev Kit never merges YAML. See the
395
+ primary
383
396
  [`setup-vp` versioning guidance](https://github.com/voidzero-dev/setup-vp#versioning),
384
397
  [Vite+ install guide](https://viteplus.dev/guide/install), and
385
398
  [Vite Task run guide](https://viteplus.dev/guide/run) when maintaining the
@@ -427,7 +440,7 @@ Pin the compatible packages in the consuming project:
427
440
  {
428
441
  "devDependencies": {
429
442
  "@danieljvdm/dev-kit": "^0.2.0",
430
- "@effect/tsgo": "0.24.3",
443
+ "@effect/tsgo": "0.33.0",
431
444
  "typescript": "7.0.2",
432
445
  },
433
446
  }
@@ -437,7 +450,30 @@ Pin the compatible packages in the consuming project:
437
450
  {
438
451
  "$schema": "./node_modules/@effect/tsgo/schema.json",
439
452
  "compilerOptions": {
440
- "plugins": [{ "name": "@effect/language-service" }],
453
+ "plugins": [
454
+ {
455
+ "name": "@effect/language-service",
456
+ "diagnosticSeverity": {
457
+ "anyUnknownInErrorContext": "warning",
458
+ "instanceOfSchema": "suggestion",
459
+ "nestedEffectGenYield": "suggestion",
460
+ "newSchemaClass": "suggestion",
461
+ "preferSchemaTypeProperty": "suggestion",
462
+ "unsafeEffectTypeAssertion": "warning",
463
+ },
464
+ "overrides": [
465
+ {
466
+ "include": ["src/**/*.ts"],
467
+ "options": {
468
+ "diagnosticSeverity": {
469
+ "nodeBuiltinImport": "warning",
470
+ "preferSchemaOverJson": "suggestion",
471
+ },
472
+ },
473
+ },
474
+ ],
475
+ },
476
+ ],
441
477
  },
442
478
  }
443
479
  ```
@@ -447,7 +483,12 @@ native TypeScript compiler. It does not download dependencies and skips an
447
483
  installation that is already patched. Use `dev-kit tsgo patch --dry-run` when
448
484
  troubleshooting the task directly.
449
485
 
450
- Dependency and `tsconfig.json` edits remain explicit.
486
+ The same typed object is exported as `recommendedEffectTsgoPlugin` for
487
+ programmatic configuration tooling. Dependency and `tsconfig.json` edits remain
488
+ explicit. In a monorepo, put the plugin in the shared root config and ensure
489
+ every workspace extends it without redeclaring `compilerOptions.plugins`:
490
+ TypeScript replaces that array in child configs rather than merging it. Adjust
491
+ the `src/**/*.ts` override to the source layout seen from each config file.
451
492
 
452
493
  ## Installed package skills
453
494
 
@@ -477,8 +518,16 @@ bun x dev-kit add @tanstack/ai#ai-core
477
518
  That writes `@tanstack/ai#ai-core` to `dev-kit.jsonc` and, unless
478
519
  `--no-apply` is passed, installs it through the normal ownership-safe sync
479
520
  path. The qualifier prevents ambiguity when two dependencies publish the same
480
- skill name. Two selected skills that would both write the same destination are
481
- rejected before any output is changed.
521
+ skill name, and the installed output carries it too: the copied directory is
522
+ named by flattening the package name (drop `@`, turn every other
523
+ non-alphanumeric run into one dash) and appending the skill name, so
524
+ `@tanstack/ai#ai-core` installs as `tanstack-ai-ai-core`. Agent harnesses
525
+ identify a project skill by its directory name, so the copied `SKILL.md`
526
+ frontmatter `name:` is rewritten to that same install name; all other content
527
+ is copied verbatim. Symlink-mode targets link straight into `node_modules`, so
528
+ only the link itself carries the qualified name while the linked frontmatter
529
+ keeps the upstream bare name. Two selected skills that would both write the
530
+ same destination are rejected before any output is changed.
482
531
 
483
532
  The initial compatibility boundary is intentionally small and deterministic:
484
533
 
@@ -496,9 +545,9 @@ and frontmatter-name invariants expected by Agent Skills targets. Dev Kit does
496
545
  not rewrite nested names or ask Intent to manage agent configuration.
497
546
 
498
547
  The project `dev-kit.lock.json` records the selected package name, installed
499
- version, skill name, and content digest. `apply --locked` therefore rejects
500
- package-version or skill-content drift. Dev Kit never downloads a missing
501
- package or substitutes a registry version.
548
+ version, original bare skill name, and the `node_modules` content digest.
549
+ `apply --locked` therefore rejects package-version or skill-content drift.
550
+ Dev Kit never downloads a missing package or substitutes a registry version.
502
551
 
503
552
  See TanStack's
504
553
  [Agent Skills documentation](https://tanstack.com/ai/latest/docs/getting-started/agent-skills)
@@ -554,34 +603,18 @@ approved Git content.
554
603
 
555
604
  ## Oxlint and Oxfmt configurations
556
605
 
557
- Dev Kit exports one typed Oxlint ruleset and one typed Oxfmt configuration for
558
- both standalone Oxc projects and Vite+ projects. A Vite+ project composes them
559
- in `vite.config.ts`:
606
+ Dev Kit exports typed Oxlint/Oxfmt presets for standalone Oxc projects. The
607
+ Vite+ factory composes both presets and keeps their tool-path ignores aligned:
560
608
 
561
609
  ```ts
562
- import { recommendedOxlintConfig } from "@danieljvdm/dev-kit/oxlint";
563
- import { recommendedOxfmtConfig } from "@danieljvdm/dev-kit/oxfmt";
610
+ import { createRecommendedVitePlusConfig } from "@danieljvdm/dev-kit/vite-plus";
564
611
  import { defineConfig } from "vite-plus";
565
612
 
566
- export default defineConfig({
567
- fmt: {
568
- ...recommendedOxfmtConfig,
569
- },
570
- lint: {
571
- extends: [recommendedOxlintConfig],
572
- rules: {
573
- // Add repository-specific rules here.
574
- },
575
- },
576
- });
613
+ export default defineConfig(createRecommendedVitePlusConfig());
577
614
  ```
578
615
 
579
- Use `lint.extends` rather than a shallow object spread so Vite+ composes the
580
- nested plugin and rule configuration correctly. Oxfmt has no `extends`, so
581
- spread its configuration before project-local formatter options. The shared
582
- lint preset enables `typeAware` for semantic lint rules but leaves `typeCheck`
583
- disabled. Managed quality config uses this composition; custom Vite configs
584
- compose the exports manually. Effect TypeScript-Go projects run:
616
+ The shared lint preset enables `typeAware` for semantic lint rules but leaves
617
+ `typeCheck` disabled. Effect TypeScript-Go projects run:
585
618
 
586
619
  ```sh
587
620
  vp fmt --check
@@ -9,10 +9,6 @@
9
9
  "vitePlus": {
10
10
  "hooks": { "enabled": true },
11
11
  "quality": {
12
- "config": {
13
- "enabled": true,
14
- "typecheck": { "strategy": "single-project" },
15
- },
16
12
  "workflow": { "enabled": true },
17
13
  },
18
14
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danieljvdm/dev-kit",
3
- "version": "0.11.3",
3
+ "version": "0.13.0",
4
4
  "private": false,
5
5
  "description": "Declarative project development toolkit with portable agent skills.",
6
6
  "license": "MIT",
@@ -38,6 +38,10 @@
38
38
  "types": "./src/oxfmt.ts",
39
39
  "default": "./src/oxfmt.js"
40
40
  },
41
+ "./vite-plus": {
42
+ "types": "./src/vite-plus.ts",
43
+ "default": "./src/vite-plus.js"
44
+ },
41
45
  "./oxlint-plugin-effect": {
42
46
  "types": "./src/oxlint-plugin-effect.d.ts",
43
47
  "default": "./src/oxlint-plugin-effect.js"
@@ -65,17 +69,17 @@
65
69
  "catalog:check": "./bin/dev-kit.mjs catalog verify"
66
70
  },
67
71
  "dependencies": {
68
- "@effect/platform-bun": "4.0.0-beta.102",
72
+ "@effect/platform-bun": "4.0.0-beta.105",
69
73
  "@stylistic/eslint-plugin": "5.10.0",
70
- "effect": "4.0.0-beta.102",
74
+ "effect": "4.0.0-beta.105",
71
75
  "jsonc-parser": "3.3.1",
72
76
  "semver": "7.8.5"
73
77
  },
74
78
  "devDependencies": {
75
79
  "@changesets/cli": "3.0.0-next.10",
76
- "@effect/platform-node": "4.0.0-beta.102",
77
- "@effect/tsgo": "0.24.3",
78
- "@effect/vitest": "4.0.0-beta.102",
80
+ "@effect/platform-node": "4.0.0-beta.105",
81
+ "@effect/tsgo": "0.33.0",
82
+ "@effect/vitest": "4.0.0-beta.105",
79
83
  "@types/node": "25.9.1",
80
84
  "@types/semver": "7.8.0",
81
85
  "oxfmt": "0.60.0",
@@ -161,32 +161,15 @@
161
161
  }
162
162
  },
163
163
  "vitePlusQualitySetup": {
164
- "description": "Opt into independently managed Vite+ quality resources for supported Effect TypeScript-Go repositories.",
164
+ "description": "Manage the Vite+ quality workflow while the repository owns and extends vite.config.ts.",
165
165
  "type": "object",
166
166
  "additionalProperties": false,
167
167
  "properties": {
168
- "config": {
169
- "$ref": "#/$defs/vitePlusQualityConfigSetup"
170
- },
171
168
  "workflow": {
172
169
  "$ref": "#/$defs/vitePlusQualityWorkflowSetup"
173
170
  }
174
171
  }
175
172
  },
176
- "vitePlusQualityConfigSetup": {
177
- "description": "Manage the canonical root Vite config without requiring Dev Kit to own CI.",
178
- "type": "object",
179
- "additionalProperties": false,
180
- "properties": {
181
- "enabled": {
182
- "type": "boolean",
183
- "default": false
184
- },
185
- "typecheck": {
186
- "$ref": "#/$defs/vitePlusQualityTypecheckSetup"
187
- }
188
- }
189
- },
190
173
  "vitePlusQualityWorkflowSetup": {
191
174
  "description": "Manage the canonical GitHub Actions check workflow without requiring Dev Kit to own the Vite config.",
192
175
  "type": "object",
@@ -235,34 +218,6 @@
235
218
  }
236
219
  }
237
220
  },
238
- "vitePlusQualityTypecheckSetup": {
239
- "description": "Select the managed typecheck topology. Single-project is the default; workspace mode runs explicitly scoped package scripts through Vite Task.",
240
- "type": "object",
241
- "additionalProperties": false,
242
- "properties": {
243
- "strategy": {
244
- "enum": ["single-project", "workspace"],
245
- "default": "single-project"
246
- },
247
- "concurrency": {
248
- "description": "Maximum concurrent workspace typecheck tasks.",
249
- "type": "integer",
250
- "minimum": 1,
251
- "maximum": 32,
252
- "default": 4
253
- },
254
- "packages": {
255
- "description": "Project-relative workspace package directories whose typecheck scripts should run.",
256
- "type": "array",
257
- "items": {
258
- "type": "string",
259
- "minLength": 1
260
- },
261
- "uniqueItems": true,
262
- "default": []
263
- }
264
- }
265
- },
266
221
  "target": {
267
222
  "type": "object",
268
223
  "additionalProperties": false,
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: build-effect-apis
3
+ description: Build and consume contract-first Effect HTTP APIs. Use when defining shared HttpApiEndpoint/HttpApiGroup contracts, implementing HttpApiBuilder or HttpApiServer handlers and middleware, deriving HttpApiClient or Effect Atom clients, or integrating those APIs with TanStack Start and Cloudflare Workers/effect-cf.
4
+ ---
5
+
6
+ # Build Effect APIs
7
+
8
+ Treat the shared `HttpApi` value as the **contract spine**: schemas, server,
9
+ OpenAPI, and clients all derive from it. Keep transport contracts isomorphic;
10
+ keep runtime behavior in handlers, services, layers, and client state modules.
11
+
12
+ Effect HTTP and reactivity APIs are version-sensitive. Read the target
13
+ repository's manifests and lockfile, inspect its existing imports, and confirm
14
+ exact signatures from the installed package declarations before editing. In
15
+ current Effect v4 betas the server module is `HttpApiBuilder`; a request that
16
+ mentions `HttpApiServer` may refer to the same server-building responsibility
17
+ from another version.
18
+
19
+ ## Build the contract spine
20
+
21
+ 1. Inventory the existing API root, groups, endpoints, schemas, transport
22
+ errors, middleware, handler layers, client construction, and runtime edge.
23
+ Finish when every existing contract consumer and provider is identified.
24
+ 2. Read [shared-contracts.md](references/shared-contracts.md), then change the
25
+ shared domain package first: schemas and errors, one endpoint contract,
26
+ group composition, root API composition, and public exports. Finish when
27
+ server and client can import the same API value without runtime-specific
28
+ dependencies entering the domain package.
29
+ 3. Read [server-and-middleware.md](references/server-and-middleware.md), then
30
+ implement middleware and every changed group handler. Keep handlers as
31
+ decoded boundary adapters into application services and assemble all
32
+ requirements at the runtime edge. Finish when each endpoint identifier has
33
+ exactly one handler and every declared middleware has a provided layer.
34
+ 4. Choose the consumer branch:
35
+ - For React server state, read
36
+ [effect-atom-client.md](references/effect-atom-client.md) and
37
+ [effect-atom-lifecycle.md](references/effect-atom-lifecycle.md), then
38
+ derive one `AtomHttpApi.Service`, stable query atoms or families, mutation
39
+ atoms, and one reactivity-key vocabulary.
40
+ - For non-React Effect code, use the direct `HttpApiClient` branch in
41
+ [effect-atom-client.md](references/effect-atom-client.md).
42
+
43
+ Finish when consumers call the shared contract rather than redefining wire
44
+ types or using ad hoc `fetch` for declared endpoints.
45
+
46
+ 5. Read [verification.md](references/verification.md). Run the repository's
47
+ format, lint, typecheck, and test commands. Finish when changed schemas
48
+ round-trip, middleware failures use declared error channels, server and
49
+ client agree on every request shape, and changed atom lifecycles have
50
+ deterministic coverage.
51
+
52
+ ## Optional branches
53
+
54
+ - Read [runtime-assembly.md](references/runtime-assembly.md) when wiring a
55
+ conventional Node/Bun server, generated API docs, process entrypoint, or
56
+ serverless web handler.
57
+ - Read [effect-atom-testing.md](references/effect-atom-testing.md) when changing
58
+ Atom cache retention, SWR, polling, invalidation, cancellation, aggregation,
59
+ provider placement, SSR, or hydration behavior.
60
+ - Read [tanstack-start.md](references/tanstack-start.md) when the client is
61
+ TanStack Start, SSR, hydration, `ClientOnly`, loaders, server functions, or a
62
+ proxied separate API.
63
+ - Read [cloudflare-workers.md](references/cloudflare-workers.md) when the server
64
+ runs on Cloudflare Workers or uses `effect-cf`, bindings, Durable Objects,
65
+ Queues, WebSockets, streaming, or raw byte routes.
66
+
67
+ ## Boundary rules
68
+
69
+ - Let schemas own wire validation, encoding, status metadata, and branded IDs.
70
+ - Let endpoint files own route inputs, success, and expected transport errors.
71
+ - Let middleware own cross-cutting request behavior and request-scoped services.
72
+ - Let handlers own transport-to-application mapping and boundary invariants.
73
+ - Let application services own orchestration, persistence, retries, and
74
+ transactions.
75
+ - Let client data modules own API services, query identity, cache policy,
76
+ invalidation keys, and mutation atoms; let UI action owners own navigation,
77
+ toasts, optimistic presentation, and form reset.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Build Effect APIs"
3
+ short_description: "Build and consume typed Effect HTTP APIs"
4
+ default_prompt: "Use $build-effect-apis to build a shared Effect HTTP API and consume it from the application client."
@@ -0,0 +1,71 @@
1
+ # Cloudflare Workers and effect-cf
2
+
3
+ Use `effect-cf` to turn Worker bindings and entrypoints into Effect services and
4
+ layers. Confirm its compatibility with the repository's exact Effect v4 beta.
5
+
6
+ ## Runtime edge
7
+
8
+ Assemble application services, `HttpApiBuilder` routes, the Effect HTTP
9
+ platform/router requirements, and binding layers once, then hand the final
10
+ layer and fetch effect to `Worker.make` or another effect-cf definition.
11
+
12
+ ```ts
13
+ import { Effect, Layer } from "effect";
14
+ import { HttpRouter } from "effect/unstable/http";
15
+ import { Worker } from "effect-cf";
16
+
17
+ const WorkerLive = Layer.mergeAll(ApplicationServicesLive, ApiRoutesLive);
18
+
19
+ const fetch = Effect.gen(function* () {
20
+ const request = yield* Worker.NativeRequest;
21
+ const router = yield* HttpRouter.HttpRouter;
22
+ return yield* router.asHttpEffect();
23
+ });
24
+
25
+ export default Worker.make(WorkerLive, { fetch });
26
+ ```
27
+
28
+ The concrete Effect HTTP platform prerequisites differ by version and runtime.
29
+ Let the `HttpApiBuilder.layer` requirements drive the layer graph and verify it
30
+ with typecheck plus a Worker startup/dry-run command.
31
+
32
+ ## Typed bindings
33
+
34
+ Represent D1, R2, KV, Queues, Durable Object namespaces, and configuration as
35
+ services/layers at the Worker boundary. Application services depend on those
36
+ tags, not on a raw `env` object. Keep Wrangler binding names synchronized with
37
+ the layers and generated Worker types.
38
+
39
+ `effect-cf` typed Durable Object and Queue definitions can serve both as the
40
+ contract and as the producer/namespace service. Use deterministic Durable
41
+ Object names for domain ownership, keep RPC errors typed, and design Queue
42
+ consumers for at-least-once delivery.
43
+
44
+ ## Raw route escape hatches
45
+
46
+ JSON request/response routes fit `HttpApi`. WebSocket upgrades, streaming
47
+ responses, passthrough `Response` values, and large or direct byte transfers may
48
+ need a raw adapter at the Worker edge.
49
+
50
+ Dispatch raw routes before `router.asHttpEffect()`, decode every path/query/
51
+ header value with shared schemas, then fall through to the generated API router.
52
+ Mirror all relevant security, tenancy, tracing, and rate-limit behavior because
53
+ `HttpApi` middleware does not run for routes that bypass it.
54
+
55
+ For uploads, verify declared size, maximum size, media type, capability, and
56
+ checksum before storage. For WebSockets, validate the upgrade request and
57
+ identity before forwarding it to a Durable Object or session service.
58
+
59
+ Apply runtime-wide CORS around both raw and `HttpApi` routes. Include every
60
+ custom request header and method, and test preflight behavior. Treat OpenAPI as
61
+ documentation only for declared `HttpApi` endpoints; document raw routes
62
+ separately when clients need them.
63
+
64
+ ## Operational checks
65
+
66
+ - Generate Worker binding types after Wrangler binding changes.
67
+ - Run local migrations before local server tests.
68
+ - Run the repository's startup or deployment dry-run check after layer changes.
69
+ - Keep remote resource creation, migrations, and deployment as explicit
70
+ user-authorized operations.
71
+ - Test Queue idempotency, Durable Object naming, and raw-route middleware parity.