@pleach/*

The agent runtime built around the audit row.

Every model call your agent makes writes one row you own. That's all it takes to bill each customer, answer an auditor in SQL, and replay last week's bug exactly.

The name is horticultural. Pleaching weaves living branches into one load-bearing hedge. Pleach weaves every call, tool, and subagent your agent produces into one structure you can query, prune, and replay.

Free and fair-source under FSL-1.1-Apache-2.0. Runs on your own database — no phone-home, no license check, no account. In production today.

One command · keyless · real audit rows
npx pleach init && npm run dev
GET /auditno key set
Audit ledger rolled up by model family after the first message — family, row count, tokens, and estimated cost.
familyrowstokensest. cost
openai2142$0.0004

No provider key. npm run dev runs a keyless demo — the real graph, base-tools, and audit ledger — and /audit shows the rows. Set ANTHROPIC_API_KEY to go live.

Five lines · no database · no provider key
import { createPleachRuntime } from "@pleach/core";

const runtime = createPleachRuntime();
const session = await runtime.sessions.create();

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

Defaults to in-memory storage + mock mode. Add a provider, a Supabase adapter, or plugins as you need them. To see the audit rows themselves, npx pleach init scaffolds a keyless demo and an /audit view.

Browse the @pleach scope on npm →
One full AuditableCall row — every column your agent writes per model callA single row from the harness_auditable_calls table with every field: record_id, tenant_id, turn_id, parent_turn_id, tool_name, subagent_depth, model_id, prompt_tokens, completion_tokens, prev_hash, and created_at. The parent_turn_id rollup key, subagent_depth, and prev_hash chain link are highlighted and gently pulse.HARNESS_AUDITABLE_CALLSone row · one model callSELECT *record_id01J9ZK7M…F2tenant_idacme_corpturn_idt_3f1a92parent_turn_idt_3f1a92tool_namesearch.websubagent_depth0model_idclaude-sonnet-4prompt_tokens1,180completion_tokens240prev_hash9af3c1…e7b1created_at2026-06-29T14:03Z
SELECT * FROM harness_auditable_calls
 ORDER BY created_at DESC LIMIT 1;
Every model call your agent makes appends exactly one row like this — to a table in your database. prev_hash links it to the call before it; subagent spend rolls up to parent_turn_id.

What you can do with it

We graded twenty agent-runtime capabilities against the market — Helicone, Langfuse, LangSmith, Portkey, LangGraph, Temporal, and the rest. These are the few the field admits it doesn't ship. The honest version, in both directions, is the landscape.

See every tool call and subagent, rolled up to the turn that caused it

Each LLM call writes one typed row keyed to the turn — which tool ran, how deep the subagent went, how many tokens it burned. Subagent spend rolls up to the parent turn as a stored field, not a trace-tree walk at query time. Per-customer billing then falls out of one SQL query.

Subagent & tool-call rollup

Replay any run, byte-identical

Same version, same input, same checkpoint replays exactly — across Node, Browser, and Edge — or strict mode throws and names the first event that diverged. Durable-execution platforms journal the output; most frameworks re-fire the call and may drift. This replays the path.

Determinism

A tamper-evident record only you hold

Every row lands in your Postgres with a prev-hash chain. Backfill or delete a row and the chain breaks at the verifier pass. No observability or gateway tool we surveyed ships a hash chain over the call log.

The hash chain

Routing that keeps replay honest

At session start the lock freezes the tokenizer, prompt-cache key, tool-call dialect, and refusal pattern. A transient fallback stays in the same family; any cross-provider change is logged on the row. Replay you can trust, because the lock keeps it valid.

Family-lock

Rewind to before the bad decision

Fork a session at any past event — not just a node boundary — then try a different path. Per-channel checkpoints make the rewind exact, so an agent can catch its own mistake instead of escalating.

Time-travel & fork
AuditableCall row schema — one row per LLM callEach LLM call lands as one row carrying tenant, turn, tool, subagent depth, model, and token usage. Subagent spawns roll back to the parent turn_id rather than stranding under the child session.tenant_idturn_idtool_namesubagent_depthmodel_idtoken_usage1acme_corpt_3f1a92search.web0sonnet-41,4202acme_corpt_3f1a92search.docs1haiku-4612subagent_depth = 1 rolls back to the parent turn_id, not the child session
SELECT tenant_id,
       SUM(token_usage) AS spend
  FROM harness_auditable_calls
 GROUP BY tenant_id, turn_id;
Two rows from the ledger. Row 2 is a subagent spawn — same turn_id as row 1, subagent_depth = 1. Finance reads the per-turn rollup as a single GROUP BY rather than stitching child sessions together after the fact.

How it works

Three structural decisions, not three best practices. Everything above reduces to these. A turn walks a fixed four-stage lattice — a shape a regulator can read off this page.

A turn walks a four-stage lattice

Each turn moves through anchor-plan, tool-loop, synthesize, and post-turn, under a discipline that fires exactly one final answer. The stages are a fixed shape a regulator can read off this page — which frees the audit row to carry what changes.

One append-only audit row per call

Each row carries the turn, the tool, the model, and the tokens, with subagent cost rolled up to the parent turn. Joinable to your billing or compliance schema today; replayable against the fingerprint stream.

Routing stays in one model family

Tokenizer, prompt-cache key, tool-call dialect, and refusal pattern freeze at session start. A transient fallback stays in-family; any cross-provider change is logged on the row.

The runtime is a contract, not a TypeScript surface — HTTP + SSE routes, the audit row, the checkpoint envelope, the version vector. @pleach/coreis the reference implementation; a Go implementation round-trips the same recorded turns, so the wire shapes aren't TypeScript-flavored. Read the contract or the architecture deep-dive.

Four-stage lattice: anchor-plan, tool-loop, synthesize, post-turnEvery turn flows through four stages in order. The flow is enforced in CI — out-of-lattice edges fail the build.01anchor-planFrame the turn02tool-loopFan out + iterate03synthesizeSingleton seamSINGLETON SEAM04post-turnFlush + close
Every node in @pleach/core sits in exactly one of these four stages. The audit:graph-stages CI gate fails the build on an out-of-lattice edge — the diagram is the invariant, not a best-practice diagram.

Should you stay where you are?

The honest version. If your shape fits one of these, reach for it — you'll ship faster. The full comparison adds LlamaIndex, Mastra, Goose, OpenHands, AutoGen, and CrewAI.

Multi-tenant SaaS, an audit-bound vertical, replay-as- regression-test, or the agent isthe product? That's the target. The same agent built four ways shows what you write yourself versus what the runtime hands you.

Vercel AI SDK

Reach for it when: A single-shot chat with tools. No persistence, no per-customer cost, no audit obligation.

Give up vs Pleach: No turn-keyed audit row, no replay determinism, no family-locked routing.

LangChain / LangGraph

Reach for it when: Chain abstractions, a large component catalog, hosted LangSmith for tracing.

Give up vs Pleach: Callbacks without shared row identity. Per-call cost is manual. No language-agnostic wire contract.

Claude Code / Goose

Reach for it when: A dev harness you run on your own machine — code review, refactor, terminal-native agents.

Give up vs Pleach: Single-user shell, not embeddable in a customer-facing SaaS. No multi-tenant audit.

Inngest / Trigger.dev

Reach for it when: Durable function chains, step-memoized retries, cron, fan-out, a hosted run dashboard.

Give up vs Pleach: Run history is the vendor's shape, not your billing schema. No family-lock, no hash chain. Use both — see Pleach + Inngest.

Which tool fits your shape — four shapes route to a faster tool; the multi-tenant, audit-bound shape routes to PleachEach row maps the shape of your agent on the left to the tool that fits it on the right. Single-shot chat, chain composition, a local dev harness, and durable function chains each have a tool that ships faster. The multi-tenant, audit-bound shape — where the agent is the product — is the Pleach target.IF YOUR SHAPE ISREACH FORSingle-shot chat + toolsVercel AI SDKno audit row · no replayChain compositionLangChain / LangGraphper-call cost is manualLocal dev harnessClaude Code / Goosesingle-user, not embeddableDurable function chainsInngest / Trigger.devvendor's run shape, no hash chainMulti-tenant, audit-bound SaaSthe agent is the productPleachthe target
Four shapes have a tool that ships faster — reach for it. The fifth row, where the agent is multi-tenant and audit-bound, is the one Pleach is built for. The table below carries the full what you give up detail.

Keep your stack

Already shipping on the AI SDK or LangChain? Add the audit row without a rewrite.

@pleach/observe is the brownfield entry point. Wrap the agent loop you already run in about fifteen lines and write one typed audit row per LLM call to a backend you pick. No runtime migration, no hosted control plane, no new vendor.

Wrap the loop you already have

It sits in front of the Vercel AI SDK, LangChain, the OpenAI or Anthropic SDK called directly, or a hand-rolled loop. Three moving parts: init, a per-turn recorder, one destination plug. BYOK observability →

Your storage, your control plane

The row lands in the destination you pass — your Postgres, Supabase, an OpenTelemetry collector, or an in-memory buffer. The OTel path is buyer-callback only: zero @opentelemetry/* runtime dependencies. @pleach/observe →

A runway, not a dead end

The ObserveRow is a strict subset of core's AuditableCall, so rows the SDK writes today stay valid rows the runtime reads tomorrow. Adopt @pleach/core later and the history comes with you — the migration is monotonic by construction. Adoption paths →

Per-customer attribution falls out of the row — (tenantId, turnId, toolName, model, tokens, costUSD) in one GROUP BY. Need replay determinism, family-locked routing, channels, or time-travel? Those live in the runtime, the greenfield path through @pleach/core. @pleach/observe is in alpha; the SDK layer stays free.

Your existing agent loop on top, the @pleach/observe hook in the middle, the destination you pick at the bottomYour agent loop stays where it is — the Vercel AI SDK, LangChain, the OpenAI or Anthropic SDK called directly, or a hand-rolled loop. The @pleach/observe SDK wraps it in about fifteen lines and writes one AuditableCall-subset row per LLM call. The row lands in the destination you pass: your Postgres, Supabase, an OpenTelemetry collector, or an in-memory buffer.YOUR AGENT LOOP · STAYS WHERE IT ISVercel AI SDK · LangChain · custom loopor the OpenAI / Anthropic SDK called directly~15 lines · no rewrite@pleach/observe · BROWNFIELD ENTRY POINTinit + per-turn recorder + destination plugone AuditableCall-subset row per LLM callDESTINATIONS YOU PICK · YOUR STORAGE, YOUR CONTROL PLANEPostgrespostgres()Supabasesupabase()OTel collectorotel()Memorymemory()
import { init, startTurn } from "@pleach/observe";
import { postgres } from "@pleach/observe/destinations";

init({ destination: postgres({ pgClient }) });

const turn = startTurn({ tenantId, sessionId });
await turn.recordCall({ model, tokens, costUSD });  // one row per call
await turn.end();
The loop you had before stays the loop you have now. The ObserveRowis a strict subset of core's AuditableCall, so rows the SDK writes today stay valid rows the runtime reads tomorrow — adopt @pleach/core later and the history comes with you.

Already paying the lab

On Anthropic or OpenAI Enterprise? Pleach composes underneath it.

Your contract keeps doing its job — SSO, ZDR, Workspaces or Projects, the Admin API, prompt caching, snapshot pinning. Pleach is an npm install plus a Postgres table you already run: no new vendor, no new SOC 2 boundary, no new ZDR review. It adds the three walls the contract doesn't cover.

Per-customer rollup inside one Workspace

The Admin API reports the Workspace or Project total — not the customers, teams, or cost centers inside it. The row carries an opaque tenant id on every call; wire it to whatever you bill or audit against. One GROUP BY, and the sums reconcile to the vendor total. Multi-tenant →

Tamper-evident row in your own DB

ZDR governs what the vendor stores. The downstream auditor asks about what you stored. Every row lands in your Postgres with a prev-hash chain that breaks at the verifier on any backfill or removal. Hash chain →

Replay across snapshots, not just inside one

A pinned snapshot doesn't make a turn replayable. The fingerprint records the inputs per turn, so drift between two snapshots surfaces as a diff in CI — early warning before a customer ticket. Determinism →

Bedrock, Azure OpenAI, or Vertex in the path? Same walls, different transport — cloud-mediated adapters land in @pleach/gateway. Two siblings ride the same contract footprint: the sandboxed coding agent and the language-agnostic contract that answers "is this TypeScript-only?" before IT asks.

Your enterprise contract on top, Pleach composing underneath, both writing into your own PostgresYour Anthropic or OpenAI Enterprise contract keeps doing its job — SSO, ZDR, Workspaces or Projects, the Admin API. Pleach is an npm install plus one Postgres table that adds three walls the contract does not cover: per-customer cost rollup, a tamper-evident hash-chain row, and replay across model snapshots. Both write into the database you already run.YOUR ENTERPRISE CONTRACT · KEEPS DOING ITS JOBAnthropic / OpenAI EnterpriseSSO · ZDR · Workspaces / Projects · Admin API · prompt cachecomposes underneathPLEACH · npm install + one table · adds three wallsWALL 1Per-customer rollupWALL 2Hash-chain rowWALL 3Replay across snapshotsYOUR POSTGRES · NO NEW VENDORharness_auditable_callsone opaque tenant_id per call · sums reconcile to vendor total
SELECT tenant_id,
       SUM(token_usage) AS spend
  FROM harness_auditable_calls
 WHERE workspace_id = 'ws_acme'   -- one Admin-API Workspace
 GROUP BY tenant_id;              -- sums reconcile to the vendor total
The contract reports the workspace total. Pleach adds the tenant_id on every row, so one GROUP BY tells you which customer caused it — and the per-customer sums add back up to what the Admin API billed.

Quick answers

The short version. The full FAQ covers the rest.

Built so an agent can read its own history and rewind itself — the same typed rows and checkpoints a developer reads. The docs render to /llms.txt and /llms-full.txt.

What is Pleach?
Pleach is a free, fair-source agent runtime. Every LLM call your agent makes writes one typed row to a database you own — which gives you per-customer cost, compliance you can query in SQL, and deterministic replay. @pleach/core is the TypeScript runtime, in production today.
How does Pleach attribute LLM cost per customer?
Every audit row carries which tenant, which turn, which model, and how many tokens — with subagent spend rolled up to the turn that caused it. Per-customer billing falls out of one SQL GROUP BY, not a separate cost pipeline.
Already on Anthropic Enterprise or OpenAI Enterprise — what does Pleach add?
It composes underneath. Your contract keeps doing its job; Pleach adds per-customer cost rollup inside one Workspace or Project, a tamper-evident audit row in your own Postgres, and replay across model snapshots. No new vendor — an npm install plus a table. See /docs/migrating-from-anthropic-enterprise.
What license does Pleach use? Is it open source?
Fair source — FSL-1.1-Apache-2.0. Source-available, free in production. Each release converts to Apache-2.0 two years after it ships. Not OSI-approved open source during that window.
How is Pleach different from the AI SDK or LangChain?
They ship faster for single-shot agents and broad chain composition. Pleach is the runtime when the agent is the product: per-customer cost, deterministic replay, time-travel checkpoints, and a typed audit row joinable to your billing and compliance schemas. See /docs/comparison.
Session manifest — the ordered, append-only event log an agent reads back and forks fromSeven events on a spine: session start, turn start, a tool call and its result, a checkpoint that is the fork point, a subagent spawn, and the final answer. The checkpoint node gently pulses. Replay or fork the session from any event.SESSION_MANIFEST · APPEND-ONLYs_91c… · ordered by seqwhat the agent reads001session.startchannel: main002turn.startt_3f1a92003tool.callsearch.web004tool.result1,180 tok005checkpointckpt_7 · fork point006subagent.spawndepth 1007turn.finalone answer
SELECT seq, event, payload
  FROM session_manifest
 WHERE session_id = 's_91c'
 ORDER BY seq;
The manifest is append-only and ordered by seq. An agent reads it back to know what it did; you replay or fork from any event — ckpt_7 makes the rewind exact.