pleach
Build

@pleach/core

The runtime substrate — sessions, graph, channels, audit ledger, checkpointing, sync, storage adapters.

The trellis the rest of @pleach/* grows on. @pleach/core is the agent-runtime substrate built on three load-bearing primitives: a four-stage lattice, a family-locked model resolution matrix, and an append-only audit ledger. Every sibling @pleach/* package plugs into it. Every LLM call inside an agent is classifiable, auditable, and replayable — not one opaque streamText.

Concretely: each call goes through exactly one of four seams (synthesizeSeam, reasoningSeam, utilitySeam, converseSeam), each seam stamps the call's row in harness_auditable_calls with the declared callClass, and each row carries the (sessionId, turnId, stageId, seqWithinTurn) identity tuple — joinable to the turn that caused it, replayable in registration order. See the architecture deep-dive for the walk, or Auditable call row for the row shape.

Package@pleach/coreSourcegithub.com/pleachhq/coreLicenseFSL-1.1-Apache-2.0

Install

npm install @pleach/core
pnpm add @pleach/core
yarn add @pleach/core
bun add @pleach/core

For the end-to-end Next.js walkthrough — env var, route handler, React surface — see Getting started. For the cross-framework matrix (Next App / Pages, Astro, SvelteKit, Remix, Hono, Workers, Bun), see Install.

Minimal example

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

const runtime = createPleachRuntime();
// `runtime` returns a substrate placeholder until an
// OrchestratorAdapter is wired — see "Advanced wiring" below.

That's the headless-script / eval-harness shape: import, construct, hold a reference. To stream messages against a real provider, the @pleach/core/quickstart subpath ships createPleachRoute() (route handler) and useChat()

  • <ChatBox /> (React). For a keyless first run, createPleachRoute({ demo: true }) drives a real graph turn over canned model text and writes real audit rows — the mode npx pleach init scaffolds behind an /audit view.

What you get

A scan of what ships. See the architecture deep-dive for the walk.

  • 4-stage lattice, lint-enforced. anchor-plan → tool-loop ⇄ synthesize → post-turn. Out-of-lattice edges fail CI.
  • 4 call classes, declared per call. utility / reasoning / converse / synthesize. The literal is lint-restricted to seam factories.
  • Family + transport lock per session. Tokenizer, prompt-cache key, tool dialect, and refusal pattern freeze at session start. The cascade walks in-family rungs only.
  • Singleton synthesize seam. Exactly one final answer per turn, enforced by SynthesizeSeamHolder + TurnSynthesizeCounter (idempotent on messageId).
  • AuditableCall ledger. Append-only, ULID-keyed, typed payloads for family-lock, fallback-step, cache-breakpoint, provider-cascade, plan-generation, synthesis-quality, interrupt-decision, tool-selection, and token-cost decisions.
  • Composes under an existing Enterprise contract. Anthropic Workspace or OpenAI Project stays the vendor axis; @pleach/core stamps tenantId on every row so per-axis rollup runs inside the contract you already pay for — end customers in a SaaS, or employees, teams, and cost centers when used internally. See Migrating from Anthropic Enterprise and Migrating from OpenAI Enterprise.
  • Reactive channels. LastValue, BinaryOperatorAggregate, Topic, EphemeralValue, NamedBarrier, DataChannel with LRU eviction. Deterministic reducers; concurrent-write semantics defined per kind.
  • BYO-DB storage + checkpointing + sync. Memory / IndexedDB / Supabase adapters; per-channel checkpoint() / restore() for time-travel; version-vector sync detects conflicts at write time.
  • Bounded plugin contract. Fill tier slots, register stream observers, contribute prompts, subscribe to events. Can't rewrite the lattice, bypass the synthesize seam, or reach the modelfamily matrix directly.

Advanced wiring — the @pleach/core/runtime subpath

The 30-second snippet (import { createPleachRuntime } from "@pleach/core") is the right entry point for tutorials, headless scripts, eval harnesses, and any consumer that does not need to wire an LLM provider through an OrchestratorAdapter. The runtime returns a substrate placeholder when no provider is configured.

The moment you wire a real provider — registering an OrchestratorAdapter ctor, an AuditEmitter, a SupabaseFactory, or any of the other app-boot registries — import from the @pleach/core/runtime subpath instead:

import {
  createPleachRuntime,
  setOrchestratorAdapterCtor,
} from "@pleach/core/runtime";

// At app boot, before any runtime executes a message:
setOrchestratorAdapterCtor(MyOrchestratorAdapter);

const runtime = createPleachRuntime({
  // host.strategies.orchestratorConfig forwards to the adapter
  host: { strategies: { orchestratorConfig: { model: "gpt-4o-mini", /* ... */ } } },
});

Why the split? @pleach/core ships each package.json:exports entry as a self-contained bundle (splitting: false in tsup.config.ts). This is intentional — it keeps tree-shaking honest, lets consumers pull only the subpaths they touch, and isolates the top-level barrel from React / Anthropic / Supabase peer-resolution surprises. The trade-off is that each bundle carries its own module-state copy of the app-boot registries, so writes through one bundle and reads through another do not see each other. The @pleach/core/runtime subpath co-locates createPleachRuntime with every registry setter the runtime reads, so consumers wiring providers can do so end-to-end through one import path.

If you only consume createPleachRuntime, both forms work. The subpath is the canonical advanced-wiring path; the top-level is the tutorial path. @pleach/recipes and the npx pleach init scaffold both already use the subpath. See Host adapter for the full host-injection contract and Subpath exports for the canonical surface map.

What lives in this package today

