atomic_write_json/atomic_write_text build their temp filename as
"{path}.tmp.{os.getpid()}". os.getpid() is constant for the life of a
process, so it only ever distinguishes concurrent writers that live in
different OS processes. Odysseus runs as a single long-lived process
per container, so two concurrent writers to the same path (e.g. two
request handlers racing a settings save) always compute the identical
temp path. Whichever finishes os.replace() first removes the shared
tmp file out from under the other, which then raises FileNotFoundError
on its own os.replace() instead of landing its write.
Fix: derive the temp suffix from uuid4() instead of the PID, so every
call gets a distinct temp path regardless of process/thread identity.
routes/prefs_routes.py's _save() had an independent, hand-rolled copy
of the exact same PID-suffix logic (not the shared core.atomic_io
helper other routes already use, e.g. routes/auth_routes.py) with the
same bug. Replaced it with a call to atomic_write_json.
Fixes #5596
|
||
|---|---|---|
| .github | ||
| companion | ||
| config/searxng | ||
| core | ||
| docker | ||
| docs | ||
| integrations | ||
| licenses | ||
| mcp_servers | ||
| routes | ||
| scripts | ||
| services | ||
| specs | ||
| src | ||
| static | ||
| swift/odysseus-mlx-image-bridge | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| ACKNOWLEDGMENTS.md | ||
| app.py | ||
| build-macos-app.sh | ||
| build-windows-portable.ps1 | ||
| CONTRIBUTING.md | ||
| docker-compose.gpu-amd.yml | ||
| docker-compose.gpu-nvidia.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| install-service.sh | ||
| launch-windows.ps1 | ||
| launcher.py | ||
| LICENSE | ||
| odysseus-ui.service | ||
| Odysseus.spec | ||
| package-lock.json | ||
| package.json | ||
| pyproject.toml | ||
| README.md | ||
| requirements-optional.txt | ||
| requirements.txt | ||
| ROADMAP.md | ||
| SECURITY.md | ||
| setup.py | ||
| start-macos.sh | ||
| THREAT_MODEL.md | ||
| update_windows.bat | ||
A self-hosted AI workspace for chat, agents, research, documents, email, notes, calendar, and local model workflows.
Quick Start · Setup Guide · Contributing · Roadmap
Quick Start
devis the default branch and gets the newest changes first. Usemainif you want the more curated branch.
git clone https://github.com/odysseus-dev/odysseus.git
cd odysseus
cp .env.example .env
docker compose up -d --build
Open http://localhost:7000 when the containers are healthy. The first admin password is printed in docker compose logs odysseus.
Native installs, GPU notes, Windows/macOS instructions, HTTPS, and configuration live in the setup guide.
Features
- Chat + Agents — local/API models, tools, MCP, files, shell, skills, and memory.
- Cookbook — hardware-aware model recommendations, downloads, and serving.
- Deep Research — multi-step web research with source reading and report generation.
- Compare — blind side-by-side model testing and synthesis.
- Documents — writing-first editor with AI edits, suggestions, Markdown, HTML, CSV, and syntax highlighting.
- Email — IMAP/SMTP inbox with triage, tags, summaries, reminders, and reply drafts.
- Notes, Tasks + Calendar — reminders, todos, scheduled agent tasks, and CalDAV sync.
- Extras — gallery/image editor, themes, uploads, web search, presets, sessions, and 2FA.
Demo
A full hover-to-play tour lives on the landing page: docs/index.html.
Contributing
Help is welcome. The best entry points are fresh-install testing, provider setup bugs, mobile/editor polish, docs, and small focused refactors. See CONTRIBUTING.md and ROADMAP.md.
Security
Odysseus is a self-hosted workspace with powerful local tools. Keep auth enabled, keep private data out of Git, and do not expose raw model/service ports publicly. Deployment details are in the setup guide.
Star History
License
AGPL-3.0-or-later -- see LICENSE and ACKNOWLEDGMENTS.md.