CX · Reference guideThe rings and the platform group
PlaygroundDownloadsAboutv0.18.0-pre.1

The rings and the platform group

How much CX do you have to take on?

Most systems make you take all of themselves. You want a config format and you get a runtime; you want to parse a file and you link a server. CX is built on two rings, with the platform, bindings and ecosystem groups layered above them, and each answers one question: how much of CX do you have to take on to get the thing you want?

DATA RING 0 · CANNOT EXECUTE codec: xml RING 1 · CODE THE PLATFORM GROUP array authz bus bytes crypto csv cx decision diagram did email env format fp ft geo graphql hash heap html http-client i18n image io json jsonrpc jsonschema locale log map math mime oidc path pdf process prof random re saml sasl sched scim set similar soap strings supervise tar term test time url uuid validate vc ws xsp zip cx-platform-net ftp http net sftp cx-platform-mail imap smtp cx-platform-identity authz-store did-web session vc-revocation cx-platform-store audit distributed_store erasure_compliance journal live store cx-platform-db db redis sql cx-platform-fabric fabric cx-platform-xsp xsp-auth cx-platform-xap xap xap-compose xap-on xap-schema xap_dist cx-platform-flow flow cx-platform-connector connector sync cx-platform-secrets secrets cx-platform-sso sso cx-platform-ux ux ux-tui ux-web cx-platform-agent a2a a2a-xap adjudicate llm mcp mcp-server run tools BINDINGS cx-binding-python cx-binding-go cx-binding-rust cx-binding-v ECOSYSTEM cx-registry cx-decisions cx-tooling IMPORTS POINT INWARD NEVER OUTWARD 92 MODULES · 25 REPOSITORIES 82 DIRECTIVES · MACHINE-CHECKED IMPORTS DRAWN FROM registry/modules.cxd AND registry/repos.cxd WHEN THIS PAGE WAS BUILT
Fig. 1 — two rings, the groups above them, one-directional imports · drawn from registry/modules.cxd and registry/repos.cxd when this page was built

Read it from the centre out. Ring 0, the data format, is the disc: it parses, converts, hashes and validates, and it cannot execute — there is no evaluator in it to switch off. Ring 1 is the ring of named ticks around it: every bundled module a program can call without leaving the two rings. The platform group is the outer annulus, one sector per repository, holding everything that serves, stores or speaks a protocol; the bindings and the ecosystem sit at the rim. Every tick is a row of registry/modules.cxd and every sector a row of registry/repos.cxd, drawn when this page was built.

Ring / group What it is What it cannot do
0 — Data the format: values, identity, schema, conversions execute anything — there is no evaluator in Ring 0
1 — Code execution: programs, queries, capabilities open a socket, start a server, or reach a database
The platform group the store, history, the wire, services be embedded — you reach it over a network
The bindings and ecosystem groups distribution, registries, the marketplace, bindings (nothing structural — they are declared acyclic graphs over the rings, not a further ring)

The order matters in one direction only. A ring, or a group above the rings, may use the rings below it and whatever its own manifest declares, never the reverse. Ring 0 uses nothing of CX at all. That single rule is why the rings stay small: no amount of growth in the platform group can reach down and make the data format heavier.

The boundary people get wrong. The XAP host — the thing that runs a feature — is in the platform group. The XAP marketplace — the thing you discover and install a feature from — is in the bindings and ecosystem groups. Running is platform; distributing is ecosystem.

Ring 0 — data

Ring 0 is CX as a data format. It parses the full grammar, gives every value an identity, validates against a schema, and converts to and from JSON, XML, YAML, TOML, and Markdown. It has no evaluator, and its only dependency is the host language's standard library.

That last sentence is the product. A Ring-0 consumer can embed CX in a place where running someone else's code is not acceptable — parsing untrusted input, a build step, a sandboxed client — and the guarantee is structural rather than a promise to be careful. There is nothing to disable.

      [order id=1001 status=:paid
        [line sku='CX-100' qty=2 unit=19.99]
        [line sku='CX-220' qty=1 unit=4.50]]
    

