@danieljvdm/dev-kit 0.13.0 → 0.15.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.
package/README.md CHANGED
@@ -179,6 +179,7 @@ tool versions. A project-local process lock also prevents concurrent applies.
179
179
  "include": [
180
180
  "dev-kit",
181
181
  "effect",
182
+ "open-pull-request",
182
183
  "workers-best-practices",
183
184
  "wrangler",
184
185
  "serve-sim",
@@ -198,18 +199,14 @@ tool versions. A project-local process lock also prevents concurrent applies.
198
199
  ```
199
200
 
200
201
  - `dev-kit` installs guidance for operating the toolkit itself.
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.
206
- - Prefer individual external skills such as `workers-best-practices` and
207
- `wrangler`, selected after scanning the project for relevant technologies.
208
- - `serve-sim` selects the approved Evan Bacon simulator skill directly.
202
+ - `effect` is a built-in family: the `effect-ts` bootstrap,
203
+ `effect-architecture-audit`, `build-effect-apis`, and `build-effect-clis`.
204
+ - External Git skills (`workers-best-practices`, `serve-sim`, …) are selected
205
+ individually after scanning the project for relevant technologies. An
206
+ approved source ID selects every skill from that source; use it only when
207
+ the scan confirms that every member applies.
209
208
  - `@tanstack/ai#ai-core` explicitly selects a skill discovered in that direct
210
209
  project dependency; discovery alone never selects it.
211
- - An approved source ID is broad shorthand that selects every skill from that
212
- source. Use it only when the scan confirms that every member applies.
213
210
 
214
211
  Dev Kit reserves `.repos/<source-id>` for project-local source checkouts. Run
215
212
  `dev-kit gitignore` to add `.repos/` and `.dev-kit/` to the project ignore file.
@@ -235,18 +232,17 @@ bridge in the manifest:
235
232
  `AGENTS.md`, preserving handwritten project guidance around them. The Dev Kit
236
233
  section contains a short description and a pointer to the installed `dev-kit`
237
234
  skill. When the root `package.json` declares `vite-plus` directly, Dev Kit
238
- renders its own repository-specific Vite+ guidance, including the unified
239
- toolchain overview, help and documentation entry points, and `vp env doctor`
240
- troubleshooting. It does not import Vite+'s generic `AGENTS.md`, which can
241
- conflict with the repository's exact commands; transitive installations do not
242
- opt a project in. Previously managed Vite+ sections are removed during a safe
243
- owned update. Ambiguous or malformed managed markers fail closed.
235
+ renders its own repository-specific Vite+ guidance toolchain overview, help
236
+ and documentation entry points, `vp env doctor` troubleshooting — rather than
237
+ importing Vite+'s generic `AGENTS.md`, which can contradict the repository's
238
+ exact commands; transitive installations do not opt a project in. Ambiguous or
239
+ malformed managed markers fail closed.
244
240
 
245
241
  The Dev Kit section also renders an opinionated project command policy. A
246
242
  direct Vite+ dependency makes `vp` the only supported front door: built-in
247
243
  format, lint, and test commands use `vp`, while repository tasks and package
248
- scripts use `vp run`. When Dev Kit manages the quality config, the canonical
249
- full validation and typecheck commands are `vp run check` and
244
+ scripts use `vp run`. When the manifest enables the Vite+ workflow scaffold,
245
+ the canonical full validation and typecheck commands are `vp run check` and
250
246
  `vp run typecheck`; `vp check` alone is only the Vite+ static-check command.
251
247
  Without Vite+, Bun is the required package-script runner and Dev Kit lists only
252
248
  quality scripts the root package actually declares. The package manager named
@@ -287,7 +283,7 @@ worktree converges its own copy during install while the project-owned
287
283
  ## Vite+ quality setup
288
284
 
289
285
  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
286
+ from that project-owned config, then opt into the scaffolded GitHub Actions
291
287
  workflow independently:
292
288
 
293
289
  ```ts
@@ -317,13 +313,6 @@ Project and framework-generated paths belong in `ignorePatterns` as shown;
317
313
  custom harness target paths belong there too. Dev Kit does not grow a global
318
314
  framework ignore list.
319
315
 
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
-
327
316
  ```jsonc
328
317
  {
329
318
  "include": ["dev-kit", "effect"],
@@ -331,19 +320,24 @@ can be removed once a supported Vite+ release executes configured JS plugins.
331
320
  "effectTsgo": { "enabled": true },
332
321
  "vitePlus": {
333
322
  "hooks": { "enabled": true },
334
- "quality": {
335
- "workflow": { "enabled": true },
336
- },
323
+ "workflow": { "enabled": true },
337
324
  },
338
325
  },
339
326
  }
