Rye comes with a small, expressive CLI parsing dialect that lets you define flags, positional arguments, validation, and nested subcommands directly in Rye code. It also generates help text for you.
You’ll use these builtins:
parse-args - parse argv against a spec, returns a Dictparse-args\ctx - like parse-args, but returns a Context (dot-access)generate-help - generate help text from a specgenerate-help\command - generate help for a specific subcommand pathformat-parse-errors - pretty-print errors from failed parsingThe dialect lives in the spec block you pass to parse-args. It shares some similarities with other Rye dialects, like validation dialect. It supports:
-v|verbose flag,-o|output string requiredinput: string required, files: string manysubcommand { 'init { ... } 'remote { subcommand { 'add { ... } } } }Looking more into details, the dialect shares mechanisms and vocabulary with the validation dialect:
-n|count integer optional 10num: check { > 0 } "must be positive"Help is also generated from the dialect so it supports:
program "mytool", description "..."doc "Enable verbose"Our basic cli has a flag –verbose, flag with argument –output and a required positional argument at the end.
; argv simulated as a block for examples
args: { "--verbose" "-o" "out.txt" "in.txt" }
spec: {
program "mytool"
description "Example tool using Rye's CLI dialect"
-v|verbose flag doc "Enable verbose output"
-o|output string required doc "Output file"
input: string required doc "Input file"
}
result: parse-args args spec |^fix {
print format-parse-errors result
}
print2 "verbose: " result."verbose"
print2 "output: " result."output"
print2 "input: " result."input"
string, integer, decimal, boolean, file, anyoptional 42, optional 1.5, optional "stdout", etc.flag is boolean.Like with validation dialect, values are converted according to the dialect.
res: parse-args\ctx { } {
-n|count integer optional 3 doc "How many"
-r|rate decimal optional 1.5
-q|quiet flag
}
|do\in {
probe count ; [Integer: 3]
probe rate ; [Decimal: 1.5]
probe quiet ; [Boolean: false]
}
Use list to collect repeated flags; use many for variadic positionals.
parse-args
{ -I "/usr/include" -I "./include" }
{ -I|include string list }
|-> "include" |length? |print ; 2
parse-args
{ "a.txt" "b.txt" "c.txt" }
{ files: string many }
|-> "files" |length? |print ; 3
Attach check { ... } "message" to a flag or positional. The block runs with the value injected; it succeeds on truthy boolean or positive integer.
spec: { -p|port integer check { >= 1024 } "port must be >= 1024" }
parse-args { --port 80 } spec
|fix {
.format-parse-errors |print
}
; => Error: --port port must be >= 1024
Another example for positionals:
spec: { file: string check { .ends-with? ".txt" } "must be .txt file" }
parse-args { "notes.pdf" } spec
|fix {
.format-parse-errors |print
}
Define subcommands with 'name { ... }. Nest with subcommand { ... } inside another.
spec: {
-v|verbose flag
subcommand {
'commit {
-m|message string required doc "Commit message"
-a|amend flag doc "Amend last commit"
}
'remote {
doc "Manage remotes"
subcommand {
'add {
name: string required
url: string required
}
}
}
}
}
; commit
r1: parse-args { commit -m "Init" } spec
print r1."command" ; "commit"
print r1."message" ; "Init"
; nested: remote add
r2: parse-args { remote add origin "https://example.com" } spec
print r2."command" ; "remote add"
print r2."command-path" ; ["remote" "add"]
print r2."name" ; "origin"
print r2."url" ; "https://example.com"
Global flags (declared at the top level) are available alongside subcommands.
args: rye .Args? ; read argv as a Rye block
spec: {
program "minitool"
description "Demo CLI"
-v|verbose flag doc "Verbose"
-o|output string required doc "Output file"
input: string required doc "Input file"
}
res: parse-args args spec
|fix {
print generate-help spec
print "" ,
.format-parse-errors .print ,
exit 1
}
if res."verbose" { print "Verbose mode ON" }
Write file res."output" Read file res."input"
list initializes to an empty list by default so you can append naturally.check blocks run with the value injected; return true/positive to accept.