<< All versions

Skill v1.0.1

currentAutomated scan100/100
lbedner/aegis-stack/add-cli-command

+2 new

──Details
PublishedNovember 5, 2026 at 08:24 PM
Content Hashsha256:8e68ccdbfb3b5263...
Git SHA08e2feaeded3
Bump Typepatch
Compare with v1.0.0
──Files
Files (1 file, 2.2 KB)
SKILL.md2.2 KBactive
SKILL.md · 57 lines · 2.2 KB

name: add-cli-command description: Use when adding a command to this project's own CLI (the app CLI under app/cli/, not the aegis tool). Covers the command module, Typer registration, the async-def rule, and i18n strings. metadata: version: "1.0.1"


Add CLI command

The project ships a Typer CLI under app/cli/. A command module exposes a Typer app that is mounted in the CLI root, so a command is not runnable until it is both defined and registered.

When to use

Use when adding a subcommand to this project's CLI.

Do NOT use for HTTP routes (see the add-api-endpoint skill) or for background or scheduled work.

Files that change

  • app/cli/: command modules live here; add <name>.py exposing a Typer app.
  • app/cli/main.py: register the command by mounting its Typer app.
  • app/i18n/locales/en.py: add any user-facing strings as i18n keys (English

only; other locales are a separate translation pass).

Procedure

  1. Write the failing test first under tests/cli/, invoking the command with

invoke from tests/_cli.py (the Typer runner's own invoke never awaits an async command). Confirm it fails for the right reason.

  1. Create the command module in app/cli/ with a Typer app and the command

functions.

  1. Commands that need async are async def with plain await. NEVER call

asyncio.run(...) inside a command: app/cli/main.py runs Typer with standalone_mode=False, checks inspect.iscoroutine on the result, and owns the single asyncio.run. Exemplar: app/cli/llm.py:reset. A helper the command calls is async def too: an asyncio.run inside the running loop fails.

  1. Register the module in app/cli/main.py (mount its Typer app under a name).
  2. Route user-facing text through i18n keys in app/i18n/locales/en.py.
  3. Run the gates and fix anything red.

Gates

  • make check: lint, typecheck, and test.

Pitfalls

  • A command defined but not registered in app/cli/main.py never appears in the

CLI; registration is what wires it in.

  • Calling asyncio.run(...) inside a command fights the harness in

app/cli/main.py, which already awaits a returned coroutine. Declare the command async def and await directly.

  • Hardcoded user-facing strings bypass i18n; add a key in en.py instead.
← v1.0.0All versions