A program is data too. CX is homoiconic, so a Ring-0 consumer reads [?for …] as an inert element tree the way an XML parser reads XSLT — it can hash it, diff it, convert it, and hand it on, without any means of running it. Identity therefore belongs to Ring 0: a definition hashes to the same bytes everywhere, whether or not the reader could execute it.

What you can do with only Ring 0: parse and emit; convert between formats losslessly; canonicalize; hash, compare, and diff; validate against a schema; embed in another language through the bindings. See data, identity, surfaces.

Ring 1 — code

Ring 1 adds execution and nothing else. The evaluator, CXPath, the directive set, quasiquotation, purity checking, capability enforcement, fmt/lint, the language server. It adds no servers, no protocol stacks, no databases — a Ring-1 deployment still cannot open a socket.

Effects are deny-by-default. A Ring-1 program that wants to read a file, dial a host, or read the clock has to be granted that capability on the command line, and a denial names the exact flag that would allow it. So \"adds execution\" does not mean \"adds reach\": the reach is a separate, explicit decision at every run. See capabilities.

      $ cx report.cx                  # pure: computes, touches nothing
         $ cx --allow-read report.cx     # now it may read files
         $ cx --allow-common report.cx   # the common working set
    

What you can do with only Ring 1: evaluate programs; query with CXPath; transform and generate; run the formatter, linter, and language server; call the stdlib packs whose own imports stay inside Rings 0–1. See code, tour-programs.

The platform group

The platform group is not a third ring — it is a declared acyclic graph of modules over the two rings: the store and its journal, the XSP session layer and its profiles, the HTTP surface, the XAP host, the fabric, database drivers, session/authz/identity services. This is where data outlives a process and where more than one party is involved.

The platform group is reached over a network, not embedded. That is the boundary that keeps Rings 0 and 1 small and auditable: the store engine itself imports Ring 0 only and stays evaluator-free, so running a platform does not drag a server into every program that merely reads data.

What you can do with only the platform group: persist and query; keep history you can audit and replay; serve HTTP and XSP; host XAP features; operate the whole thing. See store, operations.

The bindings and ecosystem groups

The bindings and ecosystem groups are everything around CX: the registry, the marketplace, feature distribution, native clients, and the packaging of the language bindings — groups on the C ABI and the released binary, not a further ring. They are the least settled part of the tree, and this guide says which parts are shipped and which are named.

What you can do with only the bindings and ecosystem groups: seal, publish, and install features; consume packages; reach CX from the four shipping host-language bindings. See xap-distribution, bindings.

The import contract

The rings are not a convention — they are enforced. Ring 0 and Ring 1 are frozen, one rule each; everything above them is a declared, acyclic GROUP rather than a further ring:

      Ring 0  MUST import nothing internal.
         Ring 1  MAY import Ring 0.
         Everything else imports the rings and what its manifest declares,
         acyclic.
    

A component may depend on rings below its own without stacking through the ones between — the shape is a directed graph, not a staircase. What no component may ever do is reach upward.

This is the promise that makes the earlier sentences true. \"Ring 0 cannot execute anything\" is not a statement about intent; it is a consequence of Ring 0 importing no evaluator, checked by the build. \"Ring 1 cannot open a socket\" is the same kind of fact.

The gate that holds it: a module's ring and group are declared once, in its registry/modules.cxd row, and make placement-gate refuses a tree where the module's spec, corpus, source or V code sits anywhere the row does not say, or where an artifact under a ring directory has no row at all; make ring-import-gate and make product-import-gate refuse an import that points outward or a product import the repository's pins= row does not declare. Both are steps of every pre-merge run, so the figure above and the sentence before it are the same fact, checked twice.

Where to go from here

Take the smallest ring, or group, that answers your question. You can always move outward later — nothing you wrote against a lower ring has to change, because the lower ring is unchanged by the higher one. choosing is the router: a table of goals and four reader paths (evaluator, data-format adopter, application author, platform operator), each ending in something you can do. If you just want to try CX first, start at quickstart — it runs entirely inside Ring 0 before it shows you anything that executes.