Install
Package-manager and framework matrix — one page that covers every way to bring `@pleach/core` into a project.
The soil layer before the trellis goes up. Install paths organized by what you already use: pick a package manager, pick a framework, pick a provider. The wizard wraps all three; the manual snippets are if you want to see what gets generated.
The wizard (recommended)
npx pleach init detects your framework, asks four questions
(template, provider, plugin stub, schema scaffold), and writes a
starter project. Per-framework template matrix lives at
CLI → pleach init.
npx pleach initpnpm dlx pleach inityarn dlx pleach initbunx pleach initRun npm run dev. On Next.js App Router the scaffold runs a
keyless demo with no key set — the real graph, base-tools, and
audit ledger run with canned model text, and the bundled /audit
view shows real rows from your first message. Set a provider key
to go live. ~60 seconds wall-clock.
Manual: install @pleach/core
npm install @pleach/corepnpm add @pleach/coreyarn add @pleach/corebun add @pleach/coreManual: set a provider key
export ANTHROPIC_API_KEY="..."export OPENAI_API_KEY="..."export GOOGLE_GENERATIVE_AI_API_KEY="..."export OPENROUTER_API_KEY="..."export DEEPSEEK_API_KEY="..."export MISTRAL_API_KEY="..."export MOONSHOT_API_KEY="..."The runtime auto-detects whichever key is set. Detection priority
matches the tab order above. To pin a provider explicitly (skipping
detection), pass provider: "anthropic" to createPleachRoute().
Manual: wire a route handler
The same createPleachRoute() factory works in any fetch-based
runtime — App Router, Pages Router, Astro, SvelteKit, Remix, Hono,
Workers, Bun. Pick the framework you're on; the body is identical.
// app/api/chat/route.ts
import { createPleachRoute } from "@pleach/core/quickstart";
export const POST = createPleachRoute();// pages/api/chat.ts
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
export const config = { api: { bodyParser: false } };
export default async function POST(req, res) {
const response = await handler(new Request(`http://x${req.url}`, {
method: "POST",
body: req as unknown as BodyInit,
}));
res.status(response.status);
response.headers.forEach((v, k) => res.setHeader(k, v));
if (response.body) {
const reader = response.body.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
res.write(value);
}
}
res.end();
}// src/pages/api/chat.ts
import type { APIRoute } from "astro";
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
export const POST: APIRoute = ({ request }) => handler(request);// src/routes/api/chat/+server.ts
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
export const POST = ({ request }) => handler(request);// app/routes/api.chat.ts
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
export const action = ({ request }) => handler(request);// src/index.ts
import { Hono } from "hono";
import { createPleachRoute } from "@pleach/core/quickstart";
const app = new Hono();
const handler = createPleachRoute();
app.post("/api/chat", (c) => handler(c.req.raw));
export default app;// src/index.ts
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
export default {
async fetch(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname === "/api/chat" && req.method === "POST") {
return handler(req);
}
return new Response("Not found", { status: 404 });
},
};// server.ts
import { createPleachRoute } from "@pleach/core/quickstart";
const handler = createPleachRoute();
Bun.serve({
port: 3000,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/api/chat" && req.method === "POST") {
return handler(req);
}
return new Response("Not found", { status: 404 });
},
});What this gives you
A streaming chat handler at POST /api/chat that accepts
{ sessionId?, message } JSON and streams StreamEvent NDJSON
back. No persistence, no plugins, no domain customization — the
runtime returns a substrate placeholder until you adopt a
storage adapter and (optionally) a
plugin.
For keyless local dev — no env var, no 503 — pass
demo: process.env.NODE_ENV !== "production" to
createPleachRoute(). With no key it drives a real graph turn
over canned model text and writes real audit rows (response
header x-pleach-mode: demo); a resolved key always wins, and it
stays off in a production build. It's the mode the wizard
scaffolds, with an /audit view to read the rows.
For the React side — useChat(), <ChatBox /> — see
Getting started. For a production-shape
handler with custom storage, plugins, and provider pinning, see
Getting started → Custom storage, plugins, or provider pinning.
Where to go next
Getting started
The end-to-end 60-second walkthrough — install, env, route handler, page.
Which SKU do I need?
14 published packages, but most projects need 3 or 4. The shortest install list for what you're building.
Runtime construction
When you need to drop below the route handler — SessionRuntime constructor + createPleachRuntime factory.
Storage
Memory, IndexedDB, Supabase, Postgres — when to use which adapter.