13/Documentation
安全性,运行前必读
Collie 暴露的内容、防御机制与设备配对:每个请求所需的凭据
Collie 在设计上即提供对您机器的远程 shell 访问权限。 单次 Collie API 调用即可将任意按键直接发送到活动终端窗格。任何已配对的设备都可以读取每个窗格(源代码、密钥、环境变量、agent 输出)并以您的用户身份执行命令。自 1.18.0 起,包括读取在内的每个 API 请求都需要已配对设备的 token,因此防线就是配对过程本身:任何能够访问该 URL 且持有有效配对码的人都具有同等权限。在 1.18.0 之前,任何能够访问该 URL 的人都可以读取每个窗格。
这里没有沙盒,也没有命令白名单,因为过滤命令违背了该工具的设计初衷。请将每个已配对的设备视为 root 登录,将配对码视为密码。设备丢失时,请立即使用 collie devices revoke <label> 撤销。配对可以降低风险但无法消除风险,因此请将 URL 保留在专用网络(例如 tailnet)中,切勿暴露在公共互联网上。
配对设备:写入凭证
自 1.18.0 起,此凭据适用于每个请求,包括读取请求,而不仅限于写入请求。
# on the host — prints an 8-character code and a QR code, good for 10 minutes
bin/collie pair配对始终开启,读取与写入均需要配对令牌。在设备配对之前,Collie 对所有手机和浏览器均响应 403 device not paired。在手机上打开 Collie 之前,请先在主机上运行 collie pair。
在手机上打开 Collie,进入 设置 → 已配对的设备,输入配对码并为设备添加标签;也可以扫描命令输出的二维码,直接打开该界面并自动填入配对码。手机会保存返回的 token。Collie 仅保留其哈希值,且该 token 仅显示一次。无需重启进程;运行中的守护进程会在下一次请求时应用配对与撤销操作。
这两个设备关卡解决不同的问题,你可以运行其中一个、两个都运行,或者都不运行:
| 询问 | 信任 | 吊销方式 | |
|---|---|---|---|
COLLIE_DEVICE_HEADER | 此设备是否在操作员的列表中? | 你的代理,用于注入其已净化的名称 | 编辑 COLLIE_DEVICE_ALLOWLIST,然后重启 |
| 配对 | 此设备是否持有我签发的凭证? | 网络上的任何内容都不信任 | collie devices revoke <label>:实时生效 |
配对无需额外的基础设施。适用于不存在注入标头的代理的直接 tailscale serve 配置。
配对会拦截除特定项外的每个 /api 路由,包含读取操作。仅保持开放两个路由:供监控器或负载均衡器请求的 /api/health,以及设备在持有 token 前所需的 /api/pair。/api/health 应答构建版本、crew 模式以及过去 7 天的三项计数(输入框被判定为空闲的次数、无法读取的次数,以及人员越过 Collie 无法读取的屏幕进行手动发送的次数)。这些计数不包含任何窗格、文本或人员的名称。
设备标头限制写入和两项读取:文件视图(可显示工作区文件夹下的所有文件),以及“新建”页面的 浏览(列出 home 目录下的文件夹名称,即 ADR 0086)。
bin/collie devices list # what holds a credential, and when each was last seen
bin/collie devices revoke old-phone # effective immediately, no restart全新安装没有配对设备,因此在运行 collie pair 之前,Collie 不会响应任何手机。撤销最后一台设备并不会重新开放 Collie:所有设备随后都会收到 device not paired。若要恢复,请在主机上运行 collie pair 并重新配对手机。未配对任何设备时,collie doctor 会发出警告。
注意。 crew 链接和 standby door 保留各自的凭据。lead 通过固定的双向 TLS 和 crew 密钥将读取请求转发给 member,因此 member 不需要自己配对设备(crew)。
输错配对码五次会导致该配对码失效,需要重新运行 collie pair。此外,bridge 会对每个来源地址每分钟限制最多十次配对尝试,超出时返回 429 和 Retry-After: 60。若位于同一台机器上的 front door 之后,来源地址为最后一条 X-Forwarded-For 记录(由 front door 添加)。来自任何其他对等端的该请求头都会被忽略。计数器保存在内存中,bridge 重启时重置。
CLI 自身的读取
每次启动时,bridge 都会在状态文件夹中的 local-secret 写入一个新的随机密钥。collie doctor 和 collie crew update 发送该密钥以读取同一台机器上的自身 bridge。该文件仅所有者可读,因此只有你的账户才能读取,正常停止时会将其删除。bridge 仅将该密钥用于读取,绝不用于写入或 Files 视图,也绝不接受来自其他机器的请求。它仅接受来自回环地址的密钥,且绝不接受带有代理请求头(例如 X-Forwarded-For)的请求。将 COLLIE_HOST 绑定到 tailnet 地址的 crew member 在回环地址上没有监听,因此那里的 bridge 也接受来自本机自身地址的密钥。同一台机器上的纯 TCP 中继(例如 socat 或 ssh -L)仍然可以传递该密钥。该文件是保障密钥归你所有的关键,因此请保持状态文件夹仅所有者可访问。
为设备设置过期时间
已配对的设备会一直保留其令牌,直到你将其撤销。若要进行限制,可以在配对时传入生命周期:
bin/collie pair --expires 30d # also 12h, 2w; at most 3650d
bin/collie devices set-expiry pixel 90d # a new lifetime, counted from now
bin/collie devices clear-expiry pixel # no expiry again生命周期自手机认领配对码的时刻起算。如果不带 --expires,令牌永不过期,与之前完全一致,现有的令牌也不会改变。过期后,bridge 会拒绝该令牌并返回 device expired 而不是 device not paired。手机随后会清除配对遗留的内容,并在“设置”中显示 重新配对,此时运行 collie pair 获取新的配对码即可。collie devices list 和“设置”界面会显示每台设备的过期时间。已过期的设备会留在列表中,直到你将其撤销或使用 set-expiry 为其指定新的过期时间。若要重新配对,可以使用相同的名称:新的配对会替换已过期的条目并撤销其旧令牌,审计日志会记录该撤销操作。如果设备仍在使用的名称对应着尚未过期的令牌,则该名称会被拒绝。crew deputy 的 standby door 也会拒绝已过期的令牌。
在运行多个实例的主机上,在命令前加上 COLLIE_INSTANCE=<name>,并在手机上打开该特定实例的 URL(单台主机上运行多个 Collie 实例)。
解除配对在手机上清除的内容
配对结束时,手机会删除 Collie 在该配对下存储的内容。在“设置”中解除手机配对时,以及 bridge 返回 device not paired 或 device expired 拒绝其令牌时,都会发生这种情况。
手机会删除 token、所有未发送的草稿、保存的窗格文本和 herd、推送订阅、“No prompts”确认记录,以及除 app shell 之外的 Collie 缓存。你的设置会保留:主题、语言、固定项和其他偏好设置不包含会话文本。在撤销任何设备之前,“设置”会要求你确认。
手机自身的擦除是唯一的清理方式。bridge 不会发送 Clear-Site-Data 请求头,因为该请求头还会清除你的设置和离线应用,并且在共享主机名下还会波及那里的其他应用。
如果 bridge 无法读取其已配对设备列表(例如文件只写入了一半),则会返回 503 pairing unavailable。手机随后会保留其令牌以及存储的所有内容,并进行重试。
手机保留的内容
手机会保留其最后所见内容的一个受大小限制的小副本,以便在冷启动且 bridge 无法访问时仍能显示。以下每一项都有大小限制和生命周期。
| 内容 | 位置 | 保留时间 | 解除配对时 |
|---|---|---|---|
| 配对令牌 | localStorage | 直到解除配对、撤销或过期 | 已删除 |
| 设置:主题、语言、固定项 | localStorage | 直到你更改它们 | 已保留 |
| 未发送草稿 | localStorage | 48 小时 | 已删除 |
| 推送端点 | localStorage | 直到发生变更 | 已删除 |
| App shell | Cache Storage | 直到下次构建 | 已保留 |
| 字体与推送标题 | Cache Storage | 直到被替换 | 已删除 |
| Whistle 语音模型与引擎文件(仅限你选择复制它们的情况) | Cache Storage | 直到你将其删除 | 已删除 |
| 最近看到的 Herd 与窗格文本 | IndexedDB collie-store | 24 小时 | 已删除 |
| 各窗格最新的 Chat 轮次 | IndexedDB collie-store | 1 天,或取决于“在此手机上保留聊天记录”设置 | 已删除 |
最后两行为设备端存储。它仅保存网桥已 已脱敏 的文本,每个窗格最多 256 KiB,总共最多 10 MiB,并优先丢弃最早的条目。窗格文本与 Chat 轮次各占窗格 256 KiB 的一半,因此二者不会相互挤出。Chat 轮次保持完整保存,按 Chat 渲染的原样存储,绝非原始终端屏幕。将“在此手机上保留聊天记录”设为关则不保留任何内容,并删除已保存的条目。当窗格请求密码时,手机会丢弃该窗格的条目。存储中的任何内容都无法发送按键或回复。解除配对时的删除内容见 解除配对在手机上清除的内容。
手机的应用切换器也可能显示窗格。离开 Collie 时,手机会为最近应用列表保留一张屏幕截图,该截图可能会显示窗格文本。Web 应用无法阻止此行为:Android 在页面收到切入后台通知前就已完成截图(已在 Pixel 上测试,2026-10-08),iOS 也不做保证。如果介意这一点,请在将手机交给他人前锁定手机或关闭 Collie。
风险模型
关键安全边界与风险:
- 它以您的用户权限运行。 Collie 继承您的全部访问权限,包括
~/.ssh、git push --force、rm -rf和sudo。 - 所有本地系统用户均可访问该端口。 标准终端多路复用器套接字(
tmux、zellij、herdr)使用文件系统权限限制其他本地用户的访问。Collie 监听本地 TCP 端口,这会将其暴露给所有本地 UID。读取操作需要配对令牌,因此没有令牌的其他本地用户除/api/health外什么都读不到。令牌就是边界:能够读取你浏览器配置文件的本地用户也能读取该令牌(ARCHITECTURE.md §6)。 - 处于 hold 状态的权限等待人工点击。 配合
collie hooks install claude --hold-permissions,Claude 的权限 hook 通过 socket 文件请求 bridge。只有你的用户可以打开它(0700 文件夹中权限为 0600 的文件)。hook 在连接前会检查 socket 所有者、该文件夹及其上层 state 目录。bridge 仅针对其放置在窗格中的进程作出应答,绝不会单独应答。点击必须携带卡片展示内容的哈希。屏幕卡片绝不会应答其对话框未显示在屏幕上的请求(为手机拦截权限)。 - Files 视图直接读取磁盘上的文件。 它会显示工作区文件夹下的任何文件,但排除
.git文件夹、Collie 自身的状态与配置文件夹,以及命名类似于 Collie 状态密钥的文件。因此它与写入操作一样需要已授权设备(ADR 0083)。 - “新建”页面的“浏览”列出 home 目录下的文件夹名称。 仅显示名称,受“文件”视图的限制:除非手动输入否则不显示点文件夹,不显示
.git,不显示 Collie 状态或配置文件夹,不包含指向 home 之外的链接,最多 200 行。它还需要已授权的设备(收藏和最近使用的文件夹)。 - 每个已配对设备都可以读取工作区文件夹下的文件。 其中包括
.env文件。仅与你信任可直接操作 shell 本身的设备配对。 - 工作区文件夹下的凭据文件可被读取。 在
~/.claude、~/.codex、~/.config/gh或~/.ssh中打开的工作区会暴露其中的内容。如果第二个 Collie 的配置文件夹位于该工作区下,其.env也会被暴露。文件夹内指向外部文件的硬链接同样不会被拦截。 - 已配对设备可以运行一次性命令。 在默认的
[phone] run = true下,手机可以将其编写的命令输入到机器上的新 shell 中。这不会增加额外权限,因为已配对的手机本就可以打开 shell 并输入内容。该命令行遵循自由行字符规则,若无已配对设备,bridge 将予以拒绝。每个已启动的命令都会保存在状态目录中的commands-recent.json中(权限模式 0600),最多保留 12 个。疑似包含敏感信息的行(如TOKEN=…之类的赋值、包含密码的 URL,或token、password之类的单词)会执行但不会保存。该检查仅为启发式猜测,因此机密仍可能混入列表中;审计日志仅记录命令行的第一个单词及其长度。解除配对或撤销设备会保留该列表,因为再次运行该行仍需要已配对设备。设置run = false可移除该快捷方式(一次性命令、ADR 0095)。 - 每台计算机会保留你通过 Collie 发送的 shell 命令行。 Sent 将你发送到 shell 窗格的单行内容以及每个一次性命令保存在状态文件夹中的
sent.jsonl(模式 0600)。配对设备可以读取它,就像读取窗格一样。部分凭据仍会保留(Sent:你发送的 shell 命令行)。 - 写入操作会记录到
<state-dir>/audit.log,即~/.local/state/collie/audit.log,除非被COLLIE_STATE_DIR移动。服务器记录所有传入的按键、回复、文件上传以及窗格/标签页生命周期事件。请注意,审计日志提供的是事后可见性,而非访问控制。在 Type 模式下发送的字符绝不会写入日志:COLLIE_AUDIT_CONTENT=none会脱敏每个字符,默认预览仅记录•标记的计数。Enter 和 Ctrl+C 等命名按键保持可读(ARCHITECTURE.md §6)。durable agent 的应答、发送、停止、按钮点击、启动、重新打开和重命名也会被记录(记录的内容)。 - 响应标头。 每个响应都携带
X-Content-Type-Options: nosniff、Referrer-Policy: no-referrer和Permissions-Policy: camera=(), geolocation=(), microphone=(self), payment=(), usb=()。麦克风权限保持允许,供免提语音设置使用。App shell 上的 Content-Security-Policy 包含object-src 'none'、form-action 'self'和frame-ancestors 'none'。Strict-Transport-Security仅在请求通过 HTTPS 到达时发送,无论是通过 TLS 监听器还是来自代理的X-Forwarded-Proto: https。它仅覆盖响应的主机名,不包含其子域名,因为 Collie 经常与其他服务共享父域名。网桥本身在tailscale serve后面使用纯 HTTP,浏览器在该环境下会忽略此标头。从/api/blobs/提供的图像属于会话内容,因此携带Cache-Control: private, no-store,任何缓存都不会保留它们,包括手机自身。 - 默认防御控制。 Collie 仅严格绑定到环回接口,仅通过
tailscale serve或等效的反向代理路由流量,并应用严格的 CSP 规则、同源检查和 host 标头验证。窗格输出渲染为 React 文本节点,而非innerHTML。切勿使用tailscale funnel或暴露原始端口。若要授权特定硬件,请直接使用 配对;或者,如果你的代理注入了设备 ID,请使用下方的两个COLLIE_DEVICE_*变量。
| 变量 | 作用 |
|---|---|
COLLIE_ALLOW_NON_LOOPBACK_BIND=1 | 选择退出仅限环回的绑定;未设置时,bridge 会拒绝绑定到 0.0.0.0。 |
COLLIE_ALLOW_ANY_HOST=1 | 禁用 host 标头验证(默认开启且失败时拒绝访问)。 |
COLLIE_TRUSTED_USER | 拒绝缺少或不匹配 Tailscale-User-Login 标头的请求。 |
COLLIE_TRUSTED_USER_OPTIONAL=1 | 允许缺少 Tailscale-User-Login 标头(标记的节点绝不会发送该标头)。 |
COLLIE_ACCESS_TEAM + COLLIE_ACCESS_AUD | 仅限 Cloudflare Tunnel。拒绝所有远程请求,除非其 Cf-Access-Jwt-Assertion 针对此 Access 应用验证通过。仅回环地址上的本地进程、/api/health 和 crew 链接可以跳过该验证,且配对机制仍然有效。其他前端入口(例如 tailscale serve)也会被拒绝(Cloudflare Tunnel)。 |
COLLIE_DEVICE_HEADER | 代理注入包含设备 ID 的标头名称。 |
COLLIE_DEVICE_ALLOWLIST | 允许写入的以逗号分隔的设备 ID 列表;所有其他设备保持只读(docs/deployment.md)。 |
COLLIE_REDACT=off | 关闭窗格文本、diff 和文件文本中的密钥脱敏(下方)。默认开启。 |
COLLIE_SENT=off | 不保留你发送的 shell 命令行记录(下方)。默认开启。 |
🚫 切勿将tailscale funnel与 Collie 配合使用。 Funnel 会将流量路由到公网,而tailscale serve则将访问限制在你的私有 tailnet 内。Collie 不支持在 Funnel 上运行。
使用 Tailscale ACL 和 COLLIE_TRUSTED_USER 进一步限制访问。按原样提供,不提供任何保证。
持久 agent
你挂载的 durable agent 是你运行或部署的代码,Collie 将其文本视为不可信内容。私有 socket 能阻挡其他用户,但无法阻挡属于你自身用户的进程;而在 https 上,token 是唯一的防线。每种传输机制的信任规则、Collie 对 durable agent 文本的处理方式以及审计日志保存的内容见 持久 agent 的安全性。
语音引擎 (Whistle)
Whistle 会运行第三方代码:来自 Cactus Compute 的 WebAssembly 引擎。它在手机上运行,或在宿主机上作为 bridge 的用户运行。Collie 会限制该代码能够访问的范围,但无法完全消除访问能力。
- 已 vendored 并固定。 引擎包含两个文件:
needle.js和needle.wasm,按上游发布的内容逐字节保留,并附带上游许可证和来源说明 (web/public/stt/needle-3-93e88ede/)。测试会固定这两个文件的 sha256 以及 wasm 可向宿主请求的 16 个函数的列表。出现新的导入即是中止运行的理由。仅限人工更新固定值,且更新前必须先阅读 diff。模型有自己固定的哈希值,Collie 仅在匹配时才会保留下载的副本。 - 在手机上,使用带有自身策略的 worker。 wasm 在专用的 worker 中运行。bridge 使用此策略提供
stt/下的所有脚本,其他页面均不使用:Content-Security-Policy: default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; base-uri 'none'worker 没有网络访问权限,没有 DOM,也无法从其他位置加载代码。它无法读取位于
localStorage中的配对 token,且 worker 没有localStorage。在执行其他操作之前,它会先编译一个微型 wasm 模块。未向 worker 提供独立策略的浏览器将拒绝此操作,此手机 在该处将显示为不可用。 - 页面策略不会改变。 文档策略绝不会获得
'wasm-unsafe-eval',并保留connect-src 'self'。 - worker 仍可访问的内容。 它可以读写该源的 IndexedDB 和 Cache Storage,任何策略指令都不会对其进行关闭。
collie-store存有近期的窗格和 Chat 文本 (手机保留的内容)。该文本虽已脱敏,但仍可读取。此访问范围已被接受,并在 ADR 中记录。如果此问题开始变得重要,下一步将是在 worker 周围使用沙盒化的 frame。 - 在宿主机上,作为 Collie 自身二进制文件的子进程。 每次听写启动一个短生命周期子进程运行
_whistle-transcribe,使用 Collie 编写的固定参数列表。在编译任何内容之前,它会针对固定值校验引擎、wasm 和模型。它有 60 秒的超时限制,超时将通过 SIGKILL 终止,并具有 256 KiB 的输出上限,最多同时运行两个。它不会获取 bridge 的任何COLLIE_*变量。bridge 仅将两个变量(状态目录和安装目录)设置为其自行解析的路径。请求中除了录音内容外,没有任何数据会进入参数列表。 - 由人工点击触发的第二次出站调用。 更新检查是第一项。模型下载是第二项:单个文件,来自一个固定的 Hugging Face 地址,仅在哈希匹配后写入。手机从不访问 Hugging Face。它通过配对 token 从宿主机复制模型。这些路由需要写入设备,仅在 lead 上运行,一次允许一个下载,并带有审计记录。
- 从 Settings 进行设置是“设置属于 CLI 行为”规则的例外。 存储凭据或指定命令的 Provider 保留在终端中。Whistle 不执行这些操作。失窃的写入 token 已经能向终端输入内容并启动更新,因此设置中的点击不会赋予它任何新权限。
- 从 Settings 切换到 Codex 是另一个例外。 写入设备可以将宿主机在 Whistle、Codex 和 Off 之间切换,不能执行其他操作。Codex 需要完整同意,文本与
collie stt setup打印的内容完全相同,并点击 我接受;随后 bridge 会运行 CLI 自身的探测程序。失窃的写入 token 可以将宿主机的语音功能指向操作员已登录的 ChatGPT 账号。它无法添加或替换密钥或命令。该 token 已经可以在终端中输入codex。ADR 0097 对此进行了权衡。从 Settings 进行切换还会将配对设备在配对时提供的名称以及时间写入stt.json,以便 宿主机语音 可以说明最后是谁更改了它。不会写入任何 token 或地址。运行collie stt setup会移除该行记录。 - 配对设备可以按名称读取宿主机语音设置中指定的内容,且仅限名称。 仅包括命令名称、模型文件名称和语音服务的主机名,绝不包括路径、参数、密钥或 URL 路径。
为何这样设计:ADR 0096。安装步骤见 语音输入与 Web Push。
Walky talky
对讲机在 agent 会话之间传递消息,因此本节说明消息能证明什么、不能证明什么。命令位于 Walky talky。
# in .env, then run `collie restart`
COLLIE_WALKY=off该行会使这台计算机拒绝发送给其窗格的所有消息。计算机上的 CLI 仍可发送消息。
- crew 密钥用于对跨机器的消息签名。 成员使用其 crew 密钥对消息签名。lead 根据其为该成员固定的密钥验证签名,然后为接收消息的计算机添加自己的签名。单独安装没有 crew 密钥。它不签署任何内容,也不向机器外发送任何内容。
- 接收方通过 lead 的背书来验证发件人。 成员仅固定其 lead。因此 lead 随消息一起发送发件人的证书,并签署一份简短声明,证明该证书属于该 crew 成员。接收计算机检查该声明,然后根据证书验证发件人的签名。如果任何检查失败,则拒绝该消息。它仍然信任 lead 关于谁在 crew 中的判定。
- 只有 lead 可以写回结果。 lead 向成员发送该成员自身消息的处理结果。成员仅接收来自其固定的 lead 的结果,且仅针对其已发送并仍在记录的消息。结果以及 lead 收到的记录保留在内存中,并在 10 分钟后清除。
- 手机卡片需要依赖该日志。 手机仅在 bridge 自身的日志包含该消息 id 时才绘制消息卡片。agent 仅打印在屏幕上的标头保持为纯文本,带有标记“此机器上无日志记录”。
- 窗格令牌不是秘密。 地址中的令牌(例如
#k3f9)可防止消息到达接管了已关闭窗格 id 的新会话。collie walky who将其打印给每个 agent,且你的用户可读取<stateDir>/walky/instances.json。它不能证明发件人是谁。 - 消息经过的每台机器都会保留该消息。 发送方机器、lead 和接收机器各自将消息记录在
<stateDir>/walky/中。日志保留 7 天,最多 2,000 行。切勿在消息中放入保密信息。 - agent 发送的消息即为对等节点发送的内容。 窗格收到包含发件人标头且无正文的单行内容。agent 将正文读取为
collie walky inbox <id>的输出,harness 会将其视为数据而非你的指令。安装的 skill 会指示 agent 权衡该内容,切勿仅仅因为对等节点的请求就运行破坏性命令。
注意。 agent 以您的用户身份运行,因此它可以读取 crew key 并打开本地 socket。它可以签署消息,也可以声明不属于它的窗格。签名用于在机器间传输时保护消息,并告知接收方是由哪台机器发送的。但如果同一台机器上的程序伪造自身身份,签名无法防范此类情况。
对讲机不会增加任何出站调用。发往另一台机器的消息使用现有的 crew link 传输,任何模型、云服务或第三方都无法看到它。
离开机器的内容均已脱敏
Collie 会在窗格文本和文件内容到达手机前,对其中已知的密钥模式进行脱敏。
# in your .env, only to turn the mask off; it is on by default
COLLIE_REDACT=off脱敏在网桥上运行,覆盖五个路径:终端镜像、Chat 与 History 视图、每条推送通知、Changes 视图中的 diff,以及 Files 视图中的文件文本。隐藏的内容会替换为相同宽度的 • 标记,以保持列数和行数不变。厂商前缀保持可读,因此 sk-o•••• 仍能提示被隐藏的内容类型。
它仅匹配高置信度模式:
| 模式 | 被脱敏内容的示例 |
|---|---|
| 带前缀的 API 密钥 | sk-…、sk-ant-…、sk-or-v1-…、ghp_…、github_pat_…、xoxb-…、AKIA…、AIza…、glpat-…、npm_… |
| JWT | 三段 base64url 部分,第一段以 eyJ 开头 |
| PEM 私钥 | BEGIN … PRIVATE KEY 及其 END 行之间的每一行 |
| Bearer 令牌 | Bearer 后面的令牌,20 个字符或更多 |
| 具名值 | password=、secret:、token=、api_key: 及类似项后面的值,8 个字符或更多 |
注意。 这是一种缓解措施,而非绝对保证。独立的明文密码、裸 hex 或 base64 值,以及前缀不在列表中的密钥都会被有意忽略。针对它们的模式会在每个屏幕上误伤普通的文本和代码。
某些普通文本也会被脱敏,例如包含 token: something 的一行文字或 YAML。你输入并发送的内容绝不会被脱敏,且审计追踪遵循其自身的规则(COLLIE_AUDIT_CONTENT)。
该开关仅存在于 bridge 上,配置项为 COLLIE_REDACT。Settings → System 中将其显示为只读的 "Secret masking"。手机端特意未提供开关:手机上的开关会让任何已配对的手机,或失窃的手机能够关闭脱敏。要读取脱敏的值,请在机器上查看。窗格首次显示脱敏文本时,手机端会显示一行提示,每台设备仅提示一次。如果你将脱敏文本粘贴到回复中,输入框下方的警告会提示窗格收到的是点号,而非密钥。
在 crew 中,每个成员会对自己的文本进行脱敏,lead 在文本送达手机前会再次脱敏。lead 会使用自身的脱敏规则脱敏成员的镜像、Chat、History、diff、文件文本和窗格标题,因此仍运行 1.17.x 的成员无法将明文密钥发送到你的手机。脱敏文本在被再次脱敏时保持原样。仅当 lead 和成员都设置了 COLLIE_REDACT=off 时,文本才会以未脱敏的形式送达手机。一种边缘情况:运行 1.17.x 的成员自身不脱敏任何内容,因此当回复校验所依据的行中存在密钥时,手机可能会拒绝该回复并提示 "The screen changed before that could be sent"。随后该回复会一直等待,直到该成员运行 1.18.0。
如果 lead 无法读取成员的回答以进行脱敏,它就不会转发该回答。随后手机端会将该读取显示为失败,就像处理无法连接的成员一样。
推送通知也仅通过你指定的名称来命名窗格:窗格的标签、Claude 的 /rename 名称,或单窗格标签页的名称。它绝不会使用窗格中程序设置的标题,因为任何程序都可以设置该标题,且标题可能包含路径、命令或密钥。没有此类名称的窗格会以其 harness 命名,例如 claude。
Sent:你发送的 shell 命令行
每台机器都会记录您通过 Collie 发送的 shell 命令行,方便您查找并重新发送。
# in your .env, to keep no record on this machine
COLLIE_SENT=off| 问题 | 回答 |
|---|---|
| 保留的内容 | 您发送到 shell 窗格的命令行,以及来自 New 页面的每个单次运行命令。针对每行记录:文本、所在目录、时间以及属于两者中的哪一种。 |
| 从不保留的内容 | 发给 agent 的 prompt、传给程序的文本、来自 Keys 面板的按键以及 Type 模式输入的内容。 |
| 位置 | 位于状态目录中的 sent.jsonl,除非由 COLLIE_STATE_DIR 移动,否则为 ~/.local/state/collie/。该文件权限模式为 0600,所在目录权限模式为 0700。 |
| 保留时间 | 每台机器最多保留 5000 行,且不保留超过 365 天的内容。 |
| 谁可以读取 | 已配对的设备,因为它可以读取这些命令行所发送到的窗格。 |
| 在 crew 中 | 每台机器保留自己的文件。当您的手机发起请求时,主控节点会向其成员节点查询,且不保留副本。 |
Collie 会发送您点击的每一行,然后决定是否保留它。对于符合以下情况的命令行,不保留任何内容:
- 以空格或制表符开头,
- 设置变量,例如
TOKEN=abc deploy或export AWS_SECRET_ACCESS_KEY=…, - 包含带密码的 URL,例如
https://user:pass@host, - 包含诸如
password、secret、token、bearer或authorization之类的词, - 包含密钥脱敏规则可识别的格式,例如
ghp_…或sk-…密钥, - 长度超过 4096 个字符。
此类命令行不会留下数据行、计数,也不会在日志行中记录其文本。
若要排除某一行,请在开头加上空格。shell 会照常运行它,Collie 则不会保留任何内容。
注意。 该检查基于启发式推测。它会保留您作为明文参数传递的密码(例如 mysql -pPASS),以及任何格式未知的机密信息。请在此类命令行开头加上空格。若要清除某一行,请在 Sent 面板中该行所在的记录上使用 Forget。若要清除整台机器的记录,请使用 Clear Sent。两项操作均在设置了 COLLIE_SENT=off 时有效。审计日志会记录每次清除操作及受影响的数量,绝不记录具体行内容。每一行在离开机器前都会经过密钥脱敏处理。
采用此设计的原因:ADR 0107。
Windows 上的机密文件
在 Windows(实验性)上,Collie 将其机密文件限制为仅对你的账户、SYSTEM 和 Administrators 可访问。“你的账户”是指运行 Collie 的 Windows 账户。
NTFS 没有 0600 模式,因此 Collie 使用其状态文件夹和配置文件夹的访问控制列表(ACL)。Collie 在此处写入的每个文件都会继承相同的列表。用户个人资料中的默认文件夹已对其他标准用户关闭访问权限。当你使用 COLLIE_STATE_DIR 或其他设置移动文件夹时,此检查最为重要。
启动时,bridge 会检查这两个文件夹及其机密文件。如果其他账户可以读取其中某个文件,bridge 会进行修复,但仅限于 Collie 自身的文件夹。它会先将旧列表保存在状态文件夹下的 acl-backups 中,并输出用于恢复该列表的 icacls /restore 命令。请在以管理员身份运行的终端中执行该命令。对于同时包含其他文件的文件夹,只做检查而不做更改:Collie 会输出供你运行的 icacls 命令。其他命令(例如 collie version)仅进行检查并给出警告。
collie doctor 将结果显示为 secrets-private。其他账户可读取的文件夹会被视为错误,并附带修复方法。Collie 无法检查的文件夹会被视为警告:cannot confirm。
| 情况 | 发生的操作 |
|---|---|
你复制、恢复或同步了该文件夹(zip、不带 /SEC 的 robocopy、OneDrive、文件历史记录、U 盘) | 副本可能会丢失该列表。Collie 会在下次启动时再次检查。 |
| 防病毒软件或受控文件夹访问限制(Controlled folder access)阻止了更改 | Collie 会提示无法将文件夹设为私有,并给出修复方法。 |
| 文件夹位于 FAT、exFAT 或网络共享上 | 没有 Collie 可以使用的列表。Collie 会提示 cannot confirm。请将状态文件夹移至此 PC 上的 NTFS 驱动器中。 |
COLLIE_NO_ACL_REPAIR=1 | Collie 不会更改任何列表。它仍然会进行检查并给出警告,且 doctor 仍会报告。 |
注意。 这不能防止管理员访问。管理员仍然可以读取这些文件。它也不涵盖以你的账户运行的其他程序、文件夹内的硬链接、~/.claude 中的 agent 备份,或者位于 OneDrive 或 Documents 内的状态文件夹。哪些数据会离开你的机器
默认情况下以及依策略而言:没有任何数据。Collie 不发送安装事件、使用统计、崩溃报告或分析数据。没有任何 flag 可以启用它们。
唯一未经提示的主动出站请求是更新检查:向 GitHub 公开 tags API(bridge/update.ts)发送一个匿名的 HTTPS GET 请求,用于将你的版本与最新标签进行比对。该请求不携带关于你或你机器的任何数据,仅包含静态 User-Agent collie-update-check。
Whistle 模型的下载是另一处出站请求。它仅在用户点击 下载到宿主机 或运行 collie stt whistle 时发生,且不会发送任何与你相关的数据(语音引擎 (Whistle))。
对讲机不会增加任何出站调用。发往另一台机器的消息通过 crew link 传输,不会流向其他任何地方(Walky talky)。
“报告问题”不会发起任何出站调用。发送失败后,手机可以在您自己的浏览器中以链接形式打开已填好内容的 GitHub 新建 issue 表单。您可以先通读全部文本,然后使用自己的账户自行提交。Collie 不保存 GitHub token,手机也绝不会调用 GitHub(ADR 0123)。
如果你设置了 COLLIE_ACCESS_TEAM,Collie 还会在启动时以及每小时一次获取该 Cloudflare Access 团队的公钥。该请求由你决定是否开启,并且同样不会发送任何关于你的信息。
若通过 URL 挂载 durable agent,Collie 会在每次轮询时调用该 URL,并在 Authorization 头中携带 durable agent 的 bearer token。该调用也由你决定是否开启,挂载之前不会发送任何内容(持久 agent 的安全性)。
如果将来加入数据收集,明确的 opt-in 是最高限度:默认关闭,以显式问题询问,绝不通过 flag 携带或默认开启。移除此承诺属于破坏性变更(ADR 0034)。