@clickhouse/rowbinary: when your library is also a parser compiler ClickHouse released @clickhouse/rowbinary, a Node.js library for reading and writing RowBinary formats, which also includes an Agent Skill that generates query-specific parsers 1.5–3.4x faster than generic parsing. The tool addresses performance and data-corruption issues in JavaScript by monomorphizing parsers to exact column types, costing about $0.20 per generated parser. We've released @clickhouse/rowbinary https://www.npmjs.com/package/@clickhouse/rowbinary , a Node.js reader and writer for ClickHouse's RowBinary https://clickhouse.com/docs/interfaces/formats/RowBinary , RowBinaryWithNames, and RowBinaryWithNamesAndTypes formats. You can import it and call its generic parser like any other library. But it also ships as an Agent Skill: point a coding agent at the bundled SKILL.md and, instead of calling the library, the agent reads it and writes a parser specialized to your query's exact column types. Those generated parsers run 1.5–3.4x faster than composing the library's functions in a loop, cost about $0.20 each to generate, and avoid the silent data-corruption bugs that models produce when they write binary decoders from memory. Why we built it RowBinary is one of the most efficient ways to get data out of ClickHouse, and one of the most annoying formats to consume from JavaScript. The wire format itself is simple: little-endian primitives, LEB128 https://en.wikipedia.org/wiki/LEB128 varints for variable widths, no per-row overhead. The pain is on the reader side. Every leaf type has its own read pattern. Nullable , Array , Map , Tuple , and LowCardinality nest arbitrarily. DateTime64 needs precision-aware scaling and an optional timezone. The Variant , Dynamic , and JSON types are self-describing and recursive: each value carries its own type tag and dispatches back into the same parsing machinery. So most applications fall back to JSON formats, which cost real CPU time and, worse, silently round UInt64 values past Number.MAX SAFE INTEGER to float64 unless you take the slow stringify-then-reparse path. Teams that do adopt RowBinary end up with a generic, type-dispatched parser: one function per type, dispatched per cell at runtime. It's easy to maintain and hard to make fast, because every cell pays a dispatch and V8's inliner gives up on the megamorphic https://people.dsv.su.se/~beatrice/python/dls15 large images.pdf call sites. What you actually want at high QPS is a parser monomorphized https://en.wikipedia.org/wiki/Monomorphization to your query: the right read operations inlined in the right order for your exact columns, with no dispatch at all. Nobody writes these by hand, per query, for every query they ship. That's the gap this package closes. The library gives you correct, tested reading primitives for the whole ClickHouse type system. The skill teaches a coding agent to assemble those primitives into the hand-tuned, query-specific parser you'd never write yourself. What it is and how to use it The package has two layers. The first is a library of type-specific reading primitives: one small function per leaf type, plus composable wrappers for Nullable , Array , Map , Tuple , and the rest of the type algebra, in full-buffer and chunked-stream variants. Each primitive is written to be monomorphizable small, single-purpose, free of megamorphic dispatch so it can be inlined into a query-specific parser without defeating V8's optimizer. This layer is a perfectly usable library on its own: import it, call parseRowBinary ... , get correct results. It also exports writers, streaming in both directions, and a dynamic RowBinaryWithNamesAndTypes pipeline built on @clickhouse/datatype-parser https://www.npmjs.com/package/@clickhouse/datatype-parser . The second layer is the SKILL.md https://github.com/ClickHouse/clickhouse-js/blob/main/skills/clickhouse-js-node-rowbinary/SKILL.md . Rather than describing how to call the API, it teaches a coding agent the policy for assembling the primitives into a bespoke parser for a given query's column types. The comments in the library source explain why each block looks the way it does and which axes are safe to change: buffer ownership, BigInt vs number for 64-bit integers, Date mapper hooks, Decimal scale handling, Array materialization strategy, fast paths for fixed-width columns. The library is the reference implementation, the comments are the design rationale, and the SKILL.md is the codegen policy. To install: 1npm i @clickhouse/rowbinary The skill is registered in the package's agents.skills field, so any agent that scans node modules for skills finds it automatically. You can also add it directly: 1npx skills add ClickHouse/clickhouse-js --skill clickhouse-js-node-rowbinary What the agent generates Take the orders schema from our benchmarks: 1id UInt8 2uid UUID 3price Decimal64 2 4status Enum8 'new' = 1, 'shipped' = 2, 'done' = 3 Composing the library's public API gives you a correct parser, and it's the obvious thing to write: js 1export const readOrderRow: Reader