diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..5640417 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,267 @@ +# CLAUDE.md — AI Assistant Guide for Timmy Time + +This file provides context for AI assistants (Claude Code, Copilot, etc.) +working in this repository. Read this before making any changes. + +For multi-agent development standards and agent-specific conventions, see +[`AGENTS.md`](AGENTS.md). + +--- + +## Project Summary + +**Timmy Time** is a local-first, sovereign AI agent system with a browser-based +Mission Control dashboard. No cloud AI — all inference runs on localhost via +Ollama (or AirLLM for large models). Bitcoin Lightning economics are built in +for API access gating. + +**Tech stack:** Python 3.11+ · FastAPI · Jinja2 + HTMX · SQLite · Agno (agent +framework) · Ollama · pydantic-settings · WebSockets · Docker + +--- + +## Quick Reference Commands + +```bash +# Setup +make install # Create venv + install dev deps +cp .env.example .env # Configure environment + +# Development +make dev # Start dashboard at http://localhost:8000 +make test # Run full test suite (no Ollama needed) +make test-cov # Tests + coverage report (terminal + XML) +make lint # Run ruff or flake8 + +# Docker +make docker-build # Build timmy-time:latest image +make docker-up # Start dashboard container +make docker-agent # Spawn one agent worker +make docker-down # Stop all containers +``` + +--- + +## Project Layout + +``` +src/ + config.py # Central pydantic-settings (all env vars) + timmy/ # Core agent: agent.py, backends.py, cli.py, prompts.py + dashboard/ # FastAPI app + routes + Jinja2 templates + app.py # App factory, lifespan, router registration + store.py # In-memory MessageLog singleton + routes/ # One file per route group (agents, health, swarm, etc.) + templates/ # base.html + page templates + partials/ + swarm/ # Multi-agent coordinator, registry, bidder, tasks, comms + coordinator.py # Central swarm orchestrator (security-sensitive) + docker_runner.py # Spawn agents as Docker containers + timmy_serve/ # L402 Lightning proxy, payment handler, TTS, CLI + spark/ # Intelligence engine — events, predictions, advisory + creative/ # Creative director + video assembler pipeline + tools/ # Git, image, music, video tools for persona agents + lightning/ # Lightning backend abstraction (mock + LND) + agent_core/ # Substrate-agnostic agent interface + voice/ # NLU intent detection (regex-based, local) + websocket/ # WebSocket connection manager (ws_manager singleton) + notifications/ # Push notification store (notifier singleton) + shortcuts/ # Siri Shortcuts API endpoints + telegram_bot/ # Telegram bridge + self_tdd/ # Continuous test watchdog +tests/ # One test_*.py per module, all mocked +static/ # style.css + bg.svg (dark arcane theme) +docs/ # GitHub Pages landing site +``` + +--- + +## Architecture Patterns + +### Config access + +All configuration goes through `src/config.py` using pydantic-settings: + +```python +from config import settings +url = settings.ollama_url # never use os.environ.get() directly in app code +``` + +Environment variables are read from `.env` automatically. See `.env.example` for +all available settings. + +### Singletons + +Core services are module-level singleton instances imported directly: + +```python +from dashboard.store import message_log +from notifications.push import notifier +from websocket.handler import ws_manager +from timmy_serve.payment_handler import payment_handler +from swarm.coordinator import coordinator +``` + +### HTMX response pattern + +Routes return Jinja2 template partials for HTMX requests: + +```python +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: + +```python +try: + result = await some_optional_service() +except Exception: + result = fallback_value +``` + +### Route registration + +New routes go in `src/dashboard/routes/.py`, then register the router in +`src/dashboard/app.py`: + +```python +from dashboard.routes. import router as _router +app.include_router(_router) +``` + +--- + +## Testing + +### Running tests + +```bash +make test # Quick run (pytest -q --tb=short) +make test-cov # With coverage (term-missing + XML) +make test-cov-html # With HTML coverage report +``` + +No Ollama or external services needed — all heavy dependencies are mocked. + +### Test conventions + +- **One test file per module:** `tests/test_.py` +- **Stubs in conftest:** `agno`, `airllm`, `pyttsx3`, `telegram` are stubbed in + `tests/conftest.py` using `sys.modules.setdefault()` so tests run without + those packages installed +- **Test mode:** `TIMMY_TEST_MODE=1` is set automatically in conftest to disable + auto-spawning of persona agents during tests +- **FastAPI testing:** Use the `client` fixture (wraps `TestClient`) +- **Database isolation:** SQLite files in `data/` are cleaned between tests; + coordinator state is reset via autouse fixtures +- **Async:** `asyncio_mode = "auto"` in pytest config — async test functions + are detected automatically +- **Coverage threshold:** CI fails if coverage drops below 60% + (`fail_under = 60` in `pyproject.toml`) + +### Adding a new test + +```python +# tests/test_my_feature.py +from fastapi.testclient import TestClient + +def test_my_endpoint(client): + response = client.get("/my-endpoint") + assert response.status_code == 200 +``` + +--- + +## CI/CD + +GitHub Actions workflow (`.github/workflows/tests.yml`): + +- Runs on every push and pull request to all branches +- Python 3.11, installs `.[dev]` dependencies +- Runs pytest with coverage + JUnit XML output +- Publishes test results as PR comments and check annotations +- Uploads coverage XML as a downloadable artifact (14-day retention) + +--- + +## Key Conventions + +1. **Tests must stay green.** Run `make test` before committing. +2. **No cloud AI dependencies.** All inference runs on localhost. +3. **No new top-level files without purpose.** Keep the root directory clean. +4. **Follow existing patterns** — singletons, graceful degradation, + pydantic-settings config. +5. **Security defaults:** Never hard-code secrets. Warn at startup when using + default values. +6. **XSS prevention:** Never use `innerHTML` with untrusted content. +7. **Keep routes thin** — business logic lives in the module, not the route. +8. **Prefer editing existing files** over creating new ones. +9. **Use `from config import settings`** for all env-var access. +10. **Every new module gets a test:** `tests/test_.py`. + +--- + +## Entry Points + +Three CLI commands are installed via `pyproject.toml`: + +| Command | Module | Purpose | +|---------|--------|---------| +| `timmy` | `src/timmy/cli.py` | Chat, think, status commands | +| `timmy-serve` | `src/timmy_serve/cli.py` | L402-gated API server (port 8402) | +| `self-tdd` | `src/self_tdd/watchdog.py` | Continuous test watchdog | + +--- + +## Environment Variables + +Key variables (full list in `.env.example`): + +| Variable | Default | Purpose | +|----------|---------|---------| +| `OLLAMA_URL` | `http://localhost:11434` | Ollama host | +| `OLLAMA_MODEL` | `llama3.2` | Model served by Ollama | +| `DEBUG` | `false` | Enable `/docs` and `/redoc` | +| `TIMMY_MODEL_BACKEND` | `ollama` | `ollama` / `airllm` / `auto` | +| `AIRLLM_MODEL_SIZE` | `70b` | `8b` / `70b` / `405b` | +| `L402_HMAC_SECRET` | *(change in prod)* | HMAC signing for invoices | +| `L402_MACAROON_SECRET` | *(change in prod)* | Macaroon signing | +| `LIGHTNING_BACKEND` | `mock` | `mock` / `lnd` | +| `SPARK_ENABLED` | `true` | Enable Spark intelligence engine | +| `TELEGRAM_TOKEN` | *(empty)* | Telegram bot token | + +--- + +## Persistence + +- `timmy.db` — Agno agent memory (SQLite, project root) +- `data/swarm.db` — Swarm registry + tasks (SQLite, `data/` directory) +- All `.db` files are gitignored — never commit database files + +--- + +## Docker + +Containers share a `data/` volume for SQLite. Container agents communicate with +the coordinator over HTTP (not in-memory `SwarmComms`): + +``` +GET /internal/tasks → list tasks open for bidding +POST /internal/bids → submit a bid +``` + +`COORDINATOR_URL=http://dashboard:8000` is set automatically by docker-compose. + +--- + +## Security-Sensitive Areas + +- `src/swarm/coordinator.py` — requires review before changes +- `src/timmy_serve/l402_proxy.py` — Lightning payment gating +- `src/lightning/` — payment backend abstraction +- Any file handling secrets or authentication tokens