Coding Standards¶
Working Style¶
Be a scalpel, not a hammer.
- Ask questions early when stuck or uncertain, rather than repeatedly trying the same approach
- If something fails 2-3 times, step back and re-evaluate
- Precision over persistence -- one well-aimed question beats five failed attempts
Language and Framework¶
- Python 3.11+ for all backend services
- FastAPI + Uvicorn for all HTTP services
- Docker + Docker Compose for containerization
- TypeScript for the mobile app (React Native/Expo)
Imports¶
All imports must be at the top of the file. No mid-file imports unless absolutely necessary (e.g., circular import resolution).
Group imports in this order:
- Standard library
- Third-party packages
- Local imports
# Standard library
import os
from datetime import datetime, timezone
from typing import Any
# Third-party
import httpx
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
# Local
from app.core.config import settings
from app.services.memory_service import MemoryService
Type Hints¶
Always use type hints on every function parameter, return type, and variable declaration. No ambiguous signatures.
# Good
def process_command(text: str, user_id: int, timeout: float = 5.0) -> CommandResponse | None:
count: int = 0
results: list[dict[str, Any]] = []
...
# Bad
def process_command(text, user_id, timeout=5.0):
count = 0
results = []
...
Prefer X | None over Optional[X] (Python 3.10+ syntax). Use the typing module for complex types (TypeVar, Protocol, etc.).
Logging¶
All logging must go through jarvis-log-client to the jarvis-logs service. No print() statements in production code.
from jarvis_log_client import JarvisLogger
logger = JarvisLogger("my-service")
logger.info("Processing command", extra={"user_id": user_id, "command": command_name})
logger.error("Command failed", extra={"error": str(e)}, exc_info=True)
The only acceptable uses of print() are:
- CLI scripts (e.g.,
install_command.py,authorize_node.py) - Test files
- Worker
_safe_print()pattern (for pre-logger-init output)
Exception Handling¶
- Never use bare
except:-- always catch specific exception types - Always capture the exception with
as ewhen usingexcept Exception - Prefer specific exceptions (
ValueError,httpx.HTTPError) over broadException
# Good
try:
result = await client.post(url, json=payload)
result.raise_for_status()
except httpx.HTTPStatusError as e:
logger.error("HTTP error", extra={"status": e.response.status_code})
except httpx.RequestError as e:
logger.error("Connection error", extra={"error": str(e)})
# Bad
try:
result = await client.post(url, json=payload)
except:
pass
New Services¶
When creating a new service:
- Use Docker containers with
Dockerfileanddocker-compose.yaml - Follow existing service patterns (FastAPI + Uvicorn)
- Include a
CLAUDE.mdwith service-specific documentation - Add health check endpoint at
/health - Use Alembic for database migrations
- Register with
jarvis-config-servicefor service discovery - Use
jarvis-log-clientfor logging - Add the service to the CLI's service registry in the
jarvisscript
Code Quality¶
- Target 80%+ test coverage for all services
- Run
pytestbefore committing - Use
rufffor linting (configured at the project level) - Keep files under 500 lines -- split into modules if growing larger