Getting started
From npm install to a streaming chat handler — one wizard or two snippets.
Two paths from zero to a working chat surface. The wizard is the faster one; the snippets are if you'd rather see what gets generated. Pick whichever fits your taste.
Path A — npx pleach init (recommended)
npx pleach initThe wizard detects your framework (Next.js App / Pages, Astro,
SvelteKit, Remix, Vite, plain Node), asks four questions
(template, provider, plugin stub, schema scaffold), and writes a
starter project. On Next.js App Router that's a route handler, a
<ChatBox /> page, and an /audit view — plus, optionally, a
plugin stub and the Postgres schema bundle. See
CLI → pleach init for the
per-framework template matrix.
Run npm run dev. With no key set, the scaffold runs a keyless
demo: the real graph, base-tools, and audit ledger execute with
canned model text, so /audit shows real rows — model family,
row count, tokens, est. cost — from your first message. Set
ANTHROPIC_API_KEY (or OPENAI_API_KEY / OPENROUTER_API_KEY)
to go live; the same route streams from the provider instead.
~60 seconds wall-clock.
Path B — wire it by hand
Two snippets. The @pleach/core/quickstart subpath is the
canonical wire-level surface and ships in @pleach/core@0.1.0.
npm install @pleach/coreSet one provider env var — pick whichever you already have a key for:
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.
// app/api/chat/route.ts
import { createPleachRoute } from "@pleach/core/quickstart";
export const POST = createPleachRoute();// app/page.tsx
"use client";
import { ChatBox } from "@pleach/core/quickstart";
export default function Home() {
return <ChatBox apiUrl="/api/chat" />;
}That's it. Run npm run dev and you have a streaming chat. The
handler accepts { sessionId?, message } JSON and streams
StreamEvent NDJSON back. <ChatBox /> is an unstyled, semantic,
ARIA-correct chat surface composed of plain HTML with
data-pleach-* selectors.
What you just got
The five @pleach/core/quickstart exports together form the
canonical wire-level surface:
| Export | Shape | Job |
|---|---|---|
createPleachRoute(opts?) | (req: Request) => Response | Promise<Response> | Fetch-handler around SessionRuntime. Works in App Router, Workers, Bun, Hono — anything Request → Response. |
useChat(opts) | React hook | Owns the in-flight stream, messages, sessionId, status (idle | submitting | streaming | error). |
<ChatBox /> | React component | Unstyled, semantic, accessible. Composes useChat. |
defaultPlugin | HarnessPlugin | Empty baseline meeting the structural contract — drop into plugins as the "no domain customization" floor. |
providerDetection | helpers + constants | detectProvider, detectAvailableProviders, DEFAULT_PROVIDER_ENV_VARS, DEFAULT_PROVIDER_PRIORITY. |
Two things to know before you ship
- No provider env var set → HTTP 503. The handler fails
loudly at install time rather than silently falling back to a
stub. Surface the 503 in your client; it's the signal that
ANTHROPIC_API_KEY(or your equivalent) didn't reach the runtime. For keyless local dev, passcreatePleachRoute({ demo: process.env.NODE_ENV !== "production" })— with no key it drives a real graph turn over canned model text and writes real audit rows (response headerx-pleach-mode: demo). A resolved key always wins, and demo never engages in a production build. This is the mode the wizard scaffolds. useChatis Pleach-native, not Vercel-AI-SDK shape. The hook speaks Pleach'sStreamEventdiscriminated union directly. If you're already on the AI SDK event taxonomy, see Migrating from the AI SDK for the compat layer.
Custom storage, plugins, or provider pinning
The zero-config defaults work for tutorials, evals, and local dev. Production hosts pass options through:
// app/api/chat/route.ts
import { createPleachRoute } from "@pleach/core/quickstart";
import { SupabaseAdapter } from "@pleach/core/sessions";
import { myPlugin } from "./pleach.plugin";
export const POST = createPleachRoute({
storage: new SupabaseAdapter({ client: supabase }),
plugins: [myPlugin],
provider: "anthropic", // pin one; skip detection
systemPrompt: (req) => promptFor(req), // per-request override
});When you need to drop below the route handler — multi-tenant SaaS, regulated deployment, custom transport — reach for the runtime construction page.
A progressive path through the docs
You can stop reading at any of these tiers and have a working deployment. Tier 2 adds production concerns; tier 3 adds the audit, compliance, and replay differentiation.
Tier 1 — ~5 minutes — streaming chat
You're here. Path A or Path B above. Add a system prompt and you're shipping.
Read next: Providers for provider
switching · <ChatBox /> styling for matching
your design system.
Tier 2 — ~30 minutes — production-ready chat
Persistent storage, custom plugins, multi-tenant cost rollup, OTel observability.
Read next: Which SKU do I need? ·
Runtime construction ·
Multi-tenant ·
@pleach/observe.
Tier 3 — ~2 hours — audit + compliance + replay
The AuditableCall ledger, the four-stage lattice, scrubbers
for HIPAA / GDPR / PCI-DSS, hash-chain attestation,
replay-deterministic regression testing.
Read next: Audit ledger ·
Compliance ·
@pleach/replay · @pleach/eval ·
Decisions.
Where to go next
Which SKU do I need?
14 published packages, but most projects need 3 or 4. The shortest install list for what you're building.
Recipes
End-to-end runnable patterns — Next.js chat, OTel, multi-tenant, compliance, RAG, subagent swarms.
Playground & devtools
What ships today for inspecting sessions, walking checkpoints, and tailing the event log — and what doesn't.
Runtime construction
When you need to drop below the route handler — SessionRuntime constructor + createPleachRuntime factory.
Decisions
Session vs Turn vs Subagent · Ledger vs Observability · Scrubber vs ComplianceRuntime · Recipe vs Direct.
License
@pleach/core is published under FSL-1.1-Apache-2.0
(Functional Source License with Apache 2.0 as the future license,
auto-transitions to Apache 2.0 two years after first stable
publish). See versioning for the policy.