- Document 3 graceful degradation patterns with code examples - Add Service Fallback Matrix for optional services - Add module dependency tree with change impact guide chore: fix typecheck environment - Add mypy to dev dependencies in pyproject.toml - Fix tox.ini typecheck environment to install mypy explicitly
9.8 KiB
CLAUDE.md — AI Assistant Guide for Timmy Time
Tech stack: Python 3.11+ · FastAPI · Jinja2 + HTMX · SQLite · Agno · Ollama · pydantic-settings · WebSockets · Docker
For agent roster and conventions, see AGENTS.md.
Architecture Patterns
Config access
from config import settings
url = settings.ollama_url # never use os.environ.get() directly in app code
Singletons
from dashboard.store import message_log
from infrastructure.notifications.push import notifier
from infrastructure.ws_manager.handler import ws_manager
HTMX response pattern
return templates.TemplateResponse(
"partials/chat_message.html",
{"request": request, "role": "user", "content": message}
)
Graceful degradation
Optional services (Ollama, Redis, AirLLM) degrade gracefully — log the error, return a fallback, never crash.
Route registration
New routes: src/dashboard/routes/<name>.py → register in src/dashboard/app.py.
Development Environments (tox)
tox is the single source of truth for all Python environments.
Never run poetry run directly — always go through tox. All environment
config (deps, markers, flags) lives in tox.ini. The Makefile and CI
both delegate to tox.
Quick reference
tox -e unit # Fast unit tests (default pre-commit gate)
tox -e ci # Full CI suite with coverage + JUnit XML
tox -e lint # black --check + isort --check + bandit
tox -e format # Auto-format (black + isort)
tox -e dev # Start dashboard with auto-reload
All tox environments
| Environment | Purpose |
|---|---|
lint |
Check formatting + imports + security |
format |
Auto-format code |
typecheck |
mypy static analysis |
unit |
Fast unit tests, parallel |
integration |
Integration tests, parallel |
functional |
Functional tests, sequential |
e2e |
End-to-end tests |
fast |
unit + integration combined |
ollama |
Live LLM tests (requires Ollama) |
ci |
Coverage + JUnit XML (mirrors GitHub Actions) |
coverage |
Coverage terminal + XML |
coverage-html |
Coverage HTML report |
pre-push |
Lint + full CI suite (mirrors GitHub Actions exactly) |
dev |
uvicorn with auto-reload |
all |
All tests, parallel |
Testing notes
- Stubs in conftest:
agno,airllm,pyttsx3,telegram,discordstubbed viasys.modules.setdefault()— tests run without those packages - Test mode:
TIMMY_TEST_MODE=1set automatically in conftest - FastAPI testing: Use the
clientfixture - Async:
asyncio_mode = "auto"— async tests detected automatically - Coverage threshold: 73% (
fail_underinpyproject.toml)
Key Conventions
- Tests must stay green. Run
tox -e unitbefore committing. Runtox -e pre-pushbefore pushing (mirrors CI exactly). - No cloud AI dependencies. All inference on localhost.
- Keep the root directory clean. No new top-level files without purpose.
- Follow existing patterns — singletons, graceful degradation, pydantic config.
- Security defaults: Never hard-code secrets.
- XSS prevention: Never use
innerHTMLwith untrusted content. - Keep routes thin — business logic lives in the module, not the route.
- Prefer editing existing files over creating new ones.
- Use
from config import settingsfor all env-var access. - Use tox for everything. Never run
poetry rundirectly — usetox -e <env>. - No inline CSS in templates. All styles go in
static/style.css(base theme) orstatic/css/mission-control.css(page-specific).{% block extra_styles %}must stay empty. If you need new styles, append them to the appropriate CSS file. - Use the panel macro for repeated
.card.mc-panelmarkup:{% from "macros.html" import panel %}/{% call panel("TITLE") %}...{% endcall %}. Seemacros.htmlfor kwargs (id, hx_get, etc.). - Toast for transient messages. Use
McToast.show(msg, level)(info/warn/error) instead of rendering errors inline in the chat log. The toast container lives inbase.html. - Never block the event loop. Wrap synchronous I/O (HTTP calls, file reads) in
asyncio.to_thread(). Cache health-check results with a TTL when polling external services.
Error Handling Patterns
All optional services (Ollama, Redis, AirLLM, voice, etc.) must degrade gracefully. Three approved patterns:
Pattern 1: Optional Return (data retrieval)
def get_user_setting(key: str) -> Optional[str]:
try:
return db.query(...)
except Exception as exc:
logger.warning("Setting lookup failed: %s", exc)
return None
Pattern 2: Fallback Value (computations)
def compute_embedding(text: str) -> list[float]:
try:
return model.encode(text)
except Exception as exc:
logger.warning("Embedding failed, using hash: %s", exc)
return hash_based_fallback(text)
Pattern 3: Feature Disable (optional services)
async def transcribe_audio(audio: bytes) -> str:
try:
return await voice_service.transcribe(audio)
except ServiceUnavailable:
logger.warning("Voice service unavailable — feature disabled")
return "" # Silently disable feature
Service Fallback Matrix
| Service | When Unavailable | Fallback Behavior |
|---|---|---|
| Ollama | No local LLM | Claude backend (if ANTHROPIC_API_KEY set) |
| Redis | Cache/storage down | In-memory dict (ephemeral) |
| AirLLM | Import error or no Apple Silicon | Ollama backend |
| Voice (Piper) | Service down | Browser Web Speech API |
| WebSocket | Connection failed | HTTP polling (degraded) |
| Telegram/Discord | No token configured | Bot doesn't start (logs only) |
Rule: Never crash the app when an optional service is down. Log at WARNING level and continue.
Frontend Architecture
Stylesheets
| File | Purpose |
|---|---|
static/style.css |
Base theme: palette, layout, header, chat, Bootstrap overrides, mobile breakpoints |
static/css/mission-control.css |
Page-specific styles (tasks, briefing, swarm, calm, etc.), toast system, connection indicator |
Rule: No <style> blocks in Jinja2 templates. All CSS lives in the two static files above. The {% block extra_styles %} hook exists for emergencies only and must remain empty in committed code.
CSS custom properties
Defined in :root in style.css. Use these — never hard-code colours:
var(--green) var(--amber) var(--red) var(--purple) var(--orange)
var(--text-bright) var(--text) var(--text-dim)
var(--bg-deep) var(--bg-panel) var(--bg-card) var(--border)
Jinja2 macros
src/dashboard/templates/macros.html — reusable components:
{% from "macros.html" import panel %}
{% call panel("TITLE", hx_get="/endpoint", hx_trigger="every 10s") %}
<p>Panel body content</p>
{% endcall %}
Toast notifications (JS)
McToast.show('Ollama reconnected', 'info'); // green border
McToast.show('Connection lost', 'warn'); // amber border
McToast.show('Request failed', 'error'); // red border
Security-Sensitive Areas
src/timmy_serve/— API server, payment configuration- Any file handling secrets or authentication tokens
Entry Points
| Command | Module | Purpose |
|---|---|---|
timmy |
src/timmy/cli.py |
Chat, think, status |
timmy-serve |
src/timmy_serve/cli.py |
API server (port 8402) |
Module Map (8 packages)
| Package | Purpose |
|---|---|
timmy/ |
Core agent, personas, agent interface, semantic memory |
dashboard/ |
FastAPI web UI, routes, templates |
infrastructure/ |
WebSocket, notifications, events, LLM router |
integrations/ |
Discord, Telegram, Siri Shortcuts, voice NLU |
spark/ |
Event capture and advisory engine |
brain/ |
Identity system, memory interface |
timmy_serve/ |
API server |
config.py |
Pydantic settings (foundation for all modules) |
Module Dependencies
config.py # Foundation — no internal dependencies
│
├── timmy/ # Core agent
│ ├── Uses: config, brain, infrastructure
│ └── Impact: 🔴 High — used by dashboard, integrations, timmy_serve
│
├── brain/ # Memory system
│ ├── Uses: config
│ └── Impact: 🟡 Medium — used by timmy, spark
│
├── infrastructure/ # Shared services
│ ├── Uses: config
│ └── Impact: 🔴 High — used by ALL packages
│ ├── ws_manager # WebSocket connections
│ ├── notifier # Push notifications
│ └── event_bus # Pub/sub events
│
├── spark/ # Intelligence engine
│ ├── Uses: config, brain
│ └── Impact: 🟢 Low — self-contained
│
├── integrations/ # External services
│ ├── Uses: config, infrastructure
│ └── Impact: 🟡 Medium — isolated by vendor
│
├── dashboard/ # Web UI
│ ├── Uses: ALL packages
│ └── Impact: 🔴 High — entry point, orchestrates everything
│
└── timmy_serve/ # API server
├── Uses: config, timmy, infrastructure
└── Impact: 🟡 Medium — standalone service
Change Impact Guide
| If you modify... | You should test... |
|---|---|
config.py |
Full suite (tox -e ci) — affects everything |
infrastructure/ |
Unit + integration + functional |
timmy/ |
Unit tests + chat/CLI tests |
dashboard/routes/ |
Dashboard route tests (usually isolated) |
brain/ |
Brain client/worker tests + timmy tests |