Decisions
Internal "when to use X vs Y" aids — Session vs Turn vs Subagent, Ledger vs Observability, Scrubber vs ComplianceRuntime, and the rest of the close-cousin pairs.
Pleach ships a handful of close-cousin primitives that often collapse into one in a reader's head. Different branches of the same lattice — looking similar from a distance, doing different work at the joint. This page is the catalog of "when to reach for which" — short answers with links to the deeper page on each side.
If your question is "do I need this SKU at all?" — see Which SKU do I need?. If it's "Pleach vs. another framework" — see Comparison. This page is for choices inside Pleach.
Session vs Turn vs Subagent
The three substrate-grain levels. They nest: Session → Turn → Subagent.
| Concept | Lifetime | What it represents | Reach for |
|---|---|---|---|
| Session | Long-lived (days / months) | One user × one product surface. Holds channels, storage, family-lock, the event log. | Persisting conversation state across pages, processes, and clients. Per-user resource attribution. |
| Turn | One round-trip | One user-message-in / one-answer-out cycle. Walks the four stages. | Auditing what one user message cost. The grain of the AuditableCall row. |
| Subagent | Inside a turn | A specialist sub-call spawned by the root turn — research / verify / refactor / etc. Rolls up to parent turnId. | Decomposing one user message into parallel specialist tasks; bounded fan-out with cost ceiling. |
A real example: a user types "summarize this PDF and email me
the key risks." That's 1 session, 1 turn, N subagents (one
to read the PDF, one to extract risks, one to draft the email).
All N subagent rows roll up to the same turnId.
Read: SessionRuntime · Turn lifecycle · Subagents.
Ledger vs Observability vs Eval
Three observability planes that look identical from a distance.
| Plane | Grain | Latency | Reach for |
|---|---|---|---|
AuditableCall ledger | One row per LLM call, keyed by turnId | Write-time | Per-tenant cost rollup, compliance review, regulator-shaped queries. Joinable to your billing in one GROUP BY. |
| OTel spans | One span per stage / tool / call, with parent threading | Sampled, async | Distributed tracing, latency profiling, error correlation across services. Pipes to Honeycomb, Tempo, Datadog. |
| Eval / replay | Fixture-driven regression run against the recorded ledger | Offline | "Does this change regress against my golden corpus?" CI-runnable scoring with Welch t-test. |
You usually want all three. The ledger is structural (every turn writes); OTel is sampled (only some make it to your backend); evals are explicit (you run them in CI). They don't replace each other.
Read: Audit ledger · OTel observability · Eval · Replay.
Scrubber vs ComplianceRuntime
Both fire on the path from runtime to event log. They cover different shapes.
| Primitive | Where it lives | What it transforms | Reach for |
|---|---|---|---|
Scrubber | @pleach/core/scrubbers contract; concrete instances in @pleach/compliance | Field-level: regex / Luhn / dictionary scrub on a string value (SSN, CC, driver license, custom keyed regex) | Surgical PII / PHI removal at the field level. Composable into bundles per regulatory profile. |
ComplianceRuntime | @pleach/compliance-contract (interface) + @pleach/compliance (impl) | Whole-profile: assembles the right scrubber bundle for HIPAA / GDPR / PCI-DSS / SOC2 and wires it into EventLogWriter | Profile-driven compliance posture — pass { profile: "HIPAA" } and get the canonical scrubber set + attestation hooks without enumerating individual scrubbers. |
You compose Scrubbers when you want bespoke control. You
hand the ComplianceRuntime a profile when you want the
canonical answer. Both are real — neither is sugar over the
other.
Read: Scrubbers · Compliance.
Recipe vs direct SessionRuntime
Same substrate, different abstraction layer.
| Path | What you write | What you give up | Reach for |
|---|---|---|---|
@pleach/recipes factory (simpleChatbot, ragChatbot, compliantChatbot, verticalAgent, subagentSwarm, enterpriseAgent) | One function call with a config object | Fine-grained channel registration, custom interrupt managers, novel plugin compositions | Use-case-shaped agents that match a known pattern. Under 100 lines of glue. |
new SessionRuntime(...) | Full constructor + channel registry + plugin set + interrupt manager + extension loader | Boilerplate; choice paralysis on what to actually wire | Novel agent shapes, multi-tenant SaaS, regulated deployment, custom transport. |
The recipes are the same SessionRuntime underneath — they're
not a separate runtime. You can always reach into
recipe.runtime for direct access. Start with the recipe;
graduate to the constructor when you outgrow it.
Read: Recipes · Runtime construction.
AiSdkProvider vs AnthropicSdkProvider vs AgentProvider
Three transport-layer choices.
| Provider | Wraps | Reach for |
|---|---|---|
AiSdkProvider | streamText from ai@6.x | Unified provider switching via OpenRouter or any @ai-sdk/<vendor> package. The recommended default. |
AnthropicSdkProvider | @anthropic-ai/sdk directly | Native Anthropic features without a wrapper — prompt caching, extended thinking, tool-use beta flags. |
AgentProvider (your own) | Anything that streams | OpenAI directly, a custom gateway, a local Ollama, a proprietary vendor — implement one interface. |
Most projects pick AiSdkProvider with OpenRouter — one key,
six families, identical request shape. The other two exist
because some teams need them. See
Providers for the swap pattern and config
matrix.
Memory vs Storage vs Checkpointer
Three persistence layers that all touch the database.
| Layer | What it persists | When it writes | Reach for |
|---|---|---|---|
| Memory | Long-term cross-session facts the agent should recall | Explicit memory.store() calls in your plugin | RAG-shaped recall across sessions; user preferences; learned habits. |
Storage (StorageAdapter) | Per-session state — messages, channels, the event log | Every turn, automatically | The session as a unit. Resume across processes / clients via version-vector sync. |
Checkpointer (Checkpointer) | Snapshots of channel state at each superstep | Per-step within a turn | Time-travel debugging, replay-deterministic regression, interrupt-resume. |
Storage is mandatory (MemoryAdapter for tests; SupabaseAdapter
for prod). Checkpointer is optional but required for time travel.
Memory is a separate concern entirely — agent-facing, not
infrastructure.
Read: Memory · Storage · Checkpointing · Time travel.
Channels vs Event log vs Stream events
Three event surfaces that look related but serve different audiences.
| Surface | Audience | Shape | Reach for |
|---|---|---|---|
| Channels | The graph engine itself | Reactive write-many / read-once values inside a turn | Wiring graph nodes; coordinating between stages within one turn. Internal. |
| Event log | Your audit / billing / compliance pipeline | Append-only typed StreamEvent rows in your DB | Per-tenant cost rollup, regulator-shaped queries, replay determinism. Durable. |
| Stream events | The client (browser / mobile / CLI) | The same StreamEvent discriminated union, served as NDJSON / SSE | Rendering streaming UI, driving useChat, building custom transports. Wire-level. |
The event log and the stream-events wire are the SAME typed union; the difference is durability vs transport. Channels are internal — you don't read them from outside the graph.
Read: Channels · Event log · Stream events.
Plugin contract vs Plugin bundle
A composition question.
| Shape | What you author | Reach for |
|---|---|---|
| Single-facet plugin (flat) | One definePleachPlugin({ ... }) const with all hooks inline | Quick scaffold; one-facet plugins (just prompts, just tools, just safety). |
| Multi-facet bundle | Multiple definePleachPlugin({ facet: "prompts" }) consts composed into an array | Bigger plugins where each facet (prompts + safety + tools) can be reviewed / tested / shipped independently. The default pleach init template. |
Bundles aren't required — the runtime accepts a single plugin and N composed plugins identically. But review surface scales better when prompts.ts and safety.ts are separate files.
Read: Plugin contract · Plugin bundles · Plugin authoring standards.
Coding-agent SKU vs DIY tool wiring
Pleach ships @pleach/coding-agent as a SKU. You also have
@pleach/tools + @pleach/sandbox to roll your own.
| Path | What you get | Reach for |
|---|---|---|
@pleach/coding-agent | SWE-bench-shaped runtime — start() / stop() / executeStep() + LRU CodingContextManager for file-context budget management. | A coding agent that matches the SWE-bench shape; benchmark adapters; out-of-the-box file-context budgeting. |
| Tools + sandbox, hand-wired | Compose @pleach/tools definitions with @pleach/sandbox execution; full control over context management | Coding agents with bespoke context-management strategies, multi-language sandboxes, or non-SWE-bench-shaped flows. |
The SKU is a specific opinionated shape. The hand-wired path gives up that opinionation for flexibility.
Read: @pleach/coding-agent ·
Tools · @pleach/sandbox.
Where to go next
Which SKU do I need?
Decide which @pleach/* packages to install for what you're building.
Comparison
How @pleach/* compares to AI SDK, LangChain, Mastra, and other harnesses.
Concept clusters
The full concept map of the substrate — seven cluster triplets at four depths.
Glossary
Canonical terms — anchor-plan, CallClass, family-lock, seam, and the rest of the vocabulary.
Ownership boundaries
Per SKU, what the package owns, what you configure, and what you must supply. The single-page map of where the substrate ends and your code begins.
Comparison
How @pleach/core compares to the AI SDK, LangChain, LlamaIndex, Mastra, and to agent harnesses like Claude Code, Goose, OpenHands, AutoGen, and CrewAI.