/SKILL.md
ALWAYS use this skill when writing ANY TypeScript code. All TypeScript in this project MUST use the Effect library. Use Effect for error handling (not try/catch), Effect.gen for async code (not async/await with Promises), Schema for validation (not zod/yup), Services and Layers for dependency injection, and Effect patterns for all business logic. This applies to any TypeScript file creation, modification, or code generation.
npx skillsauth add ivanacostarubio/effect-ts effect-tsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Effect is a powerful TypeScript library for building type-safe, composable, synchronous and asynchronous programs with:
For detailed patterns and examples, see:
Effect<Success, Error, Requirements>
Success (A) - The value produced on successError (E) - Expected errors that can occurRequirements (R) - Services/dependencies needed to runimport { Effect, pipe } from "effect"
import { Schema } from "effect"
import { Context, Layer } from "effect"
import { Option, Either } from "effect"
// Success values
const success = Effect.succeed(42)
const lazy = Effect.sync(() => computeValue())
// Failures
const fail = Effect.fail(new MyError())
const die = Effect.die("unexpected error")
// From promises
const fromPromise = Effect.tryPromise({
try: () => fetch(url),
catch: (e) => new FetchError(e)
})
// From sync that may throw
const fromSync = Effect.try({
try: () => JSON.parse(input),
catch: (e) => new ParseError(e)
})
// Async execution
await Effect.runPromise(effect)
await Effect.runPromiseExit(effect)
// Sync execution (only for sync effects)
Effect.runSync(effect)
// Fork as fiber
const fiber = Effect.runFork(effect)
const program = Effect.gen(function* () {
const a = yield* getUser(id)
const b = yield* getProfile(a.profileId)
return { user: a, profile: b }
})
const program = pipe(
getUser(id),
Effect.flatMap(user => getProfile(user.profileId)),
Effect.map(profile => profile.name)
)
// Or using .pipe() method
const program = getUser(id).pipe(
Effect.flatMap(user => getProfile(user.profileId)),
Effect.map(profile => profile.name)
)
// Catch specific error
effect.pipe(
Effect.catchTag("NotFound", (e) => Effect.succeed(defaultValue))
)
// Catch all errors
effect.pipe(
Effect.catchAll((e) => Effect.succeed(fallback))
)
// Map errors
effect.pipe(
Effect.mapError((e) => new WrappedError(e))
)
// Define service interface
class UserService extends Context.Tag("UserService")<
UserService,
{
readonly getUser: (id: string) => Effect.Effect<User, NotFoundError>
readonly saveUser: (user: User) => Effect.Effect<void, DatabaseError>
}
>() {}
// Use service
const program = Effect.gen(function* () {
const userService = yield* UserService
const user = yield* userService.getUser("123")
return user
})
// Implement as Layer
const UserServiceLive = Layer.succeed(UserService, {
getUser: (id) => Effect.succeed({ id, name: "John" }),
saveUser: (user) => Effect.succeed(undefined)
})
// Provide layer
Effect.runPromise(program.pipe(Effect.provide(UserServiceLive)))
import { Schema } from "effect"
// Define schema
const User = Schema.Struct({
id: Schema.String,
name: Schema.String,
age: Schema.Number.pipe(Schema.positive())
})
// Infer type
type User = Schema.Schema.Type<typeof User>
// Decode
const decode = Schema.decodeUnknown(User)
const result = decode({ id: "1", name: "John", age: 30 })
// Use in Effect
const parseUser = Schema.decodeUnknown(User)
const user = yield* parseUser(rawData)
// Run in parallel
const [a, b, c] = yield* Effect.all([effectA, effectB, effectC], {
concurrency: "unbounded"
})
// Race - first to complete wins
const result = yield* Effect.race(effectA, effectB)
// Timeout
const result = yield* effect.pipe(Effect.timeout("5 seconds"))
// Scoped resource
const file = Effect.acquireRelease(
Effect.sync(() => openFile(path)),
(file) => Effect.sync(() => file.close())
)
// Use with scoped
const program = Effect.scoped(
Effect.gen(function* () {
const f = yield* file
return yield* f.read()
})
)
For complete API documentation: https://tim-smart.github.io/effect-io-ai/
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.