opencode-effect-enforcer 0.2.6 → 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.
@@ -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`.
@@ -504,6 +499,7 @@ You are not done if these fail:
504
499
 
505
500
  ### EF-21: Runtime execution stays at the boundary
506
501
 
502
+ - Runtime source uses Effect `FileSystem`, `Path`, and process services instead of `node:fs`, `node:path`, or `node:child_process`.
507
503
  - Application entrypoints and tests may execute effects with `Effect.run*`.
508
504
  - Library and domain exports should return `Effect` values.
509
505
  - Keep runtime execution in one place so wiring, logging, and lifecycle behavior stay auditable.
@@ -739,30 +735,6 @@ const runIsolated = program.pipe(
739
735
  );
740
736
  ```
741
737
 
742
- ### EF-33: Schema-first development for domain models
743
-
744
- - 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.
745
- - Prefer `Schema.Class` (or another schema constructor) over plain `type` / `interface` for property-based domain shapes.
746
- - Derive runtime types from schema definitions instead of duplicating parallel `type` / `interface` models.
747
- - Keep plain `type` / `interface` for cases schema cannot represent cleanly (complex type-level transforms, utility types, overload-only surfaces).
748
-
749
- Example:
750
-
751
- ```ts
752
- import * as Schema from 'effect/Schema';
753
-
754
- // Prefer schema-first over plain interfaces for domain payloads.
755
- export class CreateOrderInput extends Schema.Class<CreateOrderInput>(
756
- 'CreateOrderInput'
757
- )(
758
- {
759
- orderId: Schema.String,
760
- customerId: Schema.String
761
- },
762
- { description: 'Input payload for creating an order.' }
763
- ) {}
764
- ```
765
-
766
738
  ### EF-34: Schema defaults over fallback object logic
767
739
 
768
740
  - Put defaults in schema definitions, not in handler/service fallback object literals.
@@ -800,10 +772,10 @@ export class VersionSyncOptions extends Schema.Class<VersionSyncOptions>(
800
772
 
801
773
  - If a guard validates domain strings/paths/tags, define a branded schema and use `Schema.is(...)`.
802
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.
803
- - 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`.
804
776
  - Keep guard intent and reusable check intent in schema annotations and check metadata.
805
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.
806
- - Prefer named intermediate schemas; export them only when reusable or when they materially clarify the module's domain model.
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.
807
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.
808
780
 
809
781
  Example:
@@ -955,25 +927,6 @@ const NativePathToPosixPath = Schema.String.pipe(
955
927
  );
956
928
  ```
957
929
 
958
- ### EF-38: Never use native array sort in Effect-first code
959
-
960
- - Use `Arr.sort(values, order)` from `effect/Array`.
961
- - Define ordering with `effect/Order` (`Order.String`, `Order.Number`, `Order.mapInput`, etc.).
962
- - Do not call native `.sort()` directly on arrays.
963
-
964
- Example:
965
-
966
- ```ts
967
- import { Order } from 'effect';
968
- import * as Arr from 'effect/Array';
969
-
970
- const byName = Order.mapInput(
971
- Order.String,
972
- (item: { readonly name: string }) => item.name
973
- );
974
- const sorted = Arr.sort(items, byName);
975
- ```
976
-
977
930
  ### EF-39: Avoid ad-hoc `String(...)` coercion for domain comparisons
978
931
 
979
932
  - When unknown/scalar data must normalize to domain strings, model the conversion with schema transformations.
@@ -1022,248 +975,3 @@ const [cachedConfig, invalidate] =
1022
975
  );
1023
976
  // Later: yield* invalidate to force reload on next access
