diff --git a/README.md b/README.md index 1aefe47..1a74b55 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,55 @@ # dspy-cli -A command-line interface tool for creating and serving DSPy projects, inspired by Ruby on Rails. +Deploy DSPy programs as HTTP APIs with standard containerization, routing, and OpenAPI specifications. Setup time: 3-5 minutes. -## Installation +**For:** Developers embedding AI features in existing applications (Chrome extensions, Notion automations, web apps) who need HTTP endpoints without manual infrastructure work. -```bash -uv add dspy-cli -``` - -### Installing for Development/Testing - -If you're testing or developing dspy-cli itself: +**Problem:** Prototype DSPy modules work locally but require Docker configs, API boilerplate, and route management to deploy. This creates friction between development and production. -```bash -# Clone or navigate to the dspy-cli repository -cd /path/to/dspy-cli - -# Sync dependencies -uv sync --extra dev - -# Now the dspy-cli command is available -dspy-cli --help -``` +**Solution:** Convention-based project structure with auto-discovery. Define signatures, implement modules, deploy. Infrastructure handled automatically. ## Quick Start -### Create a new DSPy project - ```bash -dspy-cli new my-project -cd my-project -``` +# Install +uv tool install dspy-cli -### Create a project with a custom program name +# Create project +dspy-cli new blog-tagger -s "post -> tags: list[str]" +cd blog-tagger -```bash -dspy-cli new my-project -p custom_program +# Serve locally +dspy-cli serve ``` -### Create a project with a custom signature +Test the endpoint: ```bash -dspy-cli new blog-tagger -s "post -> tags: list[str]" +curl -X POST http://localhost:8000/BlogTaggerPredict \ + -H "Content-Type: application/json" \ + -d '{"post": "How to build Chrome extensions with AI..."}' ``` -### Serve your DSPy programs as an API +Response: -```bash -dspy-cli serve --port 8000 --host 0.0.0.0 +```json +{ + "tags": ["chrome-extensions", "ai", "development", "javascript"] +} ``` ## Features -- **Project scaffolding**: Generate a complete DSPy project structure with boilerplate code -- **Code generation**: Quickly scaffold new DSPy programs with signatures and modules using Rails-style generators -- **Convention over configuration**: Organized directory structure for modules, signatures, optimizers, and metrics -- **HTTP API server**: Automatically serve your DSPy programs as REST endpoints -- **Flexible configuration**: YAML-based model configuration with environment variable support -- **Logging**: Request logging to both STDOUT and per-module log files +- **Auto-discovery** - Modules in `src/*/modules/` automatically exposed as HTTP endpoints +- **Standard containers** - Docker image generation with FastAPI server included +- **OpenAPI specs** - Auto-generated from DSPy signatures for integration with tools and clients +- **Hot reload** - Edit modules without restarting the development server +- **Model configuration** - Switch LLMs via config file without code changes +- **MCP tool integration** - Served programs work as MCP tools for AI assistants +- **Convention-based structure** - Organized directories for modules, signatures, optimizers, metrics ## Project Structure -When you create a new project, dspy-cli generates the following structure: - ``` my-project/ ├── pyproject.toml @@ -84,85 +71,51 @@ my-project/ ## Commands -### `new` - -Create a new DSPy project with boilerplate structure. +### Create Project ```bash -dspy-cli new [PROJECT_NAME] [OPTIONS] +dspy-cli new PROJECT_NAME [OPTIONS] ``` -**Options:** -- `-p, --program-name TEXT`: Name of the initial program (default: converts project name) -- `-s, --signature TEXT`: Inline signature string (e.g., `"question -> answer"` or `"post -> tags: list[str]"`) +Options: +- `-s, --signature TEXT` - Inline signature (e.g., `"question -> answer"`) +- `-p, --program-name TEXT` - Initial program name -**Examples:** - -```bash -# Basic project -dspy-cli new my-project - -# With custom program name -dspy-cli new my-project -p custom_program - -# With custom signature -dspy-cli new blog-tagger -s "post -> tags: list[str]" - -# With both program name and signature -dspy-cli new analyzer -p text_analyzer -s "text, context: list[str] -> summary, sentiment: bool" -``` - -### `generate` (alias: `g`) - -Generate new components in an existing DSPy project. +### Generate Components ```bash dspy-cli generate scaffold PROGRAM_NAME [OPTIONS] -dspy-cli g scaffold PROGRAM_NAME [OPTIONS] ``` -**Options:** -- `-m, --module TEXT`: DSPy module type to use (default: Predict) - - Available: `Predict`, `ChainOfThought` (or `CoT`), `ProgramOfThought` (or `PoT`), `ReAct`, `MultiChainComparison`, `Refine` -- `-s, --signature TEXT`: Inline signature string (e.g., `"question -> answer"`) +Options: +- `-m, --module TEXT` - Module type (`Predict`, `ChainOfThought`, `ReAct`) +- `-s, --signature TEXT` - Inline signature (e.g. "question -> answer") -**Examples:** +### Serve Locally ```bash -# Basic scaffold with default Predict module -dspy-cli g scaffold categorizer - -# Scaffold with ChainOfThought -dspy-cli g scaffold categorizer -m CoT - -# Scaffold with custom signature -dspy-cli g scaffold qa -m CoT -s "question -> answer" - -# Complex signature with types -dspy-cli g scaffold search -s "query, context: list[str] -> answer, confidence: float" +dspy-cli serve [--port PORT] [--host HOST] ``` -### `serve` +Auto-generated endpoints: +- `GET /programs` - List all programs with schemas +- `POST /{program}` - Execute program with JSON payload -Start an HTTP API server that exposes your DSPy programs. +### Deploy ```bash -dspy-cli serve [OPTIONS] +flyctl launch +flyctl secrets set OPENAI_API_KEY=your-key-here +flyctl deploy ``` -**Options:** -- `--port INTEGER`: Port to run the server on (default: 8000) -- `--host TEXT`: Host to bind to (default: 0.0.0.0) - -**Endpoints:** -- `GET /programs`: List all discovered programs with their schemas -- `POST /{program}`: Execute a program with JSON payload +See [Deployment Guide](docs/deployment.md) for detailed instructions and other platforms. ## Configuration -### dspy.config.yaml +### Model Settings -Configure your language models and routing: +`dspy.config.yaml`: ```yaml models: @@ -174,25 +127,91 @@ models: max_tokens: 16000 temperature: 1.0 model_type: chat - anthropic:sonnet-4-5: - model: anthropic/claude-sonnet-4-5 - env: ANTHROPIC_API_KEY - model_type: chat -# Optional: per-program model overrides +# Per-program overrides program_models: MySpecialProgram: anthropic:sonnet-4-5 ``` -### .env +### Environment Variables -Store your API keys and secrets: +`.env`: ``` OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... ``` +See [Configuration Guide](docs/configuration.md) for complete settings reference. + +## Integration Examples + +### Chrome Extension + +```javascript +async function summarizePage(content) { + const response = await fetch('https://your-app.fly.dev/summarizer', { + method: 'POST', + body: JSON.stringify({ content }), + headers: { 'Content-Type': 'application/json' } + }); + return response.json(); +} +``` + +### Python Client + +```python +import requests + +def tag_content(page_content): + response = requests.post( + 'https://your-app.fly.dev/BlogTaggerPredict', + json={'post': page_content} + ) + return response.json()['tags'] +``` + +### JavaScript/TypeScript + +```javascript +fetch('https://your-app.fly.dev/analyzer', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + text: document.body.innerText, + context: ['documentation', 'technical'] + }) +}) +.then(res => res.json()) +.then(data => console.log(data.summary, data.sentiment)); +``` + +## Development Installation + +For contributing or testing dspy-cli itself: + +```bash +cd /path/to/dspy-cli +uv sync --extra dev +dspy-cli --help +``` + +Run tests: + +```bash +cd dspy-cli +uv run pytest +``` + +## Next Steps + +- [Architecture Overview](docs/architecture.md) - Project structure and design decisions +- [CLI Reference](docs/cli-reference.md) - Complete command documentation +- [Configuration Guide](docs/configuration.md) - Model settings and environment variables +- [Deployment Guide](docs/deployment.md) - Production deployment workflows +- [MCP Integration](docs/mcp-integration.md) - Using with AI assistants + ## License MIT diff --git a/docs/commands/new.md b/docs/commands/new.md index df7d4d3..5adad2e 100644 --- a/docs/commands/new.md +++ b/docs/commands/new.md @@ -1,71 +1,255 @@ # dspy-cli new -Create a new DSPy project — scaffolds structure, dependencies, and sample program so you start coding immediately. +Create a new DSPy project with standard directory structure. -## Usage +## Synopsis ```bash -dspy-cli new PROJECT_NAME [OPTIONS] +dspy-cli new [OPTIONS] ``` -## What Happens +## Usage ```bash -$ dspy-cli new test-project -Creating new DSPy project: test-project - Package name: test_project - Initial program: test_project - - Created: test-project/src/test_project - Created: test-project/src/test_project/modules - Created: test-project/src/test_project/signatures - Created: test-project/src/test_project/optimizers - Created: test-project/src/test_project/metrics - Created: test-project/pyproject.toml - Created: test-project/dspy.config.yaml - Created: test-project/Dockerfile - Created: test-project/.env - Created: test-project/.gitignore - Created: test-project/README.md - ... - Created: test_project/signatures/test_project.py - Created: test_project/modules/test_project_predict.py - Created: tests/test_modules.py - Initialized git repository -✓ Project created successfully! +# Create project with default signature +dspy-cli new my-feature + +# Create project with custom signature +dspy-cli new email-summarizer -s "email: str -> summary: str, key_points: list[str]" + +# Specify program name +dspy-cli new notion-tools -p emoji_picker -s "context: str -> emoji: str" ``` +## Description + +Creates a new project with standard directory layout, dependency configuration, and initial DSPy module. Generates `modules/`, `signatures/`, `optimizers/`, `metrics/`, and `utils/` directories along with configuration files (`pyproject.toml`, `dspy.config.yaml`, `Dockerfile`, `.env`). + +The initial module is created based on the provided signature (or a default `question -> answer` signature if none is specified). + ## Options -- `--program-name`, `-p` - Initial program name -- `--signature`, `-s` - Inline signature (e.g., "question -> answer") +| Option | Short | Default | Description | +|--------|-------|---------|-------------| +| `--program-name` | `-p` | Derived from project name | Name of initial program module | +| `--signature` | `-s` | `question -> answer` | Input/output signature defining the program interface | + +## Arguments + +- `PROJECT_NAME` - Name of the project directory to create (required) + +## Generated Structure + +``` +my-feature/ +├── src/ +│ └── my_feature/ +│ ├── modules/ # DSPy program implementations +│ ├── signatures/ # Input/output type definitions +│ ├── optimizers/ # Optimization workflows +│ ├── metrics/ # Evaluation functions +│ └── utils/ # Shared utilities +├── data/ # Training examples and datasets +├── logs/ # Request/response logs +├── tests/ # Test files +├── pyproject.toml # Python dependencies +├── dspy.config.yaml # Model configuration +├── Dockerfile # Container definition +└── .env # Environment variables +``` + +### Directory Purposes + +- **modules/** - DSPy program implementations (`dspy.Module` subclasses) +- **signatures/** - Type-safe interfaces defining inputs and outputs +- **optimizers/** - Workflows for improving program performance +- **metrics/** - Functions for measuring program accuracy +- **utils/** - Shared code across modules +- **data/** - Example datasets for training and testing +- **logs/** - Production request/response logs +- **tests/** - Unit and integration tests + +## Signature Syntax + +Signatures define the program interface using `input -> output` format with optional type annotations. + +### Basic Format + +```bash +# Single input, single output +-s "question -> answer" + +# Multiple inputs +-s "context, question -> answer" + +# Multiple outputs +-s "text -> summary, key_points" +``` + +### Type Annotations + +```bash +# String types +-s "text: str -> summary: str" + +# Lists +-s "post: str -> tags: list[str]" + +# Multiple typed outputs +-s "email: str -> summary: str, action_items: list[str], priority: str" +``` + +### Examples + +```bash +# Email summarizer +-s "email: str -> summary: str, key_points: list[str]" + +# Content classifier +-s "email: str, user_context: str -> category: str, confidence: float" + +# Code analyzer +-s "code: str, language: str -> explanation: str, complexity: str" + +# Content moderator +-s "content: str -> is_safe: bool, issues: list[str]" +``` + +## Behavior + +### Module Generation + +The command generates an initial module based on the signature: + +**Command:** +```bash +dspy-cli new emoji-picker -s "context: str -> emoji: str, reasoning: str" +``` + +**Generated signature** (`src/emoji_picker/signatures/emoji_picker_signature.py`): + +```python +import dspy + +class EmojiPickerSignature(dspy.Signature): + context: str = dspy.InputField(desc="") + emoji: str = dspy.OutputField(desc="") +``` + +**Generated module** (`src/emoji_picker/modules/emoji_picker_predict.py`): + +```python +import dspy +from emoji_picker.signatures.emoji_picker_signature import EmojiPickerSignature + +class EmojiPickerPredict(dspy.Module): + def __init__(self): + super().__init__() + self.predictor = dspy.Predict(EmojiPickerSignature) + + def forward(self, context: str) -> dspy.Prediction: + return self.predictor(context=context) +``` + +### Program Naming + +- Without `-p`: Program name derived from project name (`blog-tools` → `blog_tools`) +- With `-p`: Uses specified program name (`-p tagger` → `TaggerPredict`) + +### Dependencies + +`pyproject.toml` includes: +- `dspy-ai` - Core DSPy framework +- `python-dotenv` - Environment variable management +- Development dependencies for testing ## Examples +### Basic Project + ```bash -# Simple: Basic project with default program -dspy-cli new test-project +dspy-cli new my-feature +cd my-feature +uv sync +source .venv/bin/activate +dspy-cli serve +``` -# With signature: Pre-configure input/output fields -dspy-cli new qa-bot -s "question -> answer" -# Output includes: Signature: question -> answer +Creates project with default `question -> answer` signature. Serves at `http://localhost:8000/MyFeaturePredict`. -# Typed outputs: Specify return types for validation -dspy-cli new tagger -s "post -> tags: list[str]" +### Email Summarizer -# Multi-field: Complex inputs and outputs -dspy-cli new analyzer -s "text, context -> sentiment, score: float" +```bash +dspy-cli new email-summarizer -s "email: str -> summary: str, key_points: list[str]" ``` -## Next Steps +Generates: +- Signature: `EmailSummarizerSignature` with `email` input, `summary` and `key_points` outputs +- Module: `EmailSummarizerPredict` +- Endpoint: `/EmailSummarizerPredict` + +### Multi-Input Analyzer ```bash -cd my-project -dspy-cli serve # Start API server at http://localhost:8000 +dspy-cli new code-reviewer -s "code: str, language: str -> issues: list[str], suggestions: str" ``` -Add API keys to `.env`: +Creates module accepting two inputs (`code`, `language`) and returning two outputs (`issues`, `suggestions`). + +### Custom Program Name + ```bash -OPENAI_API_KEY=sk-... -ANTHROPIC_API_KEY=sk-ant-... +dspy-cli new blog-tools -p tagger -s "blog_post: str -> tags: list[str]" ``` + +Project named `blog-tools`, initial program named `TaggerPredict`. Additional programs can be added to `modules/` later. + +## Next Steps + +After creating a project: + +1. **Configure API keys** - Edit `.env`: + ```bash + OPENAI_API_KEY=sk-... + ``` + +2. **Install dependencies:** + ```bash + cd your-project + uv sync + source .venv/bin/activate + ``` + +3. **Customize signature descriptions** - Edit generated signature file: + ```python + class EmojiPickerSignature(dspy.Signature): + """Select appropriate emoji based on context.""" + + context: str = dspy.InputField(desc="Text surrounding emoji location") + emoji: str = dspy.OutputField(desc="Single emoji character") + reasoning: str = dspy.OutputField(desc="Explanation for emoji choice") + ``` + +4. **Start development server:** + ```bash + dspy-cli serve --ui + ``` + +5. **Test the endpoint:** + ```bash + curl -X POST http://localhost:8000/EmojiPickerPredict \ + -H "Content-Type: application/json" \ + -d '{"context": "Great work everyone!"}' + ``` + +## Limitations + +- Signature parsing supports basic Python types (`str`, `int`, `float`, `bool`, `list`) +- Complex types (nested objects, custom classes) require manual signature editing +- Generated modules use `dspy.Predict` by default (change to `ChainOfThought`, `ReAct`, etc. manually) + +## See Also + +- [dspy-cli serve](serve.md) - Start development server +- [Deployment Guide](../deployment.md) - Deploy to production +- [Configuration Guide](../configuration.md) - Model configuration diff --git a/docs/commands/serve.md b/docs/commands/serve.md index 3cdb0c5..37b3b0f 100644 --- a/docs/commands/serve.md +++ b/docs/commands/serve.md @@ -1,76 +1,286 @@ # dspy-cli serve -Start HTTP API server for DSPy programs — instantly exposes your programs as REST endpoints. +Start an HTTP server that exposes DSPy modules as REST API endpoints. -## Usage +## Synopsis ```bash dspy-cli serve [OPTIONS] ``` -## What Happens +## Usage ```bash -$ dspy-cli serve -Starting DSPy API server... +# Start server with default settings +dspy-cli serve -✓ Configuration loaded +# Production configuration +dspy-cli serve --no-reload --host 0.0.0.0 --port 8000 -Discovered Programs: +# Development with UI +dspy-cli serve --ui --port 3000 - • QaBotPredict - POST /QaBotPredict +# Enable MCP tools +dspy-cli serve --mcp +``` -Additional Endpoints: +## Description - GET /programs - List all programs and their schemas +Starts an HTTP server for local testing or production deployment. Discovers DSPy modules in `src//modules/` and exposes each as a POST endpoint. Generates request/response schemas from module type hints and provides OpenAPI documentation. -============================================================ -Server starting on http://localhost:8000 -============================================================ -``` +The server watches source files and configuration, restarting automatically on changes (unless `--no-reload` is specified). ## Options -- `--port` - Server port [default: 8000] -- `--host` - Bind host [default: 0.0.0.0] -- `--logs-dir` - Logs directory [default: ./logs] -- `--ui`, `-u` - Enable web UI -- `--python` - Python interpreter path -- `--system` - Use system Python (skip venv) +| Option | Default | Description | +|--------|---------|-------------| +| `--port` | `8000` | Port to run server on (1-65535) | +| `--host` | `0.0.0.0` | Host to bind to | +| `--logs-dir` | `./logs` | Directory for log files | +| `--ui` / `-u` | disabled | Enable web UI for testing | +| `--reload` / `--no-reload` | enabled | Auto-reload on file changes | +| `--save-openapi` / `--no-save-openapi` | enabled | Save OpenAPI spec to file | +| `--openapi-format` | `json` | OpenAPI format (`json` or `yaml`) | +| `--python` | auto-detect | Path to Python interpreter | +| `--system` | disabled | Use system Python instead of venv | +| `--mcp` | disabled | Enable MCP server at `/mcp` | + +## Auto-Discovery + +The server scans `src//modules/` for classes that subclass `dspy.Module`, analyzes their `forward()` method signatures, and generates POST endpoints automatically. + +**Example module:** + +```python +# src/blog_tools/modules/summarizer_predict.py +import dspy +from blog_tools.signatures.summarizer import SummarizerSignature +from typing import Literal, Optional + +class SummarizerPredict(dspy.Module): + def __init__(self): + super().__init__() + self.predictor = dspy.Predict(SummarizerSignature) + + def forward( + self, + blog_post: str, + summary_length: Literal['short', 'medium', 'long'], + tone: Optional[str] + ) -> dspy.Prediction: + return self.predictor( + blog_post=blog_post, + summary_length=summary_length, + tone=tone + ) +``` + +**Generates:** + +``` +POST /SummarizerPredict +``` + +### Endpoint Naming + +Endpoints match module class names: +- `SummarizerPredict` → `/SummarizerPredict` +- `HeadlineGeneratorCoT` → `/HeadlineGeneratorCoT` +- `TweetExtractorPredict` → `/TweetExtractorPredict` + +### Schema Generation + +Type hints from `forward()` parameters become JSON request schemas. Default values become optional fields. + +**Python signature:** + +```python +def forward( + self, + text: str, + options: list[str], + confidence_threshold: float = 0.8 +) -> dspy.Prediction: + ... +``` + +**Generated request schema:** + +```json +{ + "type": "object", + "properties": { + "text": {"type": "string"}, + "options": { + "type": "array", + "items": {"type": "string"} + }, + "confidence_threshold": { + "type": "number", + "default": 0.8 + } + }, + "required": ["text", "options"] +} +``` + +## Hot Reload + +The server watches for changes to: +- All `.py` files in `src/` directory +- `dspy.config.yaml` configuration file +- `.env` environment variables + +Saving any watched file triggers an automatic restart (~2 seconds). Disable with `--no-reload` for production deployments. + +## Endpoints + +Every deployment provides: + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/` | POST | Execute module with JSON request body | +| `/programs` | GET | List all discovered modules and their schemas | +| `/openapi.json` | GET | OpenAPI specification | + +With `--ui` enabled: +- `/` serves interactive testing interface + +With `--mcp` enabled: +- `/mcp` provides Model Context Protocol server + +## Logging + +Requests are logged to console by default. Use `--logs-dir` to persist logs per module: + +```bash +dspy-cli serve --logs-dir ./logs +``` + +Creates: +- `logs/SummarizerPredict.log` +- `logs/HeadlineGeneratorPredict.log` + +Each log entry includes timestamp, request inputs, response outputs, execution time, and model used. ## Examples +### Basic Usage + ```bash -# Simple: Start with defaults (port 8000) dspy-cli serve +``` +Server starts on `http://localhost:8000`. Call modules: -# Custom port: Avoid conflicts -dspy-cli serve --port 8080 +```bash +curl -X POST http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{ + "blog_post": "Article text...", + "summary_length": "short", + "tone": "professional" + }' +``` -# With UI: Interactive testing interface -dspy-cli serve --ui +Response: -# Production: External access + specific port -dspy-cli serve --host 0.0.0.0 --port 8000 +```json +{ + "summary": "Generated summary text." +} ``` -## Endpoints +### Development Mode ```bash -GET /programs # List available programs -POST /{ModuleClassName} # Call program (e.g., /QaBotPredict) +dspy-cli serve --ui --logs-dir ./logs --port 3000 ``` -## Testing +Enables: +- Interactive web UI at `http://localhost:3000` +- Hot reload on file changes +- Persistent logs in `./logs/` + +### Production Mode ```bash -# List programs -curl http://localhost:8000/programs +dspy-cli serve --no-reload --host 0.0.0.0 --port 8000 +``` + +Disables hot reload and binds to all network interfaces for production deployment. -# Call a program -curl -X POST http://localhost:8000/QaBotPredict \ +### Multiple Parameters + +```bash +curl -X POST http://localhost:8000/TaggerPredict \ -H "Content-Type: application/json" \ - -d '{"question": "What is DSPy?"}' + -d '{ + "blog_post": "Content here", + "max_tags": 5, + "style": "casual" + }' ``` + +### Error Responses + +**Validation error (422):** + +```bash +curl -X POST http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{"blog_post": 123}' +``` + +```json +{ + "detail": [ + { + "type": "string_type", + "loc": ["body", "blog_post"], + "msg": "Input should be a valid string", + "input": 123 + } + ] +} +``` + +**Missing required field (422):** + +```bash +curl -X POST http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{}' +``` + +```json +{ + "detail": [ + { + "type": "missing", + "loc": ["body", "blog_post"], + "msg": "Field required", + "input": {} + } + ] +} +``` + +## Environment Variables + +Configure via environment variables or `.env` file: + +- `OPENAI_API_KEY` - OpenAI API key +- Model-specific configuration in `dspy.config.yaml` + +## Limitations + +- Module discovery requires classes to subclass `dspy.Module` +- `forward()` method must have type hints for schema generation + +## See Also + +- [dspy-cli new](new.md) - Create new projects +- [Deployment Guide](../deployment.md) - Deploy to production +- [OpenAPI Generation](../OPENAPI.md) - API specification details +- [Configuration Guide](../configuration.md) - Model configuration diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 0000000..c776d2a --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,681 @@ +# Deployment + +This guide covers deployment of DSPy applications to production environments using containerization and cloud platforms. + +## Overview + +DSPy applications generated with `dspy-cli new` include production-ready deployment artifacts: + +- **Dockerfile** - Container configuration for standardized deployment +- **REST API endpoints** - Auto-generated from DSPy modules +- **OpenAPI specification** - Type-safe integration for clients +- **Environment variable handling** - Secure secrets management + +Local development servers created with `dspy-cli serve` use identical endpoints and behavior as production deployments. + +## Prerequisites + +- Docker (version 20.10 or later) +- Active account on target deployment platform +- API keys for configured LLM providers (OpenAI, Anthropic, etc.) +- Git repository (optional, required for some platforms) + +## Deployment to Fly.io + +Time to complete: ~3-5 minutes + +Fly.io provides global container deployment with minimal configuration. + +### 1. Install Fly CLI + +```bash +# macOS +brew install flyctl + +# Linux +curl -L https://fly.io/install.sh | sh + +# Windows +pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex" +``` + +### 2. Authenticate + +```bash +flyctl auth login +``` + +Opens browser for authentication. Free tier available without credit card for starter applications. + +### 3. Initialize Application + +Navigate to your project directory and run: + +```bash +flyctl launch +``` + +**Expected output:** + +``` +Scanning source code +Detected a Dockerfile app +? Choose an app name (leave blank to generate one): blog-tools-prod +? Choose a region for deployment: Seattle, Washington (US) (sea) + +Creating app in /Users/you/blog-tools +Organization: Personal +Name: blog-tools-prod +Region: Seattle, Washington (US) +App Machines: shared-cpu-1x, 1GB RAM + +? Do you want to tweak these settings before proceeding? No +``` + +### 4. Deploy + +```bash +flyctl deploy +``` + +**Expected output:** + +``` +--> Building image +[+] Building 28.7s +--> Pushing image to fly +--> Creating release +--> Monitoring deployment + +Visit your app at: https://blog-tools-prod.fly.dev +``` + +### 5. Configure Secrets + +Set environment variables for API keys: + +```bash +flyctl secrets set OPENAI_API_KEY=sk-proj-... +``` + +**Expected output:** + +``` +Secrets are staged for the first deployment +Release v2 created +``` + +For multiple providers: + +```bash +flyctl secrets set ANTHROPIC_API_KEY=sk-ant-... +``` + +Verify configured secrets: + +```bash +flyctl secrets list +``` + +**Expected output:** + +``` +NAME DIGEST CREATED AT +OPENAI_API_KEY a1b2c3d4e5f6... 1m ago +ANTHROPIC_API_KEY f6e5d4c3b2a1... 30s ago +``` + +### 6. Verify Deployment + +Test the deployed API: + +```bash +curl -X POST "https://blog-tools-prod.fly.dev/SummarizerPredict" \ + -H "Content-Type: application/json" \ + -d '{ + "blog_post": "Sample article text for testing deployment.", + "summary_length": "short", + "tone": "casual" + }' +``` + +**Expected output:** + +```json +{ + "summary": "Testing deployment with a sample article." +} +``` + +Verify OpenAPI specification is accessible: + +```bash +curl https://blog-tools-prod.fly.dev/openapi.json +``` + +### 7. Update Deployment + +Deploy changes: + +```bash +flyctl deploy +``` + +Zero-downtime rolling deployment. Previous version remains active until new version is healthy. + +### 8. Scale Deployment (Optional) + +Add instances in multiple regions: + +```bash +flyctl scale count 2 --region sea,iad +``` + +Configure auto-scaling: + +```bash +flyctl autoscale set min=1 max=10 +``` + +## Docker Deployment (Generic) + +The generated Dockerfile is compatible with any container platform: Render, Railway, Google Cloud Run, AWS App Runner, DigitalOcean App Platform, Azure Container Instances. + +### 1. Build Container Locally + +```bash +docker build -t blog-tools:latest . +``` + +**Expected output:** + +``` +[+] Building 45.3s + => [1/5] FROM docker.io/library/python:3.11-slim + => [2/5] COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv + => [3/5] COPY . . + => [4/5] RUN uv sync --no-dev + => [5/5] RUN uv tool install dspy-cli + => exporting to image +Successfully tagged blog-tools:latest +``` + +### 2. Test Container Locally + +```bash +docker run -p 8000:8000 \ + -e OPENAI_API_KEY=sk-proj-... \ + blog-tools:latest +``` + +**Expected output:** + +``` +INFO: Started server process [1] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://0.0.0.0:8000 +``` + +Test endpoint in another terminal: + +```bash +curl -X POST http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{"blog_post": "Test content", "summary_length": "short", "tone": null}' +``` + +### 3. Push to Container Registry + +**Docker Hub:** + +```bash +docker tag blog-tools:latest your-username/blog-tools:latest +docker push your-username/blog-tools:latest +``` + +**AWS ECR:** + +```bash +aws ecr get-login-password --region us-west-2 | \ + docker login --username AWS --password-stdin .dkr.ecr.us-west-2.amazonaws.com + +docker tag blog-tools:latest .dkr.ecr.us-west-2.amazonaws.com/blog-tools:latest +docker push .dkr.ecr.us-west-2.amazonaws.com/blog-tools:latest +``` + +**Google Artifact Registry:** + +```bash +gcloud auth configure-docker us-central1-docker.pkg.dev + +docker tag blog-tools:latest us-central1-docker.pkg.dev//dspy-apps/blog-tools:latest +docker push us-central1-docker.pkg.dev//dspy-apps/blog-tools:latest +``` + +### 4. Deploy to Platform + +**Render:** + +1. Connect GitHub repository in Render dashboard +2. Create new Web Service +3. Render auto-detects Dockerfile +4. Configure environment variables in Environment tab +5. Deploy + +**Railway:** + +```bash +railway up +railway variables set OPENAI_API_KEY=sk-proj-... +``` + +Auto-deploys on Git push when repository is connected. + +**Google Cloud Run:** + +```bash +gcloud run deploy blog-tools \ + --source . \ + --region us-central1 \ + --allow-unauthenticated \ + --set-env-vars OPENAI_API_KEY=sk-proj-... +``` + +**Expected output:** + +``` +Building using Dockerfile and deploying container +✓ Deploying... Done. +Service [blog-tools] revision [blog-tools-00001] has been deployed +Service URL: https://blog-tools-xyz.a.run.app +``` + +**AWS App Runner:** + +1. Push image to ECR (see registry instructions above) +2. Create App Runner service in AWS Console +3. Configure ECR image as source +4. Set environment variables in Configuration +5. Deploy service + +**DigitalOcean App Platform:** + +1. Connect GitHub repository +2. App Platform detects Dockerfile +3. Configure environment variables in Settings +4. Click Deploy + +## Environment Configuration + +### Development Environment + +Use `.env` file for local development: + +```bash +# .env - Do not commit to version control +OPENAI_API_KEY=sk-proj-... +ANTHROPIC_API_KEY=sk-ant-... +``` + +The `dspy-cli serve` command automatically loads variables from `.env`. File is excluded via `.gitignore`. + +### Production Secrets + +Configure secrets using platform-specific secret managers: + +| Platform | Command | Injection Method | +|----------|---------|------------------| +| **Fly.io** | `flyctl secrets set KEY=value` | Environment variables | +| **Render** | Dashboard → Environment tab | Environment variables | +| **Railway** | `railway variables set KEY=value` | Environment variables | +| **Google Cloud Run** | `--set-env-vars KEY=value` or Secret Manager | Environment variables | +| **AWS** | Systems Manager Parameter Store / Secrets Manager | ECS task definition | +| **DigitalOcean** | App Platform dashboard → Settings | Environment variables | + +### Model Configuration by Environment + +Configure different models for development and production using `dspy.config.yaml`: + +```yaml +models: + default: openai:gpt-4o-mini + + registry: + # Production model + openai:gpt-4o-mini: + model: openai/gpt-4o-mini + env: OPENAI_API_KEY + max_tokens: 16000 + temperature: 1.0 + model_type: chat + + # Development model + openai:gpt-4o-nano: + model: openai/gpt-4o-nano + env: OPENAI_API_KEY + max_tokens: 8000 + temperature: 1.0 + model_type: chat + + # Local model + local:qwen: + model: openai/qwen/qwen3-4b + api_base: http://127.0.0.1:1234/v1 + api_key: placeholder + max_tokens: 4096 + temperature: 1.0 + model_type: chat + +# Override per module +program_models: + SummarizerPredict: openai:gpt-4o-nano + TaggerCoT: openai:gpt-4o-mini +``` + +Override `default` or `program_models` before deploying, or maintain separate configuration files: + +```bash +# Use production config +cp dspy.config.prod.yaml dspy.config.yaml +``` + +### Secrets Management Best Practices + +**Required:** +- Store secrets in platform secret managers +- Use `.env` for local development only +- Add `.env` to `.gitignore` +- Rotate API keys regularly (monthly or quarterly) +- Use separate keys for development, staging, and production + +**Prohibited:** +- Committing `.env` files to Git +- Hardcoding keys in source code or configuration files +- Sharing production keys in communication channels +- Using production keys in local development +- Exposing keys in client-side code + +## Health Checks and Monitoring + +### Health Check Endpoint + +Verify service availability using the OpenAPI endpoint: + +```bash +curl https://blog-tools-prod.fly.dev/openapi.json +``` + +Returns OpenAPI specification if service is healthy. + +### Log Access + +**Fly.io:** + +```bash +# Stream live logs +flyctl logs + +# View recent logs +flyctl logs --recent + +# Access log files in container +flyctl ssh console +cd logs/ +tail -f SummarizerPredict.log +``` + +**Render:** + +View logs in dashboard under Logs tab. Export logs via Export Logs button. + +**Railway:** + +```bash +# View live logs +railway logs + +# Follow logs in real-time +railway logs --follow +``` + +**Google Cloud Run:** + +```bash +# View logs in Cloud Console +gcloud logging read "resource.type=cloud_run_revision" + +# Stream logs +gcloud logging tail "resource.type=cloud_run_revision" +``` + +**AWS App Runner:** + +View logs in CloudWatch Logs console. Use CloudWatch Insights for structured queries. + +### Log Format + +Structured JSON logs capture request details: + +```json +{ + "timestamp": "2024-01-15T10:30:45.123Z", + "program": "SummarizerPredict", + "model": "openai/gpt-4o-mini", + "duration_ms": 847.23, + "inputs": { + "blog_post": "Article text...", + "summary_length": "short", + "tone": null + }, + "outputs": { + "summary": "Generated summary." + }, + "success": true +} +``` + +### Platform-Specific Health Checks + +Configure health checks in platform configuration files: + +**Fly.io (fly.toml):** + +```toml +[http_service] + internal_port = 8000 + force_https = true + auto_start_machines = true + auto_stop_machines = true + min_machines_running = 0 + + [[http_service.checks]] + grace_period = "10s" + interval = "30s" + timeout = "5s" + method = "GET" + path = "/openapi.json" +``` + +**Google Cloud Run:** + +```bash +gcloud run deploy blog-tools \ + --timeout=300 \ + --max-instances=10 \ + --cpu=1 \ + --memory=512Mi +``` + +## Troubleshooting + +### Build Errors + +**Error: `uv: command not found`** + +Update Dockerfile to include `uv` binary: + +```dockerfile +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv +``` + +Or regenerate project files: + +```bash +dspy-cli new --force +``` + +**Error: `No module named 'dspy'`** + +Verify `pyproject.toml` includes DSPy dependency: + +```toml +[project] +dependencies = [ + "dspy>=2.5.0", +] +``` + +Rebuild container: + +```bash +docker build -t blog-tools . +``` + +**Error: `failed to solve with frontend dockerfile.v0`** + +Update Docker to version 20.10 or later. + +### Runtime Errors + +**Error: `OPENAI_API_KEY not set`** + +Configure environment variable on deployment platform: + +```bash +# Fly.io +flyctl secrets set OPENAI_API_KEY=sk-proj-... + +# Railway +railway variables set OPENAI_API_KEY=sk-proj-... + +# Google Cloud Run +gcloud run services update blog-tools --set-env-vars OPENAI_API_KEY=sk-proj-... +``` + +Verify secret is loaded: + +```bash +flyctl ssh console +echo $OPENAI_API_KEY +``` + +**Error: `Module not found: SummarizerPredict`** + +Verify module exists with correct class name: + +```bash +ls src/blog_tools/modules/ +cat src/blog_tools/modules/summarizer_predict.py | grep "class" +``` + +Expected: `class SummarizerPredict(dspy.Module):` + +**Error: `500 Internal Server Error`** + +Check container logs: + +```bash +flyctl logs --recent # Fly.io +railway logs # Railway +``` + +Common causes: +- Missing environment variables +- Model API rate limits exceeded +- Invalid signature definition +- Import errors in module code + +### Performance Issues + +**Slow cold starts (10-20 seconds)** + +Platforms may shut down idle containers. Solutions: + +- **Fly.io:** Upgrade to dedicated VM tier: `flyctl scale vm dedicated-cpu-1x` +- **Render:** Enable "Always On" in paid tiers +- **Railway:** Paid plans keep services active +- **Pre-warm with cron:** Configure external service (e.g., cron-job.org) to ping `/openapi.json` every 5 minutes + +**High latency** + +Deploy in regions closer to users: + +```bash +# Fly.io: Add regions +flyctl regions add sea iad lhr +flyctl scale count 3 + +# Google Cloud Run: Deploy to multiple regions +gcloud run deploy blog-tools --region us-central1 +gcloud run deploy blog-tools --region europe-west1 +gcloud run deploy blog-tools --region asia-northeast1 +``` + +**Timeout errors (504 Gateway Timeout)** + +Increase platform timeout limits: + +```bash +# Google Cloud Run (maximum 300 seconds) +gcloud run deploy blog-tools --timeout=300 + +# Fly.io: Edit fly.toml http_service.checks.timeout +``` + +### Debugging Workflow + +1. **Test locally with Docker:** + +```bash +docker build -t blog-tools . +docker run -p 8000:8000 -e OPENAI_API_KEY=sk-proj-... blog-tools +curl -X POST http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{"blog_post": "test", "summary_length": "short", "tone": null}' +``` + +2. **Verify OpenAPI specification:** + +```bash +curl https://blog-tools-prod.fly.dev/openapi.json +``` + +3. **Check application logs:** + +```bash +flyctl logs --recent +``` + +4. **Verify environment variables:** + +```bash +flyctl ssh console +env | grep API_KEY +``` + +## Related Documentation + +- [Configuration](configuration.md) - Model configuration and advanced settings +- [MCP Integration](OPENAPI.md) - Model Context Protocol tool server +- [Getting Started](getting-started.md#continuous-optimization) - Production data optimization +- [Use Cases: AI Features](use-cases/ai-features.md) - Integration patterns + +## Platform Documentation + +- [Fly.io Documentation](https://fly.io/docs/) +- [Render Documentation](https://render.com/docs) +- [Railway Documentation](https://docs.railway.app/) +- [Google Cloud Run Documentation](https://cloud.google.com/run/docs) +- [AWS App Runner Documentation](https://docs.aws.amazon.com/apprunner/) +- [DigitalOcean App Platform Documentation](https://docs.digitalocean.com/products/app-platform/) diff --git a/docs/getting-started.md b/docs/getting-started.md index e532049..405f5f4 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,156 +1,305 @@ -# Getting Started +# Quickstart: Create, Serve, Deploy, Integrate -## The Problem +Deploy a DSPy AI application as a REST API in 5 minutes. -Building reliable LLM applications is hard. Prompts break when requirements change. Manual tuning is tedious. Production debugging is a nightmare. - -**Get from idea to working DSPy application to API endpoint in 5 minutes.** +**Time to complete:** 5-10 minutes ## Prerequisites -- Python 3.9+ -- uv ([install uv](https://docs.astral.sh/uv/)) -- An LLM API key (OpenAI, Anthropic, or local models) +- Python 3.11 or later +- [uv](https://docs.astral.sh/uv/) package manager +- LLM API key (OpenAI, Anthropic, or compatible provider) + +## 1. Install CLI + +```bash +uv tool install dspy-cli +``` + +Verify installation: + +```bash +dspy-cli --version +``` -## Installation +## 2. Create Project ```bash -uv install dspy-cli +dspy-cli new email-subject -s "body, sender, context -> subject, tone, priority" +cd email-subject ``` -## Simple → Real-world → Production-ready +**Expected output:** +``` +✓ Created project structure +✓ Generated signature: EmailSubjectSignature +✓ Scaffolded module: EmailSubjectPredict +``` -### 1. Create Your Project +Configure environment: ```bash -dspy-cli new qa-bot -s "question -> answer" -cd qa-bot echo "OPENAI_API_KEY=sk-..." > .env uv sync ``` -**What this solves:** Manual prompt engineering for every task. DSPy generates optimized prompts automatically from your signature. - -### 2. Start Building +## 3. Run Locally ```bash -dspy-cli serve +dspy-cli serve --ui --reload ``` +**Expected output:** ``` ✓ Configuration loaded Discovered Programs: - • QaBotPredict - POST /QaBotPredict + • EmailSubjectPredict + POST /EmailSubjectPredict -Server starting on http://0.0.0.0:8000 +Server running at http://0.0.0.0:8000 +Interactive UI at http://localhost:8000 ``` -**Before:** Writing Flask/FastAPI boilerplate, managing routes, validating inputs. -**After:** Automatic REST API with input and output validation. +## 4. Verify Endpoints -### 3. Test It +Test with curl: ```bash -curl -X POST http://localhost:8000/QaBotPredict \ +curl -X POST http://localhost:8000/EmailSubjectPredict \ -H "Content-Type: application/json" \ - -d '{"question": "What is DSPy?"}' + -d '{ + "body": "Team, Q4 results are in. Revenue up 23%, NPS at 72.", + "sender": "Sarah (CEO)", + "context": "Company all-hands" + }' +``` + +**Expected response:** +```json +{ + "subject": "Q4 Results: +23% Revenue, 72 NPS", + "tone": "professional", + "priority": "high" +} ``` -Or add the `--ui` flag and open `http://localhost:8000/` for interactive testing. +View interactive UI at http://localhost:8000 to test without curl. -!!! success "Why This Matters" - You now have a working LLM application. No prompt templates. No brittle string formatting. Just type-safe inputs and outputs. +## 5. Deploy to Production -### 4. Add Real-World Features +### Option A: Fly.io (Recommended) -Need chain-of-thought reasoning? +Install Fly CLI: ```bash -dspy-cli g scaffold analyzer -m CoT -s "text, context: list[str] -> summary, key_points: list[str]" +curl -L https://fly.io/install.sh | sh +flyctl auth login ``` -**What breaks in traditional approaches:** -- Chaining prompts manually = context loss -- Parsing structured outputs = fragile regex -- Managing multi-step workflows = error-prone state -- Engineering concerns are bundles together into one big string prompt that is hard to reason about and debug. +Deploy: -**DSPy prevents this:** Modules compose cleanly. Signatures enforce types. Programs are testable Python. +```bash +flyctl launch --name email-subject +flyctl secrets set OPENAI_API_KEY=sk-... +flyctl deploy +``` -Restart the server and your new `/AnalyzerCoT` endpoint is live. +**Expected output:** +``` +==> Monitoring deployment +✓ Instance created +✓ Health checks passing -## Make It Better: Optimization +Visit your deployment at https://email-subject.fly.dev +``` -Your app works. Now make it **great**. +### Option B: Docker -DSPy supports optimization through its Python API. You can use optimizers like `BootstrapFewShot` to automatically improve your prompts based on training examples: +```bash +docker build -t email-subject . +docker run -p 8000:8000 -e OPENAI_API_KEY=sk-... email-subject +``` + +Deploy to AWS ECS, Google Cloud Run, Azure Container Instances, or Kubernetes. + +## 6. Verify Production Deployment + +Test deployed endpoint: + +```bash +curl -X POST https://email-subject.fly.dev/EmailSubjectPredict \ + -H "Content-Type: application/json" \ + -d '{ + "body": "Team, Q4 results are in. Revenue up 23%, NPS at 72.", + "sender": "Sarah (CEO)", + "context": "Company all-hands" + }' +``` + +Retrieve OpenAPI schema: + +```bash +curl https://email-subject.fly.dev/openapi.json +``` + +## 7. Integrate with Applications + +### JavaScript/TypeScript + +```typescript +interface EmailSubjectRequest { + body: string; + sender: string; + context: string; +} + +interface EmailSubjectResponse { + subject: string; + tone: string; + priority: string; +} + +async function generateEmailSubject( + req: EmailSubjectRequest +): Promise { + const response = await fetch( + 'https://email-subject.fly.dev/EmailSubjectPredict', + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(req) + } + ); + + return await response.json(); +} + +// Usage +const result = await generateEmailSubject({ + body: "Team meeting notes...", + sender: "manager@company.com", + context: "Internal communication" +}); + +console.log(result.subject); // "Weekly Team Sync: Key Decisions" +``` + +### Python ```python -import dspy -from dspy.teleprompt import BootstrapFewShot - -# Define your metric -def accuracy(example, pred, trace=None): - return example.answer.lower() == pred.answer.lower() - -# Optimize -optimizer = BootstrapFewShot(metric=accuracy) -optimized_program = optimizer.compile( - student=qa_bot, - trainset=training_examples +import requests + +def generate_email_subject(body: str, sender: str, context: str) -> dict: + response = requests.post( + 'https://email-subject.fly.dev/EmailSubjectPredict', + json={ + 'body': body, + 'sender': sender, + 'context': context + } + ) + return response.json() + +# Usage +result = generate_email_subject( + body="Team meeting notes...", + sender="manager@company.com", + context="Internal communication" ) -# Then load your optimized program inside module init! -# TODO: (Isaac) Does this work? -class QaBot(dspy.Module): - def __init__(self): - self.load("path/to/optimized_program.") +print(result['subject']) # "Weekly Team Sync: Key Decisions" ``` -**Before optimization:** Generic prompts. Inconsistent quality. Trial-and-error tuning. -**After optimization:** Prompts tailored to your task. Measurable improvements. Data-driven. +### cURL -See the [DSPy documentation](https://dspy.ai) for more on optimization strategies. +```bash +curl -X POST https://email-subject.fly.dev/EmailSubjectPredict \ + -H "Content-Type: application/json" \ + -d '{ + "body": "Team meeting notes...", + "sender": "manager@company.com", + "context": "Internal communication" + }' +``` ## Module Types +Select appropriate module type for your use case: + | Type | Flag | Use Case | |------|------|----------| -| Predict | default | Simple input → output | -| ChainOfThought | `-m CoT` | Show reasoning steps | -| ReAct | `-m ReAct` | Tool-using agents | -| ProgramOfThought | `-m PoT` | Code generation | +| **Predict** | (default) | Classification, extraction, simple generation | +| **ChainOfThought** | `-m CoT` | Tasks requiring reasoning steps | +| **ReAct** | `-m ReAct` | Tool-using agents with external actions | +| **ProgramOfThought** | `-m PoT` | Code generation, calculations, structured logic | + +Use `dspy-cli generate scaffold` to create programs with specific module types: + +```bash +# Create project first +dspy-cli new document-analyzer + +# Add ChainOfThought module +cd document-analyzer +dspy-cli g scaffold analyzer -m CoT -s "document, criteria -> verdict: bool, reasoning, confidence: float" +``` ## Project Structure ``` -qa-bot/ -├── src/qa_bot/ -│ ├── modules/ # Your DSPy programs (auto-discovered) -│ ├── signatures/ # Input/output type definitions -│ ├── optimizers/ # Prompt optimization configs -│ ├── metrics/ # Custom evaluation metrics +email-subject/ +├── src/email_subject/ +│ ├── modules/ # DSPy programs (auto-discovered as endpoints) +│ ├── signatures/ # Input/output schemas +│ ├── optimizers/ # Optimization configurations +│ ├── metrics/ # Evaluation metrics │ └── utils/ # Helper functions -├── data/ # Example data -├── logs/ # Server logs -├── tests/ # Automatically generated test files -├── dspy.config.yaml # Model and LLM provider settings -├── .env # API keys (never committed) -├── Dockerfile # Production deployment -└── pyproject.toml # Dependencies and package config +├── data/ # Training/test datasets +├── logs/ # Request logs +├── tests/ # Test scaffolds +├── dspy.config.yaml # Model configuration +├── .env # API keys (gitignored) +├── Dockerfile # Container configuration +└── pyproject.toml # Dependencies ``` ## Development Workflow -### Web UI +### Hot Reload ```bash -dspy-cli serve --ui +dspy-cli serve --ui --reload +``` + +Changes to `src/email_subject/modules/*.py` reload automatically (< 1s). + +### Switch Models + +Edit `dspy.config.yaml` to change providers without code changes: + +```yaml +models: + default: openai:gpt-4o-mini + registry: + openai:gpt-4o-mini: + model: openai/gpt-4o-mini + env: OPENAI_API_KEY + max_tokens: 16000 + temperature: 1.0 + model_type: chat ``` -Visual testing interface at `http://localhost:8000`. +```yaml +# Anthropic +lm: + provider: anthropic + model: claude-3-sonnet-20240229 + max_tokens: 1000 + temperature: 0.7 +``` + +Restart server to apply configuration changes. ### Custom Port @@ -158,80 +307,83 @@ Visual testing interface at `http://localhost:8000`. dspy-cli serve --port 3000 ``` -## Common Patterns +## Next Steps -### Multiple Inputs +- **[Deployment Guide](deployment.md)** - Production configuration, scaling, monitoring +- **[Configuration Reference](configuration.md)** - Model providers, advanced settings +- **[Command Reference](commands/index.md)** - Complete CLI documentation +- **[Examples](../examples/)** - Working applications (blog-tools, code-review-agent) -```bash -dspy-cli g scaffold search -s "query, context: list[str] -> answer, sources: list[str]" -``` +## Troubleshooting + +### Module Not Found -### Typed Outputs +Activate project virtual environment: ```bash -dspy-cli g scaffold classifier -s "text -> category, confidence: float, reasoning" +cd email-subject +uv sync +source .venv/bin/activate # Unix/macOS +# or +.venv\Scripts\activate # Windows ``` -### Complex Types +Add external dependencies to `pyproject.toml`: ```bash -# Supports: str, int, float, bool, list[T], dict, Any -dspy-cli g scaffold extractor -s "document -> entities: list[str], metadata: dict" +uv add requests pandas +uv sync ``` -## Next Steps +### API Key Errors -**See Real Examples:** -- [blog-tools](../examples/blog-tools/) - Content generation pipeline -- [code-review-agent](../examples/code-review-agent/) - Code analysis automation +Verify `.env` file exists: -**Configure Models:** -- [Configuration Guide](configuration.md) - LLM providers, custom models +```bash +cat .env # Should show OPENAI_API_KEY=sk-... +``` -**Deploy:** -- Coming Soon +Export to current shell: -## Troubleshooting +```bash +export OPENAI_API_KEY=sk-... # Unix/macOS +# or +set OPENAI_API_KEY=sk-... # Windows +``` + +### Port In Use -**Module not found error:** +Use different port: -This typically happens if you are trying to import a dependency, but you're not using the correct venv. ```bash -cd qa-bot # Ensure you're in the project directory -uv venv -source .venv/bin/activate +dspy-cli serve --port 8080 ``` -To use an external dependency, you need to: -1. Have it in the pyproject.toml file -2. Make sure that you are using the correct venv -The global tool install of dspy-cli won't work with external dependencies. +Identify process using port 8000: -If you run: ```bash -which dspy-cli +lsof -ti:8000 # Unix/macOS +netstat -ano | findstr :8000 # Windows ``` -The global tool will be at: `~/.local/bin/dspy-cli` (or equivalent on your system) -The local install will be at: `./venv/bin/dspy-cli`. The local install will allow you to use external dependencies. +### Deployment Failures + +Check Fly.io logs: -**API key errors:** ```bash -cat .env # Check .env file -export OPENAI_API_KEY=sk-... # Ensure key is set +flyctl logs ``` -**Port already in use:** +Verify secrets configured: + ```bash -dspy-cli serve --port 8080 +flyctl secrets list # Should show OPENAI_API_KEY ``` -**Virtual environment issues:** +Validate Docker build: + ```bash -rm -rf .venv && uv sync -source .venv/bin/activate +docker build -t email-subject . --progress=plain ``` ---- - -**You're ready to build.** Start with a working system, iterate with real data, optimize for production. +For additional issues, see [Deployment Troubleshooting](deployment.md#troubleshooting). diff --git a/docs/index.md b/docs/index.md index 4a1c45c..0d83d89 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,207 +1,126 @@ # dspy-cli -## Tired of Prompts Breaking When You Switch Models? +## Overview -You tweak your prompt until it works perfectly with GPT-4. Then you try Claude or Llama and everything breaks. You're stuck manually tuning prompts, chasing edge cases, and praying nothing breaks in production. +dspy-cli is a deployment framework for LLM-backed application features. It generates standardized project structure and HTTP interfaces for DSPy modules, reducing setup time from hours to minutes. -**There's a better way to build AI systems.** +## The Problem -> **Build. Test. Ship. Iterate.** +Embedding LLM-backed features into applications requires: -DSPy optimizes your AI systems automatically—no manual prompt engineering. **dspy-cli gets you started in minutes.** +- Containerizing the runtime environment +- Exposing a stable HTTP interface +- Wiring API keys and secrets +- Implementing health checks and logging +- Configuring routing and auto-discovery +- Setting up local development and testing infrastructure -## From Frustration to Flow +This overhead blocks small-to-medium AI features from shipping. A DSPy module that takes 30 minutes to write can require 4+ hours of infrastructure work before it's usable in a browser extension, Notion plugin, or web application. -**Before:** -```python -# Brittle prompt strings -prompt = "You are a helpful assistant. Given this text..." -# Manual tweaking for every model -# Breaks when you change providers -# No systematic testing -``` - -**After:** -```python -# Declarative, optimizable signatures -class QASignature(dspy.Signature): - question: str = dspy.InputField() - answer: str = dspy.OutputField() -qa = dspy.Predict(QASignature) -``` - -**The difference:** Your system adapts automatically. Switch models, run an optimizer, ship with confidence. - -## Quick Start - -Go from idea to live API in three commands: - -```bash -dspy-cli new chatbot # Full project structure -cd chatbot && uv sync # Install dependencies -dspy-cli serve # Live REST API -``` - -Your LLM app is running at `http://localhost:8000`. - -## Installation - -```bash -uv tool install dspy-cli -# or: pipx install dspy-cli -``` +## What dspy-cli Provides -## What You Get +**Project Scaffolding** +- Standardized directory structure with modules, signatures, and configurations +- Auto-generated DSPy signatures from type specifications +- Docker configurations for local development and production deployment -### 1. Stop Fighting Boilerplate +**HTTP Interface** +- FastAPI-based REST endpoints with automatic module discovery +- OpenAPI documentation and interactive testing UI +- Request/response validation via Pydantic models -```bash -dspy-cli new my-app -``` +**Development Workflow** +- Hot-reload server for rapid iteration +- Built-in testing UI with form-based request construction +- Type-safe module signatures with validation -``` -Creating new DSPy project: my-app - ✓ Project structure - ✓ Type-safe signatures - ✓ Test templates - ✓ Config files - ✓ Git repository -``` +**Deployment Infrastructure** +- Production-ready Docker containers +- Environment variable management +- Inference API key authentication +- Integration with any platform that can use a Dockerfile: Fly.io, Render, AWS, and other container platforms -**No more:** "Where does this file go?" or "Where do I put my modules?" or "What configuration do I need?" +## What Are AI Features? -### 2. Ship Faster +In this context, "AI features" refers to application-embedded functionality backed by LLMs. These are exposed as HTTP endpoints and called by client applications—browser extensions, Notion workspaces, email clients, web servers. -**Before:** Building REST APIs from scratch. +This differs from: +- **Agentic Applications** where the LLM controls the conversation flow +- **Batch pipelines** that process large datasets asynchronously -**After:** Auto-discovery turns your modules into endpoints. +Examples include text summarization APIs for browser extensions, classification endpoints for content management systems, and generation services for productivity tools. -```bash -dspy-cli serve -``` +## Architecture -``` -Server starting on http://0.0.0.0:8000 +dspy-cli applications follow a standard structure: -Discovered Programs: - • MyAppPredict - POST /MyAppPredict ``` - - -### 3. Iterate Without Friction - -Built-in web UI for testing. Edit a module, restart the server, test in a ui immediately. - -```bash -dspy-cli serve --ui +my-project/ +├── pyproject.toml +├── dspy.config.yaml # Model registry and configuration +├── .env # API keys and secrets +├── README.md +├── src/ +│ └── dspy_project/ # Importable package +│ ├── __init__.py +│ ├── modules/ # DSPy program implementations +│ ├── signatures/ # Reusable signatures +│ ├── optimizers/ # Optimizer configurations +│ ├── metrics/ # Evaluation metrics +│ └── utils/ # Shared helpers +├── data/ +├── logs/ +└── tests/ ``` -## Real-World Examples - -See examples of how to use dspy-cli to solve actual problems: +**Request Flow:** +1. HTTP request → FastAPI endpoint +2. Request body validated against Pydantic signature +3. DSPy module executes with validated inputs +4. Response serialized and returned -### Content Pipeline -**Pain:** Manual content generation is slow. Generating headlines, summaries, and tags should be programs that are simple and easy to read. +**Module Discovery:** +Modules in `src/*/modules/` are automatically registered as endpoints at `/{ModuleName}`. No manual routing configuration required. -**Solution:** [blog-tools](https://github.com/cmpnd-ai/dspy-cli-tool/tree/main/examples/blog-tools) - Automated headline generator, summarizer, tagger, and tweet extractor. One system, optimized together. - -### Code Review Agent -**Pain:** Code review is tedious. You want AI help but building a reliable system takes weeks. - -**Solution:** [code-review-agent](https://github.com/cmpnd-ai/dspy-cli-tool/tree/main/examples/code-review-agent) - Give an agent tools to use to review code. Uses the GitHub API as a tool. - -## Core Workflow - -### Create Your Project +## Quick Start ```bash -dspy-cli new qa-bot -s "question -> answer" -``` - -Scaffolds modules, signatures, tests, config—everything you need to start coding. +# Install +uv tool install dspy-cli -### Add Your API Key +# Create project +dspy-cli new my-feature -s "text -> summary" +cd my-feature && uv sync -```bash -cd qa-bot +# Configure echo "OPENAI_API_KEY=sk-..." > .env -uv sync -``` - -### Build Your Logic - -Edit `src/qa_bot/modules/qa_bot_predict.py`: - -```python -class QaBotPredict(dspy.Module): - def __init__(self): - self.prog = dspy.Predict(QaBotSignature) - - def forward(self, question: str): - return self.prog(question=question) -``` - -### Test Locally -```bash -dspy-cli serve -``` - -```bash -curl -X POST http://localhost:8000/QaBotPredict \ - -H "Content-Type: application/json" \ - -d '{"question": "What is DSPy?"}' -``` - -Or open `http://localhost:8000/` for interactive testing. - -### Add More Programs - -```bash -dspy-cli g scaffold summarizer -m CoT -s "text -> summary" +# Serve locally +dspy-cli serve --ui ``` -Creates signature and module. Instantly available at `/SummarizerCoT` endpoint. - -## Why dspy-cli? - -### Speed to Production +Access the API at `http://localhost:8000/{ModuleName}` and testing UI at `http://localhost:8000/`. -- **Scaffold in seconds** - From zero to working project instantly -- **Auto-discovery** - Drop in a module, get a REST endpoint -- **Interactive testing** - Built-in web UI for rapid iteration -- **Docker ready** - Production deployment included +See the [Getting Started Guide](getting-started.md) for detailed walkthrough. -### Built for Reliability +## Use Cases -- **Type-safe signatures** - Catch errors before runtime -- **Testing built-in** - Test templates for every module -- **Config management** - Environment-based settings with `.env` support +**Browser Extensions** +HTTP endpoints for summarization, extraction, or classification that extensions call on user-triggered events. -### Focus on What Matters +**Content Management Integration** +Embedded generation or tagging services for platforms like Notion, Confluence, or custom CMSs. -**Stop spending time on:** -- Project structure -- Boilerplate code -- Server setup -- Deployment config - -**Start spending time on:** -- Your AI logic -- Understanding the user problem -- Training data -- Shipping features +**Application Microservices** +Standalone intelligence services that web or mobile applications consume via REST APIs. ## Next Steps -- [Getting Started Guide](getting-started.md) - Detailed walkthrough -- [Commands Reference](commands/) - All commands and options -- [Configuration](configuration.md) - Model settings and customization +- [Getting Started Guide](getting-started.md) - Complete setup and first deployment +- [Commands Reference](commands/) - CLI command documentation +- [Configuration](configuration.md) - Model settings and environment variables +- [Examples](https://github.com/cmpnd-ai/dspy-cli-tool/tree/main/examples) - Sample projects and patterns ```bash -dspy-cli --help # See all commands +dspy-cli --help # View all commands ``` - ---- - -**Stop tweaking. Start building.** Transform your DSPy ideas into production APIs today. diff --git a/docs/use-cases/ai-features.md b/docs/use-cases/ai-features.md new file mode 100644 index 0000000..703ff27 --- /dev/null +++ b/docs/use-cases/ai-features.md @@ -0,0 +1,177 @@ +# Concept: AI Features + +## Definition + +AI features are application-embedded functionality backed by language models. They are exposed as HTTP endpoints and integrated into existing applications, providing task-specific capabilities such as document summarization, content classification, or contextual text generation. + +Unlike conversational interfaces or autonomous agents, AI features are discrete services that applications invoke to complete specific operations within their workflow. + +## Characteristics + +AI features have several defining properties: + +- **Task-specific**: Designed to solve a particular problem rather than handle general-purpose queries +- **Endpoint-based**: Exposed as HTTP APIs that return structured responses +- **Application-embedded**: Integrated into existing software (browser extensions, plugins, background services) +- **Deterministic interfaces**: Accept defined inputs and return structured outputs +- **Stateless operation**: Each request is independent, without conversational context + +## Comparison with Other Patterns + +| Pattern | Execution Model | Interface Type | Primary Use Case | +|---------|----------------|----------------|------------------| +| **AI Features** | Application calls endpoint for specific task | HTTP API with structured I/O | Embedded functionality in existing apps | +| **Chat Interfaces** | User interacts with conversational agent | Natural language dialogue | Open-ended assistance and exploration | +| **Batch Processing** | Offline processing of datasets | Pipeline/job-based | Large-scale data transformation | +| **Agents** | LLM controls execution flow and tool use | Autonomous decision-making | Multi-step tasks requiring planning | + +AI features differ from chat interfaces in that they provide specific functionality rather than conversational interaction. Unlike agents, the application controls execution flow and calls the feature as needed. Unlike batch processing, AI features operate on individual requests in real-time. + +## Common Use Cases + +**Content Analysis** +- Document summarization that extracts key points and generates structured summaries +- Technical documentation analysis that explains complex concepts +- Code review assistance that identifies patterns and suggests improvements + +**Classification and Categorization** +- Email categorization based on content, sender, and context +- Content tagging systems that apply metadata automatically +- Priority scoring for tasks, tickets, or messages + +**Contextual Generation** +- Smart reply generation for email and messaging applications +- Form completion based on user context and historical data +- Content recommendations tailored to specific situations + +**Data Extraction** +- Invoice processing that extracts vendor, amount, and line items +- Resume parsing that structures candidate information +- Document metadata extraction from unstructured sources + +**Browser Extensions** +- Page summarizers that condense content with custom focus +- Context-aware form fillers +- Research assistants that analyze and annotate content + +## Integration Patterns + +### Browser Extension Integration + +Browser extensions call AI feature endpoints from content scripts or background workers: + +```javascript +// Content script calling document analysis endpoint +async function analyzeDocument(content) { + const response = await fetch('https://api.example.com/DocumentAnalyzerPredict', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ document: content }) + }); + return response.json(); +} +``` + +### CMS Plugin Integration + +Content management systems integrate AI features to enhance authoring workflows: + +```javascript +// Notion-style plugin calling emoji suggestion endpoint +async function suggestEmoji(postContent) { + const response = await fetch('https://api.example.com/EmojiPickerPredict', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ post_content: postContent }) + }); + const { emoji } = await response.json(); + return emoji; +} +``` + +### Email Client Integration + +Email applications use AI features for categorization and smart replies: + +```python +# Email categorizer endpoint +class EmailCategorizer(dspy.Module): + def __init__(self): + super().__init__() + self.classify = dspy.ChainOfThought( + "email_content, sender -> category, priority" + ) + + def forward(self, email_content, sender): + return self.classify(email_content=email_content, sender=sender) +``` + +### Background Automation + +Background services invoke AI features for asynchronous processing: + +```python +# Invoice processor for automated document handling +class InvoiceProcessor(dspy.Module): + def __init__(self): + super().__init__() + self.extract = dspy.ChainOfThought( + "invoice_data -> vendor, amount, date, line_items" + ) + + def forward(self, invoice_data): + return self.extract(invoice_data=invoice_data) +``` + +## Implementation with dspy-cli + +dspy-cli provides tooling to create and deploy AI features. A typical workflow: + +```bash +# Create a new AI feature module +dspy-cli new document-summarizer --program-name Summarizer \ + --signature "document -> summary, key_points" + +# Test locally +dspy-cli serve + +# Deploy to production +flyctl launch +``` + +The resulting endpoint accepts structured input and returns structured output: + +```bash +curl http://localhost:8000/SummarizerPredict \ + -H "Content-Type: application/json" \ + -d '{"document": "Long document text..."}' + +# Returns +{ + "summary": "Brief summary of document", + "key_points": ["Point 1", "Point 2", "Point 3"] +} +``` + +## Deployment Requirements + +AI features require: + +- **HTTP server**: To expose endpoints for application integration +- **Model inference**: Runtime for executing language model operations +- **Authentication**: API keys or tokens for access control +- **Monitoring**: Logging and metrics for production operations +- **Versioning**: Ability to update features without breaking integrations + +## Examples + +- [Email Categorizer](../../examples/email-categorizer/) - Classifies emails by category and priority +- [Document Summarizer](../../examples/doc-summarizer/) - Generates structured summaries from text +- [Smart Form Filler](../../examples/form-filler/) - Completes forms using contextual understanding + +## Learn More + +- [Getting Started Guide](../getting-started.md) - Build your first AI feature +- [Deployment Guide](../deployment.md) - Deploy to production environments +- [Commands: serve](../commands/serve.md) - Local development and testing +- [Examples](../../examples/) - Complete integration examples diff --git a/examples/code-review-agent/README.md b/examples/code-review-agent/README.md index 9c02833..feebe86 100644 --- a/examples/code-review-agent/README.md +++ b/examples/code-review-agent/README.md @@ -1,62 +1,171 @@ -# dspy-code-review-agent +# Code Review Agent -A DSPy project created with dspy-cli. +PR review agent demonstrating ReAct tool use with GitHub API integration. -## Setup +## Overview + +This example uses `dspy.ReAct` with GitHub API tools to: + +1. Accept repository name and PR number as input +2. Fetch PR metadata and file diffs using GitHub tools +3. Analyze code changes for issues, security concerns, and test coverage +4. Return structured review with effort estimation and key issues + +**Program:** `PRReviewer` (ReAct) +**Signature:** `ReviewPR` - Input: pr_metadata, file_list → Output: PRReview +**Tools:** GitHub API (`get_file_contents` and PR data fetching) + +## Prerequisites + +- Python 3.11+ +- OpenAI API key +- GitHub personal access token (optional, for private repos) +- `dspy-cli` installed + +## Run Locally + +### 1. Install Dependencies -1. Configure your API keys in `.env`: ```bash -# Edit .env and add your API keys -OPENAI_API_KEY=your-key-here +cd examples/code-review-agent +uv sync ``` -2. Update model configuration in `dspy.config.yaml` as needed. +### 2. Configure Environment -## Development +```bash +# Create .env file +echo "OPENAI_API_KEY=your-key-here" > .env +echo "GITHUB_TOKEN=your-token-here" >> .env # Optional +``` + +### 3. Start Server -### Project Structure +```bash +dspy-cli serve --ui +``` -- `src/code_review_agent/modules/` - DSPy program implementations -- `src/code_review_agent/signatures/` - Reusable signatures -- `src/code_review_agent/optimizers/` - Optimizer configurations -- `src/code_review_agent/metrics/` - Evaluation metrics -- `src/code_review_agent/utils/` - Shared helper functions -- `data/` - Training and evaluation data -- `logs/` - API request logs -- `tests/` - Test files +Server starts at `http://localhost:8000` -### Running the API +### 4. Test Endpoint -Start the development server: ```bash -dspy-cli serve +curl -X POST http://localhost:8000/PRReviewer \ + -H "Content-Type: application/json" \ + -d '{ + "repo": "stanfordnlp/dspy", + "pr_number": 1234 + }' ``` -Or specify custom host/port: +Expected output: +```json +{ + "estimated_effort_to_review": 3, + "relevant_tests": "Yes", + "key_issues_to_review": [ + { + "relevant_file": "src/module.py", + "issue_header": "Potential type error", + "issue_content": "Function expects string but receives int", + "start_line": 45, + "end_line": 47 + } + ], + "security_concerns": "No security issues found", + "score": 85 +} +``` + +## Deploy + ```bash -dspy-cli serve --port 8080 --host 127.0.0.1 +flyctl launch +flyctl secrets set OPENAI_API_KEY=your-key-here +flyctl secrets set GITHUB_TOKEN=your-token-here # Optional +flyctl deploy ``` -### Available Endpoints +Deployment URL: `https://your-app.fly.dev` -- `GET /programs` - List all available programs -- `POST /{program}` - Execute a program with JSON input +See [Deployment Guide](../../docs/deployment.md) for other platforms. -### Example Request +## Integrate -```bash -curl -X POST http://localhost:8000/code_review_agent \\ - -H "Content-Type: application/json" \\ - -d '{"question": "your question here"}' +### Python + +```python +import requests + +response = requests.post( + 'https://your-app.fly.dev/PRReviewer', + json={ + 'repo': 'owner/repo', + 'pr_number': 123 + } +) + +review = response.json() +print(f"Effort: {review['estimated_effort_to_review']}/5") +print(f"Tests: {review['relevant_tests']}") +print(f"Issues found: {len(review['key_issues_to_review'])}") +``` + +### JavaScript + +```javascript +const response = await fetch('https://your-app.fly.dev/PRReviewer', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + repo: 'owner/repo', + pr_number: 123 + }) +}); + +const review = await response.json(); +console.log(`Security: ${review.security_concerns}`); ``` -## Testing +### curl -Run tests: ```bash -pytest +curl -X POST https://your-app.fly.dev/PRReviewer \ + -H "Content-Type: application/json" \ + -d '{"repo": "owner/repo", "pr_number": 123}' ``` -## Learn More +## Architecture + +**Module:** `PRReviewer` +- Uses `dspy.ReAct` with GitHub API tools +- Fetches PR data with `download_and_format_pr()` +- Tool: `get_file_contents` - Retrieve full file contents from GitHub +- Returns structured `PRReview` object + +**Signature:** `ReviewPR` +- Input fields: `pr_metadata` (dict), `file_list` (list) +- Output field: `pr_review` (PRReview pydantic model) + +**Output Structure:** `PRReview` +- `estimated_effort_to_review` (1-5) +- `relevant_tests` (Yes/No/Partial) +- `key_issues_to_review` (list of issues with file, line numbers, description) +- `security_concerns` (string summary) +- Optional: `score` (0-100), `todo_sections`, `estimated_contribution_time_cost` -- [DSPy Documentation](https://dspy.ai) +## Project Structure + +``` +code-review-agent/ +├── src/code_review_agent/ +│ ├── modules/ +│ │ └── pr_reviewer.py # PRReviewer ReAct module +│ ├── signatures/ +│ │ └── review_pr.py # ReviewPR signature + PRReview model +│ └── utils/ +│ ├── pr_loader.py # Fetch and format PR data +│ └── github_tools.py # GitHub API tools +├── openapi.json # API specification +└── dspy.config.yaml # Model configuration +``` diff --git a/mkdocs.yml b/mkdocs.yml index 68fe16e..546c0b5 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,7 +43,7 @@ theme: extra: social: - icon: fontawesome/brands/github - link: https://github.com/caisco/optimization-platform + link: https://github.com/cmpnd-ai/dspy-cli-tool plugins: - search @@ -94,15 +94,15 @@ markdown_extensions: permalink: true nav: - - User Guide: - - Home: index.md - - Getting Started: getting-started.md - - Configuration: configuration.md - - Commands: - - commands/index.md - - new: commands/new.md - - serve: commands/serve.md - - generate: commands/generate.md - - Development: - - Contributing: contributing.md - - Releasing: releasing.md + - Home: index.md + - Getting Started: getting-started.md + - Use Cases: + - AI Features: use-cases/ai-features.md + - Deployment: deployment.md + - Commands: + - serve: commands/serve.md + - new: commands/new.md + - Configuration: configuration.md + - Examples: + - Blog Tools: https://github.com/cmpnd-ai/dspy-cli-tool/tree/main/examples/blog-tools + - Code Review Agent: https://github.com/cmpnd-ai/dspy-cli-tool/tree/main/examples/code-review-agent