Agent Skills: FastAPI Sweetener Skill

Add FastAPI server capabilities to an existing Python project with uvicorn, OpenAPI docs, and configuration management

UncategorizedID: pborenstein/plinth/fastapi-sweetener

Install this agent skill to your local

pnpm dlx add-skill https://github.com/pborenstein/plinth/tree/HEAD/skills/fastapi-sweetener

Skill Files

Browse the full folder contents for fastapi-sweetener.

Download Skill

Loading file tree…

skills/fastapi-sweetener/SKILL.md

Skill Metadata

Name
fastapi-sweetener
Description
Add FastAPI server capabilities to an existing Python project with uvicorn, OpenAPI docs, and configuration management

FastAPI Sweetener Skill

Add FastAPI server capabilities to an existing Python project, integrating as a CLI subcommand alongside existing functionality.

Prerequisites

This skill assumes you already have a Python project (typically created with /plinth:python-project-init) with:

  • Existing pyproject.toml
  • Package directory with __init__.py
  • Existing CLI (typically cli.py)

What This Skill Adds

Adds FastAPI server capabilities to your existing project:

  • FastAPI server with OpenAPI docs (/docs, /redoc)
  • CLI subcommand - {package} server to start the API
  • Configuration management (JSON/YAML config files)
  • CORS middleware for web clients
  • Lifespan management for startup/shutdown
  • Dependencies - adds fastapi, uvicorn, click to pyproject.toml

Files Added/Modified

New files:

  • {package}/server.py - FastAPI application
  • {package}/config.py - Configuration management
  • config.example.json - Example configuration
  • .env.example - Environment variable template

Modified files:

  • {package}/cli.py - Adds server subcommand (converts to Click if needed)
  • pyproject.toml - Adds dependencies (fastapi, uvicorn, click, pyyaml)

Implementation Steps

Step 1: Detect Project Structure

Use Glob and Read to discover:

  1. Find pyproject.toml in current directory
  2. Extract project.name and package name from pyproject.toml
  3. Locate package directory (usually {package}/ or src/{package}/)
  4. Find existing CLI file (usually cli.py)
  5. Read __init__.py or __version__.py to get description

If unable to detect structure, ask user for:

  • PACKAGE_NAME
  • PROJECT_NAME

Step 2: Check for Existing Server

Check if server already exists:

ls {package}/server.py

If it exists, ask user if they want to overwrite it.

Step 3: Gather Configuration

Ask user for (use AskUserQuestion if needed):

Optional parameters (with defaults):

  1. SERVER_HOST (string) - Default: "0.0.0.0"

    • Host to bind server to
  2. SERVER_PORT (integer) - Default: 8000

    • Port to bind server to

Step 4: Add Server Files

Create the following files from templates in skills/fastapi-sweetener/assets/:

{package}/server.py - FastAPI application:

  • Read assets/server.py.template
  • Replace template variables
  • Write to {package}/server.py

{package}/config.py - Configuration management:

  • Read assets/config.py.template
  • Replace template variables
  • Write to {package}/config.py

config.example.json - Example config:

  • Read assets/config.example.json.template
  • Replace SERVER_HOST and SERVER_PORT
  • Write to project root config.example.json

.env.example - Environment template:

  • Read assets/.env.example.template
  • Write to project root .env.example

Step 5: Update CLI to Add Server Subcommand

This is the most critical step. The CLI needs to support subcommands.

If cli.py uses Click:

Add a new @main.command() for the server:

@main.command()
@click.option('--host', default=None, help='Server host (default: from config)')
@click.option('--port', default=None, type=int, help='Server port (default: from config)')
@click.option('--reload', is_flag=True, help='Enable auto-reload for development')
@click.option('--log-level', default='info',
              type=click.Choice(['critical', 'error', 'warning', 'info', 'debug']),
              help='Logging level')
def server(host, port, reload, log_level):
    """Start the FastAPI server.

    This starts the HTTP server that provides the API.
    The server will be accessible via http://HOST:PORT
    """
    import uvicorn
    from .config import Config

    config = Config()

    # Override config with CLI options if provided
    server_host = host or config.server_host
    server_port = port or config.server_port

    print(f"Starting server at http://{server_host}:{server_port}")
    print(f"OpenAPI docs: http://{server_host}:{server_port}/docs")

    uvicorn.run(
        "{{PACKAGE_NAME}}.server:app",
        host=server_host,
        port=server_port,
        reload=reload,
        log_level=log_level
    )