1024
977
  ```
1025
-
1026
- ## Copy-Paste Templates
1027
-
1028
- ### Template: Tagged error
1029
-
1030
- ```ts
1031
- import * as Schema from 'effect/Schema';
1032
-
1033
- class DomainError extends Schema.TaggedError<DomainError>()(
1034
- 'DomainError',
1035
- {
1036
- message: Schema.String
1037
- },
1038
- { description: 'Domain failure' }
1039
- ) {}
1040
- ```
1041
-
1042
- ### Template: Safe nullable boundary conversion
1043
-
1044
- ```ts
1045
- import { pipe } from 'effect';
1046
- import * as Option from 'effect/Option';
1047
-
1048
- const fromNullableName = (name: string | null | undefined) =>
1049
- pipe(
1050
- Option.fromNullishOr(name),
1051
- Option.filter((value) => value.length > 0)
1052
- );
1053
- ```
1054
-
1055
- ### Template: Decode unknown at API edge
1056
-
1057
- ```ts
1058
- import * as Schema from 'effect/Schema';
1059
-
1060
- export class Payload extends Schema.Class<Payload>('Payload')({
1061
- query: Schema.String
1062
- }) {}
1063
-
1064
- const decodePayload = Schema.decodeUnknownEffect(Payload);
1065
- ```
1066
-
1067
- ### Template: Schema naming + type alias (no `Schema` suffix)
1068
-
1069
- ```ts
1070
- import * as Schema from 'effect/Schema';
1071
-
1072
- export const OrderId = Schema.String;
1073
- export type OrderId = typeof OrderId.Type;
1074
- ```
1075
-
1076
- ### Template: Schema-first replacement for interface
1077
-
1078
- ```ts
1079
- import * as Schema from 'effect/Schema';
1080
-
1081
- export class UserProfile extends Schema.Class<UserProfile>('UserProfile')(
1082
- {
1083
- id: Schema.String,
1084
- displayName: Schema.String
1085
- },
1086
- { description: 'User profile model used in domain workflows.' }
1087
- ) {}
1088
- ```
1089
-
1090
- ### Template: Match over switch
1091
-
1092
- ```ts
1093
- import { Match } from 'effect';
1094
- import * as Arr from 'effect/Array';
1095
-
1096
- type Phase = 'draft' | 'running' | 'done';
1097
-
1098
- const phaseLabel = (phase: Phase) =>
1099
- Match.value(phase).pipe(
1100
- Match.when('draft', () => 'draft'),
1101
- Match.when('running', () => 'running'),
1102
- Match.when('done', () => 'done'),
1103
- Match.exhaustive
1104
- );
1105
-
1106
- const summarize = (items: ReadonlyArray<string>) =>
1107
- Arr.match(items, {
1108
- onEmpty: () => 'none',
1109
- onNonEmpty: (values) => `count:${Arr.length(values)}`
1110
- });
1111
- ```
1112
-
1113
- ### Template: Effect-returning function constructor
1114
-
1115
- ```ts
1116
- import { Effect } from 'effect';
1117
-
1118
- export const runTask = Effect.fn('Task.run')(function* (taskId: string) {
1119
- yield* Effect.logInfo('run task', taskId);
1120
- return taskId;
1121
- });
1122
- ```
1123
-
1124
- ### Template: Option schema from nullish/optional
1125
-
1126
- ```ts
1127
- import * as Schema from 'effect/Schema';
1128
-
1129
- export class Input extends Schema.Class<Input>('Input')({
1130
- maybeName: Schema.OptionFromNullishOr(Schema.String),
1131
- maybeEmail: Schema.OptionFromOptionalKey(Schema.String)
1132
- }) {}
1133
- ```
1134
-
1135
- ### Template: Dual helper (data-first + data-last)
1136
-
1137
- ```ts
1138
- import { dual } from 'effect/Function';
1139
-
1140
- export const rename: {
1141
- (
1142
- to: string
1143
- ): (self: { readonly name: string }) => { readonly name: string };
1144
- (self: { readonly name: string }, to: string): { readonly name: string };
1145
- } = dual(2, (self, to) => ({ ...self, name: to }));
1146
- ```
1147
-
1148
- ### Template: JSON boundary without native JSON APIs
1149
-
1150
- ```ts
1151
- import * as Schema from 'effect/Schema';
1152
-
1153
- export class Payload extends Schema.Class<Payload>('Payload')({
1154
- query: Schema.String
1155
- }) {}
1156
-
1157
- const PayloadJson = Schema.fromJsonString(Payload);
1158
-
1159
- export const decodePayloadJson = Schema.decodeUnknownEffect(PayloadJson);
1160
- export const encodePayloadJson = Schema.encodeUnknownEffect(PayloadJson);
1161
- ```
1162
-
1163
- ### Template: Runtime boundary execution
1164
-
1165
- ```ts
1166
- import { Effect } from 'effect';
1167
-
1168
- export const buildReport = Effect.fn('Report.build')(function* () {
1169
- return 'ok';
1170
- });
1171
-
1172
- // runtime boundary only
1173
- // Effect.runPromise(buildReport())
1174
- ```
1175
-
1176
- ### Template: Scoped resource helper
1177
-
1178
- ```ts
1179
- import { Effect } from 'effect';
1180
-
1181
- export const withResource = <A, E, R>(
1182
- use: (resource: Resource) => Effect.Effect<A, E, R>
1183
- ) => Effect.acquireUseRelease(acquireResource, use, releaseResource);
1184
- ```
1185
-
1186
- ### Template: Retry + timeout
1187
-
1188
- ```ts
1189
- import { Duration, Effect, Schedule } from 'effect';
1190
-
1191
- export const resilientTask = task.pipe(
1192
- Effect.retry(Schedule.recurs(3)),
1193
- Effect.timeoutOption(Duration.seconds(5))
1194
- );
1195
- ```
1196
-
1197
- ### Template: Config + redacted secret
1198
-
1199
- ```ts
1200
- import { Config, Effect } from 'effect';
1201
-
1202
- export const loadConfig = Effect.fn('Config.load')(function* () {
1203
- const port = yield* Config.Int('PORT');
1204
- const apiKey = yield* Config.Redacted('API_KEY');
1205
- return { port, apiKey };
1206
- });
1207
- ```
1208
-
1209
- ### Template: Isolated layer provide
1210
-
1211
- ```ts
1212
- import { Effect, Layer } from 'effect';
1213
-
1214
- export const runIsolated = program.pipe(
1215
- Effect.provide(Layer.fresh(AppLayer), { local: true })
1216
- );
1217
- ```
1218
-
1219
- ## LLM Review Checklist
1220
-
1221
- Use this before submitting code:
1222
-
1223
- 1. No `any`, no type assertions, no `@ts-ignore`, no non-null assertions.
1224
- 2. No untyped error throwing in domain logic.
1225
- 3. Nullish converted to `Option` at boundaries.
1226
- 4. Unknown input decoded with `Schema`.
1227
- 5. Canonical namespace imports (`Option`, `Schema`, `Arr`, `P`, `R`, etc.) present and used.
1228
- 6. No native `Object/Map/Set/Date/String` helpers in domain logic.
1229
- 7. Branching logic is exhaustive where appropriate (`Match.exhaustive`, schema `.match`, and `Arr.match` for array emptiness).
1230
- 8. No new schema constants end with `Schema`.
1231
- 9. For non-class schemas, new schema constants expose `export type X = typeof X.Type`.
1232
- 10. Schema annotations are used only where they materially improve docs, errors, or introspection.
1233
- 11. `Effect`-returning reusable functions are created with `Effect.fn`/`Effect.fnUntraced`.
1234
- 12. Critical flows include logs/spans/metrics instrumentation.
1235
- 13. Durations/time windows use `Duration` values.
1236
- 14. Nullish schema fields use `Schema.OptionFrom*` helpers when representing absence as `Option`.
1237
- 15. Exported helper combinators support dual API via `dual`.
1238
- 16. No `JSON.parse` / `JSON.stringify` in Effect-first domain paths.
1239
- 17. Prefer `Schema.Class` over `Schema.Struct` for all decoded shapes (domain models, HTTP responses, API payloads).
1240
- 18. Required verification commands are green.
1241
- 19. `Effect.run*` appears only in runtime boundaries (entrypoint/test harness).
1242
- 20. Promise-based APIs are lifted with `Effect.tryPromise`.
1243
- 21. Acquired resources use `Effect.acquireUseRelease` or `Effect.scoped`.
1244
- 22. Retries are declared with `Effect.retry` + `Schedule`.
1245
- 23. Timeouts use `Effect.timeoutOption` / `Effect.timeoutOrElse`.
1246
- 24. Forking intent is explicit (`forkChild` default; `forkDetach` justified).
1247
- 25. Large fan-out operations specify concurrency deliberately.
1248
- 26. Config values come from `Config` / `ConfigProvider`, not direct `process.env` in domain logic.
1249
- 27. Secrets are `Redacted` (`Config.Redacted` / `Redacted.make`) and not logged raw.
1250
- 28. Recovery uses `catchTag` / `catchFilter` for targeted cases.
1251
- 29. Expected failures use `Effect.fail`; defects are reserved for invariants and discarding irrelevant upstream error types via `orDie`.
1252
- 30. Isolation-sensitive layer provisioning uses `{ local: true }` or `Layer.fresh`.
1253
- 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.
1254
- 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(...))`.
1255
- 33. Schema defaults use `Schema.withConstructorDefault` / `Schema.withDecodingDefault*`, not ad-hoc fallback objects in handlers/services.
1256
- 34. Named or reused domain constraints are modeled as schemas first; built-in schema constructors/checks are preferred before `Schema.makeFilter`.
1257
- 35. Guard helpers for domain strings/paths/tags come from branded schemas with `Schema.is(...)`, not ad-hoc `regex.test(...)` predicates.
1258
- 36. Reusable schema checks and filter groups carry `identifier`, `title`, and `description`.
1259
- 37. Intermediate schemas are exported only when reusable or materially clarifying; otherwise they stay module-local.
1260
- 38. Schema-modeled comparisons use `Schema.toEquivalence(...)` where practical.
1261
- 39. Deterministic format conversions use `Schema.decodeTo(..., SchemaTransformation.transform(...))`.
1262
- 40. Trivial helper wrapper lambdas are collapsed to direct helper refs where safe, and passthrough `pipe(...)` callbacks are expressed with `flow(...)`.
1263
- 41. Runtime source avoids `node:fs` / `node:path` / `node:child_process`; use Effect `FileSystem` / `Path` / process services.
1264
- 42. Runtime source avoids native `fetch`; HTTP boundaries use `effect/unstable/http` + platform layers (`BunHttpClient.layer`, etc.).
1265
- 43. Runtime sorting uses `Arr.sort` with explicit `Order`, not native `Array.prototype.sort`.
1266
- 44. Boolean branching prefers `Bool.match` over ad-hoc `if/else` when branching on booleans.
1267
- 45. HTTP request/response composition uses Effect HTTP modules (`HttpClientRequest`, `HttpClientResponse`, `Headers`, `UrlParams`, `HttpMethod`, `HttpBody`).
1268
- 46. Retried operations have proven idempotency, and exhausted failures remain visible unless a truthful fallback exists.
1269
- 47. Provider/network calls do not run inside authoritative database transactions.
@@ -5,7 +5,8 @@ version before applying an API: stable v3, older prereleases, and unreleased mai
5
5
  can have different contracts. Keep directly used Effect-family packages on
