---
title: "隐私"
description: "「隐私」：yokoten 使用指南的一章。"
canonical: https://yokoten.app/zh/docs/guide/privacy
lang: zh-CN
source: https://github.com/yokoten-labs/yokoten/blob/v0.1.2/docs/i18n/zh-CN/guide.md
ref: "v0.1.2"
---

> For AI agents: the documentation index is at https://yokoten.app/llms.txt. To set up yokoten in a project, follow https://yokoten.app/agents.md.

# 隐私

第 11 条规则有检查守着。CI 和每次提交都会扫个人邮箱和 IP 地址。在你自己的电脑上，它还会读
`~/.config/yokoten/private-marks`，里面是你的名字、所在城市、域名、服务器名。这个文件放在
仓库外面，因为「不能公开的东西」这张清单本身也不能公开。查到问题时只报文件和行号，不会把
词表里的词打印出来。报告会说是哪一类词，比如 `matches your git name (a private mark yokoten added by itself)`，
或者 `matches a word you added to your private marks`。后面的修复提示告诉你怎么改这个词：
yokoten 自己加的那一类用 `yokoten marks off git-name`，你自己加的词用 `yokoten marks remove`。

`YOKOTEN_PRIVATE_MARKS` 指向第二个词表文件。检查两个文件都读，里面的词都算。所以这个设置只能多加词，
不能少。`~/.config/yokoten/private-marks` 在但读不了时，不管这个设置怎么写，检查都会失败。
`yokoten marks add` 和 `install` 还是写进你家目录里的那个文件。
这台电脑的放行文件（见下文）只从 `~/.config/yokoten` 读，不会去读这个设置所指文件旁边的。

agent 也不能换家目录。`HOME=/tmp/x git commit` 会让提交检查去别的文件夹找词表，找不到，就放行了。
所以给 git、gh、yokoten，或者给会跑它们的 shell、`eval` 设 `HOME` 或 `USERPROFILE`（大小写都算），守卫都会拦，
写在 `env` 或 `sudo` 后面也一样。在整行里设也拦：`export`、`declare`、`read`、`printf -v`、`for` 循环、
`${HOME:=x}`。给别的程序设就放行：`HOME=$(mktemp -d) npm test` 是让测试别碰你的文件。只是读 `$HOME` 没问题。

只有字母和空格的词，比如名字或城市，按整个单词查。前后紧挨着别的字母时，才不算查到：`sam` 能在
`hi Sam`、`sam_dev`、`@sam`、`sam97` 里查到，在 `sample` 里查不到。反斜杠转义（如 `\n`）、URL 编码的
`%2F`、`%5C`、`%20`，以及小写字母变大写（`githubSam`、`SamDev`），也都算词的边界。较长的词，
各个单词之间可以有空格、`-`、`_`、`.`，也可以什么都没有，所以 `sam example` 能在 `sam-example` 和
`samexample` 里查到。`redact` 藏词用同样的规则。别的词，比如域名、地址、数字，在哪儿都查，
就算在单词里面。名字用的文字要是会把词或助词连在名字上，也一样在哪儿都查：中文、日文、韩文、泰文、
阿拉伯文、希伯来文。

项目自己的公开邮箱，比如自家域名下的 `support@`，也会被查出来，yokoten 不会自己放行。如果
这个邮箱本来就是公开的，把它加进 yokoten.json 的 `privacy.allow`。

这个词表是整台电脑共用的，所以私有项目的名字也该写进去。可这个项目自己的仓库总要用到自己的
名字：在它的 yokoten.json 里，把名字加进 `privacy.allow` 就行。`privacy.allow` 里有一项和词表
里的词一模一样（不管大小写），这个词就放行；只是其中一段、或者更长的字符串，都不算。放行只在
这个仓库里有效，`check`、提交钩子和 `gh` 发帖前的检查都放行；别的仓库照样拦。`doctor` 会说这个
项目放行了你几个词，只报个数，不说是哪几个。

没有 yokoten.json 的仓库也能这样放行，不想公开和 yokoten 有关系的仓库也一样。在那个仓库里运行
`yokoten marks allow <mark> --here` 就行。放行记在这台电脑上，就在
`~/.config/yokoten/private-marks-allow.json` 里，只对这一个仓库有效，认的是它的 `origin` 远程地址（主机加路径）。
仓库里什么都不写。没有 `origin` 的仓库用不了这种放行，可以改用 `privacy.allow`。远程地址改了名，
就算另一个仓库，这个词又会被拦。不是默认端口的，端口也算名字的一部分；本地路径认它指向的文件夹。
`git@host:path` 和 `https://host/path` 算同一个仓库，各大代码托管平台也是这么认的。

