BlitzGraph beta · occasional interruptions may occur
Changelog

Changelog

Recent product updates and release notes.

Beta 0.82.0
Current
Released
August 9, 2026

BlitzSheet can edit unit kinds and long text, the public playground fills the screen with a reliable agent, and new BlitzCRM spaces no longer receive platform-chosen secrets — you configure them.

Beta 0.82.0

August 9, 2026Current beta

Studio that works end-to-end: kinds, /try, agent, and your secrets

BlitzSheet can edit unit kinds and long text, the public playground fills the screen with a reliable agent, and new BlitzCRM spaces no longer receive platform-chosen secrets — you configure them.

Features
  • Editable $kinds and long text in BlitzSheet. Change a unit’s kind set through the draft/save flow ($setKinds); expand long cells into a real multiline editor.
  • /try is a full-viewport Studio with floating egress (home, Docs, Sign in), env sections as cards, and BlitzAgent that offers sign-in or “Open your space” instead of hanging without a space scope.
Improvements
  • Environment domain drafts stay quiet. New domains keep the draft badge and a single hint — Empty until you save the first variable or secret — without the long notice, toast, or selector lecture. Domains still appear in inventory only after the first write.
Fixes
  • BlitzAgent MCP tools run again, conversations persist after a successful model turn, and assistant/tool failures share one error panel.
Breaking Changes
  • New BlitzCRM spaces start without seeded secrets. Configure password_pepper and resend_api_key in Environment before portal auth works; existing spaces keep what they already have.
  • Three more failures change wire code. A JavaScript evaluation lane that cannot start (or dies mid-call) reports EVAL_RUNTIME_UNAVAILABLE (internal, recovery never) instead of INVALID_QUERY — nothing about the request was wrong. A stale expectedGeneration on an agent custody call reports AGENT_CUSTODY_GENERATION_CONFLICT (conflict): refetch the custody and resend. Agent custody generation-counter exhaustion reports STORAGE_ERROR. Clients matching INVALID_QUERY for any of these must re-match.

Beta 0.81.0

August 9, 2026

Clearer BQL wire: `$code`, honest `$var`, shared-field aliases

Executable code serializes as one $code envelope, mutation query captures reuse the engine’s own result shape, and schema import can attach shared data fields under local aliases with multi-alias runtime and physical-id deny/write floors.

Features
  • Shared fields with fromShared and rename. Import attaches a registry data field to a kind under a local name; unambiguous aliases project flat, divergent siblings stay $ambiguous. Import-only — no Studio attach editor yet.
Improvements
  • $op: "query" $var matches a standalone query (ONE object/null, MANY array) and meta.$vars is string | string[] | null with no silent drops.
  • Input still accepts $js / $ts / $code; they fold to one type. Deny and double-write rules for shared fields follow the physical field id.
Breaking Changes
  • Code on the wire out is $code only. Export, hooks, writes, aggregates, group keys, virtuals, and computed kinds emit { "$code": { "$lang", "$body" } } — not bare $js / $ts. Fold sugar on read if you still author it (Studio foldCode).
  • Pre-shared-field kind stores must wipe/reimport before load (pre-launch; no dual-read).

Beta 0.80.0

August 7, 2026

One rulebook for query names, and denied fields stay denied

Candidate-stage vs output-stage name rules are enforced identically on every query path with path-qualified diagnostics, and field permissions now bound expression evaluation itself: denied values never enter $js scope, denied computed fields never run.

Improvements
  • Name-binding rules are one contract, everywhere. Aggregate aliases in candidate $filter/$sort, unknown post-group names, duplicate output keys, and group-key collisions fail with the same error on every construction path — root and nested $expand alike — with path-qualified diagnostics (e.g. $fields/1, $expand 'members' $groupBy).
Fixes
  • Query-denied fields never enter computed evaluation. A field with permissions.fields.*.query=false is not bound into $js/$ts scope (including positional arguments access), a denied computed field is not executed, and denied names emit no values and no skip diagnostics.
  • A denied custom idField never leaks through the $id alias. Projection, expression bindings, and $groupBy share one masked resolver and fall back to the internal unit id.
  • $groupBy enforces the same deny-set: denied stored keys resolve as absent, denied computed keys are not evaluated, and group expression bindings carry no denied name.

Beta 0.79.0

August 7, 2026

Definition history you can read and trust

$history on definitions returns typed entries with exact per-definition payloads — automation definitions included — under one shared limit rule, and definition events now honor the same retention config as data history.

Features
  • Typed definition history entries. $history expands to typed entries built from the committed ops, with camelCase $consequences and payloads scoped to the exact definition (Action:a never sees Action:b).
  • Automation history un-rejected. Actions, workflows, and embedders record events under their projected $did and are readable through the same typed $history surface.
Improvements
  • One $history limit rule on every surface: default 20, max 100, $limit: 0 valid, and the last expanded projection wins — including its $as alias.
  • Definition events honor retention. The history sweep now also bounds definition history via the same history.retentionDays / history.maxEventsPerUnit config.
  • Generated definitions registry. docs/definitions-registry.md documents every member family of a Definitions document — identity, addressability, mutability — generated from the contract itself, so it cannot drift.

Beta 0.78.0

August 7, 2026

Try BlitzGraph without an account

A public, localized /try route embeds the Studio playground behind a scoped grant token — and public playground surfaces are pinned to that credential, so they can never open a visitor's private workspace.

Features
  • Public /try playground. Localized, indexed marketing route embedding the Studio playground with a runtime grant token — no signup required.
Fixes
  • The public playground can never show a private workspace. Surfaces that suppress the manual connection modal are pinned to the credential their host passes and never read the browser's persisted connection; without a token, /try shows an unavailable state.
  • One owner for public playground credentials. Landing hero, /try, and /playground share the same connection contract instead of three re-implementations.

Beta 0.77.0

August 7, 2026

Lossless transfer for same-name fields, errors that point at the problem

Namespace export/import round-trips composition-ambiguous DATA/ARC/FILE fields exactly, interval values transfer losslessly, and failures carry honest codes, stages, and paths instead of a generic INVALID_QUERY.

Features
  • Composition-ambiguous fields round-trip export → import → export. Same-name DATA/ARC/FILE facets transfer as exact $ambiguous groups; missing, duplicate, surplus, or inexact groups fail closed instead of guessing.
  • Lossless INTERVAL transfer. Artifacts render interval values with exact bounds and inclusivity; query display keeps the field's declared intervalFormat.
Improvements
  • Import failures say where and at what stage. Artifact shape/policy problems attribute as request errors; arc and blob I/O failures as execution errors with unit/field/ordinal paths that survive to the response.
  • INVALID_QUERY renders as invalid request, and definition batch errors use structured index paths instead of prose prefixes.
  • Disabled blob storage is one condition. Import preflight, materialization, and export all emit BLOB_STORAGE_DISABLED instead of divergent errors.
Breaking Changes
  • Some failures change wire code. FTS codec bounds report STORAGE_ERROR, namespace-id exhaustion reports NAMESPACE_LIMIT_EXCEEDED (recovery never — ids are not reused), and action lane/output failures report ACTION_EXECUTION_FAILED. Clients matching INVALID_QUERY for those conditions must re-match.

Beta 0.76.0

August 7, 2026

Filters fail fast, and mean the same thing on every path

Every filter lane — root, relation sub-filters, $expand, admission, hooks, mutation selectors, live queries — compiles through one schema-aware path, so invalid filters reject eagerly with a typed error instead of silently matching nothing.

Improvements
  • One schema-aware filter compiler for every lane. Root, relation, aggregate, $expand, admission floors, hooks, mutation selectors, and live queries reject the same inputs with the same errors.
  • Eager $expand.$filter validation. Probe-level gates like CURRENCY_MISMATCH and operator rejections surface at validation, even when traversal returns zero parent units.
  • Deterministic facet resolution. Homonymous-field dispatch no longer depends on map iteration order — the same query always compiles to the same plan.
Fixes
  • Arc operator gates cannot be bypassed by homonyms. A DATA-only operator (e.g. $startsWith) on a name whose selected facets are arcs rejects; a DATA facet living only on unselected kinds no longer turns it into a filter that matches nothing.
  • Relation-quantifier objects parse on kindless lanes. { "posts": { "$any": { … } } } defers to schema arbitration instead of a fabricated-cardinality reject; meta labels ($id, $createdBy) still reject.
  • Zero resolved target kinds reject instead of dropping the filter, and admission/hook currency mismatches fail closed.

Beta 0.75.0

August 6, 2026

Safer tokens, clearer request tracing, tighter SDK seams

OAuth tokens never leave the control plane as recoverable plaintext, every request carries a correlation id you can quote in support, and a few SDK ownership bugs around arcs and admin transport are closed.

Improvements
  • OAuth access and refresh tokens are stored as digests, and reads never return token material — so session APIs cannot hand a refresh token back to a holder of an access token.
  • Every HTTP response carries x-blitz-correlation-id. Report that header when a request fails; logs and support can join on the same id.
Fixes
  • Arc presence and the admin transport each have one owner in the SDK, so null-vs-absent and admin capability construction no longer diverge across call paths.
  • Studio History badges say definition, matching the renamed authoring surface instead of the old schema label.
Breaking Changes
  • Existing MCP OAuth tokens are invalidated. Deploy must delete AuthOAuthAccessToken rows (plaintext rows cannot match digests); every connected MCP client re-authenticates once.

Beta 0.74.0

August 6, 2026

Shared data fields and folded mutation projections

Define a data field once and attach it to many kinds via schema import, and mutation $fields projections share the same fetch/alias contract as queries — with inert root-only $fields rejected instead of silently ignored.

Features
  • Shared data fields (schema-import only). Define a data field in the registry and attach it to kinds on a fresh import — one physical slot, shared uniqueness across attachers when marked unique. No definition_mutate / Studio attach surface in this release.
Improvements
  • Mutation projections use the same $fetch / $as fold as queries where projection is consumed (e.g. query-shaped mutation results).
Breaking Changes
  • Root non-query $fields / $excludedFields are rejected. Create/update/upsert/delete projections that would shape nothing fail at validation instead of being accepted and ignored.

Beta 0.73.0

August 6, 2026

Open intervals and predictable expression outcomes

Interval bounds may be unbounded with one compact input grammar; expression failures can skip a unit instead of aborting the whole query; empty UnitSets are always null; and grouped aliases may intentionally shadow schema field names.

Features
  • Unbounded interval bounds. Open-ended sides use a tagged unbound (authoring / compact forms), never a fake scalar; per-field output format stays declared.
  • onExprError: "skip" on aggregates, projection/virtuals/computed, and group-key expressions. A failing evaluation omits that contribution or unit instead of failing the request when skip is set. Filter/sort $js is still unsupported.
Improvements
  • Virtuals and group-key expressions complete the query-lane skip path alongside aggregates and projection — one skip/fail policy on those surfaces.
  • Grouped output aliases may shadow schema fields when they are explicit group products — no more forced rename for legitimate group keys.
Breaking Changes
  • Empty UnitSet results are data: null, never []. A MANY query with zero units matches empty ONE. Field/arc empty arrays (tags: []) are unchanged field cardinality.

Beta 0.72.0

August 6, 2026

Errors you can act on: categories, paths, and wire values

Author-facing errors share stable categories and recovery hints, point at the JSON path that failed, and show values the way you wrote them — not Rust debug dumps.

Features
  • Eleven stable error categories (invalid_request, contract, authentication, permission, not_found, conflict, limit, unsupported, transport, internal, unknown) with consistent recovery and attribution.
  • issues[].path on input decode and write failures, so Studio and the SDK can highlight the exact field that broke.
Improvements
  • Wire-form values in error messages (e.g. "12:00:00.000" instead of Time(TimeValue(…))).
  • Did-you-mean hints on unknown keys and filter operators, including the shared typo funnel for identifiers.
  • One filter decode path carries coordinates through every operator, so nested $and/$or failures keep a usable path.

Beta 0.71.0

August 6, 2026

Code expressions on update, same as create

Update mutations accept $js / $ts field writes through the same typed code path as create defaults — no silent storage of code envelopes, one coerce funnel both ways.

Features
  • $js / $ts on update. Field writes accept typed code specs; create and update share evaluation, lowering, and coerce semantics.

Beta 0.70.0

August 6, 2026

Membership exclusion is `$nin`

BQL membership exclusion is spelled $nin only, symmetric with $in. The former $notIn wire name is removed and rejected with a did-you-mean hint.

Breaking Changes
  • Filter $notIn is removed; use $nin. Membership exclusion is now the short form only (pair $in / $nin, like $eq / $neq). $notIn is rejected as an unknown filter operator with a suggestion to use $nin.

Beta 0.69.0

August 6, 2026

One canonical spelling per projection concept

BQL projection, sort, and group vocabulary is now canonical: one structural marker per entry, one key-reference spelling, and canonical output that is always valid input. Input sugar still parses; it normalizes to the canonical form on the wire.

Breaking Changes
  • Projection references serialize as { "$fetch": … }. The $field spelling is removed from $fields entries and rejected with a targeted error; bare-string fields remain input shorthand.
  • Sort and group keys use $by. $sort/$groupBy entries spell their key reference { "$by": "name", "$order": "asc" }; the former $field key is rejected.
  • Aggregate sort entries follow the same vocabulary. AggSortField { field, desc } is replaced by string | { "$by": …, "$order": … }.
  • %name is input-only sugar. Folded virtuals serialize as entry-level { "$code": …, "$as": … } / { "$expr": …, "$as": … } markers, which are also accepted as input.

