@crustjs/core v0.5.5Roadmap

Build CLIs
agents can use.

A TypeScript CLI framework with composable modules for humans and agents.

src/cli.tsTypeScript
import { Crust } from "@crustjs/core";
import { help } from "@crustjs/extensions";

const app = new Crust("greet")
	.extend(help())
	.args({ name: "name", type: "string", default: "world" })
	.flags({ name: "shout", type: "boolean", short: "s" })
	.action(({ , , stdout }) => {
		const line = `Hello, ${args.name}!`;
		stdout(flags.shout ? line.toUpperCase() : line);
	})
	.command("wave", (command) =>
		command.action(({ stdout }) => stdout("👋")),
	);

await app.execute();

See Crust in action

  1. convert.tsTypeScript
    import { Crust } from "@crustjs/core";
    
    const convert = new Crust("convert")
    	.args({ name: "input", type: "string", required: true })
    	.flags({ name: "to", type: "string", default: "html" })
    	.action(({ args, flags, stdout }) => {
    		stdout(`Converting ${args.} as ${flags.}`);
    	});
    
    await convert.execute();
    bun run convert.ts report.mdConverting report.md as html bun run convert.ts report.md --to pdfConverting report.md as pdf
  2. serve.tsTypeScript
    import { Crust } from "@crustjs/core";
    import { z } from "zod";
    
    const Port = z.coerce.number().max(65535).default(3000);
    
    const serve = new Crust("serve")
    	.args({ name: "port", schema: Port })
    	.action(({ args, stdout }) => {
    		stdout(`listening on port ${args.}`);
    	});
    
    await serve.execute();
    bun run serve.tslistening on port 3000 bun run serve.ts 70000Error: Invalid input:  - args.port: Too big: expected number to be <=65535
  3. work.tsTypeScript
    import { Crust, defineContext } from "@crustjs/core";
    
    const db = defineContext("db").setup(
    	({ stdout, defer }) => {
    		stdout("db opened");
    		defer(() => stdout("db closed"));
    		return { query: (sql: string) => `${sql}: ok` };
    	},
    );
    
    const work = new Crust("work")
    	.provide(db())
    	.command("query", (command) =>
    		command.action(async ({ ctx, stdout }) => {
    			stdout((await ctx.).query("select 1"));
    		}),
    	)
    	.command("fail", (command) =>
    		command.action(async ({ ctx }) => {
    			await ctx.db;
    			throw new Error("query failed");
    		}),
    	);
    
    await work.execute();
    bun run work.ts querydb openedselect 1: okdb closed bun run work.ts faildb openeddb closed Error: query failed
  4. deploy.tsTypeScript
    import {
    	Crust,
    	defineExtension,
    	defineExtensionId,
    } from "@crustjs/core";
    
    const id = defineExtensionId("acme:preview");
    const preview = defineExtension(id)
    	.flags({ name: "preview", type: "boolean" })
    	.preRun((ctx) => {
    		if (ctx.flags. !== true) return;
    		ctx.stdout("nothing changed");
    		return ctx.handled();
    	});
    
    const deploy = new Crust("deploy")
    	.extend(preview)
    	.action(({ stdout }) => stdout("deployed"));
    
    await deploy.execute();
    bun run deploy.tsdeployed bun run deploy.ts --previewnothing changed
  5. cli.test.tsTypeScript
    import { Crust } from "@crustjs/core";
    import { captureExecute } from "@crustjs/testing";
    
    const app = new Crust("cli").command("greet", (command) =>
    	command.action(({ stdout }) => stdout("Hello")),
    );
    
    const captured = await captureExecute(app, ["unknown"]);
    console.log(captured.);
    console.log(captured.);
    
    bun run cli.test.ts1Error: Unknown command "unknown".
  6. package.jsonJSON
    {
      "name": "my-cli",
      "version": "1.2.3",
      "bin": {
        "my-cli": "src/cli.ts"
      },
      "crust": {
        "runtime": "bun",
        "artifact": "binary"
      },
      "scripts": {
        "build": "crust build",
        "release": "crust publish"
      }
    }
    crust build --target bun-linux-x64.crust/├── manifest.json├── root/bin/my-cli.js└── linux-x64/bin/my-cli-bun-linux-x64
  7. src/cli.tsTypeScript
    import { Crust, defineCommand } from "@crustjs/core";
    import { help } from "@crustjs/extensions";
    import { skill } from "@crustjs/skills";
    
    const deploy = defineCommand(
    	"deploy",
    	{ description: "Deploy the app" },
    	(command) => command.action(() => {}),
    );
    
    const app = new Crust("my-cli", {
    	description: "Manage deployments",
    	version: "1.2.3",
    })
    	.extend(help()) // --help for humans
    	.extend(skill({})) // SKILL.md for agents
    	.add(deploy);
    
    await app.execute();
    crust build  # stages the skill help listsbun run src/cli.ts --helpmy-cli - Manage deployments Usage:  my-cli <command> [options] Commands:  deploy     Deploy the app  skills (skill) Manage agent skill installations (shorthand for `install`) Options:  -h, --help                   Show help Agent skills:  my-cli — Manage deployments    Source: .crust/root/skills/my-cli
  8. src/cli.tsTypeScript
    import { Crust, defineCommand } from "@crustjs/core";
    import { help } from "@crustjs/extensions";
    import { skill } from "@crustjs/skills";
    
    const deploy = defineCommand(
    	"deploy",
    	{ description: "Deploy the app" },
    	(command) => command.action(() => {}),
    );
    
    const app = new Crust("my-cli", {
    	description: "Manage deployments",
    	version: "1.2.3",
    })
    	.extend(help()) // --help for humans
    	.extend(skill({})) // SKILL.md for agents
    	.add(deploy);
    
    await app.execute();
    crust build.crust/artifacts/skills/my-cli/├── SKILL.md└── commands/    ├── my-cli.md    ├── deploy.md    ├── skills.md    └── skills/        ├── install.md        ├── repair.md        └── uninstall.md

Modules

@crustjs/corev0.5.5Define, parse, route, and run type-safe CLI commands with Contexts and Extensions
→
@crustjs/extensionsv0.5.4Official Crust Extensions for help, version, completion, typo hints, color, and updates
→
@crustjs/crustv0.5.4CLI to build and publish Crust apps as npm packages or standalone binaries
→
@crustjs/createv0.2.2Headless scaffolding engine for building project generators
→
@crustjs/progressv0.1.5Spinners and determinate progress indicators for terminal tasks
→
@crustjs/tuiv0.0.5Bun-only OpenTUI renderer adapter for Crust Command Actions
→
@crustjs/effectv0.2.3Effect.ts v4 adapter for Crust Command Actions, Contexts, and errors
→
@crustjs/envv0.1.1Typed, validated environment variables as a Crust Context, documented in help and man pages
→
@crustjs/promptsv0.2.6Interactive input, password, confirm, select, and filter prompts for the terminal
→
@crustjs/stylev0.3.6Terminal styling, colors, hyperlinks, and ANSI-aware text layout
→
@crustjs/storev0.4.4Typed JSON persistence for CLI config, data, state, and cache files
→
@crustjs/skillsv0.5.4Generate and install agent skills for AI coding assistants from Crust commands
→
@crustjs/manv0.5.4Generate mdoc(7) manual pages from Crust command definitions
→
@crustjs/testingv0.1.6Test helpers for Crust CLIs with captured output and fake interactive terminals
→
@crustjs/mcpv0.1.3Serve a Crust CLI as MCP tools over stdio
→
@crustjs/renderTerminal content rendering
Coming Soon
@crustjs/logStructured logging
Coming Soon