Crust logoCrust

Core

Define, parse, route, and run type-safe CLI commands with Contexts and Extensions

@crustjs/core defines commands, routes and validates argv, constructs Contexts, applies Extensions, and runs Command Actions.

Install

npm install @crustjs/core

The package supports Bun 1.4+, Node 24+, and Deno 2.8+.

Quick example

src/cli.ts
import { Crust } from "@crustjs/core";

const app = new Crust("hello")
	.flags({ name: "verbose", type: "boolean", short: "v" })
	.action(({ flags, stdout }) => stdout(flags.verbose ? "hello!" : "hello"))
	.command("wave", (command) => command.action(({ stdout }) => stdout("o/")));

const outcome = await app.run([], { flags: { verbose: true } });
console.log(outcome.stdout); // => hello!

The root action prints hello! when verbose is true. The wave command is an app-local leaf command; use defineCommand() for a reusable definition.

Context-owned flags

src/cli.ts
import { Crust as ContextApp, defineContext, defineFlag } from "@crustjs/core";

const apiKey = defineFlag("api-key", { type: "string", required: true });
const api = defineContext("api")
	.flags(apiKey)
	.setup(({ flags }) => ({
		apiKey: flags["api-key"],
	}));

const contextApp = new ContextApp("my-cli")
	.provide(api())
	.action(async ({ ctx, stdout }) => stdout((await ctx.api).apiKey));

const contextOutcome = await contextApp.run([], { flags: { "api-key": "secret" } });
console.log(contextOutcome.stdout); // => secret

A Context can own the flags needed by its setup. .provide() installs that Context on the current command and commands added later; see Contexts.

Runtime exports

The API overview lists every runtime export of the package root.

Types

The root barrel exports the command, Context, Extension, input, snapshot, and error types used by applications. See Types for their fields and constraints.

TypeReference
ArgDef / FlagDefArgDef and FlagDef
ContextBag / ContextBuilder / ContextFactory / ContextSetupContext types
Extension / ExtensionBuilder / ExtensionFactoryExtension types
CommandSnapshot / ArgSnapshot / FlagSnapshotCommand Snapshots
BuildFile / BuildArtifacts (Extension build hooks)BuildFile and BuildArtifacts
BuildReportBuildReport
RootMetaKeyRootMetaKey
MergeFlagsMergeFlags
MergeContextMergeContext
InvocationOptions / ExecuteOptionsInvocation I/O

The root barrel is the full supported export list.

Typed invocation

const outcome = await app.run(["wave"]);
if (outcome.status === "completed") console.log(outcome.stdout); // => o/

run() returns a captured outcome after cleanup. See run() input and I/O for typed paths, structured input, validation, output capture, and failure behavior.

Tooling subpath

import { defineExtensionId } from "@crustjs/core";
import { buildCommandDocumentation, visibleSectionsFor } from "@crustjs/core/tooling";

const snapshot = await app.snapshot();
const documentation = buildCommandDocumentation(snapshot);
const visible = visibleSectionsFor(snapshot, defineExtensionId("acme:web-docs"));
ExportRole
BUILD_OUT_DIR_ENV / SNAPSHOT_PATH_ENVEnvironment variable names for the first-party subprocess protocol
buildCommandDocumentation()Builds a renderer-ready documentation tree from a Command Snapshot
formatDefault() / formatDescription()Formats input defaults and descriptions
isListed() / sectionsFor() / visibleSectionsFor()Filters commands and sections for an Extension identity
isInstalledCommandName() / INSTALLED_COMMAND_NAME_RULEChecks and describes the installed command name rule
CommandDocumentation / DocumentationArg / DocumentationFlag / UsageSegmentDocumentation model types
CommandSnapshotSame type as the root export, for tooling-only imports
parseFlagValues() / FlagEnvironmentResolves flags from their env bindings without argv

@crustjs/core/tooling contains build- and render-time helpers for Command Snapshots, documentation trees, section filtering, and formatting. They move in lockstep with first-party tooling. Application authoring and invocation APIs stay at the package root. SNAPSHOT_PATH_ENV and BUILD_OUT_DIR_ENV name the variables crust build sets when it runs a source entry to prepare its snapshot; do not set them in your CLI.

An installed command name uses letters, digits, ., _, and -, and starts with a letter or digit. crust build applies this rule to bin keys, create-crust to project names, and completion() to the root command name, which crust build requires to match the installed command.

parseFlagValues(flags, env) reuses terminal flag conversion without argv: environment splitting, choices, parsers or built-in coercion, defaults, requiredness, and Standard Schemas. Invalid definitions reject with DEFINITION; value failures reject with PARSE or VALIDATION and may quote raw input. @crustjs/env aggregates and redacts those failures for environment validation.

On this page