Beta 0.68.0

July 29, 2026

A precise, composable SDK for graph queries and definitions

The TypeScript SDK now separates data, definition, and operational administration by capability; adds compile-time query inference and mutation builders; and reports schema drift without silently changing query meaning. Polymorphic filters, grouped expressions, and definition mutations now follow the same contracts from SDK to server.

Features
  • Typed graph operations from authored BQL. Query result inference understands projections, cardinality, nested expands, groups, and aggregates, while mutation builders preserve variables and result shapes without hand-written response casts.
  • Resilient schema-aware evaluation. Queries can surface structured coverage and conformance findings when stored data drifts from the active schema; strict evaluation remains available when any mismatch must abort.
  • Dedicated SDK capability entrypoints. @blitzgraph/client-core/bql, /definitions, and /admin expose the smallest coherent surface for data operations, definition authoring, and operational administration.
  • Group by graph values, expressions, and arcs. Group keys now support scalar fields, computed expressions, and traversed role/link identity consistently across paged and nested queries, with typed response keys in the SDK.
Improvements
  • Correct polymorphic filtering. Field resolution now considers every applicable kind and descendant relation target, preserving selector scope, null semantics, sorting, grouping, and unique-result cardinality across composed units.
  • Administration is created only when requested. Data-only and definition-only clients no longer construct or retain an admin transport; React consumers opt into administration explicitly with useAdminClient.
  • One definition contract end to end. Closed definition mutations, generated validators, TypeScript types, MCP, Studio, and the Rust execution grammar now share the same canonical families and addressing rules.
  • A clearer visual language across BlitzGraph. Marketing, control-plane, and Studio surfaces now use one tree-shakeable Streamline icon system with consistent weight and sizing.
Fixes
  • Definition imports and exports no longer send transport-only error options in endpoint payloads, avoiding rejected requests against strict server option contracts.
  • ID values and unique-query cardinality agree across SDK validation, generated types, and the server, including nested JSON properties and filters that combine equality with $or.
  • Definition update/delete operations execute instead of falling through to create, and invalid operation arrays fail explicitly rather than mutating data under the wrong operation.
Breaking Changes
  • The schema-authoring client is now named definitions. Replace the former schema-shaped client access with client.definitions or import the dedicated /definitions entrypoint. Schema, portals, automations, and related authored definitions all live on this surface.
  • Operational methods require an explicit admin client. Use client.admin() or useAdminClient for namespace, task, blob, system, and portal administration; ordinary providers no longer create admin capability implicitly.
  • Raw dynamic operations keep their untyped boundary. Prefer the typed BQL helpers and generated definition contracts for authored operations; callers using runtime-provided unknown payloads must validate their result explicitly.

Beta 0.67.0

July 25, 2026

Space-bound connections and safer portal auth authoring

External connections now fence and revoke stale access before switching placement, so relocations never leave a grant pointing at stale physical infrastructure. Studio's portal auth authoring moves to per-provider cards with self-contained activation, and a string of approval/redirect and cold-start bugs in the connect flow are fixed.

Improvements
  • Relocation-safe by construction. External connection grants authorize a Space, not a physical location; a relocation revokes and fences the old placement before the new one activates, so a grant can never be replayed against stale infrastructure. A new "Use another account" flow lets you re-authorize under a different identity.
  • Redesigned portal auth authoring. Each provider (Email+password, Google, GitHub, Magic link) is its own card with an activation dialog; enabling Email+password with no pepper offers one-click secure pepper generation.
  • Version-aware template installs. Installing a portal template no longer clobbers customizations when the template contract has moved on.
  • Unified group keys. $groupBy now groups stored and computed scalars, authored expressions, and ONE arc identities through one typed runtime. Numeric forms agree across lanes, MANY keys fail explicitly, and grouped/root summaries expose Explain plans.
Fixes
  • Studio no longer wipes template-authored auth on save. App settings previously loaded auth/env/route configuration as empty and could overwrite a working template's auth setup; it now round-trips correctly.
  • MCP/OAuth approval no longer gets stuck after Space approval. Fixed a CSP-blocked redirect that silently prevented the final callback from reaching the connecting client; approvals are now safely retryable.
  • Connect redirects use the correct public URL instead of the container's internal bind address in preprod/production.
  • Portal auth recovers automatically after a fresh environment setup, instead of returning an error until an unrelated auth action happened to trigger reconciliation.

Beta 0.66.0

July 25, 2026

Sitemap, structured data, and new use-case pages

blitzgraph.com ships a real sitemap and robots.txt for the first time, canonical/hreflang URLs and JSON-LD structured data across every marketing page, and two new use-case landing pages — all resolving to the correct deployed domain instead of a build-time placeholder.

Features
  • Sitemap, robots.txt, and structured data. Every marketing route gets a sitemap entry with hreflang alternates, canonical URLs, JSON-LD entity data, and an llms.txt for AI answer engines.
  • New use-case pages. Dedicated landing pages for graph databases and agent-native application backends, linked from navigation and the footer.
Fixes
  • Absolute URLs now resolve to the real deployed domain. Canonical links, hreflang alternates, Open Graph URLs, and llms.txt no longer point at localhost on a promoted preprod or production image.

Beta 0.65.0

July 24, 2026

Unified app authoring: operations, actions, and workflows

Studio consolidates app authoring into one surface — operations now edit their full contract in the main code editor alongside pages, actions gain a manual-run surface with a reusable template vault, and Apps, History, and the Environment / Secret Vault get a broader UX pass.

Features
  • Operations join the main editor. App query and mutation operations are edited as first-class, strictly validated contracts in the same editor as pages, layouts, and components, without losing their server-generated identity.
  • Manual action runs and a template vault. Actions can be triggered manually from Studio, backed by a reusable automation template library, alongside improved parity between the Workflows UI and the underlying automation model.
Improvements
  • Apps reorganized into one authoring surface. Settings, auth, pages, endpoints, components, and operations for an app now live together; new apps require an explicit Public / User kinds / Deny-all audience, and unsaved settings are guarded across navigation.
  • Explicit access inheritance. Once an app or page authors an access rule, ruleless descendants inherit that chain instead of silently falling back to the namespace default.
  • Redesigned Environment / Secret Vault. Clearer domain navigation, contextual and race-safe destructive actions, and encryption explained without key-management jargon; Transfer & recovery moved under Namespace Settings.
  • New Select, MultiSelect, Tabs, Notice, and FloatingPanel UI with improved keyboard/focus behavior across Studio.
Fixes
  • History no longer crashes on system-barrier events; a new System filter and preserved pagination make audit history readable again.

Beta 0.64.0

July 23, 2026

More reliable BlitzAgent setups and automation

BlitzAgent provider setups move to the namespace level with independent Studio and Automation bindings, onboarding is guided end to end, and a string of turn-failure and model-selection bugs are fixed — including opaque errors that previously gave no indication of what went wrong.

Improvements
  • Namespace-level agent setups. Provider credentials (Claude, OpenAI, GLM, Kimi, Codex) are configured once per namespace; Studio and backend Automation each bind independently, so creating a setup no longer silently grants both.
  • Guided onboarding. Opening BlitzAgent with no Studio binding launches first-use setup in context, with support for both Codex subscription login and API-key providers.
  • One setup manager. Reconnect, logout, enable/disable, key rotation, assignment, and deletion are handled from a single saved-setup manager instead of split forms; deleting a setup cleanly removes its bindings and secrets in one step.
  • Model catalog and clearer errors. Studio now shows a live model selector per setup and surfaces the real turn error instead of a generic failure; a retired model pin is flagged and fixed with one click.
Fixes
  • Codex-backed BlitzAgent turns no longer fail outright. Fixed a transport mismatch that broke every first turn for Codex subscription setups.
  • External Automation connections can now call their granted tools. Fixed a gap where Codex-bound external connections could not invoke any of their permission-scoped MCP tools.

Beta 0.63.0

July 22, 2026

Reliable retries and resumable destructive operations

Long-running bulk mutations no longer fail on a retry budget that started ticking before any conflict occurred, and destructive operations — namespace wipes, subspace resets, and bundle restores — are now resumable and safe to retry after an interruption, with no partial or torn state.

Improvements
  • Resumable destructive operations. Namespace and subspace wipes, resets, and bundle restores persist fencing and progress, so an interruption can be safely retried without leaving mixed old/new state.
  • Bundle restore always starts clean. .bzg bundle imports restore into a fresh generation instead of layering onto existing state.
Fixes
  • Bulk imports no longer hit spurious conflict errors. The commit-conflict retry window now starts at the first real conflict instead of at request start, so long-running imports keep their full retry budget.

Beta 0.61.0

July 17, 2026

TypeScript expressions and protected WASM actions

Author typed expressions and reusable action bodies in TypeScript, or upload capability-free WASM components for protected pure execution. The SDK, Studio, public docs, and MCP now expose the same module lifecycle, diagnostics profile, and durable compatibility boundary.

Features
  • TypeScript-authored definitions. Computed and default fields, mutations, workflow bindings, and inline action bodies accept $ts or explicit $code; the server lowers erasable TypeScript at definition time and keeps authored source as the durable source of truth.
  • Protected WASM actions. pure×wasm actions pin a namespace-scoped component by content hash and execute ABI v1 without filesystem, network, clock, randomness, or other host imports.
  • Typed module lifecycle. The TypeScript client can upload, list, inspect, download, and delete validated WASM components; deletion fails while an Action or hook still references the pinned module.
Improvements
  • Space-bound external connections. OAuth and backend grants authorize a logical Space while every dataserver route resolves its live assignment. Relocations durably fence old projection generations, preserve consent and session identity, and issue a new bearer only after the old placement is no longer usable.
  • Consistent authoring diagnostics. Studio projects the generated restricted-TypeScript profile for fast feedback, while server lint remains authoritative and rejects imports, runtime-generating syntax, and unsupported module constructs before persistence.
  • Literal-safe mutation preflight. Typed expression preparation covers nested control flow and projections without interpreting code-shaped JSON inside explicit $value, patch, or collection payloads.
  • Bounded, fail-closed execution. WASM components have byte-weighted cache limits and shared fetch/execution deadlines; distributed TiKV deployments require durable S3 module storage instead of falling back to process-local bytes.
Breaking Changes
  • Pre-GA workflow payload boundary. Workers accept durable workflow wire V6 and checkpoint V4 only. Drain or purge older queued, running, or suspended development tasks before upgrading, and do not run mixed worker versions during the transition.

Beta 0.60.0

July 17, 2026

Effective limits you can inspect before a request fails

Operators, Studio, SDKs, and agents can now read the exact limits enforced for their current scope. Limit rejections carry the same generated identity, value, unit, provenance, retry guidance, and remediation as the protected catalog, so capacity behavior is discoverable instead of hidden in server defaults.

Features
  • Protected effective-limit catalog. GET /limits/effective, client.effectiveLimits(), the limits.effective MCP tool, and Studio expose the active admission, request-rate, request-body, and mutation-batch limits visible to the selected authority and exact scope.
  • Machine-actionable limit failures. Rejections include typed LimitViolationDetails with configured, effective, and observed values plus units, retry timing, and a retryLater or reduceRequest remediation.
Improvements
  • One enforcement SSOT. Catalog rows and rejection details are projected from the same resolved limit used by the runtime, preventing Studio, MCP, SDK, and server defaults from drifting apart.
  • Scope-safe observability. Server and store operators can inspect process-wide limits; database and namespace callers only see their effective scope, while sensitive configuration provenance is redacted from principals that cannot inspect process limits.
  • Safer request-rate identity. Rate limiting keys on the socket peer and only trusts the rightmost forwarded address when proxy-header trust is explicitly enabled.

Beta 0.59.0

July 17, 2026

Crash-resilient workflow fan-out and recovery

Durable workflow journals now preserve nested calls, mapped child membership, joins, cancellation, compensation progress, and trace context across worker crashes and restarts. Operators can inspect the same typed run history in Studio, MCP, the SDK, and task APIs.

Features
  • Durable Action and Workflow maps. A map effect can target a named Action or Workflow with bounded concurrency, ordered outcomes, retries, throw/collect behavior, and atomically recorded child membership.
  • Typed recovery timeline. Run events identify child waves, joins, state/effect boundaries, retries, compensation, and owning workflows; W3C traceparent and tracestate propagate across actions and child workflows.
Fixes
  • Nested calls resume at the caller. Checkpoints retain the parked call stack, so a crash after a child boundary resumes the full parent continuation instead of completing with the child output.
  • Saga rollback resumes exactly where it stopped. Compensation mode and progress are journaled after each successful compensator, preventing forward replay or duplicate rollback after a crash.
  • Joins and cancellation survive task movement. Parent reads resolve mapped children from their durable home, stale workers cannot clear a newer running epoch, and explicit scope purges cannot orphan child tasks behind a join gate.

Beta 0.58.0

July 17, 2026

Resumable live queries and named portal operations

Live subscriptions now deliver atomic frames with opaque reconnect checkpoints, bounded retained replay, continuity repair, byte metering, and authorization revalidation. Portal AppUsers gain the same model through validated named query operations without exposing the raw live-query surface.

