pleach
Operate

What Pleach writes to your database

Every table the runtime and its plugins write — what's on by default, what you opt into, and what each row carries. The destination is your database, not ours.

The runtime writes to your database. Point it at your Postgres, your Supabase project, an OpenTelemetry collector, or an in-memory buffer, and that's where the rows land — your storage, your control plane. The package has no phone-home: nothing it persists leaves the destination you configure.

This page is the data-emission map. It answers two questions: what appears in your database when you run Pleach, and which of it is on by default versus enabled by a config flag or a plugin.

For the column-by-column schema, see Schema. This page is the lens above it — what gets written, and why.

The destination is yours

With the Memory storage adapter, nothing is persisted at all — rows live in process and vanish on restart. With a Postgres or Supabase adapter, the tables below are created in your database and written by the adapter you configured. The @pleach/observe SDK widens the destination set further — the same audit rows can go to your OTel collector instead of a SQL table.

Nothing is written to a Pleach-operated service. The runtime is a library; the storage is a target you own.

What gets written

The package writes two primary streams plus a set of substrate and plugin tables. Each row below names the table, when it's written, and what enables it.

TableWritten whenEnabled by
harness_sessionsA session is created or its state changesA persistent storage adapter (default for Postgres / Supabase)
harness_event_logEvery observable event during a turnThe event log — on with a persistent adapter
harness_auditable_callsOne row per LLM callThe audit ledger adapter
harness_config_manifestOnce per session, content-addressedThe config manifest substrate
harness_checkpointsAt stage boundariesCheckpointing enabled
harness_outboxA mutation is buffered for the backendSync enabled
harness_errorsA structured error firesenableErrorPropagation: true on the runtime
chat_session_linksA session binds to an upstream chatSessionRuntimeConfig.chatId set
harness_audit_recordsA cross-cutting audit record is logged@pleach/compliance or a custom audit hook
harness_session_membersA user is granted session accessMulti-user sessions (useTeam)
harness_session_commentsA comment is posted on a sessionOptional surface; the runtime never writes it
pleach_gateway_cost_eventsA routed call resolves a cost@pleach/gateway cost attribution
pleach_byok_credentialsA tenant key is stored@pleach/gateway BYOK

The two write streams

Most of what the runtime emits lands in one of two streams, and the distinction matters when you decide what to retain.

The audit ledger (harness_auditable_calls) records load-bearing decisions — which model fired, why it was chosen, what it cost, whether the cache hit. One row per LLM call, joinable to your billing schema by tenantId and turnId. This is the stream you query for cost and compliance.

The event log (harness_event_log) records what happened — messages sent, tools dispatched, interrupts raised, subagents spawned, exports queued. Append-only, ULID-keyed. This is the stream you hydrate a session from and replay through @pleach/eval.

The config manifest sits beside the event log: each event-log row references the manifest_hash of the substrate that produced it, so the two together are a complete, offline-replayable record.

What's opt-in

The substrate tables — sessions, the event log, the audit ledger, the config manifest — are the runtime's working state with a persistent adapter. The rest is something you turn on:

  • Checkpointing writes harness_checkpoints only when you enable it. Off means no per-stage snapshots.
  • Sync writes harness_outbox only when the durable-sync outbox is configured. Off means writes go straight to the adapter with no buffering table.
  • Error propagation writes harness_errors only under enableErrorPropagation: true. Off means errors surface as stream events without a persisted table.
  • Compliance records (harness_audit_records) are written by @pleach/compliance and custom audit hooks — nothing lands here unless a plugin writes it.
  • Gateway tables (pleach_gateway_cost_events, pleach_byok_credentials) exist only when you run @pleach/gateway.
  • Team and comment tables (harness_session_members, harness_session_comments) are written only by the multi-user surfaces, never by a single-user runtime.

What's in the rows — and what isn't

Rows carry runtime metadata: identifiers, timestamps, event types, model and cost fields, content hashes. Message content and tool payloads land in the event log when you persist them; the audit ledger stores decision metadata, not prompt bodies.

Before any PII-adjacent field is persisted, the compliance scrubbers can redact it on the write path — the redaction is applied to the row, not bolted on at read time. Tenant isolation is enforced by the RLS template every table ships, keyed on tenant_id or organization_id.

What never gets written: telemetry to a Pleach service, usage beacons, license-check pings. The runtime doesn't call home. See Security for the full posture.

Where to go next

On this page