Clovis is a persistent AI agent built on Claude Code, reachable via Telegram. It runs as a Docker container and operates on a dedicated git workspace.
This project started as an exploration of openclaw.ai — a cloud-based AI assistant that connects to your email, calendar, todos, and messages. The idea was compelling, but the security implications were not: you are handing a third-party service full access to your Gmail, WhatsApp, and the rest of your personal data, with no real visibility into what it does with it.
The internet has also produced some memorable reminders of what happens when an agent has write access to everything and acts on ambiguous instructions — like texting your ex.
Clovis is the alternative: the same concept, but self-hosted, small, and built on Claude Code. You own the container, the credentials never leave your machine, and everything the agent does is visible in git history.
What it is today: a Docker wrapper around Claude Code that lets you run a persistent agent reachable via Telegram, using your existing Claude subscription — no API key, no extra cost on top of what you already pay.
Where it's going:
- Easy, reproducible setup — copy
docker-compose.yml, fill in.env, and have a working agent in minutes ✓ - MCP tool integrations — Gmail, Todoist, WhatsApp, Google Calendar, and others will be added incrementally as MCP servers
- Granular access control — each MCP tool restricted to read-only by default, so the agent can read your emails without being able to send them, read your calendar without creating events. You decide what it can touch.
Compliance note: Clovis is designed for personal use. If you are considering using it in a work context, your organization may have data governance policies, corporate IT requirements, or regulatory obligations (GDPR, HIPAA, SOC 2, etc.) that govern what tools can access company data. Evaluate accordingly — personal and professional contexts carry very different rules.
Anthropic Terms of Service:
CLAUDE_CODE_OAUTH_TOKENis a personal OAuth token from your Claude subscription. open-clovis passes it directly to the officialclaudeCLI — which is the intended use. The Consumer Terms of Service (§2) prohibit sharing account credentials with anyone else, and (§3) prohibit accessing services through automated means except via an API key. open-clovis does neither: it runs the officialclaudebinary and each user supplies their own token. What those clauses rule out is building tools that use someone else's subscription token to call Anthropic's API — open-clovis is not that. That said, before running it is worth reviewing your intended use case against the Consumer Terms — if your usage goes beyond personal, interactive use (e.g. fully automated pipelines, team-shared instances, or commercial workflows), switching to a proper Anthropic API key under the Commercial Terms is the safer path.
An agent instance is made of two repos:
open-clovis ← the shell: container, auth, Telegram, config
clovis-workspace ← the workspace: git repo Clovis reads and writes
open-clovis (this repo) is the environment — it defines how the agent runs, how it authenticates, and how it connects to Telegram. You manage this from the host.
clovis-workspace is where Clovis does its work — a regular git repo mounted into the container at /home/clovis. Clovis can read files, write code, make commits, and push. You review what it did via git history.
This separation keeps infra concerns out of the workspace and gives Clovis a clean, auditable place to operate.
At startup, the entrypoint registers the official plugin marketplace (anthropics/claude-plugins-official) and installs the Telegram plugin — both steps are idempotent and complete in under a second once the data volume is populated. Bun is required by the Telegram plugin's MCP server and is installed system-wide. tini is used as PID 1 to reap zombie processes that Bun spawns.
n8n runs as a sidecar container and exposes third-party service integrations (Gmail, Google Calendar, Todoist, WhatsApp, and others) as MCP servers that Claude picks up automatically on start.
code-server runs inside the agent container as a background process, exposing a browser-based VS Code at http://localhost:8080. It shares the same environment, MCP configs, and workspace as the agent — the claude CLI is available directly from the integrated terminal.
n8n is a heavier container than the rest of the stack, but it earns its keep in two ways. First, it handles OAuth authentication with Google — connecting to Gmail or Google Calendar through n8n means you go through Google's official consent screen once, and n8n stores and refreshes the credentials for you, without needing to write any auth code. Second, it lets you define exactly which tools the agent can use per integration. You wire up only the nodes you want to expose, and the agent only sees those. This is the practical path to least-privilege access: Claude can read your inbox and create drafts, but if the "Send email" node is not in the workflow, it simply cannot send.
Telegram API
│
▼
┌─────────────────────────────────────────────── clovis-net ───────────────────────────────────┐
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ agent │ MCP (HTTP) ┌──────────────────────┐│
│ │ │ ────────────► │ n8n ││
│ │ Telegram MCP plugin ◄──► Claude Code │ │ :5678 ││──► Google, Gmail
│ │ │ ◄──────────── │ workflow MCPs ││ Todoist, ...
│ │ workspace/ (clovis-workspace, mounted volume) │ └──────────────────────┘│
│ │ │ HTTP API ┌──────────────────────┐│
│ └───────────────────────────────────────────────────┘ ────────────► │ waha ││
│ │ :3000 ││──► WhatsApp
│ └──────────────────────┘│
└──────────────────────────────────────────────────────────────────────────────────────────────┘
│ ./data/ │ ./n8n-data/ │ ./waha-data/
▼ (workspace, .claude/ config) ▼ (workflows) ▼ (WA sessions)
host filesystem (all gitignored)
Host browser ─────────────────────────────────────────────► :5678 n8n UI │ :3000 Waha UI │ :8080 code-server
Note: The Telegram plugin requires a compatible Claude plan (Pro, Max, Team, or Enterprise).
mkdir clovis && cd clovisDownload it from this repo:
curl -fsSL https://raw.githubusercontent.com/open-clovis/open-clovis/main/docker-compose.yml -o docker-compose.ymlmkdir -p data/workspace
sudo chown -R 1001:1001 data/To start fresh:
git -C data/workspace initOr if you have an existing repo, clone it instead:
git clone https://github.com/<your-username>/clovis-workspace.git data/workspaceBOT_NAME=clovis
CLAUDE_CODE_OAUTH_TOKEN="your-claude-oauth-token"
TELEGRAM_BOT_TOKEN="your-telegram-bot-token"
GITHUB_TOKEN=your-github-pat
GOG_KEYRING_PASSWORD=your-random-secretCreate a bot and get its token from @BotFather on Telegram (/newbot).
GITHUB_TOKEN is optional — only needed for Clovis to push commits. Create a token with repo scope at github.com/settings/tokens.
To get a long-lived OAuth token, run on a machine where you are already logged into Claude Code:
claude setup-tokenAlways wrap
CLAUDE_CODE_OAUTH_TOKENin double quotes — the token may contain a#which.envparsers treat as a comment delimiter, silently truncating the value.
docker compose run --rm agentOn first start Claude Code will:
- Ask you to select a login method — choose Claude account with subscription
- Show a URL to complete OAuth in your browser
- Show a theme/onboarding wizard — complete it fully before exiting
If you set
TELEGRAM_BOT_TOKENin.env, the plugin picks it up automatically. If you skipped that env var, run/telegram:configure <your-botfather-token>before exiting.
Exit with Ctrl+C.
Open Telegram and send any message to your bot. It will reply with a pairing code.
Attach to the running container and open a Claude Code session:
docker compose run --rm agentOnce inside the Claude Code prompt (not your bash shell), run:
/telegram:access pair <code>
/telegram:access policy allowlist
The allowlist is critical: without it, anyone who finds your bot's username can send it messages and interact with your agent. Once enabled, only paired accounts are allowed — everyone else is silently dropped.
See the Claude Code documentation for full details on how the sender allowlist works.
Exit with Ctrl+C. All state is saved to ./data/ and persists across restarts.
n8n is available at http://localhost:5678 once the stack is running.
To connect a service (Gmail, Google Calendar, Todoist, WhatsApp, etc.):
- Open n8n, create a new workflow, add an MCP Server Trigger as the first node
- Add the service nodes as tools under that trigger
- Activate the workflow — n8n shows the MCP endpoint URL in the trigger node
- Copy the URL, replace
localhostwithn8n:http://n8n:5678/mcp/your-webhook-id - Uncomment (or add) the matching line in
docker-compose.ymlunderagent.environment:N8N_MCP_GMAIL: http://n8n:5678/mcp/your-gmail-webhook-id N8N_MCP_GCAL: http://n8n:5678/mcp/your-gcal-webhook-id
- Restart the agent:
docker compose restart agent
Claude logs entrypoint: registered MCP server 'n8n-gmail' on startup when the var is active. MCP URLs go in docker-compose.yml directly — they contain no secrets and the n8n hostname only resolves inside the Docker network.
code-server starts automatically with the agent and provides a browser-based VS Code at:
Log in with the CODE_SERVER_PASSWORD from your .env. The workspace opens at /home/clovis/workspace — the same repo Clovis operates on.
From the integrated terminal you can run claude directly, inspect MCP configs in .mcp.json, or edit files. All changes are immediately visible to the running agent.
docker compose up -dOpen Telegram and message your bot. Clovis will respond as if you were using Claude Code in a terminal, with full access to the workspace repo.
To modify the container itself, clone the repo and use setup.sh to automate steps 3 and 5 above. Since docker-compose.yml builds from the GitHub URL, override the build context locally with:
git clone https://github.com/open-clovis/open-clovis.git
cd open-clovisOverride docker-compose.yml with a local docker-compose.override.yml:
services:
agent:
build:
context: ../setup.shThe script prompts for credentials and scaffolds .env, auto-generating N8N_ENCRYPTION_KEY. Then continue from step 4 (set up the workspace) and fill in the remaining .env values.
| Variable | Required | Description |
|---|---|---|
BOT_NAME |
Yes | Agent name — sets the Docker container name to open-clovis-<name> |
CLAUDE_CODE_OAUTH_TOKEN |
Yes | Long-lived auth token from claude setup-token |
TELEGRAM_BOT_TOKEN |
Yes | Bot token from @BotFather |
GITHUB_TOKEN |
No | GitHub PAT (create one) — enables git push from the workspace |
N8N_ENCRYPTION_KEY |
Yes | Encrypts n8n credentials at rest — auto-generated by setup.sh |
CODE_SERVER_PASSWORD |
Yes | Password for the code-server web UI at http://localhost:8080 |
TZ |
No | Container timezone. Defaults to America/Sao_Paulo |
| Host path | Container path | Purpose |
|---|---|---|
./data |
/home/clovis |
Home dir — holds .claude/ config, .claude.json, and the workspace repo |
./n8n-data |
/home/node/.n8n |
n8n workflows, credentials, and settings (n8n container) |
| Port | Service | Purpose |
|---|---|---|
5678 |
n8n | Workflow automation UI |
3000 |
waha | WhatsApp API / Swagger UI |
8080 |
agent (code-server) | Browser-based VS Code |
docker compose run --rm agent # interactive session (first-time wizard, pairing) — runs entrypoint.sh
docker compose up -d # start in background
docker compose logs -f # follow logs
docker compose down # stop (state preserved in ./data/)
docker compose exec agent sh # shell into the running container (entrypoint already ran — git credentials and gogcli are set up)
docker compose run --rm agent sh # raw shell in a new container — bypasses entrypoint.sh (no git credentials, no gogcli setup)
