Crux
API Reference@use-crux/core

Contexts

context, when, match, and createContexts.

import { context, when, match, createContexts } from "@use-crux/core";

context(def)

Creates a reusable context fragment that can contribute system text, input fields, and tools to any prompt.

Static form

context({
  id?: string,
  description?: string,
  priority?: number,     // 0–100, default: 50
  use?: ContextEntry[],
  system: string | { segments: ContextTextSegment[] },
  tools?: ToolSet,
})

Dynamic form

context({
  id?: string,
  description?: string,
  priority?: number,
  input: ZodType,
  use?: ContextEntry[],
  when?: ({ input }) => boolean,
  system: ({ input }) => string | { segments: ContextTextSegment[] } | Promise<string | { segments: ContextTextSegment[] }>,
  tools?: ({ input }) => ToolSet,
  rawFields?: string[],
  memo?: { ttl: number },
  cache?: boolean,
})

Parameters

FieldTypeDescription
idstring?Identifier for debugging and devtools display
descriptionstring?Human-readable description
prioritynumber?0–100, default 50. Higher = dropped later under token pressure. Does not change normal render order.
inputZodType?Schema for input fields this context needs. Merged into prompt input.
useContextEntry[]?Nested entries resolved before this context's own system text. Supports context(), when(), match(), skills, memory, blackboards, retrievers and grounding, and custom contributor entries.
when({ input }) => boolean?When false, context is excluded entirely (no resolution, no tools, no tokens)
systemstring | { segments } | (args) => string | { segments } | Promise<...>Static or dynamic system text. Segments preserve static/dynamic attribution for inspection.
toolsToolSet | (args) => ToolSet?Static or dynamic tool set
rawFieldsstring[]?Top-level input fields skipped by auto-escape (use for HTML/Markdown that should be passed verbatim)
memo{ ttl: number }?App-side resolver memoization for dynamic contexts. Requires id.
cacheboolean?Provider cache hint for stable prompt-prefix blocks.

Caching

Use memo to skip redundant resolver calls and cache: true to request provider-level prompt caching:

FormEffect
memo: { ttl: 300_000 }Resolver memoization for 300 seconds
cache: trueProvider cache hint only
memo: { ttl: 300_000 }, cache: trueResolver memoization plus provider cache hint

Contexts with memo require an id for cache key derivation. Static string contexts cannot use memo; use cache: true when static content should participate in provider prefix caching.

Segmented system text

Return { segments } when devtools need to distinguish authored boilerplate from runtime values:

const workspace = context({
  id: "workspace",
  input: z.object({ workspaceName: z.string() }),
  system: ({ input }) => ({
    segments: [
      { text: "Current workspace: ", dynamic: false },
      { text: input.workspaceName, dynamic: true, source: "workspaceName" },
    ],
  }),
});

The runtime concatenates the segment text into the final system message. .inspect().system.parts[], context.contribution artifacts, and prompt.budget dropped previews preserve segments, staticTokens, and dynamicTokens. Segments can also carry observedAt and sourceVersion when a primitive knows when the source data was observed. Plain static strings are reported as one static segment, and dynamic string functions are reported as one dynamic segment without a source key.

Nested use

Use context({ use }) to bundle a reusable capability instead of repeating prompt wiring.

const supportContext = context({
  id: "support-context",
  use: [userMemory, docsGrounding],
  system: "Answer with user memory and cited product docs when relevant.",
});

const supportPrompt = prompt({
  id: "support",
  use: [supportContext],
  system: "Help the user.",
});

Nested entries resolve before the context's own system text. Their tools, constraints, guardrails, and metadata are merged through the same path as prompt-level use entries.

Use this when the context is more than text. For example, a supportContext can bundle product-doc grounding, user memory, skills, and a policy instruction. Prompt authors then write use: [supportContext] instead of remembering every individual primitive.

Returns

Context<TInput>: frozen instance.

when(predicate, ctx)

Wraps a context with a runtime predicate for conditional inclusion in the use array.

import { when } from "@use-crux/core";

prompt({
  use: [
    when((i) => !!i.brandVoice, brandCtx), // partial context input
    when<{ mode: string }>((i) => i.mode === "edit", editCtx), // explicit generic
  ],
});

Returns: ConditionalContext<TCtx>: the wrapped context's input keys become Partial<> in the merged prompt input type.

The default predicate parameter is typed as a partial view of the wrapped context's input, because wrapping makes those fields optional at the prompt level. Use the explicit generic form when the predicate reads prompt-owned fields. When the predicate returns false, the context is excluded entirely, the same semantics as setting when on the context definition.

match(opts)

Selects between contexts based on a discriminator value (multi-way switch).

import { match } from "@use-crux/core";

prompt({
  use: [
    match({
      on: (input) => input.mode,
      cases: { research: researchCtx, create: createCtx },
      default: createCtx,
    }),
  ],
});
OptionTypeDescription
on(input) => stringExtracts the discriminator value
casesRecord<string, Context | Context[]>Contexts per discriminator value
default?Context | Context[]?Fallback when no case matches

Every input key declared by any branch is included in the prompt's merged input type as optional, because only the selected branch is active at runtime.

Returns: MatchSpec: frozen instance.

createContexts(tree)

Same pattern as createPrompts() but for contexts.

const contexts = createContexts({
  brand: { voice, terms },
  editor: { schema },
});

contexts.brand.voice; // Context<...>
contexts._all; // Context[]: flat list

How contexts merge

When a prompt is resolved, the pipeline:

  1. Filters out contexts where when() returns false, falsy entries, and unmatched match() branches.
  2. Resolves each remaining context's system() callback in use order, with nested context({ use }) entries before the context that owns them within their cache tier.
  3. Composes the prompt's own system text first, then cached contexts (cache: true) as a stable prefix, then uncached contexts as the budget-droppable tail. Each group keeps use array order.
  4. Drops under budget if a token budget is set. Lowest-priority uncached contexts are dropped first, while the prompt's own system text and cached prefix are always kept.

Priority controls token-budget degradation, not normal rendering order. Excluded contexts contribute nothing: not system text, not tools, not tokens. Budget-dropped contexts still contribute their tools.

  • Guide: Contexts
  • Reference: Prompts: how prompts compose contexts via use
  • Guide: Caching: resolver memoization and provider cache hints
  • Guide: Token budget: automatic context dropping

On this page