Why Use This This skill provides specialized capabilities for psincraian's codebase.
Use Cases Developing new features in the psincraian repository Refactoring existing code to follow psincraian standards Understanding and working with psincraian's codebase structure
Install Guide 2 steps 1 2 Install inside Ananke
Click Install Skill, paste the link below, then press Install.
https://github.com/psincraian/myfy/tree/main/plugins/claude-code/skills/cli-module Skill Snapshot Auto scan of skill assets. Informational only.
Valid SKILL.md Checks against SKILL.md specification
Source & Community
Updated At Jan 12, 2026, 08:05 PM
Skill Stats
SKILL.md 278 Lines
Total Files 1
Total Size 0 B
License NOASSERTION
---
name: cli-module
description: myfy CliModule for custom CLI commands with DI injection. Use when working with CliModule, @cli.command decorator, command groups, CLI arguments, CLI options, or myfy app commands.
---
# CliModule - Custom CLI Commands
CliModule enables custom CLI commands with full dependency injection and Typer integration.
## Quick Start
```python
from myfy.core import Application
from myfy.commands import CliModule, cli
@cli.command()
async def seed_users(user_service: UserService, count: int = 10):
'''Seed the database with test users.'''
for i in range(count):
await user_service.create(f"user{i}@example.com")
print(f"Created {count} users")
app = Application()
app.add_module(CliModule())
# Run with: myfy app seed-users --count 20
```
## Configuration
Environment variables use the `MYFY_CLI_` prefix:
| Variable | Default | Description |
|----------|---------|-------------|
| `MYFY_CLI_VERBOSE` | `False` | Enable verbose output |
| `MYFY_CLI_NO_COLOR` | `False` | Disable colored output |
| `MYFY_CLI_TIMEOUT` | `300` | Command timeout (seconds) |
## Defining Commands
### Basic Command
```python
from myfy.commands import cli
@cli.command()
async def hello():
'''Say hello.'''
print("Hello, World!")
# Run: myfy app hello
```
### With DI Injection
Services are automatically injected:
```python
from myfy.commands import cli
from myfy.data import AsyncSession
@cli.command()
async def count_users(session: AsyncSession):
'''Count users in the database.'''
result = await session.execute(select(func.count(User.id)))
count = result.scalar()
print(f"Total users: {count}")
# Run: myfy app count-users
```
### With Arguments
```python
@cli.command()
async def greet(name: str):
'''Greet someone by name.'''
print(f"Hello, {name}!")
# Run: myfy app greet John
```
### With Options
```python
@cli.command()
async def seed(count: int = 10, verbose: bool = False):
'''Seed the database.'''
for i in range(count):
if verbose:
print(f"Creating user {i + 1}/{count}")
await create_user(i)
print(f"Created {count} users")
# Run: myfy app seed --count 50 --verbose
```
## Command Groups
Organize related commands:
```python
from myfy.commands import cli
# Create a group
db = cli.group("db")
@db.command()
async def seed(session: AsyncSession):
'''Seed the database.'''
await seed_data(session)
@db.command()
async def reset(session: AsyncSession, force: bool = False):
'''Reset the database.'''
if force or confirm("Are you sure?"):
await reset_data(session)
# Run: myfy app db:seed
# myfy app db:reset --force
```
## Typer Integration
Use Typer for advanced CLI features:
```python
import typer
from myfy.commands import cli
@cli.command()
async def import_data(
db: Database, # DI injection
file: str = typer.Argument(..., help="Path to import file"),
dry_run: bool = typer.Option(False, "--dry-run", "-n", help="Simulate import"),
format: str = typer.Option("json", "--format", "-f", help="File format"),
):
'''Import data from a file.'''
if dry_run:
print(f"Would import from {file} ({format} format)")
else:
await db.import_from_file(file, format)
# Run: myfy app import-data users.csv --format csv --dry-run
```
### Typer Features
```python
import typer
@cli.command()
async def deploy(
# Required argument
env: str = typer.Argument(..., help="Target environment"),
# Optional with short form
version: str = typer.Option(None, "--version", "-v"),
# Boolean flag
skip_tests: bool = typer.Option(False, "--skip-tests"),
# Choice from enum
region: Region = typer.Option(Region.US, "--region", "-r"),
):
'''Deploy the application.'''
...
# Run: myfy app deploy production -v 1.2.3 --skip-tests --region eu
```
## Parameter Classification
Parameters are automatically classified:
| Pattern | Classification |
|---------|---------------|
| `typer.Argument(...)` | CLI positional argument |
| `typer.Option(...)` | CLI option/flag |
| Primitive with default | CLI option |
| Primitive without default | CLI argument |
| Complex type | DI dependency |
```python
@cli.command()
async def process(
file: str, # CLI argument (required)
count: int = 10, # CLI option (--count)
verbose: bool = False, # CLI flag (--verbose)
session: AsyncSession, # DI injection
settings: AppSettings, # DI injection
):
...
```
## Custom Command Names
```python
@cli.command(name="import-users") # Explicit name
async def import_users_handler(file: str):
'''Import users from file.'''
...
# Run: myfy app import-users users.csv
```
Function name `import_users_handler` becomes command name `import-users` by default (underscores to hyphens).
## Async vs Sync
Both async and sync handlers are supported:
```python
# Async (recommended)
@cli.command()
async def async_task(session: AsyncSession):
await session.execute(...)
# Sync (also works)
@cli.command()
def sync_task(settings: AppSettings):
print(settings.app_name)
```
## Error Handling
```python
@cli.command()
async def risky_operation(session: AsyncSession):
'''Perform a risky operation.'''
try:
await do_risky_thing(session)
except RiskyError as e:
print(f"Error: {e}", file=sys.stderr)
raise typer.Exit(1)
```
## Progress and Output
```python
import typer
@cli.command()
async def process_files(files: list[str]):
'''Process multiple files.'''
with typer.progressbar(files) as progress:
for file in progress:
await process_file(file)
typer.echo(typer.style("Done!", fg=typer.colors.GREEN))
```
## Running Commands
```bash
# List available commands
myfy app --help
# Run a command
myfy app seed-users
# With options
myfy app seed-users --count 50
# Grouped command
myfy app db:reset --force
# With arguments
myfy app import users.csv
```
## Best Practices
1. **Use docstrings** - Become command help text
2. **Group related commands** - Easier to discover
3. **Use Typer for complex args** - Better help messages
4. **Handle errors gracefully** - Use `typer.Exit(1)` for failures
5. **Show progress** - Use `typer.progressbar` for long operations
6. **Inject services** - Don't create DB connections manually
7. **Keep commands focused** - One task per command