This document provides step-by-step tutorials for common tasks using the .opencode system.
Create a complete user registration endpoint with validation, password hashing, and JWT token generation.
- Python project with FastAPI installed
.opencodesystem configured
Start with a clear, specific request:
Create a POST /api/v1/auth/register endpoint with:
- Email validation (valid format, unique check)
- Password validation (min 8 chars, requires uppercase)
- Password hashing with bcrypt
- Returns JWT token on success
- Returns 409 for duplicate email
- Returns 422 for validation errors
The agent will automatically load relevant skills:
skill(name="python-fastapi")
skill(name="python-backend")The agent uses python-scout to find existing patterns:
task(
subagent_type="explore",
description="Find existing auth patterns",
prompt="Find existing authentication endpoints, user models, and schema patterns"
)Expected findings:
src/api/v1/endpoints/- Existing endpointssrc/models/user.py- User modelsrc/schemas/- Pydantic schemassrc/core/security.py- Existing security utilities
The agent delegates to python-coder:
task(
subagent_type="general",
description="Create registration endpoint",
prompt="""Create user registration endpoint:
Files to create/modify:
1. src/schemas/auth.py - Add RegisterRequest, RegisterResponse schemas
2. src/api/v1/endpoints/auth.py - Add POST /register endpoint
3. src/services/auth.py - Add register_user function
Requirements:
- Email validation with EmailStr
- Password min 8 chars, must contain uppercase
- Use bcrypt for password hashing (passlib)
- Generate JWT token on success
- Return 409 Conflict for duplicate email
Follow patterns from:
- src/api/v1/endpoints/users.py for endpoint structure
- src/core/security.py for hashing and JWT
"""
)Expected files created:
src/schemas/auth.py
from pydantic import BaseModel, EmailStr, Field
class RegisterRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=8)
class RegisterResponse(BaseModel):
id: int
email: str
access_token: str
token_type: str = "bearer"src/api/v1/endpoints/auth.py
from fastapi import APIRouter, HTTPException, status
from app.schemas.auth import RegisterRequest, RegisterResponse
from app.services.auth import register_user
from app.api.deps import DbSession
router = APIRouter()
@router.post("/register", response_model=RegisterResponse)
async def register(data: RegisterRequest, db: DbSession):
result = await register_user(data, db)
if result is None:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Email already registered"
)
return result# Type checking
uv run mypy src/
# Linting
uv run ruff check .
# Run tests (if created)
uv run pytest tests/api/test_auth.py -vWrite comprehensive tests for the registration endpoint created in Tutorial 1.
Write tests for the registration endpoint in src/api/v1/endpoints/auth.py:
- Test successful registration
- Test duplicate email rejection
- Test invalid email format
- Test weak password rejection
- Use pytest-asyncio
- Mock the database
skill(name="python-testing-general")The agent delegates to python-tester:
task(
subagent_type="general",
description="Write registration tests",
prompt="""Write tests for the registration endpoint:
Test file: tests/api/v1/test_auth.py
Test cases needed:
1. test_register_success - Valid data returns 200 with token
2. test_register_duplicate_email - Returns 409 for duplicate
3. test_register_invalid_email - Returns 422 for bad email
4. test_register_weak_password - Returns 422 for weak password
Use:
- pytest-asyncio for async tests
- httpx AsyncClient for API testing
- Mock database session
Follow patterns from:
- tests/api/test_users.py
"""
)Expected test file:
# tests/api/v1/test_auth.py
import pytest
from httpx import AsyncClient, ASGITransport
from app.main import app
@pytest.fixture
async def client():
async with AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test"
) as client:
yield client
@pytest.mark.asyncio
async def test_register_success(client: AsyncClient):
response = await client.post("/api/v1/auth/register", json={
"email": "test@example.com",
"password": "SecurePass123"
})
assert response.status_code == 200
data = response.json()
assert "access_token" in data
assert data["email"] == "test@example.com"
@pytest.mark.asyncio
async def test_register_duplicate_email(client: AsyncClient):
# First registration
await client.post("/api/v1/auth/register", json={
"email": "dupe@example.com",
"password": "SecurePass123"
})
# Second registration with same email
response = await client.post("/api/v1/auth/register", json={
"email": "dupe@example.com",
"password": "SecurePass123"
})
assert response.status_code == 409
@pytest.mark.asyncio
async def test_register_invalid_email(client: AsyncClient):
response = await client.post("/api/v1/auth/register", json={
"email": "not-an-email",
"password": "SecurePass123"
})
assert response.status_code == 422
@pytest.mark.asyncio
async def test_register_weak_password(client: AsyncClient):
response = await client.post("/api/v1/auth/register", json={
"email": "test2@example.com",
"password": "weak"
})
assert response.status_code == 422uv run pytest tests/api/v1/test_auth.py -v
# With coverage
uv run pytest tests/api/v1/test_auth.py --cov=src/api/v1/endpoints/auth.pyPerform a security review of authentication code.
Review src/core/security.py and src/api/v1/endpoints/auth.py for security issues:
- Check for hardcoded secrets
- Verify password hashing strength
- Check JWT implementation
- Look for SQL injection
- Verify input validation
The agent delegates to python-reviewer:
task(
subagent_type="general",
description="Security review of auth code",
prompt="""Review these files for security issues:
Files:
- src/core/security.py
- src/api/v1/endpoints/auth.py
Focus on:
1. Hardcoded secrets or credentials
2. Password hashing implementation
3. JWT token generation and validation
4. SQL injection vulnerabilities
5. Input validation completeness
6. Error message information leakage
Provide detailed report with:
- Critical issues (must fix)
- Warnings (should fix)
- Suggestions (consider fixing)
- Positive notes (what's done well)
"""
)Expected output:
## Code Review: Authentication Security
### Summary
Generally well-implemented authentication with some areas needing attention.
### Critical Issues π΄
1. **[security.py:15]** JWT secret key should be from environment
- Problem: Using hardcoded secret key
- Fix: Load from environment variable
\`\`\`python
# BAD
SECRET_KEY = "my-secret-key"
# GOOD
import os
SECRET_KEY = os.environ["SECRET_KEY"]
\`\`\`
2. **[auth.py:42]** No rate limiting on login endpoint
- Problem: Vulnerable to brute force attacks
- Fix: Add SlowAPI rate limiter
### Warnings π‘
1. **[security.py:30]** Consider increasing bcrypt rounds
- Current: 12 rounds
- Recommendation: 14 rounds for better security
### Suggestions π’
1. **[auth.py:25]** Add password strength validation
- Benefit: Prevents weak passwords
### Positive Notes β
- Good use of passlib with bcrypt
- Proper exception handling
- Type hints throughout
- Input validation with PydanticCreate a custom skill for API documentation generation.
mkdir -p .opencode/skills/api-documentationCreate .opencode/skills/api-documentation/SKILL.md:
---
name: api-documentation
description: "Generate OpenAPI documentation and markdown docs for FastAPI endpoints"
license: MIT
metadata:
audience: developers
workflow: documentation
---
# API Documentation
Generate comprehensive documentation for FastAPI endpoints.
## When to Use This Skill
- Documenting new endpoints
- Creating API reference docs
- Generating OpenAPI examples
- Writing endpoint usage guides
## Documentation Patterns
### Endpoint Documentation
\`\`\`python
@router.get(
"/users/{user_id}",
response_model=UserResponse,
summary="Get user by ID",
description="Retrieve a single user by their unique identifier.",
responses={
200: {"description": "User found"},
404: {"description": "User not found"},
}
)
async def get_user(user_id: int, db: DbSession):
...
\`\`\`
### Markdown Documentation
\`\`\`markdown
## GET /api/v1/users/{user_id}
Retrieve a single user by ID.
### Parameters
| Name | Type | Required | Description |
|------|------|----------|-------------|
| user_id | integer | Yes | User's unique identifier |
### Responses
| Code | Description |
|------|-------------|
| 200 | User object |
| 404 | User not found |
### Example
\`\`\`bash
curl -X GET "http://api.example.com/api/v1/users/123"
\`\`\`
\`\`\`
## Best Practices
1. Include example requests and responses
2. Document all error codes
3. Use clear, concise descriptions
4. Keep examples up-to-date with codeEdit .opencode/config/agent-metadata.json:
{
"skills": {
"api-documentation": {
"id": "api-documentation",
"name": "API Documentation",
"version": "1.0.0",
"triggers": ["documentation", "openapi", "docs", "swagger"]
}
}
}Generate documentation for the registration endpoint
The agent should now:
- Detect "documentation" keyword
- Load
skill(name="api-documentation") - Follow the documentation patterns
Safely refactor a service to use the repository pattern while maintaining test coverage.
Refactor src/services/user.py to use the repository pattern:
- Create src/repositories/user.py
- Move database operations to repository
- Keep business logic in service
- Ensure existing tests still pass
task(
subagent_type="explore",
description="Find current user service implementation",
prompt="Find src/services/user.py and related test files"
)task(
subagent_type="general",
description="Refactor to repository pattern",
prompt="""Refactor user service to repository pattern:
Current: src/services/user.py (contains both DB and business logic)
Target:
1. src/repositories/user.py - Database operations only
2. src/services/user.py - Business logic, uses repository
Steps:
1. Create src/repositories/user.py with:
- UserRepository class
- get_by_id, get_by_email, create, update methods
2. Modify src/services/user.py:
- Remove direct DB operations
- Inject UserRepository
- Keep business logic methods
3. Update tests if needed
4. Ensure all existing tests pass
Follow patterns from:
- src/repositories/item.py (if exists)
"""
)# Run all user-related tests
uv run pytest tests/services/test_user.py tests/repositories/test_user.py -v
# Check type safety
uv run mypy src/services/user.py src/repositories/user.py
# Verify coverage maintained
uv run pytest --cov=src/services/user.py --cov=src/repositories/user.py