Crux
API Reference@use-crux/core

Execution evidence

Author and inspect qualified evidence relationships for Crux executions and artifacts.

import {
  evidence,
  CruxEvidenceError,
  type EvidenceRecordInput,
  type EvidenceRef,
  type EvidenceView,
} from "@use-crux/core/evidence";

Execution evidence records a qualified relationship between a source and the execution or artifact it describes. It answers one of five fixed questions:

RoleQuestionConclusions
intentWhy was this attempted?None; intent is provenance, not a verdict
authorityWhy was it allowed or denied?allowed, denied, revoked, inconclusive
changeWhat state transition occurred?applied, partial, no-change, unknown
verificationHow was it checked?passed, failed, inconclusive
recoveryWas mitigation available or attempted?available, unavailable, succeeded, failed, partial

Evidence is not an artifact payload, an observability edge, or a claim that delivery is durable. A stable EvidenceRef identifies the relationship while Core projects its source and subject into the canonical observability graph.

Crux automatically authors selected native intent, authority, and change evidence. Start with the execution-evidence guide and use this API for advanced domain claims that have an exact subject and no native producer.

Record inline evidence

Use a non-empty custom.* kind for inline JSON evidence:

const review = evidence.record({
  role: "verification",
  conclusion: "passed",
  kind: "custom.editorial-review",
  data: {
    approved: true,
    checks: ["citations", "tone"],
  },
});

record() is synchronous. It validates and accepts the relationship into the active Core scope, then returns a frozen EvidenceRef. Delivery through the configured observability transport remains asynchronous and failure-isolated. The ref does not prove that a remote destination committed the record.

Inside a Crux execution, omit subject to describe the current span, or the current run when no span is active. Outside a Crux execution, pass an explicit execution or artifact:

const review = evidence.record({
  subject: { kind: "artifact", id: artifactId },
  role: "verification",
  conclusion: "passed",
  kind: "custom.editorial-review",
  data: { approved: true },
});

An explicit call outside an execution opens a small evidence.record observability scope automatically.

Use ref to qualify an existing artifact or execution without copying its payload:

const verification = evidence.record({
  subject: { kind: "execution", id: runId },
  role: "verification",
  conclusion: "passed",
  ref: { kind: "artifact", id: scoreArtifactId },
  kind: "score.report",
});

kind may be omitted only when Core can resolve trusted local metadata synchronously. Pass it when linking an artifact from another process or destination.

The public subject union accepts Crux-issued effect.receipt refs from the Effects API. Effects automatically author receipt-safe intent, change, and recovery evidence. Custom records may use the same receipt as an explicit subject; unresolved or malformed receipt refs are rejected.

Inspect evidence

Inspect before the owning scope closes for immediate read-your-writes:

const view = await evidence.inspect(review.subject, {
  role: "verification",
  includeData: true,
  includeHistory: true,
  limit: 25,
});

view.roles.verification.status;
view.roles.verification.records;

Every EvidenceView has all five role slots. Selecting role hydrates rows for that role while the other slots retain bounded aggregate state. limit must be an integer from 1 through 50; Core rejects larger values instead of clamping. A returned cursor is opaque and is valid only for the same subject, selected role, and history mode.

After the owning scope seals, inspection requires a configured canonical observability transport with an evidence.inspectEvidence() capability. Core captures that destination when inspect() is called, validates every returned row and aggregate, and conservatively merges it with any active-scope snapshot. Crux Local implements this capability with a durable, restart-safe read model. Devtools, the Local Go API client, and Core's Local HTTP transport consume that same model.

Each destination role includes a required status summary computed from the complete authorized active set before row hydration, pagination, or history selection. It also includes activeRecordCount, the exact authorized count of retained, active, non-superseded relationships for that role. Both values stay stable when a role is not selected and across cursor pages. present means a usable relationship representation exists; it does not promise that inline data is retained, authorized, or requested.

Crux Local also exposes bounded, positional batch reads for Devtools: complete active counts for up to 100 subjects and exact retained navigation for up to 100 canonical graph refs. Related Evidence waits for every subject-count chunk before showing an exact total. Navigation returns persisted run, span, or artifact-owner provenance and retained DefinitionRefs; it never substitutes a live Catalog lookup for historical source data.

Local inspection follows the existing same-user Devtools access model: headerless loopback access is allowed, while non-loopback browser access uses the Devtools session capability. CRUX_DEVTOOLS_TOKEN remains ingest-only; an ingest bearer does not authorize evidence inspection.

