Don't assume. Don't hide confusion. Surface tradeoffs.
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is over complicated?" If yes, simplify.
Touch only what you must. Clean up only your own mess.
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove preexisting dead code unless asked.
The test: Every changed line should trace directly to the user's request.
Define success criteria. Loop until verified.
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multistep tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
- The package manger for the project is uv
- Make
uv addfor core dependencies,uv add --devfor developer dependencies, and add optional features to groups - It is also possible to remove packages using
uv remove
- The targets python versions greater than or equal to 3.12
- Given the project targets a more modern python, use functionality such as:
- The walrus operator (
:=) - Modern type hints (
dict) - Type parameters
class MyClass[T: MyParent]: ... - The
Selftype for return types (from typing import Self)
- The walrus operator (
- Type annotations:
- Do not annotate
selfparameters - the type is implicit - Use
Selffor return types when returning the instance - Example:
def add_item(self, item: str) -> Self: ...(note: no type onself)
- Do not annotate
- Classes and data structures:
- Use
@dataclass(fromdataclasses) instead of manually defining__init__for data-holding classes - Consider using
slots=Truefor memory efficiency and attribute access protection - Use
kw_only=Trueto require keyword arguments for better readability at call sites - Use
frozen=Truefor immutable data structures - Example:
@dataclass(slots=True, kw_only=True, frozen=True) - When NOT to use dataclass:
- Inheriting from non-dataclass parents (can cause MRO and initialization issues)
- Need for
__new__method (for singleton patterns, custom object creation) - Complex property logic with getters/setters that transform data
- Need for
__init_subclass__or metaclass customization - Classes with significant behavior/methods (prefer traditional classes for these)
- When to use dataclass:
- Simple data containers with minimal logic
- Configuration objects, DTOs (Data Transfer Objects), result types
- Immutable value objects (use
frozen=True) - When you want automatic
__eq__,__repr__,__hash__implementations
- Use
- Prefer importing using
from x import yinstead ofimport x - Import local modules using the full path (ex:
from my_project.my_module import MyClass) - Don't use docstrings, instead add inline comments only in places where there is complex or easily breakable logic
- For type aliases, prefer Python's modern syntax:
type MyAlias = SomeType(PEP 695 style), especially in new code. - URL construction:
- Use
urllib.parsemethods for URL manipulation (don't use string concatenation or f-strings for query params) - Use
urlencode()for query parameters - Use
urlparse()andurlunparse()for URL composition - Example:
urlunparse((parsed.scheme, parsed.netloc, parsed.path, "", urlencode(params), "")) - This ensures proper encoding and avoids common URL injection vulnerabilities
- Use