Thread
Durable provider-neutral conversation history with atomic turns, branches, edits, redaction, and deletion.
import { thread } from "@use-crux/core/thread";thread() stores canonical Crux messages independently of any model provider.
History is immutable: appends publish new causal groups, edits create sibling
revisions, and selection moves the active head without rewriting prior nodes.
For the mental model, storage choices, managed-turn lifecycle, branch UI, and erasure decisions, start with the Threads guides.
Create and bind a Thread
import { prompt } from "@use-crux/core";
import { thread } from "@use-crux/core/thread";
const conversation = thread({
id: "support-42",
storage,
});
const support = prompt({
id: "support",
use: [conversation],
prompt: ({ input }) => input.question,
});Omit storage to use the config({ storage }) bundle. A Prompt graph may
contain exactly one Thread. Managed Prompt and Agent execution reads the
selected history once, sends that exact revision to the provider, then appends
the rendered user turn and accepted assistant/tool exchange atomically. The
operation result exposes the publication receipt as threadCommit.
Call-site messages and Prompt-level messages shadow the Thread for that
invocation, in that order. Crux uses the first complete transcript and never
merges sources; a caller-owned transcript does not imply a Thread commit.
A bare Thread remains complete exact history. Add history.recent() or
history() to opt into a bounded projection; Crux never applies an implicit
recent window. Managed summary artifacts use the Thread revision and selected
message range as their source identity. Sealed request plans pin that revision,
so an intervening edit, selection, redaction, or deletion fails before provider
dispatch instead of replaying a stale plan.
Append and read
const commit = await conversation.append([
{ id: "question", role: "user", content: "Can I change my plan?" },
{ id: "answer", role: "assistant", content: "Yes." },
]);
const snapshot = await conversation.read();Caller-supplied message IDs make identical retries replay-safe. Reusing an ID with different content or at a different parent is rejected. A multi-message append is one causal group and is never split by pagination.
await conversation.read({ at: "answer" }); // exact structural prefix
await conversation.read({ limit: 20 }); // whole-group page
await conversation.read({ before: snapshot.cursor });ThreadSnapshot.entries contains live messages plus structural removed or
redacted entries where applicable. Media is persisted through the Thread's
AssetStore and automatically hydrated when read.
Branches, edits, and selection
Appending after an earlier message creates a durable alternative when that parent is no longer the selected head:
await conversation.append(
{ id: "alternative", role: "assistant", content: "A different answer." },
{ after: "question" },
);Edit a user message to create and select an immutable sibling revision:
const edit = await conversation.edit("question", {
id: "question-v2",
content: "Can I change my annual plan?",
});
await conversation.select("answer");Reads expose deterministic variant navigation metadata for siblings.
select() accepts an existing sibling or ancestor and restores its remembered
continuation when one exists.
Redaction and deletion
await conversation.redact(["question", "answer"]);
await conversation.delete();Redaction irreversibly erases message provenance and Thread-owned assets while retaining the minimum structural tombstone needed to preserve graph safety. Redacted IDs cannot be replayed or edited.
Deletion is idempotent and publishes inaccessibility before cleanup. It rejects
with ThreadInUseError while a durable owner is registered. After deletion,
history operations fail with the deleted Thread error code.
Observability and devtools
Append, read, edit, select, redact, and delete emit thread.operation spans
with structural IDs, roles, counts, state changes, and commit decisions.
Message content is not placed in span attributes.
In development, each authored Thread registers a payload-safe Runtime Bridge resource. Devtools can inspect its tree, causal groups, branch points, and owner heads without receiving message content.
Errors
Thread failures use stable codes: invalid_message, invalid_group,
identity_conflict, commit_failed, not_found, redacted,
unsupported_capability, in_use, and deleted. Managed publication
failures reject with ThreadCommitError; a
successful provider result is never reported as fully accepted when its Thread
turn could not be committed.
Related
- Guide: Threads
- Guide: Managed conversations
- Guide: Branching and alternatives
- Guide: Removal, redaction, and deletion
- Reference: Request history