
Stavrobot 是一款个人 AI 助手,其构建原则是“AI 助手所需的一切访问权限,不多不少”。
它具备 AI 助手的所有出色功能,但专注于沙箱化、隔离和最小权限。它轻量级,只需执行 docker compose up 即可部署。
uv 运行带 pip 依赖的任意 Python 代码,与宿主环境隔离。AI 辅助安装: 告诉你的编程 AI(Claude Code、Cursor、Windsurf 等)获取并遵循 https://stavrobot.stavros.io/INSTALL.md —— 它会以交互方式引导你完成整个设置过程。
手动安装:
在 Telegram 上给 @BotFather 发消息创建一个机器人并复制 token。给 @userinfobot 发消息获取你的 Telegram 用户 ID(用作聊天 ID)。
将 env.example 复制为 .env,并将 POSTGRES_PASSWORD 修改为安全的值,将 TZ 修改为你的时区。
将 config.example.toml 复制为 data/main/config.toml,并填写必填字段:apiKey、password、publicHostname、[owner].name、[owner].telegram(你的聊天 ID)以及 [telegram].botToken。文件中的其他所有内容都是可选的。
docker compose up --build
就这样。在 Telegram 上给你的机器人发消息,它就会回复。有关 Signal、WhatsApp、电子邮件和其他选项的详细设置,请参阅下面的章节。
config.example.toml 复制为 data/main/config.toml。authFile(或 apiKey)和 publicHostname。其他所有内容都是可选的。env.example 复制为 .env 并设置你的时区(TZ)。Postgres 凭据和其他环境设置也可以在此处覆盖。务必将 POSTGRES_PASSWORD 设置为安全的值 —— 默认值是一个弱占位符,不应在生产环境中使用。应用启动后,打开 /settings/config 在浏览器中编辑 config.toml。该页面受 HTTP Basic Auth 保护,并显示原始配置,包括其中包含的任何机密信息。有效保存会创建一个 <CONFIG_PATH>.bak 备份,保存新内容并重启应用;这会中断任何正在进行的智能体回合。
plugin-runner、coder、signal-bridge 和 python-runner 仅在启动时读取 config.toml。影响它们的更改(例如密码)需要手动重启这些容器。
通过设置 config.toml 中的 baseUrl,Stavrobot 可以指向任何 OpenAI 兼容端点(Ollama、LiteLLM、vLLM 等)或自定义 Anthropic 兼容代理。有关必填字段和示例配置,请参阅 config.example.toml。
应用支持两种身份验证模式:API 密钥或 OAuth。
config.toml 中设置 apiKey。无需登录或注销。config.toml 中设置 authFile(存储凭据的路径)。登录页面适用于 Pi 支持的任何 OAuth 提供商。
<your-hostname>/login。按照页面上的提示操作,凭据将保存到 auth 文件。如果机器人在运行期间身份验证过期,它会通过你的消息平台向你发送带有登录 URL 的消息。authFile 路径下的文件。机器人将在下一条消息时检测到凭据缺失,并提示你重新登录。coder 容器是可选的(仅自我编程功能需要)。它使用 Claude Code 的订阅身份验证(OAuth),与主应用的 API 密钥分开。
Docker Compose profiles 以逗号分隔,因此你可以组合它们(例如 COMPOSE_PROFILES=signal,coder)。
.env 文件中设置 COMPOSE_PROFILES 以包含 coder(例如 COMPOSE_PROFILES=coder,或者如果你同时使用 Signal,则为 COMPOSE_PROFILES=signal,coder)。docker compose --profile coder up --builddocker compose exec -u coder coder claude(如果你尚未登录,它会提示你登录)。[coder].model 设置为 Claude Code 模型别名(sonnet、opus 或 haiku)。Signal 需要单独的电话号码——不是你的个人号码。预付费 SIM 卡或 VoIP 号码都可以。
.env 文件中取消注释 COMPOSE_PROFILES=signal 以启用 signal-bridge 容器。docker compose --profile signal builddocker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli link -n "Stavrobot" | tee >(xargs -L 1 qrencode -t utf8)' —— 用手机扫描二维码(Signal > 设置 > 已链接的设备)。docker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli -u +YOUR_NUMBER register',然后使用 docker compose --profile signal run --rm --entrypoint bash signal-bridge -c 'signal-cli -u +YOUR_NUMBER verify CODE' 进行验证。[signal].account。docker compose up --build/settings Web UI 添加允许的号码。
[telegram].botToken。[owner].telegram 里设置聊天 ID(不是你的手机号码)。/settings Web UI 添加允许的聊天 ID。WhatsApp 需要单独的 phone number,否则你就是在给自己发消息,这行不通。
WhatsApp 使用 Baileys,这是一个非官方的 WhatsApp Web 库,作为配套设备(类似 WhatsApp Web)进行关联。不需要单独的 phone number——它会关联到你现有的 WhatsApp 账户。
风险: Baileys 使用非官方 API。WhatsApp 可能会封禁使用它的账户。使用风险自负。
config.toml 中添加 [whatsapp] 部分(格式参见 config.example.toml)。docker compose up --builddocker compose logs -f app)。./data/whatsapp 中。/settings Web UI 添加允许的 phone number。Email 使用 Cloudflare Email Worker 进行入站投递,使用 SMTP 进行出站。完整的 worker 代码和详细设置说明请参见
config.example.toml。
config.toml 中添加 [email] 部分,包含 SMTP 凭据和一个随机的 webhookSecret。config.example.toml 中),并在 worker 上设置 WEBHOOK_URL 和 WEBHOOK_SECRET 环境变量。/settings Web UI 添加允许的发件人地址。配置 Pebble Index,将 ring webhook 发送到 POST /pebble-index/webhook,使用 HTTP
Basic 认证和 Stavrobot 配置的密码。multipart 请求必须
包含 recordedAt(epoch 毫秒)和 client,并且可以包含 transcription
和 audio/mp4 的 audio 文件。音频录音会作为 .m4a
附件排队等待 agent 处理。
docker compose up --build
API 可在 `http://localhost:10567/chat` 访问。完整端点列表请参见 [HTTP API](#http-api)。
**注意:** Docker Compose 仅将应用暴露在 `localhost:10567` 上。若要从外部访问(Telegram/Signal webhook 和 `publicHostname` 设置需要此条件),请设置一个反向代理(例如 Nginx、Caddy)指向 `localhost:10567`。你也可以直接暴露该端口,但不推荐这样做,因为流量将不会被加密。
### 不使用 Docker
需要 Node.js >= 20 以及一个正在运行的 PostgreSQL 实例。```bash
npm install && npm run build && npm start
注意:Python 执行和 Signal 集成仅在 Docker 容器内可用。
除下方标记为 public 的端点外,每个端点都需要使用 config.toml 中的 password 进行 HTTP Basic 认证
(用户名会被忽略)。错误响应是形如 {"error": "..."} 的
JSON 对象。
POST /chat向 agent 发送消息并返回其回复。这是主要入口点:Web UI、Signal 桥接、插件运行器、coder 以及 cron 调度器都使用它。
消息通过单个队列一次处理一条。默认情况下,请求会
阻塞直到 agent 完成其回合,如果 agent 使用了
工具,这可能需要一段时间。设置 "async": true 可在消息通过
enqueueMessage 提交后立即确认,而不等待回合完成。
请求体是一个 JSON 对象(最大 25 MB),包含以下字段。message、
files 或 attachments 中至少需要一个。
| 字段 | 类型 | 描述 |
|---|---|---|
message | string | 要发送给 agent 的文本。 |
async | boolean | 可选。设置为字面量 true 可在提交后收到 202 和 {"accepted":true},而不等待回复。省略它或将其设置为 false 则正常等待。其他值会被拒绝。 |
source | string | 消息来源的渠道。控制路由(见下文),并与消息一起展示给 agent。直接调用时省略;此时 agent 看到的是 cli。 |
sender | string | 在该渠道内发送消息的人:对于 signal 和 whatsapp 是 E.164 电话号码,对于 telegram 是聊天 ID,对于 email 是电子邮件地址。会展示给 agent。 |
files | array | 内联发送的文件。每个条目为 { "data": "<base64>", "filename": "...", "mimeType": "..." }。解码后大于 10 MB 的文件会被跳过,并在日志中记录警告。从 app 容器外部使用此项。 |
attachments | array | 已存在于 app 容器临时上传目录中的文件。每个条目为 { "storedPath", "originalFilename", "mimeType", "size" }。上传目录之外的路径会被拒绝。此项仅供内部调用方使用;外部调用方应使用 files。 |
按 source 路由:
cli、cron、coder、upload 或 plugin:<name> 之一:作为来自你的消息
发送给主 agent。signal、telegram、whatsapp、email:sender 为必填。如果它与
[owner] 中你的某个身份匹配,消息会发送给主 agent。否则发送者
必须在允许列表中,并被分配为某个 agent 的对话者;如果不是,则
消息会被丢弃。两种特殊情况: