{"id":"b72cb1ec-4868-4687-b3c8-b0317a4658c9","shortId":"gfvPSq","kind":"skill","title":"python-typer","tagline":"Use when building or structuring Python CLI commands with Typer, including commands, options, and multi-command apps.","description":"# Python CLI with Typer\n\n## Overview\n\nUse Typer for ergonomic CLI construction. Core principle: keep command wiring thin, explicit, and testable while moving business logic into regular Python functions.\n\n## Use When\n\n- Building a Python CLI with Typer.\n- Adding commands, arguments, options, prompts, or confirmations.\n- Wiring a module entry point or console script.\n- Testing CLI behavior separately from business logic.\n\n## Install\n\n```bash\nuv add typer\n```\n\n## Quick Reference\n\n| Task | Pattern |\n| --- | --- |\n| Single command | `@app.command()` |\n| Options | function args with defaults |\n| Multiple commands | multiple `@app.command()` |\n| Module run | `uv run python -m <package>.cli --help` |\n| Script run | `uv run python cli.py --help` |\n| CLI tests | `CliRunner().invoke(app, [...])` |\n\n## Workflow\n\n- Define a `typer.Typer()` app in `cli.py`.\n- Keep command functions small; move business logic into separate modules.\n- Wire either `if __name__ == \"__main__\": app()` for script/module execution or a project console script in `pyproject.toml`.\n- Run CLI via `uv run python -m <module>` or `uv run python cli.py`.\n- Test command parsing and exit behavior with `typer.testing.CliRunner`.\n- Test business logic directly with normal function tests.\n\n## Example\n\n```python\nimport typer\n\napp = typer.Typer()\n\n@app.command()\ndef greet(name: str, count: int = 1) -> None:\n    for _ in range(count):\n        typer.echo(f\"Hello, {name}!\")\n\nif __name__ == \"__main__\":\n    app()\n```\n\nUsage:\n```bash\nuv run python cli.py --help\nuv run python cli.py Alice\nuv run python cli.py Alice --count 3\n```\n\nModule entry point:\n\n```bash\nuv run python -m my_package.cli --help\n```\n\nMultiple commands:\n```python\nimport typer\n\napp = typer.Typer()\n\n\n@app.command()\ndef create(name: str) -> None:\n    \"\"\"Create a new item.\"\"\"\n    typer.echo(f\"Creating {name}...\")\n\n\n@app.command()\ndef delete(name: str, force: bool = False) -> None:\n    \"\"\"Delete an item.\"\"\"\n    if not force:\n        if not typer.confirm(f\"Delete {name}?\"):\n            raise typer.Abort()\n    typer.echo(f\"Deleted {name}\")\n\n\nif __name__ == \"__main__\":\n    app()\n```\n\nCLI test:\n\n```python\nfrom typer.testing import CliRunner\n\nfrom my_package.cli import app\n\nrunner = CliRunner()\n\n\ndef test_greet() -> None:\n    result = runner.invoke(app, [\"Alice\", \"--count\", \"2\"])\n\n    assert result.exit_code == 0\n    assert \"Hello, Alice!\" in result.stdout\n```\n\n## Common Mistakes\n\n- Putting heavy business logic inside CLI functions.\n- Forgetting to wire `if __name__ == \"__main__\"` for script entry.\n- Testing only the underlying functions and missing CLI parsing or exit-code behavior.\n- Adding shell parsing manually instead of using Typer arguments and options.\n\n## Red Flags\n\n- CLI guidance that ignores Typer when Typer is the chosen framework.\n- CLI commands that cannot be run through `uv run`.","tags":["python","typer","skills","narumiruna","agent-skills"],"capabilities":["skill","source-narumiruna","skill-python-typer","topic-agent-skills"],"categories":["skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/narumiruna/skills/python-typer","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add narumiruna/skills","source_repo":"https://github.com/narumiruna/skills","install_from":"skills.sh"}},"qualityScore":"0.453","qualityRationale":"deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 7 github stars · SKILL.md body (2,843 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:13:47.375Z","embedding":null,"createdAt":"2026-05-18T19:13:47.375Z","updatedAt":"2026-05-18T19:13:47.375Z","lastSeenAt":"2026-05-18T19:13:47.375Z","tsv":"'0':316 '1':195 '2':312 '3':227 'ad':58,354 'add':83 'alic':220,225,310,319 'app':21,120,125,143,186,208,243,289,300,309 'app.command':91,100,188,245,259 'arg':94 'argument':60,362 'assert':313,317 'bash':81,210,231 'behavior':75,171,353 'bool':265 'build':6,52 'busi':44,78,133,175,326 'cannot':381 'chosen':376 'cli':10,23,31,55,74,107,116,155,290,329,347,367,378 'cli.py':114,127,165,214,219,224 'clirunn':118,296,302 'code':315,352 'command':11,15,20,36,59,90,98,129,167,239,379 'common':322 'confirm':64 'consol':71,150 'construct':32 'core':33 'count':193,200,226,311 'creat':247,251,257 'def':189,246,260,303 'default':96 'defin':122 'delet':261,268,278,284 'direct':177 'either':139 'entri':68,229,339 'ergonom':30 'exampl':182 'execut':146 'exit':170,351 'exit-cod':350 'explicit':39 'f':202,256,277,283 'fals':266 'flag':366 'forc':264,273 'forget':331 'framework':377 'function':49,93,130,180,330,344 'greet':190,305 'guidanc':368 'heavi':325 'hello':203,318 'help':108,115,215,237 'ignor':370 'import':184,241,295,299 'includ':14 'insid':328 'instal':80 'instead':358 'int':194 'invok':119 'item':254,270 'keep':35,128 'logic':45,79,134,176,327 'm':106,160,235 'main':142,207,288,336 'manual':357 'miss':346 'mistak':323 'modul':67,101,137,228 'move':43,132 'multi':19 'multi-command':18 'multipl':97,99,238 'my_package.cli':236,298 'name':141,191,204,206,248,258,262,279,285,287,335 'new':253 'none':196,250,267,306 'normal':179 'option':16,61,92,364 'overview':26 'pars':168,348,356 'pattern':88 'point':69,230 'principl':34 'project':149 'prompt':62 'put':324 'pyproject.toml':153 'python':2,9,22,48,54,105,113,159,164,183,213,218,223,234,240,292 'python-typ':1 'quick':85 'rais':280 'rang':199 'red':365 'refer':86 'regular':47 'result':307 'result.exit':314 'result.stdout':321 'run':102,104,110,112,154,158,163,212,217,222,233,383,386 'runner':301 'runner.invoke':308 'script':72,109,151,338 'script/module':145 'separ':76,136 'shell':355 'singl':89 'skill' 'skill-python-typer' 'small':131 'source-narumiruna' 'str':192,249,263 'structur':8 'task':87 'test':73,117,166,174,181,291,304,340 'testabl':41 'thin':38 'topic-agent-skills' 'typer':3,13,25,28,57,84,185,242,361,371,373 'typer.abort':281 'typer.confirm':276 'typer.echo':201,255,282 'typer.testing':294 'typer.testing.clirunner':173 'typer.typer':124,187,244 'under':343 'usag':209 'use':4,27,50,360 'uv':82,103,111,157,162,211,216,221,232,385 'via':156 'wire':37,65,138,333 'workflow':121","prices":[{"id":"89031afd-cdc0-4f97-9473-9c9cc9ea4ec4","listingId":"b72cb1ec-4868-4687-b3c8-b0317a4658c9","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"narumiruna","category":"skills","install_from":"skills.sh"},"createdAt":"2026-05-18T19:13:47.375Z"}],"sources":[{"listingId":"b72cb1ec-4868-4687-b3c8-b0317a4658c9","source":"github","sourceId":"narumiruna/skills/python-typer","sourceUrl":"https://github.com/narumiruna/skills/tree/main/skills/python-typer","isPrimary":false,"firstSeenAt":"2026-05-18T19:13:47.375Z","lastSeenAt":"2026-05-18T19:13:47.375Z"}],"details":{"listingId":"b72cb1ec-4868-4687-b3c8-b0317a4658c9","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"narumiruna","slug":"python-typer","github":{"repo":"narumiruna/skills","stars":7,"topics":["agent-skills"],"license":"mit","html_url":"https://github.com/narumiruna/skills","pushed_at":"2026-05-17T11:15:28Z","description":null,"skill_md_sha":"07a52f2305b02a5b9c282a01b639f79c40d20fa4","skill_md_path":"skills/python-typer/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/narumiruna/skills/tree/main/skills/python-typer"},"layout":"multi","source":"github","category":"skills","frontmatter":{"name":"python-typer","description":"Use when building or structuring Python CLI commands with Typer, including commands, options, and multi-command apps."},"skills_sh_url":"https://skills.sh/narumiruna/skills/python-typer"},"updatedAt":"2026-05-18T19:13:47.375Z"}}