Coding Style Guide¶
Code conventions and standards for Nova AI contributors.
Table of Contents¶
Python Style¶
General Principles¶
- Clarity over cleverness: Code should be easy to understand
- Explicit over implicit: Be clear about intentions
- Consistency: Follow existing patterns in the codebase
- Security first: Validate inputs, handle errors, avoid vulnerabilities
Tools¶
# Formatter (auto-fix)
ruff format src/ tests/
# Linter (find issues)
ruff check src/ tests/
# Auto-fix linting issues
ruff check --fix src/ tests/
# Type checker
mypy src/
# Security scanner
bandit -r src/
Code Formatting¶
Line Length: - 100 characters maximum - Break long lines for readability
Indentation: - 4 spaces (not tabs) - Consistent indentation for continuation lines
Imports:
# 1. Future imports (if needed)
from __future__ import annotations
# 2. Standard library
import os
import sys
from pathlib import Path
# 3. Third-party
import anthropic
from pydantic import BaseModel
# 4. Local
from src.orchestrator.session_manager import SessionManager
from src.utils.path_security import validate_safe_path
# NO wildcard imports
# ❌ from module import *
# ✅ from module import specific_function
Naming Conventions:
# Classes: PascalCase
class ClaudeSDKExecutor:
pass
# Functions/methods: snake_case
def execute_agent_task() -> ExecutorResult:
pass
# Constants: UPPER_SNAKE_CASE
MAX_SESSION_TOKENS = 150_000
DEFAULT_MODEL = "sonnet"
# Private members: _leading_underscore
class MyClass:
def __init__(self):
self._internal_state = {}
def _helper_method(self):
pass
# Module-level private: _leading_underscore
_internal_cache = {}
Type Hints¶
Required for all public functions:
# ✅ Good: Complete type hints
def authenticate_user(
username: str,
password: str,
*,
timeout: int = 30,
) -> User:
"""Authenticate user."""
...
# ❌ Bad: Missing type hints
def authenticate_user(username, password, timeout=30):
...
# ✅ Good: Complex types
from collections.abc import Callable, Sequence
def process_items(
items: Sequence[str],
callback: Callable[[str], bool],
) -> list[str]:
return [item for item in items if callback(item)]
# ✅ Good: Optional and Union types
from typing import Optional
def get_user(user_id: str) -> User | None:
"""Return user or None if not found."""
...
# ✅ Good: Generic types
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T | None:
return items[0] if items else None
Avoid Any when possible:
# ❌ Bad: Lazy typing
def process(data: Any) -> Any:
...
# ✅ Good: Specific types
from typing import Protocol
class Serializable(Protocol):
def to_dict(self) -> dict[str, Any]: ...
def process(data: Serializable) -> dict[str, Any]:
...
Docstrings¶
Format: Google style
Required for: - All public functions - All public classes - All public methods - Module-level docstrings
Example:
"""Module for user authentication.
This module provides JWT-based authentication for API endpoints.
Supports token generation, validation, and refresh flows.
Example:
>>> authenticator = JWTAuthenticator()
>>> user = authenticator.authenticate("admin", "password")
>>> token = authenticator.generate_token(user)
"""
from __future__ import annotations
class JWTAuthenticator:
"""JWT-based authentication provider.
Implements token generation, validation, and refresh using
industry-standard JWT (RFC 7519) with RS256 signing.
Attributes:
secret_key: RSA private key for signing tokens
public_key: RSA public key for validation
token_ttl: Token time-to-live in seconds (default: 3600)
Example:
>>> auth = JWTAuthenticator(secret_key=key)
>>> token = auth.generate_token(user)
>>> is_valid = auth.validate_token(token)
"""
def __init__(
self,
secret_key: str,
public_key: str | None = None,
*,
token_ttl: int = 3600,
):
"""Initialize JWT authenticator.
Args:
secret_key: RSA private key PEM string
public_key: RSA public key PEM string (optional, derived from private)
token_ttl: Token lifetime in seconds (default: 3600)
Raises:
ValueError: If secret_key is invalid or empty
"""
...
def authenticate(
self,
username: str,
password: str,
) -> User:
"""Authenticate user with credentials.
Args:
username: User's username (3-50 characters)
password: User's password (plaintext, will be hashed)
Returns:
Authenticated user object with populated fields
Raises:
AuthenticationError: If credentials are invalid
ValueError: If username or password format invalid
TimeoutError: If database query times out
Example:
>>> user = auth.authenticate("admin", "secret123")
>>> print(user.username)
admin
Note:
Passwords are hashed using bcrypt with 12 rounds.
Authentication attempts are rate-limited (5/minute).
"""
...
def validate_token(self, token: str) -> bool:
"""Validate JWT token signature and expiration.
Args:
token: JWT token string to validate
Returns:
True if token valid and not expired, False otherwise
Example:
>>> is_valid = auth.validate_token(token)
>>> if not is_valid:
... raise AuthenticationError("Invalid token")
Security:
- Validates signature using RSA public key
- Checks expiration timestamp
- Verifies issuer and audience claims
"""
...
Error Handling¶
# ✅ Good: Specific exceptions
class AuthenticationError(Exception):
"""Raised when authentication fails."""
pass
def authenticate(username: str, password: str) -> User:
if not is_valid(username, password):
raise AuthenticationError(f"Invalid credentials for {username}")
# ✅ Good: Exception chaining
try:
response = make_api_call()
except requests.RequestException as e:
raise APIError(f"API call failed: {e}") from e
# ✅ Good: Cleanup with context managers
with open("file.txt") as f:
data = f.read()
# File automatically closed
# ✅ Good: Multiple exception types
try:
process_data()
except ValueError as e:
logger.error(f"Invalid data: {e}")
except RuntimeError as e:
logger.error(f"Runtime error: {e}")
except Exception as e:
logger.exception(f"Unexpected error: {e}")
raise
# ❌ Bad: Bare except
try:
dangerous_operation()
except: # Catches everything, including KeyboardInterrupt!
pass
# ❌ Bad: Swallowing exceptions
try:
might_fail()
except Exception:
pass # Silent failure - hard to debug
Security¶
# ✅ Good: Input validation
def validate_path(path: str | Path) -> Path:
"""Validate path is safe (no traversal, within allowed base)."""
from src.utils.path_security import validate_safe_path
return validate_safe_path(path, allowed_base=PROJECT_ROOT)
# ✅ Good: SQL injection prevention
def get_user(user_id: str) -> User | None:
# Use parameterized queries
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
# ❌ Bad: SQL injection vulnerability
def get_user(user_id: str) -> User | None:
cursor.execute(f"SELECT * FROM users WHERE id = '{user_id}'")
# ✅ Good: XSS prevention
from src.orchestrator.security.xss_protection import sanitize_for_display
def render_user_input(text: str) -> str:
return sanitize_for_display(text)
# ✅ Good: Command injection prevention
import shlex
def run_command(command: str):
# Validate and escape
safe_command = shlex.quote(command)
subprocess.run(safe_command, shell=False)
# ❌ Bad: Command injection vulnerability
def run_command(command: str):
os.system(command) # Dangerous!
Performance¶
# ✅ Good: Use list comprehensions
squares = [x**2 for x in range(100)]
# ❌ Bad: Inefficient loop
squares = []
for x in range(100):
squares.append(x**2)
# ✅ Good: Generator for large datasets
def read_large_file(path: Path):
with open(path) as f:
for line in f: # Memory efficient
yield line.strip()
# ❌ Bad: Load everything into memory
def read_large_file(path: Path):
with open(path) as f:
return f.readlines() # Can cause OOM
# ✅ Good: Cache expensive computations
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(x: int) -> int:
# Computed once, cached for repeated calls
return complex_calculation(x)
TypeScript Style¶
General¶
- 100 characters line length
- 2 spaces indentation
- Prettier for formatting
- ESLint for linting
Type Annotations¶
// ✅ Good: Explicit types
interface User {
id: string;
username: string;
email: string;
createdAt: Date;
}
function getUser(userId: string): Promise<User | null> {
return fetchUser(userId);
}
// ❌ Bad: Implicit any
function getUser(userId) {
return fetchUser(userId);
}
// ✅ Good: Generic types
function first<T>(items: T[]): T | undefined {
return items[0];
}
// ✅ Good: Union types
type Result<T> = { success: true; data: T } | { success: false; error: string };
Agent Development¶
Agent File Structure¶
---
name: my-agent
description: Brief one-line description of agent purpose
tools:
- Read
- Write
- Edit
- Grep
- Glob
- Bash
model: sonnet
color: blue # Optional: purple, orange, blue, green, red, yellow
---
# Agent Instructions
## Purpose
Clear description of what this agent does and when to use it.
## Capabilities
- Capability 1
- Capability 2
## Constraints
- What this agent should NOT do
- Limitations
## Examples
### Example 1: [Use Case]
Input: ...
Output: ...
### Example 2: [Use Case]
Input: ...
Output: ...
## Best Practices
- Practice 1
- Practice 2
Agent Guidelines¶
- Single Responsibility: Each agent should have one clear purpose
- Minimal Tools: Only include tools actually needed
- Clear Instructions: Be explicit about expected behavior
- Use Sonnet: Anthropic recommends Sonnet 4.5 for agents
- Test Thoroughly: Test agent with various inputs
Skills Development¶
Skill File Structure¶
---
name: my-skill
description: Brief skill description
allowed-tools: Read, Write, Grep, Glob, Bash
---
# Skill Name
Brief introduction to the skill.
## When to Use
Describe scenarios where this skill should be activated.
## How It Works
Explain the skill's approach and methodology.
## Examples
### Example 1
Input/scenario description
Expected outcome
## Guidelines
- Guideline 1
- Guideline 2
## See Also
- [Related Skill](../related/SKILL.md)
- [Documentation](../../docs/guide.md)
Skill Guidelines¶
- Progressive Disclosure: Keep SKILL.md under 500 lines
- Link to Additional Files: Use markdown links for details
- Clear Scope: Define when skill should/shouldn't be used
- Include Examples: Show real usage scenarios
- Specify Tools: List all required tools in YAML
Documentation¶
Markdown Style¶
# Page Title
Brief introduction paragraph.
## Section
Content here.
### Subsection
More specific content.
#### Rarely Use H4
Only for very deep hierarchies.
## Code Examples
All code blocks must specify language:
\`\`\`python
def example():
pass
\`\`\`
\`\`\`bash
command --flag value
\`\`\`
## Lists
- Unordered item 1
- Unordered item 2
- Nested item
- Nested item
1. Ordered item 1
2. Ordered item 2
## Links
- [Internal Link](./other-doc.md)
- [External Link](https://example.com)
- [Heading Link](#section)
## Tables
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Data | Data | Data |
## Admonitions
**Note:** Additional information
**Warning:** Caution required
**Important:** Critical information
Git Conventions¶
Commit Messages¶
Format:
Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation only
- style: Formatting, missing semi-colons, etc.
- refactor: Code change that neither fixes bug nor adds feature
- perf: Performance improvement
- test: Adding missing tests
- chore: Build process, auxiliary tools
Examples:
# Simple
feat: add JWT authentication
# With scope
feat(auth): add JWT authentication
# With body
feat(auth): add JWT authentication
Implements token generation, validation, and refresh.
Uses RS256 signing with 1-hour TTL.
# With breaking change
feat(auth): change authentication API
BREAKING CHANGE: authenticate() now returns User | None instead of User
Branch Naming¶
# Features
feat/user-authentication
feat/api-rate-limiting
# Fixes
fix/session-timeout
fix/memory-leak
# Documentation
docs/add-api-guide
docs/update-readme
# Refactoring
refactor/simplify-auth-flow
refactor/extract-validators
# Tests
test/add-integration-tests
test/improve-coverage
Code Review¶
Review Checklist¶
Security: - [ ] No secrets in code - [ ] Input validation present - [ ] SQL injection prevented - [ ] XSS prevention applied - [ ] Path traversal prevented
Correctness: - [ ] Logic is sound - [ ] Edge cases handled - [ ] Error handling appropriate - [ ] Tests cover new code
Performance: - [ ] No obvious inefficiencies - [ ] Appropriate data structures - [ ] No memory leaks - [ ] Database queries optimized
Maintainability: - [ ] Code is readable - [ ] Comments explain "why" - [ ] Functions are focused - [ ] DRY principle followed
Standards: - [ ] Follows style guide - [ ] Has type hints - [ ] Has docstrings - [ ] Passes linting
Last Updated: November 7, 2025 Version: 2.3.0