-
Notifications
You must be signed in to change notification settings - Fork 18
docs: optimize AI agent instructions for token efficiency #471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,222 +1,78 @@ | ||
| # Copilot Instructions for python-samples-fastapi-restful | ||
| # GitHub Copilot Instructions | ||
|
|
||
| ## Project Overview | ||
| > **⚡ Token Efficiency Note**: This is a minimal pointer file (~500 tokens, auto-loaded by Copilot). | ||
| > For complete operational details, reference: `#file:AGENTS.md` (~2,500 tokens, loaded on-demand) | ||
| > For specialized knowledge, use: `#file:SKILLS/<skill-name>/SKILL.md` (loaded on-demand when needed) | ||
|
|
||
| This is a RESTful API proof of concept built with **Python 3.13** and **FastAPI**. The application manages football player data with full CRUD operations, featuring async SQLAlchemy ORM, in-memory caching, and SQLite database storage. | ||
| ## 🎯 Quick Context | ||
|
|
||
| ## Tech Stack | ||
| **Project**: FastAPI REST API demonstrating modern Python async patterns | ||
| **Stack**: Python 3.13 • FastAPI • SQLAlchemy (async) • SQLite • Docker • pytest | ||
| **Pattern**: Routes → Services → Database (layered architecture) | ||
| **Philosophy**: Learning-focused PoC emphasizing async/await and type safety | ||
|
|
||
| - **Framework**: FastAPI 0.123.0 with standard dependencies | ||
| - **Database**: SQLite with async support (`aiosqlite 0.21.0`) | ||
| - **ORM**: SQLAlchemy 2.0.44 (async) | ||
| - **Caching**: aiocache 0.12.3 (SimpleMemoryCache) | ||
| - **Testing**: pytest 9.0.1, pytest-cov 7.0.0, pytest-sugar 1.1.1, gevent 25.9.1 | ||
| - **Linting**: flake8 7.3.0, black 25.11.0 | ||
| - **Python Version**: 3.13.3 (see `.python-version`) | ||
| - **Server**: uvicorn (included in FastAPI standard dependencies) | ||
| - **Container**: Docker with multi-stage builds, Docker Compose | ||
| ## 📐 Core Conventions | ||
|
|
||
| ## Project Structure | ||
| - **Naming**: snake_case for functions/variables, PascalCase for classes | ||
| - **Type Hints**: Mandatory throughout (enforced by mypy if enabled) | ||
| - **Async**: All I/O operations use `async`/`await` | ||
| - **Testing**: pytest with fixtures and async support | ||
| - **Formatting**: black (opinionated), flake8 (linting) | ||
|
|
||
| ``` | ||
| ├── main.py # FastAPI app entry point, lifespan handler, router registration | ||
| ├── databases/ | ||
| │ └── player_database.py # Async engine, sessionmaker, Base, session generator | ||
| ├── models/ | ||
| │ └── player_model.py # Pydantic models for API request/response validation | ||
| ├── schemas/ | ||
| │ └── player_schema.py # SQLAlchemy ORM table schema definitions | ||
| ├── routes/ | ||
| │ ├── player_route.py # Player CRUD endpoints with caching | ||
| │ └── health_route.py # Health check endpoint | ||
| ├── services/ | ||
| │ └── player_service.py # Async database CRUD operations | ||
| ├── tests/ | ||
| │ ├── conftest.py # pytest fixtures (TestClient) | ||
| │ ├── test_main.py # Test suite for all endpoints | ||
| │ └── player_stub.py # Test data stubs | ||
| ├── storage/ # SQLite database file (seeded) | ||
| ├── scripts/ | ||
| │ ├── entrypoint.sh # Docker entrypoint for DB initialization | ||
| │ └── healthcheck.sh # Docker health check script | ||
| └── postman_collections/ # Postman collection for API testing | ||
| ``` | ||
|
|
||
| ## Key Architectural Patterns | ||
|
|
||
| 1. **Layered Architecture**: Routes → Services → Database | ||
| 2. **Dependency Injection**: `AsyncSession` via `Depends(generate_async_session)` | ||
| 3. **Pydantic for Validation**: `PlayerModel` with camelCase aliasing (`to_camel`) | ||
| 4. **SQLAlchemy ORM**: `Player` schema mapped to `players` table | ||
| 5. **Caching**: In-memory cache (10 min TTL) with `X-Cache` headers (HIT/MISS) | ||
| 6. **Async/Await**: All database operations are async | ||
|
|
||
| ## Coding Guidelines | ||
| ## 🏗️ Architecture at a Glance | ||
|
|
||
| ### Python Style (Strict Enforcement) | ||
|
|
||
| - **Formatter**: Black (line length: 88, target: Python 3.13) | ||
| - **Linter**: flake8 (max-complexity: 10, ignores: E203, W503) | ||
| - **Run Before Commit**: `black .` and `flake8` | ||
| - **Imports**: SQLAlchemy 2.0+ style (use `select()` not legacy `Query`) | ||
| - **Docstrings**: Google-style docstrings for all modules, classes, and functions | ||
| - **Type Hints**: Use type annotations for function parameters and return values | ||
| ```text | ||
| Route → Service → Database | ||
| ↓ ↓ | ||
| Cache Session | ||
| ``` | ||
|
|
||
| ### File Exclusions | ||
| - **Routes**: FastAPI endpoints with dependency injection | ||
| - **Services**: Async database operations via SQLAlchemy | ||
| - **Database**: SQLite with async support (`aiosqlite`) | ||
| - **Models**: Pydantic for validation, SQLAlchemy for ORM | ||
| - **Cache**: aiocache SimpleMemoryCache (TTL: 600s / 10 min) | ||
|
|
||
| Black and flake8 exclude: | ||
| - `.venv`, `.git`, `.github`, `.pytest_cache`, `__pycache__` | ||
| - `assets/`, `htmlcov/`, `postman_collections/`, `scripts/`, `storage/` | ||
| - Exception: `tests/test_main.py` allows E501 (long lines for test names) | ||
| ## ✅ Copilot Should | ||
|
|
||
| ### Commit Conventions | ||
| - Generate idiomatic async FastAPI code with proper type hints | ||
| - Use SQLAlchemy async APIs (`select()`, `scalars()`, `session.commit()`) | ||
| - Follow dependency injection pattern with `Depends()` | ||
| - Write tests with pytest async fixtures | ||
| - Apply Pydantic models for request/response validation | ||
| - Use structured logging (avoid print statements) | ||
| - Implement proper HTTP status codes and responses | ||
|
|
||
| Follow **Conventional Commits** (enforced by commitlint): | ||
| - `feat:` for new features | ||
| - `fix:` for bug fixes | ||
| - `chore:` for maintenance/tooling | ||
| - Max header length: 80 characters | ||
| - Max body line length: 80 characters | ||
| ## 🚫 Copilot Should Avoid | ||
|
|
||
| ## Common Commands | ||
| - Synchronous database operations | ||
| - Mixing sync and async code | ||
| - Missing type hints on functions | ||
| - Using `print()` instead of logging | ||
| - Creating routes without caching consideration | ||
| - Ignoring Pydantic validation | ||
|
|
||
| ### Local Development | ||
| ## ⚡ Quick Commands | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| pip install -r requirements.txt | ||
| pip install -r requirements-lint.txt | ||
| pip install -r requirements-test.txt | ||
|
|
||
| # IMPORTANT: Activate virtual environment before running commands | ||
| source .venv/bin/activate | ||
|
|
||
| # Start server (auto-reload on port 9000) | ||
| uvicorn main:app --reload --port 9000 | ||
|
|
||
| # Access interactive API docs | ||
| # http://localhost:9000/docs | ||
| # Run with hot reload | ||
| uvicorn main:app --reload --host 0.0.0.0 --port 9000 | ||
|
|
||
| # Format code (must run from venv) | ||
| black . | ||
| # Test with coverage | ||
| pytest --cov=. --cov-report=term-missing | ||
|
|
||
| # Lint code (must run from venv) | ||
| flake8 . | ||
|
|
||
| # Run tests | ||
| pytest -v | ||
|
|
||
| # Run tests with coverage | ||
| pytest --cov=./ --cov-report=xml --cov-report=term | ||
| ``` | ||
|
|
||
| ### Docker | ||
|
|
||
| ```bash | ||
| # Build image | ||
| docker compose build | ||
|
|
||
| # Start app (initializes DB from seed on first run) | ||
| # Docker | ||
| docker compose up | ||
|
|
||
| # Stop app | ||
| docker compose down | ||
|
|
||
| # Reset database (removes volume) | ||
| docker compose down -v | ||
| # Swagger: http://localhost:9000/docs | ||
| ``` | ||
|
|
||
| ## Database Details | ||
|
|
||
| - **Path**: Controlled by `STORAGE_PATH` env var (default: `./storage/players-sqlite3.db`) | ||
| - **Docker Volume**: Persistent volume at `/storage/` in container | ||
| - **Initialization**: On first Docker run, `entrypoint.sh` copies seed DB from `/app/hold/` to `/storage/` | ||
| - **Schema**: Single `players` table with columns: id (PK), firstName, middleName, lastName, dateOfBirth, squadNumber (unique), position, abbrPosition, team, league, starting11 | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| | Method | Path | Description | Cache | | ||
| |--------|-------------------------------------|------------------------------|-------| | ||
| | GET | `/health` | Health check | No | | ||
| | GET | `/players/` | Get all players | Yes | | ||
| | GET | `/players/{player_id}` | Get player by ID | No | | ||
| | GET | `/players/squadnumber/{squad_number}` | Get player by squad number | No | | ||
| | POST | `/players/` | Create new player | Clears| | ||
| | PUT | `/players/{player_id}` | Update existing player | Clears| | ||
| | DELETE | `/players/{player_id}` | Delete player | Clears| | ||
|
|
||
| **Cache Notes**: | ||
| - Cache key: `"players"`, TTL: 600s (10 min) | ||
| - Cache is cleared on POST/PUT/DELETE operations | ||
| - Response header `X-Cache: HIT` or `MISS` indicates cache status | ||
|
|
||
| ## Testing | ||
|
|
||
| - **Framework**: pytest with `TestClient` from FastAPI | ||
| - **Fixture**: `client` fixture in `conftest.py` (function scope for test isolation) | ||
| - **Coverage Target**: 80% (configured in `codecov.yml`) | ||
| - **Test Data**: Use stubs from `tests/player_stub.py` | ||
| - **Warnings**: DeprecationWarning from httpx is suppressed in conftest | ||
|
|
||
| ## CI/CD Pipeline | ||
|
|
||
| GitHub Actions workflow (`.github/workflows/python-app.yml`): | ||
| 1. **Lint Job**: Commitlint → Flake8 → Black (check mode) | ||
| 2. **Test Job**: pytest with coverage report generation | ||
| 3. **Coverage Job**: Upload to Codecov and Codacy (only for same-repo PRs) | ||
|
|
||
| **All PRs must pass CI checks before review.** | ||
|
|
||
| ## Common Pitfalls & Solutions | ||
|
|
||
| 1. **Virtual Environment**: Always activate `.venv` before running black, flake8, or pytest: | ||
| ```bash | ||
| source .venv/bin/activate | ||
| ``` | ||
|
|
||
| 2. **FastAPI Route Ordering**: Static routes MUST be defined before dynamic path parameters. Place `/players/statistics` before `/players/{player_id}`, or FastAPI will try to parse "statistics" as a player_id. | ||
| ```python | ||
| # CORRECT order: | ||
| @api_router.get("/players/statistics") # Static route first | ||
| @api_router.get("/players/{player_id}") # Dynamic route after | ||
| ``` | ||
|
|
||
| 3. **SQLAlchemy 2.0 Migration**: Use `select()` not `session.query()`. Example: | ||
| ```python | ||
| statement = select(Player).where(Player.id == player_id) | ||
| result = await async_session.execute(statement) | ||
| ``` | ||
|
|
||
| 4. **Async Session Usage**: Always use `Depends(generate_async_session)` in routes, never create sessions manually. | ||
|
|
||
| 5. **Cache Invalidation**: Remember to call `await simple_memory_cache.clear(CACHE_KEY)` after mutations (POST/PUT/DELETE). | ||
|
|
||
| 6. **Pydantic Model Conversion**: Use `player_model.model_dump()` to convert Pydantic to dict for SQLAlchemy: | ||
| ```python | ||
| player = Player(**player_model.model_dump()) | ||
| ``` | ||
|
|
||
| 7. **Database Path in Docker**: Use `STORAGE_PATH` env var, not hardcoded paths. | ||
|
|
||
| 8. **Port Conflicts**: Default port is 9000. If occupied, use `--port` flag with uvicorn. | ||
|
|
||
| ## VS Code Configuration | ||
|
|
||
| Recommended extensions (`.vscode/extensions.json`): | ||
| - `ms-python.python`, `ms-python.flake8`, `ms-python.black-formatter` | ||
| - `github.vscode-pull-request-github`, `github.vscode-github-actions` | ||
| - `ms-azuretools.vscode-containers`, `sonarsource.sonarlint-vscode` | ||
| ## 📚 Need More Detail? | ||
|
|
||
| Settings (`.vscode/settings.json`): | ||
| - Auto-format on save with Black | ||
| - Pytest enabled (not unittest) | ||
| - Flake8 integration with matching CLI args | ||
| - Editor ruler at column 88 | ||
| **For operational procedures**: Load `#file:AGENTS.md` | ||
| **For Docker expertise**: *(Planned)* `#file:SKILLS/docker-containerization/SKILL.md` | ||
| **For testing patterns**: *(Planned)* `#file:SKILLS/testing-patterns/SKILL.md` | ||
|
|
||
| ## Additional Resources | ||
| --- | ||
|
|
||
| - **Postman Collection**: `postman_collections/python-samples-fastapi-restful.postman_collection.json` | ||
| - **Architecture Diagram**: `assets/images/structure.svg` | ||
| - **FastAPI Docs**: https://fastapi.tiangolo.com/ | ||
| - **SQLAlchemy 2.0**: https://docs.sqlalchemy.org/en/20/ | ||
| - **Conventional Commits**: https://www.conventionalcommits.org/ | ||
| 💡 **Why this structure?** Copilot auto-loads this file on every chat (~500 tokens). Loading `AGENTS.md` or `SKILLS/` explicitly gives you deep context only when needed, saving 80% of your token budget! | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.