Help us improve
Share bugs, ideas, or general feedback.
From effect-ts
Guides Effect Config usage for type-safe app configuration from env vars, JSON, with validation, defaults, nesting, optional values, and sensitive data redaction.
npx claudepluginhub andrueandersoncs/claude-skill-effect-ts --plugin effect-tsHow this skill is triggered — by the user, by Claude, or both
Slash command
/effect-ts:configurationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Effect provides type-safe configuration loading with:
Provides expert guidance on Effect-TS patterns including services, layers, error handling, service composition, and refactoring code with 'effect' imports. Covers Effect + Next.js integration.
Defines and composes dependencies in Effect TypeScript apps using Context tags, Layers, service definitions, and dependency graphs for type-safe programs.
Sets up Python configuration management with environment variables and pydantic-settings for typed validation, secrets handling, and environment-specific settings.
Share bugs, ideas, or general feedback.
Effect provides type-safe configuration loading with:
import { Config, Effect } from "effect";
const host = Config.string("HOST");
const port = Config.number("PORT");
const debug = Config.boolean("DEBUG");
const maxConnections = Config.integer("MAX_CONNECTIONS");
const program = Effect.gen(function* () {
const host = yield* Config.string("DATABASE_HOST");
const port = yield* Config.number("DATABASE_PORT");
return { host, port };
});
// Runs and reads from environment
await Effect.runPromise(program);
const port = Config.number("PORT").pipe(Config.withDefault(3000));
const debug = Config.boolean("DEBUG").pipe(Config.withDefault(false));
const apiKey = Config.string("API_KEY").pipe(Config.option);
// Type: Effect<Option<string>>
const dbConfig = Config.all({
host: Config.string("DB_HOST"),
port: Config.number("DB_PORT"),
database: Config.string("DB_NAME"),
maxConnections: Config.number("DB_MAX_CONN").pipe(Config.withDefault(10)),
});
const program = Effect.gen(function* () {
const config = yield* dbConfig;
// config: { host: string, port: number, database: string, maxConnections: number }
});
const dbConfig = Config.nested("DB")(
Config.all({
host: Config.string("HOST"), // Reads DB_HOST
port: Config.number("PORT"), // Reads DB_PORT
name: Config.string("NAME"), // Reads DB_NAME
}),
);
Use Effect Schema for complex validation:
import { Config, Schema } from "effect";
const PortSchema = Schema.Number.pipe(Schema.int(), Schema.between(1, 65535));
const port = Config.number("PORT").pipe(
Config.mapOrFail((n) =>
Schema.decodeUnknownEither(PortSchema)(n).pipe(
Either.mapLeft((e) => ConfigError.InvalidData([], `Invalid port: ${n}`)),
),
),
);
Prevents accidental logging of sensitive values:
const apiKey = Config.redacted("API_KEY");
// Type: Effect<Redacted<string>>
const program = Effect.gen(function* () {
const key = yield* apiKey;
// Safe to log - shows "<redacted>"
yield* Effect.log(`Key: ${key}`);
// Get actual value when needed
const actual = Redacted.value(key);
});
const dbPassword = Config.secret("DB_PASSWORD");
// Type: Effect<Secret.Secret>
const program = Effect.gen(function* () {
const password = yield* dbPassword;
const value = Secret.value(password); // Get actual string
});
const upperHost = Config.string("HOST").pipe(Config.map((s) => s.toUpperCase()));
const port = Config.string("PORT").pipe(
Config.mapOrFail((s) => {
const n = parseInt(s);
return isNaN(n) ? Either.left(ConfigError.InvalidData([], "Not a number")) : Either.right(n);
}),
);
const host = Config.string("PRIMARY_HOST").pipe(
Config.orElse(() => Config.string("SECONDARY_HOST")),
Config.orElse(() => Config.succeed("localhost")),
);
const program = Effect.gen(function* () {
const host = yield* Config.string("HOST");
});
import { ConfigProvider, Layer } from "effect";
const config = {
host: "localhost",
port: "3000",
database: {
host: "db.example.com",
port: "5432",
},
};
const JsonConfigProvider = ConfigProvider.fromJson(config);
const program = Effect.gen(function* () {
const host = yield* Config.string("host");
const dbHost = yield* Config.nested("database")(Config.string("host"));
});
const runnable = program.pipe(Effect.provide(Layer.setConfigProvider(JsonConfigProvider)));
const MapProvider = ConfigProvider.fromMap(
new Map([
["HOST", "localhost"],
["PORT", "3000"],
]),
);
const CombinedProvider = ConfigProvider.orElse(ConfigProvider.fromEnv(), () => ConfigProvider.fromJson(defaultConfig));
const AppConfigLive = Layer.effect(
AppConfig,
Effect.gen(function* () {
const host = yield* Config.string("HOST");
const port = yield* Config.number("PORT");
const debug = yield* Config.boolean("DEBUG").pipe(Config.withDefault(false));
return { host, port, debug };
}),
);
const TestConfigProvider = ConfigProvider.fromMap(
new Map([
["HOST", "test-host"],
["PORT", "9999"],
]),
);
const testProgram = program.pipe(Effect.provide(Layer.setConfigProvider(TestConfigProvider)));
const testConfig = Config.succeed({
host: "localhost",
port: 3000,
});
Config failures produce ConfigError:
const program = Effect.gen(function* () {
const host = yield* Config.string("REQUIRED_HOST");
}).pipe(Effect.catchTag("ConfigError", (error) => Effect.fail(new StartupError({ cause: error }))));
import { Config, Effect, Layer, Schema } from "effect";
// Define config shape
const AppConfig = Config.all({
server: Config.nested("SERVER")(
Config.all({
host: Config.string("HOST").pipe(Config.withDefault("0.0.0.0")),
port: Config.number("PORT").pipe(Config.withDefault(3000)),
}),
),
database: Config.nested("DATABASE")(
Config.all({
url: Config.redacted("URL"),
maxConnections: Config.number("MAX_CONN").pipe(Config.withDefault(10)),
}),
),
features: Config.all({
debug: Config.boolean("DEBUG").pipe(Config.withDefault(false)),
metrics: Config.boolean("METRICS_ENABLED").pipe(Config.withDefault(true)),
}),
});
// Use in application
const program = Effect.gen(function* () {
const config = yield* AppConfig;
yield* Effect.log(`Starting server on ${config.server.host}:${config.server.port}`);
});
For comprehensive configuration documentation, consult ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt.
Search for these sections: