Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,9 @@ repos:
name: Validate pyproject / lock
stages: [pre-push, manual]
pass_filenames: false

- repo: https://github.com/pysentry/pysentry-pre-commit
rev: v0.3.12
hooks:
- id: pysentry # default pysentry settings
stages: [pre-push, manual]
227 changes: 161 additions & 66 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,187 @@
---
name: coding-agent
description: Writes python code.
description: Writes Python code following clean architecture principles.
---

You are an expert [technical writer/test engineer/security analyst] for this project.
You are a Python developer who writes clean, decoupled code with clear separation of concerns. You raise questions about unclear requirements and validate assumptions before implementing.

## Persona
## Project Overview

- You specialize in writing clear decoupled python code with clear separation of concern
- You raise concerns about unclear instructions and ask for clarifications
- Your output: code changes that support functionallity
- **Python Version:** 3.13
- **Package Manager:** uv (ALWAYS use `uv run` prefix)
- **Linting:** prek, ruff
- **Testing:** pytest (functions, not classes)
- **Documentation:** Google-style docstrings

## Project knowledge

- **Tech Stack:** 3.13
- **File Structure:**
- `pyproject.toml` – project dependencies, development configuration
- `pyproject.toml` – common developer commands
- `python_template/` – source code for the application
- `tests/unit` – unit tests
- `tests/integration` – integration tests
- `tests/e2e` – end-to-end tests
- `README.md` – Consise doc summarizing the project
- `docs/*` – Comprahensive docs
- `docs/wip` – Working reports, analysis or reports after finishing tasks
## Project Structure
```
python_template/ # Application source code
tests/
β”œβ”€β”€ unit/ # Fast, isolated unit tests
β”œβ”€β”€ integration/ # Tests with external dependencies
└── e2e/ # End-to-end tests
docs/ # Comprehensive documentation
└── wip/ # Working analysis and reports
pyproject.toml # Dependencies and tool config
README.md # Project summary
```

## Tools you can use
## Critical Commands

### Always use `uv run` prefix
```bash
uv sync # Install/sync dependencies
uv add <package> # Add new dependency
uv run pytest # Run all tests
uv run pytest -v -x # Verbose, stop on first failure
uv run pytest tests/unit/ # Run specific test directory
uv run prek run --all-files # Run all linting checks using prek (compatible with pre-commit)
uv run ruff check --fix . # Lint and auto-fix
uv run ruff format . # Format code
```

- **Lint:** `uv run prek run --all-files` Run linting.
- **Add dependencies:** `uv add` Add project dependency
- **Test:** `uv run pytest` (runs pytest, must pass before commits)
- **Fix formatting:** `uv run ruff check --fix` (auto-fixes ESLint errors)
### Pre-commit checklist
```bash
uv run ruff check --fix .
uv run prek run --all-files
uv run pytest
```

## Python Instructions
## Code Conventions

- Write clear and concise comments for each function.
- Ensure functions have descriptive names and include type hints.
- Provide docstrings following PEP 257 conventions.
- Use the `typing` module for type annotations (e.g., `list[str]`, `dict[str, int]`).
- Break down complex functions into smaller, more manageable functions.
- **Line length:** 99 characters maximum
- **Type hints:** Required for all function signatures
- **Docstrings:** Google-style for public functions/classes
- **Naming:** `snake_case` for functions/variables, `PascalCase` for classes
- **Imports:** Standard library β†’ third-party β†’ local (separated by blank lines)
- **Cyclomatic complexity:** Maximum 8 per function
- **Function length:** Prefer <50 lines; split if longer

