Skip to content

Commit 099da38

Browse files
committed
feat(dev): add effect ts skill
1 parent 08ee941 commit 099da38

12 files changed

Lines changed: 338 additions & 110 deletions

File tree

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,75 @@
11
---
22
name: effect-ts-guide
3-
description: Teach and apply Effect-TS practices (effect, @effect/schema, @effect/platform) for architecture, typed errors, Layers, dependency injection, resource safety, testing, and migration from async/await/Promise. Use when a user asks how to use Effect, requests best practices, wants to refactor to Effect, or needs mapping from platform modules to Node/Bun/Browser APIs.
3+
description: Effect-TS guidance for architecture, typed errors, Layers, boundary validation, resource safety, compliance checks, and editor tooling. Use when a task is explicitly about reviewing or implementing Effect or @effect/* application and library code, refactoring code to Effect, validating Effect-style conventions, or wiring Effect editor/language-service setup. Do not use for generic package publishing or plugin scaffolding tasks unless the code under review is the Effect code itself.
44
---
55

66
# Effect TS Guide
77

8-
## Overview
8+
## Workflow
99

10-
Use this skill to teach Effect-TS fundamentals and best practices, then apply them to user code and architecture questions.
10+
1. Confirm the codebase or request is actually Effect-oriented. If it is not, stop and do not force this skill.
11+
2. Run the quick compliance check first:
1112

12-
## Teaching workflow
13+
```bash
14+
SKILL_DIR=<directory containing this SKILL.md>
15+
bash "$SKILL_DIR/scripts/run-effect-ts-check.sh" .
16+
```
1317

14-
1. Clarify context: runtime (node/bun/browser), goal (new app, refactor, review), and constraints.
15-
2. Separate core vs shell: identify pure domain logic vs effects and boundaries.
16-
3. Model errors and dependencies: define tagged error types and Context.Tag service interfaces.
17-
4. Compose with Effect: use pipe/Effect.gen, typed errors, and Layer provisioning.
18-
5. Validate inputs at boundaries with @effect/schema before entering core.
19-
6. Explain resource safety: acquireRelease, scoped lifetimes, and clean finalizers.
20-
7. Provide minimal, runnable examples tailored to the user context.
21-
8. If the user asks for version-specific or "latest" details, verify with official docs before answering.
18+
If the repository is mostly tooling, docs, or test fixtures for the checker itself, scope the command to the relevant Effect source directories instead of blindly linting the whole workspace.
2219

23-
## Core practices (short list)
20+
3. For stricter product-code policy checks, run:
2421

25-
- Use Effect for all side effects; keep core functions pure and total.
26-
- Avoid async/await, raw Promise chains, and try/catch in application logic.
27-
- Use Context.Tag + Layer for dependency injection and testability.
28-
- Use tagged error unions and Match.exhaustive for total handling.
29-
- Decode unknown at the boundary with @effect/schema; never leak unknown into core.
30-
- Use Effect.acquireRelease/Effect.scoped for resource safety.
31-
- Use @effect/platform services instead of host APIs (fetch, fs, child_process, etc.).
22+
```bash
23+
bash "$SKILL_DIR/scripts/run-effect-ts-check.sh" <effect-source-paths> --profile strict
24+
```
25+
26+
4. If the repository wants the official Effect dprint formatting gate too, run:
27+
28+
```bash
29+
bash "$SKILL_DIR/scripts/run-effect-ts-check.sh" <effect-source-paths> --profile strict-format
30+
```
31+
32+
5. Fix the violations that are machine-detectable.
33+
6. Apply the manual rules from the references for architecture and style decisions.
34+
7. Re-run the relevant check before finishing.
35+
36+
For editor integration tasks, treat `effect-ts-check` as the reusable CLI/compliance package and `@effect/language-service` plus VSCode settings/extensions as a separate setup concern.
37+
38+
The skill is intentionally self-contained. Resolve `scripts/run-effect-ts-check.sh` relative to the skill directory so the same instructions work for standalone installs, repo-local skills, and plugin-contributed skills without hardcoding `~/.codex`.
39+
40+
## What The Check Covers
41+
42+
The compliance check is for fast, repeatable signals:
43+
44+
- direct `async/await`
45+
- raw `Promise` usage
46+
- `try/catch` in product code
47+
- `switch`
48+
- `require`
49+
- common JavaScript and TypeScript module extensions, including `.jsx`, `.mts`, and `.cts`
50+
51+
The `strict` profile also layers in unsafe host import checks, obvious typing-policy violations such as `any` and `ts-ignore`, direct `fetch`, eslint-disable hygiene, thrown-literal checks, and path-aware CORE boundary rules for casts, `unknown`, `catchAll`, CORE-to-SHELL imports, and runtime execution calls such as `Effect.runPromise` / `Effect.runSync`.
52+
53+
The `strict-format` profile runs `strict` plus the official `@effect/dprint` formatting preset. Use it when formatting should be part of the compliance gate; use `strict` when you need semantic policy results without formatting noise.
54+
55+
The wrapper uses `npx` with a bundled `effect-ts-check` tarball. It can run from a standalone skill install, but npm registry access or an npm cache is required for package dependencies.
56+
57+
## What Still Needs Judgment
58+
59+
The check does not replace architectural reasoning. Apply manual rules for:
60+
61+
- CORE vs SHELL boundaries
62+
- typed error design
63+
- Layer and dependency injection shape
64+
- boundary decoding with `@effect/schema`
65+
- resource safety with `Effect.acquireRelease` and `Effect.scoped`
66+
- exhaustive handling of unions
67+
- project-specific service factories, local package boundaries, and allowed runtime entrypoint layouts outside the default CORE/SHELL convention
3268

3369
## References
3470

35-
- Read `references/best-practices.md` for the extended checklist and examples.
36-
- Read `references/platform-map.md` when comparing @effect/platform to Node/Bun/Browser APIs.
71+
- [Best Practices](references/best-practices.md)
72+
- [Platform Map](references/platform-map.md)
73+
- [Lint Checks](references/lint-checks.md)
74+
- [Manual Writing Rules](references/manual-writing-rules.md)
75+
- [Editor Tooling](references/editor-tooling.md)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface:
2+
display_name: "Effect TS Guide"
3+
short_description: "Effect-TS guidance, checks, and editor setup"
4+
default_prompt: "Use $effect-ts-guide to review or implement Effect-TS code; run the bundled checker from the skill directory first."
5+
6+
policy:
7+
allow_implicit_invocation: true
Binary file not shown.
Lines changed: 29 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,48 @@
1-
# Effect-TS Best Practices (concise)
1+
# Best Practices
22

3-
## Design principles
3+
## Core Principles
44

5-
- Keep core logic pure; isolate IO in a thin shell.
6-
- Model errors explicitly with tagged unions; avoid exceptions.
5+
- Keep core logic pure.
6+
- Keep IO in a thin shell.
7+
- Model errors explicitly with tagged unions.
78
- Prefer immutable data and total functions.
89

910
## Composition
1011

11-
- Use pipe + Effect.flatMap/map or Effect.gen for sequential flows.
12-
- Interop with Promise only at boundaries via Effect.try/Effect.tryPromise.
13-
- Use Match.exhaustive for union handling; avoid switch in domain logic.
12+
- Use `pipe`, `Effect.flatMap`, `Effect.map`, or `Effect.gen` for sequential flows.
13+
- Use `Match.exhaustive` for union handling.
14+
- Use `Effect.try` and `Effect.tryPromise` only at boundaries.
1415

15-
## Dependency injection
16+
## Dependency Injection
1617

17-
- Define services with Context.Tag and small interfaces.
18-
- Provide live layers at runtime; provide test layers in unit tests.
19-
- Keep service interfaces free of concrete implementations and globals.
18+
- Define services with `Context.Tag`.
19+
- Provide live layers at runtime.
20+
- Provide test layers in tests.
2021

21-
## Boundary validation
22+
## Boundary Validation
2223

23-
- Accept unknown at the boundary only.
24-
- Decode with @effect/schema and pass validated types into core.
25-
- Fail fast on invalid input; keep validation errors typed.
24+
- Accept `unknown` only at the boundary.
25+
- Decode with `@effect/schema`.
26+
- Pass validated values into core logic.
2627

27-
## Resource safety
28+
## Resource Safety
2829

29-
- Use Effect.acquireRelease for resources (connections, files, locks).
30-
- Use Effect.scoped to control lifetimes and ensure finalizers run.
30+
- Use `Effect.acquireRelease` for resources.
31+
- Use `Effect.scoped` for controlled lifetimes.
3132

32-
## Platform usage
33+
## Platform Usage
3334

34-
- Use @effect/platform services instead of host APIs:
35-
- HttpClient/HttpServer for HTTP
36-
- FileSystem/Path for files and paths
37-
- Command/Terminal for CLI and processes
38-
- KeyValueStore for local storage-like needs
39-
40-
## Runtime and entrypoints
41-
42-
- Use Effect.runMain (or platform runtime helpers) for application entry.
43-
- Use Logger/PlatformLogger for structured logging.
35+
- Prefer `@effect/platform` services over host APIs.
36+
- Use `HttpClient`, `FileSystem`, `Path`, `Command`, and `PlatformLogger` where appropriate.
4437

4538
## Testing
4639

47-
- Write tests as Effects; provide test layers/mocks.
48-
- Use TestClock/Ref for deterministic time and state.
49-
- Use property-based tests for invariants when appropriate.
50-
51-
## Minimal example (service + layer)
52-
53-
```ts
54-
import { Context, Effect, Layer, pipe } from "effect"
55-
56-
class Clock extends Context.Tag("Clock")<Clock, {
57-
readonly nowMillis: Effect.Effect<number, never>
58-
}>() {}
59-
60-
const ClockLive = Layer.succeed(Clock, {
61-
nowMillis: Effect.sync(() => Date.now())
62-
})
40+
- Write tests as Effects.
41+
- Use test layers and mocks.
42+
- Add property-based tests when a rule should hold for many inputs.
6343

64-
const program = pipe(
65-
Clock,
66-
Effect.flatMap((clock) => clock.nowMillis),
67-
Effect.map((ms) => ({ now: ms }))
68-
)
44+
## Editor Setup
6945

70-
const main = Effect.provide(program, ClockLive)
71-
```
46+
- Use `@effect/language-service` in `tsconfig.base.json` for editor diagnostics and Effect-aware suggestions.
47+
- Recommend the Effect VSCode extension alongside ESLint, but treat it as authoring support rather than a runtime or CI dependency.
48+
- Keep the editor language service separate from the reusable CLI compliance package.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Editor Tooling
2+
3+
## Scope
4+
5+
- `@prover-coder-ai/effect-ts-check` is the reusable CLI/compliance package.
6+
- `scripts/run-effect-ts-check.sh` is the self-contained skill entrypoint for running that package before npm publish.
7+
- `@effect/language-service` is the editor-facing TypeScript plugin for Effect-aware diagnostics and suggestions.
8+
- VSCode integration is a separate setup layer, not part of the CLI package.
9+
10+
## What To Mention
11+
12+
- Add `@effect/language-service` to `tsconfig.base.json` `compilerOptions.plugins`.
13+
- Recommend the Effect VSCode extension `effectful-tech.effect-vscode` when the repo is used interactively in the editor.
14+
- Keep `dbaeumer.vscode-eslint` alongside the Effect extension so editor lint feedback matches the CLI package.
15+
- Keep ESLint and language-service responsibilities separate:
16+
- ESLint/CLI catches repeatable policy violations.
17+
- The language service improves editor diagnostics and suggestions.
18+
19+
## Practical Guidance
20+
21+
- If a task is about code quality enforcement in CI, use the CLI/package docs.
22+
- If a task is about authoring experience, completion, or diagnostics in the editor, use the editor tooling docs.
23+
- Do not describe the language service as a replacement for the CLI check.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Lint Checks
2+
3+
## Quick Command
4+
5+
Run this first:
6+
7+
```bash
8+
SKILL_DIR=<directory containing this SKILL.md>
9+
bash "$SKILL_DIR/scripts/run-effect-ts-check.sh" .
10+
```
11+
12+
Resolve `scripts/run-effect-ts-check.sh` relative to the skill directory. The wrapper resolves the bundled `effect-ts-check` tarball without assuming a specific install location such as `~/.codex`.
13+
14+
If the repository is mostly tooling, docs, or test fixtures for the checker itself, run the command only against the relevant Effect source paths instead of `.`.
15+
16+
The wrapper installs the bundled tarball through `npx --package`, so npm registry access or a warm npm cache is required for the package dependencies.
17+
18+
## Minimal Profile
19+
20+
The minimal profile should catch the high-signal Effect violations:
21+
22+
- `async` functions and `await`
23+
- raw `Promise` construction and `Promise.*`
24+
- `try/catch`
25+
- `switch`
26+
- `require`
27+
- common JavaScript and TypeScript module extensions, including `.jsx`, `.mts`, and `.cts`
28+
29+
## Strict Profile
30+
31+
The strict profile should add deeper policy checks:
32+
33+
- direct host imports that bypass Effect platform services
34+
- obvious unsafe typing policy violations
35+
- safer handling around casts and `unknown`
36+
- direct `fetch` and other host API restrictions
37+
- eslint comment hygiene
38+
- thrown-literal checks
39+
- path-aware CORE/SHELL boundary checks
40+
41+
The CORE/SHELL checks apply to `src/core/**` by default:
42+
43+
- CORE must not import from SHELL.
44+
- `Effect.runPromise`, `Effect.runSync`, and `Effect.runSyncExit` are shell/runtime-boundary only.
45+
- `catchAll`, casts, and `unknown` are blocked in CORE, except casts are allowed in `src/core/axioms.ts`.
46+
47+
## Strict Format Profile
48+
49+
Use `--profile strict-format` when formatting should be part of the gate:
50+
51+
```bash
52+
bash "$SKILL_DIR/scripts/run-effect-ts-check.sh" <effect-source-paths> --profile strict-format
53+
```
54+
55+
This runs `strict` plus the official `@effect/dprint` preset. Keep it separate from `strict` when you need actionable semantic findings without formatting noise.
56+
57+
Runtime execution boundaries outside the default `src/core/**` / `src/shell/**` convention still need manual review because the correct answer depends on the repository's entrypoint layout.
58+
59+
## Editor Tooling Boundary
60+
61+
- `effect-ts-check` is the reusable command-line compliance layer.
62+
- `@effect/language-service` and VSCode settings belong to the editor experience layer.
63+
- Do not expect the CLI to provide completion or hover behavior; that comes from the language service.
64+
65+
## How To Use Results
66+
67+
- Fix machine-detectable violations first.
68+
- Treat remaining issues as architecture or design decisions.
69+
- Do not use the lint output as a substitute for boundary modeling or type design.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Manual Writing Rules
2+
3+
## Applicability Gate
4+
5+
Only apply this skill when the task is explicitly Effect-related.
6+
7+
## Architecture Rules
8+
9+
- CORE must not depend on SHELL.
10+
- Effects belong in the shell or boundary layer.
11+
- Every external input should be decoded before entering core.
12+
- Every failure that matters should be typed.
13+
14+
## Code Style Rules
15+
16+
- Prefer `Effect.gen` for readable effect composition.
17+
- Prefer `Match.exhaustive` over `switch`.
18+
- Avoid `async/await` in product logic.
19+
- Avoid `try/catch` except at boundaries where you immediately convert to typed errors.
20+
- Avoid raw `Promise` chains.
21+
- Keep `Effect.runPromise`, `Effect.runSync`, and similar runtime execution calls in shell entrypoints.
22+
23+
## Review Rules
24+
25+
- If the code compiles but violates the architecture, call that out.
26+
- Separate machine-checkable issues from design issues.
27+
- If the one-command check passes, still inspect boundaries, error types, and resource lifetimes.
28+
29+
## Response Rules
30+
31+
- Be concrete about what should change.
32+
- Prefer minimal diffs.
33+
- Explain why a change preserves purity, typing, or boundary safety.
34+
35+
## Editor Integration Rules
36+
37+
- When the user asks about Effect editor support, mention both `@effect/language-service` and the VSCode extension.
38+
- Keep the explanation split between reusable compliance tooling and editor authoring setup.
39+
- If a repo already has CLI checks, do not imply the language service replaces them.
Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,18 @@
1-
# @effect/platform map (what it replaces)
1+
# Platform Map
22

3-
## Core idea
3+
`@effect/platform` replaces host APIs with typed services and Layers.
44

5-
- @effect/platform provides platform-neutral service interfaces and Layers.
6-
- It does not monkey-patch globals; you must provide a platform layer.
5+
## Common Mappings
76

8-
## Implementation packages
7+
- `HttpClient` replaces `fetch`, `undici`, and `axios`
8+
- `FileSystem` replaces `fs` and `fs.promises`
9+
- `Path` replaces `node:path`
10+
- `Command` replaces `child_process`
11+
- `Runtime` replaces direct `process` handling
12+
- `PlatformLogger` replaces `console` for structured logging
913

10-
- Node: @effect/platform-node
11-
- Bun: @effect/platform-bun
12-
- Browser: @effect/platform-browser
14+
## Guidance
1315

14-
## Common mappings
15-
16-
- FileSystem -> node:fs / fs.promises / Bun file APIs
17-
- Path -> node:path / Bun path / Deno path
18-
- Command (+ CommandExecutor) -> child_process.spawn/exec / Deno.Command / Bun.spawn
19-
- Terminal -> process.stdin/stdout / readline
20-
- KeyValueStore -> Map / localStorage / file-backed KV
21-
- PlatformConfigProvider -> dotenv + process.env + file tree config
22-
- PlatformLogger -> console + file logging
23-
- Runtime/runMain -> manual main + process signal handling
24-
25-
## HTTP stack
26-
27-
- HttpClient -> fetch / undici / axios
28-
- FetchHttpClient -> fetch implementation
29-
- HttpServer/HttpRouter/HttpMiddleware -> node:http + express/fastify/koa
30-
- HttpApi/OpenApi -> manual route + schema + OpenAPI toolchain
31-
32-
## Sockets and workers
33-
34-
- Socket/SocketServer -> net / ws / WebSocket
35-
- Worker/WorkerRunner -> worker_threads / Web Workers
36-
37-
## Data and utilities
38-
39-
- Headers/Cookies/Multipart/Etag -> manual header/cookie parsing or third-party middleware
40-
- Url/UrlParams -> URL / URLSearchParams
41-
- Ndjson/MsgPack -> ad-hoc codecs or third-party libs
16+
- Prefer Effect platform services over host APIs.
17+
- Use host APIs only when no Effect replacement is needed and the boundary is already isolated.
18+
- Editor tooling such as `@effect/language-service` is not a runtime replacement for host APIs; it only improves authoring feedback.

0 commit comments

Comments
 (0)