Crux
API Reference@crux/core

@crux/core

The base Crux package — package overview, config, registry API, and shared utilities.

@crux/core is the base package — every Crux project depends on it. It contains all SDK-agnostic primitives organized into subpath exports. Pick the subpath page that matches what you need:

TypeScript compatibility

@crux/core is tested with TypeScript >=5.5 <7. Crux also runs a TypeScript 7 native-preview check with @typescript/native-preview / tsgo, but that is a preview signal rather than a stable support promise.

The public type surface is kept compatible with TypeScript 5.5 so projects do not need the newest compiler just to use Crux definitions.

Prompts

prompt, createPrompts, the Prompt type.

Contexts

context, when, match, createContexts.

Tools

tool and SDK-agnostic ToolDef authoring.

Tool Middleware

toolMiddleware, approvalMiddleware, resumable approvals.

Adapter Interface

adapter, executorAdapter, AdapterSpec, ExecutorSpec, and conformance harnesses.

Cache

createSemanticCache and semantic cache policies.

Retrieval

retriever, reranker, query-time context and tools.

Citations

grounding, citationConstraint, resolveCitations.

Indexing

indexer, corpus, canonical documents/chunks, write-time embedding.

Memory

memory, memoryBlock, recentMessages, workingState, episodes, facts, procedures.

Compaction

createSlidingWindow, createBudgetManager, summarizeMessages, extractKeyFacts.

Agent

agent, blackboard, handoff, delegate, compositions.

Flow

flow, signalFlow, cancelFlow, listFlows.

Plan

plan, getPlan, updatePlan, planAgent.

Tasks

tasklist, taskListAgent, taskWorker.

Skill

skill.inline, skill.fromFile, skill.fromRegistry.

Safety

guardrail and constraint primitives for I/O safety and semantic validation.

Scoring

llmJudge, prebuilt metrics, and judgeConstraint for enforcing judge scores as constraints.

Quality

quality, suite, expect, target, cassette, constraintScorer, and persisted local experiments.

Storage

DataStore, VectorStore, BlobStore, and compatibility store interfaces.

Project Index

Design-plane definitions, relations, source locations, and diagnostics.

Index Lint

Lint config, findings, rule metadata, and suppressions.

Runtime Bridge

Local-dev command-plane schemas and helpers.

Devtools Plugin

withDevtools and enableDevtools.

Subpath imports

import { prompt, context, createPrompts, createContexts, config, when, match } from '@crux/core'
import { tool } from '@crux/core/tools'
import { toolMiddleware, approvalMiddleware } from '@crux/core/tool-middleware'
import { adapter, executorAdapter, defineProviderRuntime } from '@crux/core/adapter'
import { transcriptCodecConformance } from '@crux/core/adapter/testing'
import { memory, workingState, episodes, facts, procedures } from '@crux/core/memory'
import { createSlidingWindow, createBudgetManager, extractKeyFacts, summarizeMessages } from '@crux/core/compaction'
import { agent, blackboard, handoff, delegate } from '@crux/core/agent'
import { flow, signalFlow, cancelFlow, listFlows, createFlowId } from '@crux/core/flow'
import { plan, getPlan, updatePlan, planAgent, createPlanTool } from '@crux/core/plan'
import { tasklist, taskListAgent, taskWorker, createTaskListTool } from '@crux/core/tasks'
import { skill } from '@crux/core/skill'
import { guardrail } from '@crux/core/safety'
import { constraint } from '@crux/core/safety'
import { llmJudge, metrics, judgeConstraint } from '@crux/core/scoring'
import { constraintScorer, expect, quality, suite, target } from '@crux/core/quality'
import { createSemanticCache, semanticCachePolicies } from '@crux/core/cache'
import { embedding } from '@crux/core/embedding'
import { retriever, reranker } from '@crux/core/retrieval'
import { grounding, citationSchema } from '@crux/core/citations'
import { corpus, indexer } from '@crux/core/indexing'
import { CruxProvider, usePlan, useTaskList, useTasks, createSSETransport, createPollingTransport } from '@crux/react'
import { cruxSSEHandler } from '@crux/react/server'
import { withDevtools } from '@crux/core/observability'
import type { ProjectIndexSnapshot } from '@crux/core/project-index'
import { serializeProjectIndex } from '@crux/core/project-index/serializers'
import type { CruxIndexerConfig, CruxLintConfig, ToolContentPart, ToolModelOutput, ToModelOutputArgs } from '@crux/core'

Tooling Config

config() can store inert configuration for local Crux tooling. For Project Indexer extensions, use the indexer bag:

config({
  indexer: {
    extensions: [{ package: '@acme/crux-indexer', export: 'default', version: '^1.0.0' }],
    trust: { mode: 'allowlisted', allow: ['@acme/crux-indexer'] },
  },
  experimental: {
    indexer: {
      native: true,
    },
  },
})

