Highlights
-
Add authored Eval and Case timeout policies, task-scoped cancellation context,
and automatic signal and nested-budget propagation for managed AI tasks.
Timed-out tasks now produce structured complete Run outcomes with comparable
Baseline coverage, while versioned local and remote readers preserve existing
artifacts and quarantine late evidence or result publication. Project Index
and the hydrated Eval catalog expose effective and inherited policy, while Eval
Runs and normal Runs show structured timeout causes and counts. -
Unify model-input Safety around semantic text, media, and instruction boundaries
for caller, tool, retrieval, memory, blackboard, handoff, and retry-feedback
content. Add provider-visible authored/discovered tool boundaries and managed
memory commit guardrails; raw tool execution controls remain intoolPolicy.Guard rejected output and corrective feedback before every eligible retry.
Semantic-cache hits now pass through current output guardrails, one authored
schema parse, and constraints before publication, with safe live fallback for
expected content rejections.Deprecate
boundary.validation.feedback()in favor of
boundary.input.text({ from: "feedback" }); the compatibility boundary remains
operational for validation feedback. -
Normalize structured response and tool-input schemas through provider capability
profiles. Crux now compiles provider-compatible wire schemas, decodes transport
sentinels before Safety, validates once with the authored schema, and exposes the
parsed output consistently across native, AI SDK, generate, and stream routes.Structured outputs are now always validated.
validationRetrycontrols whether
another attempt is made; without it, invalid structured output throws instead of
being returned. Adapter authors must declare their structured-output
capabilities and use the preparedoutputSchemasupplied to request builders.
AI SDK and provider adapters now accept@use-crux/mcp0.7 peers.Provider-neutral media classification
Add
guardrail.mediaClassifier()for per-part image, audio, video, and
file/document classification through anyGenerateObjectFn. Caller-authored
categories, inclusive thresholds, capability handling, input/output media
boundaries, report mode, and strip escalation share one provider-neutral
contract.GenerateObjectFnnow accepts either a text prompt or canonical messages so
structured media reaches provider adapters without flattening. Native OpenAI,
Anthropic, and Google object helpers bind only their client; callers pass the
model per invocation. Existing two-argument helper construction must migrate
tocreateGenerateObjectFn(client)plus{ model, ... }on each call.Guardrail findings now survive callback collection into audits, terminal
decisions, privacy-safe report artifacts, and Devtools Run Detail. Project
Index and Catalog expose only complete literal classifier-safe configuration;
telemetry retains bounded counts rather than category or media details.Boundary-driven streaming Safety
An
assertconstraint is transactional on a stream: it gates release, and a failed
attempt is discarded without publishing bytes and re-streamed with corrective feedback
under the sharedmaxStepsbudget. A positivevalidationRetry.maxRetriesinstalls the
same commit gate for schema validation. Buffering is attributable through a content-free
bufferedByreason andgeneration.stream.attemptspans, and constraint settlement is
occurrence- and value-precise, so a settledconstraint.judge()is not re-run at
completion.Streaming Safety holds an occurrence until every downstream transformation that could
change it has completed: an object assertion that passes while a text guard can still
rewrite the represented JSON is provisional and cannot release bytes, and it is
re-evaluated against the final value before anything is published. Object-only pipelines
keep progressive release.stream()on@use-crux/ainow honorsvalidationRetry, which it previously discarded.
Adapters report the model steps an SDK invocation actually consumed while core enforces
the sharedmaxStepsbudget; when consumption is unknown or settled tool rounds cannot be
resumed safely, Crux fails closed instead of risking duplicate tool side effects.Rejected candidates are evidence-only on public terminal errors:
ValidationExhaustedError
andConstraintViolationErrorexpose size and hash, never a preview of output the caller
was not allowed to see. Constraint feedback and metadata no longer reach telemetry (only a
feedback length and a metadata count), andValidationExhaustedErrorno longer exposes
custom Zod issue messages or model-controlled record keys — use its newissuessummary
for stable{ path, depth, code }diagnostics.Structured-output compilation fails closed rather than risking silent corruption: an
optional property is rejected at compile time when its encoding cannot be proven
reversible — inside a recursive schema, a union branch, an intersection or tuple, or when
the property is literally named"*".Managed logical streams
stream()now returns one Crux-owned logical stream with the same shape on every route:
{ runId, _meta, textStream, fullStream, partialOutputStream, completion, cancel }. A
logical stream may use several physical provider attempts, but provider framing, discarded
attempts, and the provider stream object are never observable. All three streams project
one shared append-only event log, so they can be read concurrently, a surface first read
late replays from logicalstart, and retention never delays publication —completion
settles without any stream being drained. A terminal failure now reaches every surface with
the same normalized error object rather than only rejectingcompletion.
result.cancel(reason?)aborts the whole operation, including the active provider attempt.For a structured prompt,
textStreamcarries canonical serializedz.inputJSON, and
partialOutputStreamis a parsed projection of that same published text — so a partial can
only ever describe committed output.completion.objectremains the single
authored-schema-validatedz.output.Logical
usageandcostare scalar aggregates across every BILLABLE physical attempt,
discarded ones included — the caller paid for each provider call. Everything else in the
envelope still describes the accepted attempt alone, so logicalusagedeliberately stops
equalling the sum ofsteps[].usageonce a policy retry occurred. If any billable attempt
did not report a figure the total is omitted rather than under-reported; on the AI SDK route
a rejected attempt reports no usage at all, so a retried SDK stream omits logical usage.The local runtime accepts the new
generation.stream.attemptprimitive, so coordinated
streams keep their buffering attribution in Devtools instead of being dropped as unknown.onChunk,onFinish, andonErrorare logical: they observe the published sequence and
the logical completion, and no caller callback is installed on a physical attempt, so a
discarded attempt invokes none of them.@use-crux/aiaddstoUIMessageStream(result)and
createTextStreamResponse(result), and its existing UI-message helpers are now built from
fullStream, which makes a discarded attempt unrepresentable in their input.Breaking removals
Streamed
result.rawis removed on every adapter. A provider stream resolves before
terminal Safety and describes only one attempt, so exposing it bypassed guardrail holds,
structured occurrence gating, commit gates, and validation retry. Provider-specific request
options are unchanged, and provider-specific terminal facts remain on
completion.providerMetadata. Replaceresult.raw.partialObjectStreamwith
result.partialOutputStream,result.raw.fullStreamwithresult.fullStream, and
result.raw.toUIMessageStream(...)withtoUIMessageStream(result).generate()results
keep.rawunchanged. The publicStreamResulttype parameters change from
StreamResult<TRawStream, TOutput>toStreamResult<TOutput, TPartial>, and the
TextStreamResult/ObjectStreamResultaliases are removed.Guardrail streaming configuration moved onto the boundary:
GuardrailConfig.stream, the
streamtune field,ConstraintConfig.onChunk, andonHoldLimit: 'release'are removed in
favor of
boundary.output.text().sentences() | .lines() | .deltas() | .complete() | .segments().
The curriedboundary.output.path<T>()('a.b')spelling is replaced by
boundary.output.object<T>().path('a.b'). -
Add eagerly executing, replayable
streamImage()andstreamSpeech()bounded
operations with provider-neutral events, final-result identity, cancellation,
deadlines, routing commitment, observability, and input/output Safety.OpenAI uses genuine Images API previews and Speech API response-body chunks.
Google uses current Interactions image deltas and finite Generate Content TTS
PCM chunks. Unsupported models and controls fail before provider I/O; Crux
never synthesizes progressive events from a completed artifact or persists
media implicitly.Project Index now recognizes both operations as authored media work with
static, semantic, native, and Local read-model parity. Catalog classifies them
as bounded streams with safe modality/support/source facts. Runs separates one
logical operation from its physical attempts and presents payload-free
progress, route commitment, timing, terminal, and output-media Safety facts.@use-crux/googlenow requires@google/genai2.x. This peer migration is a
breaking install change because the removed 1.x Interactions event schema is no
longer accepted. -
Memory capture now follows the active execution lifecycle automatically.
Capture modes are now
inline | deferred, withdeferredas the default. Deferred capture uses the sharedconfig({ host })retention binding; when retention is unavailable, Crux safely captures inline and emits one development warning instead of losing work. Retained failures remain observable throughmemory.flush().Adapters submit one completed turn and leave mode selection, deterministic tool-event fan-out, settlement, and block flushing to memory. Catalog exposes the effective configured mode, while Runs records one payload-free
memory.capturelifecycle inside the owning generation Run with the actual inline, fallback, retained, or Eval-captured disposition.Migrate
afterResponsetodeferred, replacedetachedwithdeferred, and remove memory-specificcapture.waitUntilin favor of a shared host binding. -
Add materialized Workspace subtree snapshots through
workspace.snapshot.create/list/restore/delete, including exact-tree restore and
independent asset ownership. Index authored snapshot usage and present observed
snapshot operations with privacy-safe, snapshot-aware Local Devtools views. -
Add deployment-wide observability redaction patterns for organization-specific
identifiers. Patterns redact captured payload values before evidence derivation
and final telemetry fan-out without changing application, model, or tool data.
Project Index reports only the privacy-safe configured state, while Local and
Devtools surface successful-redaction evidence using broad telemetry surfaces
without exposing rules, values, replacements, paths, hashes, or counts. -
Make Rust/Oxc the required Static Index path, remove the obsolete
experimental.indexer.nativeAstoption and TypeScript static-plan worker
artifact, and advance Project Index worker events to protocol v3. Configured
third-party static extractors continue to run through the trusted JavaScript
host.Lint suppressions now remain in Project Index snapshots as materialized
evidence instead of deleting matched findings.IndexLintFindingis a strict
active/suppressed union: suppressed rows require directive source, scope, and
optional reason metadata, while canonical active rows omit suppression state.
Default lint/check views remain active-only,--include-suppressedexposes the
retained rows, and suppressed findings never fail a gate.Devtools Index and Catalog Health now report active and suppressed totals
separately while retaining complete directive evidence for audit. Crux Local
run-detail reads correlate observed definition references with current Project
Index findings, and Devtools presents that non-historical context as Current
project health with links back to Catalog. This read-time context never changes
run status or creates suppression telemetry. -
Add optional Markdown-oriented prompt composition with
md, the opaque
PromptTexttype, and explicitmd.json()snapshots. Existing strings remain
fully supported. Resolution still yields provider-neutral plain text;
.inspect()retains structural provenance for PromptText, and Project Index
records compiler-provenmdregions with exact source ranges and
direct-versus-callback lifecycle metadata.Export
configure,ConfigureOptions, andPromptRegistryfrom the Core root
and let that explicit registry lifecycle publish a revisioned Prompt catalogue
for local exact inspection. Explicit preview dispatch invokes
Prompt.inspect()only; it creates no provider generation, tool invocation,
ordinary Run, or observability record. Trusted authored callbacks may still
perform their own side effects.Project Index PromptText evidence now classifies every canonical source as an
owner, named fragment, or anonymous fragment, retains exact semantic fragment
joins, and emits conservative diagnostics for invalid interpolations, inline
sequences, andmd.json()calls proven to return no text. JavaScript and
native semantic backends produce the same backend-neutral evidence.prompt.promptstays synchronous: callbacks returnstring | PromptText.
Runtime now rejects Promise results from untyped or cast async callbacks instead
of awaiting this unsupported shape, matching the existing synchronous public
type. An unconfigured user prompt stays absent through provider adaptations.
Context staticness followssystemKind, so inputless dynamic callbacks are
neither executed nor classified static during serialization or indexing.
DirectContextSystemContentandPromptTextuse the static provider-cache
lifecycle, like direct strings.Devtools now presents PromptText compiler evidence and hard diagnostics in
Catalog, shows structured exact-preview composition and validation, and keeps
PromptText segment provenance plus token attribution in ordinary captured Runs
when input capture policy permits it. Local persists that evidence through the
existing messages artifact; malformed or unavailable provenance falls back to
the ordinary plain-text Run Detail presentation. -
Add
crux lsp, a stdio language server that publishes Project Index lint
diagnostics, keeps ranges aligned with unsaved edits, explains findings on
hover, offers suppression and safe allowlisted companion-command actions, and
moves between an attachedcrux devread model and its own watcher without
clearing diagnostics during handover. Add index-backed go-to-definition,
references, document and workspace symbols, definition context on hover,
finding-count inlay hints and code lenses, Devtools definition links, and
live editor settings for hints, lenses, and inline-decoration opacity. Publish
the lockstep VSIX, six native CLI archives, and checksums on stable and nightly
GitHub Releases; discover trusted project-local npm CLI shims on Unix and
Windows, and provide npm-first plus direct-download installation guidance.
Add Project Index-aware semantic completion for supported first-party prompt,
context, MCP, tool, agent, handoff, and routing dependency slots. Completion
uses a bounded, private unsaved-document overlay, safe named-import edits, and
the existing persistent compiler in both attached and own modes. Cross-file
items require compiler-proven direct named-export evidence. This additive
Project Index metadata advances the static, semantic, and local snapshot cache
identities, so upgrades automatically reindex instead of reusing an older
snapshot.Add PromptText-aware editor support for canonical Core
mdtemplates. One
bounded Rust analysis now drives theme-aware Markdown-role highlighting,
folding, heading symbols, safe literal links, static preview, semantic
diagnostics, and versioned quick fixes while preserving native TypeScript
behavior inside interpolations. Identity-sensitive results fail closed against
saved semantic generation and source hashes; transient source and preview
content never enter Project Index, caches, logs, or broadcasts.The VS Code extension adds explicit static preview, runtime exact preview, and
latest-Run commands. Exact preview discovers a currently configured Prompt,
requires confirmation, and invokesPrompt.inspect()without model
generation, tool calls, or Run creation. Latest Run resolves current ownership
and SQLite ordering at click time, with no cached selection or automatic
navigation. The embedded Devtools routes are bounded, no-store, cancellation
aware, and keep preview inputs/results in memory only.Distribute the editor extension as a checksum-verified, lockstep GitHub Release
asset for Visual Studio Code and Cursor.crux editor install vscode|cursor
downloads the VSIX matching the running CLI version, verifiesSHA256SUMS, and
installs only into the explicitly selected editor;--download-onlysupports
managed environments. Release builds now embed that same stable or nightly
version in every native CLI, and release reconciliation shares the validated
asset set so the VSIX, six native archives, and checksums cannot disappear
after a successful staging pass.
Fixes
-
Memory capture now follows the active execution lifecycle automatically.
Capture modes are now
inline | deferred, withdeferredas the default. Deferred capture uses the sharedconfig({ host })retention binding; when retention is unavailable, Crux safely captures inline and emits one development warning instead of losing work. Retained failures remain observable throughmemory.flush().Adapters submit one completed turn and leave mode selection, deterministic tool-event fan-out, settlement, and block flushing to memory. Catalog exposes the effective configured mode, while Runs records one payload-free
memory.capturelifecycle inside the owning generation Run with the actual inline, fallback, retained, or Eval-captured disposition.Migrate
afterResponsetodeferred, replacedetachedwithdeferred, and remove memory-specificcapture.waitUntilin favor of a shared host binding. -
Unify model-input Safety around semantic text, media, and instruction boundaries
for caller, tool, retrieval, memory, blackboard, handoff, and retry-feedback
content. Add provider-visible authored/discovered tool boundaries and managed
memory commit guardrails; raw tool execution controls remain intoolPolicy.Guard rejected output and corrective feedback before every eligible retry.
Semantic-cache hits now pass through current output guardrails, one authored
schema parse, and constraints before publication, with safe live fallback for
expected content rejections.Deprecate
boundary.validation.feedback()in favor of
boundary.input.text({ from: "feedback" }); the compatibility boundary remains
operational for validation feedback. -
Normalize structured response and tool-input schemas through provider capability
profiles. Crux now compiles provider-compatible wire schemas, decodes transport
sentinels before Safety, validates once with the authored schema, and exposes the
parsed output consistently across native, AI SDK, generate, and stream routes.Structured outputs are now always validated.
validationRetrycontrols whether
another attempt is made; without it, invalid structured output throws instead of
being returned. Adapter authors must declare their structured-output
capabilities and use the preparedoutputSchemasupplied to request builders.
AI SDK and provider adapters now accept@use-crux/mcp0.7 peers.Provider-neutral media classification
Add
guardrail.mediaClassifier()for per-part image, audio, video, and
file/document classification through anyGenerateObjectFn. Caller-authored
categories, inclusive thresholds, capability handling, input/output media
boundaries, report mode, and strip escalation share one provider-neutral
contract.GenerateObjectFnnow accepts either a text prompt or canonical messages so
structured media reaches provider adapters without flattening. Native OpenAI,
Anthropic, and Google object helpers bind only their client; callers pass the
model per invocation. Existing two-argument helper construction must migrate
tocreateGenerateObjectFn(client)plus{ model, ... }on each call.Guardrail findings now survive callback collection into audits, terminal
decisions, privacy-safe report artifacts, and Devtools Run Detail. Project
Index and Catalog expose only complete literal classifier-safe configuration;
telemetry retains bounded counts rather than category or media details.Boundary-driven streaming Safety
An
assertconstraint is transactional on a stream: it gates release, and a failed
attempt is discarded without publishing bytes and re-streamed with corrective feedback
under the sharedmaxStepsbudget. A positivevalidationRetry.maxRetriesinstalls the
same commit gate for schema validation. Buffering is attributable through a content-free
bufferedByreason andgeneration.stream.attemptspans, and constraint settlement is
occurrence- and value-precise, so a settledconstraint.judge()is not re-run at
completion.Streaming Safety holds an occurrence until every downstream transformation that could
change it has completed: an object assertion that passes while a text guard can still
rewrite the represented JSON is provisional and cannot release bytes, and it is
re-evaluated against the final value before anything is published. Object-only pipelines
keep progressive release.stream()on@use-crux/ainow honorsvalidationRetry, which it previously discarded.
Adapters report the model steps an SDK invocation actually consumed while core enforces
the sharedmaxStepsbudget; when consumption is unknown or settled tool rounds cannot be
resumed safely, Crux fails closed instead of risking duplicate tool side effects.Rejected candidates are evidence-only on public terminal errors:
ValidationExhaustedError
andConstraintViolationErrorexpose size and hash, never a preview of output the caller
was not allowed to see. Constraint feedback and metadata no longer reach telemetry (only a
feedback length and a metadata count), andValidationExhaustedErrorno longer exposes
custom Zod issue messages or model-controlled record keys — use its newissuessummary
for stable{ path, depth, code }diagnostics.Structured-output compilation fails closed rather than risking silent corruption: an
optional property is rejected at compile time when its encoding cannot be proven
reversible — inside a recursive schema, a union branch, an intersection or tuple, or when
the property is literally named"*".Managed logical streams
stream()now returns one Crux-owned logical stream with the same shape on every route:
{ runId, _meta, textStream, fullStream, partialOutputStream, completion, cancel }. A
logical stream may use several physical provider attempts, but provider framing, discarded
attempts, and the provider stream object are never observable. All three streams project
one shared append-only event log, so they can be read concurrently, a surface first read
late replays from logicalstart, and retention never delays publication —completion
settles without any stream being drained. A terminal failure now reaches every surface with
the same normalized error object rather than only rejectingcompletion.
result.cancel(reason?)aborts the whole operation, including the active provider attempt.For a structured prompt,
textStreamcarries canonical serializedz.inputJSON, and
partialOutputStreamis a parsed projection of that same published text — so a partial can
only ever describe committed output.completion.objectremains the single
authored-schema-validatedz.output.Logical
usageandcostare scalar aggregates across every BILLABLE physical attempt,
discarded ones included — the caller paid for each provider call. Everything else in the
envelope still describes the accepted attempt alone, so logicalusagedeliberately stops
equalling the sum ofsteps[].usageonce a policy retry occurred. If any billable attempt
did not report a figure the total is omitted rather than under-reported; on the AI SDK route
a rejected attempt reports no usage at all, so a retried SDK stream omits logical usage.The local runtime accepts the new
generation.stream.attemptprimitive, so coordinated
streams keep their buffering attribution in Devtools instead of being dropped as unknown.onChunk,onFinish, andonErrorare logical: they observe the published sequence and
the logical completion, and no caller callback is installed on a physical attempt, so a
discarded attempt invokes none of them.@use-crux/aiaddstoUIMessageStream(result)and
createTextStreamResponse(result), and its existing UI-message helpers are now built from
fullStream, which makes a discarded attempt unrepresentable in their input.Breaking removals
Streamed
result.rawis removed on every adapter. A provider stream resolves before
terminal Safety and describes only one attempt, so exposing it bypassed guardrail holds,
structured occurrence gating, commit gates, and validation retry. Provider-specific request
options are unchanged, and provider-specific terminal facts remain on
completion.providerMetadata. Replaceresult.raw.partialObjectStreamwith
result.partialOutputStream,result.raw.fullStreamwithresult.fullStream, and
result.raw.toUIMessageStream(...)withtoUIMessageStream(result).generate()results
keep.rawunchanged. The publicStreamResulttype parameters change from
StreamResult<TRawStream, TOutput>toStreamResult<TOutput, TPartial>, and the
TextStreamResult/ObjectStreamResultaliases are removed.Guardrail streaming configuration moved onto the boundary:
GuardrailConfig.stream, the
streamtune field,ConstraintConfig.onChunk, andonHoldLimit: 'release'are removed in
favor of
boundary.output.text().sentences() | .lines() | .deltas() | .complete() | .segments().
The curriedboundary.output.path<T>()('a.b')spelling is replaced by
boundary.output.object<T>().path('a.b').
Editor and CLI assets
This release includes a lockstep VSIX, native archives, and checksums. See the installation instructions.