libreyolo-add-cli-command
DevelopmentAdd or extend a LibreYOLO CLI command or flag correctly: the Typer + KeyValueCommand architecture, both argument grammars (key=value and --key value), the --json/--quiet/--help-json contract, mode-aware aliases, family-derived defaults, and the unit tests that gate CLI behavior. Use when someone asks to add a CLI command, add a flag to predict/train/val/export, expose a Python feature on the CLI, or when a CLI parsing bug is reported (bool flags, aliases, key=value quirks). API naming decisions belong to libreyolo-api-conventions; this is the implementation side.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/LibreYOLO/libreyolo/blob/HEAD/skills/libreyolo-add-cli-command/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/libreyolo-add-cli-command, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Add or extend a LibreYOLO CLI command
The CLI is Typer with one custom layer: KeyValueCommand
(libreyolo/cli/parsing.py) rewrites YOLO-style key=value tokens into
--key value before Click parses, so every command accepts both grammars
with full Typer type-checking, help, and completion intact. Understand that
layer before touching anything; most CLI bugs live at its edges.
The map
libreyolo/cli/__init__.pyentrypoint(): registers everything. Special commands (version checks models formats cfg info metadata) come fromcommands/special.py; core modes (predict train val export ui monitor label doctor) are one module each undercommands/;profileis a Typer sub-app (command group) - use that pattern for any new multi-subcommand tool.commands/command_utils.py,output.py,errors.py: shared option handling, machine-readable output, and error rendering. Reuse; don't reimplement--jsonprinting or error exits per command.aliases.py: mode-aware translation of user-facing shorthand to internal config names (e.g. trainmosaictomosaic_prob, valconftoconf_thres). The single source of truth for name translation; never inline a rename in a command function.config.py: CLI-side config resolution.
Adding a flag to an existing command
- Add it as a typed Typer parameter in the command function, named per the
ecosystem convention (
libreyolo-api-conventions; check the standard's documented name first). - If users know it by a different name than the internal config field, add
the mapping to the right
*_ALIASESdict inaliases.py. - Bool flags need a decision: negatable (
--flag/--no-flag) or one-way (--json,--quiet)?key=falseon a one-way flag must drop the flag, not emit a nonexistent--no-<flag>; thenegatableset inrewrite_known_bool_flagsencodes this and getting it wrong is a known bug class (see the comments incli/__init__.pyaround the logging flags). Register new bool flags accordingly. - Mirror it in the Python API in the same PR (CLI and Python land together), and thread it through, verifying the value actually reaches the code that uses it; an accepted-and-ignored flag is a blocking review finding.
- Defaults come from the loaded model/family where they are family-shaped (imgsz, thresholds): read them off the model, don't hardcode (REVIEW.md: "CLI defaults are family-derived").
Adding a new command
- New module
libreyolo/cli/commands/<name>.pyexposing<name>_cmd(or a<name>_appTyper sub-app for command groups). - Register in
entrypoint()withcls=KeyValueCommand(orapp.add_typerfor groups). WithoutKeyValueCommandthe command silently loseskey=valuesupport, which users will file as a bug. - Support the output contract:
--json(machine-readable to stdout, nothing else on stdout),--quiet, and correct exit codes via the shared error helpers. Agents and scripts consume these; they are part of why the CLI is self-describing. - Keep imports inside the command function or module lazy where heavy
(torch etc.):
libreyolo --helpmust stay fast, and the entrypoint's deferred imports exist for that reason. - Docs: the command shows up in
libreyolo --helpautomatically; add it to the website docs command reference when user-facing.
Testing (the part that actually gates)
CLI tests are unit tests (tests/unit/cli/ for parsing/aliases/output/
errors, tests/unit/cli/commands/test_<cmd>.py per command) and run in the
PR gate, so they must be hermetic: mock the model layer, use tmp_path,
never download. Cover, at minimum:
- both grammars for the new surface (
key=valueand--key value), - bool-flag behavior including
key=falseon one-way flags, - alias translation if you touched
aliases.py, --jsonoutput shape (assert keys, not prose),- the failure path (bad input produces the intended error, not a traceback).
--help-json output comes from the declared Typer parameters, so it stays
correct if you declared the flag properly and wrong if you hand-parsed
argv; that is the test for whether you wired it right.
Traps
- Hand-parsing
sys.argvin a command. Everything goes through Typer parameters +KeyValueCommand, or grammar support fractures. - Renaming inside the command function instead of
aliases.py. - Printing progress to stdout (breaks
--jsonconsumers); human chatter goes to stderr / logging, respecting--quiet. - A new command that imports torch at module top (slows every
libreyoloinvocation, including--help). - Adding a
track/ task-prefixed verb without checking_strip_task_prefixincli/__init__.pyfor how task-prefixed argv is normalized.
Related
skills/libreyolo-api-conventions/: what to name it and whether it should exist on both surfaces (yes).skills/libreyolo-run-unit-tests/: keeping the new tests PR-gate-safe.tests/unit/cli/: the exemplars to copy.