6
6
  compatible release versions.
7
7
 
8
- Load all relevant skills before writing or planning any code. Effect is a massive ecosystem — without loading skills you will write outdated v3 code or miss high-leverage libraries. Load AT LEAST 4 `effect-*` skills before any Effect work.
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
 
@@ -15,21 +16,6 @@ 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.6",
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",
@@ -49,4 +49,4 @@ descending = Arr.sort (Order.reverse byName)
49
49
 
50
50
  Native `.sort()` mutates the array in place and uses an untyped comparator. `Arr.sort` from `effect/Array` returns a new sorted array using a composable, typed `Order`.
51
51
 
52
- References: EF-38 in effect-first-development.md
52
+ References: EF-5 in effect-first-development.md
@@ -51,4 +51,4 @@ extend = class Admin extends User.extend<Admin>("Admin")({
51
51
 
52
52
  `Schema.Struct` produces an anonymous schema without a constructor or `instanceof` support. `Schema.Class` provides a named type, constructor, extensibility, and optional annotation support when docs or introspection benefit from it. Prefer `Schema.Class` for decoded domain/API shapes, union members, and values that need identity. `Schema.Struct` remains appropriate for local structural composition, configuration internals, and schemas where class identity adds no value, so review this informational finding in context.
53
53
 
54
- References: EF-3, EF-33 in effect-first-development.md
54
+ References: EF-3 in effect-first-development.md
package/src/guidance.ts CHANGED
@@ -60,7 +60,6 @@ export const withPluginPolicy = (guidance: string): string =>
60
60
  [
61
61
  guidance,
62
62
  "OpenCode Effect Enforcer policy:",
63
- "- The bundled effect-* skills are available through OpenCode's skill tool. Load at least four relevant skills before planning or writing Effect code.",
64
63
  "- Treat post-write pattern feedback as an immediate review request. Fix valid findings before continuing.",
65
64
  "- Pattern findings are advisory: explain intentional exceptions or false positives instead of changing correct code."
66
65
  ].join("\n\n---\n\n")