# Install (/docs/install)



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) [#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`](/docs/cli#pleach-init--the-wizard).

<Tabs items="['npm', 'pnpm', 'yarn', 'bun']" groupId="pkg">
  <Tab value="npm">
    ```bash
    npx pleach init
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm dlx pleach init
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn dlx pleach init
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bunx pleach init
    ```
  </Tab>
</Tabs>

Run `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` [#manual-install-pleachcore]

<Tabs items="['npm', 'pnpm', 'yarn', 'bun']" groupId="pkg">
  <Tab value="npm">
    ```bash
    npm install @pleach/core
    ```
  </Tab>

  <Tab value="pnpm">
    ```bash
    pnpm add @pleach/core
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @pleach/core
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bun add @pleach/core
    ```
  </Tab>
</Tabs>

## Manual: set a provider key [#manual-set-a-provider-key]

<ProviderTabs shape="env" />

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 [#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.

<Tabs items="['Next.js App', 'Next.js Pages', 'Astro', 'SvelteKit', 'Remix', 'Hono', 'Workers', 'Bun']" groupId="framework">
  <Tab value="Next.js App">
    ```typescript
    // app/api/chat/route.ts
    import { createPleachRoute } from "@pleach/core/quickstart";

    export const POST = createPleachRoute();
    ```
  </Tab>

  <Tab value="Next.js Pages">
    ```typescript
    // 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();
    }
    ```
  </Tab>

  <Tab value="Astro">
    ```typescript
    // 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);
    ```
  </Tab>

  <Tab value="SvelteKit">
    ```typescript
    // src/routes/api/chat/+server.ts
    import { createPleachRoute } from "@pleach/core/quickstart";

    const handler = createPleachRoute();

    export const POST = ({ request }) => handler(request);
    ```
  </Tab>

  <Tab value="Remix">
    ```typescript
    // app/routes/api.chat.ts
    import { createPleachRoute } from "@pleach/core/quickstart";

    const handler = createPleachRoute();

    export const action = ({ request }) => handler(request);
    ```
  </Tab>

  <Tab value="Hono">
    ```typescript
    // 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;
    ```
  </Tab>

  <Tab value="Workers">
    ```typescript
    // 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 });
      },
    };
    ```
  </Tab>

  <Tab value="Bun">
    ```typescript
    // 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 });
      },
    });
    ```
  </Tab>
</Tabs>

## What this gives you [#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](/docs/storage) and (optionally) a
[plugin](/docs/plugin-contract).

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](/docs/getting-started). For a production-shape
handler with custom storage, plugins, and provider pinning, see
[Getting started → Custom storage, plugins, or provider pinning](/docs/getting-started#custom-storage-plugins-or-provider-pinning).

## Where to go next [#where-to-go-next]

<Cards>
  <Card title="Getting started" href="/docs/getting-started" description="The end-to-end 60-second walkthrough — install, env, route handler, page." />

  <Card title="Which SKU do I need?" href="/docs/which-sku" description="14 published packages, but most projects need 3 or 4. The shortest install list for what you're building." />

  <Card title="Runtime construction" href="/docs/runtime-construction" description="When you need to drop below the route handler — SessionRuntime constructor + createPleachRuntime factory." />

  <Card title="Storage" href="/docs/storage" description="Memory, IndexedDB, Supabase, Postgres — when to use which adapter." />
</Cards>
