Shared documentation for all AI coding assistants
This file is referenced by multiple AI tool configurations. Changes here automatically apply to all tools that support file references.
NEVER use decorative emojis in any output.
- ❌ Section markers: 🚀 🎯 🐳 🛠️ 📦 📚 🤖 🔧 📁 🎨 🔍 📝
- ❌ Callouts: 👋 📖 🎓 📧 👉 💡 ⚡ 🔥
- ❌ Celebrations: ✨ 🎉 ❤️ 💪 👏
- ❌ Status: 🚫
⚠️ 📢 🎊
- ✅ Checkboxes for completion status
- ❌ X-marks for failed/not-included items
- Code output (print statements, CLI messages, logs)
- Documentation (README, guides, docstrings, comments)
- Commit messages and PR descriptions
- Error messages and user-facing text
- File contents generated by code
- Professional appearance for enterprise use
- Universal compatibility across terminals/editors
- Better accessibility for screen readers
- Consistent with Atyantik branding standards
- Reduces visual clutter, improves readability
Code Output:
# ❌ WRONG
print("🚀 Starting process...")
print("✨ Success!")
# ✅ CORRECT
print("Starting process...")
print("Success!")Documentation:
❌ WRONG: ## 🎯 Quick Start
✅ CORRECT: ## Quick Start
❌ WRONG: **👋 Welcome!** Check out the docs 📖
✅ CORRECT: **Welcome!** Check out the docsCommit Messages:
❌ WRONG: "✨ Add new feature 🚀"
✅ CORRECT: "Add user authentication feature"ALWAYS store AI-generated summaries in .ai-summary/ directory.
- All automated AI execution summaries MUST go in
.ai-summary/ - This directory is in
.gitignore- never commit AI summaries - Examples: session summaries, execution logs, automated reports
- Keeps git history clean and focused on actual code changes
Correct:
# AI writes summary to proper location
.ai-summary/session-2025-11-02.md
.ai-summary/execution-log-20251102-143022.mdWrong:
# ❌ Never write summaries to root or other directories
./ai-summary.md
./session-notes.md
docs/ai-output.md- Prevents accidental commits of AI-generated content
- Keeps repository professional and focused
- Separates code from AI tool artifacts
- Consistent across all AI assistants
NEVER add AI co-author attribution to git commits.
- Do NOT add "Co-Authored-By: Claude" or any AI assistant attribution
- Do NOT add "Generated with [AI Tool]" footers
- Keep commit messages professional and human-authored
- Commits should reflect the human developer's work, not AI involvement
Correct:
git commit -m "Add user authentication feature
Implemented OAuth2 authentication with JWT tokens.
Added login, logout, and token refresh endpoints.
Includes comprehensive tests with 95% coverage."Wrong:
# ❌ Never add AI attribution
git commit -m "Add user authentication feature
...
Generated with Claude Code.
Co-Authored-By: Claude <noreply@anthropic.com>"- Commits should represent human intent and responsibility
- Professional git history without AI attribution
- Clear accountability for code changes
- Industry standard practice
| Aspect | Standard |
|---|---|
| Line Length | 88 characters (Black default) |
| Quotes | Double quotes preferred |
| Type Hints | Required on all functions (mypy strict) |
| Docstrings | Google style format |
| Import Sorting | isort with Black profile |
| Python Version | 3.11+ (3.13 recommended) |
# Format all code
make format
# Format specific directory
uv run black src testsStandards:
- Line length: 88 characters
- Double quotes for strings
- Trailing commas in multi-line structures
- No manual line breaks (Black decides)
- Treat Black as the source of truth for layout, then let Ruff confirm it.
- Avoid patterns the tools format differently. Instead of multi-line
assertcalls wrapped in parentheses, assign long messages to a local variable and pass that variable to the assertion. This keeps both formatters from oscillating the same lines. - After editing formatted code, run
pre-commit run --files …(ormake format) before staging to catch conflicts immediately. - If a rule keeps rewriting your changes, refactor the code so the intent is explicit rather than relying on formatter heuristics.
# ✅ Correct import order
from __future__ import annotations # Future imports first
import json # Standard library
import re
from typing import Any
import pytest # Third-party packages
import requests
from python_modern_template import helper # Local imports
from python_modern_template.utils import process_dataRules:
- One import per line
- Alphabetically sorted within groups
- Blank line between groups
- No wildcard imports (
from module import *)
from __future__ import annotations # For forward references
from typing import Any
def process_data(
input_str: str,
options: dict[str, Any] | None = None,
max_length: int = 100,
) -> list[str]:
"""Process input data with options.
Args:
input_str: Input data to process
options: Optional processing options
max_length: Maximum length for output items
Returns:
List of processed strings
"""
...# ✅ Use new union syntax
def get_value(key: str) -> str | None:
...
# ❌ Old syntax (avoid)
from typing import Optional
def get_value(key: str) -> Optional[str]:
...
# ✅ Use built-in generics
def process_items(items: list[str]) -> dict[str, int]:
...
# ❌ Old syntax (avoid)
from typing import List, Dict
def process_items(items: List[str]) -> Dict[str, int]:
...from typing import Any, Callable, Protocol
# Callable types
def apply_function(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
# Protocol for structural typing
class HasName(Protocol):
name: str
def greet(obj: HasName) -> str:
return f"Hello, {obj.name}"
# TypedDict for structured dicts
from typing import TypedDict
class UserData(TypedDict):
name: str
age: int
email: str | Nonedef calculate_total(
items: list[dict[str, Any]],
tax_rate: float = 0.1,
discount: float = 0.0,
) -> float:
"""Calculate total price with tax and discount.
This function processes a list of items, applies tax and discount,
and returns the final total price.
Args:
items: List of item dictionaries with 'price' key
tax_rate: Tax rate as decimal (default 0.1 = 10%)
discount: Discount as decimal (default 0.0 = no discount)
Returns:
Total price after tax and discount
Raises:
ValueError: If items is empty
KeyError: If item missing 'price' key
Example:
>>> items = [{"name": "Book", "price": 10.00}]
>>> calculate_total(items, tax_rate=0.1)
11.00
"""
if not items:
raise ValueError("Items list cannot be empty")
subtotal = sum(item["price"] for item in items)
total = subtotal * (1 + tax_rate) * (1 - discount)
return round(total, 2)"""Module for user authentication and authorization.
This module provides functions for:
- User login/logout
- Password validation
- Token generation
- Permission checking
Typical usage example:
from python_modern_template.auth import authenticate_user
user = authenticate_user(username, password)
if user:
print(f"Welcome, {user.name}")
"""class UserValidator:
"""Validates user data before creating user accounts.
This class provides validation for:
- Username format and uniqueness
- Email format
- Password strength
- Age requirements
Attributes:
min_age: Minimum age for user registration
password_min_length: Minimum password length
Example:
>>> validator = UserValidator(min_age=18)
>>> validator.validate_username("john_doe")
True
"""
def __init__(self, min_age: int = 13) -> None:
"""Initialize validator with age requirement.
Args:
min_age: Minimum age for registration (default 13)
"""
self.min_age = min_age# Check all code
make lint
# Auto-fix issues
uv run ruff check --fix src tests
# Check specific rules
uv run ruff check src --select=E,F,BEnabled rules:
- E/W (pycodestyle errors and warnings)
- F (pyflakes)
- B (flake8-bugbear)
- C4 (flake8-comprehensions)
- UP (pyupgrade)
# Check all code (must score 10/10)
uv run pylint src testsKey rules:
- No unused variables
- No unused imports
- No duplicate code
- Consistent naming
- Maximum function complexity: 10
# Check type hints
uv run mypy src testsConfiguration (strict mode):
- All functions must have type hints
- No implicit
Anytypes - No untyped function calls
- Check return values
# Install hooks
make install
# Run manually
make pre-commitHooks run on commit:
- Trailing whitespace removal
- YAML syntax check
- Large file prevention
- Ruff linting
- Black formatting
- isort import sorting
- mypy type checking
leadership-blog-generator/
├── src/
│ └── python_modern_template/
│ ├── __init__.py # Package exports & version
│ ├── main.py # CLI and main functionality
│ └── [modules].py # Additional modules
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Shared fixtures
│ └── test_*.py # Test files mirror src structure
├── scripts/
│ └── ai_tools/ # AI context management tools
├── AI_DOCS/ # Shared AI documentation
├── .ai-context/ # AI session files
├── pyproject.toml # Project config & dependencies
├── Makefile # Development commands
└── README.md # User documentation
# ✅ Correct - import from package name
from python_modern_template import function_name
from python_modern_template.module import ClassName
# ❌ Wrong - don't use src prefix
from src.python_modern_template import function_name# File: src/python_modern_template/__init__.py
"""Modern Python template package."""
from .main import generate_blog
from .validators import validate_email, validate_phone
__version__ = "0.1.0"
__all__ = [
"generate_blog",
"validate_email",
"validate_phone",
]# ❌ Bad - duplicate logic
def process_user(name: str) -> str:
return name.strip().lower().replace(" ", "_")
def process_product(name: str) -> str:
return name.strip().lower().replace(" ", "_")
# ✅ Good - shared logic
def normalize_name(name: str) -> str:
"""Normalize name to lowercase with underscores."""
return name.strip().lower().replace(" ", "_")
def process_user(name: str) -> str:
"""Process user name."""
return normalize_name(name)
def process_product(name: str) -> str:
"""Process product name."""
return normalize_name(name)# ✅ Good - single responsibility
def read_file(path: str) -> str:
"""Read file contents."""
with open(path) as f:
return f.read()
def parse_config(content: str) -> dict[str, Any]:
"""Parse config from string."""
return json.loads(content)
def load_config(path: str) -> dict[str, Any]:
"""Load and parse config file."""
content = read_file(path)
return parse_config(content)# ❌ Implicit behavior
def process(data, flag=True):
if flag:
return data.upper()
return data
# ✅ Explicit, testable
def uppercase(data: str) -> str:
"""Convert data to uppercase."""
return data.upper()
def process(data: str, transform: bool = True) -> str:
"""Process data with optional transformation.
Args:
data: Input data
transform: Apply uppercase transformation
Returns:
Processed data
"""
if transform:
return uppercase(data)
return data# ✅ Good - specific exceptions
def divide(a: float, b: float) -> float:
"""Divide two numbers.
Args:
a: Numerator
b: Denominator
Returns:
Result of division
Raises:
ValueError: If b is zero
"""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
# ❌ Bad - bare except
try:
result = risky_operation()
except: # Never do this!
pass
# ✅ Good - specific exceptions
try:
result = risky_operation()
except ValueError as e:
logger.error(f"Invalid value: {e}")
raise
except IOError as e:
logger.error(f"IO error: {e}")
raise# ❌ Bad - hardcoded secrets
API_KEY = "sk-1234567890abcdef"
DATABASE_URL = "postgresql://user:password@localhost/db"
# ✅ Good - environment variables
import os
API_KEY = os.environ["API_KEY"]
DATABASE_URL = os.environ["DATABASE_URL"]# ✅ Always validate user input
def create_user(email: str, age: int) -> User:
"""Create new user with validation.
Args:
email: User email address
age: User age
Returns:
Created user object
Raises:
ValueError: If email invalid or age < 0
"""
if not validate_email(email):
raise ValueError(f"Invalid email: {email}")
if age < 0:
raise ValueError(f"Invalid age: {age}")
return User(email=email, age=age)# ❌ Bad - SQL injection risk
def get_user(user_id: str) -> User:
query = f"SELECT * FROM users WHERE id = {user_id}" # Dangerous!
return db.execute(query)
# ✅ Good - parameterized queries
def get_user(user_id: int) -> User:
query = "SELECT * FROM users WHERE id = ?"
return db.execute(query, (user_id,))# snake_case for variables and functions
user_name = "John"
total_count = 100
def calculate_total_price(items: list[Item]) -> float:
"""Calculate total price."""
...# PascalCase for classes
class UserValidator:
"""Validates user data."""
...
class EmailProcessor:
"""Processes email messages."""
...# UPPER_SNAKE_CASE for constants
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"class MyClass:
"""Example class with private members."""
def __init__(self) -> None:
"""Initialize class."""
self._internal_value = 0 # Single underscore for internal use
self.__private_value = 0 # Double underscore for name mangling
def public_method(self) -> int:
"""Public method."""
return self._internal_value
def _internal_method(self) -> None:
"""Internal method (not part of public API)."""
...See @AI_DOCS/tdd-workflow.md for comprehensive testing guidelines.
Key points:
- Test file names:
test_*.py - Test function names:
test_<description> - Test class names:
Test<FeatureName> - Use fixtures in
conftest.pysparingly - Prefer parametrized tests for multiple cases
- Minimum: 80% (enforced)
- Target: 90%+
- Ideal: 100% for new code
# Check coverage
make coverage
# View HTML report
open htmlcov/index.html- Before coding: Run
uv run ai-start-task "Task description" - Write tests first: Create
test_*.pywith failing tests - Implement code: Make tests pass
- Format:
make format(Black + isort) - Lint:
make lint(Ruff + mypy + Pylint) - Test:
make test(pytest with coverage) - Quality check:
make check(all of the above) - Commit: Changes pass all checks
- Finish: Run
uv run ai-finish-task --summary="..."
All tool configurations are in pyproject.toml:
[tool.black]
line-length = 88
target-version = ["py311"]
[tool.isort]
profile = "black"
[tool.ruff]
line-length = 88
select = ["E", "F", "B", "C4", "UP"]
[tool.mypy]
strict = true
python_version = "3.11"
[tool.pylint.main]
fail-under = 10.0
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--cov=src --cov-report=term-missing --cov-fail-under=80"- TDD Workflow:
@AI_DOCS/tdd-workflow.md - AI Tools:
@AI_DOCS/ai-tools.md - Project Context:
@AI_DOCS/project-context.md
Remember: Follow these conventions consistently. Run make check before committing. Quality over quantity.