I've been running Odysseus as my daily-driver AI interface — local LLMs, document RAG, email triage, calendar sync. It's a web-based FastAPI app that works great in the browser, but I wanted a proper macOS app I could launch from my dock and distribute as a DMG.
So I built one. Here's what the app does and how I packaged it.
What it does
- 💬 Multi-Provider Chat — LM Studio, Ollama, DeepSeek, SiliconFlow, Anthropic, OpenAI
- 🤖 AI Agents — Custom assistants with MCP tools, web browsing, shell access
- 📄 Document RAG — PDFs, Office files, Markdown with full-text + vector search
- 📧 Email Client — IMAP/SMTP with AI triage
- 📅 Calendar — CalDAV sync (Nextcloud, Apple, Fastmail)
- 🍳 Cookbook — Download and serve models via llama.cpp / vLLM
- 🔬 Deep Research — Multi-step source synthesis
- 🧠 Memory & Skills — Persistent vector memory, your agent learns over time
Tech Stack
| Layer | Tool |
|---|---|
| Web framework | FastAPI (Python 3.11) |
| Frontend | Vanilla JS + CSS (PWA) |
| LLM providers | LM Studio, Ollama, DeepSeek, SiliconFlow, OpenAI, Anthropic |
| Vector store | ChromaDB + fastembed |
| Model serving | llama.cpp / vLLM |
| macOS app | Shell launcher + pywebview + DMG |
How I turned it into a macOS app
The base project already had a build-macos-app.sh script, but I rewrote it to produce a proper .app bundle and .dmg that anyone can build:
./build-macos-app.sh
This creates two things:
1. dist/Odysseus.app — A macOS app bundle. The executable is a shell script that:
- Starts the Python backend (
uvicorn app:app) - Launches ChromaDB for vector search
- Opens the UI in a chromeless window (via pywebview, or falls back to Chromium)
- Cleans up all services when you close the window
2. dist/Odysseus.dmg — A drag-to-Applications disk image for distribution.
The .app is just a launcher — no embedded Python, no bundled binary. It drives the venv in the repo directory.
The app window wrapper
The key piece is scripts/app_window.py, which uses pywebview to open the web UI in a native macOS window — no browser chrome, feels like a real app. If pywebview isn't available, it falls back to opening a chromeless Chromium window via --app=.
Closing the window stops everything: the web server, ChromaDB, all child processes. The cleanup trap in the launcher script makes sure no stray Python processes are left behind.
Architecture
Odysee/
├── app.py # FastAPI entry point
├── src/ # Core logic
│ ├── llm_core.py # Multi-provider LLM abstraction
│ ├── agent_loop.py # Agent execution loop
│ ├── chat_handler.py # Chat processing
│ ├── model_discovery.py # Auto-detect local models
│ └── mcp_manager.py # MCP server management
├── routes/ # API endpoints
├── services/ # Background services
├── static/ # Frontend (JS/CSS/HTML)
├── scripts/ # CLI tools + app_window.py
├── tests/ # ~350 tests
└── data/ # Created on first run
uvicorn app:app --host 127.0.0.1 --port 7860
The flask-style backend runs on localhost:7860. The frontend is vanilla JS with no build step — just open index.html and it works.
Quick Start
git clone https://github.com/AlexDesign420/Odysee-MacOS-App.git
cd Odysee-MacOS-App
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python setup.py
./venv/bin/uvicorn app:app --host 127.0.0.1 --port 7860
Open http://127.0.0.1:7860. First boot creates an admin account.
To build the macOS app:
./build-macos-app.sh
open dist/Odysseus.dmg
GitHub: AlexDesign420/Odysee-MacOS-App
Top comments (0)