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>
Two copies on one folder each keep their own idea of the chats and overwrite each other's saves,
and a second copy starting up would take the first one's open turns in the work log for a crash
and close them. The window, `--serve` and `--ask` now hold an OS file lock on anybot.lock in the
data folder (flock; LockFileEx on Windows), and `anybot setup` holds it while it writes the
settings, after stopping the service and before starting it again.
The lock goes with the process however it ends, so a copy that crashed or was killed never blocks
the next one. A new copy waits up to 5 s for one that is closing (a relaunch, a service restart).
Past that, a second window shows a small notice naming the holder's process and the folder, and
`--serve` / `--ask` say it on stderr and exit 1 (launchd's and systemd's restart then retry). Each
ANYBOT_DATA_DIR has its own lock; a screenshot run doesn't take it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha5F5gJt93t3yEx3XcS
Every warning `cargo clippy --all-targets` gave (50 on macOS, 8 more only on
Linux, 1 in the relay), fixed without changing what anything does:
- long types get a name (Peer, Members, Imported, Joining, Mention, Stream…);
- the two big enum variants are boxed (the vault's login plan, joining an
account);
- a test now waits for the copy it relaunched (it left a zombie behind);
- a hint's format had a dead `if` whose two branches were both "";
- the rest is what clippy suggests: sort_by_key, as_chunks, is_none_or,
is_multiple_of, while let, from_ref, next_back, struct init, no casts to
the same type.
Checked: cargo test (177 macOS, 181 Linux), relay tests (11), remote_e2e
28/28, and the live Linux test (X11; Wayland clicks, keys, Chinese typing,
scroll and screenshots).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha2RVfSYmrhqNnqx9Z4
A service set up without a screen (over SSH, or on Wayland) used to pick up the desktop
session's DISPLAY/WAYLAND_DISPLAY from systemd, so screenshots waited for a 「分享螢幕」
answer nobody could give. Now it starts its own virtual screen; `anybot setup --real-screen`
keeps the desktop. `anybot setup --refresh-service` rewrites the start script after an update
(install.sh runs it), so joined computers pick up such changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
- install.sh (curl | sh): app, hands, server and deps modes; installs system packages
(right names per release, e.g. libasound2t64 on Ubuntu 24.04), Rust via rustup (1.95+),
Docker for the server; limits parallel compiles on small machines
- Server Docker image: add the ALSA build/runtime packages (the build failed), cache the
cargo registry and target between rebuilds, JOBS build arg
- 加一台電腦 now gives a line that installs AnyBot on a blank computer before joining it
- Makefile: make deps installs Rust too, make doctor, clear message when Rust is missing/old
- README rewritten: one line per use, getting started, update/remove, troubleshooting,
deployment options; docs/install.md and multi-device.md follow it
- Tested on fresh ubuntu:24.04 (app) and debian:12 (curl | sh hands) containers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
- 加一台電腦 (phone menu and the app's 大腦 card) gives a ten-minute,
one-time code and the line to run: anybot setup <address> <code>. The
new computer joins as hands for that brain with no password and nothing
to answer, starts with the computer and checks the brain sees it.
- anybot setup without arguments is one screen: address and code (a pasted
line fills both), or the account and password instead. No role, name or
confirm questions; a brain is asked only when there are several.
- Hands computers are no longer offered as brains.
- The server setup asks only the domain, account and password.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
- anybot setup: a full-screen terminal guide (role, name, account server,
account, which brain) that saves the settings, installs a systemd user
service (with a virtual screen when there is none), and checks that the
account server and the brain see the computer. Flags for scripts.
- Hands can be limited to one brain; the account server says which AnyBot
asks. Choosing a brain in the app does the same.
- deploy/server/setup.sh: domain, account, sign-ups and keys step by step;
writes .env and Caddyfile, starts everything and checks HTTPS. The
server's brain creates the account on first start.
- deploy/linux/hands.sh installs what's needed and opens anybot setup
(no password kept in a file any more).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa