@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
@@ -0,0 +1,86 @@
1
+ # TanStack Start integration
2
+
3
+ TanStack Start modules are isomorphic unless an explicit boundary says
4
+ otherwise. Choose one data-execution model before wiring Effect Atom.
5
+
6
+ ## Client-only atom data
7
+
8
+ Use this when identity, focus signals, or other dependencies require browser
9
+ globals.
10
+
11
+ 1. Mount one `RegistryProvider` around the application subtree whose client
12
+ navigations should share cache state.
13
+ 2. Put browser-dependent atom consumers behind `ClientOnly`.
14
+ 3. Keep the runtime, `AtomHttpApi.Service`, query families, and mutations as
15
+ client module singletons.
16
+ 4. Render a useful server fallback and accept that API fetching begins after
17
+ hydration.
18
+
19
+ ```tsx
20
+ import { RegistryProvider } from "@effect/atom-react";
21
+ import { ClientOnly, Outlet } from "@tanstack/react-router";
22
+
23
+ export function Root() {
24
+ return (
25
+ <RegistryProvider defaultIdleTTL={60_000}>
26
+ <ClientOnly fallback={<AppSkeleton />}>
27
+ <Outlet />
28
+ </ClientOnly>
29
+ </RegistryProvider>
30
+ );
31
+ }
32
+ ```
33
+
34
+ `Atom.windowFocusSignal`, `localStorage`, `window`, and `document` belong in
35
+ this client-only branch.
36
+
37
+ ## SSR or loader-owned data
38
+
39
+ Prefer TanStack loaders or server functions when they already own SSR data.
40
+ Pass loader data into the client state graph or keep the query loader-owned;
41
+ avoid maintaining two independent server caches for the same request.
42
+
43
+ When atom SSR is intentional:
44
+
45
+ - create the registry and request-specific runtime/layers per request;
46
+ - give serializable queries deterministic `serializationKey` values;
47
+ - mount or run only the intended serializable atoms on the server;
48
+ - dehydrate only intended values;
49
+ - create the browser registry once and hydrate matching atom identities before
50
+ descendants read them;
51
+ - use `HydrationBoundary` when the installed React adapter supports it.
52
+
53
+ Process-global registries or memo maps can leak request-specific authentication
54
+ and server state across users. Verify request isolation with concurrent SSR
55
+ tests.
56
+
57
+ ## Focus is browser-only
58
+
59
+ `Atom.windowFocusSignal` reads `window` and `document.visibilityState` when
60
+ mounted. Keep focus-enabled consumers behind `ClientOnly`, or inject a no-op
61
+ server signal and the browser signal on the client. `revalidateOnFocus: true`
62
+ respects `staleTime`; `"always"` forces a request on each focus signal.
63
+
64
+ ## Separate API development
65
+
66
+ When TanStack Start and the Effect API run as separate local processes, proxy a
67
+ stable prefix and WebSocket upgrades through the app dev server:
68
+
69
+ ```ts
70
+ export default defineConfig({
71
+ plugins: [tanstackStart(), react()],
72
+ server: {
73
+ proxy: {
74
+ "/api": {
75
+ target: "http://127.0.0.1:8787",
76
+ changeOrigin: true,
77
+ ws: true,
78
+ },
79
+ },
80
+ },
81
+ });
82
+ ```
83
+
84
+ Keep the client base URL aligned with proxy and production routing. If
85
+ credentials cross origins, configure CORS and cookie/header behavior at the API
86
+ edge and test the deployed topology, not only the same-origin development path.
@@ -0,0 +1,50 @@
1
+ # Verification
2
+
3
+ Test the contract spine at its seams. Use the repository's established Effect
4
+ test integration and command authority.
5
+
6
+ ## Contract tests
7
+
8
+ - Decode and re-encode representative request, success, and error values.
9
+ - Prove branded path/query/header values reject invalid wire input.
10
+ - Encode any `Schema.Class` headers exactly as generated clients receive them.
11
+ - Assert each expected error carries the intended HTTP status and body encoding.
12
+ - Compare or smoke-test generated OpenAPI when the public contract changes.
13
+
14
+ ## Server tests
15
+
16
+ - Build every changed group and fail the test if an endpoint handler is missing.
17
+ - Provide deterministic test layers for application services and middleware.
18
+ - Prove each handler exposes only errors declared by its endpoint; exercise
19
+ expected reason mapping and unexpected failure defects separately.
20
+ - Exercise success, declared failure, malformed input, and middleware rejection.
21
+ - Assert cross-field boundary invariants before the service workflow runs.
22
+ - Exercise raw routes separately and prove they enforce middleware-equivalent
23
+ identity/security rules.
24
+
25
+ Use the installed `HttpApiTest` or an in-memory `HttpClient` when available;
26
+ otherwise run the built HTTP application against representative requests. Avoid
27
+ mocking below the contract so heavily that request encoding and response
28
+ decoding are skipped.
29
+
30
+ ## Client tests
31
+
32
+ - Derive the client from the same root API used by the server.
33
+ - Provide every `requiredForClient` middleware with
34
+ `HttpApiMiddleware.layerClient` and assert that it transforms the request.
35
+ - Assert params, query, headers, payload, and expected errors at least once for
36
+ every changed request shape.
37
+ - For Atom clients, complete every applicable scenario routed through
38
+ `effect-atom-testing.md`; use a deterministic HTTP layer so request encoding,
39
+ invalidation, and lifecycle remain observable.
40
+
41
+ ## Completion matrix
42
+
43
+ Account for every changed endpoint across these columns:
44
+
45
+ | Contract | Middleware | Handler/service | Client/query/mutation | Tests |
46
+ | ------------------------------------------------ | -------------------------------- | -------------------------------- | ---------------------------------------------- | -------------------------------- |
47
+ | 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
+
49
+ Completion means every changed endpoint has an entry in every applicable
50
+ column and the repository's formatter, linter, typechecker, and tests pass.
@@ -0,0 +1,61 @@
1
+ ---
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.
4
+ ---
5
+
6
+ # Build Effect CLIs
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.
12
+
13
+ Effect CLI and process APIs are version-sensitive. Read the target repository's
14
+ `node_modules/effect/AGENTS.md` completely, follow its CLI and child-process
15
+ references, and confirm exact signatures from the installed declarations before
16
+ editing.
17
+
18
+ ## Build the command boundary
19
+
20
+ 1. Inventory the existing executable entrypoints, package scripts, command
21
+ tree, shared flags, prompts, application services, platform Layers, output
22
+ 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.
28
+ 3. Keep handlers thin. Decode user and file input at the boundary, enforce
29
+ cross-input invariants, then call an application service. Keep persistence,
30
+ network calls, orchestration, retries, and transactions in services.
31
+ 4. Keep expected operational failures typed with `Schema.TaggedError`; map
32
+ platform failures into application-owned errors near the adapter that knows
33
+ what the operation means. Let defects remain defects.
34
+ 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.
38
+
39
+ ## Optional branches
40
+
41
+ - 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.
44
+ - Use `Prompt` only for an intentionally interactive path. Keep required inputs
45
+ expressible as arguments or flags so automation never depends on a terminal.
46
+ - Add `--dry-run` for commands that mutate important state and `--yes` for
47
+ explicitly authorized non-interactive confirmation. Never prompt in JSON or
48
+ CI-oriented modes.
49
+
50
+ ## CLI ownership rules
51
+
52
+ - Let `Command`, `Argument`, and `Flag` own syntax, defaults, aliases, examples,
53
+ and help text.
54
+ - Let schemas own untrusted structured input and machine-readable output.
55
+ - Let handlers own CLI-to-application mapping and presentation selection.
56
+ - Let services own reusable behavior and external capabilities.
57
+ - Let Layers own implementations and runtime dependencies.
58
+ - Let the executable entrypoint own `Command.run`, platform provisioning,
59
+ scopes, signal handling, and `NodeRuntime.runMain` or `BunRuntime.runMain`.
60
+ - Keep stdout stable for primary or machine-readable output. Send diagnostics
61
+ and progress elsewhere; never mix prose into JSON output.
@@ -0,0 +1,4 @@
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."
@@ -0,0 +1,93 @@
1
+ # Command design
2
+
3
+ Model the CLI's public surface as a typed contract. Prefer a small root command,
4
+ shared parent flags, focused subcommands, and Effect handlers.
5
+
6
+ ```ts
7
+ import { Effect } from "effect";
8
+ import { Argument, Command, Flag } from "effect/unstable/cli";
9
+
10
+ const workspace = Flag.string("workspace").pipe(
11
+ Flag.withAlias("w"),
12
+ Flag.withDescription("Workspace to operate on"),
13
+ Flag.withDefault("personal"),
14
+ );
15
+
16
+ const root = Command.make("acme").pipe(
17
+ Command.withSharedFlags({
18
+ workspace,
19
+ verbose: Flag.boolean("verbose").pipe(
20
+ Flag.withAlias("v"),
21
+ Flag.withDescription("Print diagnostic output"),
22
+ ),
23
+ }),
24
+ Command.withDescription("Operate Acme projects"),
25
+ );
26
+
27
+ const deploy = Command.make(
28
+ "deploy",
29
+ {
30
+ environment: Argument.string("environment").pipe(
31
+ Argument.withDescription("Target environment"),
32
+ ),
33
+ dryRun: Flag.boolean("dry-run").pipe(
34
+ Flag.withDescription("Show the deployment plan without applying it"),
35
+ ),
36
+ json: Flag.boolean("json").pipe(Flag.withDescription("Print machine-readable JSON")),
37
+ },
38
+ Effect.fn("deployCommand")(function* ({ dryRun, environment, json }) {
39
+ const shared = yield* root;
40
+ const deployments = yield* Deployments;
41
+ const plan = yield* deployments.plan({ environment, workspace: shared.workspace });
42
+
43
+ if (dryRun) return yield* renderPlan(plan, { json });
44
+
45
+ const result = yield* deployments.apply(plan);
46
+ return yield* renderDeployment(result, { json });
47
+ }),
48
+ ).pipe(
49
+ Command.withDescription("Deploy a workspace"),
50
+ Command.withExamples([
51
+ {
52
+ command: "acme --workspace team deploy production --dry-run",
53
+ description: "Preview a production deployment",
54
+ },
55
+ ]),
56
+ );
57
+
58
+ export const command = root.pipe(Command.withSubcommands([deploy]));
59
+ ```
60
+
61
+ ## Input and help
62
+
63
+ - Use arguments for essential positional identity and flags for optional
64
+ behavior. Prefer named flags when position would be ambiguous.
65
+ - Give public commands, arguments, and non-obvious flags descriptions. Add
66
+ examples for quoting, shared flags, or surprising combinations.
67
+ - Put cross-command inputs in `Command.withSharedFlags`; read them by yielding
68
+ the parent command instead of duplicating parsing or reading globals.
69
+ - Use `Flag.choice` for closed vocabularies and schemas for structured values
70
+ loaded from JSON, files, or environment boundaries.
71
+ - Keep aliases additive and unsurprising. Never give two concepts the same
72
+ short flag in one command path.
73
+
74
+ ## Interactive and automated use
75
+
76
+ - Make every required value available non-interactively. A fallback `Prompt`
77
+ may improve terminal use but must not be the only way to supply input.
78
+ - Prompt only after deterministic discovery cannot choose safely. Summarize the
79
+ detected state and the exact mutation before requesting confirmation.
80
+ - Pair destructive execution with a genuine plan/apply split. `--dry-run` must
81
+ run the real discovery and planning logic while skipping writes.
82
+ - Require explicit `--yes` or an equivalent authorization flag when a
83
+ non-interactive destructive path cannot prompt.
84
+
85
+ ## Output contract
86
+
87
+ - Treat human and machine output as separate renderers over the same result.
88
+ - In `--json` mode, emit one documented schema-encoded value to stdout. Send no
89
+ headings, spinners, progress, or warnings to stdout.
90
+ - Use stderr for diagnostics and failures. Keep normal human output concise and
91
+ stable enough for users to understand without reading source.
92
+ - Do not expose stack traces for expected failures. Preserve causes for logs and
93
+ tests, then render an actionable message at the executable boundary.
@@ -0,0 +1,59 @@
1
+ # Entrypoints and testing
2
+
3
+ Separate command definition from execution. Importing a command module in a test
4
+ or another program must not parse `process.argv`, start fibers, or terminate the
5
+ process.
6
+
7
+ ```ts
8
+ // src/cli/command.ts
9
+ export const command = root.pipe(Command.withSubcommands([deploy, status]));
10
+
11
+ // src/bin/acme.ts
12
+ import { NodeRuntime, NodeServices } from "@effect/platform-node";
13
+ import { Effect } from "effect";
14
+ import { Command } from "effect/unstable/cli";
15
+ import { command } from "../cli/command";
16
+
17
+ const program = Command.run(command, { version: VERSION }).pipe(
18
+ Effect.scoped,
19
+ Effect.provide(ApplicationLive),
20
+ Effect.provide(NodeServices.layer),
21
+ );
22
+
23
+ NodeRuntime.runMain(program, { disableErrorReporting: true });
24
+ ```
25
+
26
+ Use `BunRuntime` and `BunServices` together when Bun owns the executable. Let
27
+ `runMain` own signals, interruption, and process completion. Do not call
28
+ `Effect.runPromise`, `process.exit`, or runtime globals inside command handlers.
29
+ If expected errors need custom presentation, catch and render them immediately
30
+ before `runMain` while preserving CLI control-flow errors such as help output.
31
+
32
+ ## Test at three seams
33
+
34
+ 1. Test application services directly with deterministic Layers. Cover domain
35
+ success, expected failure, interruption, and plan/apply separation without
36
+ involving argument parsing.
37
+ 2. Test thin command handlers through their services when CLI input mapping or
38
+ output-mode selection contains meaningful logic.
39
+ 3. Spawn the real executable for boundary behavior. At minimum cover:
40
+ - root and changed-command `--help`;
41
+ - representative valid arguments and flags;
42
+ - missing or invalid input and a non-zero exit;
43
+ - one expected operational failure with an actionable message;
44
+ - exact JSON output with no prose contamination;
45
+ - dry-run proving writes did not occur;
46
+ - confirmation behavior in both interactive and non-interactive modes.
47
+
48
+ Run executable tests through Effect's child-process APIs with an explicit `cwd`,
49
+ captured stdout/stderr, and controlled environment. Use the repository's normal
50
+ runtime launcher and command authority; a test that bypasses the packaged or
51
+ declared entrypoint does not prove the CLI works for users.
52
+
53
+ ## Completion checks
54
+
55
+ - Ensure every executable TypeScript entrypoint belongs to a checked project.
56
+ - Run the repository's formatter, linter, typechecker, and tests.
57
+ - Execute `--help` through the real entrypoint.
58
+ - Exercise a harmless dry-run or read-only command outside the source module.
59
+ - Verify non-zero exits for parsing and expected operational failures.
@@ -0,0 +1,73 @@
1
+ # Processes and platform services
2
+
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.
6
+
7
+ ## Own subprocess behavior in a service
8
+
9
+ ```ts
10
+ import { Context, Effect, Layer, Schema, String } from "effect";
11
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
12
+
13
+ export class ToolError extends Schema.TaggedError<ToolError>()("ToolError", {
14
+ command: Schema.String,
15
+ cause: Schema.Defect(),
16
+ }) {}
17
+
18
+ export class Tools extends Context.Service<
19
+ Tools,
20
+ {
21
+ readonly gitVersion: Effect.Effect<string, ToolError>;
22
+ changedFiles(baseRef: string): Effect.Effect<ReadonlyArray<string>, ToolError>;
23
+ }
24
+ >()("app/Tools") {
25
+ static readonly layer = Layer.effect(
26
+ Tools,
27
+ Effect.gen(function* () {
28
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
29
+ const gitVersion = spawner.string(ChildProcess.make("git", ["--version"])).pipe(
30
+ Effect.map(String.trim),
31
+ Effect.mapError((cause) => new ToolError({ command: "git --version", cause })),
32
+ );
33
+ const changedFiles = Effect.fn("Tools.changedFiles")(function* (baseRef: string) {
34
+ return yield* spawner
35
+ .lines(ChildProcess.make("git", ["diff", "--name-only", `${baseRef}...HEAD`]))
36
+ .pipe(
37
+ Effect.mapError(
38
+ (cause) =>
39
+ new ToolError({ command: `git diff --name-only ${baseRef}...HEAD`, cause }),
40
+ ),
41
+ );
42
+ });
43
+
44
+ return Tools.of({ changedFiles, gitVersion });
45
+ }),
46
+ );
47
+ }
48
+ ```
49
+
50
+ Pass the executable and arguments separately to `ChildProcess.make`; never
51
+ construct a shell command from user input. Set `cwd` explicitly when repository
52
+ identity matters. Provide `env` narrowly and choose `extendEnv` deliberately so
53
+ tests and CI do not inherit accidental machine state.
54
+
55
+ Use the smallest spawner operation that matches the contract:
56
+
57
+ - `string` for bounded complete output;
58
+ - `lines` for bounded line-oriented output;
59
+ - `spawn` plus a scoped process handle for streaming, interactive, or
60
+ exit-code-sensitive work;
61
+ - `ChildProcess.pipeTo` for a real pipeline without invoking a shell.
62
+
63
+ When using `spawn`, consume stdout/stderr without deadlocking, inspect
64
+ `handle.exitCode`, and wrap the whole process lifetime in `Effect.scoped`.
65
+ Map platform failures once into an operation-specific error; do not expose a
66
+ generic subprocess error throughout the application.
67
+
68
+ ## Keep the runtime choice at the edge
69
+
70
+ Application services may require `FileSystem`, `Path`, `Terminal`, or
71
+ `ChildProcessSpawner`, but they should not import `NodeServices` or `BunServices`.
72
+ Provide the matching platform Layer only in the executable entrypoint. This
73
+ keeps workflows reusable and lets tests provide deterministic substitutes.
@@ -66,6 +66,18 @@ external source ID is also a family, but expands to every approved skill from
66
66
  that source, so prefer individually relevant external skills. Include this
