CLI with API Gateway¶
Overview¶
The CLI can be configured to route commands through an API server, enabling:
- Concurrent access: Multiple clients (CLI, API, external tools) safely accessing the same database
- Distributed deployment: CLI on one machine, API server on another
- Unified data: All clients see the same data through shared database
- Security: API authentication, request validation, audit logging
Problem Statement¶
DuckDB Concurrency Issue¶
DuckDB (default database) is optimized for single-process access:
┌──────────┬──────────┬──────────┐
│ CLI │ API │ External │
│ │ Server │ Tools │
└─────┬────┴────┬─────┴────┬─────┘
│ │ │
└─────────┴──────────┘
↓
DuckDB (Single-process optimized)
Problem: Multiple processes accessing DuckDB simultaneously can cause: - Lock contention - Transaction conflicts - Potential data corruption
Solution: API Gateway Pattern¶
Route all database access through a single API server:
┌──────────┬──────────┬──────────┐
│ CLI │ External │ Browser │
│ │ Tools │ Client │
└─────┬────┴────┬─────┴────┬─────┘
│ │ │
└─────────┼──────────┘
↓
API Server (Single-process)
↓
DuckDB (Safe)
Benefits: - Single process accesses database (safe) - Multiple clients use safe HTTP API - All writes serialized through API - Supports concurrent reads - Enables distributed deployment
Architecture¶
Two Operating Modes¶
Mode 1: Direct Database Access (Default)¶
┌─────────────────────────────┐
│ CLI Process │
│ (cli_config.py) │
│ ↓ │
│ TaskRepository │
│ ↓ │
│ DuckDB Instance │
│ (~/.aipartnerup/data/) │
└─────────────────────────────┘
When to use: Single user, single machine, development
Commands:
Pros: - No server required - Fast (direct DB access) - Simple setup - Good for development
Cons: - Only works locally - Single-process only - Cannot share database with API
Mode 2: API Gateway (Configured)¶
┌─────────────────┐
│ CLI Process │
│ (api_client) │
└────────┬────────┘
│ HTTP/A2A
↓
┌─────────────────────────────┐
│ API Server │
│ (api/app.py) │
│ ↓ │
│ TaskRepository │
│ ↓ │
│ DuckDB Instance │
│ (Shared) │
└─────────────────────────────┘
When to use: Multi-client, production, distributed systems
Commands:
# Configure API server
apflow config init-server
# CLI automatically uses API
apflow run batch --tasks '[...]'
apflow tasks list
apflow tasks status task-001
Pros: - Multiple clients safe - Supports distributed deployment - Can run API and CLI on different machines - Production-ready concurrency
Cons: - Requires API server running - Slightly higher latency (HTTP overhead) - More complex setup
Configuration¶
Quick Setup¶
# Initialize API server configuration (recommended)
apflow config init-server
# This creates:
# - .data/config.cli.yaml with api_server_url and generated JWT secret
Manual Configuration¶
# Set API server URL
apflow config set api_server_url http://localhost:8000
# Generate authentication token
apflow config gen-token --role admin --save
Environment Override¶
# Override for specific command
export APFLOW_CONFIG_DIR=/custom/config
apflow run batch --tasks '[...]'
# Or use environment variable directly
export APFLOW_API_SERVER=http://api.example.com
export APFLOW_API_AUTH_TOKEN=your-token
Configuration File¶
config.cli.yaml:
api_server_url: http://localhost:8000
api_timeout: 30
api_retry_count: 3
auto_use_api_if_configured: true
admin_auth_token: your-jwt-token
jwt_secret: server-jwt-secret
CLI Usage with API Gateway¶
Enable API Gateway¶
Once API server is configured, CLI automatically uses it:
Run Without API (Force Direct Access)¶
If you want to skip API and use direct database access:
Or remove configuration:
Error Handling¶
Common Errors¶
Error: "Cannot connect to API server"
# Check if server is running
curl http://localhost:8000/health
# If not, start it
apflow serve start
# Or for daemon mode
apflow daemon start --port 8000
Error: "Unauthorized (401)"
# Check token
apflow config set api_auth_token <new-token> --sensitive
# Or regenerate
apflow config gen-token --role admin --save
Error: "Connection timeout"
Error: "Database locked"
# Check if multiple processes accessing DuckDB
ps aux | grep apflow
# Use API server instead to avoid conflicts
apflow config init-server
apflow serve start
Error Recovery¶
Automatic retry with exponential backoff:
Request → Fail (retried up to 3 times)
↓ Wait 1s, retry
↓ Fail, Wait 2s, retry
↓ Fail, Wait 4s, retry
↓ Final error
Configure retry behavior:
Retry Strategy¶
Default Behavior¶
- Retries: 3 attempts
- Initial delay: 1 second
- Backoff: Exponential (1s → 2s → 4s)
- Max timeout: 30 seconds per request
Configuration¶
# Increase retries for unreliable networks
apflow config set api_retry_count 5
# Increase timeout for slow servers
apflow config set api_timeout 60
Idempotent Operations¶
All CLI operations are idempotent: - Running same task twice creates duplicate (OK, different ID) - Querying same task returns same result (safe to retry) - Cancelling same task twice is safe (already cancelled)
Deployment Patterns¶
Pattern 1: Single Machine (Development)¶
┌─────────────────────────────────┐
│ Same Machine │
│ ┌─────────────┐ │
│ │ CLI │ (Manual) │
│ └──────┬──────┘ │
│ │ HTTP │
│ ┌──────▼──────────────────┐ │
│ │ API Server (daemon) │ │
│ │ (HTTP port 8000) │ │
│ │ ↓ │ │
│ │ DuckDB (shared) │ │
│ └────────────────────────┘ │
└─────────────────────────────────┘
Setup:
# Initialize configuration
apflow config init-server
# Start API server in background
apflow daemon start --port 8000
# Use CLI (automatically uses API)
apflow run batch --tasks '[...]'
apflow tasks list
Pattern 2: Distributed (Production)¶
┌──────────────────────┐
│ Client Machine A │
│ ┌────────────────┐ │
│ │ CLI Instance │ │
│ └────────┬───────┘ │
└───────────│──────────┘
│ HTTP
┌───────────▼──────────┐
│ API Server │
│ (machine B) │
│ (HTTP port 8000) │
│ ↓ │
│ DuckDB (NFS) │
└────────────────────┘
▲
┌───────────│──────────┐
│ Client Machine C │
│ ┌────────────────┐ │
│ │ CLI Instance │ │
│ │ or Web Browser │ │
│ └────────────────┘ │
└──────────────────────┘
Setup:
# On API Server Machine
export DATABASE_URL="postgresql+asyncpg://user:pass@db-server/apflow"
apflow daemon start --port 8000
# On Client Machine
apflow config set api_server http://api-server:8000
apflow config set api_auth_token <token> --sensitive
apflow run batch --tasks '[...]'
Pattern 3: Hybrid (API + CLI Mixed)¶
┌─────────────────────┐
│ API Server │
│ (HTTP clients) │
│ ↓ │
│ DuckDB │
└──────────┬──────────┘
▲
│ Direct Access
┌──────────┴──────────┐
│ CLI Instance │
│ (Local tasks) │
└─────────────────────┘
Use case: CLI tasks locally, API for remote access
Setup:
# API and CLI on same machine
# - CLI uses direct DB access (no config)
# - API uses same DuckDB
# - They share data automatically
# Start API server
apflow serve start --reload
# In another terminal, use CLI
apflow run batch --tasks '[...]'
# Both see same data
apflow tasks list # Shows tasks from CLI and API
Migration Guide¶
From Direct Access to API Gateway¶
Step 1: Start API server
Step 2: Configure CLI
Step 3: Switch to API CLI automatically detects and uses API. No code changes needed.
Step 4: Verify
Step 5: Stop direct access Once API is stable, can stop direct CLI database access:
Testing & Validation¶
Health Check¶
# Check if API server is responding
curl http://localhost:8000/health
# Check authentication
curl -H "Authorization: Bearer <token>" \
http://localhost:8000/api/tasks
Load Testing¶
# Test concurrent CLI access through API
for i in {1..10}; do
(apflow run batch$i --tasks '[...]' &)
done
wait
# All requests handled safely
apflow tasks list
Data Consistency¶
# Via API
curl -H "Authorization: Bearer <token>" \
http://localhost:8000/api/tasks
# Via CLI
apflow tasks list
# Data should be identical
FAQ¶
Q: Do I need API server for CLI?¶
A: No. CLI works independently. API server is optional for multi-client scenarios.
Q: Can CLI and API run at the same time?¶
A: Yes. When API is configured, CLI automatically routes through it. Both read/write to same database.
Q: What if API server goes down?¶
A: CLI falls back to direct database access (if configured), or fails with connection error.
Q: Is API gateway required for production?¶
A: Recommended for production because it: - Handles concurrent access safely - Supports distributed deployment - Provides audit logging - Enables request validation
Q: Can I use PostgreSQL instead of DuckDB?¶
A: Yes. Set DATABASE_URL environment variable:
export DATABASE_URL="postgresql+asyncpg://user:pass@localhost/apflow"
apflow daemon start # Uses PostgreSQL
Both CLI and API will use PostgreSQL automatically.
Q: How do I know if CLI is using API or direct DB?¶
A: Check configuration:
apflow config path
# Shows active config location
# If api_server is set, CLI uses API
# Otherwise, CLI uses direct DB
Summary¶
- ✅ CLI can work with or without API server
- ✅ API gateway solves DuckDB concurrency
- ✅ All data shared between CLI and API
- ✅ Easy to enable:
apflow config init-server - ✅ Automatic routing: no code changes needed
- ✅ Supports distributed deployment
Use direct access for development, API gateway for production.