{"id":34753915,"url":"https://github.com/singularitylab-swufe/fastapi-template-agent","last_synced_at":"2026-02-08T11:03:56.240Z","repository":{"id":325085895,"uuid":"1099762349","full_name":"SingularityLab-SWUFE/fastapi-template-agent","owner":"SingularityLab-SWUFE","description":"Modern FastAPI Boilerplate for Agent Coding","archived":false,"fork":false,"pushed_at":"2026-01-30T14:42:17.000Z","size":169,"stargazers_count":2,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-31T07:48:55.777Z","etag":null,"topics":["agent","boilerplate","bootstrap","claude-code","fastapi","template"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SingularityLab-SWUFE.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-19T12:11:50.000Z","updated_at":"2026-01-30T14:42:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SingularityLab-SWUFE/fastapi-template-agent","commit_stats":null,"previous_names":["singularitylab-swufe/fastapi-template-agent"],"tags_count":32,"template":true,"template_full_name":null,"purl":"pkg:github/SingularityLab-SWUFE/fastapi-template-agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SingularityLab-SWUFE%2Ffastapi-template-agent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SingularityLab-SWUFE%2Ffastapi-template-agent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SingularityLab-SWUFE%2Ffastapi-template-agent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SingularityLab-SWUFE%2Ffastapi-template-agent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SingularityLab-SWUFE","download_url":"https://codeload.github.com/SingularityLab-SWUFE/fastapi-template-agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SingularityLab-SWUFE%2Ffastapi-template-agent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29228560,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-08T09:43:19.170Z","status":"ssl_error","status_checked_at":"2026-02-08T09:42:55.556Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","boilerplate","bootstrap","claude-code","fastapi","template"],"created_at":"2025-12-25T05:28:34.788Z","updated_at":"2026-02-08T11:03:56.233Z","avatar_url":"https://github.com/SingularityLab-SWUFE.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fastapi-template-agent\n\n[![GitHub stars](https://img.shields.io/github/stars/SingularityLab-SWUFE/fastapi-template-agent?style=social)](https://github.com/SingularityLab-SWUFE/fastapi-template-agent/stargazers)\n[![GitHub forks](https://img.shields.io/github/forks/SingularityLab-SWUFE/fastapi-template-agent?style=social)](https://github.com/SingularityLab-SWUFE/fastapi-template-agent/network/members)\n[![GitHub license](https://img.shields.io/github/license/SingularityLab-SWUFE/fastapi-template-agent)](https://github.com/SingularityLab-SWUFE/fastapi-template-agent/blob/main/LICENSE)\n[![Python](https://img.shields.io/badge/Python-3.12%2B-blue.svg)](https://www.python.org/downloads/)\n[![FastAPI](https://img.shields.io/badge/FastAPI-0.115%2B-005571?logo=fastapi)](https://fastapi.tiangolo.com/)\n\nModern FastAPI Boilerplate for Agent Coding\n\n## Features\n\n### Agent\n\nHave you ever been bothered by coding agent consistently wasting token usage? This repo summarizes few patterns (e.g. outputing unnecessary documentation rubbish), and offer a ready-to-use solution:\n\n- **Cost-Effective Instructions**: Well-crafted prompts and guidelines optimized for efficient and economical agent usage.\n- **Unified Instruction for all agents**: Instructions that different coding agents can consistently follow, and automatic sync in precommit hook.\n\n| Agent product | Instruction file |\n| --- | --- |\n| Codex | `AGENTS.md` (source of truth) |\n| Cline | `.clinerules` |\n| Cursor | `.cursorrules` |\n| GitHub Copilot | `.github/copilot-instructions.md` |\n\nYou can use the same pattern to your any other project that uses coding agent as well.\n\n#### Project-Level Claude Configuration\n\nFor Claude Code, configure agent behaviors in `.claude/` directory:\n\n- **Rules** (`.claude/rules.md`) - Output standards and coding guidelines\n- **Skills** (`.claude/skills/*/SKILL.md`) - Reusable workflows like backend patterns, testing guidelines, TDD cycle\n- **Commands** (`.claude/commands/*.md`) - Slash commands for subagents: `/review`, `/plan`, `/refactor`, `/tdd`\n- **Subagents** (`.claude/agents/*.md`) - Specialized agents for code review, planning, refactoring\n\nBuilt-in slash commands and automatic skill discovery in `.claude/*` are currently Claude Code-only behaviors.\n\nInspired by [everything-claude-code](https://github.com/affaan-m/everything-claude-code), few patterns were summarized to help you better utilize Claude for coding a backend project.\n\n### Backend\n\nThis repo also provides a full-featured, best-practiced backend template for building a robust/modern FastAPI application:\n\n- **Modern Tooling Stack**: State-of-the-art setup with `uv` for package management, `just` as task runner, `pre-commit` for git hooks, `pytest` for testing, and more.\n- **Authentication \u0026 Authorization**: Secure JWT-based authentication with role-based access control (RBAC).\n- **Structured Logging**: Production-ready logging with loguru - colored console output with clickable file:line references for development, JSON logs for production.\n- **Caching**: Pluggable caching system with built-in Redis support.\n- **Retry Mechanism**: Automatic retry for network errors and transient failures with exponential backoff using `tenacity`.\n- **Standardized Responses**: Middleware for consistent, unified JSON response formatting across all endpoints.\n- **Custom Error Codes**: Flexible handling of business-specific error codes and messages.\n- **Pagination**: Built-in support for paginating query results using `fastapi-pagination`.\n- **Timezone Handling**: UTC storage with presentation-layer conversion - store in UTC, query in UTC, convert to local time at presentation time.\n\n### DDD guidelines\n\nThis repo follows **Domain-Driven Design (DDD)** principles to structure the codebase for better maintainability and scalability:\n\n- **Domain Modules**: Each domain (e.g., `auth/`, `users/`) has its own module containing models(SQLTable), schemas (Request/Response), services.\n- **Representation Layer**: `http/` module handles HTTP requests, routing, and controllers. You can add `grpc`, `graphql` in this layer as needed.\n- **Core Layer**: `core/` module contains business-related domains.\n\nThe `shared/` module contains **cross-cutting concerns** used by multiple domains. Before adding code to `shared/`, it must meet these criteria:\n\n**✅ Belongs in `shared/`:**\n- Used by 3+ domains\n- Pure utility with no business logic\n- Infrastructure-level abstractions (error codes, mixins, cache keys)\n\n**❌ Does NOT belong in `shared/`:**\n- Domain-specific logic (put in domain directory)\n- Used by only 1-2 domains (co-locate with primary domain)\n- Business rules or policies\n\n## Use\n\nYou can **clone or fork** the repo as it is, or use `copier` to create a new project from the template:\n\n```bash\nuvx copier copy gh:SingularityLab-SWUFE/fastapi-template-agent my-backend-project --trust  # will do some file mv\n```\n\nThis repo is also a public template on GitHub, you can directly use the \"Use this template\" button on the repo page, and vibing with Copilot!\n\n## CI\n\nThe CI workflow runs tests on pull requests with branch names starting with `fix/`, `feat/`, or `refactor/`.\n\nTo enables/configures ci, create repository variables and secrets as needed:\n\n- `CI_JWT_SECRET`\n- `CI_APP_NAME`\n- `CI_CACHE_BACKEND`\n- `CI_DB_DATABASE`\n- `CI_DB_DRIVER`\n\n## Deploy\n\n### Docker Setup\n\n- Start services (production):\n\n```bash\ndocker compose -f docker/docker-compose.yml up --build\n```\n\n- Start services for development (mounts project and enables hot reload):\n\n```bash\ndocker compose -f docker/docker-compose.yml -f docker/docker-compose.dev.yml up --build\n```\n\nThe compose files read environment variables from the repository root `.env` file. Adjust that file for DB and cache settings as needed.\n\n**Note**: the docker compose setup will run database migrations automatically before the app starts (the app image's entrypoint runs `alembic upgrade head` against the `db` service). The repository `.env` has been updated to use a local Postgres instance (`DB__DRIVER=postgresql`, host `db`).\n\n## Agent instructing\n\nThis repo keeps a single source of truth for agent rules in `AGENTS.md`, and syncs it to:\n\n- `.clinerules`\n- `.cursorrules`\n- `.github/copilot-instructions.md`\n\nUpdate `AGENTS.md`, then run:\n\n```bash\njust agent-rules-sync\n```\n\nThe `pre-commit` hook `agent-rules` runs the same check on commit.\n\nFor Codex, Cline, Cursor, and GitHub Copilot, `.claude` slash-command execution and skill auto-discovery are not built-in.\n\n## Usage Examples\n\n### Structured Logging\n\nLogging system built with [loguru](https://github.com/Delgan/loguru) provides colored console output with clickable file:line references for development and JSON logs for production.\n\n```python\nfrom loguru import logger # just import loguru\n\n@router.post(\"/orders\")\nasync def create_order(order: Order):\n    logger.info(f\"Creating order {order.id}\")\n    try:\n        result = await process_order(order)\n        logger.bind(order_id=order.id, amount=order.total).info(\"Order completed\")\n        return result\n    except Exception as e:\n        logger.exception(\"Order processing failed\")  # Auto-captures traceback\n        raise\n```\n\n### Using Cache\n\n```python\nfrom src.cache import CacheProtocol, get_cache\n\n@router.get(\"/user/{user_id}\")\nasync def get_user(user_id: int, cache: CacheProtocol = Depends(get_cache)):\n    # Try cache first\n    cached = await cache.get(f\"user:{user_id}\")\n    if cached:\n        return {\"source\": \"cache\", \"data\": cached}\n\n    # Fetch from DB\n    user_data = fetch_user_from_db(user_id)\n\n    # Cache for 5 minutes\n    await cache.set(f\"user:{user_id}\", user_data, ttl=300)\n\n    return {\"source\": \"db\", \"data\": user_data}\n```\n\n### Response Middleware\n\nAll JSON responses automatically wrapped in `{code, msg, data}` format:\n\n```python\nfrom fastapi import APIRouter\nfrom src.http import Response\n\nrouter = APIRouter()\n\n# Option 1: Return raw data (middleware wraps it)\n@router.get(\"/items\")\nasync def list_items():\n    return [{\"id\": 1, \"name\": \"Item 1\"}]\n    # Response: {\"code\": 200, \"msg\": \"success\", \"data\": [...]}\n\n# Option 2: Explicit Response wrapper\n@router.get(\"/items/{item_id}\")\nasync def get_item(item_id: int):\n    return Response.success(data={\"id\": item_id, \"name\": \"Item\"})\n    # Response: {\"code\": 200, \"msg\": \"success\", \"data\": {...}}\n\n# Custom success message\n@router.post(\"/items\")\nasync def create_item(item: dict):\n    return Response.success(data=item, msg=\"Item created\", code=201)\n```\n\n### Custom Error Codes\n\n**1. Define error codes:**\n```python\n# src/shared/errors.py\nclass ErrorCode(IntEnum):\n    # Your custom codes\n    PRODUCT_OUT_OF_STOCK = 50101\n    PAYMENT_DECLINED = 50201\n    SHIPPING_UNAVAILABLE = 50301\n\n# mapping to HTTP status code\nERROR_CODE_TO_HTTP = {\n    ErrorCode.PRODUCT_OUT_OF_STOCK: 409,\n    ErrorCode.PAYMENT_DECLINED: 402,\n    ErrorCode.SHIPPING_UNAVAILABLE: 503,\n}\n```\n\n**2. Raise business exceptions:**\n```python\nfrom src.shared.errors import ErrorCode\nfrom src.exceptions import BusinessException\n\n@router.post(\"/orders\")\nasync def create_order(product_id: int, quantity: int):\n    stock = get_stock(product_id)\n    if stock \u003c quantity:\n        raise BusinessException(\n            ErrorCode.PRODUCT_OUT_OF_STOCK,\n            f\"Only {stock} items available\",\n            data={\"available\": stock, \"requested\": quantity}\n        )\n\n    # Response:\n    # HTTP 409\n    # {\"code\": 50101, \"msg\": \"Only 3 items available\", \"data\": {...}}\n```\n\n**3. Custom exception classes:**\n```python\n# src/exceptions.py\nclass OutOfStockException(BusinessException):\n    def __init__(self, product_id: int, available: int):\n        super().__init__(\n            code=ErrorCode.PRODUCT_OUT_OF_STOCK,\n            msg=f\"Product {product_id} out of stock\",\n            data={\"product_id\": product_id, \"available\": available}\n        )\n\n# Usage\nraise OutOfStockException(product_id=123, available=0)\n```\n\n`BusinessException` can be addressed globally by the exception handlers, so you don't need to catch it in every endpoint.\n\n### Pagination\n\nPaginate query results with built-in [`fastapi-pagination`](https://github.com/uriyyo/fastapi-pagination) support.\n\n**Usage:**\n```python\nfrom fastapi import APIRouter, Depends\nfrom fastapi_pagination import Page\nfrom fastapi_pagination.ext.sqlalchemy import apaginate\nfrom sqlalchemy import select\nfrom sqlalchemy.ext.asyncio import AsyncSession\n\nfrom src.auth.schemas import User\nfrom src.session import get_session\n\nrouter = APIRouter()\n\n@router.get(\"/users\", response_model=Page[User])\nasync def list_users(session: AsyncSession = Depends(get_session)):\n    return await apaginate(session, select(User))\n    # Response: {\"code\": 200, \"msg\": \"success\", \"data\": {\"items\": [...], \"total\": 100, \"page\": 1, \"size\": 50}}\n```\n\n### Protected Routes\n\nAuthentication is well-implemented by `fastapi-users`, so use `current_user` and `current_superuser` dependencies to register route login or superuser access:\n\n```python\nfrom fastapi import APIRouter, Depends\nfrom src.auth import current_user, current_superuser\nfrom src.auth.schemas import User\n\nrouter = APIRouter()\n\n@router.get(\"/profile\")\nasync def get_profile(user: User = Depends(current_user)):\n    return {\"username\": user.username, \"email\": user.email}\n\n@router.delete(\"/users/{user_id}\")\nasync def delete_user(user_id: int, admin: User = Depends(current_superuser)):\n    # Only superusers can access\n    delete_user_from_db(user_id)\n    return {\"deleted\": user_id}\n```\n\nWe recommend you use RBAC related dependencies for permission control. Try avoid use `current_superuser`.\n\n### RBAC (Role-Based Access Control)\n\nIf your views require more fine-grained permission control, use the `require_permissions`, `require_roles`, and `owner_or_perm` dependencies:\n\n```python\nfrom fastapi import APIRouter, Depends\nfrom src.auth import require_permissions, require_roles, owner_or_perm\n\nrouter = APIRouter()\n\n# Require specific permission\n# Note: you do not need to set current_user dependency here, as require_permissions does it internally\n@router.post(\"/users\", dependencies=[Depends(require_permissions(\"user:create\"))])\nasync def create_user(data: dict):\n    return {\"created\": True}\n\n# Require multiple permissions (all)\n@router.delete(\n    \"/users/{user_id}\",\n    dependencies=[Depends(require_permissions(\"user:delete\", \"audit:log\", match=\"all\"))]\n)\nasync def delete_user(user_id: int):\n    return {\"deleted\": user_id}\n\n# Require any of multiple permissions\n@router.get(\n    \"/users/{user_id}\",\n    dependencies=[Depends(require_permissions(\"user:read\", \"user:write\", match=\"any\"))]\n)\nasync def get_user(user_id: int):\n    return {\"id\": user_id}\n\n# Require specific role\n# You can register an endpoint that both needs permission check and role check\n@router.get(\"/admin/stats\", dependencies=[Depends(require_roles(\"admin\"))])\nasync def admin_stats():\n    return {\"stats\": \"...\"}\n\n# Owner or permission check\nasync def get_post_owner_id(post_id: int) -\u003e int:\n    # Fetch owner_id from database\n    return fetch_post_owner(post_id)\n\n@router.put(\n    \"/posts/{post_id}\",\n    dependencies=[Depends(owner_or_perm(get_post_owner_id, [\"post:edit\"]))]\n)\nasync def update_post(post_id: int, data: dict):\n    # User can edit if they own the post OR have \"post:edit\" permission\n    return {\"updated\": True}\n```\n\n**Permission Format:**\n- `required_perm` must be `module:action` (e.g., `\"user:read\"`, `\"post:delete\"`)\n- `user_perm` can be `module` (full module access) or `module:action` (specific action)\n- `user_perm=\"user\"` matches any `required_perm=\"user:*\"`\n- Use `bypass_superuser=True` to allow superusers to bypass checks\n\n### Dependency Injection settings\n\n`settings` can be injected into your path operation functions using `Depends`:\n\n```python\nfrom fastapi import Depends\nfrom src.config import Settings, get_settings\nfrom src.cache import CacheProtocol, get_cache\n\nasync def my_handler(\n    settings: Settings = Depends(get_settings),\n    cache: CacheProtocol = Depends(get_cache)\n):\n    max_retries = settings.app.max_retries\n    await cache.set(\"config\", settings.app.name)\n```\n\nThis allows you to test different configurations by overriding the `get_settings` dependency in your tests.\n\n### Retry\n\nAutomatic retry for network errors, timeouts, and 5xx responses using [tenacity](https://github.com/jd/tenacity). Retries up to 3 times with exponential backoff (1-10 seconds).\n\n```python\nimport httpx\nfrom src.retry import retry_on_network, async_retry_on_network\n\n# Decorator for sync functions\n@retry_on_network()\ndef fetch_data():\n    response = httpx.get(\"https://api.example.com/data\")\n    response.raise_for_status()\n    return response.json()\n\n# Decorator for async functions\n@retry_on_network()\nasync def fetch_user(user_id: int):\n    async with httpx.AsyncClient() as client:\n        response = await client.get(f\"https://api.example.com/users/{user_id}\")\n        response.raise_for_status()\n        return response.json()\n\n# Manual retry control (async)\nasync def fetch_with_manual_retry():\n    async for attempt in async_retry_on_network():\n        with attempt:\n            async with httpx.AsyncClient() as client:\n                response = await client.get(\"https://api.example.com/data\")\n                response.raise_for_status()\n                return response.json()\n```\n\n### Testing\n\n`pytest` is used as the testing framework.\n\nWe use `locust` for integrated load testing. User behaviors are defined in `tests/locustfile.py`, you can use it to simulate concurrent users, and get QPS/response metrics for analysis.\n\n## Development Setup\n\n- Python \u003e= 3.12\n- [uv](https://github.com/astral-sh/uv)\n- [just](https://github.com/casey/just)\n\n### Install uv\n\n```bash\ncurl -LsSf https://astral.sh/uv/install.sh | sh\n```\n\n### Install just\n\n`just` is used to simplify command execution. You can also refer to commands in `justfile` directly. Installation options:\n\n```bash\ncargo install just\n```\n\nOr\n\n```bash\ncurl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin\n```\n\n## Contributing\n\n**Read [CONTRIBUTIONS.md](/CONTRIBUTIONS.md) before contributing.**\n\n### Quick Start for Contributors\n\n1. **Install dependencies**\n   ```bash\n   just dev\n   ```\n\n2. **Install pre-commit hooks**\n   ```bash\n   just hooks\n   ```\n\n3. **Create an issue first**\n   - Every PR requires a corresponding issue\n   - Discuss approach and scope before writing code\n\n4. **Run checks before submitting PR**\n   ```bash\n   just check\n   just test\n   ```\n\nFor Chinese contributors, since this is a open-source project, please ensure that your commit messages or issues/PRs can be understood by the global community. It's recommended to write in English or provide English version alongside Chinese descriptions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsingularitylab-swufe%2Ffastapi-template-agent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsingularitylab-swufe%2Ffastapi-template-agent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsingularitylab-swufe%2Ffastapi-template-agent/lists"}