多 Agent 共用终端时如何保住命令历史
文章从多个编码 Agent 与人工终端并行运行的场景出发,讨论 zsh 和 bash 历史记录的保存与共享问题。重点风险包括终端退出顺序导致命令丢失,以及含密钥的命令进入历史文件。
AI 深度解读
多个 AI 编程终端共用一份 shell 历史,麻烦不只是命令太多:有的命令要等退出才落盘,有的会被最后关闭的窗口覆盖,临时输入的 API Key 却可能留在明文文件里。作者借 Hermes IDE 的两项修复,整理了 zsh 和 bash 的 8 项历史配置。
这篇最有用的地方,是把「写入文件」「按方向键能翻到」「IDE 会不会推荐」拆开讲清楚。对同时运行 Claude Code、Codex 的开发者,这些差别直接影响命令找回、故障排查和凭据留存。
先弄清楚:哪些命令会进入历史
作者描述的场景是:5 个窗格运行编程代理,第 6 个留给自己。启动前输入过 export ANTHROPIC_API_KEY=...,随后随意关闭窗口,哪些命令能留下?
先别把代理的所有工具调用算进去。它们通常运行在非交互式子 shell 中,而 bash 默认只给交互式 shell 开启命令历史。常见的历史来源,是你在窗格提示符后输入的启动命令、环境变量,以及代理退出后继续执行的命令。

每个 shell 都维护自己的内存历史,再按配置写入共享文件。bash 默认退出时会覆盖历史文件,最后退出的窗格可能盖掉其他窗格保存的内容。按原文所述,zsh 默认通过 APPEND_HISTORY 追加,但也要等退出;窗格被直接终止,尚未保存的命令就可能丢失。
命令已经执行,不代表它已经写进历史文件;已经写进文件,也不代表其他窗口马上能翻到。
zsh 的第 1 项设置是 setopt INC_APPEND_HISTORY,让命令输入后立即追加到 $HISTFILE。另一种选择是 SHARE_HISTORY,它还会导入其他 shell 新写入的命令,但不应与前者同时开启。
作者偏向 INC_APPEND_HISTORY:先保证落盘,自己窗口的 ↑ 则保持相对独立。开启 SHARE_HISTORY 后,↑ 默认也会访问其他窗格导入的记录;需要调整时可使用 set-local-history widget。
凭据过滤要做两层,但它不是保险箱
第 2 项是忽略以空格开头的命令。zsh 使用 setopt HIST_IGNORE_SPACE;bash 使用 HISTCONTROL=ignoreboth,同时启用 ignorespace 和 ignoredups,即忽略前导空格与相邻重复命令。
临时输入凭据时,在整行最前面加一个空格,就能触发过滤。原文提醒,zsh 里这行仍可能短暂留在当前 shell 的内部历史中,直到输入下一条命令。
问题在于,人会忘记加空格。第 3 项因此增加模式过滤,兜住常见的 KEY、TOKEN 导出命令:
HISTORY_IGNORE='(export *KEY*=*|export *TOKEN*=*)'
zshaddhistory() {
emulate -L zsh
[[ $1 != ${~HISTORY_IGNORE} ]]
}
要看清 zshaddhistory() 的作用:单独设置 HISTORY_IGNORE,只在写历史文件时过滤,匹配命令仍会留在当前窗格的 ↑ 列表中;加上钩子后,也能阻止它正式进入历史列表,但仍存在等下一条命令输入后才消失的短暂窗口。
bash 用 HISTIGNORE='export *KEY*=*:export *TOKEN*=*' 同时处理这两处过滤,模式必须匹配完整行。

