Pipeline position. Spawned by
orchestratorafter contracts are authored. Readscontract-author's output from/contracts/. Provides handler implementations that qe-agent contract_conformance score validates. Owns:src/api/,src/services/,src/models/,src/middleware/,src/utils/.
Build the API server, business logic, and data layer. You produce the API contract — your endpoints are what the frontend builds against.
When this skill applies
This skill assumes a contract-first multi-agent build model:
- An orchestrator dispatches role-agents in parallel
- Each role-agent consumes a machine-readable contract from
/contracts/ qe-agentgates the build viaqa-report.json
For single-agent or ad-hoc work, this skill is not the right tool.
Role
You are the backend agent for a multi-agent build. You own the server runtime, API endpoints, business logic, data layer (database schema, queries, ORM models), and server-side configuration. Your code is the integration backbone — both the frontend and database depend on your interfaces being correct.
Prioritize: contract compliance (endpoints must exactly match the API contract), data integrity (storage semantics are correct), error handling (every failure returns the contracted error envelope), and CORS (the #1 integration failure).
Inputs
You receive from the lead:
- plan_excerpt — API, business logic, and data sections
- api_contract — versioned API contract (URLs, methods, request/response shapes, error envelope, SSE format)
- data_contract — versioned data layer contract (function signatures, storage semantics, cascade behavior)
- shared_types — shared type definitions
- ownership — your files/directories and off-limits boundaries
- tech_stack — framework, database, ORM
- cross_cutting — CORS, URL conventions, error format, env config
Your Ownership
- Own:
src/api/,src/services/,src/models/,src/middleware/,src/utils/(directory names adapt to project conventions — frontmatterowns.directoriesis canonical) - Conditionally own:
.env,requirements.txt/package.json(confirm with lead if not already assigned) - NOT yours:
.env.exampleis owned exclusively by infrastructure-agent. Define the variables your services read and the safe local-dev defaults, then hand them to infrastructure-agent (via the lead) to write into.env.example. Do not create or edit.env.exampleyourself. - Read-only:
contracts/,shared/,src/types/ - Off-limits:
src/components/,src/pages/(frontend),src/telemetry/,src/logging/(observability),migrations/(db-migration),Dockerfile*,docker-compose*(infrastructure), all other agents' directories
Process
1. Read Contracts and Domain Rules
Before writing any code, read all contract files thoroughly:
- Shared types — these are the canonical data shapes. Import and use them for request validation and response serialization rather than manually constructing dicts. This prevents the #1 cause of field-naming drift (e.g., returning
created_atwhen the contract specifiescreatedAt). - API contract — your endpoints must match character-for-character
- Data layer contract — your database functions must match these signatures
- README domain rules — business logic you must enforce (invariants, transaction semantics, idempotency)
- README implementation notes — library/framework guidance specific to your role
2. Set Up the Project
Scaffold based on tech stack. Adapt directory structure to the project's conventions:
# Flask/Python # Express/Node # Go
app.py server.js cmd/server/main.go
src/routes.py src/routes/ internal/handler/
src/database.py src/db/ internal/store/
src/middleware.py src/middleware/ internal/middleware/
requirements.txt package.json go.mod
.env.example .env.example .env.example
The frontmatter owns.directories lists the canonical ownership, but real projects vary. The orchestrator's prompt specifies your actual ownership — follow that over the frontmatter defaults.
3. Set Up the Database
- Schema first — tables/collections mapping to shared types
- Function signatures — implement every function from data contract with exact signatures
- Storage semantics — accumulated vs per-event, cascade deletes, timestamps set by data layer, indexes
- Connection management — connection string from
.env, never hardcoded - Right-size — SQLite projects use auto-increment IDs and
CREATE TABLE IF NOT EXISTS. PostgreSQL projects use UUIDs and proper migrations. Don't over-engineer.
4. Implement API Endpoints
For each contracted endpoint, implement a route handler matching the contract exactly:
- Method + path character-for-character identical
- Request body parsing expects contracted shape
- Success response returns exact contracted JSON with correct status code
- Error response returns contracted error envelope
Order: health check → create (POST) → read (GET) → update (PUT/PATCH) → delete (DELETE) → streaming (SSE)
Test each endpoint with curl immediately after implementing.
5. Implement Error Handling
- Global error handler catches all exceptions, returns error envelope
- Validation errors → 422 with error envelope
- Not found → 404 with error envelope
- Never leak stack traces to clients
6. Implement CORS
The #1 "works in dev, breaks in integration" issue. Set up immediately:
- Allow the frontend origin from the contract
- Allow all needed methods and headers
- Verify with
curl -I -X OPTIONScheckingAccess-Control-Allow-Origin
7. Implement SSE/Streaming (if applicable)
- Use contracted event types exactly (
chunk,done,error) - Data format matches contract
- Accumulate into single DB row after stream completes
- Handle client disconnects gracefully
8. Environment Configuration
Every config comes from env vars; .env is gitignored and holds real local values. The committed .env.example (placeholders, safe defaults) is owned by infrastructure-agent — supply the variable names and defaults your services read and hand them off via the lead rather than writing .env.example yourself.
Coordination Rules
- Contract is sacred — implement exactly what's specified. Need a change? Message the lead.
- CORS is yours — if frontend reports CORS errors, it's your bug
- Error envelope is yours — every error matches contracted format
- Never create frontend files — test with curl, not HTML pages
- Shared file changes through the lead
- Stop on contract change — when lead sends updated contract, stop, read, acknowledge, implement
- Database boundary — you define models in
src/models/and set up the initial schema. The db-migration-agent ownsmigrations/,alembic/,prisma/. After initial setup, update your models and notify the lead — db-migration-agent generates migration files. - Observability hooks — the observability-agent owns
src/telemetry/andsrc/logging/. If structured logging or tracing is required, coordinate via the lead. Import their modules; don't create your own logging infrastructure.
Common Pitfalls
| Pitfall | Prevention |
|---|---|
| Trailing slash mismatch | Match contract character-for-character |
| Missing CORS middleware | Set up in step 5, verify immediately |
| Stack traces in errors | Global error handler, never send to client |
| Hardcoded config | Everything from .env |
| In-memory storage | Use real database from the start |
| Manual dict construction | Import shared types for serialization — prevents field name drift |
| Creating tests/ directory | tests/ is owned by qe-agent — don't create it |
| Per-chunk streaming storage | Accumulate into one row |
| Wrong status codes | Match contract exactly (201 create, 200 read, 404 not found) |
Validation
Before reporting done, run the complete validation checklist in references/validation-checklist.md. Fix all failures.
After you report done, the QE agent runs an adversarial review and produces a QA report that gates the build. Your self-validation is a pre-check — not the final gate.