diff --git a/.codex/skills/effect-ts-guide b/.codex/skills/effect-ts-guide new file mode 120000 index 00000000..d33b492b --- /dev/null +++ b/.codex/skills/effect-ts-guide @@ -0,0 +1 @@ +../../third_party/effect-ts-skills/plugins/effect-ts-skills/skills/effect-ts-guide \ No newline at end of file diff --git a/.codex/skills/effect-ts-guide/SKILL.md b/.codex/skills/effect-ts-guide/SKILL.md deleted file mode 100644 index 07b0d138..00000000 --- a/.codex/skills/effect-ts-guide/SKILL.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -name: effect-ts-guide -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. ---- - -# Effect TS Guide - -## Overview - -Use this skill to teach Effect-TS fundamentals and best practices, then apply them to user code and architecture questions. - -## Teaching workflow - -1. Clarify context: runtime (node/bun/browser), goal (new app, refactor, review), and constraints. -2. Separate core vs shell: identify pure domain logic vs effects and boundaries. -3. Model errors and dependencies: define tagged error types and Context.Tag service interfaces. -4. Compose with Effect: use pipe/Effect.gen, typed errors, and Layer provisioning. -5. Validate inputs at boundaries with @effect/schema before entering core. -6. Explain resource safety: acquireRelease, scoped lifetimes, and clean finalizers. -7. Provide minimal, runnable examples tailored to the user context. -8. If the user asks for version-specific or "latest" details, verify with official docs before answering. - -## Core practices (short list) - -- Use Effect for all side effects; keep core functions pure and total. -- Avoid async/await, raw Promise chains, and try/catch in application logic. -- Use Context.Tag + Layer for dependency injection and testability. -- Use tagged error unions and Match.exhaustive for total handling. -- Decode unknown at the boundary with @effect/schema; never leak unknown into core. -- Use Effect.acquireRelease/Effect.scoped for resource safety. -- Use @effect/platform services instead of host APIs (fetch, fs, child_process, etc.). - -## References - -- Read `references/best-practices.md` for the extended checklist and examples. -- Read `references/platform-map.md` when comparing @effect/platform to Node/Bun/Browser APIs. diff --git a/.codex/skills/effect-ts-guide/references/best-practices.md b/.codex/skills/effect-ts-guide/references/best-practices.md deleted file mode 100644 index c9518624..00000000 --- a/.codex/skills/effect-ts-guide/references/best-practices.md +++ /dev/null @@ -1,71 +0,0 @@ -# Effect-TS Best Practices (concise) - -## Design principles - -- Keep core logic pure; isolate IO in a thin shell. -- Model errors explicitly with tagged unions; avoid exceptions. -- Prefer immutable data and total functions. - -## Composition - -- Use pipe + Effect.flatMap/map or Effect.gen for sequential flows. -- Interop with Promise only at boundaries via Effect.try/Effect.tryPromise. -- Use Match.exhaustive for union handling; avoid switch in domain logic. - -## Dependency injection - -- Define services with Context.Tag and small interfaces. -- Provide live layers at runtime; provide test layers in unit tests. -- Keep service interfaces free of concrete implementations and globals. - -## Boundary validation - -- Accept unknown at the boundary only. -- Decode with @effect/schema and pass validated types into core. -- Fail fast on invalid input; keep validation errors typed. - -## Resource safety - -- Use Effect.acquireRelease for resources (connections, files, locks). -- Use Effect.scoped to control lifetimes and ensure finalizers run. - -## Platform usage - -- Use @effect/platform services instead of host APIs: - - HttpClient/HttpServer for HTTP - - FileSystem/Path for files and paths - - Command/Terminal for CLI and processes - - KeyValueStore for local storage-like needs - -## Runtime and entrypoints - -- Use Effect.runMain (or platform runtime helpers) for application entry. -- Use Logger/PlatformLogger for structured logging. - -## Testing - -- Write tests as Effects; provide test layers/mocks. -- Use TestClock/Ref for deterministic time and state. -- Use property-based tests for invariants when appropriate. - -## Minimal example (service + layer) - -```ts -import { Context, Effect, Layer, pipe } from "effect" - -class Clock extends Context.Tag("Clock") -}>() {} - -const ClockLive = Layer.succeed(Clock, { - nowMillis: Effect.sync(() => Date.now()) -}) - -const program = pipe( - Clock, - Effect.flatMap((clock) => clock.nowMillis), - Effect.map((ms) => ({ now: ms })) -) - -const main = Effect.provide(program, ClockLive) -``` diff --git a/.codex/skills/effect-ts-guide/references/platform-map.md b/.codex/skills/effect-ts-guide/references/platform-map.md deleted file mode 100644 index 82905daa..00000000 --- a/.codex/skills/effect-ts-guide/references/platform-map.md +++ /dev/null @@ -1,41 +0,0 @@ -# @effect/platform map (what it replaces) - -## Core idea - -- @effect/platform provides platform-neutral service interfaces and Layers. -- It does not monkey-patch globals; you must provide a platform layer. - -## Implementation packages - -- Node: @effect/platform-node -- Bun: @effect/platform-bun -- Browser: @effect/platform-browser - -## Common mappings - -- FileSystem -> node:fs / fs.promises / Bun file APIs -- Path -> node:path / Bun path / Deno path -- Command (+ CommandExecutor) -> child_process.spawn/exec / Deno.Command / Bun.spawn -- Terminal -> process.stdin/stdout / readline -- KeyValueStore -> Map / localStorage / file-backed KV -- PlatformConfigProvider -> dotenv + process.env + file tree config -- PlatformLogger -> console + file logging -- Runtime/runMain -> manual main + process signal handling - -## HTTP stack - -- HttpClient -> fetch / undici / axios -- FetchHttpClient -> fetch implementation -- HttpServer/HttpRouter/HttpMiddleware -> node:http + express/fastify/koa -- HttpApi/OpenApi -> manual route + schema + OpenAPI toolchain - -## Sockets and workers - -- Socket/SocketServer -> net / ws / WebSocket -- Worker/WorkerRunner -> worker_threads / Web Workers - -## Data and utilities - -- Headers/Cookies/Multipart/Etag -> manual header/cookie parsing or third-party middleware -- Url/UrlParams -> URL / URLSearchParams -- Ndjson/MsgPack -> ad-hoc codecs or third-party libs diff --git a/.gitmodules b/.gitmodules index 7c169f03..03a92977 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "third_party/skiller-desktop-skills-manager"] path = third_party/skiller-desktop-skills-manager url = https://github.com/beautyfree/skiller-desktop-skills-manager.git +[submodule "third_party/effect-ts-skills"] + path = third_party/effect-ts-skills + url = https://github.com/ProverCoderAI/effect-ts-skills.git diff --git a/docs/integrations/effect-ts-skills.md b/docs/integrations/effect-ts-skills.md new file mode 100644 index 00000000..318aa124 --- /dev/null +++ b/docs/integrations/effect-ts-skills.md @@ -0,0 +1,62 @@ +# Effect TS Skills + +The repository includes the `effect-ts-guide` Codex skill from `ProverCoderAI/effect-ts-skills` as a project-scoped skill through a git submodule. + +## Source + +- Repository: https://github.com/ProverCoderAI/effect-ts-skills +- Submodule path: `third_party/effect-ts-skills` +- Skill source path: `third_party/effect-ts-skills/plugins/effect-ts-skills/skills/effect-ts-guide` +- Submodule commit: `178adff12f5bf020b55e1aef347e2258e5033192` +- Project skill path: `.codex/skills/effect-ts-guide` + +`.codex/skills/effect-ts-guide` is a symlink to the submodule skill directory. This keeps Codex discovery on the usual project-scoped skill path without copying the upstream skill files into this repository. + +## Usage + +Codex can use the skill directly from this workspace when a task mentions `$effect-ts-guide` or asks for Effect-TS compliance work. + +The submodule skill bundles a reusable `effect-ts-check` runner and tarball asset, so the OpenAPI Effect boundary can be checked without installing the plugin globally: + +```bash +bun run effect:skill:check +``` + +The check command initializes `third_party/effect-ts-skills` first. To only initialize the submodule, run: + +```bash +bun run effect:skill:init +``` + +For exploratory migration scans across more of the monorepo, run the bundled checker directly and choose the target paths: + +```bash +bash .codex/skills/effect-ts-guide/scripts/run-effect-ts-check.sh --profile minimal +bash .codex/skills/effect-ts-guide/scripts/run-effect-ts-check.sh --profile strict +``` + +## Current Scope + +`bun run effect:skill:check` is intentionally scoped to the OpenAPI Effect client boundary that is currently green under the strict profile. A full monorepo scan still reports known legacy migration violations in API and session-sync code, so it is useful as backlog discovery rather than a merge gate. + +## Update Procedure + +Initialize the submodule after cloning this repository: + +```bash +bun run effect:skill:init +``` + +To refresh the project skill from upstream: + +```bash +git -C third_party/effect-ts-skills fetch origin main +git -C third_party/effect-ts-skills checkout +git add third_party/effect-ts-skills +``` + +After updating, run: + +```bash +bun run effect:skill:check +``` diff --git a/package.json b/package.json index 27e3c7cd..b35463f1 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,8 @@ "lint": "bun run --filter @prover-coder-ai/docker-git-terminal lint && bun run --filter @prover-coder-ai/docker-git lint && bun run --filter @effect-template/lib lint", "lint:tests": "bun run --filter @prover-coder-ai/docker-git lint:tests", "lint:effect": "bun run --filter @prover-coder-ai/docker-git-session-sync lint:effect && bun run --filter @prover-coder-ai/docker-git-terminal lint:effect && bun run --filter @prover-coder-ai/docker-git lint:effect && bun run --filter @prover-coder-ai/docker-git-container lint:effect && bun run --filter @effect-template/lib lint:effect && bun run --filter @effect-template/api lint:effect", + "effect:skill:init": "git submodule update --init --checkout third_party/effect-ts-skills", + "effect:skill:check": "bun run effect:skill:init && bash .codex/skills/effect-ts-guide/scripts/run-effect-ts-check.sh packages/app/src/web/api-create-project.ts packages/app/src/web/api-database.ts packages/app/src/web/api-http.ts packages/app/src/web/api-prompts.ts packages/app/src/web/api-skills.ts packages/app/src/web/api-tasks.ts packages/openapi/src --profile strict", "test": "bun run --filter @prover-coder-ai/docker-git-session-sync test && bun run --filter @prover-coder-ai/docker-git-terminal test && bun run --filter @prover-coder-ai/docker-git test && bun run --filter @effect-template/lib test", "typecheck": "bun run --filter @prover-coder-ai/docker-git-session-sync typecheck && bun run --filter @prover-coder-ai/docker-git-terminal typecheck && bun run --filter @prover-coder-ai/docker-git-openapi typecheck && bun run --filter @prover-coder-ai/docker-git typecheck && bun run --filter @effect-template/lib typecheck", "start": "bun run --cwd packages/app build:docker-git && bun ./packages/app/dist/src/docker-git/main.js" diff --git a/third_party/effect-ts-skills b/third_party/effect-ts-skills new file mode 160000 index 00000000..178adff1 --- /dev/null +++ b/third_party/effect-ts-skills @@ -0,0 +1 @@ +Subproject commit 178adff12f5bf020b55e1aef347e2258e5033192