If cli.py uses argparse:

Convert to Click. This is a significant change but necessary for subcommands:

  1. Read existing cli.py
  2. Identify the main() function
  3. Rewrite to use Click groups:
    • Convert ArgumentParser() to @click.group()
    • Convert existing logic to @main.command() named appropriately
    • Add the server subcommand as shown above
  4. Use Edit tool to update the file

Step 6: Update pyproject.toml Dependencies

Add required dependencies to pyproject.toml:

Use Edit tool to add to the dependencies array:

dependencies = [
    # ... existing deps ...
    "fastapi>=0.104.0",
    "uvicorn[standard]>=0.24.0",
    "click>=8.0",
    "pyyaml>=6.0",
]

Step 7: Install Dependencies

Run uv sync to install new dependencies:

uv sync

Step 8: Create Config File

Guide user to create config from example:

cp config.example.json config.json

Step 9: Verification & Next Steps

Provide verification commands:

# Verify CLI still works
uv run {package} --version

# Start development server
uv run {package} server --reload

# Open in browser
open http://localhost:{port}/docs

Tell user:

  1. Server added as {package} server subcommand
  2. Configure via config.json (copy from config.example.json)
  3. Add API endpoints to {package}/server.py
  4. OpenAPI docs available at /docs and /redoc
  5. Use /plinth:macos-launchd-service to set up auto-start

Template Variable Reference

| Variable | Example | Source | |----------|---------|--------| | {{PROJECT_NAME}} | "Temoa" | From pyproject.toml or user input | | {{PACKAGE_NAME}} | "temoa" | Detected from directory structure | | {{PACKAGE_NAME_UPPER}} | "TEMOA" | Derived from PACKAGE_NAME | | {{DESCRIPTION}} | "Semantic search" | From init.py or user input | | {{SERVER_HOST}} | "0.0.0.0" | User input or default | | {{SERVER_PORT}} | "8000" | User input or default |

Example Execution

User request: "Add FastAPI to my CLI project"

Detected:

  • PROJECT_NAME: "MyProject" (from pyproject.toml)
  • PACKAGE_NAME: "myproject" (from directory structure)
  • Existing cli.py with Click

User provides:

  • SERVER_PORT: 8080 (default: 8000)

Result:

Files added:

  • myproject/server.py
  • myproject/config.py
  • config.example.json
  • .env.example

Files modified:

  • myproject/cli.py (added server command)
  • pyproject.toml (added fastapi, uvicorn, etc.)

Usage:

myproject --help          # Shows all subcommands
myproject server          # Starts FastAPI on port 8080
myproject server --reload # Development mode with auto-reload

Idempotency

The skill should be safe to run multiple times:

  • Check if server.py exists before creating
  • Ask user before overwriting existing files
  • Only add dependencies if not already present
  • Don't duplicate CLI commands

Common Issues

CLI Not Using Click

If the existing CLI uses argparse, the skill will convert it to Click. This is necessary for subcommands. The conversion:

  • Preserves existing CLI functionality
  • Moves it to a default command or appropriately named subcommand
  • Adds the server subcommand

Warn the user about this change.

Port Already in Use

If the default port is occupied, user can override:

myproject server --port 8001

Missing Config File

Server requires config.json. If missing:

cp config.example.json config.json

Edit values as needed.

What NOT to Do

  • Don't create this from scratch - requires existing project
  • Don't skip the CLI conversion if needed - subcommands require Click
  • Don't overwrite server.py without asking
  • Don't add emojis to any files
  • Don't run python directly - always use uv run
  • Don't modify README.md or documentation files (user does this)

Post-Addition Customization

After adding FastAPI, users typically:

  1. Edit config.json with their specific configuration
  2. Add API endpoints to server.py
  3. Update tests to include API endpoint tests
  4. Set up launchd service using /plinth:macos-launchd-service
  5. Document API endpoints in README.md

Integration with Other Skills

Works well with:

  • /plinth:python-project-init - Creates the base project first
  • /plinth:macos-launchd-service - Auto-start the server
  • /plinth:session-wrapup - Document the addition