
1. 为什么要在 tmux 里跑 1Password CLI如果你平时在终端里干活尤其是用 openclaw 这类 Agent 工具跑自动化任务迟早会遇到一个尴尬问题脚本要读数据库密码、API Key、SSH 私钥但你又不想把它们明文写进.env或者 shell 历史里。1Password CLI命令是op就是来解决这件事的——它让你从 1Password 密码库里按需读取凭据用完即走不落盘。但op有个脾气它依赖桌面应用的授权会话而这个会话在非交互式环境里很容易断。你在普通终端里op signin成功了换个脚本跑就报account is not signed in。openclaw 的 1Password CLI 技能给出的解法很直接——把所有op命令塞进一个专用的 tmux 会话里执行。tmux 会话是一个持续存在的伪终端授权状态能稳住op就不会莫名其妙掉线。这套组合适合谁三类人最受益一是用 openclaw 做本地自动化、需要动态取密钥的开发者二是写 CI/CD 或部署脚本、又不想把 secret 提交进仓库的运维三是单纯想在终端里安全用 1Password、不想每次手动复制的重度 CLI 用户。核心检索词就三个1Password CLI、op、tmux把它们串起来的关键动作是「在 tmux 会话里注入环境变量」。我先说清楚它到底能做什么。op本身支持op read读单个字段、op inject把模板里的占位符替换成真实值、op run带着环境变量跑命令。这三种方式都不需要你把密钥写进文件。而 tmux 的作用是给这些命令提供一个「有状态的终端」让op signin的授权会话活得更久。两者结合你就能在 openclaw 的工作流里安全取用密钥脚本里只出现引用不出现明文。下面我会从环境准备讲起给出可复制的配置片段、tmux 注入写法再用op item get和env检查完成验证。整个过程你可以在本地终端跟着做一遍。2. 前置准备装好 op 并打通桌面应用集成在动 tmux 之前得先把op本身跑通。这一步没做好后面全是白费。2.1 安装 1Password CLImacOS 上用 Homebrew 最省事brew install --cask 1password-cliLinux 用户走官方脚本或包管理器装完先验证版本op --version能打印出版本号比如2.x.x就说明二进制没问题。注意op只是命令行客户端它本身不存密码真正的凭据在 1Password 桌面应用或云端账户里。2.2 启用桌面应用集成这是最关键的一步。op有两种工作模式一种是通过桌面应用授权推荐一种是纯手动输入主密码。桌面应用集成开启后op会调用本地已解锁的 1Password 应用来授权不用每次敲主密码。打开 1Password 桌面应用进入设置找到「开发者」或「Developer」选项卡勾选「与 1Password CLI 集成」Integrate with 1Password CLI。开启后应用会提示你授权确认即可。这里有个前提桌面应用必须处于解锁状态。如果你锁了应用op命令会卡住等待授权在 tmux 里表现为「命令发出去了但没反应」。所以跑自动化之前确保 1Password 是解锁的。2.3 登录账户单账户直接op signin它会弹出桌面应用让你确认授权后终端就处于登录态。多账户的话用--account指定op signin --account my.1password.com或者设置环境变量OP_ACCOUNT后续命令就不用每次都带参数。登录完立刻验证op whoami输出里会显示当前账户的 URL 和用户信息。这一步必须成功否则任何读取操作都会报account is not signed in。2.4 为什么非要 tmux你可能会问我在普通终端里op signin也能用为什么 openclaw 技能强调要放进 tmux原因是授权会话的「生命周期」问题。op的登录态和终端会话绑定普通终端一关或者脚本以非交互方式启动一个新 shell登录态就没了。而 tmux 会话是一个长期存在的伪终端你可以在里面op signin一次之后所有通过tmux send-keys发进去的命令都共享这个登录态。openclaw 的自动化流程正是靠这个机制在后台稳定地调用op。另外tmux 还能隔离环境。用独立的 socket 和会话名避免和你日常用的 tmux 会话互相干扰。技能里给的SOCKET_DIR和SESSION命名就是干这个的。3. 可复制配置tmux 会话与 op 注入写法这一节是核心我给你可以直接抄的片段。先建一个专用的 tmux socket 目录再起会话然后在会话里完成登录和注入。3.1 创建专用 tmux 会话openclaw 技能里的写法是这样的我把它拆开解释SOCKET_DIR${OPENCLAW_TMUX_SOCKET_DIR:-${CLAWDBOT_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/openclaw-tmux-sockets}} mkdir -p $SOCKET_DIR SOCKET$SOCKET_DIR/openclaw-op.sock SESSIONop-auth-$(date %Y%m%d-%H%M%S) tmux -S $SOCKET new -d -s $SESSION -n shell这段逻辑是优先用OPENCLAW_TMUX_SOCKET_DIR环境变量指定的目录没有就退到CLAWDBOT_TMUX_SOCKET_DIR再没有就用系统临时目录下的openclaw-tmux-sockets。-S指定 socket 路径-d表示后台创建-s是会话名-n shell给第一个窗口命名。会话名带上时间戳避免重复。3.2 在会话内登录并验证会话建好后用send-keys把命令发进去tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op signin --account my.1password.com Enter tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op whoami Enter tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op vault list Enter-t $SESSION:0.0定位到会话的第 0 个窗口第 0 个窗格。--后面跟要发送的字符串Enter是回车。注意op signin会触发桌面应用授权弹窗你得在应用里点确认。3.3 用 op inject 注入环境变量真正让密钥「不落盘」的关键是op inject或op run。假设你有一个模板文件secrets.tplDB_PASSWORD{{ op://Private/MyDB/password }} API_KEY{{ op://Private/MyService/credential }}用op inject渲染成真实值op inject -i secrets.tpl -o /dev/stdout但更安全的做法是配合op run让密钥只存在于进程环境里op run --env-filesecrets.env -- your-command其中secrets.env里写的是引用DB_PASSWORDop://Private/MyDB/password API_KEYop://Private/MyService/credentialop run会在执行your-command前把这些引用解析成真实值注入到子进程环境变量里命令结束后环境就没了。整个过程密钥不写磁盘。3.4 在 tmux 会话里执行注入把上面的op run通过 tmux 发进去tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op run --env-filesecrets.env -- env | grep DB_PASSWORD Enter这样你就能在 tmux 会话的登录态下安全地跑带密钥的命令。openclaw 的自动化流程就是这么组织的建会话、登录、注入、执行、抓取输出、销毁会话。3.5 抓取输出并清理执行完用capture-pane把窗格内容抓出来tmux -S $SOCKET capture-pane -p -J -t $SESSION:0.0 -S -200-p打印到标准输出-J合并折行-S -200从历史 200 行开始抓。最后销毁会话tmux -S $SOCKET kill-session -t $SESSION用完即销不留残留会话这也是安全实践的一部分。4. 验证请求用 op item get 与 env 确认注入成功配置写完不算完得验证密钥真的注入进去了而且没有明文落盘。这一节给你两个验证动作。4.1 用 op item get 读取单个字段最直接的验证是读一个具体条目op item get MyDB --fields labelpassword如果登录态正常它会直接打印密码值。如果报account is not signed in说明 tmux 会话里的登录态掉了需要重新op signin。你也可以用op read读引用路径op read op://Private/MyDB/password这两种方式都能确认op能正常访问密码库。4.2 用 env 检查环境变量注入在 tmux 会话里跑tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op run --env-filesecrets.env -- env | grep -E DB_PASSWORD|API_KEY Enter然后抓取输出tmux -S $SOCKET capture-pane -p -J -t $SESSION:0.0 -S -50你应该能看到DB_PASSWORD真实值这样的行。注意这里打印出来是为了验证实际生产里别把值打到日志。验证完可以改成只检查变量是否存在op run --env-filesecrets.env -- sh -c test -n $DB_PASSWORD echo DB_PASSWORD is set这样只输出「已设置」不泄露值。4.3 确认没有明文落盘验证的另一个维度是检查磁盘。你可以搜一下工作目录里有没有意外写出的密钥文件grep -r 真实密码片段 . --exclude-dir.git正常情况下应该搜不到。op run和op inject的设计就是让密钥只存在于内存和进程环境里。如果你发现某个脚本把op read的结果重定向到了文件那就是踩坑了得改掉。4.4 完整验证脚本示例把上面的动作串成一个可复制的验证流程SOCKET_DIR${TMPDIR:-/tmp}/openclaw-tmux-sockets mkdir -p $SOCKET_DIR SOCKET$SOCKET_DIR/openclaw-op.sock SESSIONop-verify-$(date %Y%m%d-%H%M%S) tmux -S $SOCKET new -d -s $SESSION -n shell tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op signin --account my.1password.com Enter sleep 3 tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op whoami Enter tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op item get MyDB --fields labelpassword Enter tmux -S $SOCKET send-keys -t $SESSION:0.0 -- op run --env-filesecrets.env -- sh -c test -n \\$DB_PASSWORD\ echo OK Enter sleep 2 tmux -S $SOCKET capture-pane -p -J -t $SESSION:0.0 -S -100 tmux -S $SOCKET kill-session -t $SESSION跑完看输出op whoami有账户信息、op item get有密码、OK出现就说明整条链路通了。5. 常见报错排查401、local proxy failed 与 OAuth实际用起来报错集中在几个地方。我按真实遇到的顺序列一下。5.1 account is not signed in这是最高频的。原因通常是 tmux 会话里的登录态过期或者你根本没在会话内op signin。解决重新在 tmux 会话里执行op signin并在桌面应用里授权。注意在 tmux 之外op signin对会话内无效必须在同一个会话里操作。5.2 401 Unauthorizedop返回 401一般是账户地址写错或者OP_ACCOUNT指向了不存在的账户。检查op signin --account后面的地址是否和你的账户 URL 一致。多账户场景下确认当前命令用的是正确的账户可以用op whoami看当前身份。5.3 local proxy failed这个报错通常和桌面应用集成有关。op通过本地 socket 和 1Password 应用通信如果应用没启动、没解锁或者集成开关没开就会报 local proxy failed。解决确认 1Password 桌面应用在运行且已解锁设置里的 CLI 集成是开启状态。重启应用有时也能解决。5.4 OAuth 相关报错如果你用的是 OAuth 方式登录报错可能提示 token 过期或授权失败。重新op signin走一遍授权流程即可。注意别把 OAuth token 手动写进配置文件让它由op自己管理。5.5 tmux 命令发出去了没反应send-keys发出命令后capture-pane抓不到输出常见原因是命令还在等待授权弹窗或者sleep时间不够。给op signin留几秒确保桌面应用弹窗被确认。另外确认-t定位的窗口窗格正确$SESSION:0.0里的0.0别写错。5.6 密钥值打印到了日志这是安全坑不是功能报错。如果你用env | grep验证时把真实值打进了日志记得改成只检查存在性。生产脚本里永远不要echo密钥值。5.7 三件套对照表如果你在 openclaw 里配置的是 Cline MCP 或 Codex 这类工具涉及auth.json或settings时记住三件套要写全配置项说明示例Base URL服务地址https://taotoken.net/apiKey访问密钥从控制台获取Model ID模型标识按文档填写缺任何一个都会导致请求失败。Base URL 用 API 地址不要带多余路径。6. 把 op 注入接进你的终端工作流到这里1Password CLI 和 tmux 的配合基本讲完了。最后说几个我实际用下来觉得值得固化的习惯。第一永远用专用 socket 和带时间戳的会话名。openclaw 技能里那套SOCKET_DIR逻辑不是随便写的它避免了和你日常 tmux 会话冲突也避免了旧会话名复用导致的登录态混乱。第二优先op run和op inject别用op read加重定向。op read本身没问题但一旦你把结果到文件明文就落盘了。op run把密钥限制在子进程环境里命令结束就消失这是更安全的模式。第三验证时只检查存在性不打印值。test -n $VAR echo OK这种写法既确认了注入成功又不泄露内容。第四用完就kill-session。tmux 会话长期挂着虽然方便但登录态一直活着也是风险。openclaw 的流程是执行完就销毁你也可以照做。如果你想把密钥管理接进更完整的编码或 Agent 工作流可以看看 Coding Plan 的用法需要验证模型对话效果模型对话页面能直接试要拿 Key 和看接入细节去 API Keys 和接入文档。这几个入口按你的场景选就行。实际跑的时候最容易卡住的地方是桌面应用授权那一步——确保 1Password 解锁、集成开关打开剩下的就是复制上面的片段改改账户地址和条目名。跑通一次之后你会发现终端里再也不用到处贴明文密钥了。