The root barrel re-exports the most-used types and functions (SessionRuntime, createPleachRuntime, channel primitives, the plugin contract, prompt helpers, the event log writer, the cache backend factory). Specialized subsystems are reachable through deep subpath imports — see Subpath exports for the canonical grouping. The substrate covers:

  • Runtime + facets. SessionRuntime, createPleachRuntime, TurnOrchestrator, and ~18 named facet accessors (runtime.sessions, runtime.events, runtime.spans, runtime.tenant, runtime.graph.{recovery, heuristics, config}, runtime.plugins, …). See Facets for the full inventory and the per-facet audit gates that enforce coverage.
  • Persistence. MemoryAdapter, IndexedDBAdapter, SupabaseAdapter storage adapters; matching MemorySaver, IndexedDBSaver, SupabaseSaver checkpointers; SyncCoordinator + version-vector primitives (incrementVersion, mergeVectors, compareVectors). See Storage, Checkpointing, and Sync.
  • Event log. EventLogWriter (fire-and-forget enqueue + durable flush), EventLogClient (read-side), 10 named GraphProjection<T> projections (interrupt, subagent, exports, artifact, …), and the chainStep hash-chain primitive that stamps prev_hash / row_hash per row when c9PhaseBEnabled is set. See Event log and Event log projections.
  • Audit ledger. MemoryProviderDecisionLedger default implementation, typed AuditableCall payloads (family-lock, fallback-step, cache-breakpoint, provider-cascade, plan-generation, synthesis-quality, interrupt-decision, tool-selection, token-cost), at auditRecordVersion = 18. See Audit ledger and Typed records.
  • Attestation. signAttestation / verifyAttestation over the canonical row hash + a pluggable keystore (file-backed for test, AWS KMS, Vault Transit). Ships via the @pleach/core/attestation and @pleach/core/attestation/keyStores subpaths. See Attestation.
  • Cache. createMemoryCacheBackend (default-constructed in the SessionRuntime constructor since PA-2 C2 Phase 3) plus the CacheBackend interface for swapping in Redis / Upstash. Threads through the four seam factories. See Cache.
  • Safety. SafetyPolicyRegistry (per-runtime, opt-in via enabledSafetyPolicies) + composeSafetyContent wired into the prompt resolver. See Safety.
  • Scrubbers. Scrubber interface, DefaultScrubberChain, and SCRUBBABLE_FIELDS allowlist enforced by audit:c8-event-type-allowlist-coverage at PR time. See Scrubbers.
  • Prompts + builder. PromptContributionRegistry and resolvePromptContributions for the contribution contract; friendly-API helpers (appendPrompt, prependPersona, replaceCore, scopedPrompt, gatedPrompt, createPlugin); 41 universal Phase H core fragment templates; the @pleach/core/prompt-builder shell with composeBudgetedPrompt and the per-section authoring kit. See Prompts and Prompt builder.
  • Plugin contract. 67 contributeX hooks on HarnessPlugin (prompts, runtime-aware prompts, stream observers, safety policies, fabrication detectors, tools, intent-tool map, tool-coupling hints, continuation policy, retry policy, …) plus the definePleachPlugin discoverable entry point. See Plugin contract.
  • OTel + lineage + fingerprint. The observability triplet: runtime.spans for OTel-style span introspection (inFlightCount, isShutdown, snapshot); LineageTracker for cross-session parent/child/forked relationships; the pure-function fingerprint module that hashes prepared LLM inputs platform-uniformly (the determinism property @pleach/eval and @pleach/replay build on). See Observability, Lineage, and Fingerprint.
  • Quickstart. createPleachRoute + the React quickstart surface (useChat, <ChatBox/>) at the @pleach/core/quickstart subpath for one-line bootstraps.
  • Adapters + integration. Subpaths for query (/query), inspector (/inspector), MCP (/mcp via createHarnessMCPServer), mock executors (/mock), and finalization helpers (/finalization).

Language-agnostic contract

The runtime contract — sessions, checkpoints, storage, tools, sync, SSE wire — is language-agnostic by design. The TypeScript distribution in @pleach/core is the reference implementation, in production today. A Go implementation has been built against the same contract and round-trips a shared corpus of recorded turns through the same AuditableCall rows and Checkpoint envelopes — that's the test that catches anything TypeScript-flavored leaking into the wire (see Language-agnostic contract for the three falsification mechanisms — shared fixtures, cross-runtime replay, and the schema gate). The Go implementation isn't published as a SKU yet; an official @pleach Go runtime is the next planned published implementation.

If a claim in these docs only holds in JavaScript, that's a documentation bug — open an issue against pleachhq/core.

Every sibling @pleach/* package plugs into @pleach/core. The ones first-wave consumers most often pair with it:

  • @pleach/recipes — use-case-targeted factories (chatbot, RAG, compliant chatbot, enterprise agent, swarm) over the core runtime. The shortest path past the quickstart.
  • @pleach/compliance — scrubbers + CI audit gates that wrap core's EventLogWriter at the persistence boundary. Adopt when audit rows are evidence.
  • @pleach/gateway — multi-tenant routing client over core's family-locked matrix. Per-tenant scoping, BYOK fingerprinting, per-call cost events.
  • @pleach/replay — event-granular replay via the canonical runtime.events.iterate/fold surface. Deterministic fork-from-prefix + hash-chain verification.
  • @pleach/evalEvalSuite + four scorers; takes a ReplayClient through constructor DI.
  • @pleach/observe — OpenTelemetry / Datadog / Honeycomb wiring over core's two write streams.
  • @pleach/react — primitive hooks + <ChatBox /> surface. Either the lower-level @pleach/react or the bundled @pleach/core/quickstart exports.
  • @pleach/toolsdefineTool contract + @pleach/base-tools for the batteries-included starter set.

For the full SKU map see Which SKU do I need?.

Where to go next

On this page