Features
  • Opaque live resume checkpoints. POST /query/live accepts opts.resume; clients persist a checkpoint only after applying its complete snapshot or patch, then replay retained projected frames after a disconnect.
  • Named AppUser live operations. Portal /_ops/query/{op}/live subscriptions enforce the authored operation, input contract, subject floor, and authorization policy. React portals consume them through useLiveOperation().
  • Atomic LiveFrame wire contract. Snapshot, patch, heartbeat, and terminal frames share generated Rust, JSON Schema, TypeScript, SDK, and portal-runtime contracts.
Improvements
  • Fail-closed continuity repair. Gaps are durably fenced and repaired before subscriptions continue; retryable LIVE_CONTINUITY_GAP and stable LIVE_RESUME_UNAVAILABLE failures let clients distinguish transient repair from an unconfigured keyring.
  • Bounded replay and egress. Disconnect grace, global retention, replay-window limits, and actual SSE byte metering bound session memory and delivery cost without minting a second ordering coordinate.
  • Hardened reconnect loops. Shared client-store subscriptions back off short or unstable closes, stop retrying an unavailable resume configuration, and clear checkpoints when a patch cannot be applied atomically.

Beta 0.57.0

July 17, 2026

Bounded search and safer data lifecycles

Full-text search now bounds fuzzy and prefix expansion work, numeric filters use one exact comparison model, and FILE references are tracked transactionally from upload through import, mutation, wipe, and cleanup. Studio transfer workflows also expose the complete bundle and JSON surfaces without requiring manual API calls.

Improvements
  • Bounded, cancellable lexical search. Prefix and fuzzy expansion use explicit work and memory budgets, cooperative cancellation, and a split top-K scorer so broad terms cannot grow without bound while a request is being cancelled.
  • Exact numeric semantics. INTEGER, DECIMAL, FLOAT, CURRENCY, and PERCENTAGE values are canonicalized before equality, ordering, filter evaluation, mutation validation, and import, removing cross-type comparison drift.
  • Complete Studio transfer surface. Operators can export namespace or single-subspace .bzg bundles, move data as JSON with progress, and import/export definitions, schema, portals, and automations from the same Transfer panel.
Fixes
  • FILE cleanup is transactional and recoverable. Reference changes are indexed in the mutation transaction; finalization, import, deletion, namespace wipes, and retry handoffs preserve exact namespace/subspace ownership before an object can be removed.
  • FTS maintenance survives cancellation and compaction races. Lease cleanup, derived manifests, reindex handoff, and query-local summary reuse no longer leave stale ownership or unbounded background work.
  • Transfer and task views stay scope-safe. Connection changes cancel stale requests, subspace bundle exports only include that subspace's selected FILE fields, and server-reported authorization errors keep their original status.

Beta 0.56.0

July 17, 2026

Canonical responses and strict public contracts

Every runtime now consumes the same generated public contracts and the same BlitzResponse envelope. Structured issues replace response side channels, SDK callers can choose throw or collect behavior, and schema authoring accepts one documented grammar instead of silently normalizing stale aliases.

Features
  • One operation response model. Query, mutate, definition, admin, import, portal, task, MCP, and Studio paths return typed data, outcome, issues, meta, and explain fields with stable issue codes, severities, phases, and bounded summaries.
  • Configurable SDK error handling. errorMode: "throw" | "collect" can be set globally or per call, so applications can use exceptions or inspect committed/partial/rejected outcomes and issues directly.
Improvements
  • Rust-to-TypeScript contract closure. Public request, response, database, task, portal, and automation types are generated from the canonical Rust DTOs; SDK, MCP, Studio, SSR, and server validation consume those generated shapes instead of parallel hand-written mirrors.
  • Actionable validation failures. Closed envelopes reject unknown keys with stable error codes, RFC 6901 paths, and allowed-key details while preserving HTTP authorization, rate-limit, and not-found statuses.
Breaking Changes
  • Schema authoring now uses canonical names only. Use extends instead of kind-level parent, roleFields instead of kind-level roles, and canonical camelCase keys such as idField, userKind, emailField, onDelete, and jsonSchema; the old aliases and snake_case spellings are rejected.
  • Development and preproduction data must be reset and reseeded. Unit, history, commit-event, FTS-segment, and portal-binding persistence now use one revision with no old-format readers; rebuild FTS and recreate portal registry bindings after upgrading.
  • Raw response side channels are gone. Consumers must read issues and meta.issues from BlitzResponse; stale QueryResult mirrors and endpoint-specific error payload assumptions are no longer supported.

Beta 0.55.0

July 17, 2026

BlitzAgent, provider setups, and reusable connections

BlitzGraph now includes an in-product agent that works through the same generated MCP tools and documentation as external agents. Named, namespace-scoped setups keep provider credentials in server custody, while reusable external connection grants provide a browser-approved handoff for MCP and confidential backends.

