tanmayraut45 c1df31fda5 Honor AUTH_ENABLED=false in route-level auth gate (#785)
#622 reported "I cant even paste that hash pw and granted So auth_en
=false & localbypass= true But then the host still is showing login
page?" — the operator turned auth off in .env and still gets bounced
to /login on every page load. The flow:

The auth middleware in app.py is correctly gated on AUTH_ENABLED, so
the middleware itself does not install when AUTH_ENABLED=false. The
SPA front-end at static/app.js wraps window.fetch and redirects to
/login on ANY 401 response from any API call. So all it takes for the
operator to see a login page is one route-level 401.

src/auth_helpers.require_user — the shared FastAPI dependency mounted
on ~50 routes (email, contacts, personal, …) — was the source. It is
documented as defense-in-depth in case the middleware was bypassed
unexpectedly (SSRF from a sibling service), but the implementation
treated AUTH_ENABLED=false as one of those unexpected bypasses and
401'd anyway. The loopback fall-through that would have admitted the
operator does not fire under docker compose / a reverse proxy because
the container sees the request arriving from the bridge gateway
(172.x.x.x), not 127.0.0.1.

require_user now short-circuits to "" when AUTH_ENABLED=false so the
explicit operator opt-out reaches the route layer too. While in the
file, also mirror LOCALHOST_BYPASS=true the same way for loopback
callers — the middleware already lets them through, and routes 401'ing
the same caller would produce the same /login bounce. Non-loopback
callers under LOCALHOST_BYPASS are still rejected, matching the
middleware's _is_trusted_loopback check.

Add three focused regression tests in tests/test_security_regressions.py:
docker-bridge caller is admitted under AUTH_ENABLED=false, loopback
caller is admitted under LOCALHOST_BYPASS=true, LAN caller under
LOCALHOST_BYPASS=true is still rejected. The existing
test_require_user_rejects_unauthenticated and
test_require_user_accepts_loopback_when_unconfigured tests continue to
pass because neither sets AUTH_ENABLED, so the AUTH_ENABLED=true
default path is unchanged.

Closes #622.
2026-06-02 11:23:47 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-06-01 10:57:31 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-05-31 23:58:26 +09:00
2026-06-01 22:30:07 +09:00
2026-05-31 23:58:26 +09:00
2026-06-01 22:38:56 +09:00

Odysseus

─────────────────────────────────────────────── ⊹ ࣪ ˖ ૮( ˶ᵔ ᵕ ᵔ˶ )っ Odysseus vers. 1.0 ───────────────────────────────────────────────

Odysseus

A self-hosted AI workspace -- meant to be the self-hosted version of the UI experience you get from ChatGPT and Claude. But with more jank and fun. Running on your own hardware, with your own data -- local-first, privacy-first, and no trojan.

Features

  • Chat -- chat with any local model or API; adding them is super simple.
     vLLM · llama.cpp · Ollama · OpenRouter · OpenAI
  • Agent -- hand it tools and let it run the whole task itself.
     built on opencode · MCP · web · files · shell · skills · memory
  • Cookbook -- Scans your hardware, recommends models, click to download and serve.. easy!
     built on llmfit · VRAM-aware · GGUF / FP8 / AWQ · fit scoring · vLLM / llama.cpp serving
  • Deep Research -- multi-step runs that gather, read, and synthesize sources into a nice visual report.
     adapted from Tongyi DeepResearch
  • Compare -- a fun tool to compare models side by side. Test completely blind, no bias!
     multi-model · blind test · synthesis
  • Documents -- YOU write the text, AI is there to assist, not the opposite.
     multi-tab editor · markdown · HTML · CSV · syntax highlighting · AI edits · suggestions
  • Memory / Skills -- Persistent memory and skills, your agent evolves over time as it better understands you and your tasks!
     ChromaDB · fastembed (ONNX) · vector + keyword retrieval · import/export
  • Email -- IMAP/SMTP inbox with AI triage built in: urgency reminders, auto-tag, auto-summary, auto-reply drafts, auto-spam.
     IMAP · SMTP · per-account routing · CalDAV-aware
  • Notes & Tasks -- Quick notes with reminders, a todo list, and scheduled tasks the agent can act on.
     note pings · checklist · cron-style tasks · ntfy / browser / email channels
  • Calendar -- Local-first calendar with CalDAV sync to Radicale / Nextcloud / Apple / Fastmail.
     CalDAV pull · .ics import/export · per-calendar colors · agent-aware
  • Works on mobile -- looks and runs great on your phone, not just desktop.
     responsive · installable (PWA) · touch gestures
  • Extras -- more to explore, happy if you give it a go!
     image editor · theme editor · file uploads (vision + PDF) · web search · presets · sessions · 2FA

Demo

A full, hover-to-play tour lives on the landing page (docs/index.html).

Screenshots / clips

Chat & Agents

Chat & Agents

Deep Research

Deep Research

Compare

Compare

Documents

Documents

Notes & Tasks

Notes & Tasks

Quick Start

Defaults work out of the box: clone, run, then configure models/search/email inside Settings. Only edit .env for deployment-level overrides like APP_BIND, APP_PORT, AUTH_ENABLED, DATABASE_URL, or a pre-seeded admin password.

On first setup, Odysseus creates an admin account (admin unless ODYSSEUS_ADMIN_USER is set) and prints a temporary password in the terminal. For Docker installs, the same line is in docker compose logs odysseus. Use that for the first login, then change it in Settings.

Contributing? See CONTRIBUTING.md for setup, testing, and pull request guidelines.

git clone https://github.com/pewdiepie-archdaemon/odysseus.git
cd odysseus
cp .env.example .env       # optional, but recommended for explicit defaults
docker compose up -d --build

Open http://localhost:7000 when the containers are healthy. Docker Compose binds the web UI to 127.0.0.1 by default. If the port is taken, set APP_PORT=7001 in .env and recreate the container. Set APP_BIND=0.0.0.0 only when you intentionally want LAN/reverse-proxy access.

Native Linux / macOS

git clone https://github.com/pewdiepie-archdaemon/odysseus.git
cd odysseus
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python setup.py
python -m uvicorn app:app --host 127.0.0.1 --port 7000

Requirements: Python 3.11+. Cookbook also needs tmux for background model downloads and serves. Use --host 0.0.0.0 only when you intentionally want LAN/reverse-proxy access.

Apple Silicon

Docker on macOS cannot use the Metal GPU. For GPU-accelerated Cookbook on an M-series Mac, run Odysseus natively:

git clone https://github.com/pewdiepie-archdaemon/odysseus.git
cd odysseus
./start-macos.sh

It launches at http://127.0.0.1:7860. To build a clickable app wrapper:

./build-macos-app.sh
Cookbook, GPU, Ollama, and troubleshooting notes

Docker bundled services. Compose starts Odysseus, ChromaDB, SearXNG, and ntfy. Odysseus and the bundled service ports bind to 127.0.0.1 by default, so they are reachable from the host but not exposed to your LAN/public internet unless you opt in.

Cookbook storage in Docker. Downloads live in ./data/huggingface (~/.cache/huggingface in the container). Cookbook-installed Python CLIs and serve engines live in ./data/local (~/.local in the container), so they survive container recreation.

Remote servers. In Cookbook -> Settings -> Servers, generate the Odysseus SSH key and add the public key to the remote server's ~/.ssh/authorized_keys. From the host you can also run:

ssh-copy-id -i data/ssh/id_ed25519.pub user@server

NVIDIA / AMD Docker GPU overlays. Install the host runtime first, then add one of these to .env:

COMPOSE_FILE=docker-compose.yml:docker/gpu.nvidia.yml
COMPOSE_FILE=docker-compose.yml:docker/gpu.amd.yml

Verify with:

docker compose exec odysseus nvidia-smi -L
docker compose exec odysseus rocm-smi

Ollama with Docker. If Ollama runs on the host, add this endpoint in Settings:

http://host.docker.internal:11434/v1

Ollama must listen outside its own loopback interface:

OLLAMA_HOST=0.0.0.0:11434 ollama serve

Useful checks.

docker compose ps
docker compose logs --tail=120 odysseus
docker compose logs odysseus | grep -E 'ChromaDB|MemoryVectorStore|DEGRADED'

macOS details. start-macos.sh installs Homebrew deps, creates the venv, runs setup, and starts uvicorn on port 7860 because AirPlay often holds 7000. It uses llama.cpp/Ollama for Metal. vLLM/SGLang are CUDA/ROCm-only and do not run on macOS. MLX-only models are not served by Odysseus.

Native Windows

One-command launcher (creates the venv, installs deps, runs setup, starts the server; safe to re-run):

git clone https://github.com/pewdiepie-archdaemon/odysseus.git
cd odysseus
powershell -ExecutionPolicy Bypass -File .\launch-windows.ps1

Or do it by hand:

git clone https://github.com/pewdiepie-archdaemon/odysseus.git
cd odysseus
python -m venv venv
venv\Scripts\Activate.ps1
pip install -r requirements.txt
python setup.py
python -m uvicorn app:app --host 127.0.0.1 --port 7000

Requirements: Python 3.11+. The core app (chat, agent, memory, documents, email, calendar, deep research) runs fully native. For full Cookbook background model downloads and the agent shell tool, also install Git for Windows (provides bash.exe). Local GPU serving of vLLM/SGLang needs Linux/WSL2; for a local model on Windows, Ollama is the easiest path — point Odysseus at http://localhost:11434/v1 in Settings.

Open http://localhost:7000, log in with the generated admin password, and configure everything else inside Settings.

Security Notes

Odysseus is a self-hosted workspace with powerful local tools: shell access, file uploads, model downloads, web research, email/calendar integrations, and API tokens. Treat it like an admin console.

  • Keep AUTH_ENABLED=true for any network-accessible deployment.
  • Do not expose it directly to the public internet without HTTPS and a trusted reverse proxy.
  • Keep data/, .env, logs, databases, and uploaded/generated media out of Git. They are ignored by default.
  • Review data/auth.json after first boot: disable open signup unless you intentionally want it, make only your own account admin, and keep demo/test accounts non-admin.
  • Non-admin users do not get shell/Python/file read/write by default, and admin-only routes/tools such as MCP management, API tokens, webhooks, model/cookbook serving, backup/vault, and app settings are admin-gated. Other features are controlled by per-user privileges, so review each user's privileges before exposing a deployment.
  • Rotate any API keys or tokens that were ever pasted into a shared chat, demo, screenshot, or log.
  • If you enable API tokens or webhooks, create separate tokens per integration and delete unused ones.
  • Prefer binding manual development runs to 127.0.0.1; bind to 0.0.0.0 only when you intentionally want LAN/reverse-proxy access.
  • Before publishing a fork, run git status --short and confirm no private files from .env, data/, logs/, uploads, backups, or local databases are staged.

Putting it behind HTTPS

Odysseus serves plain HTTP on its port. That's fine for localhost and trusted LAN/VPN use, but browsers will warn ("Password fields present on an insecure page") and the login + API tokens travel in cleartext. For anything reachable outside your machine — including a Tailscale IP shared with other devices — put a TLS-terminating reverse proxy in front.

Shortest path with Caddy (auto-renews Let's Encrypt certs):

odysseus.example.com {
  reverse_proxy localhost:7000
}

For a LAN-only Tailscale deployment, Caddy + tailscale-cert or the built-in MagicDNS HTTPS feature both work. nginx/Traefik configs are similar — proxy localhost:7000, terminate TLS at the proxy. Once that's in place, the browser warning goes away and your login is encrypted.

Contributing

Help is welcome. The best entry points are fresh-install testing, provider setup bugs, mobile/editor polish, docs, and small focused refactors. See ROADMAP.md for the current help-wanted list.

Configuration

Most setup is done inside the app with /setup or Settings. Use .env for deployment-level defaults and secrets you want present before first boot. Key settings:

Variable Default Description
LLM_HOST localhost Your LLM server (e.g. llm-host.local:8000)
LLM_HOSTS -- Comma-separated list for model discovery
OPENAI_API_KEY -- Optional OpenAI key. Prefer adding providers in the app unless pre-seeding.
SEARXNG_INSTANCE http://localhost:8080 SearXNG URL. Docker overrides this to http://searxng:8080.
SEARXNG_SECRET generated on first Docker boot Optional SearXNG cookie/CSRF secret. Leave blank unless you need to pin it.
APP_BIND 127.0.0.1 Docker Compose host bind address for the web UI. Use 0.0.0.0 only for intentional LAN/reverse-proxy access.
APP_PORT 7000 Docker Compose host port for the web UI.
AUTH_ENABLED true Enable/disable login
LOCALHOST_BYPASS false Development-only auth bypass for loopback requests. Keep false for shared/network deployments.
DATABASE_URL sqlite:///./data/app.db Database connection string
CHROMADB_HOST localhost ChromaDB host for vector memory. Docker overrides this to chromadb.
CHROMADB_PORT 8100 ChromaDB port for manual host runs. Docker overrides this to 8000.
EMBEDDING_URL -- OpenAI-compatible embeddings endpoint

Built-in MCP servers (optional setup)

Odysseus auto-registers a few built-in MCP servers at startup. The npx-based ones (currently the browser server, @playwright/mcp) only start when their npm package is already in the local npx cache. If a package isn't cached, that server is skipped with a startup log message explaining what to do, so a fresh install does not block on a multi-minute npm download or hang if Playwright system deps are missing.

To enable the browser MCP (page navigation, screenshots, vision), run once:

npx -y @playwright/mcp@latest --version

That installs @playwright/mcp plus Playwright (~300MB total). Restart Odysseus and the server will register at startup.

Architecture

app.py                   # FastAPI entry point
core/      auth, database, middleware, constants
src/       llm_core, agent_loop, agent_tools, chat_processor, search/
routes/    chat, session, document, memory, model … endpoints
services/  docs, memory, search, hwfit (Cookbook) …
static/    index.html + app.js + style.css + js/ (modular front-end)
docs/      landing page (index.html) + preview clips

Data

All user data lives in data/ (gitignored): app.db (sessions, messages, documents), memory.json, presets.json, uploads/, personal_docs/, chroma/, settings.json.

Star History

Star History Chart

License

MIT -- see LICENSE and ACKNOWLEDGMENTS.md.

                                  |
                                 |||
                                |||||
                  |    |    |   |||||||
                 )_)  )_)  )_)   ~|~
                )___))___))___)\  |
               )____)____)_____)\\|
             _____|____|____|_____\\\__
             \                       /
       ~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~
               ~^~  all aboard!  ~^~
       ~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~~^~^~
Description
No description provided
Readme MIT 28 MiB
Languages
Python 44.7%
JavaScript 43.6%
CSS 9.3%
HTML 1.8%
Shell 0.5%