From effect-ts
This skill should be used when the user asks about "Effect Config", "environment variables", "configuration management", "Config.string", "Config.number", "ConfigProvider", "Config.nested", "Config.withDefault", "Config.redacted", "sensitive values", "config validation", "loading config from JSON", "config schema", or needs to understand how Effect handles application configuration.
npx claudepluginhub andrueandersoncs/claude-skill-effect-ts --plugin effect-tsThis skill uses the workspace's default tool permissions.
Effect provides type-safe configuration loading with:
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
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: