CX · Reference guideIntroduction
PlaygroundDownloadsAboutv0.18.0-pre.1

Introduction

Hello, CX

CX starts from a single axiom: computing is data transformation, nothing more. Languages, frameworks and processes are ceremony around that fact. CX is the principle made a language: transform.

Reach for CX whenever the data is the point. One bracketed syntax is the document, the query, the program and the compiler's own tree, so the file you read is the file you transform, validate, hash, store and serve — with no second language in between.

We hold ourselves to a standard we can state in one line — readable on day one, batteries included, exact by default, and effects you grant rather than inherit — and we prove each term of it with a conformance case this page replayed when it was built:

a query is a pattern over the document, not code over an object model

input.cx

          [users
  [user [name Alice] [email a@x.com]]
  [user [name Bob] [email b@x.com]]]
        

prog.cx

          [?for [user [name $n] [email $e]]
       [yield [pair name=$n email=$e]]]
        
          $ cx --data=input.cx prog.cx
[pair name=Alice email='a@x.com']
[pair name=Bob email='b@x.com']
        

Fixture program-for-003-name-email-pair in deps/cx-core-code/conformance/code.cxd — replayed against this cx when the page was built.

a fraction literal is an exact decimal, and mixing one with a binary float is refused out loud rather than rounded in silence

prog.cx

          [?let [= $subtotal 19.99] [= $shipping 5.01] [total [+ $subtotal $shipping]]]
        
          $ cx prog.cx
[total 25.00]
        

Fixture ap-decimal-float-mix-right in conformance/llm/antipatterns.cxd — replayed against this cx when the page was built.

an error is a value that propagates out of whatever is built from it — no exception unwinds past you

prog.cx

          [?let [= $e [err code='c' message='m']] [report $e]]
        
          $ cx prog.cx
[err code=c message=m]
        

Fixture program-construction-err-004-captured-err-propagates in deps/cx-core-code/conformance/code.cxd — replayed against this cx when the page was built.

a program reads nothing it was not granted, and the denial is a value naming the flag that would allow it

prog.cx

          [?lib 'cx-stdlib/io']
[$io:read-file "/var/log/app.log"]
        
          $ cx prog.cx
[err code=cx-err:CXER0271 message='E_CAP_DENIED: read capability required for io-read-file; none granted (grant via --allow-read)' at='2:1']
        

Fixture io-001-read-file-cap-denied in deps/cx-core-code/conformance/stdlib/io.cxd — replayed against this cx when the page was built.

a regular expression cannot backtrack, so no input can make it run for as long as it likes

prog.cx

          [?lib 'cx-stdlib/re']
[$re:compile "(.)\\1"]
        
          $ cx prog.cx
[err code=cx-err:CXER3200 message='E_RE_FEATURE_UNSUPPORTED: CXER3200:E_RE_FEATURE_UNSUPPORTED: (.)\1' at='2:1']
        

Fixture re-003-compile-backreference-unsupported in deps/cx-core-code/conformance/stdlib/re.cxd — replayed against this cx when the page was built.

state that outlives the program is two calls to a content-addressed store

prog.cx

          [?lib 'cx-platform/store']
[?let [= $s [$store:open "mem://"]] [= $h [$store:put-doc $s [doc [item "hello"]]]] [$store:get-doc $s $h]]
        
          $ cx prog.cx
[doc [item hello]]
        

Fixture store-rt-001-round-trip-get in deps/cx-platform-store/conformance/platform/store.cxd — replayed against this cx when the page was built.

an agent-protocol message is an ordinary value projected to its wire form

prog.cx

          [?lib 'cx-platform/mcp' as=mcp]
[?lib 'cx-stdlib/json' as=json]
[$json:emit [$mcp:call-tool-request 1 "get_weather" {location: "NYC"}]]
        
          $ cx prog.cx
'{"id":1,"jsonrpc":"2.0","method":"tools/call","params":{"arguments":{"location":"NYC"},"name":"get_weather"}}'
        

Fixture mcp-001-call-tool-request-shape in deps/cx-platform-agent/conformance/x/mcp.cxd — replayed against this cx when the page was built.

The smallest document is one element. It is also its own canonical form: the data reading projects it back to CX and answers the same bytes it read.

input.cx

        [input type=text name=q]
      
        $ cx --from=cx --to=cx input.cx
[input type=text name=q]
      

Fixture 004-element-attrs-only in conformance/../deps/cx-core-data/conformance/core.cxd — replayed against this cx when the page was built.

That is a complete CX document. It is also a complete CX program when passed to the evaluator — it evaluates to itself. CX is homoiconic: programs are data; data round-trips through every supported surface (JSON, YAML, TOML, XML, Markdown); identity is the SHA-256 of the canonical bytes.