67
67
  skill as `dev-kit` when project agents should carry the toolkit procedure.
68
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.
80
+
69
81
  ```jsonc
70
82
  {
71
83
  "$schema": "./node_modules/@danieljvdm/dev-kit/schema/dev-kit.schema.json",
@@ -77,7 +89,6 @@ skill as `dev-kit` when project agents should carry the toolkit procedure.
77
89
  "vitePlus": {
78
90
  "hooks": { "enabled": true },
79
91
  "quality": {
80
- "config": { "enabled": true },
81
92
  "workflow": { "enabled": true },
82
93
  },
83
94
  },
@@ -105,10 +116,16 @@ useful unified-toolchain overview, help and documentation entry points, and
105
116
  contradict the repository policy. Treat duplicate, overlapping, reversed, or
106
117
  unmatched managed markers as a conflict rather than guessing which content Dev
107
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.
108
124
  The managed section also publishes the repository's command authority. Direct
109
- Vite+ projects must use `vp` built-ins and `vp run <task>`; managed quality
110
- projects use `vp run check` for the complete format/lint/test/typecheck suite
111
- and `vp run typecheck` for the Effect-patched compiler. Non-Vite+ projects run
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
112
129
  existing root quality scripts through `bun run`; package-manager metadata and
113
130
  lockfiles affect dependency-install guidance only. Never substitute another
114
131
  script runner or call raw `tsc`, test, lint, or format binaries when a project
@@ -122,27 +139,31 @@ place.
122
139
 
123
140
  Enable `setup.vitePlus.hooks` when an installed direct `vite-plus` dependency
124
141
  should manage Git hooks. Each apply checks the local `.vite-hooks/_` dispatcher,
125
- the portable `.vite-hooks/pre-commit` hook, and `core.hooksPath`, then runs the
126
- project-local `vp config --no-agent` when they need convergence. This recreates
127
- ignored dispatchers in linked worktrees. Preserve other hook managers; Dev Kit
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
128
146
  refuses to replace an unrelated `core.hooksPath`. Use `VITE_GIT_HOOKS=0` or
129
147
  `HUSKY=0` to skip hook setup for an invocation.
130
148
 
131
- Enable `setup.vitePlus.quality.config` and
132
- `setup.vitePlus.quality.workflow` independently in supported Vite+/Effect
133
- repositories. Config owns canonical root `vite.config.ts`; workflow owns
134
- `.github/workflows/check.yml`; selecting one must not constrain the other's
135
- config, scripts, or TypeScript topology. Both require direct Dev Kit, compatible
136
- Vite+, Effect, Effect TypeScript-Go, and native TypeScript dependencies with
137
- `setup.effectTsgo.enabled`. Preserve unowned destinations and adopt only exact
138
- rendered matches.
139
-
140
- Managed config defines separate `check` and pure `typecheck` Vite tasks. Its
141
- default single-project strategy rejects project references; workspace mode
142
- requires explicit package directories with `typecheck` scripts and generates
143
- cached, dependency-ordered, bounded-concurrency filters. Keep project-reference
144
- builds custom. Workflow-only consumers may configure `workflow.beforeChecks`
145
- and `workflow.typecheck`; treat these commands as trusted manifest input.
149
+ 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.
146
167
 
147
168
  The workflow must use one frozen, script-suppressed install, then locked Dev Kit
148
169
  convergence before preparation or checks. Set up Bun from the consumer's
@@ -234,39 +255,42 @@ Enable the setup task in the same manifest:
234
255
  Install the exact `@effect/tsgo` and native `typescript` versions required by
235
256
  the installed dev-kit. Point `tsconfig.json` at
236
257
  `./node_modules/@effect/tsgo/schema.json` and configure the
237
- `@effect/language-service` compiler plugin. `dev-kit plan` validates these local
238
- dependencies; `dev-kit apply` patches once and then converges.
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
265
+ `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.
239
270
 
240
271
  Use `dev-kit tsgo patch --dry-run` for focused diagnosis. Use `--force` only
241
272
  after the user accepts a potentially commit-incompatible TypeScript binary.
242
273
 
243
274
  ## Oxlint and Oxfmt configurations
244
275
 
245
- Use Dev Kit's canonical Oxlint and Oxfmt objects in Vite+ projects:
276
+ Use Dev Kit's composable factory in Vite+ projects:
246
277
 
247
278
  ```ts
248
- import { recommendedOxlintConfig } from "@danieljvdm/dev-kit/oxlint";
249
- import { recommendedOxfmtConfig } from "@danieljvdm/dev-kit/oxfmt";
279
+ import { createRecommendedVitePlusConfig } from "@danieljvdm/dev-kit/vite-plus";
250
280
  import { defineConfig } from "vite-plus";
251
281
 
252
- export default defineConfig({
253
- fmt: {
254
- ...recommendedOxfmtConfig,
255
- },
256
- lint: {
257
- extends: [recommendedOxlintConfig],
258
- rules: {
259
- // Project-specific rules apply after the shared preset.
260
- },
261
- },
262
- });
282
+ export default defineConfig(
283
+ createRecommendedVitePlusConfig({
284
+ ignorePatterns: ["src/routeTree.gen.ts"],
285
+ }),
286
+ );
263
287
  ```
