pleach
Get Started

Overview

The conceptual map — what Pleach is, what a turn looks like, what gets recorded, and which door to open next.

Pleach is a TypeScript agent runtime. Sessions hold state; turns drive change; every LLM call lands as one append-only audit row keyed by turnId. The runtime, the four-stage lattice, and the audit ledger form a triangle — the rest of the docs are detail.

The name is horticultural. A streamText call is one branch upright in a pot. Pleach is the lattice — every addressable event the agent produces (each LLM call, tool dispatch, subagent spawn) lands as a branch, woven into one structure you can query, prune, and replay six months later. The four stages are the trellis; the audit row is the weave.

This page gives you the shape in 90 seconds. Install steps live on Getting started; framework comparison lives on Comparison.

The mental model

One request in, one streamed answer out. The SessionRuntime owns the turn; the ledger hangs off it as an append-only sink so every addressable decision is queryable after the fact.

Session vs turn

A session is the unit of identity that outlives any one message. A turn is one message-in, one answer-out. They have different shapes:

PropertySessionTurn
ScopePer-conversation; locks (provider, model) for its lifetimePer-message; runs the four-stage lattice once
PersistenceDurable row + checkpoint chain in storageDerived from the event log; no separate row
Abort behaviorIdempotent delete; checkpoints drop, audit rows stayAbortSignal cancels in-flight provider calls; partial spend still lands a row

Session lifecycle (mint, resume, fork, delete) is documented at Session lifecycle. The dynamic per-message arc lives at Turn lifecycle.

A turn, in four stages

The lattice is structural. Every node in the compiled graph belongs to exactly one stage; audit:graph-stages fails the build on an out-of-lattice edge. post-turn is terminal — no edge out.

anchor-plan

Bootstraps the turn: intent classification, plan generation, and anchoring of references the tool loop will need. Fires step.start on the stream and writes one ledger row per call with payload.kind: "planGeneration".

tool-loop

The iterative core. One reasoning call per iteration may emit tool calls; the runtime dispatches them and re-enters the loop. Fires tool.started / tool.completed per dispatch and writes cacheBreakpoint, toolSelection, and (on retry) fallbackStep rows.

synthesize

Exactly one synthesize call per turn — capped by a per-runtime singleton seam plus an idempotent counter so the rendered string and the audited string are the same string. Fires message.delta and message.complete; writes one synthesisQuality row.

post-turn

Terminal stage. Durable writes flush, enrichment plugins run, checkpoints land. No LLM calls fire here. Fires checkpoint.created and then done.

For the full per-stage stream-event and ledger-payload tables, see Turn lifecycle → the four-stage execution path.

What gets recorded

Every addressable decision — every seam-bound provider call, every in-family retry, every tool-cascade rung — lands one row. The ledger is append-only by contract: ProviderDecisionLedger exposes no update and no delete. A per-turn cost rollup is one GROUP BY turn_id; a per-stage budget is one GROUP BY stage_id.

The four-field identity tuple is what makes joins cheap. turnId joins to your billing row; stageId slices the spend; sessionId joins to the session record; seqWithinTurn gives a stable order inside the turn. See The AuditableCall row for the full field shape and the typed-payload discriminants.

Concretely, a per-turn cost rollup looks like:

SELECT turn_id, SUM(input_tokens + output_tokens) AS total_tokens
FROM harness_auditable_calls
WHERE session_id = $1
GROUP BY turn_id;

That query works against a row shape that exists by construction — every row carries a non-null turn_id because a call that fires outside the lattice fails CI before it ever reaches a provider.

The axis is yours to pick. tenantId carries customer-acme if you're invoicing end customers in a SaaS; it carries cost-center-eng-platform if you're attributing employee or team spend under one Anthropic Workspace or OpenAI Project on an Enterprise contract. The rollup is the same GROUP BY either way — no second vendor contract, no second admin key. See Migrating from Anthropic Enterprise and Migrating from OpenAI Enterprise for the composition walk-through.

Three doors

Pick the closest. The rest of the index is reference.

Where the rest of the docs live

The sidebar is grouped by what you reach for, not by package boundary. Core primitives (SessionRuntime, Facets, Providers, Tools, Prompts) is the day-one surface. Compose agents (Agents, Subagents, Skills, Plans, Memory) is the multi-step shape. Runtime lifecycle (Channels, Event log, Projections, Stream events, Interrupts, Async tasks) is what the runtime is doing between your calls. State & persistence (Storage, Cache, Checkpointing, Sync) is how state survives a process restart. Safety & determinism (Safety policies, Scrubbers, Fabrication detection, Determinism, Fingerprint) is the property set replay and eval depend on. Audit & observability (Audit ledger, Hash chain, AuditableCall row, Lineage, OTEL spans) is the read side. Frontend (React, Server, API routes, Query, DevTools) and Integration (MCP, LangChain adapter, Host adapter, Plugin contract) wire the runtime into a real application. Operations (Deployment, Multi-tenant, Performance, Security, Compliance, Error codes) is what production needs.

What this site is not

Not where the package source lives. @pleach/core is published from the upstream repository at github.com/pleachhq/core and consumed here as a documentation target — the version of @pleach/core rendered against this site is whatever the package manifest pins.

Not the canonical reference for any individual package — each package's README on npm is. If this site disagrees with a published README (a row in the model resolution matrix, a field name in the AuditableCall row, a verdict in the stream-observer ladder), the README wins.

Where to go next

On this page