Crux
API Reference@use-crux/core

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.

On this page