340
327
  ```
341
328
 
342
- `quality.workflow.enabled` owns `.github/workflows/check.yml` but never reads,
343
- rewrites, adopts, or removes `vite.config.ts`. Workflow setup requires direct
344
- `@danieljvdm/dev-kit`, `vite-plus`, `effect`, `@effect/tsgo`, and native
345
- TypeScript dependencies with `setup.effectTsgo.enabled`. The installed Vite+
346
- must satisfy Dev Kit's peer range.
329
+ `setup.vitePlus.workflow` scaffolds `.github/workflows/check.yml` and never
330
+ reads, rewrites, adopts, or removes `vite.config.ts`. Scaffolds are
331
+ create-only: the file is written only when missing, never recorded in
332
+ `dev-kit.lock.json`, and never touched again — the repository owns it from
333
+ creation, and disabling the task leaves it in place. Edit the YAML directly
334
+ for repository-specific preparation steps or a custom typecheck command; when
335
+ the shipped template improves, compare against the installed copy under
336
+ `node_modules/@danieljvdm/dev-kit/templates/` and merge what fits.
337
+ Scaffolding requires direct `@danieljvdm/dev-kit`, `vite-plus`, `effect`,
338
+ `@effect/tsgo`, and native TypeScript dependencies with
339
+ `setup.effectTsgo.enabled`, and the installed Vite+ must satisfy Dev Kit's
340
+ peer range.
347
341
 
348
342
  Workspaces select bounded, dependency-ordered typechecking in their config:
349
343
 
@@ -359,44 +353,51 @@ export default defineConfig(
359
353
  );
360
354
  ```
361
355
 
