Crust logoCrust

Arguments

Define positional arguments with types, defaults, and validation.

Arguments are positional values passed to your CLI without a flag name. They're defined as an ordered array via .args(), and Crust maps them to named, typed values.

my-cli serve 3000 localhost
#            ^^^^  ^^^^^^^^^
#            arg 1  arg 2

Defining Arguments

Arguments are defined with the .args() method. Order matters — the first argument definition maps to the first positional value:

const cmd = new Crust("serve")
  .args([
    { name: "port", type: "number", default: 3000 },
    { name: "host", type: "string", default: "localhost" },
  ])
  .run(({ args }) => {
    console.log(`Listening on ${args.host}:${args.port}`);
  });

Argument Properties

Each argument is an ArgDef object with properties like name, type, description, default, required, and variadic. See the ArgDef reference for the full property table.

Types

Crust supports three argument type literals:

.args([
  { name: "port", type: "number" },    // Coerced to number
  { name: "host", type: "string" },    // Kept as string
  { name: "verbose", type: "boolean" }, // Coerced to boolean
])
  • "string" — The value is kept as-is
  • "number" — The value is coerced to a number. Throws a PARSE error if the value isn't a valid number
  • "boolean" — The value is coerced to a boolean ("true" / "1" -> true)

Required Arguments

Mark an argument as required to error when it's missing:

.args([
  { name: "name", type: "string", required: true },
])
$ my-cli
# Error: Missing required argument "<name>"

When required is true, the inferred type is guaranteed (no | undefined).

Default Values

Provide a default for optional arguments:

.args([
  { name: "port", type: "number", default: 3000 },
])

When a default is set, the argument is always present in args — the inferred type is guaranteed (no | undefined).

Optional Arguments

Arguments without required or default are optional. Their type includes | undefined:

new Crust("example")
  .args([
    { name: "name", type: "string" },
  ])
  .run(({ args }) => {
    args.name; // string | undefined
  })

Variadic Arguments

The last argument can be variadic, collecting all remaining positional values into an array:

const cmd = new Crust("copy")
  .args([
    { name: "destination", type: "string", required: true },
    { name: "files", type: "string", variadic: true },
  ])
  .run(({ args }) => {
    args.destination; // string
    args.files;       // string[]
    for (const file of args.files) {
      console.log(`Copying ${file} to ${args.destination}`);
    }
  });
my-cli /output file1.txt file2.txt file3.txt

Only the last argument can be variadic. Crust enforces this at both compile time and runtime. Placing variadic: true on a non-last argument produces a type error.

Variadic arguments with required: true error when no values are provided. Without required, an empty array is returned.

The -- Separator

Arguments after -- are collected into rawArgs and not processed as positional arguments or flags:

.run(({ args, rawArgs }) => {
  // rawArgs contains everything after --
  console.log("Raw args:", rawArgs);
})
my-cli build -- --some-flag --passed-through
# rawArgs: ["--some-flag", "--passed-through"]

This is useful for forwarding arguments to child processes.

Type Inference

Crust infers argument types from your definitions — required and default guarantee the value, otherwise it's T | undefined. Variadic arguments always return an array. See the full inference rules for all cases.

On this page