# Skill: Register a Pipeline with the API

Use when you want to expose your pipeline over HTTP — synchronous POST, SSE streaming,
or WebSocket.

## How the API Works

`arccrew/api/app.py` creates a FastAPI app with:
- `POST /api/run` — synchronous pipeline run, returns JSON when complete
- `GET /api/run/{run_id}/stream` — SSE stream of a running pipeline
- `WS /api/ws` — WebSocket for real-time bidirectional communication
- `GET /api/pipelines` — list all registered pipelines
- `POST /api/auth/token` — get a JWT token (only when `API_AUTH_ENABLED=true`)

When `arccrew serve` starts, it auto-loads `pipeline.py` from the project root. Any
`pipeline_registry.register()` calls at module level in that file are executed automatically.

## Registering Your Pipeline

At the bottom of your `pipeline.py`, call `pipeline_registry.register()`:

```python
from arccrew.api.deps import pipeline_registry

pipeline_registry.register("my_pipeline", create_my_pipeline)

# Multiple pipelines in the same project:
pipeline_registry.register("another_pipeline", create_another_pipeline)
```

Do NOT modify `arccrew/api/app.py` — it is a library file.

`pipeline_registry.register(name, factory_fn)` takes:
- `name`: string identifier used in API requests
- `factory_fn`: a callable that returns a compiled LangGraph — called once on first use

## `PipelineRequest` Schema

The request body for `POST /api/run`:

```json
{
  "pipeline": "my_pipeline",
  "tasks": [
    {"description": "First task description"},
    {"description": "Second task description"}
  ],
  "options": {
    "dry_run": false,
    "workspace_dir": "/tmp/my_workspace"
  }
}
```

Fields:
- `pipeline` (required): name used in `pipeline_registry.register()`
- `tasks` (required): list of task dicts; agents read `tasks[current_task_index]`
- `options.dry_run`: if `true`, agents can check `state.get("dry_run")` to skip side effects
- `options.workspace_dir`: overrides `WORKSPACE_DIR` from `.env` for this run

## curl Examples

### Synchronous Run (POST /api/run)

```bash
# Basic run
curl -X POST http://localhost:8000/api/run \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": "my_pipeline",
    "tasks": [{"description": "Research AI trends in healthcare"}]
  }'

# With options
curl -X POST http://localhost:8000/api/run \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": "my_pipeline",
    "tasks": [
      {"description": "Task one"},
      {"description": "Task two"}
    ],
    "options": {
      "dry_run": false,
      "workspace_dir": "/tmp/my_run_123"
    }
  }'
```

Response:
```json
{
  "run_id": "run-20250324-143022-abc123",
  "status": "completed",
  "pipeline": "my_pipeline",
  "results": [{"task_index": 0, "summary": "...", "files_created": [...]}],
  "duration_seconds": 12.4
}
```

### SSE Streaming (GET /api/run/{run_id}/stream)

```bash
# Start a run and get the run_id
RUN_ID=$(curl -s -X POST http://localhost:8000/api/run \
  -H "Content-Type: application/json" \
  -d '{"pipeline": "my_pipeline", "tasks": [{"description": "test"}]}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['run_id'])")

# Stream events (SSE)
curl -N http://localhost:8000/api/run/$RUN_ID/stream
```

SSE events look like:
```
data: {"event": "agent_start", "agent": "researcher", "timestamp": "..."}
data: {"event": "agent_complete", "agent": "researcher", "elapsed": 4.2}
data: {"event": "pipeline_complete", "results": [...]}
```

### WebSocket

```bash
# Using wscat (npm install -g wscat)
wscat -c ws://localhost:8000/api/ws

# Send a run request over WebSocket
{"pipeline": "my_pipeline", "tasks": [{"description": "test"}]}
```

## Viewing Registered Pipelines

```bash
curl http://localhost:8000/api/pipelines
```

Response:
```json
{
  "pipelines": ["researcher_writer", "my_pipeline"],
  "count": 2
}
```

If your pipeline is not listed, the registration in `pipeline.py` did not run — check for
import errors or exceptions thrown during module load (check server logs on startup).

## Authentication (Optional)

Auth is disabled by default. To enable for production:

```bash
# .env
API_AUTH_ENABLED=true
API_SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
API_TOKEN_EXPIRE_MINUTES=1440   # 24 hours
```

### Get a Token

```bash
curl -X POST http://localhost:8000/api/auth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=admin&password=your_password"
```

Response:
```json
{"access_token": "eyJ...", "token_type": "bearer"}
```

### Use the Token

```bash
curl -X POST http://localhost:8000/api/run \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJ..." \
  -d '{"pipeline": "my_pipeline", "tasks": [{"description": "test"}]}'
```

## Rate Limiting

Default: 60 requests/minute per IP with a burst of 10.

```bash
# .env
API_RATE_LIMIT=60         # requests per minute (0 = disabled)
API_RATE_LIMIT_BURST=10   # burst allowance
```

## Starting the API Server

```bash
# Development (hot reload)
arccrew serve --reload

# Production
arccrew serve

# With custom port
arccrew serve --port 9000
```

The API docs are at: http://localhost:8000/docs (Swagger UI)

## CORS Configuration

For browser clients:

```bash
# .env
API_CORS_ORIGINS=https://myapp.com,https://staging.myapp.com

# Or allow all (development only)
API_CORS_ORIGINS=*
```

## Accessing the API Interactively

Visit http://localhost:8000/docs for the Swagger UI — you can test all endpoints
directly in the browser without curl.
