effect-patterns-observability
Effect-TS patterns for Observability. Use when working with observability in Effect-TS applications.
Install
mkdir -p .claude/skills/effect-patterns-observability && curl -L -o skill.zip "https://mcp.directory/api/skills/download/2805" && unzip -o skill.zip -d .claude/skills/effect-patterns-observability && rm skill.zipInstalls to .claude/skills/effect-patterns-observability
About this skill
Effect-TS Patterns: Observability
This skill provides 13 curated Effect-TS patterns for observability. Use this skill when working on tasks related to:
- observability
- Best practices in Effect-TS applications
- Real-world patterns and solutions
🟢 Beginner Patterns
Debug Effect Programs
Rule: Use Effect.tap and logging to inspect values without changing program flow.
Good Example:
import { Effect, pipe } from "effect"
// ============================================
// 1. Using tap to inspect values
// ============================================
const fetchUser = (id: string) =>
Effect.succeed({ id, name: "Alice", email: "alice@example.com" })
const processUser = (id: string) =>
fetchUser(id).pipe(
// tap runs an effect for its side effect, then continues with original value
Effect.tap((user) => Effect.log(`Fetched user: ${user.name}`)),
Effect.map((user) => ({ ...user, processed: true })),
Effect.tap((user) => Effect.log(`Processed: ${JSON.stringify(user)}`))
)
// ============================================
// 2. Debug a pipeline
// ============================================
const numbers = [1, 2, 3, 4, 5]
const pipeline = Effect.gen(function* () {
yield* Effect.log("Starting pipeline")
const step1 = numbers.filter((n) => n % 2 === 0)
yield* Effect.log(`After filter (even): ${JSON.stringify(step1)}`)
const step2 = step1.map((n) => n * 10)
yield* Effect.log(`After map (*10): ${JSON.stringify(step2)}`)
const step3 = step2.reduce((a, b) => a + b, 0)
yield* Effect.log(`After reduce (sum): ${step3}`)
return step3
})
// ============================================
// 3. Debug errors
// ============================================
const riskyOperation = (shouldFail: boolean) =>
Effect.gen(function* () {
yield* Effect.log("Starting risky operation")
if (shouldFail) {
yield* Effect.log("About to fail...")
return yield* Effect.fail(new Error("Something went wrong"))
}
yield* Effect.log("Success!")
return "result"
})
const debugErrors = riskyOperation(true).pipe(
// Log when operation fails
Effect.tapError((error) => Effect.log(`Operation failed: ${error.message}`)),
// Provide a fallback
Effect.catchAll((error) => {
return Effect.succeed(`Recovered from: ${error.message}`)
})
)
// ============================================
// 4. Trace execution flow
// ============================================
const step = (name: string, value: number) =>
Effect.gen(function* () {
yield* Effect.log(`[${name}] Input: ${value}`)
const result = value * 2
yield* Effect.log(`[${name}] Output: ${result}`)
return result
})
const tracedWorkflow = Effect.gen(function* () {
const a = yield* step("Step 1", 5)
const b = yield* step("Step 2", a)
const c = yield* step("Step 3", b)
yield* Effect.log(`Final result: ${c}`)
return c
})
// ============================================
// 5. Quick debug with console
// ============================================
// Sometimes you just need console.log
const quickDebug = Effect.gen(function* () {
const value = yield* Effect.succeed(42)
// Effect.sync wraps side effects
yield* Effect.sync(() => console.log("Quick debug:", value))
return value
})
// ============================================
// 6. Run examples
// ============================================
const program = Effect.gen(function* () {
yield* Effect.log("=== Tap Example ===")
yield* processUser("123")
yield* Effect.log("\n=== Pipeline Debug ===")
yield* pipeline
yield* Effect.log("\n=== Error Debug ===")
yield* debugErrors
yield* Effect.log("\n=== Traced Workflow ===")
yield* tracedWorkflow
})
Effect.runPromise(program)
Rationale:
Use Effect.tap to inspect values and Effect.log to trace execution without changing program behavior.
Debugging Effect code differs from imperative code:
- No breakpoints - Effects are descriptions, not executions
- Lazy evaluation - Code runs later when you call
runPromise - Composition - Effects chain together
tap and logging let you see inside without breaking the chain.
Your First Logs
Rule: Use Effect.log and related functions for structured, contextual logging.
Good Example:
import { Effect, Logger, LogLevel } from "effect"
// ============================================
// 1. Basic logging
// ============================================
const basicLogging = Effect.gen(function* () {
// Different log levels
yield* Effect.logDebug("Debug message - for development")
yield* Effect.logInfo("Info message - normal operation")
yield* Effect.log("Default log - same as logInfo")
yield* Effect.logWarning("Warning - something unusual")
yield* Effect.logError("Error - something went wrong")
})
// ============================================
// 2. Logging with context
// ============================================
const withContext = Effect.gen(function* () {
// Add structured data to logs
yield* Effect.log("User logged in").pipe(
Effect.annotateLogs({
userId: "user-123",
action: "login",
ipAddress: "192.168.1.1",
})
)
// Add a single annotation
yield* Effect.log("Processing request").pipe(
Effect.annotateLogs("requestId", "req-456")
)
})
// ============================================
// 3. Log spans for timing
// ============================================
const withTiming = Effect.gen(function* () {
yield* Effect.log("Starting operation")
// withLogSpan adds timing information
yield* Effect.sleep("100 millis").pipe(
Effect.withLogSpan("database-query")
)
yield* Effect.log("Operation complete")
})
// ============================================
// 4. Practical example
// ============================================
interface User {
id: string
email: string
}
const processOrder = (orderId: string, userId: string) =>
Effect.gen(function* () {
yield* Effect.logInfo("Processing order").pipe(
Effect.annotateLogs({ orderId, userId })
)
// Simulate work
yield* Effect.sleep("50 millis")
yield* Effect.logInfo("Order processed successfully").pipe(
Effect.annotateLogs({ orderId, status: "completed" })
)
return { orderId, status: "completed" }
}).pipe(
Effect.withLogSpan("processOrder")
)
// ============================================
// 5. Configure log level
// ============================================
const debugProgram = basicLogging.pipe(
// Show all logs including debug
Logger.withMinimumLogLevel(LogLevel.Debug)
)
const productionProgram = basicLogging.pipe(
// Only show warnings and errors
Logger.withMinimumLogLevel(LogLevel.Warning)
)
// ============================================
// 6. Run
// ============================================
const program = Effect.gen(function* () {
yield* Effect.log("=== Basic Logging ===")
yield* basicLogging
yield* Effect.log("\n=== With Context ===")
yield* withContext
yield* Effect.log("\n=== With Timing ===")
yield* withTiming
yield* Effect.log("\n=== Process Order ===")
yield* processOrder("order-789", "user-123")
})
Effect.runPromise(program)
Rationale:
Use Effect's built-in logging functions for structured, contextual logging that works with any logging backend.
Effect's logging is superior to console.log:
- Structured - Logs are data, not just strings
- Contextual - Automatically includes fiber info, timestamps
- Configurable - Change log levels, formats, destinations
- Type-safe - Part of the Effect type system
🟡 Intermediate Patterns
Instrument and Observe Function Calls with Effect.fn
Rule: Use Effect.fn to wrap functions with effectful instrumentation, such as logging, metrics, or tracing, in a composable and type-safe way.
Good Example:
import { Effect } from "effect";
// A simple function to instrument
function add(a: number, b: number): number {
return a + b;
}
// Use Effect.fn to instrument the function with observability
const addWithLogging = Effect.fn("add")(add).pipe(
Effect.withSpan("add", { attributes: { "fn.name": "add" } })
);
// Use the instrumented function in an Effect workflow
const program = Effect.gen(function* () {
yield* Effect.logInfo("Calling add function");
const sum = yield* addWithLogging(2, 3);
yield* Effect.logInfo(`Sum is ${sum}`);
return sum;
});
// Run the program
Effect.runPromise(program);
Explanation:
Effect.fn("name")(fn)wraps a function with instrumentation capabilities, enabling observability.- You can add tracing spans, logging, metrics, and other observability logic to function boundaries.
- Keeps instrumentation separate from business logic and fully composable.
- The wrapped function integrates seamlessly with Effect's observability and tracing infrastructure.
Anti-Pattern:
Scattering logging, metrics, or tracing logic directly inside business functions, making code harder to test, maintain, and compose.
Rationale:
Use Effect.fn to wrap and instrument function calls with effectful logic, such as logging, metrics, or tracing.
This enables you to observe, monitor, and debug function boundaries in a composable, type-safe way.
Instrumenting function calls is essential for observability, especially in complex or critical code paths.
Effect.fn lets you add effectful logic (logging, metrics, tracing, etc.) before, after, or around any function call, without changing the function’s core logic.
Leverage Effect's Built-in Structured Logging
Rule: Use Effect.log, Effect.logInfo, and Effect.logError to add structured, context-aware logging to your Effect code.
Good Example:
import { Effect } from "effect";
// Log a simple message
const program = Effect.gen(function* () {
yield* Effect.log("Starting the ap
---
*Content truncated.*
More by PaulJPhilp
View all skills by PaulJPhilp →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversEffortlessly manage Google Cloud with this user-friendly multi cloud management platform—simplify operations, automate t
MCP server connects Claude and AI coding tools to shadcn/ui components. Accurate TypeScript props and React component da
Boost your AI code assistant with Context7: inject real-time API documentation from OpenAPI specification sources into y
By Sentry. MCP server and CLI that provides tools for AI agents working on iOS and macOS Xcode projects. Build, test, li
Cloudflare Observability offers advanced network monitoring software, delivering insights and trends for smarter network
Securely join MySQL databases with Read MySQL for read-only query access and in-depth data analysis.
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.