CLI reference

The complete command-line surface of the cruft binary: every command and execution option, the capability and sandboxing flags, exit codes, all CRUFT_* environment variables, the Compartment constructor, and the cruft-caps.json grant file.

The cruft binary, complete. Concepts and rationale live in the concepts and subsystems tiers; this page is the surface itself. Where behavior is stated concretely, it describes the current cruft binary.

Commands

CommandEffect
cruft <file>Run a file (shorthand for cruft run <file>)
cruft run <file>Run a JS/TS file or package script; --backend=auto/node/cruft --explain selects the engine (front door)
cruft wrap -- <cmd>Supervise a Node-family command (front door)
cruft wrap install / cruft wrap status / cruft unwrapManage the persistent node/npm/npx shim layer (front door)
cruft doctorExplain execution modes and wrapper state (--json for automation)
cruft policyShow the policy-profile control semantics
cruft trust install [--enforce] [-- npm install…]npm install risk preflight (front door)
cruft compat <target> / cruft promoteCompatibility-evidence cockpit (front door)
cruft agent run/doctor/replayRun code in an audited, budgeted compartment (full page)
cruft installInstall dependencies, write cruft-lock.json
cruft test262 run <path> / cruft test262 sweep …Conformance harness entries (maintainer surface)
cruft help, cruft --help, -hHelp
cruft --version, -v, -VVersion

Runnable file extensions now include .tsx and .fts (CruftScript) alongside the JavaScript and TypeScript set:

Runnable
.js.mjs.cjs.ts.mts.cts.tsx.fts

Unlike node, run is a real verb (node run x tries to execute a file named run). File-type dispatch is by extension: .mjs/.mts are ES modules, .cjs/.cts CommonJS, .js/.ts follow the nearest package.json "type"; .ts/.mts/.cts pass through type erasure first. .tsx is dispatched but not yet type-stripped and has no JSX support — TypeScript type annotations and JSX elements in a .tsx file currently fail to parse.

Execution options

OptionEffect
-e, --eval <src>Run inline source as a script (sloppy mode, like node; not type-stripped)
-p, --print <src>Run inline source, print the result (console.log formatting)
-c, --check <file>Parse-only syntax check; exit 0 if valid, 65 on syntax error
-i, --interactiveForce the REPL, even on piped stdin
-Read the script from stdin

Option parsing stops at the first entry point; flags after it go to your program's process.argv, exactly like node.

Capability options

The sandboxing surface (full treatment: Compartments and capabilities):

OptionEffect
--auditRun normally; log every I/O capability use (caller, capability, operation, timestamp)
--audit-log <path>Write the audit log to <path> instead of stderr
--sealedDeny all I/O not granted via cruft-caps.json; ungranted use throws
--sealed-depsYour code runs normally; node_modules code is denied I/O
--allow-net-loopbackRe-grant loopback listen authority under sealed modes

Inline -e/-p source runs under the same capability mode as a file; there is no separate eval policy.

Unrecognized flags

The flag set is deliberately small, and anything else in flag position is rejected, not ignored (cruft: bad option: --x, exit 64). This includes node flags Cruft has not implemented: they fail loudly rather than silently running without the requested behavior. (--require/-r preload is implemented — see CRUFT_PRELOAD in the environment table.)

Exit codes

process.exit(N) propagates faithfully. For Cruft's own errors the current convention is sysexits.h, which differs from node, branch on these with care:

SituationCruftnode
Clean run00
process.exit(N)NN
Uncaught exception11
Syntax error in entry1 (run) / 65 (--check)1
Entry file not found661
Unrecognized flag649
Install resolution failure (peer conflict, unsatisfiable range)70

The convention difference is tracked and may converge toward node-faithful behavior; treat non-zero-ness, not specific codes, as the portable signal.

cruft install

No positional arguments, no flags, configuration is entirely by environment variable (below). Reads dependencies from ./package.json; writes node_modules and cruft-lock.json. Output format:

cruft install: project=<dir> registry=<url> mode=<mode>
+ name@version      # installed this run
= name@version      # already satisfied, skipped
cruft install: <n> installed, <m> skipped

There is no add/remove/init/update yet; edit package.json and re-run. Root devDependencies are not yet read, and lifecycle scripts are not run (both tracked, see the package manager documented limitations).

Environment variables

Runtime / GC

VariableDefaultEffect
CRUFT_GC_HEADROOM4.0Heap growth multiplier between collections; floor 1.1. Lower = tighter RSS, higher = more throughput. Applies to every heap including workers.
CRUFT_GC_TARGET_MBunsetSoft memory target (GOMEMLIMIT-style): effective headroom tightens as process RSS rises from 50% to 100% of target. Bounds reclaimable memory, not the live set.
CRUFT_GC_STRESSunsetDiagnostic: force collection at a bounded allocation cadence. Not for production.

Package manager

VariableDefaultEffect
CRUFT_REGISTRYhttps://registry.npmjs.orgRegistry for resolution and downloads
CRUFT_STORE~/.cruft/storeContent-addressed store root
CRUFT_INSTALL_MODElinklink (hard-links from store, pnpm-style) or isolated/npm/copy (self-contained copies)
CRUFT_PM_LEGACY_PEER_DEPSoffOn peer conflict: pick most-satisfying and warn (npm --legacy-peer-deps)
CRUFT_PM_NO_PEERSoffIgnore peer dependencies entirely (escape hatch)
CRUFT_PM_CONCURRENCY16Max concurrent registry connections

Compartment API (runtime globals)

Not a CLI flag but part of the operable surface, the constructor options in one place:

new Compartment(opts) optionEffect
globals: {…}The capability grant: each entry becomes a global inside the fresh realm; nothing else exists there
timeout_ms: NWall-clock budget per evaluate; expiry terminates beneath the language
worker: trueBuild the realm on a worker thread; communicate via send
onMessageSource: "src"Message-handler source text, compiled on the worker; handler receives { data } events

Methods: evaluate(src) (compile + run in the realm, returns completion value; state persists across calls), send(payload) (worker-hosted only: structured-clone delivery; SharedArrayBuffer crosses by reference; functions rejected).

Capability grant file

Sealed modes read grants from a cruft-caps.json next to (or above) the entry file, allow-lists per family:

{ "fs": ["./"], "net": ["127.0.0.1:8080"], "env": ["HOME"], "exec": ["git"], "stdio": { "stdout": true, "stderr": true } }

The stdio family authorizes a sealed program to write to standard output and standard error, so a directly-run sealed script that prints can be granted the streams it needs. Note stdio takes object form ({ "stdout": true, "stderr": true }), not an array — the fs/net/env/exec families are arrays. fs entries match the as-written operation path (use "./" for relative access).