Trending-skills creationix-rx-data-store
Expert skill for using RX, an embedded data store for JSON-shaped data with random-access reads, no-parse lookups, and a text-safe binary encoding format.
git clone https://github.com/Aradotso/trending-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/Aradotso/trending-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/creationix-rx-data-store" ~/.claude/skills/aradotso-trending-skills-creationix-rx-data-store && rm -rf "$T"
skills/creationix-rx-data-store/SKILL.mdRX Data Store
Skill by ara.so — Daily 2026 Skills collection.
RX is an embedded data store for JSON-shaped data. Encode once, then query the encoded document in place — no parsing, no object graph, no GC pressure. Think of it as no-SQL SQLite: unstructured data with database-style random access.
Key benefits:
- O(1) array access, O(log n) object key lookup on encoded data
- Automatic deduplication of values and shared schemas
- Text-safe encoding (copy-paste friendly, no binary tooling needed)
- Minimal heap allocations (~10 vs millions for JSON parsing)
- ~18x compression on real deployment manifests (92 MB → 5.1 MB)
Installation
npm install @creationix/rx # library npm install -g @creationix/rx # CLI (global) npx @creationix/rx data.rx # CLI (one-off)
Core API
String API (most common)
import { stringify, parse } from "@creationix/rx"; // Encode const rx = stringify({ users: ["alice", "bob"], version: 3 }); // Returns a string — store it anywhere you'd store JSON text // Decode (returns a read-only Proxy) const data = parse(rx) as any; data.users[0] // "alice" data.version // 3 Object.keys(data) // ["users", "version"] JSON.stringify(data) // works — full JS interop
Uint8Array API (performance-critical paths)
import { encode, open } from "@creationix/rx"; const buf = encode({ path: "/api/users", status: 200 }); const data = open(buf) as any; data.path // "/api/users" data.status // 200
Inspect API (lazy AST)
import { encode, inspect } from "@creationix/rx"; const buf = encode({ name: "alice", scores: [10, 20, 30] }); const root = inspect(buf); root.tag // ":" root[0].tag // "," (a string key) root[0].value // "name" root.length // 4 (key, value, key, value) // Iterate children for (const child of root) { console.log(child.tag, child.b64); } // Object helpers for (const [key, val] of root.entries()) { /* ... */ } const node = root.index("name"); // key lookup → node const elem = root.index(2); // array index → node // Filtered key search (O(log n + m) on indexed objects) for (const [key, val] of root.filteredKeys("/api/")) { /* ... */ }
Escape hatch to underlying buffer
import { handle } from "@creationix/rx"; const h = handle(data.nested); // h.data: Uint8Array // h.right: byte offset
Encoding Options
stringify(data, { // Add sorted indexes to containers with >= N entries (enables O(log n) lookup) // Use 0 for all containers, false to disable entirely indexes: 10, // External refs — shared dictionary of known values for cross-document dedup refs: { R: ["/api/users", "/api/teams"] }, // Streaming — receive chunks as they're produced onChunk: (chunk: string, offset: number) => process.stdout.write(chunk), }); encode(data, { indexes: 10, refs: { R: ["/api/users", "/api/teams"] }, onChunk: (chunk: Uint8Array, offset: number) => { /* ... */ }, });
If the encoder used external refs, pass the same dictionary to the decoder:
const data = parse(payload, { refs: { R: ["/api/users", "/api/teams"] } }); const data = open(buf, { refs: { R: ["/api/users", "/api/teams"] } });
CLI
rx data.rx # pretty-print as tree (default on TTY) rx data.rx -j # convert to JSON rx data.json -r # convert to RX cat data.rx | rx # read from stdin (auto-detect format) rx data.rx -s key 0 sub # select a sub-value: data["key"][0]["sub"] rx data.rx -o out.json # write to file rx data.rx --ast # output encoding structure as JSON rx data.rx -w # write converted file (.json↔.rx)
Full CLI flags:
| Flag | Description |
|---|---|
| Input file (format auto-detected) |
| Read from stdin explicitly |
, | Output as JSON |
, | Output as RX |
, | Output as tree |
, | Output encoding structure |
, | Select a sub-value by path segments |
, | Write converted file |
, | Write to file instead of stdout |
, / | Force or disable ANSI color |
| Index containers above n values (default: 16) |
| Split strings longer than n (default: 64) |
| Delimiter for string chains (default: ) |
| Max object complexity for dedupe keys (default: 100) |
Shell completions:
rx --completions setup zsh # or bash
Tip — paged, colorized viewing:
p() { rx "$1" -t -c | less -RFX; }
Proxy Behavior
The value returned by
parse/open is read-only:
obj.newKey = 1; // throws TypeError delete obj.key; // throws TypeError "key" in obj; // works (zero-alloc key search) obj.nested === obj.nested // true (container Proxies are memoized)
Supported operations on the Proxy:
- Property access:
,data.keydata[0]
,Object.keys()
,Object.entries()Object.values()
,for...offor...inArray.isArray()
,.map()
,.filter()
,.find().reduce()- Spread and destructuring
JSON.stringify()
Common Patterns
Build-step: convert JSON artifact to RX
import { readFileSync, writeFileSync } from "fs"; import { stringify } from "@creationix/rx"; const json = JSON.parse(readFileSync("manifest.json", "utf-8")); const rx = stringify(json, { indexes: 10 }); writeFileSync("manifest.rx", rx, "utf-8");
Runtime: sparse read from large RX file
import { readFileSync } from "fs"; import { parse } from "@creationix/rx"; const manifest = parse(readFileSync("manifest.rx", "utf-8")) as any; // Only the accessed values are decoded — everything else is skipped const route = manifest.routes["/dashboard/projects"]; console.log(route.title, route.component, route.auth);
Streaming encode to stdout
import { stringify } from "@creationix/rx"; stringify(largeData, { onChunk: (chunk, offset) => process.stdout.write(chunk), });
Using external refs for cross-document deduplication
import { stringify, parse } from "@creationix/rx"; const sharedRefs = { R: ["/api/users", "/api/teams", "/api/projects"] }; // Encode multiple documents sharing the same ref dictionary const doc1 = stringify(data1, { refs: sharedRefs }); const doc2 = stringify(data2, { refs: sharedRefs }); // Decode with the same dictionary const val1 = parse(doc1, { refs: sharedRefs }) as any; const val2 = parse(doc2, { refs: sharedRefs }) as any;
Low-level inspect traversal (zero allocation)
import { encode, inspect } from "@creationix/rx"; const buf = encode(routes); const root = inspect(buf); // Walk object entries without creating JS objects if (root.tag === ":") { for (const [key, val] of root.entries()) { if (key.value === "/dashboard") { console.log("Found:", val.index("title").value); break; } } }
Type-safe usage pattern
import { parse } from "@creationix/rx"; interface Route { title: string; component: string; auth: boolean; } interface Manifest { routes: Record<string, Route>; version: number; } // Cast after parse — RX Proxy supports all read operations const manifest = parse(rxString) as unknown as Manifest; const dashboard = manifest.routes["/dashboard"];
Format Reference
RX is a text encoding — not human-readable like JSON, but safe to copy-paste.
Every value is read right-to-left. The parser scans left past base64 digits to find a tag character:
[body][tag][b64 varint] ◄── read this way ──
| JSON | RX | Description |
|---|---|---|
| | tag (integer), b64 = 84, zigzag → 42 |
| | tag (string), length = 2 |
| | tag (ref), built-in literal |
| | tag (array), b64 = content size |
| | tag (object), interleaved keys/values |
Tags:
+ integer · * decimal · , string · ' ref/literal · : object · ; array · ^ pointer · . chain · # index
When to Use RX vs Alternatives
| Scenario | Use |
|---|---|
| Large artifact, sparse reads | RX |
| Build manifests, route tables | RX |
| Small config files | JSON |
| Human-authored config | JSON/YAML |
| Write-heavy / mutable data | Real database |
| Fixed schema, minimize wire size | Protobuf |
| Relational/tabular data | SQLite |
| Minimizing compressed transfer | gzip/zstd + JSON |
Troubleshooting
on decoded value
The Proxy returned by TypeError: Cannot set property
parse/open is read-only by design. To mutate, spread into a plain object first:
const mutable = { ...parse(rx) }; mutable.newKey = "value"; // works
Decoded value looks correct but
fails
Use instanceof Array
Array.isArray(val) instead — this is correctly intercepted by the Proxy.
External refs mismatch / wrong values decoded Ensure the exact same
refs dictionary (same keys, same arrays, same order) is passed to both stringify/encode and parse/open.
CLI not found after global install
npm install -g @creationix/rx # If still not found, check your npm global bin path: npm bin -g
Inspecting encoded bytes
rx data.rx --ast # shows encoding structure with tags and offsets
Or use the live viewer at rx.run — paste RX or JSON directly.
Performance: lookups slower than expected Ensure
indexes threshold is set appropriately when encoding. For large objects (e.g., 35k keys), use indexes: 0 to index all containers:
stringify(data, { indexes: 0 });
Resources
- rx.run — live web viewer, paste RX or JSON to inspect
- docs/rx-format.md — full format spec with grammar and railroad diagrams
- docs/cursor-api.md — low-level zero-allocation cursor API
- samples/ — example datasets (route manifest, RPG state, emoji metadata, sensor telemetry)