Features
  • In-product BlitzAgent. Studio gains streaming agent chat, persistent scoped conversations and memory, tool-result rendering, navigation actions, and a command palette that exposes the canonical Studio/MCP command surface.
  • Named agent setups. Spaces can create namespace assignments backed by sealed provider custody and grant-projected permissions. The effective setup is resolved server-side, so browser requests never carry an API key or choose a more privileged setup.
  • Generated provider catalog. Claude, OpenAI, GLM, Kimi, and Codex subscription execution share one model/provider registry, context budgeting, transport selection, health contract, and Studio status surface.
  • Reusable external connections. The /connect/* flow adds discovery, browser approval with explicit target selection, authorization-code exchange, connection metadata, and revocation for MCP and confidential application backends.
Improvements
  • Server-owned Codex subscription runtime. Codex OAuth custody and the managed-process execution path stay on the server, separated from ordinary model API-key transports and scoped to the selected namespace assignment.
  • Hardened agent boundaries. Tool permissions are derived on the server, mutation and dangerous-operation tiers are explicit, provider egress is pinned and SSRF-guarded, histories are sanitized, and abort/rate-limit signals propagate through the streaming loop.
  • Connection credentials are deterministic and revocable. A connection grant owns its derived dataserver credential, target, capability ceiling, expiry, projection recovery, and cleanup instead of relying on surface-specific token state.
Breaking Changes
  • Inline agent BYOK overrides are removed. Configure a named Studio agent setup and assign it to the namespace; chat and automation requests use that server-resolved setup rather than accepting per-request provider keys.

Beta 0.54.0

July 17, 2026

Native portal identity and operation authorization

Portal identity now runs inside the dataserver and binds verified users directly to graph Units. Email/password, magic link, Google, and GitHub providers converge on one session and signup model, while authored page, route, and named-operation rules are enforced from Studio through SSR and runtime execution.

Features
  • Dataserver-native portal auth. Portals can enable email/password, magic link, Google, and GitHub sign-in with open, invite-only, or closed signup. A provider-neutral blueprint creates the bound graph Unit only after verified evidence and required onboarding input are complete.
  • Full identity lifecycle. Native sessions, email verification, password reset/change, magic-link consumption, OAuth PKCE/state validation, provider-account binding, and Resend delivery use scoped, hash-at-rest records that participate in backup and restore.
  • Portal and operation authorization. App access, ancestor route rules, page/endpoint access, and named query/mutation operation policies compose fail-closed. Private operations bind $me; guest-reachable operations must explicitly declare public.
  • Auth authoring in Studio. Pages Builder can configure signup mode, providers, delivery/env bindings, app/page/endpoint access, and operation admission with generated contracts and readiness feedback.
  • BlitzCRM template. The demo catalog includes a multi-tenant CRM portal with real native auth, memberships, role-aware routes, scoped operations, and a complete importable dataset.
Improvements
  • Sessions revalidate live authority. Identity epoch, credential revision, provider binding, Unit existence/kinds, and admission policy are checked at the security boundary so password resets, demotions, disables, and definition changes take effect without trusting stale browser state.
  • Portal operation rules are visible before publish. Studio explains effective route ancestry and derived operation admission, and rejects incomplete demo/template replacement or unsupported reserved auth/operation route rules.
Breaking Changes
  • Portal auth mutations moved to /_auth/*. The old /_session/sign-in, sign-up, sign-out, and refresh bridge routes are removed; /_session/subject remains the current-subject surface.
  • Named operations are explicit capabilities. Direct operation access is derived from its consumers and operation authorization; rules under reserved /_auth, /_session, or /_ops route prefixes are rejected.

Beta 0.53.0

July 17, 2026

Durable actions and graph workflows

Actions and workflows are now first-class graph definitions with durable execution, automatic triggers, simulation, inspection, and Studio/MCP/SDK management. Runs pin their executable program, survive suspension and restart, and expose enough trust and blast-radius information to operate safely.

Features
  • Durable workflow engine. Author Actions and state-machine Workflows with manual, commit, graph-pattern, cron, webhook, signal, and nested-workflow triggers plus delays, retries/backoff, keyed concurrency, fan-out, exits, and saga compensation.
  • Exactly-once graph mutation steps. Idempotency keys and persisted step markers let client retries and process recovery reuse the same run without duplicating committed graph writes.
  • Workflow safety tools. Typed lint, Mermaid render, side-effect-free simulation with mocks, blast-radius analysis, checked-in golden tests, and cascade inspection are available through HTTP, the TypeScript SDK, MCP, and Studio.
  • Live run operations. Studio and SDK clients can stream task events, inspect the pinned program digest and timeline, cancel or retry tasks, and answer an ask or deliver the exact signal awaited by a suspended workflow.
Improvements
  • Pinned executable closures. Editing, pausing, or deleting a definition cannot change an already-submitted run; execution and inspection verify the stored closure digest before trusting it.
  • Bounded execution and retention. Step/run budgets, cascade caps, network allowlists, task/event retention, signal race fencing, and durable event identities keep automation work observable and recoverable under restart or contention.
  • MCP and Studio parity. Agents and operators can author definitions, run/simulate/render/test workflows, inspect tasks and events, send signals, and manage task lifecycle without falling back to raw HTTP calls.

Beta 0.52.0

July 17, 2026

Live graph queries and reactive clients

Applications can subscribe to ordered graph query results over SSE and consume them through a framework-neutral normalized store or React hooks. Durable commit identities, bounded admission, replay/resync, and credential revalidation make live state predictable across reconnects and server restarts.

Features
  • POST /query/live. A live query starts with an ordered snapshot and emits authoritative added, updated, and removed deltas plus explicit replacement snapshots or terminal events when continuity cannot be preserved.
  • Reactive TypeScript clients. client.queryLive(), the new @blitzgraph/client-store package, and React useLiveQuery() share normalized units, subscription deduplication, optimistic overlays, graph-aware invalidation, and framework-independent delta application.
  • Studio live mode. Query results can switch between one-shot execution and a managed live subscription with explicit start/stop state and server-authored row ordering.
Improvements
  • Durable replay and resync. Exact-subspace commit sequences survive restart; duplicate notifications are ignored, retained gaps replay in order, and expired or oversized gaps force a fresh snapshot instead of applying uncertain deltas.
  • Bounded, revocable subscriptions. Process and principal/Space admission caps return structured 429 errors, RAII teardown releases capacity, and grant/internal-key expiry, rotation, or revocation terminates the stream without emitting protected events.
  • Stable row identity. Deltas carry internal identity and server-authoritative indexes, so composed-kind rows, relation filters, custom IDs, and equal sort keys update without client-side re-sorting drift.

Beta 0.51.0

July 9, 2026

BQL Filter API V2 and auth authoring contracts

BQL filters now use one canonical operator vocabulary, auth access rules are generated from the Rust contract all the way into Pages Builder, and MCP dataserver credentials become deterministic, recoverable system credentials. This release also tightens protected expands so hidden children cannot leak through nested filters, windows, aggregates, or explain output.

Features
  • BQL Filter API V2. Negative operators are now canonicalized as $neq and $notIn, with a typed taxonomy for scalar, MANY, interval, and relation fields. Contract schemas, generated TypeScript, docs, portal auth, live-query validation, read floors, macros, and Studio affordances use the same operator registry.
  • Auth access authoring contracts. App, page, and endpoint access rules now have strict generated AccessRule / AccessQuery contracts from Rust to @blitzgraph/client-core, and Pages Builder operations round-trip those rules through the existing definition mutation path.
  • Deterministic MCP dataserver credentials. MCP dataserver tokens are derived from the grant target and key material, carry projection/source metadata, and show as system-managed credentials in Access. Unsupported manual rotate/revoke actions are blocked; connection disconnect owns grant and token revocation.
Improvements
  • Protected expands prune children, not roots. Public parent units can expand protected child relations; hidden children are filtered through the app-user read floor before nested filters, pagination windows, aggregates, and explain counts can observe them.
  • Credential projection recovery is safer. Token projection, deprojection, revoked-token retry, and failed-projection cleanup paths now reconcile deterministically and fail closed on malformed grant state.
  • Runtime and dependency refresh. The workspace moved to Rust 1.96.1, Wasmtime 46, Better Auth 1.6.23, current Bun/CodeMirror/Next-intl related patches, and updated pinned CI actions. Bundle import query parsing treats empty subspace= / subspaces= parameters as absent while preserving non-empty overrides.
Breaking Changes
  • Legacy filter spellings are rejected. Replace $ne with $neq and $nin with $notIn. Collection aliases $includes and $overlaps are removed; use $has, $any, $all, $none, $exact, or interval $contains / $intersects according to field cardinality.
  • Auth access nulls are update-only clears. Authored create/import/read surfaces reject access: null; clear an existing access rule through an update/JSON patch clear instead of storing null as a valid rule.
  • Permission rules reject $js predicates. Schema import and registry resolution reject unsupported $js permission predicates instead of failing closed later at runtime. Use BQL predicate rules over $me.

Beta 0.50.0

July 8, 2026

App-user authorization and env vault

Portals gain an AppUser subject model, BQL-native permissions, and route admission rules through the same query language developers already use. The release also adds a namespace env vault for constants and write-only secrets, with SDK, MCP, and Studio surfaces over the same typed contract.

Features
  • AppUser authorization foundation. Verified portal identities resolve to a live graph subject on every request. AppUser access is structurally capped to portal/data capabilities, and useMe() exposes the current subject to React portals.
  • BQL-native kind permissions. Kinds can declare userKind, emailField, and permissions rules. The server re-resolves the subject, injects read floors, gates writes, masks fields, and enforces link/unlink permissions with rules evaluated from the target unit against $me.
  • Portal admission rules. App, page, and endpoint access rules use the same $me predicate language as data permissions. Missing auth returns SIGN_IN_REQUIRED; denied access returns ACCESS_FORBIDDEN; malformed or unresolved rules fail closed.
  • Namespace env vault. POST /admin/env, client.env(), namespace/subspace SDK helpers, MCP, and the Studio Env panel manage constants plus write-only sealed secrets. Secrets are sealed under a namespace DEK, support KEK rotation, and never echo values from read APIs.
Improvements
  • Route permissions are enforced everywhere. claims.permissions gates data, definition, admin, portal, and internal routes through a drift-locked route catalog instead of treating any namespace-scoped grant as fully privileged.
  • Subject authority is live. Subject deletion, kind demotion, permission changes, and access-rule changes take effect at the next request rather than waiting for a long-lived token to expire.
Breaking Changes
  • Namespace grants must carry the permission they use. A token that authenticates but lacks the route permission now receives PERMISSION_DENIED instead of falling through to full namespace access. Builder/root tokens are minted with the full builder permission set.

Beta 0.49.0

July 5, 2026

BQL projection and query semantics

BQL now has one typed projection path from root queries through nested expands, deterministic grouped aggregation semantics, and explicit behavior for polymorphic field-name collisions. Candidate windows, group-row windows, null filters, and $all matching are now precise enough for large graph queries and generated clients.

Features
  • Per-unit field ambiguity with $definedOn. Same-named fields across unrelated composed kinds are resolved per result row. A genuinely multi-kind row with divergent definitions renders a {"$ambiguous": { Kind: value }} marker, and $definedOn selects one defining kind when a client needs a stable key.
  • Selector-stage windowing. Node and expand-level $sort, $limit, and $offset window candidate units before shaping. Group row filtering, ordering, and pagination live inside the $groupBy object, so "top 100 events, then group" and "first 5 groups" are separate, expressible queries.
  • Typed nested projection. Nested $expand uses the same normalized projection model as root queries. Grouped expands, aggregate expands, $as, $definedOn, and per-parent candidate windows share the same validation and rendering path.
Improvements
  • Null filters mean empty content. { field: null } and { field: { "$eq": null } } fold to $isEmpty: true; $neq: null folds to $isEmpty: false. This matches absent fields, empty MANY lists, and empty interval sets.
  • One grouped aggregation engine. Root and nested grouped queries stream through one accumulator, with deterministic first-encounter group order, post-aggregate virtuals, HAVING, and parity across scalar, MANY, temporal, and currency values.
  • Planner parity for polymorphic queries. $kinds.$all scans seed from the cheapest kind subtree, $sort: "$id" orders by public id, and shaped expand windows avoid the old root-vs-nested semantic split.
Breaking Changes
  • Group-row operations moved under $groupBy. Node $filter/$sort/$limit/$offset are candidate-stage only. HAVING is $groupBy.$filter; group-row sorting/paging is $groupBy.$sort / $limit / $offset; node-level aggregate-alias filters or $having reject.
  • Shaped windows require explicit ordering. A query or expand that combines $limit / non-zero $offset with $groupBy or root/nested $aggFields must include an explicit $sort.
  • Ambiguous writes never guess. Bare writes to genuinely ambiguous same-name fields fail with AMBIGUOUS_FIELD_ACROSS_KINDS; read projections return the ambiguity marker or require $definedOn when a single definer is intended.

Beta 0.48.0

July 4, 2026

Self-service namespace bundles

Namespace transfer now has a namespace-scoped .bzg bundle surface in addition to stored admin artifacts. Operators can download or upload whole-namespace and per-subspace bundles, Studio gets a transfer panel, MCP namespace targeting is hardened, and portal SSR startup failures degrade to client rendering instead of blocking the server.

Features
  • .bzg namespace and subspace bundles. /namespace/bundle/plan, /namespace/bundle/export, /namespace/bundle/import, /subspace/bundle/export, and /subspace/bundle/import provide namespace-scoped transfer without database-level artifact access. Bundle imports accept multipart uploads, return 202 Accepted, and resume when the same bundle/options match the persisted sentinel.
  • Bundle SDK and Studio transfer UI. namespace.bundle.plan/export/import and subspace bundle helpers wrap the HTTP surface; Studio adds transfer planning, namespace/subspace bundle downloads, uploads, status polling, and FILE-field selection.
  • Grant-bound MCP target selection. The connect flow binds an OAuth grant to the selected namespace, and tools use that grant target plus opts.defaultSubspace for per-call subspace routing instead of mutating workspace selection state.
Improvements
  • Stored artifact transfer is stricter. Store-level /namespace/export and /namespace/import use the canonical include shape, per-database artifact isolation, terminal records, crash-resume checks, and explicit FILE omission counts.
  • Portal SSR degrades to CSR on startup failure. A failed SSR runtime no longer prevents the data server from starting; affected portals fall back to client rendering while the env contract keeps SSR-only settings scoped to the data-server deploy profile.
Breaking Changes
  • The orphaned Rust multi-statement Transaction API is gone. Use the existing single-call query/mutate/import paths and builders instead.
  • Namespace transfer request shapes changed. Internal artifact routes use include.definitions, include.units, and include.files; the old top-level files: { mode: ... } shape is no longer the documented contract.

Beta 0.47.0

June 16, 2026

Namespace export and import

Export an entire namespace — schema, portals, data, arcs, and FILE attachments — to a verified artifact, and import it into a fresh target. Imports are chunked and crash-resumable, exports can stream as NDJSON + zstd, artifacts can live on disk or S3, and Studio gets a full artifact browser to export, browse, and restore right from the Namespaces panel.

Features
  • Whole-namespace export / import. Export a namespace to a blake3-verified artifact and import it into an empty target (auto-created when missing) over HTTP, the TypeScript SDK (NamespaceClient.export / import / importStatus), and MCP. A per-namespace maintenance lock blocks writes during export and blocks reads + writes during restore, and a crashed import auto-recovers on the next boot.
  • Chunked, crash-resumable imports. Imports commit per chunk (chunkSize, default 1,000) behind typed checkpoints. Re-importing the same artifact resumes from the last committed chunk instead of starting over, so peak memory scales with chunk size, not artifact size.
  • Streaming NDJSON + zstd, disk or S3 artifacts. Exports can stream as an NDJSON line format with per-chunk zstd frames (opt in with payload: "ndjsonZstd") to lift the in-memory size ceiling for large namespaces, and artifacts can be stored on local disk or in S3 with multipart, manifest-last atomic publish.
  • FILE / blob round-trip. Export and import namespaces with their FILE attachments via files: "all" or per-subspace files: "selective" (the default stays "rejected"). Each blob is blake3-verified on import and re-materialized as a fresh, re-scanned attachment in the target namespace.
  • Studio import / export UI. The Namespaces panel gains an artifact browser (refresh, copy ID, import, delete), an export modal with subspace selection and a FILE mode (none / all / selective), live import-status polling, and maintenance badges — with export disabled while reads are blocked.
Improvements
  • Server-owned export plan. GET /namespace/export/plan lets the UI preview exactly what an export will contain before running it.
  • Per-database artifact isolation. Artifact stores are scoped per database, so listing, exporting, and importing only ever see the current database's artifacts.

Beta 0.46.0

June 13, 2026

MCP namespace targeting

AI agents connected over MCP choose a namespace target during OAuth, use opts.defaultSubspace per call for subspace routing, and get the matching API handoff through api.connection. OAuth dynamic client registration is hardened against unsafe redirect URIs.

Features
  • MCP namespace targeting is grant-bound: OAuth target selection binds the grant to one Space namespace. Reconnect BlitzGraph MCP to change namespace; use opts.defaultSubspace when a single call should use a different subspace default.
  • api.connection reports the grant target. Alongside url, database, namespace, auth, and docs, it returns the grant space, namespace default subspace, routing guidance, and capability flags for direct API/SDK handoff.
  • Workspace tools no longer retarget grants. spaces.list / spaces.create and subspaces.list / subspaces.create are available for discovery and setup; subspaces.setDefault changes the shared namespace default.
Improvements
  • OAuth registration is stricter. Dynamic client registration at /api/auth/mcp/register validates redirect_uris — bind-only hosts (0.0.0.0, [::]), non-loopback http, and dangerous schemes (javascript:, data:, file:, …) are rejected with RFC 7591 invalid_redirect_uri, while loopback, https, and custom-scheme-with-host URIs keep working.

Beta 0.45.0

June 9, 2026

Batch-size guardrails

Authored mutation batches now carry a soft size cap, so a single oversized request fails fast with a clear error instead of exhausting memory or holding a long write-conflict window. Defaults are generous, configurable per call and per namespace, and reported on /config.

Features
  • maxBatchSize soft caps. db.mutate() defaults to 10,000 operations per call and definition_mutate to 500 items. Breaching either returns BATCH_TOO_LARGE, pointing data callers at chunked data_import (or namespace import) and definition callers at smaller batches. The cap is checked after $for / $if expansion, before the batch is materialized.
  • Configurable and visible. Raise maxBatchSize per call (up to the server hard cap) or per namespace (mutation.maxBatchSize / definitionMutation.maxBatchSize, raise-only and clamped to the hard cap). The effective values now show up under /config. maxTotalGeneratedItems (100,000) stays the absolute $for expansion ceiling.
Breaking Changes
  • The data cap counts every operation, not just creates. Batch size is now the count of all root and nested mutation nodes (create / update / upsert / delete / query) plus each explicit arc link / unlink / replace target; a filter-scoped bulk op still counts as one. Large explicit update / delete / link batches that used to slip past the cap now correctly trip it, and the BATCH_TOO_LARGE payload reports unit: "operations" (was "units").

Beta 0.44.0

June 5, 2026

Filter and sort relationships by arc time

Relationship queries can now filter and sort by when each edge was created — $arcCreatedAt becomes a first-class predicate and sort key inside $expandArc, evaluated before the connected units are fetched.

Features
  • Filter and sort by arc creation time. Inside $expandArc, $arcCreatedAt is now filterable and sortable: { "$expandArc": "members", "$filter": { "$arcCreatedAt": { "$gte": { "#datetime": "…" } } }, "$sort": "-$arcCreatedAt" }. Comparison operators only, as a top-level condition (or inside a top-level $and), and only as the primary sort key. The predicate is evaluated before unit fetch, so non-matching children are pruned early.
Fixes
  • $expandArc with $limit keeps its arc timestamps. A paged direct role-field expand used to return $arcCreatedAt: null; it now always takes the timed scan. Two-hop expands report max(hop1, hop2).

Beta 0.43.0

June 3, 2026

Cursor pagination and a clearer, stricter API

Queries can page through large result sets with an opaque cursor, responses now warn when a filter quietly matches nothing, and definition reads echo the subspace they resolved against. /admin joins the canonical request envelope, and options that were never implemented now reject loudly instead of pretending to work.

Features
  • Cursor pagination. Pass $cursor with $limit and replay meta.$nextCursor verbatim to walk a large result set; no $nextCursor means the last page. The token is opaque — never parse or build it — and excludes $offset. Root queries only; $groupBy and root aggregates are rejected.
  • Queries return warnings. A query whose filter matched zero units (and was not an identity or $offset lookup), or that used an empty $in: [], now comes back with a warnings entry explaining why, so an empty result is no longer a silent dead end.
  • Subspace observability on definition reads. definitions/query (single-object) and the definitions / schema / portals exports echo the resolved meta.subspace. When the read is empty but the namespace has other subspaces, a warning names them and points you at opts.defaultSubspace.
Breaking Changes
  • POST /admin uses the canonical envelope { "admin": { … }, "opts"?: { … } }. The bare top-level resource body is rejected; the SDK and control plane already send the new shape.
  • Options that were never implemented now reject. parallel (on queries and mutations) and limits.maxMemoryBytes / limits.maxRegexComplexity return NOT_IMPLEMENTED instead of being silently ignored, and parallel is gone from namespace overrides and the Studio options modal.
  • Unknown option keys are rejected with a structured UNKNOWN_OPTS_KEY (carrying { unknown, allowed }) on every envelope endpoint, including multipart /mutate. Rate-limit (429), quota (429), and timeout (408) responses now use the canonical { errors: [{ code, message }] } shape, and a new SUBSPACE_LIMIT_EXCEEDED code replaces a miscategorized INVALID_QUERY.

Beta 0.42.0

May 30, 2026

Search 2.0 and deterministic query planning

Full-text search is rebuilt on an LSM-style derived index whose segments are written inside the same transaction as your data — so a committed unit is always searchable and large imports no longer fail with opaque storage errors. And the engine now picks query indexes deterministically, ending the bimodal latency where the same query could be fast or slow at random.

Features
  • FTS 2.0: the search index commits with your data. Full-text segments are now written inside the mutation transaction instead of by a separate post-commit writer. A unit that committed is guaranteed searchable, and a failed write rolls back its index changes atomically.
Improvements
  • Large search imports are reliable. Bulk full-text imports of tens of thousands of documents no longer intermittently fail with opaque RocksDB TryAgain errors. When a burst of writes outpaces the search index, the server returns a clean 429 backpressure signal that bulk import retries on, instead of a cryptic failure.
  • Deterministic, unique-first index selection. A query touching both a unique and an indexed field used to resolve through whichever index happened to come up first — so the same query could take ~25µs (unique point lookup) or ~2.4ms (multi-thousand-row field scan) at random. The engine now ranks candidates unique-first across the whole $and tree, eliminating the swing.
  • Unique-only fields finally use their index. A field marked unique but not indexed used to silently fall back to a full kind scan; equality lookups on it now resolve through the unique index as documented. Index-resolution storage errors propagate instead of degrading to a scan.
Fixes
  • Ambiguous multi-kind writes error clearly. Writing a field that resolves to conflicting definitions across a unit's kinds now returns AMBIGUOUS_FIELD instead of guessing a winner.

Beta 0.41.0

May 26, 2026

Atomic schema changes

Saving a batch of schema changes is now all-or-nothing: definition_mutate runs the whole batch in a single transaction, so if one item fails the rest roll back cleanly instead of leaving half-applied kinds, fields, or portals behind. Deleting a unit now also records the relationships it breaks as proper unlink events.

Features
  • Schema edits are all-or-nothing. A definition_mutate batch — kinds, fields, apps, components, hooks, and the schema-version bump — now commits in a single transaction. Either every item lands or none does, matching the atomicity of a data mutation batch, and import / wipe are atomic per call too. A mid-batch failure rolls back to the exact pre-batch state, so a failed schema migration never leaves a half-updated schema behind.
  • Deletes record the links they break. When deleting a unit breaks its relationships, those breaks now surface as unlink events — in normalized mutation output, in $history, and in the $delta.arcs.unlink seen by survivor update hooks. Previously a plain delete removed the arcs silently, with no trail for audit or hook logic.

Beta 0.40.0

May 18, 2026

Schema-level hooks

Hooks now live at the top of the schema as a named, BQL-shaped registry, not embedded inside each kind. The mutation pipeline routes per-unit with precise validate/transform/effect gating, the commit-event diff records exactly which keys moved, and Studio surfaces the registry as a first-class section. Pre-launch breaking change: legacy per-kind hooks blocks are no longer accepted on import.

Features
  • definition_mutate knows about hooks. Create / update / delete / query via { "$type": "hook", "name": "..." }. Schema events emit $sid (hook name) for hook ops and $did for kinds/fields, so audit subscribers can distinguish the two without parsing the type.
  • Per-unit hook gating. The validate / transform / effect gates short-circuit at the unit level — a batch that mixes a hooked kind (e.g. Post) with an unhooked kind (e.g. User) only runs hooks against Post. Multi-subspace batches stay correct because the gate inspects each unit's subspace.
  • Hook dependency validation on schema deletes. Deleting a kind or field that a hook still targets fails with a clear error before any prefix is written. Renaming a field that a hook filter references in the same batch is allowed if the hook update lands first; otherwise the batch is rejected as dangling.
  • Transform conflict detection across hooks. When two top-level transform hooks write the same leaf path on the same unit during one pass, the batch errors out instead of silently picking the last writer.
  • Studio Hooks sidebar. Schema sidebar shows a Hooks section with a Zap icon, hook name, and type chip (unit.validate / unit.transform / unit.effect). Renders even when there are no kinds yet, so freshly-imported hook-only schemas are visible.
Improvements
  • Commit-event diff is precise for hook updates. Only the keys that actually changed appear in changed / details. Optional fields removed by the update (e.g. dropping when or timeoutMs) are recorded with a null sentinel so audit subscribers can tell "removed" apart from "unchanged".
  • Schema version stays consistent on dep-check rollback. Hook CRUD no longer inline-persists the schema version — the outer dispatcher does it after validate_hook_dependencies clears, so a rejected batch leaves the on-disk version exactly where it was.
  • Bulk hook load on schema open. set_hooks_bulk indexes the entire hook set once instead of rebuilding the index on every insert.
  • Duplicate-kind entries in $kinds.$any collapse to one index slot, so ["Post", "Post"] no longer fires the hook twice.
Fixes
  • Top-level effect snapshot path matches per-unit gating. A batch touching only unhooked kinds no longer pays the snapshot cost when the schema declares effect hooks elsewhere.
  • definition_import rejects the legacy per-kind hooks block with an explicit error instead of silently dropping it.
Breaking Changes
  • Hooks move to schema.hooks. The per-kind hooks block on KindDef is removed. Hooks now live in a top-level map keyed by hook name (schema.hooks["Post.audit"] = { type, target: { ops, $kinds, $filter }, $js }). Existing definitions must be rewritten — there is no transparent migration.
  • schema.hooks targets are BQL-shaped. A hook declares its target with { ops, $kinds, $filter }. ops accepts create | update | delete; link and unlink are rejected at parse time (use update on the role/link field for those). $filter rejects arc-field paths.
  • Hook arity per name is 1. Each hook is identified by name and replaces in place — update is full-replace semantics. Use distinct names to attach multiple hooks to the same kind.

Beta 0.39.0

May 17, 2026

Safer portals, smarter Studio, and ergonomic SDK

Portal save now catches broken hooks and undefined variables before they reach the browser. Components can be renamed with all import paths updated automatically. The React SDK drops the empty-input boilerplate for no-input operations.

Features
  • Portal hooks validated at save time. Unknown hooks, definition-domain hooks (schema/portals API), and cross-source hook usage are rejected when saving a page or component — with a did-you-mean suggestion — instead of failing silently at browser runtime.
  • Portal undefined variables caught at save time. Typos in variable names (e.g. useMutationn) are now detected by semantic analysis and rejected with the offending line number and a spelling suggestion.
  • Component rename rewrites all imports. Renaming a component in Pages Builder cascades @components/OldName@components/NewName across every page, layout, and component that references it.
  • useQuery(ref) no longer requires {} for operations with no input fields. Pass the ref alone when the input schema is empty; ops with required fields still type-check as before.
  • $search gains $mode: "all" to run all search strategies simultaneously, returning the broadest match set.
Improvements
  • Studio: double-click a kind or field row to edit it directly. The kind edit modal opens on the matching tab with that field pre-selected.
  • BQL completions are mode-aware. $code and $js no longer appear at the query/mutation root (they are only valid inside field-value objects).
  • additionalProperties strict-mode errors include the reason. Validation rejections now say which field triggered the extra-property check.
  • Doc search finds concepts faster. Frontmatter aliases and stemmed boosting surface the right page with partial or alternate terms.
Fixes
  • Namespace-imported hooks (import { useQuery } from "@blitzgraph/client-react") are now validated the same as default imports — the bypass is closed.
  • Saving an app no longer silently drops pages or layouts included in the update payload; they are rejected explicitly.
  • FTS segment flush is now High priority so index updates are not starved by lower-priority background tasks.

Beta 0.38.0

May 14, 2026

Roundtrip-safe data import and export

BlitzGraph data exports now produce query-shaped units that can be imported with minimal drift, including cross-subspace references and stable arc wiring.

Improvements
  • Imports support multiple subspaces in one payload. Root and nested create items can carry $subspace, matching normal mutation defaults while keeping $id references scoped correctly.
  • Export output mirrors query output more closely. Link fields and role fields can both appear in exported units so the data shape stays familiar to query consumers.
  • Import errors are more precise. Duplicate $id, non-create $op, id conflicts, and missing kind context now return structured error codes for SDK and MCP callers.
Fixes
  • Roundtrip imports preserve exported relationships without requiring callers to hand-author $var aliases.
  • Import ignores exported $iid values instead of trying to preserve internal ULIDs.
Breaking Changes
  • Data import is create-only. /data/import accepts missing $op or $op: "create" and rejects update-style import items.
  • Export no longer emits mutation-only fields. Exported units omit $op, $var, and $iid; import treats $id as the roundtrip reference key for rebuilding arcs inside the imported payload.

Beta 0.37.1

May 14, 2026

Scan-aware FILE uploads

BlitzGraph FILE uploads now share stricter validation across Studio and portals, expose scan-aware readiness, and refresh expiring file links from the client.

Improvements
  • FILE uploads are harder to spoof. Browser uploads now share filename, MIME allowlist, magic-byte, size, and finalize checks across presign, inline mutation, and portal flows.
  • File links are scan-aware. Processing or blocked files no longer expose signed URLs, while ready files include URL expiry metadata so clients can refresh before links expire.
  • React FILE previews handle security states. Processing and blocked attachments render explicit states, while expiring signed links refresh before they become dead download links.
Fixes
  • Inline portal uploads now use the same FILE validation path as staged uploads, closing bypasses around declared MIME types and executable payloads.
  • Malicious attachment filenames render as plain text in React previews.

Beta 0.37.0

May 14, 2026

Canonical imports, safer portals, and hosted hardening

BlitzGraph now uses one canonical envelope for HTTP, SDK, and MCP imports/exports, validates portal apps before saving broken code, and tightens hosted security, uploads, feedback, and data protection.

Features
  • Schema and portals can be imported/exported independently. Use /schema/import|export for kinds only, /portals/import|export for apps/components only, and /definitions/import|export for the full bundle.
  • Subspace opts accept names or numeric IDs. HTTP, SDK, and generated types now share the same opts.defaultSubspace shape as per-item $subspace.
  • Public Bugs / feedback dialog. The marketing header can now send bug reports, feature requests, friction notes, or other feedback through a rate-limited marketing.feedback.send op.
Improvements
  • MCP import tools match the HTTP/SDK contracts. data.import now uses { units, opts }, preserves optional opts, and rejects unknown wrapper keys before execution.
  • Portal ops fail earlier and clearer. queryOps / mutationOps BQL, $input markers, declared inputSchema, and mutation invalidation targets are validated before an app is saved.
  • Hosted security is stricter. BlitzGraph now sends centralized CSP/security headers, hides the Next.js version header, and keeps required presigned S3 upload origins allowed for FILE uploads.
  • Hosted data protection is explicit. Server data lives on dedicated /data volumes with daily snapshots and environment-specific retention.
Fixes
  • Scoped imports now keep their opts.defaultSubspace target through SDK, MCP, seed, and HTTP paths, preventing schema/data imports from landing in the wrong subspace.
  • FILE uploads from Studio and portals are no longer blocked by the app CSP when using presigned S3 upload URLs.
  • Server-side PostHog exception reporting flushes in the background, so telemetry does not block user responses.
Breaking Changes
  • Definition endpoints are pluralized. Use /definitions/query, /definitions/mutate, /definitions/import, and /definitions/export. The old /definition/* paths are gone.
  • Import/export bodies use canonical envelopes. /data/import takes { units, opts? }; /data/export takes { selector?, opts? }; definition/schema/portal imports carry opts in the JSON body. Subspace defaults now live at opts.defaultSubspace.
  • Options are camelCase only. Use timeoutMs, failFast, returnMode, defaultMeta, maxErrors, onExprError, etc. Snake_case option keys and root-level request subspace fields are rejected.
  • Data import/export response keys are camelCase. Import progress/results expose inputItems, unitsCreated, and byKind; export chunks/results expose units instead of items.
  • Portal TSX must use generated refs from @app/ops. String op names, inline/local refs, tuple-destructured hooks, and broken TSX/server modules now reject at save time.

Beta 0.36.0

May 13, 2026

Granular subspace wipes: schema-only and portals-only

wipe_schema previously wiped both schema (kinds) and portals (apps + components) together. It now clears kinds only — portals survive. The previous combined behavior moved to wipe_definitions. A new wipe_portals clears apps and components without touching kinds or data.

Features
  • New admin op wipe_definitions — kinds + schema events + apps + components. Same KV scope as definition/import. Rejected when unit data exists.
  • New admin op wipe_portals — apps + components only. Kinds and unit data survive. No data-empty guard, since portals do not constrain unit data.
  • TS sub-accessors: subspace.data.wipe(), subspace.definitions.wipe(), subspace.schema.wipe(), subspace.portals.wipe() mirror the four admin ops. Top-level subspaceWipeData / wipeDefinitions / wipeSchema / wipePortals shorthands available on BlitzGraphClient and NamespaceClient.
  • Four MCP tools: data.wipe, definitions.wipe, schema.wipe, portals.wipe.
Fixes
  • Full-reset guidance in SCHEMA_ALREADY_EXISTS and SUBSPACE_HAS_DATA error messages now suggests wipe_definitions() instead of wipe_schema(), so portals are not left behind on a full reset (the subsequent additive definition_import() would have failed with portal overlap).
Breaking Changes
  • Admin op wipe_schema semantics changed. It was a full definitions wipe (kinds + apps + components); it is now kinds-only. Use wipe_definitions (admin op) / subspace.definitions.wipe() (TS) for the previous behavior.
  • TS SDK wipeSchema semantics changed identically. subspace.schema.wipe(), client.subspaceWipeSchema(), and NamespaceClient.wipeSchema() no longer touch portals. Migrate full-reset call sites to wipeDefinitions() / subspaceWipeDefinitions().
  • Studio "Wipe Schema" button relabeled to "Wipe Definitions" since the call wipes both branches.

Beta 0.35.0

May 12, 2026

Full-screen Studio, steadier dashboard loading, and larger portal uploads

Studio now opens as a focused full-screen workspace from owner-scoped space URLs, dashboard space lists recover cleanly from rapid navigation and first-login bootstrap races, and portal mutation uploads work past Axum's 2 MiB default up to BlitzStore's configured body limit.

Features
  • Owner-scoped Studio opens full screen. /u/<owner>/<space>/studio and /o/<owner>/<space>/studio skip the regular webapp chrome and pin the resolved server connection so users land directly in the workspace.
  • Larger portal mutation uploads. Portal operations that include files or images can now pass the server's configured BlitzStore request limit instead of failing at Axum's 2 MiB default.
Improvements
  • Lighter MCP tool discovery. Generic unknown response schemas no longer crowd the tool list, while concrete result schemas remain for exports, docs, Studio links, feedback, and portal URLs.
  • Dashboard spaces load more reliably after cold login and quick remounts. Personal-space bootstrap is coalesced per user, and the React query cache no longer leaves aborted requests stuck in a permanent pending state.
  • Sign-out clears cached space data before redirect. Switching accounts no longer risks showing stale spaces from the previous identity during client-side navigation.
  • Open in Studio is placement-aware. The overview action is disabled until the space has a server placement, avoiding a dead-end Studio launch while provisioning is still pending.
  • Cleaner Studio loading states. Studio connection and workspace loading now use a consistent Blitz loader instead of small text-only spinners.
  • Cleaner link previews. Shared BlitzGraph landing-page URLs now include an Open Graph image.
  • Better abuse protection for public entry points. Sign-in, agent device auth, and feedback submission now return bounded rate-limit responses under repeated requests.

Beta 0.34.1

May 12, 2026

Quality-of-life fixes for portals, Studio, and MCP

Catches a common React-hooks mistake in portals at compile time instead of in the browser, accepts more shapes of valid schema and definition input, and tightens a few rough edges in the Tasks API, MCP server, and Studio Pages Builder.

Features
  • Portal compile catches const [x] = useMutation(ref) / useQuery(ref). The hooks return objects, not tuples, so this used to compile and then crash at runtime with is not iterable. Saving the portal now fails with a clear error pointing at the offending line — including namespace imports and bracket-form calls.
Fixes
  • /tasks?subspace=<name> accepts the subspace name (was numeric id only — Studio requests were returning 400).
  • schema_import / portals_import / set_definitions accept the natural map-shape input where the slug lives in the map key (portals.apps.<slug>). Previously these typed setters rejected payloads that the JSON import path accepted.
  • Studio Pages Builder and portal image CSP allow https://host:443 and other explicit-default-port forms in the external-image allowlist.
  • MCP server: per-session context cache now has a bounded LRU so long-lived agents no longer leak memory. Structured BlitzGraphError instances are still recognized as such after JS minification, so error codes propagate to clients instead of collapsing to a generic message.

Beta 0.34.0

May 10, 2026

File values, native expressions, and portal hardening

FILE fields are now first-class everywhere — storage, HTTP API, TypeScript SDK, portals, Studio, and MCP. BQL gains typed literals under #…, interval containment and overlap operators, and a checked native fast lane for virtual fields. Portals validate their operation schemas and serve under stricter image CSP, and definition import / export use direct endpoint contracts.

Features
  • First-class FILE fields. Write files inline with a File / Blob from the browser or with a finalized blob marker; read back a FileValue with filename, mime, size, hash, signed url, and thumbnail_url for images.
  • Blob upload APIs. New /blob/presign and /blob/finalize endpoints plus SDK helpers blob.uploadFile, blob.uploadFiles, and mutateMultipart. Regular mutate() auto-detects File / Blob values and switches to multipart for you.
  • React and Studio file UX. @blitzgraph/client-react exports FilePreview, FileDownloadLink, FileUploadInput, and useFileObjectUrl. BlitzSheet can preview, download, replace, and clear FILE cells.
  • Native BQL expressions. Virtual fields can use { "$expr": { "@text.concat": [...] } } as a checked native fast lane. $js stays available for everything else.
  • Portal operation contracts. queryOps and mutationOps can declare inputSchema / outputSchema. Generated @app/ops refs carry typed input/output validation and mutation invalidation metadata.
  • Portal image allowlist. Apps can declare portalSecurity.externalImages.manualOrigins for dynamic hosts; literal TSX image origins and blob storage origins are merged into the served CSP automatically.
  • MCP file tools. Agents can presign, upload, and finalize blobs through MCP — including a batch blob.uploadMany.
  • Branch-shaped definitions accessors. New schema_import / portals_import and typed set_schema / set_portals / set_definitions setters in Rust and TS take { kinds } or { apps, components } directly without manual wrapping, and reject cross-branch keys at parse time.
Improvements
  • Portal pages run under stricter CSP. Framing is denied, component previews only allow the matching Studio origins, and CSP reports are accepted at /csp-report.
  • BlitzGraph UI polish. Sidebar navigation, version badge, and Studio namespace / subspace selectors received a pass; space URLs are now scoped per owner.
Fixes
  • Space slugs are per-owner. Two owners can use the same slug; duplicates under the same owner are still rejected.
  • dev:data:noauth binds to loopback only. No more accidentally exposing an unauthenticated dev server on a LAN address.
  • Multipart uploads are size-capped before parsing. Portal operations require a declared content-length under the op body cap, and JSON requests cannot spoof multipart files metadata.
  • FILE download links reject unsafe protocols. Studio previews and downloads sanitize URLs before binding to src / href.
Breaking Changes
  • Typed literals moved to #… keys. Use { "#datetime": "…" }, { "#decimal": "…" }, { "#intervals": [...] }, etc. The $… prefix is reserved for BQL selectors and operators. Migrate any { "$decimal": "…" } / { "$intervals": [...] } you have.
  • Interval filters. $covers is gone. Use $contains for point or interval containment, $intersects for overlap.
  • Subspace option renamed. Query and mutation options use default_subspace instead of subspace. The per-item BQL $subspace and request-envelope subspace are unchanged.
  • Definition export has no JSON body. POST /definition/export?subspace=main expects an empty request body. Definition import accepts the full definitions document directly.
  • Definition import only accepts the nested shape { schema: { kinds }, portals: { apps, components } }. For branch-only payloads use the new schema_import / portals_import accessors instead of wrapping by hand.
  • FILE markers use #file. Multipart placeholders are { "#file": "file_0" }; finalized write markers are sealed { "#file": { …, "capability": "…" } } objects. Old $file / $cap shapes are rejected.
  • Portal op schemas are strict. inputSchema / outputSchema only accept the supported JSON Schema subset; object inputs must explicitly declare additionalProperties.

Beta 0.33.0

May 9, 2026

Cross-kind numeric conversions

Changing a field's valueType between INTEGER, DECIMAL, FLOAT, and PERCENTAGE now succeeds. The schema commit returns immediately; a background task rewrites stored rows using the field's numericPolicy. CURRENCY is carved out — it needs an FX policy that the runtime does not have yet.

Features
  • All 12 cross-kind conversions between INTEGER, DECIMAL, FLOAT, and PERCENTAGE are supported. Per-field numericPolicy controls rounding: rejectOnLoss (default), round (banker's), truncate (toward zero), or allowPrecisionLoss. NaN / ±Infinity always reject.
  • Two new error codes exported from @blitzgraph/client-core: NUMERIC_PRECISION_LOSS (per-row precision drop with { field, from, to, value }) and INVALID_NUMERIC_CONVERSION (unsupported numeric pair).
Improvements
  • round and allowPrecisionLoss use banker's rounding (2.5 → 2, 3.5 → 4); pick truncate explicitly when toward-zero is required.
  • rejectOnLoss now catches scale-only precision drops too (DECIMAL(scale=4) → PERCENTAGE(scale=2) with non-zero trailing digits errors instead of silently rounding).
  • FLOAT → INTEGER rejects out-of-range floats instead of silently saturating to i64::MAX.
Breaking Changes
  • Numeric valueType changes used to be rejected synchronously with INVALID_TEMPORAL_CONVERSION. They now commit immediately and a background task rewrites the rows; per-row failures surface on the task. UIs that disabled the picker on the old rejection should switch to checking task completion.
  • Unsupported numeric transitions now emit INVALID_NUMERIC_CONVERSION (was INVALID_TEMPORAL_CONVERSION for everything). Both codes are exported.
  • numericPolicy is now validated upfront: it is rejected if there is no valueType change, on temporal transitions, or with a typo. Previously these were silently ignored.

Beta 0.32.0

May 8, 2026

HTTP 422 on rejected bodies, batch topo-sort, object-shaped mutation hooks

Rejected bodies now surface at the transport layer (422 instead of 200 with errors[]). definition_mutate batches sort themselves by intra-batch dependencies so you no longer hand-order delete batches. React mutation hooks return objects instead of tuples, so misnamed destructure becomes a type error instead of a runtime undefined.

Features
  • definition_mutate batches are topo-sorted by intra-batch dependencies. Creates/updates run dependencies-first, deletes run dependents-first, mixed batches do all deletes before all creates. Schema-aware enrichment also pulls in refs the JSON doesn't carry (e.g. a $did-only delete on a linkField now correctly removes it before the roleField it tunnels through). The response array still preserves input position.
  • canonicalize_path_strict for the authoring boundary — definition_mutate errors loudly on non-canonical paths, while the existing tolerant import path keeps normalizing.
Improvements
  • TS client handles 422 transparently: the parsed BlitzResponse still comes back. Void-returning paths (deleteDatabase, …) raise BlitzGraphError with errors[] populated.
Breaking Changes
  • BQL, schema, admin, blob, and task endpoints return 422 Unprocessable Entity when errors[] is non-empty (was 200 OK). Clients using fetch + res.ok or default axios will see the rejection at the transport layer. The body shape is unchanged, so code that already inspected errors[] keeps working.
  • React mutation hooks (useMutation, useRawMutation, useScopedMutate, usePortalsMutate, useSchemaMutate, …) return { mutate, ...state } instead of [mutate, state]. Migrate via object destructure: const { mutate, isLoading } = useMutation(ref) or rename with const { mutate: createUser } = useMutation(ref). The previous tuple silently bound undefined on misnamed positions — now it's a compile error.

Beta 0.31.4

May 8, 2026

Symmetric relations and self-relation enforcement

symmetric: true and allowSelfRelation: false are now enforced at write time. Symmetric roles collapse A↔B and B↔A into a single edge; the default allowSelfRelation: false rejects a player appearing in multiple roles of the same relation unit.

Features
  • Symmetric roles reject duplicate reverse-direction edges (SYMMETRIC_RELATION_EXISTS) both for new edges in the same batch and against already-committed relations.
  • allowSelfRelation: false (the default) rejects the same player appearing in two or more distinct roles of one relation unit (SELF_RELATION_FORBIDDEN). Per-kind scoped, so multi-kind composition stays unaffected. Validation respects child overrides on inherited roles.
  • Error payloads include kind name, role name, and the offending player ID list — enough to fix the mutation without exposing unrelated units.

Beta 0.30.3

May 8, 2026

Safer destructive actions and clearer credential UX

Subspace cards no longer surface Wipe Data, Wipe Schema, and Delete on hover — they live behind a kebab menu so a stray click can't nuke a subspace. The same menu adds quick-open shortcuts to BlitzSheet and Query Studio (double-clicking a card also opens BlitzSheet). The Access page tightens credential management: rotate and revoke now go through a confirmation dialog with a description that spells out the consequence, the misleading row-level "copy" button (which copied JSON metadata, never the secret) is gone, the Last Used column is hidden until the backend actually populates it, and expiry shows date plus time and switches to "Expired …" once past. The Studio connection modal defaults to https:// when you type a URL without a scheme, and IPv6 loopback (::1, [::1]:3011) is now correctly classified as local.

Improvements
  • Subspaces panel: destructive actions (Wipe Data, Wipe Schema, Delete) moved into a kebab menu so accidental clicks can no longer trigger them. Same menu adds Open in BlitzSheet and Open in Query Studio; double-click opens BlitzSheet.
  • Access page: rotate / revoke require a confirmation dialog; expiry shows date + time and switches to "Expired …" once past.
  • Studio connection modal auto-prefixes https:// for non-loopback URLs (was http://); loopback (localhost, 127.0.0.1, ::1, [::1], *.localhost) keeps http://.
Fixes
  • Removed the row-level "Copy" button on the Access page — it serialized JSON metadata, never the actual secret. Tokens are hashed at rest, so only the Token Created modal and the rotate banner can return one.
  • Hid the "Last Used" column until the backend populates lastUsedAt. Token status derives "Expired" client-side; rotate / revoke disable for expired tokens.
  • normalizeStudioUrl IPv6 parsing fixed: ::1 and [::1]:3011 were classified as remote and silently received https://. Bracketed authority and bare-IPv6 are now handled correctly.

Beta 0.30.2

May 8, 2026

React SDK: stricter, safer types

@blitzgraph/client-react tightens its hook types so misuse fails to compile instead of crashing at runtime, and the cached query data is frozen so accidental in-place mutation is caught immediately.

Breaking Changes
  • useRawResource.data is now readonly T[], and the response array is frozen. Mutating helpers (push, in-place sort, …) stop type-checking and throw at runtime. Clone with [...result.data] if you need a mutable copy.
  • useInfiniteQuery(ref, …) requires a ref whose output is { items, nextCursor? }. Refs returning a plain array no longer compile.
  • useQuery / useRawQuery / useRawDefinitionQuery only accept a <TSelected> type parameter when you also pass a matching select projection. Omit the type argument for the identity case.

Beta 0.30.1

May 7, 2026

Structured envelope errors and better mutation error visibility

Envelope-level rejections now carry structured error codes, every content type ships its own prose docs through the SDK and JSON Schema, and mutation errors no longer disappear silently when batching against maxErrors.

Features
  • Envelope rejections now carry three structured codes — UNKNOWN_ENVELOPE_KEY, UNKNOWN_MULTIPART_FIELD, INVALID_ENVELOPE — with data: { unknown, allowed } so clients can branch on code instead of parsing prose.
  • Every content type now ships a docs: { summary, description, related } block. Generated TS, JSON Schema, and the marketing docs glossary all read from the same source.
  • useRawMutation accepts a mutationOpts field for forwarding execution options to the wire.
  • Browser-friendly 404 page for unknown portals (JSON clients still receive a JSON body). All portal 404s set Cache-Control: no-store so a stale 404 cannot shadow-ban a freshly created portal.
Improvements
  • Parse-time mutation validation now surfaces every per-item error in one response, even with failFast: true. Runtime fail-fast still applies to execution errors.
  • When the error list is truncated by maxErrors, MutateResult.info includes "N additional error(s) elided due to maxErrors" so truncation is no longer silent.
  • Portal 404 body no longer echoes the requested portal id — removes a trivial enumeration vector.

Beta 0.30.0

May 6, 2026

Numeric types split, typed error codes, and MCP tooling

NUMBER splits into INTEGER, DECIMAL, and FLOAT so indexes, aggregates, and sort orders are exact where it matters and lossy where it has to be. Server error codes are exposed as a typed TypeScript surface so clients can branch on stable strings. The MCP server gains tools for opening Studio, resolving portal URLs, and sending feedback.

Features
  • NUMBER splits into three explicit value types: INTEGER (exact i64), DECIMAL (arbitrary-precision base-10, max scale 28), and FLOAT (IEEE 754 f64). Pick INTEGER for counts/ids, DECIMAL for money and fractional measurements, FLOAT for ML / scientific values.
  • DECIMAL fields support optional fixed scale: 0..=28 and round-trip exactly through storage, indexes, aggregates, $js, and computed fields as { "#decimal": "<canonical-string>" }.
  • BlitzStudio sheet cells get dedicated INTEGER, DECIMAL, and FLOAT editors. The DECIMAL cell is precision-safe (no JS Number round-trip) and respects the field's scale.
  • Typed error-code surface in @blitzgraph/client-core: SERVER_ERROR_CODES, CLIENT_ERROR_CODES, ERROR_DESCRIPTORS, KnownErrorCode, and isKnownErrorCode(). Regenerated from the Rust registry so clients can branch on stable codes and policy metadata.
  • New numeric error codes: DECIMAL_SCALE_EXCEEDED, FLOAT_NOT_FINITE, INTEGER_OVERFLOW, DECIMAL_OVERFLOW.
  • MCP server gains three tools: studio.open (absolute Studio URL for the caller), portals.url (resolve app slug to public portal URL), feedback.send (post agent-authored reports to the control plane). The same feedback flow is also exposed via POST /agents/feedback.
  • MCP initialize ships an instructions string, per-tool annotations (readOnlyHint, destructiveHint, title), and docs URLs — ready for connector-store submission.
  • Pages Builder can rename pages and layouts directly from the tree, with path canonicalization and duplicate detection.
Improvements
  • PERCENTAGE is now backed by DECIMAL (was FLOAT), so percentages round-trip exactly through storage, indexes, and aggregates.
  • FLOAT is rejected as unique, indexed, idField, or interval-bounds value type at schema import — index keys would not be exact and unique would not survive NaN semantics.
  • MCP tools/call no longer races into duplicate token rotations on a cold cache: concurrent calls per access token now share one issuance.
  • Agent feedback writes are rate-limited per (IP, space) (30/hour). REST and MCP paths share one budget.
Fixes
  • Number JS built-in is no longer blocklisted inside $js bodies (broke expressions like Number(x)).
  • Switching a field out of CURRENCY no longer leaves stale currency metadata behind.
  • portals.url only treats HTTP 404 as "portal not found" — transient 5xx and network errors no longer mask a misconfigured portal as missing.
Breaking Changes
  • valueType: "NUMBER" is no longer accepted. Migrate each field to INTEGER, DECIMAL, or FLOAT. Schema import and definition_mutate reject NUMBER with a migration hint.
  • Cross-numeric valueType transitions are rejected with UnsupportedTransition in this release. They land properly in 0.33.0.
  • DECIMAL aggregate results (SUM, AVG, MIN, MAX, MEDIAN) are now canonical decimal strings rather than JSON numbers. Read them via { "#decimal": "..." } or parse the string directly. STDDEV continues to return f64.
  • $js and computed-field code emitting decimals must use { "#decimal": "<string>" } for DECIMAL fields. Returning a JS number may lose precision and is rejected for non-finite values.
  • NaN and ±Infinity are rejected at every DECIMAL coercion boundary with FLOAT_NOT_FINITE (previously silently produced corrupted index keys).
  • Pre-launch policy: existing dev databases were wiped as part of the numeric split. Re-import schemas and data on upgrade.

Beta 0.29.0

May 2, 2026

Native Currency, definition_query projection, and path-keyed portals

CURRENCY becomes a first-class value type with fixed-currency or multi-currency declarations at the schema level. definition_query adopts the BQL projection model with identity-only defaults. Portals replace routeTree with path-keyed layouts and per-page overrides. BQL contracts get tighter: $ids is gone, valueType replaces type, and definition payloads reject unknown keys.

Features
  • Native CURRENCY value type with fixed (currency: "USD") or multi-currency (currency: "*") declarations. Wire shape: { amount: DecimalString, currency: ISO4217Alpha3 }, validated end-to-end.
  • Fixed-currency fields DX-expand bare scalar writes and filters (19.99, { "$gt": 100 }) into canonical money objects. Multi-currency fields require the explicit { amount, currency } shape.
  • BlitzStudio renders CURRENCY values as amount currency, accepts paste coercion ("24500 USD" → canonical object), and exposes a currency picker on field editing.
  • New endpoint POST /docs/batch and TS helper client.docs.batch(req) for ordered multi-doc lookup with duplicate preservation and result: null for misses.
  • definition_query supports $as aliases on identity fields and $expand children.
  • Per-page layoutChainOverride: string[] | null on portal pages with tri-state semantics: absent inherits, [] opts out, [...] is an explicit override.
  • New TS surface subspace.definitions.{query,mutate}() (raw passthrough, no family validation) for mixed schema+portal batches, backed by matching MCP tools.
  • New layout.delete mutation in the portals client-ops surface.
Improvements
  • CURRENCY parse errors pinpoint the exact failure (bad ISO code, missing keys, lossy JSON float, malformed decimal) instead of a generic type mismatch.
  • BQL comparison operators on CURRENCY use schema-aware coercion and exact decimal comparison within the same currency.
  • Aborted batch mutations return commit-truthful responses: phantom IDs from never-persisted units are stripped, surviving IDs are rewritten to their public idField value.
  • Portal page and layout paths are canonicalized on bulk import (collapsing repeated slashes, stripping trailing slashes), and duplicate canonical paths fail with an explicit error.
  • Batch errors preserve their original code and expose the item index through structured issues[].path attribution.
  • React SDK cache invalidation now correctly handles $id in scalar, array, and $in shapes, and invalidates on unlink (was missed).
Fixes
  • Failed batch creates no longer leak phantom $id values when errorMode: "collect" is in effect (including nested inline creates).
  • Failed batches under returnMode: "normalized" no longer synthesize fake $op commit operations for items that never committed.
  • Transient updated / created / deleted flags are stripped only at the top level — user-defined fields by those names are preserved.
  • Switching a field away from CURRENCY clears stale currency metadata so export / import round-trips do not fail later.
Breaking Changes
  • $ids is removed end-to-end. Use $id: [a, b] (sugar) or $id: { "$in": [...] } (canonical). Bulk-delete responses also use $id instead of $ids.
  • Data fields must use valueType instead of type, and kinds must use dataFields (object) instead of fields (array). No alias, no shim.
  • Definition payloads reject unknown keys (additionalProperties: false everywhere).
  • Root update mutations require an explicit selector ($id, $iid, $kinds, $filter, $search, or $var). Tunnel and arc-scoped update no longer accept $setKinds (set kinds at the root level only).
  • definition_query defaults to identity-only payloads. Omitting $fields returns only $type, $did, and the type-specific identity (slug / name / path). Heavy fields like tsxSource, clientJs, and compile artifacts require $fields: "*" or explicit projection.
  • $expand is only valid inside $fields and is restricted per definition type: app → pages / layouts / $history, page → layouts / $history, layout / component → $history only. Unsupported $expand options now error instead of being silently ignored.
  • definition_query $filter accepts equality and $in only (not the full BQL DSL); filtering on pages or layouts requires a map shape or null.
  • CURRENCY fields must declare currency (ISO 4217 alpha-3 or "*"). Multi-currency fields reject bare scalar writes and filter probes with CURRENCY_AMBIGUOUS; fixed-currency rejects mismatched currency with CURRENCY_MISMATCH. Cross-currency comparisons on multi-currency fields currently match nothing silently; convert to a canonical currency via a computed field for now.
  • Portals: routeTree is removed; DefinitionApp.layouts is keyed by path, not by name. Rename layout keys from labels ("root", "dashboard") to paths ("/", "/dashboard"). Layout chains are derived from page-path ancestors.
  • @blitzgraph/client-core renames OperatorDoc / OperatorDocSchema to DocOperator / DocOperatorSchema and removes the route-tree types (DefinitionRouteNode, DefinitionRouteGroup, DefinitionRoutePage).

Beta 0.28.0

April 27, 2026

Temporal types, stricter BQL, and schema integrity

Native DATE, DATETIME, TIME, and interval values land across the runtime, Studio, and client helpers. BQL validates malformed queries and mutations at the boundary instead of executing partially, and schema mutations refuse to leave dangling linkFields or role references behind.

Features
  • Native DATE (YYYY-MM-DD), DATETIME (YYYY-MM-DDTHH:MM:SS.SSSZ), and TIME (HH:MM:SS.SSS) value types with canonical wire formats.
  • Native interval values via { "#intervals": [...] }; queried with $contains (point or set containment) and $intersects (set overlap).
  • @blitzgraph/client-core exports temporal helpers (formatDate, formatDateTime, formatTime, isCanonical*, wrapTemporalCast).
  • Mutation roots and arc operations support multi-target selectors and narrowing with $id.$in, $iid, $iid.$in, $filter, $search, $kinds, $sort, $limit, and $offset.
  • Responses include a detailed meta.timings breakdown; @blitzgraph/client-core exposes getResponseClientTimings() for client-side response + JSON parse timing, and Studio shows the breakdown.
  • @blitzgraph/client-react/raw entrypoint with isolated cache keys for raw definition hooks, accepting BqlBatchQuery / BqlBatchMutation.
  • Background TaskManager gains a real three-phase IndexRebuild handler; schema type-change dispatch (FTS reindex + field conversion) is wired end-to-end.
Improvements
  • BQL query preparation is unified before execution, so root keys, selectors, filters, $fields, nested $expand, $expandArc, $groupBy, $sort, and $score are checked consistently.
  • Definition import / mutate validates linkField ownership against role playedBy (including inherited kinds) and rejects invalid target / targetRoles.
  • Role renames propagate to dependent link.plays and tunnel targetRoles. Role deletes, playedBy narrowing, and kind deletes are blocked when they would leave dangling links.
  • Schema mutation rejects unsupported value_type transitions at commit time instead of corrupting stored values.
  • update_kind_in with parent: null now actually clears the parent (was a silent no-op).
  • Auth/context HTTP failures return canonical errors: [{ code, message }] responses; MCP tool failures preserve structured error identity in structuredContent.error.
  • Bearer auth strictly accepts only bzt_* and bzi_* token prefixes.
  • BlitzGraph Studio renders and validates DATE, DATETIME, and TIME as distinct types; control / auth timestamp fields use DATETIME.
Fixes
  • Nested $fields, $expand, and $expandArc projections are recursively validated against the resolved target kinds.
  • Definition exports emit wildcard role playedBy as ["*"] instead of an empty array.
  • Role rename keeps local linkFields on descendant kinds intact instead of overwriting them.
  • Scoped arc mutations targeted by $id resolve through the engine, so custom-idField lookups work inside parent-scoped contexts.
  • BQL topo sort skips line / block comments and regex literals when walking arrow bodies, so JS defaults containing these tokens no longer corrupt dependency analysis.
  • Portal asset bodies scrub raw engine internals outside dev mode.
Breaking Changes
  • DATE no longer accepts timestamp strings. Use DATETIME for instants.
  • Interval values must use { "#intervals": [...] }; replace $includes / $overlaps filters with $contains / $intersects.
  • The untagged { "min": n, "max": n } cardinality shortcut is removed — use "MANY" (with optional min / max siblings) or { "MANY": { "min": n, "max": n } }.
  • BQL validation is stricter: malformed $and / $or / $not, unknown $... filter operators, unknown multi-kind fields, scalar $expand, and ambiguous JSON-vs-arc paths now fail instead of being silently ignored.
  • $meta is no longer accepted as a root query key — use it only inside $fields.
  • Query-backed mutation selectors ($filter, $search) resolve against the mutation-start snapshot. To target units created earlier in the same batch, capture them with $var.
  • Upsert requires exactly one scalar identity selector ($id, $iid, or $filter); $id.$in, $iid.$in, $sort, $limit, and $offset are rejected.
  • Schema mutation is stricter: creating a role without playedBy errors, invalid linkField owners error, inherited role / link clones cannot be edited through descendants, role deletes are rejected while dependent linkFields exist.
  • @blitzgraph/client-react split into a root surface (typed safe operations) and a /raw surface (raw definition / resource hooks). useResource is renamed to useRawResource and moved to /raw.
  • @blitzgraph/client-core renamed the public auth surface to token. The previous auth* exports were removed.
  • KindDef is no longer exported from generated/schema; source kind definitions from the dedicated defs entry point.
  • Portals: layouts use name as the authoritative key (no more path); pages and layouts must be sent as a map, not an array. The dead segment, isGroup, hasLayout, and synthetic /_layout/{index} slots are removed.

Beta 0.26.0

April 18, 2026

Agent tooling, safe operations, and a full storage reset

AI coding agents talk to BlitzGraph over MCP, client packages move to @blitzgraph/, contract-backed docs are served at /docs/, the web app moves to typed safe operations with a unified cache, HTTP auth unifies on Authorization: Bearer, and the storage layout is reset to widen subspaces to 65,535 per namespace.

Features
  • Google OAuth sign-in alongside GitHub and magic link.
  • Public MCP server at /mcp. Claude Code and Codex connect as remote MCP hosts with device-flow OAuth.
  • Typed MCP tool surface: schema and portal export/import/query/mutate, BQL data query/mutate, and docs.* (overview/concept/operator/example/list/search).
  • Dynamic MCP resources: blitzgraph://schema/current, blitzgraph://docs/overview, and one per concept, enumerated live from the contract at resources/list time (no codegen drift).
  • /docs/* HTTP surface (overview, concept, operator, example, list, search) served from the Rust contract as the single source of truth.
  • Safe operations layer: typed client-ops refs, same-origin CSRF check, streamed body size limit, RFC 7239 Forwarded parsing, per-user sliding-window rate limit, and default-deny authorization per ref.
  • Unified operation cache with normalized units, descriptor-based family invalidation, optimistic updates, prefetch for RSC, Suspense-first queries, and infinite-query support.
  • Subspace capacity widened to 65,535 per namespace (up from 255).
  • Task routing is now target-aware with stable ID-based targets for database, namespace, subspace, kind, and field work.
  • Namespace-scoped principals can now list and operate on tasks within their own namespace.
Improvements
  • Definitions reshape: on the wire every bundle is { $bzv, schema, portals }. The TS client exposes client.schema, client.portals, and client.definitions accessors over the same HTTP endpoints.
  • definition_import is strictly additive (rejects overlapping kinds, apps, or components). Mixed nested + flat DX payloads are hoisted into the canonical nested shape before the overlap check, so no branch can slip past.
  • Admin namespace and subspace responses expose stable numeric $rid values (ns:1, ss:2) that survive renames.
  • Blob cleanup, usage metering, and task routing all handle subspace IDs above 255 correctly.
  • Storage internals now use explicit system namespace and system subspace planes instead of overloaded auth-style metadata slots.
  • Agent device verification page redesigned with branded UI.
  • Billing upgrade flow simplified to a "book a call" modal.
  • Space overview replaces connection bundle reveal with retry provisioning.
  • Marketing hero and background paint is smoother under animation thanks to explicit stacking-context isolation and will-change transform hints.
  • Feedback widget loads its Slack thread only after the launcher is opened, so marketing pages start with one less network round-trip.
Fixes
  • Namespace-scoped task APIs no longer leak foreign-namespace tasks or database-level tasks.
  • FTS reindex tasks now trigger correctly for field-level schema mutations.
  • Blob orphan cleanup now scans all known subspaces before deleting objects, including high-numbered ones.
  • Subspace and namespace drop paths clean up routed task state more safely; drop(unknown_namespace) returns UnknownNamespace instead of panicking.
  • CSRF: honor the rightmost element of the RFC 7239 Forwarded header (appended by the proxy closest to us). A forged leftmost value can no longer forge same-origin.
  • Rate limit IP derivation no longer trusts X-Forwarded-For or X-Real-IP. A value is only used when BLITZGRAPH_HTTP_TRUST_PROXY_HEADERS_ENABLED=true and parsed from the rightmost for= entry. Otherwise rate limiting falls back to the userId (or a shared anonymous bucket).
  • Body-size cap on /api/ops/* is enforced while streaming chunks; oversized payloads no longer allocate before rejection.
  • Handler errors on /api/ops/* log full server-side and surface an opaque fallback to the client, so driver messages can't leak.
  • useQuery cleanup only aborts the in-flight fetch when the LAST observer for that key unmounts. Sibling components sharing a deduped request no longer get stuck on pending.
  • Operation descriptor context tracks the effective scope from input (caller overrides provider), so family invalidation tags records under the namespace they actually queried.
  • Social sign-in buttons stay disabled during OAuth redirect to prevent double-click.
  • MCP OAuth metadata consistently includes the mcp scope across all discovery endpoints.
  • transport.parseError guards the JSON body parse, so malformed 5xx bodies surface with the HTTP status instead of a SyntaxError.
  • BlitzStudio schema view keeps the last good schema on a refresh failure instead of wiping the cache to { kinds: {} }.
  • controlSpaces{Create,Update}Ref reject whitespace-only names at the schema boundary.
  • Marketing background noise layer is correctly scoped via isolation: isolate so mix-blend-overlay no longer flickers or bleeds into page chrome.
  • Marketing header anchors (#playground, #features, #compare) use absolute paths so they work from /docs and other non-home pages.
  • Feedback widget only surfaces an error after two consecutive poll failures and polls less aggressively, so transient outages no longer show a red flash.
Breaking Changes
  • Persisted storage from before this release is not compatible with the new key layout (5-byte header, u16 subspace). Reset or reimport existing data.
  • Public client packages renamed: @blitzstore/client-core@blitzgraph/client-core, @blitzstore/client-react@blitzgraph/client-react. Update your imports; the API surface is unchanged.
  • definition_import / definition_export now speak the nested { schema, portals } shape on the wire. The flat { kinds, apps, components } root is still accepted as DX input but is hoisted before processing. Custom consumers of the raw definitionExport payload must read from .schema.kinds and .portals.{apps,components}.
  • Removed the TS mirror consts CONCEPTS_MANIFEST and OPERATOR_DOCS from @blitzgraph/client-core. Call client.docs.list("concept"), client.docs.list("operator"), or the dedicated per-name endpoints instead. The contract is the only registry.
  • HTTP BQL routes now require the request envelope shape with body instead of accepting direct top-level BQL payloads.
  • Task payloads now return target instead of namespace, subspace_id, and scope; published TaskScope schemas and SDK exports were replaced by TaskTarget.
  • GET /tasks?namespace=... now returns 400 Bad Request when the namespace cannot be resolved instead of an empty success response.
  • Namespace admin updates now expect defaultSubspace as a subspace RID like ss:2, not a raw name or bare numeric value.
  • Public namespace and subspace resolution rejects the reserved system ID 0 instead of treating it like a normal selector.
  • HTTP auth is now Authorization: Bearer <token> for both scoped grant tokens (bzt_*) and internal keys (bzi_*). The blitz-internal-key header and its rate-limit bypass were removed.

Beta 0.25.1

April 16, 2026

Google sign-in, MCP transport, and agent tooling (rolled into 0.26.0)

Early cut of Google OAuth and the MCP transport that shipped on main while the @blitzgraph rename and safe-ops work were stabilizing in parallel. Consolidated into 0.26.0; this entry is kept for historical reference.

Features
  • Google OAuth sign-in alongside GitHub and magic link.
  • Public MCP server at /mcp. Claude Code and Codex can connect as remote MCP hosts.
  • 10 MCP tools: schema and portal export/import/query/mutate, plus BQL data query and mutate.
  • Live schema resource (blitzgraph://schema/current) for agent context.
  • Standard OAuth discovery metadata at /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource.
Improvements
  • Agent device verification page redesigned with branded UI.
  • Billing upgrade flow simplified to a "book a call" modal.
  • Space overview replaces connection bundle reveal with retry provisioning.
Fixes
  • Social sign-in buttons stay disabled during OAuth redirect to prevent double-click.
  • MCP OAuth metadata now consistently includes the mcp scope across all discovery endpoints.

Beta 0.25.0

April 11, 2026

Tunnel mutations, root aggregates, and stricter API contracts

New graph write capabilities, root-level aggregate queries, and clearer transport rules across admin and import APIs.

Features
  • Root aggregate BQL queries no longer require $groupBy for a single summary row.
  • Tunnel query and projected update support for linkField target:"role".
  • Relation-tree create support for tunnel writes through role-target links.
Improvements
  • Blob upload contracts are now typed around presign and finalize flows.
  • Blob finalization is stricter about subspace, principal, and finalize race handling.
Fixes
  • Target-scope validation fails more safely on tampered or invalid access payloads.
  • JS HTTP redirect handling is stricter against unsafe redirect chains.
  • Tunnel selector narrowing is more robust for $id filtering and deduplicated endpoint frontiers.
Breaking Changes
  • POST /admin expects the raw admin payload directly, not a { body, opts } envelope.
  • POST /data/import supports SSE progress with Accept: text/event-stream and one-shot JSON otherwise.
  • Endpoint-shaped tunnel writes on linkField target:"role" now reject; use projected updates or explicit relation-tree create.

Beta 0.24.0

April 9, 2026

Magic link sign-in, UI polish, and feedback fixes

Email sign-in, cleaner product chrome, and a more stable feedback flow.

Features
  • Email magic-link sign-in.
Improvements
  • Updated navbar and feedback widget styling.
Fixes
  • Feedback conversations behave more reliably during longer sessions.
  • Magic-link sign-in states and messages are less error-prone.

Beta 0.23.0

April 7, 2026

Docs, legal pages, and cleaner control-backed flows

Public docs, legal pages, and cleaner product flows across the marketing site and app.

Features
  • Full public docs page.
  • Terms, Privacy, Acceptable Use, and Report Abuse pages.
Improvements
  • Landing page refresh with updated branding, header, and comparisons.
  • Dashboard, spaces, and settings moved onto cleaner control-backed flows.
Fixes
  • Custom-ID and not-found errors fail more clearly across the app and client flows.

Beta 0.22.0

April 5, 2026

Storage reset and stricter server URL config

This release was mainly about a storage reset and stricter runtime config validation.

Breaking Changes
  • Storage revisions were reset, so existing stored data needed a reset or reimport.
  • Server URL config became stricter around valid baseUrl and publicUrl values.

Beta 0.21.2

April 4, 2026

More automatic Studio and Playground connections

Studio and Playground became easier to connect to and more reliable in scoped setups.

Improvements
  • Studio and Playground connection flow became more automatic and scope-aware.
Fixes
  • Studio reconnect flow was cleaned up.
  • Ambiguous space resolution in Studio bootstrap was fixed.
  • Playground autoconnect became more reliable.

Beta 0.21.0

April 1, 2026

Same-origin Studio bootstrap and better navigation

Studio setup got simpler, the landing gained a new background, and several navigation issues were fixed.

Features
  • Same-origin Studio session bootstrap from a Space.
  • New constellation landing background.
Improvements
  • Studio can resolve connections from scope with less manual setup.
Fixes
  • Space to Studio navigation now lands on the correct server.
  • Docs and changelog footer links now point to the correct localized or external destinations.

Beta 0.20.0

March 31, 2026

Real control-plane flows and managed space provisioning

The app moved from placeholders to real provisioning, real tokens, and real billing reads.

Features
  • Real control-plane integration in the web app.
  • Real space tokens and billing reads.
  • End-to-end space provisioning with a one-time builder token reveal after creation.
Improvements
  • Space creation now returns a real connection bundle instead of mock placeholders.
Fixes
  • Unauthenticated users are redirected home instead of hitting a dead end.
  • Space creation and post-create redirect flow were made more reliable.

Beta 0.19.0

March 24, 2026

GitHub sign-in, onboarding, and custom public IDs

This release added the first full auth and onboarding flows plus better support for custom public IDs.

Features
  • GitHub OAuth sign-in and protected routes.
  • Sign-in onboarding modal flow.
  • Webapp onboarding routes.
  • URL value type support.
  • Arc responses and link operations can use custom public IDs.
Improvements
  • Studio and onboarding flows were cleaned up.
Fixes
  • Custom ID resolution works more reliably across linked records and batch writes.