Core stores this data only. @crux/indexer owns extension trust checks, compatibility checks, loading, compiler execution, and diagnostics.

experimental.indexer.native enables the native semantic Project Index backend. The field accepts true, false, or { engine?: 'tsgo'; tsserverPath?: string }:

config({
  experimental: {
    indexer: {
      native: {
        engine: 'tsgo',
        tsserverPath: '/path/to/tsgo',
      },
    },
  },
})

Omit the field to use the default JavaScript typescript compiler API backend. The native backend is experimental because the current TypeScript-Go engine depends on the unstable upstream native-preview API; Crux expects supported semantic facts to match the default backend without a JavaScript TypeScript semantic fallback.

TypeScript Guarantees

Crux APIs are designed to preserve inference across composition. Context input schemas merge into prompt() inputs, grounded retrieval composes through use, and retriever tool names are typed for common manual cases:

const brand = context({
  input: z.object({ brandVoice: z.string() }),
  system: ({ input }) => `Voice: ${input.brandVoice}`,
})

const answer = prompt({
  use: [brand],
  input: z.object({ question: z.string() }),
  system: ({ input }) => input.question,
})

answer.resolve({
  input: {
    question: 'How do refunds work?',
    brandVoice: 'Concise and direct',
  },
})

const tools = docs.asTools({
  prefix: 'docs',
  include: ['search', 'getSource'],
})

tools.docsSearch
tools.docsGetSource

@crux/core also has a package-local typecheck task that runs strict TypeScript plus compile-time API tests. New production any usage is blocked by an explicit-any checker; existing legacy entries are tracked as debt and should only shrink.

config(config)

The single entry point for configuring Crux project policy and explicit runtime behavior. It applies immediately when the config file is imported. Module caching ensures it runs once per process.

Prompt, context, tool, and registry definitions are authored in normal TypeScript modules and discovered from source by local tooling. They are not repeated in config().

DomainTypeDescription
qualityQualityConfigLocal quality discovery, persistence root, redaction, and run defaults.
lintCruxLintConfigProject Index lint profile and rule overrides.
indexerCruxIndexerConfigExtension references, extension trust policy, and indexer rule options.
experimentalCruxExperimentalConfigUnstable opt-in tooling features such as the TypeScript-Go semantic indexer backend.
persistence.storeCruxStoreExplicit runtime persistence for flows, plans, and bridge reads.
generation.middlewarePromptMiddlewareGlobal generate/stream wrapper.
generation.tokenizer(text: string) => numberCustom token counting.
generation.autoEscapebooleanAuto-escape XML-like user input. Defaults to true.
generation.securityWarningsbooleanWarn on suspicious input patterns. Defaults to development-only.
devtoolsCruxDevtoolsConfigNon-default local, tunnel, remote, or Runtime Bridge behavior.
observabilityCruxObservabilityConfigExplicit observability export or custom transport behavior.
pluginsCruxPlugin[]Composable runtime extensions.

Returns: Crux — exposes the raw .config, lifecycle .dispose(), and compatibility registry methods. Source-discovered projects should use their authored prompt/context exports directly rather than looking them up through config(). | .config | Readonly<CruxConfig> | | .dispose() | Tear down middleware, devtools, globals |

CruxEvalConfig

FieldTypeDefaultDescription
includestring | string[]requiredGlob pattern(s) for prompt eval files
flowIncludestring | string[]Glob pattern(s) for flow eval files
ragIncludestring | string[]Glob pattern(s) for RAG eval files
suiteIncludestring | string[]Glob pattern(s) for code or JSON suite files
concurrencynumber5Max concurrent eval runs
timeoutnumber60_000Per-case timeout in ms
setup() => Promise<EvalSetupResult>requiredLazy loader for eval deps (use dynamic import())

Plugin system

import type { CruxPlugin, CruxRuntime, CruxPluginResult } from '@crux/core'
import { mergeRuntime, applyPlugins } from '@crux/core'

CruxPlugin

FieldTypeDescription
namestringUnique plugin name for debugging
install(runtime: Readonly<CruxRuntime>) => CruxPluginResultInstall hooks into the runtime

CruxPluginResult extends Partial<CruxRuntime> with optional dispose?: () => void.

Built-in pluginPackage
withDevtools(options)@crux/core/observability — name 'crux:devtools'
withTelemetry(options?)@crux/otel — name 'crux:otel'

mergeRuntime(base, patch)

Compose two runtimes with fan-out semantics:

  • Hooks — both handlers fire for every event
  • Middleware — patch wraps base
  • Collector — last-write-wins

applyPlugins(plugins, initialRuntime)

Process an ordered list of plugins. Returns { runtime, dispose }.

Observability context