这套规则的覆盖范围很窄:匹配区分大小写,curl -H "Authorization: ..." 就能绕过去。需要根据实际输入方式补充规则。
过滤命中了哪些写法,才保护了哪些写法。
历史文件是明文,同一用户身份运行的进程,包括代理的 shell 工具,都可能读取它。与此同时,历史过滤只解决历史留存,不能据此推导凭据在其他位置也得到保护。
想找回命令,还要补上时间和执行前确认
第 4 项是时间信息。zsh 使用 setopt EXTENDED_HISTORY,记录格式为 : <beginning time>:<elapsed seconds>;<command>。history 等同于 fc -l,配合 history -i 可以查看 ISO 8601 日期。
bash 则设置 HISTTIMEFORMAT='%F %T ',让时间戳能够写入文件并跨会话保留。
多个终端的命令汇在一起,只有先后列表往往不够。时间戳能帮助你把某次数据库迁移与代理会话记录对上,但这里有个取舍:INC_APPEND_HISTORY 在命令结束前就写入,无法在此时得到完整耗时。INC_APPEND_HISTORY_TIME 等执行结束再写,能记录耗时,却延迟了其他 shell 看见命令的时间。它与 INC_APPEND_HISTORY、SHARE_HISTORY 三者互斥。
第 5 项是历史展开确认:zsh 使用 setopt HIST_VERIFY,bash 使用 shopt -s histverify。
开启后,包含 !!、!$、!git 的命令会先展开并回到编辑区,让你检查,再决定执行。尤其是 sudo !!,确认一步的价值很直接。历史来源变多之后,不能仅凭印象判断展开结果。
它只针对历史展开,并不是所有命令都会经过额外审核。
bash 要补写入机制,两种 shell 都要管理容量
第 6 项专门解决 bash 的覆盖与延迟问题:
shopt -s histappend
PROMPT_COMMAND="history -a${PROMPT_COMMAND:+; $PROMPT_COMMAND}"
第一行让退出时追加历史。第二行在每次显示提示符前执行 history -a,把本会话新增记录写入文件;${PROMPT_COMMAND:+; $PROMPT_COMMAND} 用于接回原有提示符命令。
要注意保存时机:它等下一次提示符出现才写。如果启动代理后长时间不退出,启动命令也要等代理结束、提示符重新出现后才落盘。
第 7 项是容量。作者给 zsh 的组合是 HISTFILE=~/.zsh_history、HISTSIZE=60000、SAVEHIST=50000,再开启 setopt HIST_EXPIRE_DUPS_FIRST,裁剪时优先淘汰重复记录。HISTFILE 未设置就不会保存历史;内存容量大于文件容量,则给去重留出余量。
使用 INC_APPEND_HISTORY 时,文件超过 SAVEHIST 上限的 20% 后仍会重写裁剪。bash 的示例是 HISTSIZE=50000、HISTFILESIZE=50000,退出写入后按文件上限截断。这些容量是作者给出的配置值,并没有最佳值的对照测试。
第 8 项是按需导入其他窗格的记录。zsh 执行 fc -RI,只加入内部历史尚未包含的事件;bash 执行 history -n,读取尚未从文件导入的行。
如果希望 bash 持续共享,可在同一 PROMPT_COMMAND 中把 history -n 放到 history -a 后面。代价与 zsh 自动共享类似:↑ 会混入其他窗格的命令。
我的判断
作者把保存、过滤、检索分开处理,这个思路成立。它也解释了为什么 IDE 修复无法代替 shell 配置。
按原文,Hermes IDE 2.3.7 于 2026 年 11 月 7 日 UTC 中午发布,修复了 macOS 新终端读取、保存历史的问题,并排除自身的代理启动命令;建议列表打开时,↑ 也能访问历史。此前 2.3.2 已隐藏包含 key、token、password 或 auth header 的命令建议,但明确不修改 shell 自己的历史文件。

作者是 Hermes IDE 的开发者,文末也有推广。产品免费、采用 BSL 1.1 源码可用许可,支持 macOS、Windows、Linux,与 Nous Research、Anthropic、OpenAI 或代理厂商无隶属关系;不过这些都不改变配置由 ~/.zshrc、~/.bashrc 决定这一点。
原文的论据主要来自手册行为,没有提供多窗格压力测试、命令丢失率或过滤覆盖率。「即时落盘、按需导入」是合理的工作流偏好,不能当成实测最优方案。喜欢跨窗格连续操作的人,可能更适合自动共享。
我的取舍是优先保留命令,再按需要决定是否自动导入。至于把历史用于排查,它能辅助还原操作,却不能单独证明命令是否成功,或代理实际改了什么。
能拿来做什么
- 同时运行多个 AI 编程终端时,先检查 zsh 是否启用即时追加,或 bash 是否配置
histappend与history -a,再按自己的习惯选择自动共享或手动导入。 - 临时输入 API Key、Token 时,同时使用前导空格和针对实际命令写法的过滤规则,并分别检查文件记录与当前窗口的历史列表。
- 经常执行数据库迁移、部署或排查代理操作时,开启时间戳,把历史与终端输出、代理会话记录一起核对。
- 使用
sudo !!等历史展开前开启确认,并根据每日命令量调整容量,避免重复测试命令过早挤掉需要保留的记录。