Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/andabove-effect-schema
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, data, writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/effect-schema
What's inside
- Skill name
effect-schema- Description
- Effect 4 Schema for parsing and modelling data. Use when you decode untrusted input such as a request body, JSON, a form or a database row, define a domain model or a tagged error with Schema.Class or Schema.TaggedError, write a transformation between an encoded and a decoded form, format validation errors for users, or connect Schema to zod or another Standard Schema library.
- License
- MIT
- Instructions
- 196 lines in SKILL.md · view on GitHub
Files (5)
- SKILL.md
- effect-schema-building-blocks.md · references/
- effect-schema-errors.md · references/
- effect-schema-interop.md · references/
- effect-schema-transformations.md · references/
SKILL.md (first lines)
# Effect Schema
Checked against `effect 4.0.0`. When the project has a newer version, search `node_modules/effect/src/Schema.ts` (it is large: search for the name, read the match), `SchemaGetter.ts`, `SchemaTransformation.ts` and `SchemaIssue.ts`, and read `node_modules/effect/AGENTS.md`. The installed source wins over this skill.
Schema needs `"strict": true` in `tsconfig.json`. Turn on `"exactOptionalPropertyTypes": true` as well: without it, the type of a `Schema.optionalKey` field accepts `undefined`, which decoding still rejects.
## The model
A schema is a value that describes data in two forms: `Type`, the value your code uses, and `Encoded`, the value on the wire or on disk. Its full type is `Codec<Type, Encoded, DecodingServices, EncodingServices>`.
- Decoding turns `Encoded` (or `unknown`) into `Type` and validates it. Encoding turns `Type` back into `Encoded`.
- Read the types with `typeof S.Type` and `typeof S.Encoded`.
- A name `XFromY` decodes `Y` into `X`: `Schema.FiniteFromString` has `Type` `number` and `Encoded` `string`.
- Parse every value from outside the process with a schema at the boundary, and use `Schema` for all validation. Hand-written type guards drift from the types they guard.
## Decode untrusted input
```ts
import * as Effect from "effect/Effect"
import * as Schema from "effect/Schema"
export const CreateOrder = Schema.Struct({
sku: Schema.NonEmptyString,
quantity: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })),
note: Schema.optionalKey(Schema.String)
})
export type CreateOrder = typeof CreateOrder.Type
export class InvalidOrder extends Schema.TaggedError<InvalidOrder>()("InvalidOrder", {
message: Schema.String
}) {}
const decodeCreateOrder = Schema.decodeUnknownEffect(CreateOrder)
export const parseOrder = (body: unknown): Effect.Effect<CreateOrder, InvalidOrder> =>
decodeCreateOrder(body, { errors: "all" }).pipe(
Effect.mapError((error) => new InvalidOrder({ message: error.message }))
)
```
Pick the decoder by where the code runs:
| Situation | Decoder | On invalid input |
| --- | --- | --- |
| inside Effect code | `Schema.decodeUnknownEffect(S)` | fails with `SchemaError` |
| plain code that branches on the outcome | `Schema.decodeUnknownResult(S)` | returns a `Result` failure holding a `SchemaError` |
| plain code where invalid input is a bug | `Schema.decodeUnknownSync(S)` | throws `SchemaError` |
| plain code with async transformations | `Schema.decodeUnknownPromise(S)` | rejects with `SchemaError` |
| a yes or no answer | `Schema.is(S)` | returns `false` |
- `decodeUnknown*` accepts `unknown`. `decode*` accepts a value already typed as `Encoded`. The `encode*` family mirrors both.
- Build each decoder once, at module scope. Options go to the factory or to each call: `Schema.decodeUnknownEffect(S, { errors: "all" })` or `decode(input, { errors: "all" })`.
- Unknown keys are dropped without an error. Pass `{ onExcessProperty: "error" }` to reject them. The option takes only `"ignore"` (the default) and `"error"`.
- Only the first issue is reported. Pass `{ errors: "all" }` for forms and API error bodies.
- The Sync, Result and Option decoders cannot run an asynchronous transformation. They throw a plain `Error`, not a `SchemaError`, and `decodeUnknownExit` returns a defect. Decode such schemas with the Effect or Promise decoder.
- Parse JSON text with `Schema.fromJsonString(S)`. Invalid JSON fails with `Expected a valid JSON string`.
- Catch the error with `Effect.catchTag("SchemaError", ...)`. Map it to a domain error at the boundary, as `parseOrder` does.
- `Schema.Finite` rejects `NaN` and `Infinity`; `Schema.Number` accepts them. Prefer `Finite` or `Int` for input.
- `Schema.optional(S)` accepts an absent key or `undefined`. `Schema.optionalKey(S)` accepts an absent key but rejects `undefined`.
Primitives, filters, unions, records and recursion: [references/effect-schema-building-blocks.md](references/effect-schema-building-blocks.md).
## Encode for the wire
Before you send or store a decoded value, encode it with the same schema: `Schema.encodeEffect(S)(value)` inside Effect, `Schema.encodeSync(S)(value)` outside. Encoding produces the `Encoded` form: a `Date` from `DateFromString` becomes an ISO string, a class instance becomes a plain object, an `Option` from `OptionFromNullOr` becomes `null` or the value. `JSON.stringify` on the decoded value skips this and emits the wrong shape.
## Schema.Class: a domain model
```ts
import * as Equal from "effect/Equal"
import * as Schema from "effect/Schema"
export class Customer extends Schema.Class<Customer>("myapp/Customer")({
id: Schema.String,
email: Schema.String.check(Schema.isPattern(/^[^@]+@[^@]+$/)),
joinedAt: Schema.DateFromString
}) {
get domain(): string {
return this.email.split("@")[1] ?? ""
}
}
const customer = Schema.decodeUnknownSync(Customer)({ id: "c1", email: "ada@example.com", joinedAt: "2026-01-01T00:00:00.000Z" })
customer.domain // "example.com"
Schema.encodeSync(Customer)(customer) // { id: "c1", email: "ada@example.com", joinedAt: "2026-01-01T00:00:00.000Z" }
Equal.equals(customer, new Customer({ ...customer })) // true
```
- Decoding returns an instance of the class. Encoding returns a plain object in the `Encoded` form.
- The string identifier names the schema in error messages and JSON Schema, and recognizes instances across hot module reloads. Make it unique.
- `new Customer({ ... })` and `Customer.make({ ... })` validate and throw an `Error` whose message is `Schema validation failed`; the issue is on `error.cause`. For input that can be invalid, decode it, or call `Customer.makeOption`, which returns an `Option`.
- The `Type` side is the class: `Schema.is(Customer)` returns `false` for a plain object with the same fields.
- Instances compare by value with `Equal.equals`.
- `Customer.extend<Vip>("myapp/Vip")({ tier: Schema.Int })` adds fields and keeps the methods. `Schema.TaggedClass<Self>()("Tag", fields)` adds a `_tag` field.
- Use `Schema.Class` when the value needs methods, `instanceof` or a nominal type. Use `Schema.Struct` for plain data such as request bodies.
## Schema.TaggedError: a typed, serializable error
```ts
import * as Effect from "effect/Effect"
import * as Schema from "effect/Schema"
export class PaymentDeclined extends Schema.TaggedError<PaymentDeclined>()("PaymentDeclined", {
orderId: Schema.String,
reason: Schema.Literals(["insufficient_funds", "card_expired"])
}) {}
export const charge = Effect.fn("charge")(function* (orderId: string): Effect.fn.Return<string, PaymentDeclined> {
if (orderId.startsWith("x")) return yield* new PaymentDeclined({ orderId, reason: "card_expired" })
return `receipt-${orderId}`
})
export const handled = charge("x1").pipe(
Effect.catchTag("PaymentDeclined", (e) => Effect.succeed(`declined: ${e.reason}`))
)
```
- Write `return yield* new PaymentDeclined({ ... })` inside the generator. The `return` tells TypeScript the branch ends.
- An instance is an `Error` with a stack. Its `name` is the tag. Its `message` is empty unless you declare a `message` field.From andabove/skills, MIT.
More from andabove/skills
- 0.570score
effect-testing
andabove
Testing Effect code with @effect/vitest, TestClock and test layers.
SkillAFreshness: AClaude Code +9 - 0.570score
effect
andabove
Effect (the TypeScript library) core and router to the other Effect skills.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-adoption
andabove
Adopting Effect in an existing Promise codebase one module at a time.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-concurrency
andabove
Effect concurrency - fibers, interruption, coordination and Schedule.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-data
andabove
Effect 4 data types, equality, caching and batching.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-errors
andabove
Effect error handling, for expected errors, defects and interruptions.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-observability
andabove
Effect 4 logging, tracing and metrics, and their export.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-services
andabove
Effect 4 services, layers and resources.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-streams
andabove
Effect Stream, Sink and Channel.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-v3-to-v4
andabove
Effect v3 to v4 migration.
SkillAFreshness: AClaude Code +9 - 0.565score
linear-comment
andabove
Write a comment on a Linear issue as a status record against its acceptance criteria and QA notes.
SkillAFreshness: AClaude Code +9 - 0.565score
code-style
andabove
Fifteen TypeScript code rules for modules, names, doc comments, types, boundaries, errors and side effects.
SkillAFreshness: AClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Oct 3, 2026 (26 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/andabove/skills
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from andabove
- 0.570score
effect-data
andabove
Effect 4 data types, equality, caching and batching.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-concurrency
andabove
Effect concurrency - fibers, interruption, coordination and Schedule.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-testing
andabove
Testing Effect code with @effect/vitest, TestClock and test layers.
SkillAFreshness: AClaude Code +9 - 0.570score
effect
andabove
Effect (the TypeScript library) core and router to the other Effect skills.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-adoption
andabove
Adopting Effect in an existing Promise codebase one module at a time.
SkillAFreshness: AClaude Code +9 - 0.570score
effect-errors
andabove
Effect error handling, for expected errors, defects and interruptions.
SkillAFreshness: AClaude Code +9
Cite this page
effect-schema skill. Agent Mart. https://agentmart.dev/skills/andabove-effect-schema (last updated 2026-10-24)