Overview

The firestone ecosystem includes two separate but related packages:

  • firestoned - The command-line tool (CLI)
  • firestone-lib - The programmatic library

This guide explains the differences, when to use each, and how they relate.

Package Names vs Module Names

First, let's clarify the naming:

The 'd' Suffix Situation

Installation names:

pip install firestoned      # CLI tool
pip install firestone-lib   # Library

Why "firestoned"? The name firestone was already taken on PyPI (though essentially unused). The firestone project publishes the CLI as firestoned with a 'd' suffix.

Import names:

# After installing 'firestoned', import as:
import firestone

# After installing 'firestone-lib', import as:
import firestone_lib

Command-line usage:

# Both packages installed, command is:
firestone generate --resources book.yaml openapi
# No 'd' in the command

firestone (CLI Tool)

What It Is

A command-line application for generating specs and code from the terminal.

Installation

# With Poetry (recommended)
poetry add firestoned

# With pip
pip install firestoned

Usage

# Run commands from terminal
firestone generate --resources book.yaml openapi > spec.yaml
firestone generate --resources book.yaml cli > cli.py
firestone --version
firestone --help

Key Features

1. Terminal-First Interface

  • Designed for shell usage
  • Pipes output to stdout or files
  • Integrates with Unix tools

2. Built-in UI Server

  • Launches Swagger UI for testing
  • Quick visualization of specs
firestone generate --resources book.yaml openapi --ui-server
# Opens browser at http://127.0.0.1:5000/apidocs

3. Simple Workflow

  • No programming required
  • Direct file-to-file transformation
  • Perfect for scripts and automation

4. Multiple Output Formats

  • OpenAPI, AsyncAPI, CLI, Streamlit
  • Output to stdout or files

Use Cases

