opencode-effect-enforcer 0.2.5 → 0.2.8
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 +42 -140
- package/docs/effect-4.0.0-rc.116-changelog.md +2654 -0
- package/docs/effect-4.0.0-rc.116.md +102 -0
- package/guidance/effect-first-development.md +28 -311
- package/guidance/progressive-disclosure-guidance.md +5 -19
- package/package.json +2 -2
- package/patterns/avoid-direct-tag-checks.md +1 -1
- package/patterns/avoid-process-env.md +4 -4
- package/patterns/context-tag-extends.md +4 -4
- package/patterns/prefer-arr-sort.md +1 -1
- package/patterns/prefer-redacted-config.md +10 -10
- package/patterns/prefer-schema-class.md +1 -1
- package/patterns/require-effect-concurrency.md +1 -1
- package/skills/effect-ai-chat/SKILL.md +2 -2
- package/skills/effect-ai-language-model/SKILL.md +36 -4
- package/skills/effect-ai-prompt/SKILL.md +1 -1
- package/skills/effect-ai-provider/SKILL.md +23 -12
- package/skills/effect-ai-tool/SKILL.md +13 -0
- package/skills/effect-atom-rpc/SKILL.md +7 -1
- package/skills/effect-atom-state/SKILL.md +8 -2
- package/skills/effect-cache/SKILL.md +10 -1
- package/skills/effect-cli/SKILL.md +105 -94
- package/skills/effect-command-executor/SKILL.md +7 -1
- package/skills/effect-config/SKILL.md +67 -44
- package/skills/effect-domain-modeling/SKILL.md +3 -3
- package/skills/effect-error-handling/SKILL.md +2 -2
- package/skills/effect-fiber/SKILL.md +2 -2
- package/skills/effect-filesystem/SKILL.md +34 -4
- package/skills/effect-http-api/SKILL.md +17 -2
- package/skills/effect-http-client/SKILL.md +11 -2
- package/skills/effect-http-server/SKILL.md +28 -11
- package/skills/effect-layer-design/SKILL.md +6 -2
- package/skills/effect-mcp-server/SKILL.md +21 -4
- package/skills/effect-observability/SKILL.md +2 -2
- package/skills/effect-optics/SKILL.md +1 -1
- package/skills/effect-parallelization/SKILL.md +2 -2
- package/skills/effect-pattern-matching/SKILL.md +1 -1
- package/skills/effect-platform-abstraction/SKILL.md +3 -3
- package/skills/effect-rpc-api/SKILL.md +3 -3
- package/skills/effect-rpc-client/SKILL.md +14 -13
- package/skills/effect-rpc-cluster/SKILL.md +15 -12
- package/skills/effect-rpc-server/SKILL.md +11 -13
- package/skills/effect-scheduling/SKILL.md +7 -0
- package/skills/effect-schema-composition/SKILL.md +12 -4
- package/skills/effect-schema-v4/SKILL.md +75 -20
- package/skills/effect-scope/SKILL.md +4 -4
- package/skills/effect-socket/SKILL.md +161 -658
- package/skills/effect-sql/SKILL.md +50 -12
- package/skills/effect-stream/SKILL.md +19 -24
- package/skills/effect-testing/SKILL.md +35 -22
- package/skills/effect-workflow/SKILL.md +13 -2
- package/src/guidance.ts +0 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Effect 4.0.0-rc.112 → 4.0.0-rc.116
|
|
2
|
+
|
|
3
|
+
## Provenance and release scope
|
|
4
|
+
|
|
5
|
+
- Previous dependency: `effect@4.0.0-rc.112`.
|
|
6
|
+
- Target: `effect@4.0.0-rc.116`, npm's `rc` dist-tag checked on 2026-09-18.
|
|
7
|
+
- npm's `latest` tag is the separate v3 line (`3.22.2`).
|
|
8
|
+
- Exact source: [`effect@4.0.0-rc.116`](https://github.com/Effect-TS/effect/tree/effect%404.0.0-rc.116), commit `d62dd0d65252e5d3635538f0e41adc7c08aa9beb`.
|
|
9
|
+
- [Complete source comparison](https://github.com/Effect-TS/effect/compare/effect%404.0.0-rc.112...effect%404.0.0-rc.116).
|
|
10
|
+
- [Full upstream release notes](effect-4.0.0-rc.116-changelog.md): 121 complete release sections across 31 packages, including dependency-only entries.
|
|
11
|
+
|
|
12
|
+
The interval includes rc.113, rc.114, rc.115, and rc.116. The changelog collection
|
|
13
|
+
was checked section-by-section against every package `CHANGELOG.md` at the target
|
|
14
|
+
tag. No upstream entry in that interval was omitted. Later releases supersede
|
|
15
|
+
earlier changes; notably PostgreSQL timestamp decoding and unknown-OID behavior
|
|
16
|
+
are documented using the final rc.116 contract.
|
|
17
|
+
|
|
18
|
+
## Changes applied
|
|
19
|
+
|
|
20
|
+
| Area | Alignment |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| Dependency and baseline | Pin Effect and lockfile to rc.116; update README and privileged baseline references. |
|
|
23
|
+
| Config and CLI | PascalCase scalar constructors, explicit Boolean defaults, typed arrays/records and ByteSize configuration. Update secret-config detector and fixtures. |
|
|
24
|
+
| Schema | Effectful transformations, standalone Getter combinators, native Arbitrary, parse options, class identity, revivers, AST contracts, template literals, JSON Schema and compilation. |
|
|
25
|
+
| Socket | Scoped pull readers, batched values, Writer objects, typed closure, backpressure, TLS/STARTTLS, addresses, framing, and reconnect ownership. |
|
|
26
|
+
| RPC and cluster | Replace MessagePack recommendations with SchemaBinary; preserve transport framing rules and codec selection; use cluster option `serialization: 'binary'`. |
|
|
27
|
+
| Filesystem and HTTP | ByteSize counts versus numeric buffer lengths and bigint seek offsets; HTTP schemas in Schema; NetAddress, eager web-handler construction, file/range responses, upgrades, parsing and SSE options. |
|
|
28
|
+
| PostgreSQL | Native PgConnection/PgPool, explicit JSON binding, preparation, registry codecs, final row representations, scoped notification queues, startup and TLS behavior. |
|
|
29
|
+
| AI and MCP | Branded service interfaces, opaque/encoded parameter modes, failure-result codecs/origins, DecisionModel, protocol adapters, strict tools, instructions, prompt titles, and stderr logging. |
|
|
30
|
+
| Streams and atoms | Lazy scan seeds, partition ordering/capacity, mapBoth names, targeted error handling, middleware errors, zero TTL, reactivity branding and dehydration. |
|
|
31
|
+
| Lifetimes and scheduling | Cache TTL by Exit, LayerMap acquisition errors, observer error types, process cleanup, timeout fallback lifetime, repeat metadata, rate-limiter store contract, durable queue policy. |
|
|
32
|
+
| Testing | Native Arbitrary sampling/property checks; adapter peer/runtime requirements; compiler-checked migration examples. |
|
|
33
|
+
| Writing | Remove release-qualified behavior from live skills, patterns, and guidance; retain version history here and in upstream release notes. |
|
|
34
|
+
|
|
35
|
+
## Content audit inventory
|
|
36
|
+
|
|
37
|
+
The audit covered all 53 bundled skill directories (54 Markdown files), all 45
|
|
38
|
+
pattern definitions, all four guidance documents, and the runtime source.
|
|
39
|
+
Removed public exports were compared between the exact old and new tags and
|
|
40
|
+
searched across the complete live content tree. Targeted scans also covered
|
|
41
|
+
lowercase Config/CLI constructors, callback sockets, MessagePack, fast-check,
|
|
42
|
+
service interface names, Stream scans, and filesystem sizes.
|
|
43
|
+
|
|
44
|
+
The following grouping records every skill directory; unchanged skills were
|
|
45
|
+
included in the compatibility scans rather than edited merely to mark an audit.
|
|
46
|
+
|
|
47
|
+
| Skill directories (`effect-` prefix omitted) | Review focus |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| schema-v4, schema-composition, domain-modeling, domain-predicates, pattern-matching, optics | Schema syntax, transformations, predicates, tagged unions and issue contracts. |
|
|
50
|
+
| config, cli | Constructor renames, defaults, prompts, collection configuration and secrets. |
|
|
51
|
+
| socket, filesystem, path, platform-abstraction, platform-layers, command-executor | Platform boundaries, scoped I/O, byte counts, address types and process lifetime. |
|
|
52
|
+
| http-api, http-client, http-server | HTTP schemas, parsing, server construction, transport errors, files, SSE and WebSocket upgrades. |
|
|
53
|
+
| rpc-api, rpc-client, rpc-server, rpc-cluster | Schema-aware serialization, framing, cluster defaults, storage and peer compatibility. |
|
|
54
|
+
| ai-chat, ai-language-model, ai-prompt, ai-provider, ai-streaming, ai-tool, mcp-server | Service types, provider responses, tool failures, decisions and MCP contracts. |
|
|
55
|
+
| atom-rpc, atom-state, react-composition | RPC/HTTP error channels, TTL, stream scan, React peer and reactive service contracts. |
|
|
56
|
+
| cache, batching, layer-design, scope, service-implementation, context-witness, managed-runtime, incremental-migration | Cached acquisition, service/layer patterns, resource ownership and runtime boundaries. |
|
|
57
|
+
| fiber, parallelization, concurrency-testing, pubsub-event-bus, stream, scheduling | Structured concurrency, stream operators, timing, retry and test synchronization. |
|
|
58
|
+
| testing, error-handling, observability, wide-events | Native property generation, error surfaces, logger configuration and instrumentation. |
|
|
59
|
+
| sql, workflow, graph, typeclass-design | Native database adapters, durable processing, graph and dual-helper compatibility. |
|
|
60
|
+
|
|
61
|
+
Patterns requiring content changes were `avoid-process-env`,
|
|
62
|
+
`prefer-redacted-config`, `avoid-direct-tag-checks`, `context-tag-extends`, and
|
|
63
|
+
`require-effect-concurrency`. The secret-config detector recognizes
|
|
64
|
+
`Config.String` and `Config.NonEmptyString`; its examples and regression cases
|
|
65
|
+
use the supported constructors. Bidirectional pattern/test inventory and README
|
|
66
|
+
catalog coverage remain required checks.
|
|
67
|
+
|
|
68
|
+
The active guidance baseline and examples were updated. Historical essays and
|
|
69
|
+
the earlier rc.112 audit retain their historical context.
|
|
70
|
+
|
|
71
|
+
## Compatibility decisions
|
|
72
|
+
|
|
73
|
+
- Keep directly consumed Effect-family packages on compatible release versions.
|
|
74
|
+
This package directly depends only on `effect`; companion adapters are teaching
|
|
75
|
+
material, not additional runtime dependencies.
|
|
76
|
+
- `@effect/vitest` requires Vitest `>=5.0.0 <6.0.0` and Node
|
|
77
|
+
`^22.12.0 || ^24.0.0 || >=26.0.0`. This repository uses plain Vitest 3 and does
|
|
78
|
+
not install that adapter; its own runner therefore remains unchanged.
|
|
79
|
+
- SchemaBinary is a wire/persistence format change, not a transparent replacement
|
|
80
|
+
for existing MessagePack bytes. Coordinate peers and stored-data migration.
|
|
81
|
+
- Native PostgreSQL is a driver change. Validate row decoding, custom OIDs,
|
|
82
|
+
preparation/pooler settings and notification recovery at consuming boundaries.
|
|
83
|
+
- The source reference's moving main branch is not the baseline. The exact tag
|
|
84
|
+
takes precedence when source and prose disagree.
|
|
85
|
+
|
|
86
|
+
## Verification
|
|
87
|
+
|
|
88
|
+
- Changelog completeness: all 121 selected upstream sections matched the collected
|
|
89
|
+
text across 31 package changelogs.
|
|
90
|
+
- Removed-export scan: no old-only qualified public Effect symbols remain in
|
|
91
|
+
skills, patterns, guidance or runtime source.
|
|
92
|
+
- `bun run check`: passed formatting, lint (zero warnings/errors) and TypeScript
|
|
93
|
+
compilation.
|
|
94
|
+
- `bun run test`: passed all 912 tests in 53 files, including detector cases,
|
|
95
|
+
inventory/catalog coverage, runtime tests and marked Markdown example
|
|
96
|
+
compilation against installed rc.116.
|
|
97
|
+
- `git diff --check`: passed.
|
|
98
|
+
|
|
99
|
+
The documentation compiler checks explicitly marked, independent TypeScript
|
|
100
|
+
fences. It does not execute every illustrative fragment or verify integrations
|
|
101
|
+
against live databases/providers. Companion-package examples were reviewed
|
|
102
|
+
against tagged source rather than adding all companion dependencies here.
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
This document defines the working model behind Effect-first code using the Effect v4 ecosystem.
|
|
4
4
|
|
|
5
|
-
Bundled baseline: **Effect 4.0.0-rc.
|
|
5
|
+
Bundled baseline: **Effect 4.0.0-rc.116**. Check the consuming project's installed
|
|
6
6
|
version and inspect the matching upstream release tag before using newer APIs.
|
|
7
|
-
The release changelog and migration audit are in `docs/effect-4.0.0-rc.
|
|
7
|
+
The release changelog and migration audit are in `docs/effect-4.0.0-rc.116.md`.
|
|
8
8
|
Source paths below are relative to the Effect source reference; locate symbols
|
|
9
9
|
by name rather than relying on line numbers or a particular tool name.
|
|
10
10
|
|
|
@@ -46,6 +46,8 @@ At boundaries:
|
|
|
46
46
|
|
|
47
47
|
## Laws and Conventions
|
|
48
48
|
|
|
49
|
+
Keep types sound: no `any`, type assertions, `@ts-ignore`, or non-null assertions.
|
|
50
|
+
|
|
49
51
|
### EF-1: Errors are data, not side effects
|
|
50
52
|
|
|
51
53
|
- If logic can fail, return `Effect.Effect<A, E, R>` with a typed error `E`.
|
|
@@ -103,8 +105,9 @@ const toDisplayName = (rawName: string | null | undefined) =>
|
|
|
103
105
|
|
|
104
106
|
- Unknown or external data must be decoded at the boundary.
|
|
105
107
|
- Prefer `Schema.decodeUnknownEffect` for effectful paths and `Schema.decodeUnknownSync` only where sync failure handling is explicit.
|
|
106
|
-
- Never use `JSON.parse` / `JSON.stringify`; use schema JSON codecs (`Schema.fromJsonString`, `Schema.decodeUnknown*`, `Schema.encode*`). For unknown JSON, use `Schema.fromJsonString(Schema.Unknown)`.
|
|
107
108
|
- Prefer `Schema.Class` over `Schema.Struct` for all decoded shapes — including HTTP response bodies, API payloads, and ephemeral wire formats, not just domain models. Named `Schema.Class` types enable `instanceof` discrimination (e.g., `Schema.Union([SuccessResponse, ErrorResponse])` then `if (parsed instanceof ErrorResponse)`), which is compile-time safe.
|
|
109
|
+
- Use `Schema.Class` for shapes discriminated via `instanceof` or participating in a `Schema.Union`.
|
|
110
|
+
- Prefer schema constructors over plain `type` / `interface` for property-based domain shapes; derive types from schemas rather than maintaining parallel models. Keep plain types for shapes schema cannot represent cleanly, such as complex type-level transforms, utility types, and overload-only surfaces.
|
|
108
111
|
- Do not name schemas with a `Schema` suffix; schema constants should be named after the domain type.
|
|
109
112
|
- For non-class schemas, export type aliases with the same identifier name as the schema value.
|
|
110
113
|
|
|
@@ -143,6 +146,7 @@ export const decodeCreateTaskInput =
|
|
|
143
146
|
### EF-5: Effect modules over native collection helpers
|
|
144
147
|
|
|
145
148
|
- Use `Arr`, `R`, `Str`, `Eq`, `HashMap`, `HashSet`, `MutableHashMap`, `MutableHashSet`.
|
|
149
|
+
- Sort with `Arr.sort(values, order)` and explicit `effect/Order` values (`Order.String`, `Order.Number`, `Order.mapInput`, etc.), never native array `.sort()`.
|
|
146
150
|
- Avoid domain usage of native `Object`, `Map`, `Set`, `Date`, and direct native string helpers.
|
|
147
151
|
- Do not use imperative `for` / `for...of` loops in domain code. Use `Arr.map`, `Arr.filter`, `Arr.filterMap`, or `Arr.reduce` for pure transformations. For effectful iteration, use `Effect.forEach` (which also supports concurrency).
|
|
148
152
|
- When behavior is unchanged, prefer the tersest helper form: direct helper refs over trivial wrapper lambdas, `flow(...)` over passthrough `pipe(...)` callbacks, and shared thunk helpers when already in scope.
|
|
@@ -206,7 +210,6 @@ const summarizeAttempts = (attempts: ReadonlyArray<number>) =>
|
|
|
206
210
|
|
|
207
211
|
### EF-8: Services use explicit tags + `Layer`
|
|
208
212
|
|
|
209
|
-
- Service identity comes from a unique string key.
|
|
210
213
|
- Honor a current Effect service-tag style already standardized by the project; otherwise default to `Context.Service`.
|
|
211
214
|
- Service constructors are explicit and layered.
|
|
212
215
|
- Dependency wiring happens in Layer composition, not hidden global state.
|
|
@@ -276,14 +279,6 @@ export const TenantHeader = Tenant.annotate({
|
|
|
276
279
|
export type Tenant = typeof Tenant.Type;
|
|
277
280
|
```
|
|
278
281
|
|
|
279
|
-
### EF-12b: Schema-first internal domain building blocks
|
|
280
|
-
|
|
281
|
-
- If an intermediate domain concept is named, reused, matched on, or structurally validated, model it as a schema first instead of an ad-hoc boolean helper.
|
|
282
|
-
- Prefer built-in schema constructors/checks such as `Schema.NonEmptyString`, `Schema.NonEmptyArray`, `Schema.TupleWithRest`, `Schema.Union`, `Schema.isPattern`, and `Schema.isIncludes` before reaching for `Schema.makeFilter`.
|
|
283
|
-
- Derive domain guards with `Schema.is(SomeSchema)`.
|
|
284
|
-
- If an internal literal domain needs type guards, use `Schema.is(Schema.Literal(...))`. For exhaustive matching over literals, use `Match`. For annotation-bearing schema values, use `Schema.Literal(...).annotate({...})`.
|
|
285
|
-
- Prefer named intermediate schemas; export and document them when reusable or when they materially clarify the module’s domain model, otherwise keep them module-local.
|
|
286
|
-
|
|
287
282
|
### EF-12c: Reusable schema checks carry metadata
|
|
288
283
|
|
|
289
284
|
- Reusable `Schema.makeFilter`, `Schema.makeFilterGroup`, and reusable built-in check blocks must include `identifier`, `title`, and `description`.
|
|
@@ -296,7 +291,7 @@ export type Tenant = typeof Tenant.Type;
|
|
|
296
291
|
- Prefer `Schema.Class` for tagged union member schemas.
|
|
297
292
|
- Use `Schema.TaggedUnion` only for canonical `_tag` object-union construction.
|
|
298
293
|
- Reference: `packages/effect/SCHEMA.md`, sections `TaggedUnion` and `toTaggedUnion`.
|
|
299
|
-
-
|
|
294
|
+
- Both union forms offer `matchOrElse` for partial matching with a typed fallback. Prefer `match` when every variant must be handled separately. `toTaggedUnion` narrows fallback input to unmatched variants; direct `Schema.TaggedUnion` types it as the full union.
|
|
300
295
|
|
|
301
296
|
Example:
|
|
302
297
|
|
|
@@ -420,6 +415,12 @@ const pollInterval = Duration.millis(250);
|
|
|
420
415
|
const program = Effect.sleep(pollInterval).pipe(Effect.timeout(timeout));
|
|
421
416
|
```
|
|
422
417
|
|
|
418
|
+
### EF-16b: Byte counts use `ByteSize`
|
|
419
|
+
|
|
420
|
+
Use `ByteSize` and `ByteSize.Input` for byte counts and storage/network limits.
|
|
421
|
+
Keep signed seek offsets as `bigint`. Parse external size strings before passing
|
|
422
|
+
them to APIs, and preserve exact counts rather than coercing them to numbers.
|
|
423
|
+
|
|
423
424
|
### EF-17: Nullable/nullish schema fields should decode to `Option`
|
|
424
425
|
|
|
425
426
|
- Use dedicated schema helpers for optional/null conversions:
|
|
@@ -467,7 +468,7 @@ const b = pipe('value', addPrefix('p:'));
|
|
|
467
468
|
|
|
468
469
|
### EF-19: JSON parse/stringify must use Schema
|
|
469
470
|
|
|
470
|
-
- Use `Schema.fromJsonString(Schema.Unknown)` for unknown JSON payloads.
|
|
471
|
+
- Use `Schema.fromJsonString(Schema.Unknown)` for unknown JSON payloads.
|
|
471
472
|
- Use `Schema.fromJsonString(MySchema)` for typed JSON string boundaries.
|
|
472
473
|
- Avoid direct `JSON.parse` / `JSON.stringify` in Effect-first code.
|
|
473
474
|
- Reference: [`fromJsonString`](packages/effect/src/Schema.ts) in the Effect v4 source.
|
|
@@ -498,6 +499,7 @@ You are not done if these fail:
|
|
|
498
499
|
|
|
499
500
|
### EF-21: Runtime execution stays at the boundary
|
|
500
501
|
|
|
502
|
+
- Runtime source uses Effect `FileSystem`, `Path`, and process services instead of `node:fs`, `node:path`, or `node:child_process`.
|
|
501
503
|
- Application entrypoints and tests may execute effects with `Effect.run*`.
|
|
502
504
|
- Library and domain exports should return `Effect` values.
|
|
503
505
|
- Keep runtime execution in one place so wiring, logging, and lifecycle behavior stay auditable.
|
|
@@ -540,7 +542,7 @@ const readSdkValue = (client: ExternalSdk) =>
|
|
|
540
542
|
- Prefer `Effect.scoped` for helper composition that allocates resources.
|
|
541
543
|
- Do not manually open resources without an explicit finalization strategy.
|
|
542
544
|
- Reference: `acquireUseRelease` and `scoped` in `packages/effect/src/Effect.ts`.
|
|
543
|
-
- For pool checkouts
|
|
545
|
+
- For pool checkouts use `Pool.use(pool, callback)` to return the item on every exit without adding a caller `Scope` requirement. Do not return an item from `Effect.scoped(Pool.get(pool))` and then use it after release.
|
|
544
546
|
|
|
545
547
|
Example:
|
|
546
548
|
|
|
@@ -615,7 +617,7 @@ const runWithHeartbeat = Effect.fn('Worker.run')(function* () {
|
|
|
615
617
|
- For non-trivial fan-out, set concurrency in `Effect.forEach`, `Effect.all`, or `Effect.validate`.
|
|
616
618
|
- Avoid implicit unbounded parallelism on large collections.
|
|
617
619
|
- Concurrency should be part of API intent for throughput-sensitive paths.
|
|
618
|
-
- Use an explicit number or `"unbounded"
|
|
620
|
+
- Use an explicit number or `"unbounded"`; pass concurrency policy directly to each combinator.
|
|
619
621
|
- Reference: `Effect.forEach`, `Effect.all`, and `Types.Concurrency` in the Effect v4 source.
|
|
620
622
|
|
|
621
623
|
Example:
|
|
@@ -640,16 +642,16 @@ Example:
|
|
|
640
642
|
import { Config, Effect } from 'effect';
|
|
641
643
|
|
|
642
644
|
const loadPort = Effect.fn('Config.loadPort')(function* () {
|
|
643
|
-
return yield* Config.
|
|
645
|
+
return yield* Config.Int('PORT');
|
|
644
646
|
});
|
|
645
647
|
```
|
|
646
648
|
|
|
647
649
|
### EF-29: Secrets must stay redacted
|
|
648
650
|
|
|
649
|
-
- Use `Config.
|
|
651
|
+
- Use `Config.Redacted` for secret config values.
|
|
650
652
|
- Use `Redacted.make` for sensitive values coming from non-config sources.
|
|
651
653
|
- Never log secret values after unwrapping.
|
|
652
|
-
- Reference: `Config.
|
|
654
|
+
- Reference: `Config.Redacted` in `packages/effect/src/Config.ts` and `packages/effect/src/Redacted.ts`.
|
|
653
655
|
|
|
654
656
|
Example:
|
|
655
657
|
|
|
@@ -657,7 +659,7 @@ Example:
|
|
|
657
659
|
import { Config, Effect } from 'effect';
|
|
658
660
|
|
|
659
661
|
const loadApiKey = Effect.fn('Config.loadApiKey')(function* () {
|
|
660
|
-
const apiKey = yield* Config.
|
|
662
|
+
const apiKey = yield* Config.Redacted('API_KEY');
|
|
661
663
|
yield* Effect.logDebug(`apiKey=${String(apiKey)}`);
|
|
662
664
|
return apiKey;
|
|
663
665
|
});
|
|
@@ -733,30 +735,6 @@ const runIsolated = program.pipe(
|
|
|
733
735
|
);
|
|
734
736
|
```
|
|
735
737
|
|
|
736
|
-
### EF-33: Schema-first development for domain models
|
|
737
|
-
|
|
738
|
-
- If a data shape is decoded from external input, will be discriminated via `instanceof`, or participates in a `Schema.Union`, define it as `Schema.Class` first — regardless of whether it is a "domain model" or an ephemeral HTTP response shape.
|
|
739
|
-
- Prefer `Schema.Class` (or another schema constructor) over plain `type` / `interface` for property-based domain shapes.
|
|
740
|
-
- Derive runtime types from schema definitions instead of duplicating parallel `type` / `interface` models.
|
|
741
|
-
- Keep plain `type` / `interface` for cases schema cannot represent cleanly (complex type-level transforms, utility types, overload-only surfaces).
|
|
742
|
-
|
|
743
|
-
Example:
|
|
744
|
-
|
|
745
|
-
```ts
|
|
746
|
-
import * as Schema from 'effect/Schema';
|
|
747
|
-
|
|
748
|
-
// Prefer schema-first over plain interfaces for domain payloads.
|
|
749
|
-
export class CreateOrderInput extends Schema.Class<CreateOrderInput>(
|
|
750
|
-
'CreateOrderInput'
|
|
751
|
-
)(
|
|
752
|
-
{
|
|
753
|
-
orderId: Schema.String,
|
|
754
|
-
customerId: Schema.String
|
|
755
|
-
},
|
|
756
|
-
{ description: 'Input payload for creating an order.' }
|
|
757
|
-
) {}
|
|
758
|
-
```
|
|
759
|
-
|
|
760
738
|
### EF-34: Schema defaults over fallback object logic
|
|
761
739
|
|
|
762
740
|
- Put defaults in schema definitions, not in handler/service fallback object literals.
|
|
@@ -764,6 +742,8 @@ export class CreateOrderInput extends Schema.Class<CreateOrderInput>(
|
|
|
764
742
|
- Use `Schema.withDecodingDefault` / `Schema.withDecodingDefaultKey` for decode-time defaults.
|
|
765
743
|
- Constructor defaults may fail with `SchemaIssue.Issue`. Likewise, `MySchema.makeEffect(fields)` returns validation failures directly as `SchemaIssue.Issue`, not wrapped in `Schema.SchemaError`.
|
|
766
744
|
- Constructor defaults (including `Schema.tag`) do not automatically apply during boundary decoding. Unknown input uses `Schema.decodeUnknownEffect`; `decodeSync` is not a constructor replacement.
|
|
745
|
+
- Class `make`, `makeOption`, and `makeEffect` preserve an existing instance. Use `new` when a distinct instance is intended.
|
|
746
|
+
- Pass parsing options to the decoder/encoder/constructor adapter. Model retained extra properties with `Record` or `StructWithRest`; use `onExcessProperty: "error"` for closed boundaries.
|
|
767
747
|
|
|
768
748
|
Example:
|
|
769
749
|
|
|
@@ -792,10 +772,10 @@ export class VersionSyncOptions extends Schema.Class<VersionSyncOptions>(
|
|
|
792
772
|
|
|
793
773
|
- If a guard validates domain strings/paths/tags, define a branded schema and use `Schema.is(...)`.
|
|
794
774
|
- If a domain constraint is named, reused, matched on, or structurally validated, model it as a schema first rather than a forest of ad-hoc predicate helpers.
|
|
795
|
-
- Prefer built-in schema constructors/checks before `Schema.makeFilter`.
|
|
775
|
+
- Prefer built-in schema constructors/checks such as `Schema.NonEmptyString`, `Schema.NonEmptyArray`, `Schema.TupleWithRest`, `Schema.Union`, `Schema.isPattern`, and `Schema.isIncludes` before `Schema.makeFilter`.
|
|
796
776
|
- Keep guard intent and reusable check intent in schema annotations and check metadata.
|
|
797
777
|
- For internal literal domains, use `Schema.is(Schema.Literal(...))` for type guards, `Match` for exhaustive matching, and `Schema.Literal(...).annotate({...})` for annotated schema values.
|
|
798
|
-
- Prefer named intermediate schemas; export them
|
|
778
|
+
- Prefer named intermediate schemas; export and document them when reusable or when they materially clarify the module's domain model, otherwise keep them module-local.
|
|
799
779
|
- Propagate branded schema types through the persistence layer (e.g., ORM column types: `text().$type<AccessToken>()`) to enforce compile-time safety across the entire stack and prevent parameter-swapping bugs.
|
|
800
780
|
|
|
801
781
|
Example:
|
|
@@ -925,6 +905,7 @@ const arraysEqual = (
|
|
|
925
905
|
|
|
926
906
|
- If conversion is deterministic and type-shaping (path normalization, filename conversion, tagged-string normalization), model it with `Schema.decodeTo(..., SchemaTransformation.transform(...))`.
|
|
927
907
|
- Prefer schema transformation helpers over ad-hoc conversion functions.
|
|
908
|
+
- Use `SchemaGetter.transformEffect` / `SchemaTransformation.transformEffect` for effectful conversion. Compose getters with standalone `SchemaGetter.compose`, and transformation pairs with `SchemaTransformation.composeTransformation`.
|
|
928
909
|
|
|
929
910
|
Example:
|
|
930
911
|
|
|
@@ -946,25 +927,6 @@ const NativePathToPosixPath = Schema.String.pipe(
|
|
|
946
927
|
);
|
|
947
928
|
```
|
|
948
929
|
|
|
949
|
-
### EF-38: Never use native array sort in Effect-first code
|
|
950
|
-
|
|
951
|
-
- Use `Arr.sort(values, order)` from `effect/Array`.
|
|
952
|
-
- Define ordering with `effect/Order` (`Order.String`, `Order.Number`, `Order.mapInput`, etc.).
|
|
953
|
-
- Do not call native `.sort()` directly on arrays.
|
|
954
|
-
|
|
955
|
-
Example:
|
|
956
|
-
|
|
957
|
-
```ts
|
|
958
|
-
import { Order } from 'effect';
|
|
959
|
-
import * as Arr from 'effect/Array';
|
|
960
|
-
|
|
961
|
-
const byName = Order.mapInput(
|
|
962
|
-
Order.String,
|
|
963
|
-
(item: { readonly name: string }) => item.name
|
|
964
|
-
);
|
|
965
|
-
const sorted = Arr.sort(items, byName);
|
|
966
|
-
```
|
|
967
|
-
|
|
968
930
|
### EF-39: Avoid ad-hoc `String(...)` coercion for domain comparisons
|
|
969
931
|
|
|
970
932
|
- When unknown/scalar data must normalize to domain strings, model the conversion with schema transformations.
|
|
@@ -994,7 +956,7 @@ const UnknownToString = Schema.Unknown.pipe(
|
|
|
994
956
|
- For invalidatable caches, use `Effect.cachedInvalidateWithTTL(effect, Duration.infinity)` which returns a `[cachedEffect, invalidate]` tuple. Call `yield* invalidate` to force re-computation on next access.
|
|
995
957
|
- For time-based caches, use `Effect.cachedWithTTL(effect, duration)`.
|
|
996
958
|
- Prefer `Effect.cachedInvalidateWithTTL` with `Duration.infinity` over mutable `let` rebinding of cached effects.
|
|
997
|
-
- For keyed scoped resources,
|
|
959
|
+
- For keyed scoped resources, use `RcMap.getOption` and `LayerMap.contextEffectOption` to atomically retain already-cached entries and propagate acquisition failures; `None` means missing/closed, not failed. A `has` check followed by `get` is not equivalent.
|
|
998
960
|
|
|
999
961
|
Example:
|
|
1000
962
|
|
|
@@ -1013,248 +975,3 @@ const [cachedConfig, invalidate] =
|
|
|
1013
975
|
);
|
|
1014
976
|
// Later: yield* invalidate to force reload on next access
|
|
1015
977
|
```
|
|
1016
|
-
|
|
1017
|
-
## Copy-Paste Templates
|
|
1018
|
-
|
|
1019
|
-
### Template: Tagged error
|
|
1020
|
-
|
|
1021
|
-
```ts
|
|
1022
|
-
import * as Schema from 'effect/Schema';
|
|
1023
|
-
|
|
1024
|
-
class DomainError extends Schema.TaggedError<DomainError>()(
|
|
1025
|
-
'DomainError',
|
|
1026
|
-
{
|
|
1027
|
-
message: Schema.String
|
|
1028
|
-
},
|
|
1029
|
-
{ description: 'Domain failure' }
|
|
1030
|
-
) {}
|
|
1031
|
-
```
|
|
1032
|
-
|
|
1033
|
-
### Template: Safe nullable boundary conversion
|
|
1034
|
-
|
|
1035
|
-
```ts
|
|
1036
|
-
import { pipe } from 'effect';
|
|
1037
|
-
import * as Option from 'effect/Option';
|
|
1038
|
-
|
|
1039
|
-
const fromNullableName = (name: string | null | undefined) =>
|
|
1040
|
-
pipe(
|
|
1041
|
-
Option.fromNullishOr(name),
|
|
1042
|
-
Option.filter((value) => value.length > 0)
|
|
1043
|
-
);
|
|
1044
|
-
```
|
|
1045
|
-
|
|
1046
|
-
### Template: Decode unknown at API edge
|
|
1047
|
-
|
|
1048
|
-
```ts
|
|
1049
|
-
import * as Schema from 'effect/Schema';
|
|
1050
|
-
|
|
1051
|
-
export class Payload extends Schema.Class<Payload>('Payload')({
|
|
1052
|
-
query: Schema.String
|
|
1053
|
-
}) {}
|
|
1054
|
-
|
|
1055
|
-
const decodePayload = Schema.decodeUnknownEffect(Payload);
|
|
1056
|
-
```
|
|
1057
|
-
|
|
1058
|
-
### Template: Schema naming + type alias (no `Schema` suffix)
|
|
1059
|
-
|
|
1060
|
-
```ts
|
|
1061
|
-
import * as Schema from 'effect/Schema';
|
|
1062
|
-
|
|
1063
|
-
export const OrderId = Schema.String;
|
|
1064
|
-
export type OrderId = typeof OrderId.Type;
|
|
1065
|
-
```
|
|
1066
|
-
|
|
1067
|
-
### Template: Schema-first replacement for interface
|
|
1068
|
-
|
|
1069
|
-
```ts
|
|
1070
|
-
import * as Schema from 'effect/Schema';
|
|
1071
|
-
|
|
1072
|
-
export class UserProfile extends Schema.Class<UserProfile>('UserProfile')(
|
|
1073
|
-
{
|
|
1074
|
-
id: Schema.String,
|
|
1075
|
-
displayName: Schema.String
|
|
1076
|
-
},
|
|
1077
|
-
{ description: 'User profile model used in domain workflows.' }
|
|
1078
|
-
) {}
|
|
1079
|
-
```
|
|
1080
|
-
|
|
1081
|
-
### Template: Match over switch
|
|
1082
|
-
|
|
1083
|
-
```ts
|
|
1084
|
-
import { Match } from 'effect';
|
|
1085
|
-
import * as Arr from 'effect/Array';
|
|
1086
|
-
|
|
1087
|
-
type Phase = 'draft' | 'running' | 'done';
|
|
1088
|
-
|
|
1089
|
-
const phaseLabel = (phase: Phase) =>
|
|
1090
|
-
Match.value(phase).pipe(
|
|
1091
|
-
Match.when('draft', () => 'draft'),
|
|
1092
|
-
Match.when('running', () => 'running'),
|
|
1093
|
-
Match.when('done', () => 'done'),
|
|
1094
|
-
Match.exhaustive
|
|
1095
|
-
);
|
|
1096
|
-
|
|
1097
|
-
const summarize = (items: ReadonlyArray<string>) =>
|
|
1098
|
-
Arr.match(items, {
|
|
1099
|
-
onEmpty: () => 'none',
|
|
1100
|
-
onNonEmpty: (values) => `count:${Arr.length(values)}`
|
|
1101
|
-
});
|
|
1102
|
-
```
|
|
1103
|
-
|
|
1104
|
-
### Template: Effect-returning function constructor
|
|
1105
|
-
|
|
1106
|
-
```ts
|
|
1107
|
-
import { Effect } from 'effect';
|
|
1108
|
-
|
|
1109
|
-
export const runTask = Effect.fn('Task.run')(function* (taskId: string) {
|
|
1110
|
-
yield* Effect.logInfo('run task', taskId);
|
|
1111
|
-
return taskId;
|
|
1112
|
-
});
|
|
1113
|
-
```
|
|
1114
|
-
|
|
1115
|
-
### Template: Option schema from nullish/optional
|
|
1116
|
-
|
|
1117
|
-
```ts
|
|
1118
|
-
import * as Schema from 'effect/Schema';
|
|
1119
|
-
|
|
1120
|
-
export class Input extends Schema.Class<Input>('Input')({
|
|
1121
|
-
maybeName: Schema.OptionFromNullishOr(Schema.String),
|
|
1122
|
-
maybeEmail: Schema.OptionFromOptionalKey(Schema.String)
|
|
1123
|
-
}) {}
|
|
1124
|
-
```
|
|
1125
|
-
|
|
1126
|
-
### Template: Dual helper (data-first + data-last)
|
|
1127
|
-
|
|
1128
|
-
```ts
|
|
1129
|
-
import { dual } from 'effect/Function';
|
|
1130
|
-
|
|
1131
|
-
export const rename: {
|
|
1132
|
-
(
|
|
1133
|
-
to: string
|
|
1134
|
-
): (self: { readonly name: string }) => { readonly name: string };
|
|
1135
|
-
(self: { readonly name: string }, to: string): { readonly name: string };
|
|
1136
|
-
} = dual(2, (self, to) => ({ ...self, name: to }));
|
|
1137
|
-
```
|
|
1138
|
-
|
|
1139
|
-
### Template: JSON boundary without native JSON APIs
|
|
1140
|
-
|
|
1141
|
-
```ts
|
|
1142
|
-
import * as Schema from 'effect/Schema';
|
|
1143
|
-
|
|
1144
|
-
export class Payload extends Schema.Class<Payload>('Payload')({
|
|
1145
|
-
query: Schema.String
|
|
1146
|
-
}) {}
|
|
1147
|
-
|
|
1148
|
-
const PayloadJson = Schema.fromJsonString(Payload);
|
|
1149
|
-
|
|
1150
|
-
export const decodePayloadJson = Schema.decodeUnknownEffect(PayloadJson);
|
|
1151
|
-
export const encodePayloadJson = Schema.encodeUnknownEffect(PayloadJson);
|
|
1152
|
-
```
|
|
1153
|
-
|
|
1154
|
-
### Template: Runtime boundary execution
|
|
1155
|
-
|
|
1156
|
-
```ts
|
|
1157
|
-
import { Effect } from 'effect';
|
|
1158
|
-
|
|
1159
|
-
export const buildReport = Effect.fn('Report.build')(function* () {
|
|
1160
|
-
return 'ok';
|
|
1161
|
-
});
|
|
1162
|
-
|
|
1163
|
-
// runtime boundary only
|
|
1164
|
-
// Effect.runPromise(buildReport())
|
|
1165
|
-
```
|
|
1166
|
-
|
|
1167
|
-
### Template: Scoped resource helper
|
|
1168
|
-
|
|
1169
|
-
```ts
|
|
1170
|
-
import { Effect } from 'effect';
|
|
1171
|
-
|
|
1172
|
-
export const withResource = <A, E, R>(
|
|
1173
|
-
use: (resource: Resource) => Effect.Effect<A, E, R>
|
|
1174
|
-
) => Effect.acquireUseRelease(acquireResource, use, releaseResource);
|
|
1175
|
-
```
|
|
1176
|
-
|
|
1177
|
-
### Template: Retry + timeout
|
|
1178
|
-
|
|
1179
|
-
```ts
|
|
1180
|
-
import { Duration, Effect, Schedule } from 'effect';
|
|
1181
|
-
|
|
1182
|
-
export const resilientTask = task.pipe(
|
|
1183
|
-
Effect.retry(Schedule.recurs(3)),
|
|
1184
|
-
Effect.timeoutOption(Duration.seconds(5))
|
|
1185
|
-
);
|
|
1186
|
-
```
|
|
1187
|
-
|
|
1188
|
-
### Template: Config + redacted secret
|
|
1189
|
-
|
|
1190
|
-
```ts
|
|
1191
|
-
import { Config, Effect } from 'effect';
|
|
1192
|
-
|
|
1193
|
-
export const loadConfig = Effect.fn('Config.load')(function* () {
|
|
1194
|
-
const port = yield* Config.int('PORT');
|
|
1195
|
-
const apiKey = yield* Config.redacted('API_KEY');
|
|
1196
|
-
return { port, apiKey };
|
|
1197
|
-
});
|
|
1198
|
-
```
|
|
1199
|
-
|
|
1200
|
-
### Template: Isolated layer provide
|
|
1201
|
-
|
|
1202
|
-
```ts
|
|
1203
|
-
import { Effect, Layer } from 'effect';
|
|
1204
|
-
|
|
1205
|
-
export const runIsolated = program.pipe(
|
|
1206
|
-
Effect.provide(Layer.fresh(AppLayer), { local: true })
|
|
1207
|
-
);
|
|
1208
|
-
```
|
|
1209
|
-
|
|
1210
|
-
## LLM Review Checklist
|
|
1211
|
-
|
|
1212
|
-
Use this before submitting code:
|
|
1213
|
-
|
|
1214
|
-
1. No `any`, no type assertions, no `@ts-ignore`, no non-null assertions.
|
|
1215
|
-
2. No untyped error throwing in domain logic.
|
|
1216
|
-
3. Nullish converted to `Option` at boundaries.
|
|
1217
|
-
4. Unknown input decoded with `Schema`.
|
|
1218
|
-
5. Canonical namespace imports (`Option`, `Schema`, `Arr`, `P`, `R`, etc.) present and used.
|
|
1219
|
-
6. No native `Object/Map/Set/Date/String` helpers in domain logic.
|
|
1220
|
-
7. Branching logic is exhaustive where appropriate (`Match.exhaustive`, schema `.match`, and `Arr.match` for array emptiness).
|
|
1221
|
-
8. No new schema constants end with `Schema`.
|
|
1222
|
-
9. For non-class schemas, new schema constants expose `export type X = typeof X.Type`.
|
|
1223
|
-
10. Schema annotations are used only where they materially improve docs, errors, or introspection.
|
|
1224
|
-
11. `Effect`-returning reusable functions are created with `Effect.fn`/`Effect.fnUntraced`.
|
|
1225
|
-
12. Critical flows include logs/spans/metrics instrumentation.
|
|
1226
|
-
13. Durations/time windows use `Duration` values.
|
|
1227
|
-
14. Nullish schema fields use `Schema.OptionFrom*` helpers when representing absence as `Option`.
|
|
1228
|
-
15. Exported helper combinators support dual API via `dual`.
|
|
1229
|
-
16. No `JSON.parse` / `JSON.stringify` in Effect-first domain paths.
|
|
1230
|
-
17. Prefer `Schema.Class` over `Schema.Struct` for all decoded shapes (domain models, HTTP responses, API payloads).
|
|
1231
|
-
18. Required verification commands are green.
|
|
1232
|
-
19. `Effect.run*` appears only in runtime boundaries (entrypoint/test harness).
|
|
1233
|
-
20. Promise-based APIs are lifted with `Effect.tryPromise`.
|
|
1234
|
-
21. Acquired resources use `Effect.acquireUseRelease` or `Effect.scoped`.
|
|
1235
|
-
22. Retries are declared with `Effect.retry` + `Schedule`.
|
|
1236
|
-
23. Timeouts use `Effect.timeoutOption` / `Effect.timeoutOrElse`.
|
|
1237
|
-
24. Forking intent is explicit (`forkChild` default; `forkDetach` justified).
|
|
1238
|
-
25. Large fan-out operations specify concurrency deliberately.
|
|
1239
|
-
26. Config values come from `Config` / `ConfigProvider`, not direct `process.env` in domain logic.
|
|
1240
|
-
27. Secrets are `Redacted` (`Config.redacted` / `Redacted.make`) and not logged raw.
|
|
1241
|
-
28. Recovery uses `catchTag` / `catchFilter` for targeted cases.
|
|
1242
|
-
29. Expected failures use `Effect.fail`; defects are reserved for invariants and discarding irrelevant upstream error types via `orDie`.
|
|
1243
|
-
30. Isolation-sensitive layer provisioning uses `{ local: true }` or `Layer.fresh`.
|
|
1244
|
-
31. All decoded shapes (domain models, HTTP responses, API payloads) are schema-first with `Schema.Class`; plain `type` / `interface` is used only when schema is not a practical fit.
|
|
1245
|
-
32. Literal-string discriminant unions use `Schema.Union` + `Schema.toTaggedUnion`. For exhaustive matching over literals, use `Match`. For type guards, use `Schema.is(Schema.Literal(...))`.
|
|
1246
|
-
33. Schema defaults use `Schema.withConstructorDefault` / `Schema.withDecodingDefault*`, not ad-hoc fallback objects in handlers/services.
|
|
1247
|
-
34. Named or reused domain constraints are modeled as schemas first; built-in schema constructors/checks are preferred before `Schema.makeFilter`.
|
|
1248
|
-
35. Guard helpers for domain strings/paths/tags come from branded schemas with `Schema.is(...)`, not ad-hoc `regex.test(...)` predicates.
|
|
1249
|
-
36. Reusable schema checks and filter groups carry `identifier`, `title`, and `description`.
|
|
1250
|
-
37. Intermediate schemas are exported only when reusable or materially clarifying; otherwise they stay module-local.
|
|
1251
|
-
38. Schema-modeled comparisons use `Schema.toEquivalence(...)` where practical.
|
|
1252
|
-
39. Deterministic format conversions use `Schema.decodeTo(..., SchemaTransformation.transform(...))`.
|
|
1253
|
-
40. Trivial helper wrapper lambdas are collapsed to direct helper refs where safe, and passthrough `pipe(...)` callbacks are expressed with `flow(...)`.
|
|
1254
|
-
41. Runtime source avoids `node:fs` / `node:path` / `node:child_process`; use Effect `FileSystem` / `Path` / process services.
|
|
1255
|
-
42. Runtime source avoids native `fetch`; HTTP boundaries use `effect/unstable/http` + platform layers (`BunHttpClient.layer`, etc.).
|
|
1256
|
-
43. Runtime sorting uses `Arr.sort` with explicit `Order`, not native `Array.prototype.sort`.
|
|
1257
|
-
44. Boolean branching prefers `Bool.match` over ad-hoc `if/else` when branching on booleans.
|
|
1258
|
-
45. HTTP request/response composition uses Effect HTTP modules (`HttpClientRequest`, `HttpClientResponse`, `Headers`, `UrlParams`, `HttpMethod`, `HttpBody`).
|
|
1259
|
-
46. Retried operations have proven idempotency, and exhausted failures remain visible unless a truthful fallback exists.
|
|
1260
|
-
47. Provider/network calls do not run inside authoritative database transactions.
|
|
@@ -1,35 +1,21 @@
|
|
|
1
1
|
# Agent Rules
|
|
2
2
|
|
|
3
|
-
The bundled guidance targets **Effect 4.0.0-rc.
|
|
3
|
+
The bundled guidance targets **Effect 4.0.0-rc.116**. Read the consuming project's
|
|
4
4
|
version before applying an API: stable v3, older prereleases, and unreleased main
|
|
5
5
|
can have different contracts. Keep directly used Effect-family packages on
|
|
6
6
|
compatible release versions.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Before planning or writing Effect code, load the skills relevant to the APIs involved.
|
|
9
|
+
For other tasks, load a skill only when its guidance is needed to answer or complete the task.
|
|
9
10
|
|
|
10
11
|
When skills leave any ambiguity, or when you encounter unfamiliar APIs during implementation, read the OpenCode `effect` reference at `~/.local/share/opencode/repos/github.com/Effect-TS/effect@main/`. Treat this reference as the source of truth over `node_modules`, stale external docs, or memory.
|
|
11
12
|
|
|
12
13
|
Check the reference revision too. For this baseline, inspect the
|
|
13
|
-
`effect@4.0.0-rc.
|
|
14
|
-
effect@4.0.0-rc.
|
|
14
|
+
`effect@4.0.0-rc.116` tag (for example with `git show
|
|
15
|
+
effect@4.0.0-rc.116:packages/effect/src/Schema.ts`) when main has moved ahead.
|
|
15
16
|
Source symbols and signatures at that tag take precedence over stale prose or
|
|
16
17
|
line-number links. Public exports marked `@internal` in source are not application APIs.
|
|
17
18
|
|
|
18
|
-
## Skill routing
|
|
19
|
-
|
|
20
|
-
Load every branch that the task crosses:
|
|
21
|
-
|
|
22
|
-
- Schemas, brands, variants, optionality, or decoding: `effect-schema-v4`, `effect-schema-composition`, and `effect-domain-modeling`.
|
|
23
|
-
- Binary schema codecs and framed binary streams: `effect-schema-composition` and `effect-stream`; RPC serialization also needs `effect-rpc-client` / `effect-rpc-server`.
|
|
24
|
-
- Services, layers, runtime wiring, or scoped lifetimes: `effect-service-implementation`, `effect-layer-design`, `effect-scope`, and `effect-fiber`.
|
|
25
|
-
- Configuration or secrets: `effect-config`.
|
|
26
|
-
- Retry, repeat, polling, backoff, pacing, or recurrence: `effect-scheduling` plus the relevant error, HTTP, or testing skill.
|
|
27
|
-
- Memoization, keyed caches, or request batching: `effect-cache` and `effect-batching`.
|
|
28
|
-
- Retained keyed resources or pooled checkout: `effect-cache`, `effect-layer-design`, and `effect-scope`.
|
|
29
|
-
- Streams, queues, pubsubs, pagination, or backpressure: `effect-stream` and the relevant concurrency skill.
|
|
30
|
-
- Outgoing HTTP: `effect-http-client` plus the relevant platform-layer skill.
|
|
31
|
-
- Effect tests, virtual time, or concurrent synchronization: `effect-testing` and `effect-concurrency-testing`.
|
|
32
|
-
|
|
33
19
|
## Start here
|
|
34
20
|
|
|
35
21
|
- `~/.local/share/opencode/repos/github.com/Effect-TS/effect@main/LLMS.md` — generated task-oriented guide for Effect v4, with links to examples.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-effect-enforcer",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.8",
|
|
5
5
|
"description": "OpenCode V2 plugin for Effect v4 skills, guidance, and pattern enforcement",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"opencode",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@ast-grep/napi": "^0.42.3",
|
|
47
47
|
"@opencode/plugin": "2.0.8",
|
|
48
48
|
"diff": "^9.0.0",
|
|
49
|
-
"effect": "4.0.0-rc.
|
|
49
|
+
"effect": "4.0.0-rc.116",
|
|
50
50
|
"picomatch": "^4.0.3",
|
|
51
51
|
"yaml": "^2.8.1"
|
|
52
52
|
},
|
|
@@ -55,6 +55,6 @@ TypeScript correctly narrows literal `_tag` checks. Prefer exported guards and
|
|
|
55
55
|
matching helpers for consistent semantics and exhaustiveness as variants evolve.
|
|
56
56
|
For schema-first models use union `.guards`, `.match`, or `Schema.is`; class
|
|
57
57
|
variants can also use `instanceof`. `Schema.toTaggedUnion` supports discriminator
|
|
58
|
-
keys beyond `_tag`.
|
|
58
|
+
keys beyond `_tag`. `.matchOrElse` provides partial matching with a typed
|
|
59
59
|
fallback. For trusted `Data.taggedEnum` values use `$is` / `$match`; `$is` checks
|
|
60
60
|
only the tag and is not structural validation of unknown input.
|