platform
This skill should be used when the user asks about "@effect/platform", "Effect HTTP client", "Effect HTTP server", "FileSystem", "KeyValueStore", "Terminal", "platform services", "HttpClient", "HttpServer", "Effect file operations", "Effect networking", or needs to understand Effect's platform-agnostic I/O capabilities.
What this skill does
# Effect Platform
## Overview
`@effect/platform` provides cross-platform abstractions for:
- **HTTP Client** - Make HTTP requests
- **HTTP Server** - Build HTTP servers
- **FileSystem** - File operations
- **KeyValueStore** - Persistent storage
- **Terminal** - CLI interactions
- **Worker** - Background workers
## HTTP Client
### Installation
```bash
npm install @effect/platform
# For Node.js:
npm install @effect/platform-node
# For Bun:
npm install @effect/platform-bun
```
### Basic Requests
```typescript
import { HttpClient } from "@effect/platform";
import { NodeHttpClient } from "@effect/platform-node";
import { Effect } from "effect";
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
// GET request
const response = yield* client.get("https://api.example.com/users");
const data = yield* response.json;
return data;
}).pipe(Effect.provide(NodeHttpClient.layer));
```
### Request Configuration
```typescript
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
// POST with body
const response = yield* client.post("https://api.example.com/users", {
body: HttpClientRequest.jsonBody({ name: "Alice", email: "[email protected]" }),
});
// With headers
const response = yield* client.get("https://api.example.com/protected", {
headers: { Authorization: "Bearer token123" },
});
// With timeout
const response = yield* client.get("https://api.example.com/slow").pipe(Effect.timeout("5 seconds"));
});
```
### Response Handling
```typescript
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
const response = yield* client.get("https://api.example.com/data");
// Parse as JSON
const json = yield* response.json;
// Parse as text
const text = yield* response.text;
// Get status
const status = response.status;
// Get headers
const contentType = response.headers["content-type"];
});
```
### Schema Validation
```typescript
import { HttpClient, HttpClientResponse } from "@effect/platform";
import { Schema } from "effect";
const User = Schema.Struct({
id: Schema.Number,
name: Schema.String,
email: Schema.String,
});
const program = Effect.gen(function* () {
const client = yield* HttpClient.HttpClient;
const response = yield* client.get("https://api.example.com/users/1");
// Validate response with schema
const user = yield* HttpClientResponse.schemaBodyJson(User)(response);
return user;
});
```
## HTTP Server
### Basic Server
```typescript
import { HttpServer, HttpServerResponse } from "@effect/platform";
import { NodeHttpServer } from "@effect/platform-node";
import { Effect, Layer } from "effect";
import { createServer } from "node:http";
const app = HttpServer.router.empty.pipe(
HttpServer.router.get("/", HttpServerResponse.text("Hello, World!")),
HttpServer.router.get(
"/users",
HttpServerResponse.json([
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]),
),
);
const ServerLive = NodeHttpServer.layer(createServer, { port: 3000 });
const program = Effect.gen(function* () {
yield* Effect.log("Server starting on port 3000");
yield* Effect.never; // Keep running
}).pipe(Effect.provide(HttpServer.router.Live(app)), Effect.provide(ServerLive));
```
### Route Parameters
```typescript
const app = HttpServer.router.empty.pipe(
HttpServer.router.get(
"/users/:id",
Effect.gen(function* () {
const params = yield* HttpServer.router.params;
const id = params.id;
return HttpServerResponse.json({ id, name: "User " + id });
}),
),
);
```
### Request Body
```typescript
import { HttpServerRequest } from "@effect/platform";
const app = HttpServer.router.empty.pipe(
HttpServer.router.post(
"/users",
Effect.gen(function* () {
const request = yield* HttpServerRequest.HttpServerRequest;
const body = yield* request.json;
// Or with schema validation
const validated = yield* HttpServerRequest.schemaBodyJson(CreateUser)(request);
return HttpServerResponse.json({ created: true, user: validated });
}),
),
);
```
## FileSystem
### Reading Files
```typescript
import { FileSystem } from "@effect/platform";
import { NodeFileSystem } from "@effect/platform-node";
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const content = yield* fs.readFileString("./config.json");
const bytes = yield* fs.readFile("./image.png");
const exists = yield* fs.exists("./file.txt");
}).pipe(Effect.provide(NodeFileSystem.layer));
```
### Writing Files
```typescript
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
yield* fs.writeFileString("./output.txt", "Hello, World!");
yield* fs.writeFile("./data.bin", new Uint8Array([1, 2, 3]));
yield* fs.appendFileString("./log.txt", "New log entry\n");
});
```
### Directory Operations
```typescript
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
yield* fs.makeDirectory("./new-dir", { recursive: true });
const files = yield* fs.readDirectory("./src");
yield* fs.remove("./temp", { recursive: true });
yield* fs.copy("./source.txt", "./dest.txt");
yield* fs.rename("./old.txt", "./new.txt");
});
```
### File Info
```typescript
const program = Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const stat = yield* fs.stat("./file.txt");
console.log({
size: stat.size,
isFile: stat.type === "File",
isDirectory: stat.type === "Directory",
modified: stat.mtime,
});
});
```
## KeyValueStore
Persistent key-value storage:
```typescript
import { KeyValueStore } from "@effect/platform";
import { NodeKeyValueStore } from "@effect/platform-node";
const program = Effect.gen(function* () {
const store = yield* KeyValueStore.KeyValueStore;
yield* store.set("user:1", JSON.stringify({ name: "Alice" }));
const value = yield* store.get("user:1");
yield* store.remove("user:1");
const exists = yield* store.has("user:1");
}).pipe(Effect.provide(NodeKeyValueStore.layerFileSystem("./data")));
```
## Terminal
CLI interactions:
```typescript
import { Terminal } from "@effect/platform";
import { NodeTerminal } from "@effect/platform-node";
const program = Effect.gen(function* () {
const terminal = yield* Terminal.Terminal;
const name = yield* terminal.readLine;
yield* terminal.display(`Hello, ${name}!`);
}).pipe(Effect.provide(NodeTerminal.layer));
```
## Complete Example: REST API
```typescript
import { HttpServer, HttpServerResponse, HttpServerRequest } from "@effect/platform";
import { NodeHttpServer } from "@effect/platform-node";
import { Effect, Layer, Schema } from "effect";
import { createServer } from "node:http";
// Schemas
const CreateUser = Schema.Struct({
name: Schema.String,
email: Schema.String,
});
const User = Schema.Struct({
id: Schema.Number,
name: Schema.String,
email: Schema.String,
});
// In-memory store
let users: Schema.Schema.Type<typeof User>[] = [];
let nextId = 1;
// Routes
const app = HttpServer.router.empty.pipe(
HttpServer.router.get("/users", HttpServerResponse.json(users)),
HttpServer.router.post(
"/users",
Effect.gen(function* () {
const body = yield* HttpServerRequest.schemaBodyJson(CreateUser);
const user = { id: nextId++, ...body };
users.push(user);
return HttpServerResponse.json(user, { status: 201 });
}),
),
HttpServer.router.get(
"/users/:id",
Effect.gen(function* () {
const { id } = yield* HttpServer.router.params;
const user = users.find((u) => u.id === parseInt(id));
return user ? HttpServerResponse.json(user) : HttpServerResponse.json({ error: "Not found" }, { status: 404 });
}),
),
);
// Server
const ServerLive = NodeHttpServer.layer(createServer, { port: 3000 });
const main = HttpServer.serve(app).pipe(Effect.provide(ServerLivRelated 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.