yokoten 拿不准发帖或推送会去哪里时，一个词也不放行，`doctor` 会说原因。这些情况都算拿不准：
除了 `origin` 还有别的远程；gh 设了自己的默认仓库（`gh repo set-default`）；设了
`remote.pushDefault` 或 `branch.*.pushRemote`；`origin` 的拉取和推送地址（按 git 的 `insteadOf`
改写之后）指向不同的仓库；或者有两条记录都对得上。`gh` 发帖可能发到别的仓库时，这里的放行和
`privacy.allow` 都不算：带 `-R` 或 `--repo`、带 issue 或 PR 的网址、设了 `GH_REPO` 或 `GH_HOST`、
还有所有 `gh api` 和 `gh gist`。发帖还必须是这一行里唯一的命令：前面不能加环境变量、`env`、
`sudo`，也不能有管道或 `$(…)`。heredoc 最多一个，结束词要写成单引号里的名字，比如 `<<'EOF'`。前面只允许一个 `cd`，而且要留在同一个仓库里。这一行里有别的
东西，就可能改了 gh 发到哪里，所以这条帖子按全部词表检查。`doctor` 会说放行是从哪来的：这台电脑，还是 `privacy.allow`。只有词表里有的词
才能放行。想撤回，运行 `yokoten marks allow --remove <mark> --here`。

有些文件本来就要写你的账号名。所以 yokoten 自动加进词表的 forge 登录名，在这几处不算问题：
CODEOWNERS 里的负责人、`.github/` 里的 `@` 提及、`package.json` 或插件清单里的 author、owner
这类字段，还有 LICENSE 的版权行。别的地方照样会查出来。你自己写进词表的词，在哪里都会查。

IP 只查 IPv4，内网地址（比如 `10.x`、`192.168.x`）也算；IPv6 不查。本机地址和专门留给文档用的
几段地址（`192.0.2.0/24` 等三段）不算。浏览器的版本号（比如 `Chrome/120.0.0.0`）不算 IP，
`logo@2x.png` 这种高清图的文件名也不算邮箱。不过写在 `http://` 后面或者路径里（比如 `api/`
后面）的 IP 照样会查出来。

这个检查也会查密钥：GitHub、npm、Slack、Stripe、Google、OpenAI 和 Anthropic 的 token，
AWS 的 access key id，还有 PEM 私钥。你环境变量里名字像密钥的那些变量，它们的真实值也会查。
每一条都标着有多确定：`sure`（确定）会让检查失败，`likely`（像）和 `unknown`（说不准）只提醒。
查到了只说是哪一种密钥，不会把密钥本身打印出来。光删掉不够，git 历史里还留着，得去把它作废，
换一个新的。

查错了的话，在那一行写个注释，开头是 `yokoten-ignore secret: 为什么没问题`。不是密钥的，把 `secret` 换成那条的规则名。
也可以在 `.yokotenignore` 里写一行 `secret: 为什么没问题`。忽略掉的那条还会列出来；不写理由的忽略本身算失败。

`sure` 的密钥和私有词表里的词，不能在那一行忽略，只能写进 `.yokotenignore`，而这个文件只有
lead 能改。PR 上，`yokoten check --pr` 会把这个 PR 新加的每一条忽略都显示成一条提示，审的人
一眼就能看到。

agent 用 `gh` 发文字之前，工具调用守卫也跑同一套检查。直接用 gh 或经过 `yokoten bot -- gh` 都算：

- `gh issue` 的 `create`、`comment`、`edit`、`close`；`gh pr` 的 `create`、`comment`、
  `edit`、`review`、`merge`、`close`；`gh release` 的 `create`、`edit`。
- `--title`、`--body`、`--notes`、`--subject` 里的文字，还有关闭时 `--comment` 的文字。
- `--body-file`、`--notes-file`、`-F` 指向的文件，前面有 `cd` 也跟着找。检查在命令运行前做，
  所以同一条命令里才写的文件，检查时还不存在。只认一种写法：整条命令就是
  `cat > body.md <<'EOF' && gh … --body-file body.md`，后面跟正文和 `EOF`。路径要简单、两边一样，
  结束标记是用单引号括起来的名字，这样 shell 会原样保留正文。这时查正文，原来就有这个文件的话也一起查。
  heredoc 的结束标记里有 `\` 加换行的，直接拒绝。

  别的写法里，只有整条命令是简单的一行时，才读已经在磁盘上的文件：词之间只用 `;` 或 `&&` 连接。
  引号外面不能有 `\`、`$`、反引号、`<`、`>`、`|`、单个 `&`、`(`、`)`、`[`、`{`、`}`、`#`、`*`、`?`；
  `"…"` 里面不能有 `$`、反引号、`\`、`!`。只有一条 `gh … --body-file - < body.md` 也可以。
  以 `~` 开头的词只能是 `cd` 的文件夹或文件路径，而且只能是单独一个 `~` 或以 `~/` 开头，不加引号。
  `cd` 之后，路径里有 `..` 的文件不读。
  gh 旁边的每条命令都必须是下面这些不写文件的命令之一：

  - `true`、`:`、`echo`、`popd`；没有以 `-v` 开头的参数的 `printf`；不带 `-v` 的 `test`、`[`。
  - 只带 `-e`、`-u`、`+e`、`+u`（可以单写，也可以连写，比如 `-eu`）和 `-o pipefail`、`+o pipefail` 的 `set`。
    什么都不带的 `set` 不算。
  - 只跟一个文件夹的 `cd`、`pushd`。
  - 普通赋值，但不能给 shell 自己用的名字赋值，比如 `PATH`、`HOME`、`PS4`。
  - 只设 `GH_REPO`、`GH_HOST`、`NODE_USE_ENV_PROXY` 和 `TZ=UTC` 的 `export` 或命令前缀。
  - 不带 `--web`、`-w` 的 `gh pr|issue|repo|run view|list|checks`。
  - `git rev-parse`、`git config --get <名字>`、`git remote get-url`。
  - 经过 `yokoten bot --` 的上面这些命令。

  不是这样的话，找不到文件、或者文件可能被改，都会拦下命令：请先用一条命令写好文件，
  下一条命令再发，并写完整路径。
- 从标准输入来的正文：heredoc、`<<<`、`< 文件`。
- `gh api` 的字段和 `--input`，只在会写东西的调用里查：POST、PATCH、PUT，或 GraphQL 的
  mutation。搜索、GraphQL 查询这类只读的调用直接放行。

查到问题就拦下命令，修法和提交检查一样。公开的地址加进 `privacy.allow`。命令运行时才拼出来的
文字它看不到：`$(cat notes.md)`、变量、别的程序用管道传进来的内容。文件最多读 1 MB，更大的放行。
它只看命令，不看你的 shell：shell 配置文件里包住 `cd`、`echo` 的函数或别名，它看不到。
`gh api` 的某个选项后面跟着一个像选项的词（比如 `-H -f`），正文照样会查（#659）。

gh 的令牌不给任何 agent 看，lead 和 worker 都一样（#659、#668）。拿到令牌，`curl` 或脚本就能
直接调 GitHub，绕开上面所有规则。gh 和 `yokoten bot` 自己会用令牌，不用看到它。所以对每个
agent，守卫都拦下这些：

- 会打印令牌的 gh 命令：`gh auth token`、`gh auth status --show-token`（`-t`）、
  `gh auth git-credential`、`gh config get oauth_token`。
- 存登录信息的地方：`git credential fill`、凭据助手的 `get`（如 `git credential-manager get`）、
  `git -c credential.…`、`~/.git-credentials`、gh 的 `hosts.yml`、
  `security find-…-password -w`、`secret-tool lookup`。
- 令牌的变量：`$GH_TOKEN`、`$GITHUB_TOKEN`、`$GH_ENTERPRISE_TOKEN`、`$GITHUB_ENTERPRISE_TOKEN`，
  PowerShell 的 `$env:GH_TOKEN` 和 cmd 的 `%GH_TOKEN%` 也算；命令里写了这些名字的 `node`、
  `python`、`jq` 等会跑代码的程序也拦。要在帖子里写这个名字，用正文文件；要搜它，去掉 `$`。
- `GIT_TRACE_REDACT=0`：它会让 git 的跟踪日志打印出令牌。
- bot 的 git 不能带 `-c`，也不能在环境变量里加 git 设置（`GIT_CONFIG_*`）。bot 自己也会去掉
  分页器、编辑器、浏览器、ssh、askpass 这些程序和跟踪、调试设置，分页一律用 `cat`。

`gh auth status`、`gh pr view`、`curl https://example.com` 照常放行。

`gh workflow disable` 对每个 agent 也一律拦下：工作流关掉以后，所有 PR 都不再跑它的检查。
只有 owner 能关。

## agent 读到的东西

上面的检查管的是仓库里的内容。agent 还会读命令的输出，这些输出会进对话记录、发给模型，发出去
就收不回来了。所以有些命令跑之前，yokoten 先把你的信息藏起来。

- **`yokoten redact`**：从标准输入读文字，换成占位符再输出。它会藏起密钥（`<secret>`）、个人
  邮箱（`<email>`）、git 的 user.name 和 Linux、Windows 的用户名（`<owner>`）、主目录（`~`）、
  私有远程仓库的主机名（`<host>`），还有私有
  词表里的词。像域名的词换成 `<host>`，其他的换成 `<mark>`。查词的办法和上面的检查一样。没有私有
  词表也能用，这时只藏邮箱、密钥这类格式和 git 知道的信息。它要是读不了词表，或者有一段藏不住，
  后面的输出就一个字也不印，在 stderr 上用一行字说明，退出码是 1。
- **在 Claude Code 里，守卫会过滤单纯的读命令。** 下面这些命令会打印账号信息：`git log`、`git show`、
  `git shortlog <revision>`、`git blame`、`git for-each-ref`（不管带什么格式），`git cat-file -p`；`git remote -v`、
  `get-url`、`show`；`git config --list`，以及读 `user.*`、`remote.*`（比如 `git config user.email`）；`gh auth status`；用 `gh`
  以 GET 查访问量和账号；`npm whoami`；`wrangler whoami`。整条命令只有其中一条、前后没有别的东西
  时，守卫会把它改成 `set -o pipefail # yokoten-redact`，再接
  `( <命令> ) 2>&1 | <node> <yokoten> redact`，退出码还是原命令的。redact 跑不起来时，输出整个藏起来，
  stderr 上只说一行原因；这时命令本身成功的话，退出码是 1。命令里有 `&&`、
  `;`、管道、重定向、`$(...)`、`sudo` 这类前缀，或者会写文件的选项，就不改，照原样跑。
- **别的 agent 照常跑命令。** 它们的 hook 改不了命令。`doctor` 和会话开头会说一次。想在那边
  直接拦下这类命令，就在 `yokoten.json` 里设 `"privacy": { "output": "stop" }`，守卫会拦下命令，
  告诉 agent 过滤后的命令怎么写。
- **让 git 自己先藏。** `install` 会先问你，再把 git 全局的 `mailmap.file` 指向
  `~/.config/yokoten/mailmap`，这个文件不在任何仓库里。之后 `git log` 和 `git show` 会把你的
  邮箱显示成 `owner`。没有终端，或者你说不要，`install` 就不碰你的 git 配置，只印出要跑的那条命令。文件已经有了的话，`install` 只补缺的行。你要是设了自己的
  `mailmap.file`，`install` 不动它，只告诉你要加哪几行。
- **词表自己补。** `install` 和 `doctor` 会把这台电脑知道的信息加进词表：git 的名字（`user.name`，
  地址、`your name` 这样的占位符、`test` 这样大家都在用的名字除外）、git 的邮箱（noreply 邮箱除外）、
  `gh` 登录的账号、私有远程仓库的主机名。git 名字要是就是你的登录名，只加一次，按登录名加。
  只往后加，从不打印具体的词。和登录名不同，git 名字在 LICENSE 的一行和作者字段里也会被查出来：
  真名可以藏在 noreply 邮箱和 mailmap 后面。词表里只要有一个词，不管哪一类，
  `private-marks` 检查就是 ok；只有词表里一个词也没有，才算缺。另外 `doctor` 会把它找不到的类别
  列成一条可选的提示，比如所在城市、域名。这些只有你自己能加；git 里没有真名的话，真名也要你自己加。
- **想自己管：`yokoten marks`。** 单独运行，只按类别数一数你有多少个词，不显示词本身。
  `yokoten marks add` 加一个你自己的词：在终端里敲（不会显示出来），或者用管道传进去。
  绝不写在命令行上，因为 shell 的历史会留着它。`yokoten marks remove` 用同样的办法删一个。
  `yokoten marks off git-name`（或 `git-email`、`forge-login`）让 `install` 不再加这一类，
  并把它为这一类加过的词删掉。这个选择记在 `~/.config/yokoten/machine.json` 里。想改回默认，
  运行 `yokoten marks on git-name`，名字会重新加上。你自己加的词，它从不动。

套上去的命令要用 bash 跑。在 Windows 上，请在 Git Bash 或 WSL 里用 agent；PowerShell 没有
`pipefail`。

老实说，下面这些藏不住：

- **会改东西或往外发的命令。** `git push`、`fetch`、`pull`、`clone`，还有 `wrangler deploy`、
  `login`，都照原样跑。push 出错时可能会露出私有主机名。改写它们会让不弹确认的 worker 卡住。
- **agent 读的文件。** `cat CODEOWNERS`，或者 agent 自己的读文件工具，看到的就是文件原样。
- **环境变量。** `env` 和 `printenv` 不过滤：它们会打印各种密钥。别在 agent 会话里跑。
- **浏览器页面和截图。** 别把账号页面当文字读给 agent。

hook 不可能认得所有命令。输出里露出了你的信息，就开一个事故 issue，再给那条命令在
`ACCOUNT_PRINTERS`（`src/rules/guards.ts`）里加一行。

## agent 拿到的环境变量

你的 shell 里可能有 token 和密钥。agent 看得到，就能把它们打印出来、拿去推送，或者发出去。
所以 yokoten 有一个函数，专门给 agent 准备一份干净的环境变量，所有运行环境都用它（#613）。
这个函数现在就有，`yokoten worker env` 可以看它的结果。

`yokoten desk` 就用这份环境变量启动 agent（见 [工位](https://yokoten.app/zh/docs/guide/managing-agents-like-a-team.md#工位)）。用别的办法启动的 agent，拿到的是
启动它的会话的全部环境变量。所以 lead 的会话要从不带 token 的 shell 里启动。

这个函数留下什么、去掉什么：

- **留下**每个程序都要用的变量：`PATH`、`HOME`、`LANG`、`LANGUAGE`、`LC_*`、`TERM`、
  `COLORTERM`、`TZ`、`TMPDIR`、`TEMP`、`TMP`、`USER`、`LOGNAME`、`SHELL`，还有
  `XDG_CONFIG_HOME`、`XDG_DATA_HOME`、`XDG_CACHE_HOME`、`XDG_STATE_HOME`、`XDG_RUNTIME_DIR`。
  Windows 上还留 `SystemRoot`、`USERPROFILE`、`APPDATA`、`PATHEXT`、`ComSpec` 这一类。
- **留下让护栏更严的 `YOKOTEN_*`：** `YOKOTEN_ROLE`、`YOKOTEN_FIX_TASK`、`YOKOTEN_PRIVATE_MARKS`
  和几个设置项。机器人的密钥和 app id、`YOKOTEN_RELEASE_APPROVAL`、`YOKOTEN_LEAD_ONLY_OK`
  不会从你的 shell 带过去，要给的话由 lead 专门给。
- **其余变量一律去掉。** 名字里带 `TOKEN`、`SECRET`、`KEY`、`PASSWORD`、`AUTH`、
  `CREDENTIAL`、`PRIVATE` 的也去掉。只有两个例外：`YOKOTEN_PRIVATE_MARKS`（它只是个路径），
  和运行环境自己的登录变量。
- **值长得像密钥的也去掉：** GitHub、GitLab、Hugging Face、AWS、Google、Slack、JWT、
  `sk-` 开头的密钥、私钥，还有带密码的 URL。超过 32 KiB 的值太长，来不及查，也去掉。
- **厂商自己的登录变量：** 每个运行环境的文件里写明它家的登录变量，比如 Claude Code 的
  `ANTHROPIC_API_KEY`。只有这个运行环境的 agent 拿得到。通用的凭据永远不算登录变量：
  `GH_TOKEN`、`GITHUB_TOKEN`、AWS 的密钥，以及 Gemini CLI 那边的 `GOOGLE_API_KEY` 和
  `GOOGLE_APPLICATION_CREDENTIALS`。用 Vertex AI 的话，要由 lead 专门把它们传过去。

想看 agent 会从你的 shell 拿到哪些变量，就跑 `yokoten worker env`；加上运行环境名，比如
`yokoten worker env claude-code`，会把它的登录变量也算进去。它只列名字、数去掉了几个，
从不显示值。

## 时区

每个提交还会记下提交时间和你的时区，而时区能大致看出你住在哪里。所以提交检查要求用 UTC：
`init` 会给 agent 会话设好 `TZ=UTC`，你自己提交时，它会告诉你怎么设。

---

上一章: [像带团队一样管 agent](https://yokoten.app/zh/docs/guide/managing-agents-like-a-team.md)
下一章: [做不到的事](https://yokoten.app/zh/docs/guide/what-it-doesnt-do.md)