Use the CLI when:

  • Generating specs during development

    firestone generate --resources *.yaml openapi > openapi.yaml
    
  • Building CI/CD pipelines

    # .github/workflows/generate.yml
    - name: Generate OpenAPI spec
      run: |
        poetry run firestone generate \
          --resources resources/*.yaml \
          openapi > openapi.yaml
    
  • One-off code generation

    firestone generate --resources user.yaml cli > user_cli.py
    
  • Quick prototyping

    firestone generate --resources proto.yaml openapi --ui-server
    
  • Shell scripting

    #!/bin/bash
    for resource in resources/*.yaml; do
      name=$(basename "$resource" .yaml)
      firestone generate --resources "$resource" \
        openapi > "specs/${name}.yaml"
    done
    

Advantages

  • Zero code - Just run commands
  • Fast - Quick iterations
  • Scriptable - Easy automation
  • Self-contained - Everything in one tool

Limitations

  • Less flexible - Command-line options only
  • No programmatic control - Can't customize mid-generation
  • Limited integration - Harder to embed in applications

firestone-lib (Library)

What It Is

A Python library providing programmatic access to firestone's generation capabilities.

Installation

# With Poetry (recommended)
poetry add firestone-lib

# With pip
pip install firestone-lib

Usage

import yaml
from firestone_lib.spec import openapi, asyncapi, cli

# Load resource data
with open('book.yaml') as f:
    resource_data = [yaml.safe_load(f)]

# Generate OpenAPI spec programmatically
openapi_spec = openapi.generate(
    rsrc_data=resource_data,
    title='Library API',
    desc='API for managing books',
    summary='Book management',
    version='1.0.0'
)

print(openapi_spec)  # YAML string

# Generate AsyncAPI spec
asyncapi_spec = asyncapi.generate(
    rsrc_data=resource_data,
    title='Library Events',
    desc='WebSocket events',
    summary='Real-time book updates',
    version='1.0.0'
)

# Generate CLI code
cli_code = cli.generate(
    pkg='library',
    client_pkg='library.client',
    rsrc_data=resource_data,
    title='Library CLI',
    desc='Command-line interface',
    summary='CLI tool',
    version='1.0.0'
)

Key Features

1. Programmatic API

  • Full Python access to generation
  • Customize behavior with code
  • Integrate into applications

2. Embeddable

  • Use in web apps, tools, frameworks
  • Build custom workflows
  • Extend functionality

3. Flexible

  • Modify resources before generation
  • Transform outputs after generation
  • Build complex pipelines

4. Reusable

  • Create libraries on top of firestone
  • Share generation logic
  • Build frameworks

Use Cases

Use the library when:

  • Embedding in applications

    # Flask app that generates specs on-demand
    from flask import Flask, request, jsonify
    from firestone_lib.spec import openapi
    import yaml
    
    app = Flask(__name__)
    
    @app.route('/generate', methods=['POST'])
    def generate_spec():
        resource_yaml = request.data.decode('utf-8')
        resource = yaml.safe_load(resource_yaml)
        spec = openapi.generate(
            rsrc_data=[resource],
            title=request.args.get('title'),
            version='1.0.0'
        )
        return spec, 200, {'Content-Type': 'application/yaml'}
    
  • Building custom tools

    # Tool that validates and generates in one step
    class ResourceValidator:
        def __init__(self, schema_path):
            self.schema = load_json_schema(schema_path)
    
        def validate_and_generate(self, resource_file):
            with open(resource_file) as f:
                resource = yaml.safe_load(f)
    
            # Custom validation
            self.validate(resource)
    
            # Generate if valid
            return openapi.generate(
                rsrc_data=[resource],
                title=resource['kind'],
                version=resource['apiVersion']
            )
    
  • Dynamic resource generation

    # Generate resources from database schema
    def generate_from_db_schema(table_name):
        # Query database schema
        columns = get_table_columns(table_name)
    
        # Build resource definition
        resource = {
            'kind': table_name,
            'apiVersion': 'v1',
            'schema': {
                'type': 'array',
                'key': {'name': 'id', 'schema': {'type': 'integer'}},
                'items': {
                    'type': 'object',
                    'properties': {
                        col.name: {'type': map_db_type(col.type)}
                        for col in columns
                    }
                }
            }
        }
    
        # Generate OpenAPI spec
        return openapi.generate(
            rsrc_data=[resource],
            title=f"{table_name.title()} API",
            version='1.0.0'
        )
    
  • Custom templates

    # Use custom Jinja2 template
    from jinja2 import Environment, FileSystemLoader
    
    def generate_with_custom_template(resource, template_path):
        # Load resource
        with open(resource) as f:
            resource_data = [yaml.safe_load(f)]
    
        # Custom template environment
        env = Environment(loader=FileSystemLoader('.'))
        template = env.get_template(template_path)
    
        # Generate with custom context
        return template.render(
            resources=resource_data,
            custom_field='custom_value'
        )
    
  • Complex workflows

    # Multi-stage generation pipeline
    def build_api_package(resource_files, output_dir):
        # Stage 1: Load all resources
        resources = []
        for rf in resource_files:
            with open(rf) as f:
                resources.append(yaml.safe_load(f))
    
        # Stage 2: Generate OpenAPI
        openapi_spec = openapi.generate(
            rsrc_data=resources,
            title='Multi-Resource API',
            version='1.0.0'
        )
    
        # Stage 3: Write to file
        with open(f'{output_dir}/openapi.yaml', 'w') as f:
            f.write(openapi_spec)
    
        # Stage 4: Generate client SDK
        subprocess.run([
            'openapi-generator', 'generate',
            '-i', f'{output_dir}/openapi.yaml',
            '-g', 'python',
            '-o', f'{output_dir}/client'
        ])
    
        # Stage 5: Generate CLI
        cli_code = cli.generate(
            pkg='api',
            client_pkg='api.client',
            rsrc_data=resources,
            title='API CLI',
            version='1.0.0'
        )
    
        with open(f'{output_dir}/cli.py', 'w') as f:
            f.write(cli_code)
    
        return output_dir
    

Advantages

  • Programmable - Full Python control
  • Flexible - Customize everything
  • Embeddable - Use in any Python app
  • Extensible - Build on top of it

Limitations

  • Requires programming - Not for non-coders
  • More complex - Need to write code
  • Dependencies - Manage as a library

Side-by-Side Comparison

Featurefirestone (CLI)firestone-lib (Library)
Installationpip install firestonedpip install firestone-lib
UsageCommand linePython code
Skill RequiredBasic shellPython programming
Primary UseGeneration tasksEmbedded generation
FlexibilityCommand optionsFull programmatic control
IntegrationShell scripts, CI/CDApplications, tools, frameworks
CustomizationLimited to flagsUnlimited with code
Learning CurveLowMedium
OutputStdout or filesPython strings
TemplatesFile-basedFile or programmatic
Best ForQuick generationComplex workflows

When to Use Both

Many projects use both packages for different purposes:

Example Workflow

Development (CLI):

# Quick iteration during development
poetry run firestone generate --resources book.yaml openapi --ui-server

CI/CD (CLI):

# .github/workflows/specs.yml
- name: Generate specs
  run: |
    poetry run firestone generate \
      --resources resources/*.yaml \
      openapi > openapi.yaml

Production Application (Library):

# app.py - Generate specs dynamically
from firestone_lib.spec import openapi

@app.route('/api/schema/<resource>')
def get_resource_schema(resource):
    resource_def = load_resource(resource)
    spec = openapi.generate(
        rsrc_data=[resource_def],
        title=f"{resource} API",
        version='1.0.0'
    )
    return spec

Choosing Between Them

Use firestone (CLI) if you:

  • ✅ Want to generate specs from the command line
  • ✅ Are building CI/CD pipelines
  • ✅ Prefer declarative, file-based workflows
  • ✅ Don't need programmatic customization
  • ✅ Want quick, one-off generation

Use firestone-lib if you:

  • ✅ Need to embed generation in Python applications
  • ✅ Want programmatic control over generation
  • ✅ Are building tools or frameworks
  • ✅ Need dynamic or conditional generation
  • ✅ Want to extend firestone's capabilities

Use both if you:

  • ✅ Develop locally with CLI, deploy with library
  • ✅ Use CLI in CI/CD, library in production
  • ✅ Want flexibility across different contexts

Installation Together

Both can be installed side-by-side:

# Install both
poetry add firestoned firestone-lib

# Use CLI
poetry run firestone generate --resources book.yaml openapi

# Use library in Python scripts
python my_generator.py

They don't conflict and can be used together in the same project.

Migration Between Them

From CLI to Library

If you outgrow the CLI:

Before (CLI):

firestone generate --resources book.yaml openapi > openapi.yaml

After (Library):

from firestone_lib.spec import openapi
import yaml

with open('book.yaml') as f:
    resource = yaml.safe_load(f)

spec = openapi.generate(
    rsrc_data=[resource],
    title='Book API',
    version='1.0.0'
)

with open('openapi.yaml', 'w') as f:
    f.write(spec)

From Library to CLI

If you want simpler workflows:

Before (Library):

spec = openapi.generate(...)
with open('openapi.yaml', 'w') as f:
    f.write(spec)

After (CLI):

firestone generate --resources book.yaml openapi > openapi.yaml

Documentation and Support

CLI Documentation:

  • Command-line help: firestone --help
  • This documentation site
  • Examples in the repo

Library Documentation:

  • API docs (autodoc)
  • Source code
  • This documentation site

Next Steps

Now that you understand the difference: