Back to skills
SkillHub ClubShip Full StackFull Stack

adding-cli-command

Provides Typer templates, handles registration, and ensures consistency. ALWAYS use this skill when adding or modifying CLI commands. Use when user requests to add/create/implement/build/write a new command (e.g., "add edit command", "create search feature") OR update/modify/change/edit an existing command.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
835
Hot score
99
Updated
March 20, 2026
Overall rating
C3.9
Composite score
3.9
Best-practice grade
A88.4

Install command

npx @skill-hub/cli install https-deeplearning-ai-sc-agent-skills-files-adding-cli-command

Repository

https-deeplearning-ai/sc-agent-skills-files

Skill path: L6/.claude/skills/adding-cli-command

Provides Typer templates, handles registration, and ensures consistency. ALWAYS use this skill when adding or modifying CLI commands. Use when user requests to add/create/implement/build/write a new command (e.g., "add edit command", "create search feature") OR update/modify/change/edit an existing command.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: https-deeplearning-ai.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install adding-cli-command into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/https-deeplearning-ai/sc-agent-skills-files before adding adding-cli-command to shared team environments
  • Use adding-cli-command for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: adding-cli-command
description: Provides Typer templates, handles registration, and ensures consistency. ALWAYS use this skill when adding or modifying CLI commands. Use when user requests to add/create/implement/build/write a new command (e.g., "add edit command", "create search feature") OR update/modify/change/edit an existing command. 
---

# Adding CLI Commands

Templates and workflow for adding or updating Typer CLI commands.

`<cli_app>` refers to the name of your CLI application (e.g., `task`, `myapp`, `todo`).

## Workflow

1. Identify command type (single command, command group, or destructive)
2. Create file in `src/<cli_app>/commands/<command>.py`
3. Use appropriate template below
4. Register in `src/<cli_app>/commands/__init__.py`


## Template A: Single Command

For commands taking arguments directly (`<cli_app> add "item"`).

```python
import typer
from typing import Annotated

from <cli_app>.storage import add_task
from <cli_app>.display import display
from <cli_app>.constants import EXIT_INVALID_INPUT

app = typer.Typer()


@app.command()
def add(
    title: Annotated[str, typer.Argument(help="task title")],
    priority: Annotated[str, typer.Option("--priority", "-p", help="priority level")] = "low",
):
    """Add a new task."""
    if not title.strip():
        display.error("Title cannot be empty")
        raise typer.Exit(EXIT_INVALID_INPUT)

    task = add_task(title=title, priority=priority)
    display.success(f"Added '{task.title}'")
```

## Template B: Command Group

For commands with subcommands (`<cli_app> db migrate`, `<cli_app> db status`).

```python
import typer

from <cli_app>.storage import storage
from <cli_app>.display import display

app = typer.Typer(help="Database operations.")


@app.command()
def migrate():
    """Run database migrations."""
    storage.migrate()
    display.success("Migrations complete")


@app.command()
def status():
    """Show database status."""
    info = storage.get_status()
    display.info(f"Version: {info.version}")
```

## Template C: Destructive Command

For deletion with confirmation.

```python
import typer
from typing import Annotated

from <cli_app>.storage import get_task, delete_task
from <cli_app>.display import display
from <cli_app>.constants import EXIT_ERROR

app = typer.Typer()


@app.command()
def clear(
    task_id: Annotated[int, typer.Argument(help="task ID to delete")],
    force: Annotated[bool, typer.Option("--force", "-f", help="skip confirmation")] = False,
):
    """Delete a task permanently."""
    task = get_task(task_id)
    if not task:
        display.error(f"Task {task_id} not found")
        raise typer.Exit(EXIT_ERROR)

    if not force:
        confirm = typer.confirm(f"Delete '{task.title}'?", default=False)
        if not confirm:
            display.info("Cancelled")
            raise typer.Abort()

    delete_task(task_id)
    display.success(f"Deleted '{task.title}'")
```

## Registration

Register in `commands/__init__.py`:

```python
import typer

from .add import app as add_app
from .clear import app as clear_app

app = typer.Typer(help="<cli_app> CLI.", no_args_is_help=True)

# Single commands - add WITHOUT name
app.add_typer(add_app)
app.add_typer(clear_app)

# Command groups - add WITH name
# app.add_typer(db_app, name="db")
```

## Conventions

| Rule | Example |
|------|---------|
| Arguments | `Annotated[str, typer.Argument(help="...")]` |
| Options | `Annotated[str, typer.Option("--name", "-n", help="...")]` |
| Docstrings | Imperative mood, < 60 chars |
| Output | Always via `display` module |
| Exit codes | 0=success, 1=error, 2=invalid |
| Destructive | Must have `--force` flag, `default=False` confirmation |
adding-cli-command | SkillHub