264
288
 
265
- Use `lint.extends` instead of spreading the object so Vite+ composes nested
266
- rule maps correctly. Oxfmt has no inheritance mechanism, so spread its object
267
- before project-local options. Standalone `oxlint.config.ts` uses the same
268
- `extends: [recommendedOxlintConfig]`; standalone `oxfmt.config.ts` spreads the
269
- same `recommendedOxfmtConfig`. The shared lint preset enables `typeAware` for
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
270
294
  semantic lint rules but leaves `typeCheck` disabled. Effect TypeScript-Go
271
295
  projects must run the patched native compiler separately with
272
296
  `vp run typecheck` after `vp fmt --check`, `vp lint`, and `vp test`; Oxlint's
@@ -277,6 +301,12 @@ The Oxlint preset enables the fixable
277
301
  declarations grouped, requires a blank line before the next logical statement,
278
302
  and separates every `return` statement from the preceding statement.
279
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
+
280
310
  The Oxlint preset registers Dev Kit's shared Effect plugin as `effect`, but
281
311
  does not enable its scope-sensitive rules globally. Effect projects should
282
312
  enable rules such as `effect/no-effect-run`, `effect/no-unsafe-promise`, and
@@ -290,8 +320,7 @@ in the consuming project.
290
320
 
291
321
  Manage skill outputs, the `setup.agentInstructions` marked sections, the