import { observe } from '@crux/core/observability'
import { withSession, createSessionId, createFlowId } from '@crux/core'

withSession(sessionId, fn)

Groups all generate() calls within fn under a single session ID for devtools correlation.

createSessionId() / createFlowId()

Generate unique IDs for cross-boundary correlation.

observe.captureContext() / observe.withContext(ctx, fn)

Snapshot and restore observability context across async boundaries. In Convex, prefer @crux/convex/server and ctx.crux.runAction() so the boundary helper handles propagation.

Captured observability context

FieldTypeDescription
runIdCruxRunIdCurrent run ID
traceIdCruxTraceIdCurrent trace correlation ID
spanStackCruxSpanId[]Active span stack, deepest last
currentSpanIdCruxSpanId?Deepest open span

Model fallback

import { fallback, isFallback, classifyError, shouldAttemptFallback } from '@crux/core'

fallback(...models, options?)

Wraps multiple models into a single reference that tries each in order on qualifying failure.

const model = fallback(gpt4o, claudeSonnet)
const model = fallback(gpt4o, claudeSonnet, { on: ['rate_limit', 'timeout'], timeout: 10_000 })
OptionTypeDescription
onErrorCategory[]?Which categories trigger fallback (default: all)
shouldFallback(error: Error) => boolean?Custom predicate (takes priority over on)
timeoutnumber?Per-attempt timeout in ms
onAttemptError(error, attempt, model) => void?Called on each failed attempt

ErrorCategory = 'rate_limit' | 'timeout' | 'server_error' | 'connection_error' | 'auth_error' | 'validation_exhausted'

classifyError(error)

Classifies an error into an ErrorCategory or null.

ErrorCategory
HTTP 429rate_limit
HTTP 500–599server_error
HTTP 401/403auth_error
ETIMEDOUT, AbortErrortimeout
ECONNREFUSED, ENOTFOUNDconnection_error
ValidationExhaustedErrorvalidation_exhausted
HTTP 400, unknownnull (no fallback)

Validation retry

import { ValidationExhaustedError, isValidationExhaustedError, repairJsonText } from '@crux/core'
import type { ValidationRetryOptions } from '@crux/core'

ValidationRetryOptions

FieldTypeDescription
maxRetriesnumber?Default 3. Each consumes a step from maxSteps.
onRetry(attempt, zodError) => void?Per-retry hook
onExhausted(attempts, lastError) => void?Final-failure hook

ValidationExhaustedError

Thrown when validation retries exhaust. Properties: lastRawOutput, zodErrors, attempts, maxAttempts, promptId.

repairJsonText(text)

Zero-cost JSON text repair. Returns repaired text or null if unfixable.

See the Validation retry guide.

Security utilities

import { safe, raw, limit, wrap, escapeXml, truncate, userContent, detectSuspiciousPatterns } from '@crux/core'
FunctionSignatureDescription
escapeXml(text)string → stringEscape <>&"'
truncate(text, max?)string → stringTruncate (default max: 10,000)
safe\...``tagged templateAuto-escape interpolated values
raw(text)string → SafeWrapperSkip escaping inside safe templates
limit(text, max?)string → SafeWrapperTruncate + escape inside safe templates
wrap(text, opts?)string → SafeWrapperEscape + wrap in <user-input>
userContent(text)string → stringStandalone escape + wrap
detectSuspiciousPatterns(text)string → { suspicious, patterns[] }Scan for prompt injection patterns

Embedding

import { embedding } from '@crux/core/embedding'

Creates a reusable dense or sparse embedding primitive with built-in batching, governance, and concurrency control. See the Embeddings guide for usage.

Think of embedding() as provider policy, not search policy:

const dense = embedding({ kind: 'dense', ... }) // semantic vector
const sparse = embedding({ kind: 'sparse', ... }) // keyword vector

indexer({ dense, sparse })   // write vectors
retriever({ dense, sparse }) // query vectors

Hybrid search uses both embeddings through retriever() or VectorStore.search(). It is not kind: 'hybrid'.

FieldTypeDescription
kind'dense' | 'sparse'Vector type
namestringEmbedding model name
dimensionsnumber?Required for 'dense'
maxInputTokensnumberHard limit per text
batch{ maxSize?, concurrency? }?Batch behavior
preprocessEmbeddingPreprocessor | EmbeddingPreprocessor[]?Normalization before cache/provider calls
truncate{ strategy: 'fail' } | { strategy: 'chars'; maxChars: number }?Input-limit policy
retry{ maxAttempts; baseDelayMs?; maxDelayMs?; shouldRetry? }?Provider batch retry policy
cacheEmbeddingCache?Policy-aware per-text vector cache
rateLimit{ concurrency: number }?Cross-call provider concurrency cap
countTokens(text) => numberOptional tokenizer for maxInputTokens checks
embed(texts) => Promise<{ embeddings }>Provider call