Missing and conflicting states

A role status describes what the current source can prove:

StatusMeaning
presentAt least one usable active relationship is available or referenced; inline data may still be omitted
not-yet-recordedNo relationship or explicit coverage fact is visible
not-configuredA producer or destination explicitly reports no configured producer
not-applicableA producer or destination explicitly reports that the role does not apply
not-capturedCapture policy intentionally retained no source content
redactedPrivacy policy removed the usable source

“Active” means “not explicitly superseded,” not “newest.” Replace an earlier same-subject, same-role relationship explicitly:

const corrected = evidence.record({
  role: "verification",
  conclusion: "failed",
  kind: "custom.editorial-review",
  data: { approved: false },
  supersedes: review,
});

Timestamps do not choose a winner. If active classified records disagree, conflicting is true, the records remain visible, and the aggregate conclusion is omitted. includeHistory: true returns explicitly superseded rows separately.

Capture and privacy

Inline data passes through the existing observability capture and privacy policy before the collector, Eval capture, subscribers, or transport sees it. includeData: true requests retained data but never overrides policy.

payloadStateRetained data
availableThe exact safe preview after configured redaction
referenceNo inline data; only reference-level capture remains
not-capturedCapture is off
redactedPrivacy policy removed the preview or rejected the graph batch

A preview containing [redacted] markers remains available: safe content is still present. If privacy rejects either the inline artifact or its evidence.for edge, Core publishes neither half, retains no data, and records the local relationship as redacted.

Raw idempotency keys, inline data, paths, authorization details, and arbitrary resource metadata never appear on the qualified edge.

Local retention

Crux Local retains relationships independently from routine runs. Relationship retention defaults to the normalized observability retention age, currently 14 days; CRUX_EVIDENCE_RETENTION_DAYS overrides it. Payload retention defaults to the relationship window and can be shortened with CRUX_EVIDENCE_PAYLOAD_RETENTION_DAYS.

An expired formerly available payload returns payloadState: "redacted" with optional payloadUnavailableReason: "retention" and no data. The relationship, conclusion, source identity, and conflict behavior remain until relationship expiry. Retries never refresh or restore expired content. Durable first-write-wins lasts for the configured relationship-retention window.

Idempotent retries

Pass a stable bounded key when the same logical authoring call may retry:

const ref = evidence.record({
  role: "change",
  conclusion: "applied",
  kind: "custom.cms-publication",
  data: { revision: 42 },
  idempotencyKey: `publish:${operationId}`,
});

Within one active collector, an identical retry returns the original frozen ref and emits nothing again. Reusing the identity with different post-policy content throws EVIDENCE_IDEMPOTENCY_CONFLICT. The raw key is never returned or emitted; only a one-way bounded digest may appear in qualified graph metadata. Across process restarts, durable deduplication belongs to the readable destination.

Errors

Evidence failures use CruxEvidenceError. Each error includes code, whatFailed, why, whatStillWorks, nextStep, and a stable docsUrl. Use CruxEvidenceError.isInstance(error) when multiple copies of Core may be installed. Local delivery dispositions use the same evidence error catalog.

CodeCause
EVIDENCE_INPUT_INVALIDA record, option, or destination shape is invalid
EVIDENCE_SUBJECT_REQUIREDNo explicit or ambient subject exists
EVIDENCE_SUBJECT_NOT_FOUNDA readable destination cannot find the subject
EVIDENCE_KIND_INVALIDThe kind is invalid or cannot be resolved locally
EVIDENCE_CONCLUSION_INVALIDThe conclusion does not belong to the selected role
EVIDENCE_REFERENCE_INVALIDA subject or source cannot map to a canonical reference
EVIDENCE_SUPERSESSION_INVALIDSupersession is duplicated, mismatched, self-referential, or cyclic
EVIDENCE_IDEMPOTENCY_CONFLICTOne visible retry identity has different immutable content
EVIDENCE_WRITE_QUARANTINEDA closed Eval cell rejected a late authoring call
EVIDENCE_QUERY_UNAVAILABLENeither an active collector nor readable destination can answer
EVIDENCE_CURSOR_INVALIDThe cursor is empty, oversized, stale, or bound to another query
EVIDENCE_ACCESS_DENIEDThe readable destination denied the query

All exports are available from both @use-crux/core and @use-crux/core/evidence. See Observability for the canonical artifact and evidence.for projection.

On this page