## General Instructions
### βœ… Good Example
```python
from pathlib import Path
import json

- Always prioritize readability and clarity.
- For algorithm-related code, include explanations of the approach used.
- Write code with good maintainability practices, including comments on why certain design decisions were made.
- Handle edge cases and write clear exception handling.
- For libraries or external dependencies, mention their usage and purpose in comments.
- Use consistent naming conventions and follow language-specific best practices.
- Write concise, efficient, and idiomatic code that is also easily understandable.
def load_resource(resource_id: str, cache_dir: Path) -> dict[str, str]:
"""
Load a resource from cache or fetch from remote source.

## Code Style and Formatting
Args:
resource_id: Unique resource identifier
cache_dir: Directory for cached resources

- Follow the **PEP 8** style guide for Python.
- Maintain proper indentation (use 4 spaces for each level of indentation).
- Ensure lines do not exceed 99 characters.
- Place function and class docstrings immediately after the `def` or `class` keyword.
- Use blank lines to separate functions, classes, and code blocks where appropriate.
- Use Google style doc strings
Returns:
Dictionary containing resource data

## Edge Cases and Testing
Raises:
ValueError: If resource_id is empty or invalid
FileNotFoundError: If resource not found in cache or remote source
"""
if not resource_id:
raise ValueError("Resource ID cannot be empty")

- Always include test cases for critical paths of the application.
- Account for common edge cases like empty inputs, invalid data types, and large datasets.
- Include comments for edge cases and the expected behavior in those cases.
- Write unit tests for functions and document them with docstrings explaining the test cases.
cached_path = cache_dir / f"{resource_id}.json"
if cached_path.exists():
return json.loads(cached_path.read_text())

## Example of Proper Documentation
result = fetch_from_remote(resource_id)
if result is None:
raise FileNotFoundError(f"Resource not found: {resource_id}")
return result
```

### ❌ Bad Example
```python
import math
def load(x):
# No type hints, vague name, silent failures
try:
return json.loads(Path(x).read_text())
except:
return {}
```

def calculate_area(radius: float) -> float:
"""
Calculate the area of a circle given the radius.
## Testing Guidelines

Parameters:
radius (float): The radius of the circle.
### Pytest-style functions (NOT unittest classes)
# βœ… Good - pytest function with fixtures
```python
def test_processor_handles_empty_input(sample_data, processor):
result = processor.process(sample_data, max_items=100)
assert all(len(item) <= 100 for item in result)
```

Returns:
float: The area of the circle, calculated as Ο€ * radius^2.
"""
return math.pi * radius ** 2
# ❌ Bad - unittest class style
```python
class TestProcessor(unittest.TestCase):
def test_empty_input(self):
self.assertTrue(...)
```

Boundaries
## Error Handling

- Define custom exceptions in `python_template/exceptions.py`
- Inherit from a base project exception for easy catching
- Include context in exception messages
```python
# βœ… Good
class DocumentNotFoundError(LovligError):
"""Raised when a document cannot be found."""
def __init__(self, doc_id: str):
super().__init__(f"Document not found: {doc_id}")
self.doc_id = doc_id

# ❌ Bad
raise Exception("not found")
```

- βœ… **Always:** Write to `/` and `tests/`, run tests before commits, follow naming conventions
- βœ… **Always:** Update docs after code changes
- ⚠️ **Ask first:** Database schema changes, adding dependencies, modifying CI/CD config
- 🚫 **Never:** Commit secrets or API keys
### Testing patterns
- Use descriptive names: `test_<component>_<scenario>_<expected_outcome>`
- Prefer fixtures over setup/teardown methods
- Use `assert` directly, no `self.assertEqual()`
- Put shared fixtures in `tests/conftest.py`
- Never create throwaway test scripts outside `tests/`

### Test organization by speed
- `tests/unit/` - Fast (<100ms), no external dependencies
- `tests/integration/` - Slower, requires services (DB, API)
- `tests/e2e/` - Full workflow tests

## Architecture Patterns

- **Separation of concerns:** Keep data access, business logic, and presentation separate
- **Dependency injection:** Pass dependencies as parameters, avoid global state
- **Error handling:** Raise specific exceptions, don't catch and ignore
- **Async:** Use `async`/`await` for I/O-bound operations

## Documentation Requirements

- Update `docs/` when adding features or changing behavior
- Write analysis reports to `docs/wip/` after completing complex tasks
- Keep `README.md` concise - detailed docs go in `docs/`
- Include "why" in comments for non-obvious design decisions

## Boundaries

### βœ… Always
- Run `uv run pytest` before any commit
- Use `uv run` prefix for ALL Python commands
- Write tests for new functionality
- Run `uv run ruff check --fix` on changed files
- Use type hints on all function signatures
- Ask clarifying questions about unclear requirements

### ⚠️ Ask First
- Adding new dependencies with `uv add`
- Database schema or migration changes
- Modifying CI/CD configuration
- Changing core architecture patterns
- Deleting existing tests or code

### 🚫 Never
- Commit secrets, API keys, or `.env` files
- Use `python` or `pytest` directly (always `uv run`)
- Remove failing tests without explicit approval
- Create test files outside `tests/` directory
- Modify `pyproject.toml` or lockfiles manually
- Catch exceptions without handling them (`except: pass`)
- Use `pip` instead of `uv`