Releases: cx-home/cx
Release list
CX v0.15.0
CX v0.15.0 — Release Notes
Date: 2026-08-03
Tag: v0.15.0
The toolchain release. The vendored V compiler moves from its 0.5.1-era
base to upstream V 0.5.2, carrying the cx fork's memory-management
patch series forward — plus two sharp fixes that the upgrade's own
validation battery surfaced. Deliberately thin and shipped fast: a
compiler upgrade is a foundation change worth isolating from feature work.
No breaking changes. cx source needed zero changes for the new
compiler.
Headlines
- V 0.5.2 under the hood — the fork's 79-patch series rebased onto the
upstream tag as 76 commits. In-window upstream wins: cgen
sumtype/generic correctness fixes (the CX element tree is
sumtype-heavy),-usecacherepairs, mbedtls TLS-handshake hardening,
and array micro-optimizations. - A collector-soundness find upstream can't see: two innocuous-looking
upstream array changes — zeroing vacated delete slots, and letting
empty arrays carry no buffer — each independently caused
sweep-while-live use-after-frees under cx's conservative collector at
high thread counts. Invisible under Boehm (upstream's only GC), caught
by cx's masking-proof concurrency-soundness gate, and fixed as a
fork-side conservative-retention contract that keeps all of
upstream's performance work. The gate ladder (5 thread configurations
on macOS, plus Linux-container parity) runs at zero catches and zero
crashes. - Ingest regression found and erased — v0.14.0's demand-paged store
load had quietly routed first-touch object reads through a
scan-the-world cold path, collapsing embedded journal-bound ingest
2881 → 91 events/s. An object-location index plus an MRU pack reader
restore 2861 events/s — parity — with the lazy-load memory wins
intact. - Authenticated event streams from CX —
[$http:sse-connect]now
sendsopts.headers, so a proof-bound SSE subscription (the identity
model's required three-header handshake) finally works from a
CX-native client.
Toolchain notes
- The 0.5.2 builder's new C-error telemetry (auto-reports to the upstream
tracker) is opt-in in the cx fork (V_C_ERROR_BUG_REPORT=1) — a
fork must not phone home. - The vc bootstrap pin is regenerated for the new base and verified by a
fresh-clonemake; the concurrency-soundness gates are parameterized
(VFORK_ROOT/VFORK_SRC/VFORK_V) so a candidate compiler tree is
arbitrated before the submodule pin moves. - Upstream's closure-lifetime reclamation is enabled — it was the
upgrade's top predicted risk and was exonerated by the gate once the
real regressions were isolated.
Install
Download the release artifact for your platform and extract, or build
from source with make build. The hosted one-liner remains blocked on
GitHub Pages certificate issuance (#508).
Migration
None. v0.15.0 is additive over v0.14.0; the compiler upgrade is invisible
at the CX surface.
What's next
The CX partition (#516) — targeted, per-use-case consumables along
capability rings — is now slated as v0.16.0's headline, design-gated
behind its spec and the architecture review (#37).
CX v0.14.0
CX v0.14.0 — Release Notes
Date: 2026-08-02
Tag: v0.14.0
The eventing + endurance release. v0.13.0 made CX consumable; v0.14.0
makes a CX deployment survive its own success.
Two arcs dominate. cx fabric graduates from a design note to a served
platform tier: durable and transient event planes over XSP, with consumer
groups, failover, dead-letter policy, request–reply, backpressure, and a
NATS bridge — where a durable stream is a journal stream, so ordering and
verification come from the journal contract rather than a second
implementation. And the journal and store grow a lifecycle: rotation,
tiered retention with cold archive and chain anchors, and demand-paged
loading — so a long-lived deployment's cost tracks its working set
instead of its lifetime volume.
Between them sits a sustained performance campaign that moved remote
journal-bound ingest from ~16 events/s to ~660, and a fail-loud sweep
that closed a family of silent-wrong-answer defects in the evaluator.
No breaking changes.
Headlines
- cx fabric, served —
cx fabric-servewith durable + transient
planes, consumer groups with sticky-exclusive assignment and liveness
failover, DLQ + redelivery policy, request–reply, XSP §5 heartbeat /
credit flow control / reconnect-resume, and a NATS subject bridge. - The journal has a lifecycle —
[rotate keep-n=N]seals every stream
at its own boundary and moves the hot window to a fresh store; a
segment index keeps sealed history walkable from the newest store
alone.[retention …]policy sweeps it automatically with per-stream
hot windows, cold archive, chain anchors retained whether a segment is
archived or dropped, and a legal hold that suspends both. - The store pages on demand — opening an object-graph store populates
only the refs layer; objects resolve on first touch through a
self-verifying getter, so corruption still refuses loudly at first
touch while resident memory tracks the working set. The whole-graph
check becomes the explicit[$store:verify]. - ~40× remote ingest — ~16 → ~660 events/s through pipelined appends,
render caching, fold checkpoints, and finally moving the delivery pump's
read+render off the sequencer lock (663/s measured at K=2000). - Per-principal read surfaces —
readout($store, $t, $actor)receives
the request's resolved principal, so a confidentiality boundary folds
server-side instead of shipping a full read-model to every client. - Self-hosting all the way down — a fabric mount can ride a served
cx-store://store, with alias remoting (explicit presence, optional
CAS) closing the last gap.
Language & stdlib
[?loop]with[break]/[continue], and[?do]— the
condition-driven loop and evaluate-for-effect sequencing, with
all-explicit exits: a branch that forgets its exit word is a diagnostic,
never a silent wrong answer.%as modulo, joining+ - * /.- Per-thread PRNG streams and instantiable generators (
[$random:new])
—[?worker]threads no longer race a process-global RNG. CX-L007flags aggregation over a simple field accessor, catching
the count-composition trap mechanically.
Fail-loud hardening
A deliberate sweep against silent wrong answers, each closed at the root:
$firstreturned the whole collection for$filterresults; err values
vanished in unobserved[?let]bindings; absence in call position
misdiagnosed asno callable;[?for] [where]calls never matched;
[?element]as a call argument arrived as absence;[?async]never ran
without[?await]despite the spec requiring eager spawn.$cx:emitemitted unescaped quotes that broke re-parse; CXPath over an
[err …]yielded zero matches, turning parse failures into empty
results; a parsed MapNode was unnavigable.- Module-imported code now evaluates identically to program-context
code — derived evaluation frames dropped their lexical position, so
closures created inside imported defs resolved against the importing
scope. One root cause behind three distinct reported symptoms.
Durability
- Crash consistency: the journal store corrupted on unclean shutdown
and then SIGBUS'd on reopen. Two-pass replay with a structural
torn-tail discard; 0/40 corrupt across a kill-at-any-point harness. - Two writable in-process opens of one store root shared segment
numbering; they now share the live handle or refuse loudly.
Toolchain & packaging
- The public mirror builds from a clean clone again (V bootstrap and fork
makefiles no longer float on remote HEADs). - The darwin artifact is self-contained — RE2 vendored and statically
linked, dropping the Homebrew/abseil dylib chain. - WSL2 source builds work via the recursive-clone path.
- Bindings: the retired
:table[opener purged from Go/Rust/Python; Rust
arrow/parquetfeatures compile; previously-unwired Python tests now
run in the gate.
Install
Download the release artifact for your platform and extract, or build from
source with make build. The hosted https://cxhome.org/install one-liner
remains blocked on GitHub Pages certificate issuance (#508) and is not
advertised for this release.
Migration
None required — v0.14.0 is additive over v0.13.0. Two optional surfaces are
worth adopting deliberately:
- Retention is opt-in. Without a
[retention …]block a fabric mount
keeps its full history exactly as before. Sizing guidance for thehot=
window is inbench/xap/SIZING.md§1. - Store loading is now demand-paged by default. Per-object integrity is
unchanged (every paged read self-verifies), but the exhaustive
whole-graph reconstruction that used to run at every open is now the
explicit[$store:verify]. Pass[opts eager="true"]to restore the
inline check.
What's next
The CX partition (#516) — breaking CX into targeted, per-use-case
consumables along capability rings — is the next release's headline,
deliberately design-gated behind its spec and the architecture review.
CX v0.13.0
CX v0.13.0 — Release Notes
Date: 2026-07-16
Tag: v0.13.0
The platform + consumption release. The cx store becomes a production
platform component — a content-addressed multimodel engine under a
single-node service tier with authN/authZ, observability, and deploy
artifacts — and XAP features become a full distribution unit: sealed,
signed, published, discovered, verified, installed, and entitled. Around
that core, this release makes CX radically easier to consume in all four
modes: as a data format (a lossless conversion contract that finally
keeps its promise), as code (a CLI whose help, flags, and errors cannot
drift from the implementation), as a platform (the store + XAP guides,
verified live), and in operations (a real process-model story, a hosted
installer, and a public mirror that builds from a clean clone).
Two breaking changes (store scheme cutover and strictly-scalar attributes)
— see Migration.
Headlines
- XAP feature distribution — the compose→package→publish→verify→install→
entitle staircase ([$xap:compose],pkg-*, entitlement VCs,
git-repo-as-registry), plus the deployment host: a XAP server is data
plus adapters, zero bespoke server code. - cx store, production tier —
cx store-serve(CSRP + gRPC, static/
JWT/DID/OIDC authN, RBAC, tenants, Prometheus/OTel, systemd/Docker
artifacts), encryption-at-rest with KEK rotation, two-tier identity, and
fifteen hardening waves over the serve plane. - The lossless contract, kept —
--losslessJSON and YAML now recover
element documents byte-identically via the$tagenvelope: structure,
attributes, mixed-content order, metadata, and[table]payloads all
survive. XML kept its exact lane; every lane now carries table images
(cx:cols/cx:row, AST-JSONcols/rows, Markdown pipe tables,
ast-bin v9 records). - A CLI that tells the truth — one registry drives dispatch and help
(20+ verbs, uniform--help); unknown flags are hard errors instead of
silent no-ops;cx selectships;cx FILE --data=INPUTbinds$doc;
cx demodemonstrates a working product. - Consumable out of the box —
curl -sSL https://cxhome.org/install | sh
(SHA-256-verified), editors that work on first open (Neovim fallback +
tree-sitter repaired, VS Code extension actually activates), a 20-section
guide whose every example executes against the live binary under a gate,
and a public mirror that builds and tests from a fresh
git clone --recursive.
Changed (breaking)
- Store scheme cutover —
cxpack:///cxobj://retired:file://is
the universal subtree model,document+<substrate>://the document model,
?encoding=selects framing; contradictions with the on-disk marker are a
hardCXER1120. - Attributes are strictly scalar (code.md §6.4.1 wins) — a non-scalar
attr value raisesCXER0100with a child-element hint; validate.md's
vocabulary moves to child elements ([enum v …],[schema …],
[extends $Base]), old attr spellings fail loud with migration hints
(CXER1603). - CXPath predicate sublanguage retired (from the 0.13 line's early
waves; #110) — predicates are homoiconic prefix CX (//user[= $_@id 991]);
cx fmt --migrate-predicates -wmigrates fail-closed.
Fail-loud hardening
The release closes a long tail of silent-wrong-answer classes: unknown CLI
flags, empty-attr writes, unbound-$doc queries, out-of-range ascriptions
(including the 8-byte-hex i64 clamp), element-valued attributes, comment
placement moving hashes, [table[…]] heads mis-parsing under attributes or
nesting, YAML block-sequence import losing rows, and cx diff's table
blind spot. Where behavior is deliberately typed-lossy (Markdown tables,
CSV), the spec now says so and the flag surface rejects what it can't honor.
Migration
- Store URIs: replace
cxpack:///cxobj://per the table in store.md;
stores reopen self-describing. - Collection-valued attributes: move the value to a child element —
[e sel=$nodes]→[e [sel $nodes]]; validate schemas:enum=[a b]→
[enum a b],schema=[…]→ nested[schema …],extends=$B→
[extends $B]. - Predicates (if arriving from 0.12): run
cx fmt --migrate-predicates -wacross your tree. - Hex under
::decimal/::bigint: write base-10.
Toolchain & public build
The vendored V fork pins its complete bootstrap inputs (vc, tcc,
macports-legacy) — clean clones build offline-deterministically; public
make test runs under a real C compiler; the mirror's CI calls only
public targets. Release artifacts: cx-darwin-arm64.tar.gz (CLI +
libcx.dylib + cx.h) with SHA256SUMS.txt.
Full detail: CHANGELOG.md §0.13.0.
CX v0.12.0
CX v0.12.0 — Release Notes
Date: 2026-06-22
Tag: v0.12.0
The reliability release. Concurrency and memory move from "works with
caveats" to sound by construction: tail calls no longer overflow the native
stack, the precise GC's cooperative-safepoint collector becomes the default so
multi-reactor HTTP and concurrent workers are safe, and the reactor / streaming
write paths are bounded against runaway RSS. Alongside that: the block-comment
syntax is unified on [; … ] (the one breaking change — see Migration), the
single-source-of-truth versioning model is enforced end to end, the CLI learns
stdin / inline evaluation, and roughly twenty bugs are fixed — several of them
silent-wrong-answer or capability-fails-silently violations of CX's fail-loud
principle.
Changed (breaking)
- Block comments are now
[; … ]only.[- … -]and[-- … --]are retired
as comment forms, and[- a b]is always subtraction. This removes the
long-standing[--token ambiguity between a comment and a minus expression.
See Migration below. (Language version → 0.12.0.)
Reliability — concurrency & memory
- Tail-call optimization (#60). Tail self-calls and tail closure-calls now
run in O(1) native stack via a trampoline in the evaluator, so loop-shaped
recursion no longer SIGSEGVs at depth (pure tail recursion is exercised
100,000,000 deep). Semantics-preserving; non-tail and a few non-trampolined
shapes fall back to ordinary recursion. - Cooperative-safepoint STW is now the default GC collector (#63 / #58).
The precise-gc ecollector parks running mutators at cooperative safepoints
(mach-suspending only stragglers) before a stop-the-world cycle, so
multi-reactor HTTP (CX_HTTP_WORKERS>1) and concurrent[?worker]threads are
sound by construction rather than racing the collector. Revert with
-d vgc_legacy_stwif needed. Single-reactor throughput is within noise;
8-reactor is the tuning follow-up. - Reactor heap is bounded by heap growth, not request count (#57). The HTTP
reactor collects its per-request transient heap once it has grown by
CX_HTTP_GC_MBMB (default 64) since the last collect — self-tuning across
light and heavy handlers. A light handler barely allocates so it almost never
collects (full throughput + multi-reactor scaling); a heavy handler trips it
every few requests so RSS stays bounded. (The earlier every-N-requests gate,
default 64, fired a global stop-the-world ~hundreds of times/sec and cut
throughput ~3× — that regression is fixed here.CX_HTTP_GC_MB=0disables it;
the legacyCX_HTTP_GC_EVERYrequest-count gate is still honored when set.) - HTTP serves multi-reactor by default (
min(4, cores)). The server fans
out across a few cores out of the box — sound on the cooperative-safepoint
collector, and ~4 reactors is the sweet spot before the per-request GC lock
starts to contend on a many-core box. Tune withCX_HTTP_WORKERS: an integer
(honored as asked — a 64-core test gets 64; above the core count it
oversubscribes, with a one-line note, and a 256 safety ceiling guards typos),
maxfor one worker per core, or1to opt back into a single reactor.
(Measured: ~162k req/sec default, ~110k at=1, on a 12-core box with a
trivial handler.) - Streaming
data-binwrites are bounded under-gc e(#52). Large-span
recycling plus periodic collection cap the live set on the fd-streaming write
path, so emitting a large document no longer balloons memory. - Comprehension memory fix (#62).
[?for]’s per-itemenv.clone()no
longer deep-copies the shared closures table, eliminating a general
(non-HTTP) memory blow-up on large comprehensions. - Concurrent
[?worker]threads (#58), behindCX_WORKER_THREADS. A
[?worker]body runs on its own thread and coexists with a{block:true}
serve, instead of monopolizing the thread so the server never binds. Off by
default this release.
Changed
cx <file>renders every top-level form, not just the last (#16). A script
with multiple top-level expressions now prints each result in order.--allow-netno longer bypasses the §4.5 SSRF deny-set (#47). A bare
--allow-netgrants outbound reach but still refuses loopback / link-local /
private / metadata ranges unless an explicit literal-IP orlocalhostgrant
admits them; only--allow-allbypasses the deny-set. Tightens the default
security posture.
Added
cx-stdlib/stringsstring→number parsers (#54).to-number/to-int/
to-float— a locale-free bridge that returns a numeric scalar for valid
input and the absence channel()for non-numeric input (no silent
string passthrough), so callers branch with[?else …]. Replaces the unsafe
[$cx:parse …]workaround.- Concurrent SSE push on the
servepath (#28). Topic pub/sub: a handler
subscribes a connection to a topic andsse-publishfans one event out to
every subscriber. cx -andcx -e EXPR. Read a program from stdin (cx -) or evaluate an
inline expression (cx -e '…') — nocx evalneeded.tools/vgc-debug/toolkit (#70). Durable probes, gated diagnostic patches,
and methodology for the precise-GC concurrency work — for contributors
investigating collector behavior.
Versioning & release hygiene (#67)
- The repo-root
VERSIONfile is the single source of truth, enforced.
Every surface either derives the version (the CLI / C-ABI via the build
define, the guide at build time, the wasm build, runtime error messages) or is
stamped from it bybump_version.sh(package manifests, README badges, the
VS Code extension). User-facing error messages no longer cite a frozen release
(e.g. thecasterror lists supported kinds instead of "v0.8.0 supports …"). check-version-consistencynow scansvcx/,spec/,docs-src/,
stdlib/, andtooling/and fails the build on any strayvX.Y.Zliteral
outside an explicit history allowlist — so a release can no longer ship docs,
tooling, or a playground that advertise an older version.
Fixed
Silent-wrong / data-loss (highest priority — fail-loud violations):
- #38 —
[$idiv]/[$mod]/[$div]now reject bigint and decimal
operands (CXER0100) instead of silently returning an i64-wrapped wrong answer. - #10 — JSON / YAML emit of a
:tableblock now projects its rows instead
of dropping them tonull. - #21 —
[?for [in $x $m/key]]over a map member whose value is a
sequence-of-elements now iterates the members (count and iteration agree). - #16 — see Changed (was: all but the last top-level form silently dropped).
Fail-loud / capability-silent:
- #46 — a
[?def]body that raises now surfaces the error instead of
collapsing to a silent data literal. - #29 —
net:set-deadline/set-opton a std-stream handle now reject
loudly instead of silently no-op'ing. - #23 —
accept-itersurfaces a handler that returns without responding. - #56 —
net:read-all/read-line/line-iterhonor a configured
read-deadline (dial opt orset-deadline), raisingCXER4507instead of
hanging forever on a peer that never closes. - #55 — a zero-argument user
[?def]is now callable by its bareword head
([f]) instead of parsing as a data element. - #53 — a bareword-head recursive
[?def]call with computed arguments now
dispatches instead of falling through to data construction. - #11 — unknown / retired directives stay fail-loud rather than silently
falling back to a data literal (a pure-data resource still evaluates to
itself; the fallback no longer over-reaches).
Lossless import:
- #4 / #5 — YAML and TOML now import losslessly into the native map/array
value model.
Other:
- #48 — the HTTP server waits for the full POST body before invoking the
handler. - #27 —
[?select]sequence diagrams emit arrows with correct labels. - #39 —
cx:parseof a single-root document returns a navigable node. - #18 — a
[where]infix-comparison error points at the prefix form. - #17 — docs / examples / scripts use
cx <file>instead of the redundant
cx eval. - #15 — the published
cx-vpackage shipstransport/+x/and builds
withclang(-cc cc).
Migration — comment syntax
The only breaking change. Block comments must use [; … ]:
[; this is a comment ] ; the old [- … -] / [-- … --] forms are retired
[- 5 2] ; this is now subtraction (= 3), never a comment
- Replace any
[- … -]or[-- … --]comment with[; … ]. - If you used
[- … -]to comment out a block, switch it to[; … ]. - Bare
[- a b]that you intended as subtraction is unchanged and now
unambiguous.
Compatibility
Language version advances to 0.12.0. The comment-syntax unification is the
sole breaking change; every other change is backward-compatible. The
cooperative-safepoint GC default is transparent to programs (revertible with
-d vgc_legacy_stw), and the new concurrency knobs (CX_HTTP_WORKERS,
CX_WORKER_THREADS) are opt-in. The ABI, on-disk format, and bundled-library
version axes are unchanged.