pleach
Get Started

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.

npx pleach init

The 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/core

Set 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:

ExportShapeJob
createPleachRoute(opts?)(req: Request) => Response | Promise<Response>Fetch-handler around SessionRuntime. Works in App Router, Workers, Bun, Hono — anything Request → Response.
useChat(opts)React hookOwns the in-flight stream, messages, sessionId, status (idle | submitting | streaming | error).
<ChatBox />React componentUnstyled, semantic, accessible. Composes useChat.
defaultPluginHarnessPluginEmpty baseline meeting the structural contract — drop into plugins as the "no domain customization" floor.
providerDetectionhelpers + constantsdetectProvider, 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, pass createPleachRoute({ 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 header x-pleach-mode: demo). A resolved key always wins, and demo never engages in a production build. This is the mode the wizard scaffolds.
  • useChat is Pleach-native, not Vercel-AI-SDK shape. The hook speaks Pleach's StreamEvent discriminated 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

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.

On this page