# I built a self-hosted AI workspace for macOS — meet Odysee

> Source: <https://dev.to/alexdesign420/i-cleaned-up-a-self-hosted-ai-workspace-and-put-it-on-github-meet-odysee-macos-4291>
> Published: 2026-06-05 13:20:37+00:00

I've been running [Odysseus](https://github.com/pewdiepie-archdaemon/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.

| 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 |

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:

`uvicorn app:app`

)**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 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.

```
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.

```
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](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](https://github.com/AlexDesign420/Odysee-MacOS-App)
