---
type: skill
domain: development
links: [Corpus_Callosum/CONSTITUTION.md, PULSE_OS.md]
---

# API_GURU.md
> **ROLE:** INTEGRATION LEAD
> **TRIGGER:** "CONNECT" / "API" / "ENDPOINT"

## Step-by-Step Protocol
1. **Query existing APIs** — run `brain_query.py --query "API design endpoints"`. Map all current endpoints, methods, and auth mechanisms before adding new ones.
2. **Design with REST naming conventions** — nouns for resources (`/agents`, `/tasks`), not verbs (`/getAgent`). Plural nouns. Nested resources max 2 levels deep (`/agents/{id}/tasks`). Use HTTP verbs: GET (read), POST (create), PUT (full replace), PATCH (partial update), DELETE (remove).
3. **Implement pagination, filtering, rate limiting** — cursor-based pagination for large sets (`?cursor=abc&limit=50`, default limit=20, max=100). Rate limit: 100 req/min per agent with `429 Too Many Requests` + `Retry-After` header.
4. **Version the API** — URL path versioning (`/v1/agents`). Never break existing clients. Deprecation policy: announce 30 days before removal, return `Sunset` header on deprecated endpoints.
5. **Validate and document** — Pydantic models for every request/response body. OpenAPI spec auto-generated via FastAPI. Every endpoint has example request + response in docs.

## Metrics & Thresholds
- **Response time:** p50 <100ms, p99 <500ms for reads; p99 <1s for writes
- **Rate limit:** 100 req/min default, 1000 req/min authenticated, `429` + `Retry-After` header
- **Pagination:** default page size 20, max 100, cursor-based (not offset) for >1000 records
- **Uptime target:** 99.9% (8.7h downtime/year max)
- **Error response consistency:** 100% of errors return `{"error": {"code": str, "message": str}}`

## Good Example
```python
from fastapi import FastAPI, Query, HTTPException
from pydantic import BaseModel

class TaskResponse(BaseModel):
    task_id: str
    title: str
    status: str  # "open" | "claimed" | "done"
    domain: str

class PaginatedTasks(BaseModel):
    data: list[TaskResponse]
    next_cursor: str | None
    total: int

@app.get("/v1/tasks", response_model=PaginatedTasks)
async def list_tasks(
    status: str = Query(None, regex="^(open|claimed|done)$"),
    cursor: str = Query(None),
    limit: int = Query(20, ge=1, le=100),
):
    """Cursor-based pagination with filtering."""
    tasks, next_cursor, total = await task_store.list(
        status=status, cursor=cursor, limit=limit
    )
    return PaginatedTasks(data=tasks, next_cursor=next_cursor, total=total)
```

## Anti-Patterns
1. **Verb-based URLs** — `/getTask`, `/deleteAgent` breaks REST; use HTTP methods + noun resources.
2. **Offset pagination on large datasets** — `OFFSET 10000` is O(n) in most DBs; use cursor-based (keyset) pagination.
3. **Unversioned breaking changes** — removing/renaming a field silently breaks every consumer. Always version.

## Tools to Use
- `python Autonomic_System/Utilities/Tools/brain_query.py --query "API design REST"` — find prior API decisions
- `python Autonomic_System/Utilities/Tools/pulse_relay.py --tasks "API Contract Test:development:standard"` — delegate contract validation
- `python Autonomic_System/Utilities/Tools/pulse_save.py --agent api_guru --learnings "what you learned"` — save API design decisions

## Verification Checklist
- [ ] All endpoints use noun resources with HTTP verbs (no verb URLs)
- [ ] Pagination is cursor-based with `limit` capped at 100
- [ ] Rate limiting returns `429` with `Retry-After` header
- [ ] Every endpoint has a Pydantic request/response model
- [ ] API is versioned (`/v1/`) and deprecation uses `Sunset` header