One document, one query, one answer — the three things every later section of this guide builds on. The document is data; the query is a pattern over its shape ([?for] over every user whose active is true, binding its email); the answer is what the pattern yields:

input.cx

        [users
  [user active=true [name Alice] [email a@x.com]]
  [user active=false [name Bob] [email b@x.com]]
  [user active=true [name Carol] [email c@x.com]]]
      

prog.cx

        [?for [user @active=true [email $e]] [yield $e]]
      
        $ cx --data=input.cx prog.cx
'a@x.com'
'c@x.com'
      

Fixture program-for-002-active-emails in deps/cx-core-code/conformance/code.cxd — replayed against this cx when the page was built.

Three forms, one language. No string concatenation; no AST mismatch between selectors and templates; no separate type system for queries. The full vocabulary is detailed in data and code; this section is just the elevator pitch.

Design philosophy

CX is built on six commitments. Every design choice in the rest of this guide — and every choice deliberately deferred — falls out of one of them.

1. Data and code share one syntax. A directive like [?for] is spelled the same way as a data element like [user]. There is no "template language" embedded inside a "data language". A program is a document; a document is potentially a program. Tooling — parser, lexer, AST, tree-sitter grammar, LSP — is shared end-to-end.

2. Projections round-trip. CX has a canonical surface (the bracket form) and projections for JSON, YAML, TOML, XML, and Markdown. JSON, YAML, TOML, and XML are lossless in the round-trip sense under the --lossless flag: CX → JSON → CX produces byte-identical canonical bytes. The default JSON projection is idiomatic and lossy for mixed content; Markdown (and CSV) are lossy by design. The normative round-trip rules live in surfaces and in spec/03-approved/core/canonical.md.

3. Pure-functional updates. There is no in-place mutation in CX. The [?modify] directive (see modify) takes a document and a CXPath focus, and returns a new document. Unchanged branches share structure with the original (the standard persistent-tree technique). Concurrency is safe by construction — no reader ever observes a half-modified tree.

input.cx

        [users [user name=Alice]]
      

prog.cx

        [?let [= $orig $doc] [= $new [?modify $doc //user/@name [set "Bob"]]] [pair orig=$orig/user@name new=$new/user@name]]
      
        $ cx --data=input.cx prog.cx
[pair orig=Alice new=Bob]
      

Fixture program-modify-003-original-unchanged in deps/cx-core-code/conformance/code.cxd — replayed against this cx when the page was built.

4. Identity via canonical bytes plus SHA-256. Two CX documents are equal iff their canonical bytes are equal, and the document's identifier is the SHA-256 of those bytes. This makes caching, deduplication, content-addressable storage, and cross-language equality checks trivially correct. See identity. The same value written two ways is one identity:

prog.cx

        [$eq [$cx:hash [$cx:parse "[a   1]"]] [$cx:hash [a 1]]]
      
        $ cx prog.cx
true
      

Fixture cx-025-hash-value-and-source-agree in deps/cx-core-code/conformance/stdlib/cx.cxd — replayed against this cx when the page was built.

5. One selector vocabulary everywhere. CXPath is the way to point at things — for reading (select_all), for iteration ([?for]), for type-tests in [?match], and for update focus in [?modify]. It aligns with XPath 3.1 (see the CXPath sections of spec/03-approved/core/code.md and the conformance corpus conformance/xpath_31_parity.cxd) so that developers coming from the XML ecosystem feel at home, with deliberate divergences to keep it safe and CX-shaped.

6. Orthogonality — one rule, no exceptions. CX has exactly one syntactic form: [head …]. Calls, operators, directives, and data elements are all that one shape, distinguished only by the head. There is no statement/expression divide, no infix, no special slots, and no keyword the grammar treats as a privileged exception. Even the constructs other languages hard-code — if, lambda, quote, for — are in CX ordinary forms obeying the same rule. Read it like XML, program it like Lisp; CX is more uniform than either, because in CX the surface is the rule. And the discipline extends from syntax to features: every feature must apply uniformly across its natural domain or carry a written, justified exception — enforced by the UNIFORM review gate in spec/03-approved/process/spec-authoring-guide.md §3, not merely aspired to.

Orthogonality in context. Orthogonality is the uniform application of a small rule set — features compose without special cases. It is not the same as simplicity: a language can be small yet riddled with privileged built-ins user code cannot reproduce, or large yet principled. The table below states CX's case on this one axis against a dozen languages readers arrive from; comparison states it against each data format.

language tier why
CX Reference One grammar production; every construct is the same [head …] form. No statement/expression split, no infix, no privileged keyword — even special forms obey the one rule.
Lisp-1 (Scheme) Near-reference Homoiconic S-expressions; single namespace (more uniform than Lisp-2). Loses only because quote, lambda and if are privileged special forms — CX folds even those into the one rule.
Scala High (uniform model) Everything is an expression; functions are objects; operators are methods; uniform access. Diluted by a large sugary surface — implicits/givens, two dialects.
Ruby High (uniform model) Smalltalk lineage — everything is an object, everything a message send, operators are methods. Uniform core, non-uniform surface (blocks vs procs vs lambdas, many sugars).
V Moderate Deliberately minimal, one canonical way to do things. Orthogonality by austerity; still carries privileged built-ins and a partial statement/expression split.
Kotlin Moderate Expression-oriented (if, when, try are expressions); operators by convention. Primitives-as-objects is a JVM fiction; much surface exists for Java interop.
Swift Moderate Genuine protocol-oriented uniformity, but a special-case-dense surface — optionals, guard, defer, property wrappers, result builders.
Rust Low–moderate Expression-oriented core, but a federation of subsystems with their own rules — ownership, lifetimes, traits plus coherence, a separate macro grammar, async, unsafe. Powerful is not orthogonal.
C# Low Multi-paradigm, accreted over many versions — LINQ, async, properties, events, pattern matching each a distinct syntax. Statement/expression divide.
Java Low The classic wart — primitives vs objects — plus special-cased arrays, no operator overloading, erasure generics, statement-heavy ceremony.
Go Low Simple but not orthogonal — magic built-ins user code cannot replicate (make, append, len, cap, delete), special slice/map/channel semantics, retrofitted generics, error-by-convention.
TypeScript / JavaScript Lowest Most accreted — this-rebinding, hoisting, prototype vs class, == vs ===; TypeScript layers an entire erased second language over the runtime.

Two distinctions drive the ranking. Simplicity vs orthogonality: Go and V are simple, but Go is not orthogonal — its magic built-ins are unreproducible by user code. Uniform model vs uniform surface: Scala and Ruby have uniform semantic cores but large sugary surfaces; CX is the only entry whose surface itself is the single rule, because it is homoiconic (see homoiconicity) — there is no gap between model and syntax for uniformity to fall out of.

How to read this guide

This guide is the developer-facing reference for CX. Read it linearly the first time. After that, sections are independent enough to use as topic-specific reference.

The flow is data → surfaces → identity → analytics → code → bindings → tooling → concepts → migration. Each section calls out the normative spec documents — approved specs live under spec/03-approved/ — rather than restating them; if you need the formal grammar, error matrix, or wire-format details, the guide points you there. Front-matter (quickstart) and back-matter (glossary / faq / comparison) flank the numbered sequence.

  • data — the data language: lexical structure, scalars, collections, sigils, prose, typed columnar tables, schema language, includes. Start here if you've never seen CX.
  • surfaces — the canonical CX form and its JSON / YAML / TOML / XML / Markdown projections, plus the round-trip contract.
  • identity — canonical bytes, SHA-256 hashing, the ast-bin and data-bin binary wire formats, ID/IDREF scoping, capability bits, FFI lifetime.
  • analytics — the columnar / streaming binary surface: :table data shape, CXCol format, Arrow zero-copy bridge, Parquet read/write, ecosystem integrations (DuckDB / Polars / pandas / DataFusion / Spark).
  • code — the CX code language: the directive registry, CXPath, patterns, bindings, the six core constructs, builtins, errors-as-values, services / workers / async, resilience.
  • bindings — the C ABI, Layer 1 canonical method set, Layer 2 host idiom packs, and a quickstart per binding.
  • tooling — LSP, tree-sitter, VS Code, Neovim, Helix, make guide, the playground.
  • value-model, computation-identity, commands-effects, runtime-representation — the concept arcs: identity, determinism, effects, structural sharing, and how values are represented at runtime.
  • migration — upgrade guide: renames, retired surfaces, the cx fmt --migrate-predicates / --collapse-lets rewriters, the archived binding set.

Conventions used throughout. Code blocks tagged cx are literal CX (data or code; the same shape). Code blocks tagged with a host language are binding code, and appear only in bindings. Cross-references to other sections use [[anchor]]. References to spec documents use ordinary markdown links.

The normative grammar lives in spec/03-approved/formal/grammar.ebnf; the directive registry is in spec/03-approved/core/code.md; the C ABI surface is in spec/03-approved/core/abi.md. This guide is curated learning + reference path, not a replacement for those documents.