Command Syntax

firestone generate [COMMON_OPTIONS] cli [CLI_OPTIONS]

Basic Usage

Single File Output

Generate a single Python file containing the entire CLI:

firestone generate \
  --title "My API" \
  --description "My API description" \
  --version 1.0 \
  --resources resource.yaml \
  cli \
  --pkg myapi \
  --client-pkg myapi.client \
  --output cli.py

This creates cli.py - a standalone CLI script.

Module Output

Generate separate module files for each resource:

firestone generate \
  --title "My API" \
  --description "My API description" \
  --version 1.0 \
  --resources persons.yaml addressbook.yaml \
  cli \
  --pkg myapi \
  --client-pkg myapi.client \
  --as-modules \
  --output-dir myapi/cli/

This creates:

myapi/cli/
├── persons.py
└── addressbook.py

Common Options

These options apply to all firestone generate commands:

--title (required)

The title of your API/CLI:

--title "Task Manager API"

Used in:

  • CLI help text
  • Main command docstring
  • Generated code comments

--description (required)

Description of your API/CLI:

--description "Manage tasks and projects"

Appears in the main CLI help page.

--version (required)

Version number for your API:

--version 1.0
# or
--version 2.1.3

--resources (required)

One or more resource YAML files:

# Single resource
--resources tasks.yaml

# Multiple resources
--resources tasks.yaml projects.yaml users.yaml

Firestone processes each resource and generates CLI commands for all of them.

--summary (optional)

Short summary (defaults to description if not provided):

--summary "Task management"

CLI-Specific Options

--pkg (required)

The Python package name where your application code lives:

--pkg taskmanager

This determines import statements in the generated code:

from taskmanager import ...

--client-pkg (required)

The package where OpenAPI-generated client code is located:

--client-pkg taskmanager.client

Used for importing API client classes:

from taskmanager.client import api_client
from taskmanager.client import configuration
from taskmanager.client.api import tasks_api

Important: This should point to code generated by openapi-generator or a similar tool.

--output (optional)

Output file path (defaults to stdout):

# Write to file
--output mycli.py

# Write to stdout (default)
--output -

# Redirect stdout to file
firestone generate ... cli ... > mycli.py

--output-dir (required with --as-modules)

Directory for generated module files:

--as-modules \
--output-dir myapi/cli/

Creates one .py file per resource in the specified directory.

--as-modules (flag)

Generate separate module files instead of one monolithic file:

--as-modules

Without --as-modules (default):

cli.py  # All resources in one file

With --as-modules:

cli/
├── tasks.py
├── projects.py
└── users.py

When to use:

  • Single file: Simple APIs with 1-3 resources
  • Modules: Complex APIs with many resources, better organization

--template (optional)

Path to custom Jinja2 template:

--template custom_cli.jinja2

See Customization for details on custom templates.

Complete Examples

Simple CLI

firestone generate \
  --title "Todo API" \
  --description "Manage your todos" \
  --version 1.0 \
  --resources todos.yaml \
  cli \
  --pkg todoapi \
  --client-pkg todoapi.client \
  --output todo_cli.py

Multi-Resource CLI

firestone generate \
  --title "CRM API" \
  --description "Customer relationship management" \
  --version 2.0 \
  --resources \
    customers.yaml \
    orders.yaml \
    products.yaml \
  cli \
  --pkg crm \
  --client-pkg crm.client \
  --output crm_cli.py

Modular CLI Structure

firestone generate \
  --title "E-commerce API" \
  --description "Complete e-commerce platform" \
  --version 1.5.0 \
  --resources \
    users.yaml \
    products.yaml \
    orders.yaml \
    payments.yaml \
  cli \
  --pkg ecommerce \
  --client-pkg ecommerce.client \
  --as-modules \
  --output-dir ecommerce/cli/

With Custom Template

firestone generate \
  --title "Custom CLI" \
  --description "CLI with custom formatting" \
  --version 1.0 \
  --resources resource.yaml \
  cli \
  --pkg myapp \
  --client-pkg myapp.client \
  --template templates/custom_cli.jinja2 \
  --output custom_cli.py

Generated Output

Single File Structure

#!/usr/bin/env python
"""
Main entry point for a click based CLI.
"""
import click
from myapi.client import api_client
from myapi.client.api import tasks_api

@click.group()
@click.option("--api-url", envvar="API_URL")
def main(api_url):
    """My API

    My API description
    """
    # Setup configuration
    pass

@main.group()
async def tasks(ctx_obj):
    """High level command for tasks."""
    # Initialize API client
    pass

@tasks.command("list")
async def tasks_get(ctx_obj):
    """List all tasks"""
    # API call
    pass

# ... more commands ...

if __name__ == "__main__":
    main()

Module Structure

Each module (tasks.py, projects.py, etc.) exports an init() function:

# tasks.py
def init():
    """Initialize tasks resource CLI."""

    @click.group()
    async def tasks(ctx_obj):
        """High level command for tasks."""
        pass

    @tasks.command("list")
    async def tasks_list(ctx_obj):
        """List all tasks"""
        pass

    return tasks

You then import and register these in your main CLI:

# main.py
import click
from myapi.cli import tasks
from myapi.cli import projects

@click.group()
def main():
    pass

tasks_cli = tasks.init()
projects_cli = projects.init()
main.add_command(tasks_cli)
main.add_command(projects_cli)

Using the Generated CLI

Make It Executable

chmod +x cli.py

Run Directly

# Using python
python cli.py --help

# As executable
./cli.py --help

Install as Console Script

Add to your pyproject.toml:

[tool.poetry.scripts]
mycli = "myapi.cli:main"

Or setup.py:

setup(
    entry_points={
        'console_scripts': [
            'mycli=myapi.cli:main',
        ],
    }
)

Then install:

poetry install
# Now 'mycli' is available in your PATH
mycli --help

Workflow Integration

1. Define Resources

# tasks.yaml
kind: tasks
apiVersion: v1
# ... schema ...

2. Generate OpenAPI Spec

firestone generate \
  --title "Task API" \
  --description "Manage tasks" \
  --version 1.0 \
  --resources tasks.yaml \
  openapi \
  --output openapi.yaml

3. Generate Client Library

openapi-generator generate \
  -i openapi.yaml \
  -g python \
  -o taskapi/client/

4. Generate CLI

firestone generate \
  --title "Task API" \
  --description "Manage tasks" \
  --version 1.0 \
  --resources tasks.yaml \
  cli \
  --pkg taskapi \
  --client-pkg taskapi.client \
  --output taskapi/cli.py

5. Use CLI

python taskapi/cli.py --api-url https://api.example.com tasks list

Common Patterns

Development vs Production

# Development - stdout for quick testing
firestone generate ... cli ... --output -

# Production - file output
firestone generate ... cli ... --output production_cli.py

Makefile Integration

.PHONY: gen-cli
gen-cli:
	firestone generate \
	  --title "$(APP_TITLE)" \
	  --description "$(APP_DESC)" \
	  --version $(APP_VERSION) \
	  --resources $(RESOURCES) \
	  cli \
	  --pkg $(PKG_NAME) \
	  --client-pkg $(PKG_NAME).client \
	  --output $(OUTPUT_FILE)

Usage:

make gen-cli \
  APP_TITLE="My API" \
  APP_DESC="Description" \
  APP_VERSION=1.0 \
  RESOURCES="tasks.yaml" \
  PKG_NAME="myapi" \
  OUTPUT_FILE="cli.py"

Next Steps