292
322
  `setup.claudeInstructions` link, the `setup.vitePlus.hooks` dispatcher, the
293
- independently opt-in `setup.vitePlus.quality` config and GitHub workflow, the
294
- `setup.effectSource` checkout, and the explicit `setup.effectTsgo` task.
295
- Dependency and `tsconfig.json` contributions remain deliberate user-owned
296
- edits. Custom Vite configs compose the Oxlint and Oxfmt package exports
297
- manually, leave managed config disabled, and may still use the managed workflow.
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.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: effect-architecture-audit
3
+ description: Audit an Effect TypeScript codebase's services, Layers, dependency ownership, hidden requirements, test substitutes, Schema boundaries, assertions, unknown values, and typed error channels. Use for architecture reviews, service refactors, dependency-injection audits, and type-boundary investigations; do not use as a general Effect API reference.
4
+ ---
5
+
6
+ # Audit Effect Architecture
7
+
8
+ Read the target repository's `node_modules/effect/AGENTS.md` completely before
9
+ evaluating Effect code. Follow its version-matched references for library APIs;
10
+ use this skill only for the application-architecture judgments it does not own.
11
+
12
+ Read [service-and-boundary-audit.md](references/service-and-boundary-audit.md),
13
+ then:
14
+
15
+ 1. Establish the repository's local architecture and testing rules.
16
+ 2. Inventory every service, Layer, dependency path, runtime authority, test
17
+ substitute, and unsafe type boundary in scope.
18
+ 3. Trace each capability to its owner and composition root.
19
+ 4. Classify each candidate as a built-in capability, application authority,
20
+ technology adapter, explicit value, framework boundary, or pass-through
21
+ abstraction.
22
+ 5. Report evidence-backed findings and explicit keep decisions. Do not propose
23
+ a wrapper, service, or Schema merely to make the inventory symmetrical.
24
+
25
+ When asked only to audit or review, stop after the findings. Implement changes
26
+ only when the user also requests them.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Effect Architecture Audit"
3
+ short_description: "Audit Effect service and boundary ownership"
4
+ default_prompt: "Use $effect-architecture-audit to audit this Effect codebase's services, Layers, and type boundaries."