smithery.ai

layer-design

Design and compose Effect layers for clean dependency management

First seen Apr 17, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,172 B
  • docs SUMMARY.md 84 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 2 installs

SKILL.md

Layer Design Skill

Create layers that construct services while managing their dependencies cleanly.

Layer Structure

Layer<RequirementsOut, Error, RequirementsIn>
         ▲                ▲           ▲
         │                │           └─ What this layer needs
         │                └─ Errors during construction
         └─ What this layer produces

Pattern: Simple Layer (No Dependencies)

export class Config extends Context.Tag("Config")<
  Config,
  {
    readonly getConfig: Effect.Effect<ConfigData>
  }
>() {}

// Layer<Config, never, never>
//         ▲      ▲      ▲
//         │      │      └─ No dependencies
//         │      └─ Cannot fail
//         └─ Produces Config
export const ConfigLive = Layer.succeed(
  Config,
  Config.of({
    getConfig: Effect.succeed({
      logLevel: "INFO",
      connection: "mysql://localhost/db"
    })
  })
)

Pattern: Layer with Dependencies

export class Logger extends Context.Tag("Logger")<
  Logger,
  { readonly log: (message: string) => Effect.Effect<void> }
>() {}

// Layer<Logger, never, Config>
//         ▲      ▲      ▲
//         │      │      └─ Needs Config
//         │      └─ Cannot fail
//         └─ Produces Logger
export const LoggerLive = Layer.effect(
  Logger,
  Effect.gen(function* () {
    const config = yield* Config  // Access dependency
    return Logger.of({
      log: (message) =>
        Effect.gen(function* () {
          const { logLevel } = yield* config.getConfig
          console.log(`[${logLevel}] ${message}`)
        })
    })
  })
)

Pattern: Layer with Resource Management

Use Layer.scoped for resources that need cleanup:

// Layer<Database, DatabaseError, Config>
export const DatabaseLive = Layer.scoped(
  Database,
  Effect.gen(function* () {
    const config = yield* Config

    // Acquire resource with automatic release
    const connection = yield* Effect.acquireRelease(
      connectToDatabase(config),
      (conn) => Effect.sync(() => conn.close())  // Cleanup
    )

    return Database.of({
      query: (sql) => executeQuery(connection, sql)
    })
  })
)

Composing Layers: Merge vs Provide

Merge (Parallel Composition)

Combine independent layers:

// Layer<Config | Logger, never, Config>
//         ▲               ▲      ▲
//         │               │      └─ LoggerLive needs Config
//         │               └─ No errors
//         └─ Produces both Config and Logger
const AppConfigLive = Layer.merge(ConfigLive, LoggerLive)

Result combines:

  • Requirements: Union (never | Config = Config)
  • Outputs: Union (Config | Logger)

Provide (Sequential Composition)

Chain dependent layers:

// Layer<Logger, never, never>
//         ▲      ▲      ▲
//         │      │      └─ ConfigLive satisfies LoggerLive's requirement
//         │      └─ No errors
//         └─ Only Logger in output
const FullLoggerLive = Layer.provide(LoggerLive, ConfigLive)

Result:

  • Requirements: Outer layer's requirements (never)
  • Output: Inner layer's output (Logger)

Pattern: Layered Architecture

Build applications in layers:

// Infrastructure: No dependencies
const InfrastructureLive = Layer.mergeAll(
  ConfigLive,          // Layer<Config, never, never>
  DatabaseLive,        // Layer<Database, never, Config>
  CacheLive            // Layer<Cache, never, Config>
).pipe(
  Layer.provide(ConfigLive)  // Satisfy Config requirement
)

// Domain: Depends on infrastructure
const DomainLive = Layer.mergeAll(
  PaymentDomainLive,   // Layer<PaymentDomain, never, Database>
  OrderDomainLive,     // Layer<OrderDomain, never, Database>
).pipe(
  Layer.provide(InfrastructureLive)
)

// Application: Depends on domain
const ApplicationLive = Layer.mergeAll(
  PaymentGatewayLive,
  NotificationServiceLive
).pipe(
  Layer.provide(DomainLive)
)

Pattern: Multiple Implementations

Switch implementations for different environments:

// Production
export const DatabaseLive = Layer.scoped(
  Database,
  Effect.gen(function* () {
    const connection = yield* connectToProduction()
    return createDatabaseService(connection)
  })
)

// Test
export const DatabaseTest = Layer.succeed(
  Database,
  Database.of({
    query: () => Effect.succeed({ rows: [] })
  })
)

// Use in application
const program = myProgram.pipe(
  Effect.provide(process.env.NODE_ENV === "test" ? DatabaseTest : DatabaseLive)
)

Pattern: Layer Sharing

Layers are memoized - same instance shared across program:

// Config is constructed once and shared
const program = Effect.all([
  Effect.gen(function* () {
    const config = yield* Config
    // Uses shared instance
  }),
  Effect.gen(function* () {
    const config = yield* Config
    // Same instance
  })
]).pipe(Effect.provide(ConfigLive))

Error Handling in Layers

Handle construction errors:

export const DatabaseLive = Layer.effect(
  Database,
  Effect.gen(function* () {
    const connection = yield* connectToDatabase().pipe(
      Effect.catchTag("ConnectionError", (error) =>
        Effect.fail(new DatabaseConstructionError({ cause: error }))
      )
    )
    return createDatabaseService(connection)
  })
)

Naming Convention

  • *Live - Production implementation
  • *Test - Test implementation
  • *Mock - Mock for testing
  • Descriptive names for specialized implementations

Quality Checklist

  • Layer type accurately reflects dependencies
  • Resource cleanup using acquireRelease if needed
  • Layer can be tested with mock dependencies
  • No dependency leakage into service interface
  • Appropriate use of merge vs provide
  • Error handling for construction failures
  • JSDoc with example usage

Layers should make dependency management explicit while keeping service interfaces clean and focused.