Architecture¶
Odysseus is a single FastAPI application (app.py) that serves both the API
and the static frontend, backed by SQLite (via SQLAlchemy) for structured data
and a set of optional local services for AI features. It's designed to run as
one process (or one container) per user/household, not as a multi-tenant SaaS.
This document is a house-pipeline-convention companion to the existing
SECURITY.md, THREAT_MODEL.md,
and docs/security-ci.md - those remain the canonical
security docs; this file is about component shape, not trust boundaries.
Component diagram¶
flowchart TB
subgraph Client["Browser"]
UI["static/ (vanilla JS SPA)"]
end
subgraph App["Odysseus process (app.py, FastAPI/Starlette)"]
MW["core/middleware.py\n(security headers, CORS)"]
Auth["core/auth.py\n(sessions, TOTP, API tokens)"]
Routes["routes/*.py\n(~60 route modules)"]
Agent["src/agent_loop.py + src/tool_*\n(agent/tool execution)"]
Services["services/*\n(search, memory, hwfit, docs, shell, stt/tts, youtube)"]
Companion["companion/*\n(remote pairing)"]
MCP["mcp_servers/*\n(email, image-gen, memory, rag)"]
end
subgraph Data["Local data"]
SQLite[("data/app.db\nSQLAlchemy models")]
AuthJSON["data/auth.json"]
Chroma[("ChromaDB\n(vector store, optional)")]
FS["data/ (uploads, gallery, logs, backups)"]
end
subgraph External["External / host services (all optional, user-configured)"]
LLM["LLM providers\n(Ollama/OpenAI/Anthropic/local servers)"]
Search["SearXNG / web search"]
Mail["IMAP/SMTP"]
CalDAV["CalDAV servers"]
Ntfy["ntfy push"]
end
UI <--> MW --> Auth --> Routes
Routes --> Agent
Routes --> Services
Routes --> Companion
Agent --> MCP
Agent --> Services
Routes --> SQLite
Auth --> AuthJSON
Services --> Chroma
Services --> FS
Agent --> LLM
Services --> Search
Services --> Mail
Services --> CalDAV
Services --> Ntfy
Request sequence: authenticated chat turn¶
sequenceDiagram
participant U as Browser
participant MW as SecurityHeadersMiddleware
participant A as core/auth.py
participant R as routes/chat_routes.py
participant CH as src/chat_handler.py
participant AG as src/agent_loop.py
participant LLM as LLM provider
participant DB as data/app.db
U->>MW: POST /api/chat (session cookie)
MW->>A: validate session / CSRF / origin
A-->>MW: user + owner scope
MW->>R: request, scoped user
R->>CH: dispatch chat turn
CH->>DB: load session history (owner-scoped)
CH->>AG: build tool-augmented prompt
AG->>LLM: stream completion (+ tool calls)
LLM-->>AG: tokens / tool_call events
AG->>DB: persist assistant message, tool results
AG-->>R: SSE stream
R-->>U: streamed response
Key directories¶
| Path | Purpose |
|---|---|
app.py |
Application entrypoint: FastAPI app, middleware, static mounting, lifespan startup. |
core/ |
Auth, DB session/models, middleware, exceptions, platform compatibility, atomic file I/O. |
routes/ |
One module per feature area (chat, email, calendar, gallery, research, vault, ...); thin HTTP layer over src//services/. |
src/ |
The bulk of business logic: agent loop and tool implementations, LLM client abstraction (llm_core.py), integrations, RAG/embeddings, security helpers (tool_security.py, url_safety.py, prompt_security.py). |
services/ |
Larger subsystems with their own internal structure: search, memory, hwfit (hardware-aware model fitting), research, shell, stt/tts, youtube. |
mcp_servers/ |
Standalone MCP server implementations Odysseus itself exposes (email, image-gen, memory, rag). |
companion/ |
Remote pairing/companion-device support. |
static/ |
The frontend: vanilla JS (no framework/bundler), organized by feature (static/js/editor/, static/js/compare/, etc.). |
data/ |
Gitignored runtime data: SQLite DB, auth store, uploads, logs, embedding/model caches. |
tests/ |
~1,300+ pytest files plus a tests/streaming/*.mjs Node harness for frontend streaming/markdown logic. |
.github/workflows/ |
CI: syntax checks, pytest (informational), secret scan (gitleaks), workflow security (actionlint/zizmor), container scan (hadolint/Trivy), dependency review, docker publish. |
Notable design choices¶
- Single-tenant-per-deployment, multi-user within it. Auth is real
(sessions, TOTP, API tokens, owner-scoped queries throughout
routes/andsrc/), but the threat model assumes a trusted set of users on a private network, not public multi-tenant isolation against malicious end users - seeTHREAT_MODEL.md. - No ORM migrations framework visible at this audit -
core/database.pydefines SQLAlchemy models directly;scripts/update_database.pyandscripts/backfill_model_release_dates.pyhandle ad hoc schema evolution. - Encrypted-at-rest integration credentials.
src/secret_storage.pyprovidesencrypt/decrypt/is_encrypted, used bysrc/integrations.pyto store user-supplied third-party API keys (e.g. Vaultwarden) rather than storing them in plaintext. - Vanilla JS frontend, no build step for the SPA itself -
static/js/is served directly, organized by feature folder.