|
1 | 1 | # AI Agent Code Guidelines |
2 | 2 |
|
3 | | -This document provides coding guidelines for AI agents working on this Python project. |
| 3 | +## Core Directives |
4 | 4 |
|
5 | | -## Environment and Dependencies |
| 5 | +- **Tooling**: `uv` (manager), `ty` (checker), Python 3.13+. |
| 6 | +- **Format**: 2-space indent, single quotes, 88 chars, `snake_case`, `PascalCase` classes. |
| 7 | +- **Typing**: Strict `ty` checking. Pydantic `BaseModel` for interfaces/schemas. `dataclasses` only for internal perf. |
| 8 | +- **Docs**: One-line docstrings. Type hints > text. Comments explain *why*, not *what*. |
6 | 9 |
|
7 | | -- **Tooling**: Use `uv` for all package management |
8 | | -- **Python Version**: 3.13+ |
9 | | -- **Package Manager**: uv (fast, modern dependency management) |
10 | | -- **Type Checker**: ty (Astral's fast type checker, alpha stage) - `make typecheck` |
11 | | - - Note: ty is in early development and may have bugs/missing features |
| 10 | +## Architecture & Patterns |
12 | 11 |
|
13 | | -## Code Style |
| 12 | +- **Functional Core, Imperative Shell**: Classes for state/lifecycle, pure functions for logic. |
| 13 | +- **Protocols**: Duck-typing over inheritance (`typing.Protocol`). |
| 14 | +- **Config**: Frozen dataclasses/Pydantic models with factories (`from_env`). |
| 15 | +- **Resource Safety**: Context managers (`with`), reference counting, explicit ownership. |
| 16 | +- **Data Flow**: Streaming `Iterator[T]`. RORO (Receive Object, Return Object). Pipeline pattern. |
| 17 | +- **Errors**: Custom domain exceptions. No broad catches. |
14 | 18 |
|
15 | | -**Format**: 2-space indentation, single quotes, 88-character lines, `snake_case` variables/functions, `PascalCase` classes, boolean flags prefixed with `is_/has_/should_`. Pre-commit hooks ensure code quality on commit. |
| 19 | +## Quality Standards |
16 | 20 |
|
17 | | -**Docstrings**: |
| 21 | +- **Complexity**: Max 25 lines per method. Break large functions into small, focused helpers. |
| 22 | +- **Readability**: Optimize for review. Explicit dependencies over global state. No magic values. |
| 23 | +- **Testing**: Test behaviors, not implementation details. High coverage on core logic. |
| 24 | +- **Reviewability**: Code should be obvious. If it needs a long comment, refactor it. |
18 | 25 |
|
19 | | -- Use simple one-line docstrings for most functions - be concise and descriptive |
20 | | -- Type hints replace Args/Returns documentation - don't duplicate what's in the signature |
21 | | -- No Examples section - type hints + function name should be self-explanatory |
22 | | -- Exception: Top-level user-facing APIs may include brief usage notes if necessary |
23 | | -- Rationale: Modern Python with PEP 484 type hints makes verbose docstrings redundant |
| 26 | +## Anti-Patterns |
24 | 27 |
|
25 | | -**Comments**: |
26 | | - |
27 | | -- Avoid narrating the code; prefer clear names and small functions |
28 | | -- Comments should explain *why* (tradeoffs, invariants, pitfalls), not *what* |
29 | | -- Delete commented-out code instead of keeping it around |
30 | | - |
31 | | -**Naming**: |
32 | | - |
33 | | -- Prefer domain-specific, intention-revealing names over generic ones (`process`, `handle`, `manager`, `util`) |
34 | | -- Keep public API names stable and unsurprising; avoid cleverness |
35 | | - |
36 | | -## Architecture Principles |
37 | | - |
38 | | -**Classes for state and lifecycle**, pure functions for transformations. Use classes when managing resources, coordinating operations, or defining interfaces. |
39 | | - |
40 | | -**Protocols over inheritance**: Define interfaces with `typing.Protocol` for flexible, duck-typed implementations. |
41 | | - |
42 | | -**Immutable configs**: Frozen dataclasses with `__post_init__` validation and factory classmethods (`from_uri()`, `from_dict()`). |
43 | | - |
44 | | -**Factory functions**: Standalone functions (`get_backend()`, `resolve_config()`) that map configurations to implementations. |
45 | | - |
46 | | -**Resource management**: |
47 | | - |
48 | | -- Reference counting for expensive resources (connections, clients) with acquire/release semantics |
49 | | -- Context managers (`__enter__`/`__exit__`) for automatic cleanup |
50 | | -- Track ownership with boolean flags to avoid closing borrowed resources |
51 | | - |
52 | | -**Streaming over bulk**: Use `Iterator[T]` to yield chunks for large datasets. Implement retry logic within generators for resilience. |
53 | | - |
54 | | -**Separation by lifecycle**: Split read and write operations into distinct classes, even when working with the same backend (e.g., `SessionStoreReader`, `SessionStoreWriter`). |
55 | | - |
56 | | -**Domain exceptions**: Create specific exception types rather than generic `RuntimeError`. |
57 | | - |
58 | | -**Performance**: Use `@dataclass(slots=True)` for frequently-instantiated objects and `TypeVar` for type-safe generic protocols. |
59 | | - |
60 | | -**Resilience**: Exponential backoff for network operations, graceful empty returns over exceptions, debug logging for key metrics. Keep error handling targeted (catch specific exceptions, add context, re-raise/convert). |
61 | | - |
62 | | -## Best Practices |
63 | | - |
64 | | -- RORO pattern: service functions receive/return single Pydantic objects |
65 | | -- Single responsibility: break 150+ line functions into focused 15-25 line methods |
66 | | -- Early returns, no magic values, explicit dependencies |
67 | | -- DRY principle: extract utility functions to eliminate duplication |
68 | | -- Pipeline pattern: chain transformations with clear inputs/outputs |
69 | | -- No excessive error handling or low-value comments |
70 | | - |
71 | | -## Code Quality Bar (What to Avoid) |
72 | | - |
73 | | -When generating code, optimize for reviewability and long-term maintainability. |
74 | | - |
75 | | -- **Unnecessary comments**: If a comment just restates the code, remove it and improve naming/structure instead |
76 | | -- **Long docstrings**: Keep most docstrings to a single line; only expand when a public API truly needs usage notes |
77 | | -- **Overly defensive code**: Don’t add “just in case” checks everywhere; validate at boundaries and trust validated data internally |
78 | | -- **Broad `try/except`**: Avoid wrapping whole functions; don’t swallow exceptions; catch specific errors only to recover or add context |
79 | | -- **Deep nesting**: Prefer guard clauses and extraction to keep indentation shallow (avoid multi-level `if/for/try`) |
80 | | -- **Bad abstractions**: Don’t create classes/protocols/layers without clear value; avoid one-method wrappers and “framework-building” |
81 | | -- **Vague naming**: Avoid generic verbs (`do`, `process`, `handle`) and generic buckets (`utils`, `helpers`) for core logic |
82 | | -- **Weak typing / schemas**: Avoid `Any` and unstructured `dict[str, Any]` in core code; prefer Pydantic models (or narrow typed objects) with explicit fields and validation |
83 | | -- **Noisy error handling**: Prefer a small number of well-placed domain exceptions over many `RuntimeError`/`ValueError` catch-alls |
84 | | - |
85 | | -## Pydantic Commitment |
86 | | - |
87 | | -- All interface models use Pydantic `BaseModel` (not dataclasses) |
88 | | -- Validation, `.model_dump()`, JSON serialization built-in |
89 | | -- Reserve `@dataclass(slots=True)` only for inner performance-critical helpers (graph traversal caches, etc.) |
| 28 | +- **Verbosity**: Long docstrings, narrating comments, redundant type info in docs. |
| 29 | +- **Vague Naming**: `manager`, `handler`, `util`, `data`. Be specific. |
| 30 | +- **Defensive Coding**: Validate at boundaries, trust internals. No "just in case" checks. |
| 31 | +- **Deep Nesting**: Use guard clauses and early returns. |
| 32 | +- **Over-Abstraction**: No single-method classes or speculative layers. |
0 commit comments