pleach
Get Started

Runtime construction

When you need to drop below `createPleachRoute` — the `createPleachRuntime` factory, the `SessionRuntime` constructor, and the React `HarnessProvider`.

Getting started shows the route-handler path — createPleachRoute() wraps everything below into one fetch handler. This page is for the cases where you need direct access to the runtime:

  • A headless script, eval harness, or test fixture (no HTTP boundary).
  • A multi-tenant SaaS with per-tenant storage / policies / plugins.
  • A custom transport that doesn't fit the Request → Response shape.
  • An existing React app that wants the hook surface without the route handler.

Three entry points, ordered by depth.

createPleachRuntime — the factory

One line, sensible defaults baked in: in-memory storage, the default memoryCacheBackend, no plugins, no safety policies. Use it in tutorials, eval harnesses, and headless scripts.

import { createPleachRuntime } from "@pleach/core";

const runtime = createPleachRuntime();

const { id: sessionId } = await runtime.sessions.create();

for await (const event of runtime.executeMessage(sessionId, "Hello")) {
  console.log(event.type, event);
}

Every field on CreatePleachRuntimeConfig is optional. The typical form layers on a persistent storage adapter, an explicit tenantId, and a plugin set:

import { createPleachRuntime } from "@pleach/core";
import { SupabaseAdapter } from "@pleach/core/sessions";

const runtime = createPleachRuntime({
  userId: "alice@example.com",
  tenantId: "acme-corp",
  storage: new SupabaseAdapter({ client: supabase }),
  plugins: [myAppPlugin],
});

Model and provider are not locked at factory creation — per-session locking is the canonical pattern. Pass provider and model when you mint the session:

const session = await runtime.sessions.create({
  provider: { type: "anthropic" },
  model:    { id: "claude-sonnet-4-5" },
});

The factory is a thin layer over the SessionRuntime constructor; the advanced?: Partial<SessionRuntimeConfig> pass-through reaches the full config surface.

SessionRuntime — the constructor

When you need persistent storage, checkpointing, or per-request user identity, drop to the constructor directly:

import { SessionRuntime } from "@pleach/core";
import { SupabaseAdapter } from "@pleach/core/sessions";
import { SupabaseSaver } from "@pleach/core/checkpointing";

const runtime = new SessionRuntime({
  storage:      new SupabaseAdapter({ client: supabase }),
  checkpointer: new SupabaseSaver({ client: supabase }),
  userId:       "user_123",
});

const { id: sessionId } = await runtime.sessions.create();

for await (const event of runtime.executeMessage(sessionId, "Hello")) {
  console.log(event.type, event);
}

The full constructor surface — including plugin sets, the provider, the channel registry, the interrupt manager, and the extension loader — lives at SessionRuntime.

HarnessProvider — the React surface

If you want the hook surface without the route handler — for example, embedding the runtime in an Electron app or a React Native shell — use @pleach/core/react directly:

// app/layout.tsx
import { HarnessProvider, useHarness } from "@pleach/core/react";

function App() {
  return (
    <HarnessProvider userId="user_123">
      <ChatComponent />
    </HarnessProvider>
  );
}

function ChatComponent() {
  const { createSession, sendMessage, messages } = useHarness();

  return (
    <div>
      <button onClick={() => createSession()}>New Session</button>
      {messages.map((m) => (
        <div key={m.id}>{m.content}</div>
      ))}
    </div>
  );
}

The provider owns one SessionRuntime instance per mount and hands it down through context. See the React page for the full hook + facade surface.

Mock mode for tests and CI

For local development without a database or provider account, HARNESS_MOCK_MODE=true gates the mock tool executor — a host-side utility (createMockToolExecutor / isMockModeEnabled) that synthesizes tool results. It is the only thing that reads the env var; the runtime constructors (new SessionRuntime, createPleachRuntime) do not, so wiring mock mode into a runtime is a manual step — construct the mock executor and pass it in, and pair it with the in-memory MemoryAdapter + MemorySaver yourself. The mock executor does not classify seams or write ledger rows; it only produces synthesized tool outputs. (The default provider-decision ledger is NoopProviderDecisionLedger, which drops all writes unless a host supplies a real ledger.) A regression test (planned: @pleach/eval; DIY today) composes these pieces itself.

Choosing between the three

If you're building...Reach for
A tutorial, eval harness, headless smoke scriptcreatePleachRuntime
An HTTP chat handler + UI in five minutes@pleach/core/quickstart
A multi-tenant SaaS, regulated deployment, custom transportnew SessionRuntime(...) directly
An existing React app composing the runtimeHarnessProvider + useHarness

The four are the same substrate at different abstraction layers — a createPleachRoute handler internally constructs a SessionRuntime per request; createPleachRuntime is the substrate factory the handler delegates to; HarnessProvider wraps the same constructor for React.

Already on Anthropic Enterprise or OpenAI Enterprise?

Pleach runs underneath. AnthropicSdkProvider and the AI SDK's OpenAI provider both accept your existing workspace or project admin key; the runtime stamps tenantId on every audit row so per-axis rollup runs inside the Workspace or Project you already pay for. See Migrating from Anthropic Enterprise and Migrating from OpenAI Enterprise for the contract-composition walk-through.

Where to go next

On this page