effect-dependency-injection
Use when Effect dependency injection patterns including Context, Layer, service definitions, and dependency composition. Use for managing dependencies in Effect applications.
What this skill does
# Effect Dependency Injection
Master dependency injection and management in Effect applications using Context
and Layers. This skill covers service definitions, layer construction, and
composing complex dependency graphs.
## Context and Services
### Defining Services with Context.Tag
Services are defined using Context.Tag to create type-safe identifiers:
```typescript
import { Context, Effect } from "effect"
// Define service interface
interface UserService {
getUser: (id: string) => Effect.Effect<User, UserNotFound, never>
createUser: (data: UserData) => Effect.Effect<User, ValidationError, never>
}
// Create service tag
const UserService = Context.GenericTag<UserService>("UserService")
// Using the service
const program = Effect.gen(function* () {
const userService = yield* UserService
const user = yield* userService.getUser("123")
return user
})
// Effect<User, UserNotFound, UserService>
```
### Multiple Services
```typescript
import { Context, Effect } from "effect"
interface Logger {
info: (message: string) => Effect.Effect<void, never, never>
error: (message: string) => Effect.Effect<void, never, never>
}
interface Database {
query: <T>(sql: string) => Effect.Effect<T, DbError, never>
}
const Logger = Context.GenericTag<Logger>("Logger")
const Database = Context.GenericTag<Database>("Database")
// Using multiple services
const program = Effect.gen(function* () {
const logger = yield* Logger
const db = yield* Database
yield* logger.info("Querying database...")
const users = yield* db.query<User[]>("SELECT * FROM users")
yield* logger.info(`Found ${users.length} users`)
return users
})
// Effect<User[], DbError, Logger | Database>
```
## Creating Layers
Layers are blueprints for constructing services.
### Layer.succeed - Simple Service Implementation
```typescript
import { Context, Effect, Layer } from "effect"
interface Config {
apiUrl: string
timeout: number
}
const Config = Context.GenericTag<Config>("Config")
// Create a layer with a fixed value
const ConfigLive = Layer.succeed(
Config,
{
apiUrl: "https://api.example.com",
timeout: 5000
}
)
```
### Layer.effect - Service with Dependencies
Create a service that depends on other services:
```typescript
import { Context, Effect, Layer } from "effect"
interface HttpClient {
get: (url: string) => Effect.Effect<Response, NetworkError, never>
post: (url: string, body: unknown) => Effect.Effect<Response, NetworkError, never>
}
const HttpClient = Context.GenericTag<HttpClient>("HttpClient")
// HttpClient depends on Config and Logger
const HttpClientLive = Layer.effect(
HttpClient,
Effect.gen(function* () {
const config = yield* Config
const logger = yield* Logger
return {
get: (url: string) =>
Effect.gen(function* () {
yield* logger.info(`GET ${url}`)
const response = yield* Effect.tryPromise({
try: () => fetch(`${config.apiUrl}${url}`, {
timeout: config.timeout
}),
catch: (error) => ({
_tag: "NetworkError",
message: String(error)
})
})
return response
}),
post: (url: string, body: unknown) =>
Effect.gen(function* () {
yield* logger.info(`POST ${url}`)
const response = yield* Effect.tryPromise({
try: () => fetch(`${config.apiUrl}${url}`, {
method: "POST",
body: JSON.stringify(body),
timeout: config.timeout
}),
catch: (error) => ({
_tag: "NetworkError",
message: String(error)
})
})
return response
})
}
})
)
// Layer<HttpClient, never, Config | Logger>
```
### Layer.scoped - Resources with Cleanup
For services that need cleanup:
```typescript
import { Context, Effect, Layer } from "effect"
interface DatabaseConnection {
query: <T>(sql: string) => Effect.Effect<T, DbError, never>
}
const DatabaseConnection = Context.GenericTag<DatabaseConnection>("DatabaseConnection")
const DatabaseConnectionLive = Layer.scoped(
DatabaseConnection,
Effect.gen(function* () {
const config = yield* Config
// Acquire connection
const connection = yield* Effect.tryPromise({
try: () => createConnection(config.dbUrl),
catch: (error) => ({
_tag: "ConnectionError",
message: String(error)
})
})
// Register cleanup
yield* Effect.addFinalizer(() =>
Effect.sync(() => {
console.log("Closing database connection")
connection.close()
})
)
return {
query: <T>(sql: string) =>
Effect.tryPromise({
try: () => connection.query<T>(sql),
catch: (error) => ({
_tag: "DbError",
message: String(error)
})
})
}
})
)
```
## Providing Layers
### Effect.provide - Provide Single Layer
```typescript
import { Effect, Layer } from "effect"
const program = Effect.gen(function* () {
const config = yield* Config
return config.apiUrl
})
// Effect<string, never, Config>
// Provide the Config layer
const runnable = program.pipe(
Effect.provide(ConfigLive)
)
// Effect<string, never, never>
// Now can run without dependencies
const result = await Effect.runPromise(runnable)
```
### Effect.provideService - Provide Service Directly
For testing or simple cases:
```typescript
import { Effect } from "effect"
const testConfig: Config = {
apiUrl: "http://localhost:3000",
timeout: 1000
}
const program = Effect.gen(function* () {
const config = yield* Config
return config.apiUrl
})
const runnable = program.pipe(
Effect.provideService(Config, testConfig)
)
```
## Composing Layers
### Layer.provide - Layer Dependencies
Provide dependencies to a layer:
```typescript
import { Layer } from "effect"
// UserServiceLive needs HttpClient
// HttpClient needs Config and Logger
const UserServiceLive = Layer.effect(
UserService,
Effect.gen(function* () {
const http = yield* HttpClient
return {
getUser: (id: string) =>
Effect.gen(function* () {
const response = yield* http.get(`/users/${id}`)
const user = yield* Effect.tryPromise({
try: () => response.json(),
catch: () => ({ _tag: "ParseError" })
})
return user
})
}
})
)
// Provide HttpClient to UserService
const UserServiceWithDeps = UserServiceLive.pipe(
Layer.provide(HttpClientLive)
)
// Layer<UserService, never, Config | Logger>
```
### Layer.merge - Combine Layers
Merge multiple independent layers:
```typescript
import { Layer } from "effect"
// Combine Config and Logger
const AppConfigLayer = Layer.merge(
ConfigLive,
LoggerLive
)
// Layer<Config | Logger, never, never>
// Use merged layer
const program = Effect.gen(function* () {
const config = yield* Config
const logger = yield* Logger
yield* logger.info(`API URL: ${config.apiUrl}`)
})
const runnable = program.pipe(
Effect.provide(AppConfigLayer)
)
```
### Layer Pipelines
Build complex dependency graphs:
```typescript
import { Layer, Effect } from "effect"
// Build dependency graph
const AppLayer = Layer.merge(
ConfigLive,
LoggerLive
).pipe(
Layer.provideMerge(HttpClientLive),
Layer.provideMerge(DatabaseConnectionLive),
Layer.provideMerge(UserServiceLive)
)
// All services now available
const program = Effect.gen(function* () {
const userService = yield* UserService
const logger = yield* Logger
yield* logger.info("Fetching user...")
const user = yield* userService.getUser("123")
yield* logger.info(`User: ${user.name}`)
return user
})
const runnable = program.pipe(
Effect.provide(AppLayer)
)
```
## Service Patterns
### Repository Pattern
```typescript
import { Context, Effect, Layer } from "effect"
interface UserRepository {
findById: (id: string) => Effect.Effect<Option<URelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.