Permissions and reach - a file leaving a computer passes the same questions as reading it; "looking" shell commands that do more than look ask first - a symlink out of the work/sealed folder counts as outside it (real paths, not just lexical ones); the search walk skips links - web_fetch and skill_install read the public web only: localhost, the LAN and cloud metadata are refused, at every redirect - preview shows a file without running it; browser_upload may ask - vault: logins no longer match across shared suffixes (pages.dev, com.tw, ...); registrable_domain knows public suffixes - axwrite: found elements are retained (use-after-free) Relay - replacing or turning off 2FA needs the current code (rate-limited); new recovery codes only count once enrollment is verified - a removed computer loses its socket and its `call` access - a site name taken by another account answers 409 - RELAY_TRUST_PROXY: the login lock counts the caller's address, not the proxy's (compose files and README) - httpd: half a body is not a request Desktop - sign-in, join and restore work with 2FA on (code field; --serve reads ANYBOT_ACCOUNT_CODE; the setup wizard points to a pairing code) - Windows: text was typed twice; modifiers are held through click, drag and scroll; horizontal scroll; screen control is no longer refused - a recording that hits the limit is transcribed, not thrown away - bot's computer: a new home volume restores the snapshot; a snapshot is read through before the home is wiped; a failed volume removal stops reset/restore - events of a stopped turn no longer land in the next one; each channel message gets a turn of its own - saving a bot's settings keeps what it got meanwhile (three-way merge); a save file that cannot be read is kept - pages in Big5/GBK/Shift_JIS are read in their own encoding (encoding_rs); osascript output past 64 KB no longer stalls - pick_tab keeps a job's own non-http tab; pictures larger than the texture limit are fitted; the auto-update time field takes typing - skills live in <data>/skills; memories are unnumbered in the prompt; the phone may skillify and skill_install CI - the test step fails when the tests fail (it piped into tail) Tests: anybot 268 passed, 27 ignored; relay 16 passed; clippy unchanged. Not run: Windows on a real machine (win.rs type-checked alone), the Docker paths of the bot's computer, the live accessibility writes. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|---|---|---|
| .gitea/workflows | ||
| bench/computer-use | ||
| box | ||
| deploy | ||
| docs | ||
| fonts | ||
| icons | ||
| mobile | ||
| relay | ||
| skills | ||
| src | ||
| .dockerignore | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| FEATURES.md | ||
| LICENSE | ||
| MECHANICS.md | ||
| Makefile | ||
| README.en.md | ||
| README.md | ||
| SECURITY.md | ||
| install.sh | ||
| mechanics.json | ||
README.en.md
AnyBot
中文 README · English
Your own AI bot. It chats, and it does things: files, shell commands, your browser, your screen, scheduled jobs. Self-hosted — your data stays on machines you own.
- Every bot can use a different model: xAI Grok, OpenAI, Claude, Gemini, OpenRouter, OpenCode Go, Ollama (local), or any OpenAI-compatible endpoint
- Desktop app (macOS, Linux) + mobile web app (install to home screen, push notifications)
- Multiple computers: one brain, the others are its hands — all linked through your own account server, no ports opened
Demo
📹 No recording yet — see docs/demo/README.md.
How it compares
| AnyBot | OpenClaw | OpenHands | Khoj | UI-TARS-Desktop | |
|---|---|---|---|---|---|
| Positioning | Personal bot across your machines | Agent gateway on your hardware | Coding agent in sandboxes | Personal knowledge/RAG assistant | GUI agent on one desktop |
| Chat with your own bots | ✅ multi-bot, per-bot model | ✅ via gateways | coding-focused | ✅ | — |
| Controls your real desktop/browser | ✅ + approvals, VNC takeover | via plugins | sandboxed, not your desktop | — | ✅ (its whole product) |
| Multi-device brain/hands/phone | ✅ built in, zero open ports | bring your own | — | server + apps | single machine |
| Bot's own sandboxed computer (Docker, optional gVisor) | ✅ | host shell | ✅ | — | — |
| Secrets never enter the model (vault fills forms directly) | ✅ | — | — | — | — |
| Phone web app + push, no app store | ✅ | community | — | ✅ | — |
| One binary, JSON files, no database server | ✅ | ✅ | — | needs services | Electron |
| License | Apache-2.0 | MIT | MIT | AGPL-3.0 | Apache-2.0 |
AnyBot's bet: a bot that touches your real machines is only trustworthy when the harness — not the model — owns the safety gates: per-action approvals, a sensitive-click policy the model cannot talk its way past, secrets painted out of screenshots, and an audit trail that survives crashes.
Install
Pick one row, paste it into a terminal. The script installs what's needed (system packages, Rust, Docker).
| I want… | On which machine | Command |
|---|---|---|
| Desktop app | macOS, Linux with a screen | curl -fsSL https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.sh | sh |
| Account server (+ brain + HTTPS) | A Linux host with a domain | curl -fsSL https://code.30cm.net/daniel.w/AnyBot/raw/branch/main/install.sh | sh -s -- server |
| Add a computer as hands | Any Linux (headless fine) | In AnyBot press “Add a computer”, paste the one-liner it shows |
First run compiles on your machine (5–15 min); later updates take 1–2 min. Read the script first: install.sh. It installs into your user folders — no root.
Getting started
One computer: install the desktop app → Settings › Models → paste an API key → chat.
Phone + several computers: run the server once (asks only for URL, account, password; gets HTTPS by itself), open the URL on your phone and “Add to Home Screen”, then pair other computers with one-time pairing codes. Any Linux box can become the bot's own computer, running inside Docker (optionally gVisor). A Mac can be the brain instead of a server (docs/multi-device.md, method B). No database to run: state is a handful of JSON files, crash-safe writes; back up two Docker volumes.
Updates, removal
| What | Command |
|---|---|
| Update app / hands | re-run the install line |
| Update server | on the server: cd ~/AnyBot && make server → “keep settings, update, restart” |
| Uninstall the program | cd ~/AnyBot && make uninstall (your bots and chats are kept) |
| Stop a hands machine | systemctl --user disable --now anybot |
Troubleshooting
cd ~/AnyBot && make doctor
It tells you what's missing. Common: Killed/signal: 9 while compiling → add 2 GB swap; requires rustc 1.95 → rustup update stable; Mac says “cannot verify developer” → right-click › Open once; phone says “brain offline” → the brain machine is asleep (docs/multi-device.md).
Build from source
git clone https://code.30cm.net/daniel.w/AnyBot.git
cd AnyBot
make deps && make && make install # deps: system packages + Rust 1.95+ (one time)
make run · make test · make doctor · make serve (headless) · make setup (pair this machine) · make server · make dist · make help. Needs: Rust ≥1.95, a C compiler, git; on Linux also pkg-config + libasound2-dev (deps installs all).
Deployment
| Method | For | Notes |
|---|---|---|
| Docker Compose (default) | server | install.sh server: relay + brain + Caddy (auto-HTTPS) containers; data in Docker volumes; Tailscale URLs skip Caddy (compose file) |
| Unattended | servers, Ansible | ANYBOT_SETUP_USER=… ANYBOT_SETUP_PASSWORD=… [ANYBOT_SETUP_DOMAIN=…] sh install.sh server |
| Portainer/Coolify/Dokploy | existing PaaS | they take the standard deploy/server/docker-compose.yml — set ANYBOT_USER, ANYBOT_PASSWORD, ANYBOT_RELAY_PUBLIC_URL |
| systemd user service | hands, headless brains | anybot setup installs anybot.service; loginctl enable-linger to keep it running logged-out |
| launchd | Mac as brain/relay | see docs/multi-device.md |
| Gitea Actions | release builds on v* tags |
see docs/release.md |
Security in one paragraph
Commands run in a macOS sandbox (deny ~/.aws, Keychain, AnyBot's own data; allow only the attachments dir); per-action approvals with a policy layer the model cannot negotiate; clicking anything labelled “send/pay/transfer” is asked every time, even in direct mode, with no grant that silences it; card numbers and OTPs in screenshots are painted black before the model sees them; everything read from outside is wrapped as <untrusted> data, never treated as orders; the bot's own computer is a Docker container (gVisor for a second wall); relay stores only hashes (argon2id) and supports 2FA with recovery codes; egress binds loopback + detected bridge gateways, never 0.0.0.0. Details: SECURITY.md (summary here) and docs/architecture.md (Chinese; English summary).
Documentation
| Doc | Contents |
|---|---|
| docs/install.md (en) | per-platform details, manual steps, FAQ |
| docs/multi-device.md (en) | brain / hands / screen: setup, pairing, offline |
| docs/architecture.md (en) | layers, data storage, security design |
| docs/protocol.md (en) | relay API and long-connection wire format |
| docs/release.md | packaging, CI |
| FEATURES.md | every feature (Chinese) |
License
Apache License 2.0 — see LICENSE. Copyright the contributors (The AnyBot contributors). Calls to third-party services (xAI, OpenAI, …) go through their public APIs; follow each service's terms and your own key agreements.
Repository layout
install.sh one-line installer (app, hands, server)
src/ AnyBot: desktop app, headless, `anybot setup`
relay/ account server
mobile/ phone web app (single file, embedded)
box/ the bot's own computer (Docker container)
deploy/ per-platform install & deployment files
docs/ technical docs (docs/en/ = English)
bench/ computer-use benchmark (tasks, scoring, red-team suite)