\

Show HN: Crust – A CLI framework for TypeScript and Bun

39 points - today at 4:43 AM


We've been building Crust (https://crustjs.com/), a TypeScript-first, Bun-native CLI framework with zero dependencies. It's been powering our core product internally for a while, and we're now open-sourcing it.

The problem we kept running into: existing CLI frameworks in the JS ecosystem are either minimal arg parsers where you wire everything yourself, or heavyweight frameworks with large dependency trees and Node-era assumptions. We wanted something in between.

What Crust does differently:

- Full type inference from definitions β€” args and flags are inferred automatically. No manual type annotations, no generics to wrangle. You define a flag as type: "string" and it flows through to your handler.

- Compile-time validation β€” catches flag alias collisions and variadic arg mistakes before your code runs, not at runtime.

- Zero runtime dependencies β€” @crustjs/core is ~3.6kB gzipped (21kB install). For comparison: yargs is 509kB, oclif is 411kB.

- Composable modules β€” core, plugins, prompts, styling, validation, and build tooling are all separate packages. Install only what you need.

- Plugin system β€” middleware-based with lifecycle hooks (preRun/postRun). Official plugins for help, version, and shell autocompletion.

- Built for Bun β€” no Node compatibility layers, no legacy baggage.

Quick example:

  import { Crust } from "@crustjs/core";
  import { helpPlugin, versionPlugin } from "@crustjs/plugins";

  const main = new Crust("greet")
    .args([{ name: "name", type: "string", default: "world" }])
    .flags({ shout: { type: "boolean", short: "s" } })
    .use(helpPlugin())
    .use(versionPlugin("1.0.0"))
    .run(({ args, flags }) => {
      const msg = `Hello, ${args.name}!`;
      console.log(flags.shout ? msg.toUpperCase() : msg);
    });

  await main.execute();
Scaffold a new project:

  bun create crust my-cli
Site: https://crustjs.com GitHub: https://github.com/chenxin-yan/crust

Happy to answer any questions about the design decisions or internals.

Source
  • nullstyle

    today at 8:26 PM

    I’ve been using the jsr:@cliffy/* packages from deno to solve the same problem.

    • camkego

      today at 6:23 PM

      This looks useful. But, it's interesting how the backend-world and front-end world keep diverging. I must admit, I had no idea what this was from the title. "CLI framework"? But in backend-land, these would typically be called "argument parsers" or "command line argument parsers". But maybe I am missing some of the functionality.

        • embedding-shape

          today at 8:16 PM

          Both in the frontend and the backend, I've usually used "If it calls your code, it's a framework, if you call its code, it's a library", and would seem to fit here too. An argument parser you'd call from your main method, then do stuff with what it returns. In Crust, it seems you instead setup the command + what will happen when it's called, then let the framework call your code.

          • jellyotsiro

            today at 6:40 PM

            good point.

            we’re using β€œframework” intentionally because it goes beyond argument parsing. crust handles parsing, but also:

            type inference across args + flags end to end compile-time validation (so mistakes fail before runtime) plugin system with lifecycle hooks (help, version, autocomplete, etc.) composable modules (prompts, styling, validation, build tooling) auto-generates agent skills and modules from the CLI definitions

            so it sits a layer above a traditional arg parser like yargs or commander, closer to something like oclif, but much lighter and bun-native.

        • bennettpompi1

          today at 5:57 PM

          this is cool! i'd recommend fleshing out the README. Clicked on the link before the discussion and was a tad confused.

            • jellyotsiro

              today at 5:59 PM

              will fix in the next hour!

          • matt_kantor

            today at 5:36 PM

            > Versions before 1.0 do not strictly follow semantic versioning.

            Sorry for being nitpicky, but yes they do. Semantic versioning[0] allows arbitrary changes while the major version is 0:

            > Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

            [0]: https://semver.org/

              • jellyotsiro

                today at 5:43 PM

                thanks for the catch, what we meant is that we’re not committing to strict stability guarantees yet, so APIs may still change as we iterate toward 1.0.

                  • matt_kantor

                    today at 5:46 PM

                    I understand, but that's already implied by a 0.y.z version number.

            • rgbrgb

              today at 6:37 PM

              nice, congrats on launch. To get an idea... what's the size of a standalone hello world cli binary?

                • jellyotsiro

                  today at 7:11 PM

                  tens of KBs (v small)

                    • rgbrgb

                      today at 7:39 PM

                      Isn't a standalone Bun binary like 50MB because it has to bundle the runtime? How could this get smaller?

              • landl0rd

                today at 5:33 PM

                Is there an examples section? Would be helpful to see a demo

                  • jellyotsiro

                    today at 5:42 PM

                    one of the examples would be trynia.ai (search and index api for ai agents)

                    here is github: github.com/nozomio-labs/nia-cli

                • leontloveless

                  today at 8:02 PM

                  [dead]

                  • dnlzro

                    today at 6:11 PM

                    Psst, the GitHub link in your post is broken (it should be https://github.com/chenxin-yan/crust).

                      • dang

                        today at 7:31 PM

                        Fixed above. Thanks for the heads-up!

                        • jellyotsiro

                          today at 6:15 PM

                          thanks for flagging! the post itself works, just the link at the bottom

                          • today at 6:14 PM