The primitive surface: built-in modules
The reference for the 21 cruft:* built-in modules, the runtime's own primitive layer beneath the node:* compatibility modules. Each is minimal, promise-native, bytes-first, and capability-gated. Lists every module, its exports, and how the tier is organized.
Beneath every node:* module Cruft ships sits its own tier: the host primitives, importable directly as cruft:*. The node:* modules carry Node's full API history; each is shaped over a smaller primitive that names what the operation fundamentally is, and the cruft:* specifiers expose that primitive tier directly. The contrast shows in the surface sizes: node:fs carries dozens of functions across three calling conventions, cruft:fs is seven verbs. This page is the reference for that surface, all 21 modules.
The primitive tier is Cruft-owned and intentional, but at 0.0.10 it is not yet a stability-guaranteed public API the way the node:* adapters are. Treat it as the runtime's native idiom, attractive for Cruft-first code, and expect the surface to keep refining.
What "primitive" means here
The Node compatibility layer is deliberately two-tiered (subsystems): the node:* modules absorb Node's API archaeology, and each rests on a primitive that expresses the core operation. The cruft:* tier is that primitive layer, and it has four consistent properties:
- Minimal and designed. One obvious way per operation, no legacy variants.
- Promise-native where async.
cruft:fsoperations return promises; there is no callback convention here. - Bytes-first. Binary data is
Uint8Arrayin and out, with no implicit string-coercion layer. - Capability-gated by construction. The capability checks live at this tier, so sealed and audit modes cover it automatically.
The same objects also exist as __cruft_* non-enumerable globals; prefer the module form.
Inventory
| Module | Exports | What it is |
|---|---|---|
cruft:fs | read write stat readdir mkdir remove exists | The seven filesystem verbs, promise-native |
cruft:path | join resolve normalize relative dirname basename extname format parse isAbsolute sep delimiter | Path algebra |
cruft:os | arch platform type release version hostname homedir tmpdir cpus totalmem freemem uptime endianness availableParallelism EOL | Host facts |
cruft:process | argv argv0 env cwd exit pid platform arch title uptime hrtime memoryUsage nextTick version versions | Process identity and control |
cruft:spawn | run exec | Minimal subprocess: run(cmd, args) → {code, stdout, stderr} |
cruft:child_process | Node-shaped set (spawn exec fork spawnSync …) | The full process family on the primitive tier |
cruft:http | createServer createSecureServer request | HTTP server and client primitives |
cruft:tls | connect createServer | TLS 1.3 transport |
cruft:dns | lookup resolve4 resolve6 | Name resolution |
cruft:url | URL URLSearchParams fileURLToPath pathToFileURL domainToASCII domainToUnicode | URL algebra |
cruft:querystring | parse stringify | Query-string codec |
cruft:buffer | Buffer | The binary-data type |
cruft:events | EventEmitter | The eventing primitive |
cruft:press | squeeze juice | Byte compression: squeeze(bytes, {as}) / juice(bytes, {as}), formats gzip/zlib/deflate/brotli |
cruft:sqlite | open | SQLite over Cruft's own engine, SQL stack |
cruft:orm | openSqlite openPostgres | Crizzle, the boundary-validating ORM, full page |
cruft:serve | serve staticDir | Fetch-shaped HTTP(S) server, full page |
cruft:pm | resolve canonicalKey | Package-manager resolution primitives |
cruft:presto | escapeHtml slugify titleCase classAttr openTag applyPipe | Embedded CruftScript templating kernel, full page |
cruft:test | TestNode runNode | Primitive test-tree kernel beneath node:test, full page |
cruft:vm | compile run createContext | In-context evaluation, isolated by default (see Limitations) |
Behavior
A sampler:
// cruft:fs — promise-native, bytes-first
import * as fs from "cruft:fs";
await fs.write("/tmp/probe.txt", "pure bytes");
const bytes = await fs.read("/tmp/probe.txt"); // Uint8Array
new TextDecoder().decode(bytes); // "pure bytes"
await fs.exists("/tmp/probe.txt"); // true
Object.keys(await fs.stat("/tmp/probe.txt"));
// size, mode, uid, gid, dev, ino, …, atimeMs, ctimeMs, birthtimeMs
// (numeric fields only; isFile()/isDirectory() are methods and atime/birthtime
// are non-enumerable getters, so none appear in Object.keys)
// cruft:press — one compression call, format as data
import * as press from "cruft:press";
const sq = press.squeeze(new TextEncoder().encode("hello hello hello"),
{ as: "gzip" }); // Uint8Array(27)
new TextDecoder().decode(press.juice(sq, { as: "gzip" }));
// "hello hello hello"
// cruft:spawn — the whole subprocess result in one value
import * as spawn from "cruft:spawn";
await spawn.run("echo", ["pure"]);
// { code: 0, stdout: "pure\n", stderr: "" }
// cruft:presto — templating helpers
import * as presto from "cruft:presto";
presto.escapeHtml("<a&b>"); // "<a&b>"
presto.slugify("Hello World!"); // "hello-world"
presto.titleCase("hello world"); // "Hello World"
The names have personality on purpose (squeeze/juice rather than compress/decompress). The primitive tier does not imitate anyone's API, so its names are chosen for the operation itself.
Reading the tier
Three groups are worth telling apart. The primitive duals of Node modules are the primitives the node:* adapters are shaped over. The Cruft-native capabilities exist first at the primitive tier and have no Node equivalent; some, like the ORM's boundary role in CruftScript, are architectural surfaces in their own right. The runtime-internal helpers are the package manager's resolution primitives, exposed for tooling.
Limitations
- Not a stability-guaranteed API yet. As the blockquote above says, the primitive tier is still refining at 0.0.10. The
node:*adapters are the surface to build on when you need a stable contract; reach forcruft:*when you want the native idiom and can absorb changes. cruft:vmis isolation-by-default, not a security sandbox. With no context,runevaluates in a fresh context that never sees the caller'sglobalThis, and a context you build only reaches what you put in it. That contains honest code, it does not contain adversarial code. To run untrusted code, use theCompartmentAPI and the agent sandbox, which are the real isolation boundary.