The Problem
Teams that need a locally‑hosted AI assistant must cobble together separate chat, document, and tooling services, each with its own auth, persistence, and deployment model. Maintaining consistency, security, and a unified UI quickly becomes a heavy operational burden.
What This Does
odysseus bundles a full AI workspace behind a single FastAPI‑style backend (app.py) and a React front‑end (static/app.js). Core persistence lives in core/database.py, which defines the ORM models and the utcnow_* helpers used throughout the stack. Feature modules such as chat, email, documents, and calendar are organized under routes/ (e.g., routes/chat_routes.py, routes/email_routes.py) and services/ (e.g., services/docs/service.py). The repository ships Docker orchestration (Dockerfile, docker‑compose.yml, GPU‑specific compose files) so the entire stack can be launched with a single command.
How It Is Wired
Execution begins in app.py at line 177 (dispatch) which registers the FastAPI app and mounts static assets. From there the request lifecycle follows the internal call graph:
- Request routing – each HTTP endpoint is wired in
routes/*. For example,setup_email_routes(inroutes/email_routes.py) registers aPOSThandler that ultimately callspost(a generic DB helper) 14 times. - Core services – handlers call into
core/database.py(query,filter,commit,delete). Thequeryfunction is the most widely used primitive (called from 268 distinct places). - Business logic –
src/llm_core.pyandsrc/agent_loop.pyimplement LLM interaction and agent orchestration; both are part of a circular import cycle (highlighted as a high‑risk module). - External effects – the call chain
dispatch → create_task → db.query(...).filter(...)performs a cryptographic token (secrets.token_urlsafe) and writes to the database. Similarly,execute(viascripts/_lib/cli.py:run) creates a session and commits changes. Outbound network calls are limited to a few helpers incore/auth.pyandroutes/email_helpers.py, which contact external mail providers. - Blast radius –
core/database.pyis a hub (104 inbound imports, 3 outbound), so any change here can affect the entire codebase. The import cycle involvingsrc/llm_core.pyandstatic/js/ui.jsraises instability (0.98) and makes refactoring risky.
Unmapped wiring: the React front‑end (static/app.js) interacts with the backend via the generated OpenAPI spec, but static analysis does not resolve those HTTP calls.
How To Use It
# Clone the exact repo
git clone https://github.com/moses-y/odysseus.git
cd odysseus
# Prepare environment (see .env.example)
cp .env.example .env
# Build and start all containers (GPU optional)
docker compose up -d --build # default CPU
# or for NVIDIA GPUs
docker compose -f docker-compose.gpu-nvidia.yml up -d --build
The service listens on http://localhost:7000 once containers are healthy. The first admin password appears in docker compose logs odysseus. For CLI tasks, invoke the bundled script:
python scripts/_lib/cli.py run --help
Real‑World Use
A SaaS team can run odysseus on an internal VM to provide a private chat assistant that can read corporate documents, draft emails, and schedule calendar events without exposing any data to external APIs. The workflow is:
import requests
resp = requests.post(
"http://localhost:7000/api/chat",
json={"message": "Summarize the Q3 report"},
timeout=30, # respects the CI‑recommended timeout
)
print(resp.json()["reply"])
All persistence stays in the local SQLite/Postgres DB defined in core/database.py.
Code Health & Issues
- High – Remove
continue-on-errorfrom correctness steps in.github/workflows/ci.yml(line 55). - Medium – Pin Docker base image by digest in
Dockerfile. - Medium – Add explicit request timeouts to outbound calls (identified in
docker-compose.yml). - Medium – Exclude generated build output from VCS (
static/contains six generated files). - Medium – Run container as non‑root (add
USERdirective toDockerfile). - Low – Set
timeout-minuteson CI jobs (.github/workflows/ci.yml).
Static analysis also flagged 620 issues: deep nesting (max depth 8) and oversized files (> 1900 lines) in core/database.py, src/llm_core.py, and static/js/ui.js; broad except: blocks; and import cycles (e.g., src/llm_core.py). These are documented in the measured findings and should be prioritized for maintainability.
The Bottom Line
odysseus delivers a feature‑complete, self‑hosted AI workspace with a single Docker‑compose launch, but its core modules are tightly coupled and contain several high‑impact technical debts (large hub files, import cycles, deep nesting). It is suitable for teams that value on‑prem control and can allocate effort to refactor the database and LLM core layers for long‑term stability.