This document tracks all notable changes to ArgMojo, including new features, API changes, bug fixes, and documentation updates.
- Add
.default_if_no_value["value"]()builder method for default-if-no-value semantics. When an option has a default-if-no-value, it may appear without an explicit value:--compressuses the default-if-no-value, while--compress=bzip2uses the explicit value. For long options,.default_if_no_value()implies.require_equals(). For short options,-cuses the default-if-no-value while-cbzip2uses the attached value (PR #12). - Add
.require_equals()builder method. When set, long options reject space-separated syntax (--key value) and require--key=value. Can be used standalone (the value is mandatory via=) or combined with.default_if_no_value()(the value is optional; omitting it uses default-if-no-value) (PR #12). - Help output adapts to the new modifiers:
--key=<value>for require_equals,--key[=<value>]for default_if_no_value (PR #12). Add(Temporarily disabled — triggers a Mojo compiler deadlock underresponse_file_prefix()builder method onCommandfor response-file support. When enabled, tokens starting with the prefix (default@) are expanded by reading the referenced file — each non-empty, non-comment line becomes a separate argument. Supports comments (#), escape (@@literal), recursive nesting (configurable depth), and custom prefix characters (PR #12).-D ASSERT=all. The implementation is preserved as module-level functions and will be re-enabled when the Mojo compiler bug is fixed.)- Add
.remainder()builder method onArgument. A remainder positional consumes all remaining tokens (including ones starting with-), similar to argparsenargs=REMAINDERor claptrailing_var_arg. At most one remainder positional is allowed per command and it must be the last positional (PR #13). - Add
parse_known_arguments()method onCommand. Likeparse_arguments(), but unrecognised options are collected into the result instead of raising an error. Access them viaresult.get_unknown_args(). Useful for forwarding unknown flags to another program (PR #13). - Add
.allow_hyphen_values()builder method onArgument. When set on a positional, values starting with-are accepted without requiring--(e.g.,-for stdin). Remainder positionals have this enabled automatically (PR #13). - CJK-aware help alignment. Help output now computes column padding using terminal display width instead of byte length. CJK ideographs and fullwidth characters are correctly treated as 2-column-wide, so help descriptions stay aligned when option names, positional names, or subcommand names contain Chinese, Japanese, or Korean characters. ANSI escape sequences are skipped during width calculation. No API changes — this is automatic (PR #14).
- Full-width → half-width auto-correction. When CJK users forget to switch input methods and type fullwidth ASCII (e.g.,
--verboseinstead of--verbose, or=instead of=), ArgMojo auto-detects and corrects these characters with a coloured warning. Fullwidth spaces (U+3000) embedded in a token cause it to be split into multiple arguments. All tokens containing fullwidth ASCII are normalized; only option tokens (starting with-after correction) trigger a warning. Disabled viadisable_fullwidth_correction()(PR #15). - CJK punctuation auto-correction. Common CJK punctuation outside the fullwidth ASCII range is also corrected — for example, em-dash (
——verbose) is converted to--verbose. This runs as a separate pass after fullwidth correction. Disabled viadisable_punctuation_correction()(PR #16). - Argument groups in help. Add
.group["name"]()builder method onArgument. Arguments assigned to the same group are displayed under a dedicated heading in--helpoutput, in first-appearance order. Ungrouped arguments remain under the default "Options:" heading. Persistent arguments are collected under "Global Options:" as before (PR #17). - Value-name wrapping control. Change
.value_name()to accept compile-time parameters:.value_name["NAME"]()or.value_name["NAME", False](). WhenwrappedisTrue(the default), the custom value name is displayed in angle brackets (<NAME>) in help output — matching the convention used by clap, cargo, pixi, and git. WhenwrappedisFalse, the value name is displayed bare (NAME). The auto-generated default placeholder (<arg_name>) is not affected (PR #17). - Registration-time validation for group constraints.
mutually_exclusive(),required_together(),one_required(), andrequired_if()now validate argument names againstself.argsat the moment they are called. AnErroris raised immediately if any name is unknown, empty lists are rejected, and duplicates are silently deduplicated.required_if()additionally rejects self-referential rules (target == condition). This catches developer typos on the very firstmojo run, without waiting for end-user input (PR #22). - Interactive prompting. Add
.prompt()and.prompt["text"]()builder methods onArgument. When an argument marked with.prompt()is not provided on the command line, the user is interactively prompted for its value before validation runs. Use.prompt()to prompt with the argument's help text, or.prompt["Custom text"]()to set a custom message. Works on both required and optional arguments. Prompts show valid choices for.choice[]()arguments and show default values in parentheses. For flag arguments,y/ninput is accepted. When stdin is not a terminal (e.g., piped input, CI environments,/dev/null), or wheninput()otherwise raises, the exception is caught, prompting stops gracefully, and any values collected so far are preserved (PR #23). - Argument parents. Add
add_parent(parent)method onCommand. Copies all argument definitions and group constraints (mutually exclusive, required together, one-required, conditional requirements, implications) from a parentCommandinto the current command. This lets you share a common set of arguments across multiple commands without repeating them — equivalent to Python argparse'sparentsparameter. The parent is not modified. All registration-time validation guards run on each inherited argument as usual (PR #25). - Confirmation option. Add
confirmation_option()andconfirmation_option["prompt"]()builder methods onCommand. - Usage line customisation. Add
usage(text)method onCommand. When set, the given text replaces the auto-generatedUsage: myapp [OPTIONS] ...line in both--helpoutput and error messages. This lets you write git-style usage strings likegit [-v | --version] [-h | --help] [-C <path>] <command> [<args>]. When not set, the default auto-generated usage line is used. When enabled, the command automatically registers a--yes/-yflag and prompts the user for confirmation after parsing (and after interactive prompting, if any). If the user does not confirm (y/yes), the command aborts with an error. Passing--yesor-yon the command line skips the prompt entirely. When stdin is not interactive (piped input,/dev/null), the command aborts gracefully. This is equivalent to Click'sconfirmation_optiondecorator (PR #26).
- Rename
.metavar()to.value_name()across the entire API and documentation. The internal field is now_value_name. This follows clap's naming convention and better describes the purpose. There is no backward-compatible alias — all call sites must use.value_name()(PR #13). - Value-name display now uses angle brackets by default. Custom value names set via
.value_name["FOO"]()are now rendered as<FOO>in help output. To preserve the old behaviour (bareFOO), use.value_name["FOO", False](). This only affects custom value names — the auto-generated placeholder was already wrapped in<>(PR #17). - Parameterise
.alias_name[]()as a compile-time parameter. Changed from.aliases(["color"])(runtimeList[String]) to.alias_name["color"]()(compile-timeStringLiteral). Alias names are validated at compile time (same rules as.long[]). For multiple aliases, chain calls:.alias_name["out"]().alias_name["fmt"]()(PR #18). - Parameterise
.delimiter[]()as a compile-time parameter. Changed from.delimiter(",")(runtimeString) to.delimiter[","]()(compile-timeStringLiteral). Only,,;,:,|are accepted; validated at compile time (PR #18). - Parameterise
.default[]()as a compile-time parameter. Changed from.default("val")(runtimeString) to.default["val"]()(compile-timeStringLiteral). No additional compile-time validation beyond the type change. - Parameterise
.deprecated[]()as a compile-time parameter. Changed from.deprecated("msg")(runtimeString) to.deprecated["msg"]()(compile-timeStringLiteral). Message must be non-empty (validated at compile time). - Parameterise
.default_if_no_value[]()as a compile-time parameter. Changed from.default_if_no_value("val")(runtimeString) to.default_if_no_value["val"]()(compile-timeStringLiteral). No additional compile-time validation beyond the type change. - Parameterise
.group[]()as a compile-time parameter. Changed from.group("name")(runtimeString) to.group["name"]()(compile-timeStringLiteral). Group name must be non-empty (validated at compile time). - Replace
.choices()with chained.choice[](). Changed from.choices(list^)(runtimeList[String]) to chained.choice["a"]().choice["b"]()(compile-timeStringLiteral). Each choice value must be non-empty (validated at compile time). This uses the same singular-parameter + chaining pattern as.alias_name[](), since Mojo'sStringLiteralembeds its value in the type and variadic parameters require homogeneous types.
- Clarify documentation and docstrings:
default_if_no_valuedoes not "reject"--key value; it simply does not consume the next token as a value (PR #12, review feedback). - Fix cross-library comparison: click is described as "Python CLI framework" instead of incorrectly saying "built on top of argparse" (PR #12, review feedback).
- Reject
.require_equals()/.default_if_no_value()combined with.number_of_values[N]()atadd_argument()time with a clear error (PR #12, review feedback).
- Compile-time
StringLiteralparameters. Builder methods that accept fixed, known values (.long[],.short[],.choice[],.default[],.delimiter[],.deprecated[],.default_if_no_value[],.group[],.alias_name[],.value_name[],header_color[],arg_color[],warn_color[],error_color[],.max[],.range[],.number_of_values[],response_file_max_depth[]) now use compile-timeStringLiteralorIntparameters. Invalid values are rejected by the compiler before a binary is produced (PR #18, and earlier PRs). - Registration-time name validation.
mutually_exclusive(),required_together(),one_required(), andrequired_if()now raise anErrorimmediately if any referenced argument name is not registered. Empty lists are rejected and duplicates are deduplicated.required_if()rejects self-referential rules. This matches the existing pattern inimplies()(PR #22).
- Add
tests/test_const_require_equals.mojowith 30 tests covering default_if_no_value, require_equals, and their interactions with choices, append, prefix matching, merged short flags, persistent flags, and help formatting (PR #12). - Add
tests/test_response_file.mojowith 17 tests covering basic expansion, comments, whitespace stripping, escape, recursive nesting, depth limit, custom prefix, disabled-by-default, and error handling (PR #12). - Add
tests/test_remainder_known.mojowith 18 tests covering remainder positionals,parse_known_arguments(),allow_hyphen_values(), and thevalue_namerename (PR #13). - Add
tests/test_fullwidth.mojowith 30 tests covering full-width → half-width auto-correction and CJK punctuation correction, including utility functions, fullwidth flags, equals syntax, embedded fullwidth spaces, opt-out, choices validation, merged short flags, subcommand dispatch, parse_known_arguments, and CJK punctuation em-dash correction (PR #15, #16). - Add
tests/test_groups_help.mojowith 25 tests covering argument groups in help output and value-name wrapping control, including basic grouping, multiple groups, independent padding, hidden arguments in groups, groups with subcommands, wrapped/unwrapped value names with append/nargs/require_equals/default_if_no_value, and coloured output (PR #17). - Add 5 tests to
tests/test_groups.mojocovering registration-time validation: unknown argument detection formutually_exclusive,required_together,one_required, andrequired_if(both target and condition) (PR #22). - Add Developer Validation section to user manual documenting the two-layer validation model (compile-time
StringLiteral+ runtime registration-timeraises) with recommended workflow (PR #22). - Add
pixi run debugtask that runs all examples under-D ASSERT=allwith--helpto exercise registration-time validation in CI (PR #22). - Add
tests/test_prompt.mojowith tests covering interactive prompting builder methods, optional/required prompt arguments, prompting skipped when values are provided, choices and defaults integration, field propagation through copy, and combined features (PR #23). - Add
tests/test_parents.mojowith 20 tests covering argument parents: basic flag/value/positional/default inheritance, short flags, multiple parents, child-own args coexistence, group constraint inheritance (mutually exclusive, required together, one-required, conditional, implications), parent shared across children, count/append/range argument inheritance, empty parent, parent immutability, and parent with subcommands (PR #25). - Add
tests/test_confirmation.mojowith 13 tests covering confirmation option:--yes/-yflag skips, non-interactive stdin abort, custom prompt text, coexistence with other arguments, no-confirmation normal behavior, subcommand integration, copy preservation, prompt argument integration, and parent argument integration (PR #26).
ArgMojo v0.3.0 adds shell completion, typo suggestions, mutual implication, hidden subcommands, NO_COLOR support, and several builder-method improvements. Internally the code is decomposed into smaller helpers and a new utils.mojo module; several API names are refined for consistency. Two breaking changes affect call sites that use nargs, max, or range (now compile-time parameters) and the renamed methods listed below.
ArgMojo v0.3.0 is compatible with Mojo v0.26.1.
- Implement shell completion script generation for Bash, Zsh, and Fish, with a built-in
--completions <shell>flag that emits a ready-to-source script (PR #4). - Allow disabling the built-in flag (
disable_default_completions()), customising the trigger name (completions_name()), or exposing completions as a subcommand (completions_as_subcommand()) (PR #4). - Add Levenshtein-distance based "did you mean ...?" suggestions for misspelled long options and subcommand names (PR #3).
- Implement
command_aliases()onCommandto register alternative names for subcommands. Aliases are shown in help, accepted during dispatch, and included in shell completions and typo suggestions (PR #5). - Add
.clamp()modifier for.range[min, max]()-- out-of-range values are adjusted to the nearest boundary with a warning instead of a hard error (PR #6). - Move count-ceiling enforcement (
.max[N]()) and range validation into the_validate()phase so all post-parse checks run in a single pass (PR #6). - Parameterise
.max[ceiling](),.range[min, max](), and.number_of_values[N]()as compile-time parameters, enabling build-time validation of invalid values (PR #8). - Add
Command.hidden()builder method. Hidden subcommands are excluded from help output, shell completions, "Available commands" error messages, and typo suggestions, while remaining dispatchable by exact name or alias (PR #9). - Honour the
NO_COLORenvironment variable (any value, including empty). When set, all ANSI colour output from help, warning, and error messages is suppressed, following the no-color.org standard (PR #9). - Add
Command.implies(trigger, implied)to automatically set one argument when another is present. Supports chained implications (A -> B -> C) with cycle detection at registration time. Works with flags and count arguments, and integrates with existing constraints (required_if,mutually_exclusive) (PR #10).
parse_args()renamed toparse_arguments()(PR #5).help_on_no_args()renamed tohelp_on_no_arguments()(PR #5)..nargs()renamed to.number_of_values()andnargs_countfield renamed to_number_of_values(PR #5).- Several
ArgumentandParseResultattributes are now underscore-prefixed (private). Public builder methods are unchanged (PR #7). - Decompose
parse_args()into four sub-methods:_parse_long_option(),_parse_short_single(),_parse_short_merged(),_dispatch_subcommand()(PR #2). - Decompose
_generate_help()into five sub-methods:_help_usage_line(),_help_positionals_section(),_help_options_section(),_help_commands_section(),_help_tips_section()(PR #2). - Extract ANSI colour constants and utility functions into a new internal module
utils.mojo(PR #2). - Rename example files to avoid confusion:
git.mojo->mgit.mojo,grep.mojo->mgrep.mojo. - Add
examples/demo.mojo-- a comprehensive showcase of all ArgMojo features in a single CLI (PR #7).
- Add
tests/test_typo_suggestions.mojocovering Levenshtein-based suggestions (PR #3). - Add
tests/test_completion.mojowith comprehensive tests for Bash, Zsh, and Fish script generation (PR #4). - Add
tests/test_implies.mojocovering basic, chained, and multi-target implications, cycle detection, and constraint integration (PR #10). - Add builder method compatibility section to the user manual with an ASCII tree, Mermaid diagram, and compatibility table (PR #11).
- Set up GitHub Actions workflow for automatic wiki synchronisation from
docs/user_manual.md. - Update user manual to cover all new features.
ArgMojo v0.2.0 is a major release that transforms the library from a single-command parser into a full subcommand-capable CLI framework. It introduces hierarchical subcommands with automatic dispatch, persistent (global) flags with bidirectional sync, negative number passthrough, colored error messages, custom tips, and significant help/UX improvements. The public API is also refined: Arg -> Argument, Result -> ParseResult (old names kept as aliases). Two complete example CLIs (mgrep and mgit) replace the previous demo.
ArgMojo v0.2.0 is compatible with Mojo v0.26.1.
- Implement full subcommand support with
add_subcommand()API, hierarchical dispatch, and nested subcommands (e.g.,git remote add). - Auto-register a
helpsubcommand so thatapp help <command>works out of the box; opt out withdisable_help_subcommand(). - Add
allow_positional_with_subcommands()guard -- prevents accidental mixing of positional args and subcommands on the sameCommand, following the cobra/clap convention. Requires explicit opt-in. - Add
subcommandandsubcommand_resultfields onParseResultwithhas_subcommand_result()/get_subcommand_result()accessors. - Add
command_aliases()builder method for subcommand short names (e.g.,clone->cl). Aliases dispatch to the canonical subcommand, appear in help output, shell completions, and typo suggestions. - Add
.persistent()builder method onArgumentto mark a flag as global. - Persistent args are automatically injected into child commands and support bidirectional sync: flags set before the subcommand push down to the child, and flags set after the subcommand bubble up to the root.
- Detect conflicting long/short names between parent persistent args and child local args at registration time (
add_subcommand()raises an error). - Recognize negative numeric tokens like
-3.14or-42as positional values instead of unknown short options. Addallow_negative_numbers()opt-in onCommandfor explicit control. - Add
add_tip()API onCommandto attach user-defined tips that render as a dedicated section at the bottom of help output. - Colored error and warning messages -- ANSI-styled stderr output for all parse errors.
- Unknown subcommand error now lists all available commands.
- Errors inside child parse are prefixed with the full command path (e.g.,
git remote add: ...).
- Rename
Argstruct toArgumentandResultstruct toParseResult. The old names are kept as aliases for backward compatibility. - Rename source files:
arg.mojo->argument.mojo,result.mojo->parse_result.mojo. - Add a "Commands" section to help output listing available subcommands with aligned descriptions.
- Show
<COMMAND>placeholder in the usage line for commands that have subcommands. - Display persistent flags under a "Global Options" heading in child help.
- Show the full command path in child help and error messages (e.g.,
Usage: git remote add [OPTIONS] NAME URL). - Extract
_apply_defaults()and_validate()into private helper methods onCommand, enabling clean reuse for both root and child parsing.
- Add two complete example CLIs:
examples/mgrep.mojo(single-command, demonstrating all argument features) andexamples/mgit.mojo(subcommand-based, with nested subcommands and persistent flags). - Add
tests/test_subcommands.mojocovering data model, dispatch, help subcommand, persistent flags, allow-positional guard, and error handling. - Add
tests/test_negative_numbers.mojo. - Add
tests/test_persistent.mojo. - Update user manual (
docs/user_manual.md) to cover all new features.
ArgMojo v0.1.0 is the initial release, providing a builder-pattern API for defining and parsing command-line arguments in Mojo. It covers all commonly-used features from argparse, clap, and cobra for single-command CLI applications.
ArgMojo v0.1.0 is compatible with Mojo v0.26.1.
- Long options (
--verbose,--output file.txt,--output=file.txt) and short options (-v,-o file.txt). - Boolean flags that take no value.
- Positional arguments matched by position, with optional default values.
- Required argument validation.
--stop marker -- everything after--is treated as positional.- Short flag merging --
-abcexpands to-a -b -c. - Attached short values --
-ofile.txtmeans-o file.txt. - Count flags --
-vvv->get_count("verbose") == 3. - Positional argument count validation -- reject extra positional args.
- Choices validation -- restrict values to a set (e.g.,
json,csv,table). - Negatable flags --
--color/--no-colorpaired flags with.negatable(). - Long option prefix matching --
--verbauto-resolves to--verbosewhen unambiguous. - Conditional requirements --
--outputrequired only when--saveis present. - Numeric range validation --
.range[1, 65535]()validates value is within bounds. - Mutually exclusive groups -- prevent conflicting flags (e.g.,
--jsonvs--yaml). - Required-together groups -- enforce that related flags are provided together (e.g.,
--username+--password). - One-required groups -- require at least one argument from a group.
- Append / collect action --
--tag x --tag ycollects repeated options into a list with.append(). - Value delimiter --
--env dev,staging,prodsplits by delimiter into a list with.delimiter[","](). - Multi-value options (nargs) --
--point 10 20consumes N consecutive values with.number_of_values[N](). - Key-value map option --
--define key=valuebuilds aDictwith.map_option(). - Auto-generated help with
--help/-h/-?, dynamic column alignment, pixi-style ANSI colours, and customisable header/arg colours. - Help on no args -- optionally show help when invoked with no arguments.
- Version display with
--version/-V. - Metavar -- custom display name for values in help text.
- Hidden arguments -- exclude internal args from help output.
- Aliases for long names --
.alias_name["color"]()for--colour/--color. - Deprecated arguments --
.deprecated["Use --format instead"]()prints warning to stderr.