362
- Each listed package must expose a pure `typecheck` script. Repositories can
363
- also declare workflow-specific preparation and typecheck commands:
356
+ Each listed package must expose a pure `typecheck` script.
357
+
358
+ The scaffolded workflow performs one frozen, script-suppressed install, runs
359
+ `dev-kit apply --locked`, and only then runs formatting, linting, tests, and
360
+ `vp run typecheck`. See the primary
361
+ [`setup-vp` versioning guidance](https://github.com/voidzero-dev/setup-vp#versioning),
362
+ [Vite+ install guide](https://viteplus.dev/guide/install), and
363
+ [Vite Task run guide](https://viteplus.dev/guide/run) when maintaining the
364
+ templates.
365
+
366
+ ## Worktrunk project config
367
+
368
+ Enable a scaffolded default [Worktrunk](https://worktrunk.dev) project config
369
+ in the manifest:
364
370
 
365
371
  ```jsonc
366
372
  {
373
+ "include": ["dev-kit"],
367
374
  "setup": {
368
- "effectTsgo": { "enabled": true },
369
- "vitePlus": {
370
- "quality": {
371
- "workflow": {
372
- "enabled": true,
373
- "beforeChecks": [
374
- {
375
- "name": "Install media tools",
376
- "run": ["sudo apt-get update", "sudo apt-get install --yes ffmpeg"],
377
- },
378
- ],
379
- "typecheck": [
380
- "vp run -F './apps/*' -F './packages/*' check",
381
- "vp exec tsc --noEmit -p scripts/tsconfig.json",
382
- ],
383
- },
384
- },
385
- },
375
+ "worktrunk": { "config": { "enabled": true } },
386
376
  },
387
377
  }
388
378
  ```
389
379
 
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
396
- [`setup-vp` versioning guidance](https://github.com/voidzero-dev/setup-vp#versioning),
397
- [Vite+ install guide](https://viteplus.dev/guide/install), and
398
- [Vite Task run guide](https://viteplus.dev/guide/run) when maintaining the
399
- templates.
380
+ `setup.worktrunk.config` scaffolds `.config/wt.toml` with the portable hooks an
381
+ app repository wants in every worktree: a `pre-start` pipeline that copies
382
+ gitignored files matched by `.worktreeinclude` (a no-op without that file) and
383
+ then installs dependencies, plus a `pre-merge` full-validation hook. Hook
384
+ commands render for the repository's command runner: a direct `vite-plus`
385
+ dependency selects `vp install` and `vp run check`; otherwise Dev Kit requires
386
+ a declared root `check` package script, runs it through `bun run check`, and
387
+ takes the install command from the detected package manager. Repositories with
388
+ neither fail the plan instead of shipping a broken hook.
389
+
390
+ The config follows the same create-only scaffold semantics as the check
391
+ workflow above: created once, never locked or touched again, owned by the
392
+ repository. Edit hooks freely after creation.
393
+
394
+ The config intentionally carries no worktree-path template or other user
395
+ preferences—those belong in each user's `~/.config/worktrunk/config.toml`. A
396
+ commented `post-start` block shows how to run a per-worktree dev server on a
397
+ stable branch-derived port (`{{ branch | hash_port }}`) under `wt step tether`;
398
+ point it at the repository's dev entrypoint and uncomment to opt in. Worktrunk
399
+ never runs project hooks until each user approves them with
400
+ `wt config approvals add`.
400
401
 
401
402
  ## Effect source checkout
402
403
 
@@ -518,31 +519,20 @@ bun x dev-kit add @tanstack/ai#ai-core
518
519
  That writes `@tanstack/ai#ai-core` to `dev-kit.jsonc` and, unless
519
520
  `--no-apply` is passed, installs it through the normal ownership-safe sync
520
521
  path. The qualifier prevents ambiguity when two dependencies publish the same
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.
531
-
532
- The initial compatibility boundary is intentionally small and deterministic:
533
-
534
- - only packages named in the root project's `dependencies`,
535
- `devDependencies`, `optionalDependencies`, or `peerDependencies` are
536
- scanned;
537
- - package code is never imported or executed;
538
- - npm-style and pnpm/workspace symlinks under `node_modules` are supported;
539
- - Yarn Plug'n'Play and transitive dependency traversal are not scanned; and
540
- - immediate `skills/<name>/SKILL.md` roots are listed. Nested topic skills and
541
- references remain part of that root and are copied with it.
542
-
543
- The last rule adapts Intent's routed, nested skill trees to the immediate folder
544
- and frontmatter-name invariants expected by Agent Skills targets. Dev Kit does
545
- not rewrite nested names or ask Intent to manage agent configuration.
522
+ skill name, and the installed output carries it: the copied directory flattens
523
+ the package name and appends the skill name (`@tanstack/ai#ai-core`
524
+ `tanstack-ai-ai-core`), and the copied `SKILL.md` frontmatter `name:` is
525
+ rewritten to match because harnesses identify a skill by its directory name.
526
+ Symlink-mode targets link straight into `node_modules`, so only the link
527
+ carries the qualified name. Two selections that would write the same
528
+ destination are rejected before any output changes.
529
+
530
+ The compatibility boundary is intentionally small and deterministic: only the
531
+ root project's direct dependencies are scanned, package code is never imported
532
+ or executed, npm-style and pnpm/workspace symlinks are supported (Yarn
533
+ Plug'n'Play and transitive traversal are not), and only immediate
534
+ `skills/<name>/SKILL.md` roots are listed — nested topic skills and references
535
+ are copied as part of their root.
546
536
 
547
537
  The project `dev-kit.lock.json` records the selected package name, installed
548
538
  version, original bare skill name, and the `node_modules` content digest.
@@ -648,7 +638,11 @@ export default defineConfig({
648
638
  The Oxlint preset enables `stylistic/padding-line-between-statements`: adjacent
649
639
  variable declarations remain grouped, while the next logical statement and
650
640
  all `return` statements require a separating blank line. The rule is fixable,
651
- so `vp lint --fix` repairs missing spacing automatically.
641
+ so `vp lint --fix` repairs missing spacing automatically. Vite+ 0.2.6 forwards
642
+ the preset's JavaScript-plugin declarations but its native Oxlint path does not
643
+ execute their rules — run standalone Oxlint when `effect/*` or the padding rule
644
+ must be enforced, until a supported Vite+ release executes configured JS
645
+ plugins.
652
646
 
653
647
  The preset also registers the shared `effect` JavaScript plugin. Effect
654
648
  projects opt into its rules in path-specific overrides, for example
@@ -8,9 +8,10 @@
8
8
  "effectTsgo": { "enabled": true },
9
9
  "vitePlus": {
10
10
  "hooks": { "enabled": true },
11
- "quality": {
12
- "workflow": { "enabled": true },
13
- },
11
+ "workflow": { "enabled": true },
12
+ },
13
+ "worktrunk": {
14
+ "config": { "enabled": true },
14
15
  },
15
16
  },
16
17
  "targets": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danieljvdm/dev-kit",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "private": false,
5
5
  "description": "Declarative project development toolkit with portable agent skills.",
6
6
  "license": "MIT",
@@ -48,6 +48,9 @@
48
48
  },
49
49
  "vitePlus": {
50
50
  "$ref": "#/$defs/vitePlusSetup"
51
+ },
52
+ "worktrunk": {
53
+ "$ref": "#/$defs/worktrunkSetup"
51
54
  }
52
55
  },
53
56
  "default": {}
@@ -144,8 +147,8 @@
144
147
  "hooks": {
145
148
  "$ref": "#/$defs/vitePlusHooksSetup"
146
149
  },
147
- "quality": {
148
- "$ref": "#/$defs/vitePlusQualitySetup"
150
+ "workflow": {
151
+ "$ref": "#/$defs/vitePlusWorkflowSetup"
149
152
  }
150
153
  }
151
154
  },
@@ -160,61 +163,35 @@
160
163
  }
161
164
  }
162
165
  },
163
- "vitePlusQualitySetup": {
164
- "description": "Manage the Vite+ quality workflow while the repository owns and extends vite.config.ts.",
166
+ "vitePlusWorkflowSetup": {
167
+ "description": "Scaffold the canonical GitHub Actions check workflow (.github/workflows/check.yml); the repository owns the file after creation.",
165
168
  "type": "object",
166
169
  "additionalProperties": false,
167
170
  "properties": {
168
- "workflow": {
169
- "$ref": "#/$defs/vitePlusQualityWorkflowSetup"
171
+ "enabled": {
172
+ "type": "boolean",
173
+ "default": false
170
174
  }
171
175
  }
172
176
  },
173
- "vitePlusQualityWorkflowSetup": {
174
- "description": "Manage the canonical GitHub Actions check workflow without requiring Dev Kit to own the Vite config.",
177
+ "worktrunkSetup": {
178
+ "description": "Manage project-local Worktrunk setup tasks.",
175
179
  "type": "object",
176
180
  "additionalProperties": false,
177
181
  "properties": {
178
- "enabled": {
179
- "type": "boolean",
180
- "default": false
181
- },
182
- "beforeChecks": {
183
- "description": "Repository-specific preparation steps inserted after locked setup verification and before quality checks.",
184
- "type": "array",
185
- "items": {
186
- "$ref": "#/$defs/vitePlusQualityWorkflowStep"
187
- },
188
- "default": []
189
- },
190
- "typecheck": {
191
- "description": "Shell commands for the workflow's pure typecheck step.",
192
- "type": "array",
193
- "minItems": 1,
194
- "items": {
195
- "type": "string",
196
- "minLength": 1
197
- },
198
- "default": ["vp run typecheck"]
182
+ "config": {
183
+ "$ref": "#/$defs/worktrunkConfigSetup"
199
184
  }
200
185
  }
201
186
  },
202
- "vitePlusQualityWorkflowStep": {
187
+ "worktrunkConfigSetup": {
188
+ "description": "Scaffold the default Worktrunk project config (.config/wt.toml) with portable pre-start and pre-merge hooks rendered for the repository's command runner; the repository owns the file after creation.",
203
189
  "type": "object",
204
190
  "additionalProperties": false,
205
- "required": ["name", "run"],
206
191
  "properties": {
207
- "name": {
208
- "type": "string",
209
- "minLength": 1
210
- },
211
- "run": {
212
- "type": "array",
213
- "minItems": 1,
214
- "items": {
215
- "type": "string",
216
- "minLength": 1
217
- }
192
+ "enabled": {
193
+ "type": "boolean",
194
+ "default": false
218
195
  }
219
196
  }
220
197
  },
@@ -64,6 +64,28 @@ from another version.
64
64
  runs on Cloudflare Workers or uses `effect-cf`, bindings, Durable Objects,
65
65
  Queues, WebSockets, streaming, or raw byte routes.
66
66
 
67
+ ## Choose typed Schema codecs by default
68
+
69
+ Match the codec to the static type at the call site. When decoding a value that
70
+ is already typed as the schema's `Encoded` type, use `Schema.decodeEffect` or
71
+ the typed `Schema.decodeSync`, `Schema.decodeExit`, `Schema.decodeOption`,
72
+ `Schema.decodeResult`, or `Schema.decodePromise` variant. When encoding a value
73
+ that is already typed as the schema's `Type`, use `Schema.encodeEffect` or the
74
+ corresponding typed `Schema.encodeSync`, `Schema.encodeExit`,
75
+ `Schema.encodeOption`, `Schema.encodeResult`, or `Schema.encodePromise` variant.
76
+
77
+ Reserve `Schema.decodeUnknown*` and `Schema.encodeUnknown*` for genuinely
78
+ untyped boundaries: values from `JSON.parse`, `Response.json`, external
79
+ messages, or persistence APIs whose declared result is actually `unknown`.
80
+ Never choose an unknown codec to bypass a `Schema.Class` or other static type
81
+ mismatch. Map the source value or construct the correct schema `Type` first,
82
+ then use the typed encoder; similarly, establish the correct `Encoded` value
83
+ before using a typed decoder.
84
+
85
+ This rule is toolchain-neutral. A repository may reinforce it with a lint
86
+ warning and a documented local suppression for a justified untyped boundary,
87
+ but the boundary and type reasoning remain the source of truth.
88
+
67
89
  ## Boundary rules
68
90
 
69
91
  - Let schemas own wire validation, encoding, status metadata, and branded IDs.
@@ -11,6 +11,20 @@ test integration and command authority.
11
11
  - Assert each expected error carries the intended HTTP status and body encoding.
12
12
  - Compare or smoke-test generated OpenAPI when the public contract changes.
13
13
 
14
+ ## Unknown codec audit
15
+
16
+ Inventory every `Schema.decodeUnknown*` and `Schema.encodeUnknown*` call in the
17
+ changed scope. Record a concrete untyped-boundary justification for each one,
18
+ such as `JSON.parse`, `Response.json`, an external message, or a persistence API
19
+ whose declared result is actually `unknown`. Replace any call whose input is
20
+ already the schema's `Encoded` or `Type` with the corresponding typed `Effect`,
21
+ `Sync`, `Exit`, `Option`, `Result`, or `Promise` codec.
22
+
23
+ An unknown codec is not a valid workaround for a `Schema.Class` or other static
24
+ type mismatch: map or construct the correct typed value instead. If the
25
+ repository enforces this policy with a lint warning, keep any necessary local
26
+ suppression documented with the same concrete boundary justification.
27
+
14
28
  ## Server tests
15
29
 
16
30
  - Build every changed group and fail the test if an endpoint handler is missing.
@@ -47,4 +61,5 @@ Account for every changed endpoint across these columns:
47
61
  | Params, query, headers, payload, success, errors | Scope, provided services, errors | Identifier, invariants, workflow | Typed call shape, identity, cache/invalidation | Round-trip and boundary behavior |
48
62
 
49
63
  Completion means every changed endpoint has an entry in every applicable
50
- column and the repository's formatter, linter, typechecker, and tests pass.
64
+ column, every unknown codec call has a concrete boundary justification, and the
65
+ repository's formatter, linter, typechecker, and tests pass.
@@ -1,30 +1,61 @@
1
1
  ---
2
2
  name: build-effect-clis
3
- description: Build and maintain command-line applications entirely with Effect. Use when creating or changing CLI commands, arguments, flags, subcommands, prompts, help, JSON output, dry-run or confirmation flows, platform services, child processes, Node/Bun entrypoints, or CLI integration tests.
3
+ description: Write and maintain every executable script and command-line application in an Effect repository as an Effect program. Use when creating or changing any script, one-off automation, CI check, deploy/release/build glue, package-script entrypoint, CLI command, arguments, flags, prompts, child process, filesystem or environment workflow, Node/Bun entrypoint, or integration test—including extending an existing plain-TypeScript script.
4
4
  ---
5
5
 
6
- # Build Effect CLIs
6
+ # Build Effect Scripts and CLIs
7
7
 
8
- Treat a CLI as an Effect application: the `Command` tree owns the user-facing
9
- contract, handlers adapt decoded input into application workflows, services own
10
- capabilities, and the executable entrypoint supplies platform Layers and runs
11
- the program. Do not introduce a separate CLI framework for new command work.
8
+ ## Effect-first scope
9
+
10
+ Every executable script and CLI in an Effect repository is an Effect program.
11
+ This includes one-off scripts, CI checks, deploy/release/build glue, files under
12
+ `scripts/`, package-script targets, migrations, and application entrypoints—not
13
+ only polished command-line tools.
14
+
15
+ Apply this rule when modifying code as well as when creating it. When a task
16
+ touches an existing plain-TypeScript script, convert the whole script to Effect
17
+ in the same change; matching the surrounding file's style or minimizing the
18
+ diff is not a valid exception. Prefer the repository's established Effect
19
+ patterns, including those in sibling scripts, over legacy patterns in the file
20
+ being converted.
21
+
22
+ Leave a script outside Effect only for a good, concrete technical or user
23
+ constraint that makes Effect unsuitable. Explicitly state that reason before
24
+ proceeding and in the final handoff, and keep the exception as narrow as
25
+ possible. Convenience, one-off status, and existing plain-TypeScript style are
26
+ not sufficient reasons.
27
+
28
+ Use Effect platform services for filesystem, path, environment, terminal, and
29
+ child-process work. Raw `node:*` or Bun runtime imports, `process.env`, `fs`,
30
+ `path`, `child_process`, and synchronous helpers such as `execFileSync` do not
31
+ belong in script workflows. If the installed Effect platform has no required
32
+ capability, isolate the runtime call in an explicit boundary adapter whose API
33
+ returns an Effect with typed errors, and document why that adapter is required.
34
+
35
+ Treat each executable as an Effect application. For a CLI, the `Command` tree
36
+ owns the user-facing contract, handlers adapt decoded input into application
37
+ workflows, services own capabilities, and the executable entrypoint supplies
38
+ platform Layers and runs the program. A fixed automation script with no public
39
+ arguments may export an Effect workflow directly instead of inventing a
40
+ `Command` tree. Do not introduce a separate CLI framework for command work.
12
41
 
13
42
  Effect CLI and process APIs are version-sensitive. Read the target repository's
14
43
  `node_modules/effect/AGENTS.md` completely, follow its CLI and child-process
15
44
  references, and confirm exact signatures from the installed declarations before
16
45
  editing.
17
46
 
18
- ## Build the command boundary
47
+ ## Build the executable boundary
19
48
 
20
49
  1. Inventory the existing executable entrypoints, package scripts, command
21
50
  tree, shared flags, prompts, application services, platform Layers, output
22
51
  modes, and subprocess helpers. Finish when every way to invoke and test the
23
- CLI is known.
24
- 2. Read [command-design.md](references/command-design.md). Define arguments and
25
- flags with `Argument` and `Flag`, compose commands with `Command`, and give
26
- every public input useful help. Use `Effect.fn` handlers and yield the root
27
- command when a subcommand needs shared parent input.
52
+ affected scripts or CLI is known, including sibling Effect scripts whose
53
+ patterns should replace legacy plain-TypeScript style.
54
+ 2. When the executable accepts public arguments or flags, read
55
+ [command-design.md](references/command-design.md). Define arguments and flags
56
+ with `Argument` and `Flag`, compose commands with `Command`, and give every
57
+ public input useful help. Use `Effect.fn` handlers and yield the root command
58
+ when a subcommand needs shared parent input.
28
59
  3. Keep handlers thin. Decode user and file input at the boundary, enforce
29
60
  cross-input invariants, then call an application service. Keep persistence,
30
61
  network calls, orchestration, retries, and transactions in services.
@@ -32,15 +63,15 @@ editing.
32
63
  platform failures into application-owned errors near the adapter that knows
33
64
  what the operation means. Let defects remain defects.
34
65
  5. Read [entrypoints-and-testing.md](references/entrypoints-and-testing.md).
35
- Export the command tree without running it, wire one Node or Bun entrypoint,
36
- and verify help, parsing, successful execution, expected failure, JSON
37
- output, and every dry-run or confirmation path.
66
+ Export the command tree or fixed script workflow without running it, wire
67
+ one Node or Bun entrypoint, and verify the applicable success, expected
68
+ failure, help, parsing, JSON, dry-run, and confirmation paths.
38
69
 
39
70
  ## Optional branches
40
71
 
41
72
  - Read [processes-and-platform.md](references/processes-and-platform.md) when a
42
- command reads files, inspects the environment, starts child processes,
43
- streams their output, or differs between Node and Bun.
73
+ script or command reads files, inspects the environment, starts child
74
+ processes, streams their output, or differs between Node and Bun.
44
75
  - Use `Prompt` only for an intentionally interactive path. Keep required inputs
45
76
  expressible as arguments or flags so automation never depends on a terminal.
46
77
  - Add `--dry-run` for commands that mutate important state and `--yes` for
@@ -1,4 +1,4 @@
1
1
  interface:
2
- display_name: "Build Effect CLIs"
3
- short_description: "Build typed Effect command-line applications"
4
- default_prompt: "Use $build-effect-clis to build a typed Effect CLI with clear commands, platform boundaries, and tests."
2
+ display_name: "Build Effect Scripts and CLIs"
3
+ short_description: "Write every script and CLI with Effect"
4
+ default_prompt: "Use $build-effect-clis to write or modify this script or CLI as an Effect program with explicit platform boundaries and tests."
@@ -4,6 +4,11 @@ Separate command definition from execution. Importing a command module in a test
4
4
  or another program must not parse `process.argv`, start fibers, or terminate the
5
5
  process.
6
6
 
7
+ For a fixed CI or automation script with no public command syntax, export its
8
+ Effect workflow and provide platform Layers only in a thin executable module;
9
+ it does not need an artificial `Command` tree. Use the same `runMain` boundary,
10
+ typed failures, platform services, and import-safety rules shown below.
11
+
7
12
  ```ts
8
13
  // src/cli/command.ts
9
14
  export const command = root.pipe(Command.withSubcommands([deploy, status]));
@@ -1,8 +1,9 @@
1
1
  # Processes and platform services
2
2
 
3
3
  Use Effect platform services inside CLI workflows. Keep direct `node:*`, Bun
4
- globals, `process`, filesystem calls, and shell execution at explicit adapters
5
- or the executable boundary.
4
+ globals, `process`, filesystem calls, and shell execution inside explicit
5
+ boundary adapters. The executable boundary itself should use Effect platform
6
+ runtime and service APIs.
6
7
 
7
8
  ## Own subprocess behavior in a service
8
9