[HN Gopher] Show HN: Crust - A CLI framework for TypeScript and Bun
___________________________________________________________________
Show HN: Crust - A CLI framework for TypeScript and Bun
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.
Author : jellyotsiro
Score : 59 points
Date : 2026-03-17 04:43 UTC (18 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| landl0rd wrote:
| Is there an examples section? Would be helpful to see a demo
| jellyotsiro wrote:
| one of the examples would be trynia.ai (search and index api
| for ai agents)
|
| here is github: github.com/nozomio-labs/nia-cli
| matt_kantor wrote:
| > 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 wrote:
| 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 wrote:
| I understand, but that's already implied by a 0.y.z version
| number.
| olivia-banks wrote:
| I will say that this doesn't seem to be how semver is used
| in the wild, which I would argue is more important. I
| personally didn't know about this rule. Tons of Rust
| projects follow semver don't follow it either, and just
| stay on 0.x.y forever.
| chenxin-yan wrote:
| Hi, the comment I left in README.md is just to warn user that
| do expect breaking changes before 1.0 for THIS PROJECT
| specifically. there is no implication that semver as a standard
| is promoting arbitrary changes/version before 1.0.
| bennettpompi1 wrote:
| this is cool! i'd recommend fleshing out the README. Clicked on
| the link before the discussion and was a tad confused.
| jellyotsiro wrote:
| will fix in the next hour!
| chenxin-yan wrote:
| Hi, I will update the README.md to make it more informative.
| The reason I left it kinda empty is because curst has a website
| that have more details about this project at crustjs.com. I
| just had the link in README.md for now
| dnlzro wrote:
| Psst, the GitHub link in your post is broken (it should be
| https://github.com/chenxin-yan/crust).
| jellyotsiro wrote:
| thanks for flagging! the post itself works, just the link at
| the bottom
| dang wrote:
| Fixed above. Thanks for the heads-up!
| camkego wrote:
| 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.
| jellyotsiro wrote:
| 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.
| embedding-shape wrote:
| 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.
| codybontecou wrote:
| That's... actually a great definition. I'm going to try to
| retain that.
| chenxin-yan wrote:
| Hi, I called it "CLI framework" because it is more of a
| ecosystem of modules that contains everything you need to build
| a CLI, argument parsing is just part of it. The @crustjs/core
| module is the argument parser, and there are more modules such
| as @crustjs/skills that would derive agent skills from your
| command definition, @crustjs/store that state persistent and so
| on
| rgbrgb wrote:
| nice, congrats on launch. To get an idea... what's the size of a
| standalone hello world cli binary?
| jellyotsiro wrote:
| tens of KBs (v small)
| rgbrgb wrote:
| Isn't a standalone Bun binary like 50MB because it has to
| bundle the runtime? How could this get smaller?
| chenxin-yan wrote:
| Hi, the creator of crust here, the binary size varies
| between platforms. With the hello world cli, the smallest,
| on darwin-arm64 it is 58.1M, the largest on windows-x64 is
| 109M. hope this helps!
| nullstyle wrote:
| I've been using the jsr:@cliffy/* packages from deno to solve the
| same problem.
___________________________________________________________________
(page generated 2026-03-17 23:00 UTC)