Hybrid retrieval is composed above this layer through stores or retrievers.

import { embedding, embeddingCache, normalizeText } from '@crux/core/embedding'

const dense = embedding({
  kind: 'dense',
  name: 'docs-embedding',
  dimensions: 1536,
  maxInputTokens: 8191,
  batch: { maxSize: 100, concurrency: 3 },
  preprocess: normalizeText({ trim: true, collapseWhitespace: true }),
  truncate: { strategy: 'fail' },
  retry: { maxAttempts: 3, baseDelayMs: 250 },
  cache: embeddingCache({ store, namespace: 'embed-cache' }),
  rateLimit: { concurrency: 3 },
  embed: async (texts) => ({ embeddings: await provider.embedMany(texts) }),
})

Retrieval

import { retriever, reranker } from '@crux/core/retrieval'

Creates a query-first retriever that turns text into scored hits, prompt context, and query tools. See the Retrieval guide for the full architecture.

Use retriever() as the app-facing search object:

const docs = retriever({
  id: 'docs',
  namespace: 'product-docs',
  data,
  vectors,
  dense,
  sparse,
  search: { mode: 'hybrid' },
})

const hits = await docs.retrieve('refund policy')

const answer = prompt({
  use: [docs],
  system: 'Answer from the retrieved docs.',
})
FieldTypeDescription
idstringStable retriever identifier
namespacestringRequired corpus boundary
dataDataStore?JSON record hydration for store-backed retrieval
vectorsVectorStore?Dense, sparse, or hybrid vector search
denseDenseEmbedding?Dense query embedding
sparseSparseEmbedding?Sparse query embedding
retrieve(query, options) => Promise<RetrieverHit[]>?Fully custom retrieval path

Retrievers expose:

  • retrieve(query, options?)
  • inject: 'context' | 'tool' | 'both' when used in prompt({ use })
  • asContext() and asTools() for advanced/manual integrations

reranker() creates a provider-agnostic reranking stage that can be attached to a retriever through rerank.

Use grounding() from @crux/core/citations when retrieval context must become a cited answer contract.

Indexing

import { indexer } from '@crux/core/indexing'

Creates the write-time document indexing primitive. It owns chunking, transforms, embedding at write time, and store writes.

FieldTypeDescription
idstringStable indexer identifier
namespacestringRequired corpus boundary
dataDataStoreChunk, parent, and corpus record storage
vectorsVectorStore?Dense, sparse, or hybrid vector index
denseDenseEmbedding?Dense write-time embedding
sparseSparseEmbedding?Sparse write-time embedding
chunkerChunker?Override default chunker
transformsChunkTransform[]?Transform chunks before write

Indexers expose:

  • chunk()
  • indexDocuments()
  • indexChunks()
  • deleteSource()
  • clear()

Routing

@crux/core/routing exports router, cascade, fallback, the type guards isRouter, isCascade, isFallback, and resolveModel. Stable id fields on router/cascade/fallback configs are optional for execution but recommended for index and trace joins. See the Routing guide for full coverage.

Internal orchestration

@crux/core exports orchestration primitives (orchestrateGenerate, orchestrateStream, executeFallbackLoop, wrapStreamIterable, withAttemptTimeout) used by adapter packages. They're stable for adapter authors but not intended for general application code. See Building custom adapters.

Types

import type {
  Prompt,
  AnyPrompt,
  Context,
  PromptConfig,
  ContextDef,
  ResolvedPrompt,
  SystemBlock,
  InspectResult,
  InspectPart,
  DroppedContext,
  GenerationSettings,
  PromptAdaptation,
  AdapterMap,
  ModelInfo,
  PromptHooks,
  PrepareHookArgs,
  GenerateHookArgs,
  ErrorHookArgs,
  PromptMiddleware,
  MergedInput,
  Message,
  FallbackModel,
  FallbackOptions,
  FallbackMeta,
  ErrorCategory,
  CruxConfig,
  Crux,
  CruxEvalConfig,
  EvalSetupResult,
  PromptRegistry,
  FlowScope,
  FlowResult,
  FlowSnapshot,
  FlowSummary,
  StepOptions,
  SuspendOptions,
} from '@crux/core'

SystemBlock, ResolvedPrompt, ModelInfo, and AnyPrompt are re-exported from @crux/core for adapter authors who consume .resolve() output directly. Adapter packages constrain their context tuple as readonly Context<z.ZodType>[] (rather than Context<any>[]) so MergedInput<TOwnInput, TContexts> carries through generate() / stream() without explicit type arguments at the call site.

  • Guide: Foundations — mental model and primitives tour
  • Reference: Adapters — execution layer
  • Reference: Storage — persistent DataStore, VectorStore, and BlobStore implementations

On this page