
An AI personal assistant with a focus on security.

Stavrobot is a personal AI assistant built with the principle of "all the access an AI assistant needs, and no more".
It has all the nice features of an AI assistant, but focuses on sandboxing, isolation, and minimal permissions. It's lightweight and is deployed with only a docker compose up.
uv, isolated from the host environment.AI-assisted install: Tell your coding AI (Claude Code, Cursor, Windsurf, etc.) to fetch and follow https://stavrobot.stavros.io/INSTALL.md — it will walk you through the whole setup interactively.
Manual install:
Message @BotFather on Telegram to create a bot and copy the token. Message @userinfobot to get your Telegram user ID (this is used as the chat ID).
Copy env.example to .env and change POSTGRES_PASSWORD to something secure and TZ to your timezone.
Copy config.example.toml to data/main/config.toml and fill in the required fields: apiKey, password, publicHostname, [owner].name, [owner].telegram (your chat ID), and [telegram].botToken. Everything else in the file is optional.
docker compose up --build
That's it. Message your bot on Telegram and it will respond. See the detailed setup sections below for Signal, WhatsApp, email, and other options.
config.example.toml to data/main/config.toml.authFile (or apiKey) and publicHostname. Everything else is optional.env.example to .env and set your timezone (TZ). Postgres credentials and other environment settings can also be overridden there. Always set POSTGRES_PASSWORD to something secure — the default is a weak placeholder and should not be used in production.After the app starts, open /settings/config to edit config.toml in the browser. The
page is protected by HTTP Basic Auth and displays the raw configuration, including any
secrets it contains. A valid save creates a single <CONFIG_PATH>.bak backup, saves the
new content, and restarts the app; this interrupts any in-progress agent turn.
plugin-runner, coder, signal-bridge, and python-runner read config.toml only
when they start. Changes that affect them, such as the password, require manually
restarting those containers.
Stavrobot can be pointed at any OpenAI-compatible endpoint (Ollama, LiteLLM, vLLM, etc.) or a custom Anthropic-compatible proxy by setting baseUrl in config.toml. See config.example.toml for the required fields and example configurations. Set reasoning = true only for models that support thinking, since it is what makes thinkingLevel apply on a custom endpoint.
The app supports two authentication modes: API key or OAuth.
apiKey in config.toml. No login or logout needed.authFile in config.toml (a path where credentials will be stored). The login page works with any OAuth provider supported by Pi.
<your-hostname>/login in a browser. Follow the prompts on the page, and credentials are saved to the auth file. Stavrobot picks the provider's headless login method, so you never get redirected to an unreachable localhost callback. With Anthropic, after you select Authorize, Anthropic shows a code, which you copy and paste into the Stavrobot login page. Providers with a device-code flow show the code on the Stavrobot page instead, and you type it on the provider's site. If auth expires while the bot is running, it sends a message with the login URL to you via your messaging platform.authFile path. The bot will detect missing credentials on the next message and prompt you to log in again.The coder container is optional (needed only for the self-programming feature). By default it uses Claude Code with subscription auth (OAuth), separate from the main app's API key. To use an Anthropic-compatible API endpoint instead, set both [coder].apiKey and [coder].baseUrl in config.toml; Claude Code then uses them as ANTHROPIC_API_KEY and ANTHROPIC_BASE_URL. The top-level apiKey/baseUrl only configure the main app's model and never affect the coder. Setting only one of the two [coder] keys is a startup error.
Docker Compose profiles are comma-separated, so you can combine them (e.g. COMPOSE_PROFILES=signal,coder).
COMPOSE_PROFILES in your .env file to include coder (e.g. COMPOSE_PROFILES=coder, or COMPOSE_PROFILES=signal,coder if you are also using Signal).docker compose --profile coder up --build[coder].apiKey/[coder].baseUrl): docker compose exec -u coder coder claude (it will prompt you to log in if you haven't).[coder].model in your config to a Claude Code model alias (sonnet, opus, or haiku).Signal requires a separate phone number — not your personal one. A prepaid SIM or VoIP number works.