Odysseus: dev is the default branch, the image tag moves on every push, and the admin password arrives in the logs
Self-hosted AI workspace. A self-hosted AI workspace for chat, agents, research, documents, email, notes, calendar, and local model workflows.
At a glance
- What is it?
- odysseus-dev/odysseus is a self-hosted AI workspace covering chat, agents, research, documents, email, notes and calendar, distributed as a multi-arch container image. The README is unusually candid about three traps: dev is what you clone, the short image tags move, and the first admin password is printed into docker compose logs.
- Who is it for?
- Use Odysseus if you want one self-hosted surface for chat, agents, research, email and calendar, and you are prepared to run it as a container with a real password and a pinned tag. Do not expose it to a network with AUTH_ENABLED left at a development value, and do not adopt it inside a product you cannot relicense, because the project is AGPL-3.0-or-later.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.
Star history
- odysseus-dev/odysseus95,610 ★ · +33,275
| Repository | 2026-07-28 | 2026-11-13 |
|---|---|---|
| odysseus-dev/odysseus | 62.3k | 95.6k |
33,275 Stars in the last 108 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
dev is the default branch, and the README tells you when to switch to main
The Quick Start begins with a warning before it begins with a command: dev is the default branch and gets the newest changes first, and main is the more curated branch. Anyone who clones without reading lands on the branch the maintainers change first.
git clone https://github.com/odysseus-dev/odysseus.git
cd odysseus
cp .env.example .env
docker compose up -d --buildConsequence for the reader: a clone is not a release. The distinction matters for anyone who intends to read the code rather than run it, because the two branches answer different questions: dev answers what the project is about to do, main answers what it currently supports. Neither is a version you can cite, and the repository publishes no GitHub releases at all, so the branch name is the only stability signal in the file.
The last push was on 2026-11-02, so the branch that moves fastest is also the one being written.
The compose file pulls a published image and only builds when the pull fails
The compose files point at the official multi-arch image ghcr.io/odysseus-dev/odysseus, published by CI on every push to main and to dev, and they build locally only if the pull does not succeed. The README draws the consequence explicitly: this also works on hosts without a build toolchain, for example as a Portainer stack.
That is a real design decision with a real cost. A machine with Docker and nothing else can run the whole workspace, and a machine with a stale or unreachable registry cannot, because the fallback is a local build that needs a build toolchain.
Consequence for the reader: the quick start is not the same operation as building the project. If you are reading the repository to understand how it works, the compose path skips almost all of the source, and the tree tells you why: app.py, launcher.py, setup.py, core/, routes/, services/, integrations/, src/, config/, companion/, and mcp_servers/ are all bypassed when the image pull succeeds.
The short tags move, and the immutable one has a commit sha in it
The README separates two kinds of tag in plain language. :latest and bare :X.Y.Z tags move on every push to main. A tag written as :X.Y.Z-<sha> always refers to one specific build, and the example given is 1.0.2-7c8070f.
ODYSSEUS_IMAGE=ghcr.io/odysseus-dev/odysseus:1.0.2-7c8070f docker compose up -dConsequence for the reader: a deployment that records which version it runs is recording a tag that may no longer point at that code. A rollback written as ODYSSEUS_IMAGE set to a version number is not a rollback, because the image behind that number has been replaced. Only the form with the sha in it survives, which is also the form nobody writes by hand, so the gap between what the README recommends and what most compose files contain is where upgrade surprises come from.
There is no GitHub release to pair the sha with, so the tag is the only handle you have.
The first admin password is printed into the compose logs
After the containers come up you open http://localhost:7011, and the first admin password is not written to a file you can find. The README says to read it from the container output, from docker compose logs odysseus.
Consequence for the reader: the README points you at the container logs rather than a file, so capture the password when you first start the stack.
The README's own security section is blunt about the rest: keep auth enabled, keep private data out of Git, and do not expose raw model or service ports publicly.
setup.py creates eleven directories before it creates a table
The native setup script is not a wrapper around a package manager. It imports a list of directory constants from src.constants, including DATA_DIR, UPLOAD_DIR, PERSONAL_DIR, PERSONAL_UPLOADS_DIR, TTS_CACHE_DIR, GENERATED_IMAGES_DIR, DEEP_RESEARCH_DIR, CHROMA_DIR, RAG_DIR, MEMORY_VECTORS_DIR, and AGENT_WORKSPACE_DIR, plus a logs directory, and creates each one. It then sets DATABASE_URL to a SQLite file inside the data directory if the environment does not already define one, imports Base and engine from core.database, and calls Base.metadata.create_all.
Only after that does it ask for a username and password, defaulting the username to admin, rejecting anything in RESERVED_USERNAMES imported from core.auth, and reading the password through getpass when a terminal is attached. A minimum length comes from the same constants module.
Consequence for the reader: the on-disk layout is created before anything is validated, so a half-finished setup leaves directories behind. And because create_all creates what is missing rather than migrating what is there, the script is a first-run tool, not an upgrade path. Native installs also bypass Docker entirely, which means the container image and the local install can drift in what they put on disk.
requirements.txt caps the MCP SDK below v2 and explains why in a comment
The dependency file is annotated rather than bare, and one of the annotations is a hard pin: mcp<2, with a comment saying that built-in servers use the v1 low-level Server decorator API, that MCP SDK v2 is a breaking rewrite, and that fresh installs stay on the maintained v1 line until the servers are migrated together.
Other comments record why a dependency is a core requirement rather than an extra. markdown is imported at module top for research reports, so it is a hard dependency. nh3 sanitizes rendered report HTML, because report content is untrusted as LLM output over crawled pages and report pages run under a relaxed CSP. caldav handles PROPFIND discovery and REPORT fetch across Radicale, Nextcloud, Apple and Fastmail, with the note that the protocol would otherwise be reinvented.
Consequence for the reader: chromadb-client and fastembed are installed by default for the vector store and local embeddings, with a comment that the app degrades to a keyword fallback if they are missing. The fallback is real but not free, so a deployment that strips those two packages to save space gets recall by keyword rather than by meaning. And mcp<2 means a security fix in the v2 line is unreachable until the server migration the comment describes is finished.
AUTH_ENABLED and LOCALHOST_BYPASS are the two switches the README names
The security section of the README is short and names two settings. Keep AUTH_ENABLED=true for any deployment that is reachable over a network. Keep LOCALHOST_BYPASS=false outside local development. Deployment details are in the setup guide under a security-notes heading.
The repository also carries THREAT_MODEL.md.
Consequence for the reader: the project tells you which two environment variables decide whether authentication is in the path at all, and a deployment can go wrong quietly, because AUTH_ENABLED=false is a perfectly reasonable value while developing on a laptop and a serious exposure on anything else.
The workspace's own feature list explains the stakes: shell access, file access, skills, memory, and a deep research mode that reads pages and writes reports.
The pytest config is a marker taxonomy with a fallback bucket and a fast lane
pyproject.toml holds no build metadata. It holds a pytest configuration with testpaths set to tests, asyncio_mode set to auto, and a marker list that is a classification scheme rather than a set of labels: area_security for auth, owner-scope, SSRF, XSS, confinement and redaction; area_routes for HTTP and API behavior; area_services for the service layer; area_cli; area_js for JavaScript and Node-backed tests; area_helpers for self-tests of the shared helpers; area_unit for parser and utility tests; and area_uncategorized, described as a fallback for tests not yet matched.
The last marker is different. slow is opt-in for known-slow tests and is excluded by a fast lane running not slow, and the comment attaches it to issue 3443 and says a test should be marked slow only with duration evidence.
Consequence for the reader: the taxonomy tells you where the project thinks its risk is, and the security bucket names the threat classes by their usual short names. But the presence of an area_uncategorized bucket means a contributor can add a test that lands in the fallback, and a fallback bucket is where coverage quietly stops being organised. The dynamic sub_ markers are registered by a hook in the test conftest rather than here, so a typo outside the taxonomy shows up as an unknown-mark warning rather than as a silently ignored label.
Editorial conclusion
Use Odysseus if you want one self-hosted surface for chat, agents, research, email and calendar, and you are prepared to run it as a container with a real password and a pinned tag. Do not expose it to a network with AUTH_ENABLED left at a development value, and do not adopt it inside a product you cannot relicense, because the project is AGPL-3.0-or-later. Before the first start, check three things: which branch you cloned, since dev is the default and gets the newest changes first, which image tag you pinned, since :latest and bare :X.Y.Z move on every push to main while :X.Y.Z-<sha> does not, and where the admin password was written, because it is printed into the compose logs rather than stored where you would look for it.
Frequently asked questions
How do I install Odysseus?
Clone the repository, copy .env.example to .env, and start it with docker compose up -d --build. The compose files pull the multi-arch image ghcr.io/odysseus-dev/odysseus and only build locally if the pull fails, so a host with Docker but no build toolchain is enough. Open http://localhost:7011 once the containers are healthy.
How do I use Odysseus once it is running?
The feature list covers chat and agents over local and API models with tools, MCP, files, shell, skills and memory; a Cookbook for hardware-aware model recommendations, downloads and serving; deep research with source reading and report generation; blind side-by-side model comparison; a writing-first document editor; an IMAP and SMTP inbox with triage and reply drafts; notes, tasks and calendar with CalDAV sync.
How do I install Odysseus on Mac?
The README's Quick Start is container based and platform neutral, using docker compose up -d --build. For a native macOS install the repository ships build-macos-app.sh and start-macos.sh, and the details live in the setup guide, website/setup.md.
How do I use Odysseus on Windows?
The repository ships Windows-specific entry points: launch-windows.ps1, build-windows-portable.ps1, and update_windows.bat. The README's documented start is the Docker Compose path, and it points native installs, including Windows and macOS instructions, to the setup guide.
What is the Odysseus Cookbook feature?
Cookbook is described as hardware-aware model recommendations, downloads, and serving. The rest of the feature list covers chat and agents with local and API models, deep research with source reading and report generation, compare for blind side-by-side model testing, an email inbox over IMAP and SMTP, and calendar with CalDAV sync.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/odysseus-dev-odysseus)[](https://hysenlabs.com/projects/odysseus-dev-odysseus)Star history chart for your README
[](https://hysenlabs.com/projects/odysseus-dev-odysseus)Was this useful?