使用指南
每一节回答一个「我想做什么」,可以单独读。第一次用 agentrun,先读快速开始。全部选项见运行。
选择运行时与模型
子命令决定运行时:agentrun claude-code、agentrun codex、agentrun pi、agentrun dsh。四个子命令接受同一组选项,换运行时只需要换子命令。
不写 --model 时,运行时用它自己的默认模型。要指定模型,用 --model,值原样交给运行时;推理强度用 --effort:
agentrun claude-code --model sonnet --effort high --prompt "..."
agentrun pi --model deepseek/deepseek-flash --prompt "..."
agentrun dsh --model deepseek-v4-pro --effort max --prompt "..."
dsh 的模型名直接写 DeepSeek 的模型,例如 deepseek-flash 或 deepseek-v4-pro;--effort 取 off、low、high、max。模型名写错时,dsh 在第一次请求模型时失败,detail 以 INVALID_REQUEST: 开头并列出可用的模型。
pi 的模型必须写成 服务商/模型。pi 找不到指定的模型时会改用别的模型继续运行,所以 agentrun 会在 pi 开始请求之前核对 pi 实际选中的模型,不一致就停止运行。只写模型名会直接报错:
传入提示词
三种方式,选一种:
agentrun claude-code --prompt "给 parse 模块补测试"
agentrun claude-code --prompt-file task.md
agentrun claude-code < task.md
长提示词放在文件里,避免 shell 的引号问题。同时给出两种方式,或者提示词为空,agentrun 都会报用法错误。
让 agent 看图片
需要模型看截图、设计稿或照片时,用 --image 把图片和提示词一起传入。有多张图片时重复这个选项,模型按你给出的顺序看到它们:
text 与 rich 格式在 prompt 一行的末尾写出图片的张数。图片可以放在任何你能读到的位置,不需要放进工作目录。在 jsonl 输出里,prompt 事件的 images 列出你给的路径,可以用来核对这次运行带了哪些图片:
{
"schema": 1,
"type": "prompt",
"time": "2026-10-19T03:14:26.078Z",
"text": "图里写的是什么?只回答图里的文字。",
"images": ["screenshot.png"]
}
只支持 PNG、JPEG、GIF 和 WebP,单个文件不超过 20 MiB。文件不存在、不是普通文件、类型不对(包括动画 PNG)或太大时,agentrun 报用法错误,运行时不会启动。用 pi 时要选支持图片输入的模型:模型不支持图片时 pi 不报错,模型看不到图片。dsh 不能传图片,给出 --image 时 agentrun 报用法错误 --image is not supported by dsh: its headless mode takes text only。传法的细节见图片。
让 agent 访问网络
默认情况下,agent 运行的命令不能联网。运行时自己访问模型服务不受影响。需要联网时有两种放开方式:
| 写法 | agent 的命令能访问 |
|---|---|
--network none(默认) | 不能联网 |
--network custom --allow-host HOST | 只能访问列出的主机,--allow-host 可以写多次,*.example.com 匹配所有子域名 |
--network full | 任何公网主机,并打开网页搜索 |
例如只允许访问 PyPI:
被拒绝的连接显示为 net denied 一行,括号里是原因。解析到内网地址的主机默认也会被拒绝,需要访问时把主机名原样写进 --allow-host。agentrun 不支持 IPv6。规则的细节见网络。
不让 agent 读某些文件
默认情况下,agent 读不到 ~/.ssh、~/.aws、~/.gnupg、~/.config/gh、~/.netrc、~/.kube、~/.docker/config.json、~/.config/gcloud、~/.azure,也读不到 claude-code、codex 与 pi 的登录文件(运行 pi 时 pi 自己的登录文件除外),以及 claude-code 与 codex 保存的会话记录(~/.claude/projects、~/.codex/sessions、~/.codex/history.jsonl)。还有别的文件不想让 agent 看到时,用 --deny-read 加上,可以写多次,文件和目录都可以:
agent 看到的目录是空的,文件读取报错,运行照常继续。这次运行的读取限制列表见 jsonl 输出里 start 事件的 deny_read,或者加 --dry-run 看 deny read: 一行。
agent 确实需要读默认列表里的某个路径时,加 --no-default-deny-read 去掉整个默认列表,再用 --deny-read 把其余路径加回来。--deny-read 不能写工作目录、临时目录(TMPDIR,没有设置时是 /tmp)或它们的上层目录,运行 pi 时也不能写 pi 的状态目录 ~/.pi/agent 与它的上层目录。路径里的 ~ 不展开,请写完整路径。运行 codex 时,路径里不能有 * ? [ ] { },codex 无法挡住这样的路径。
这项限制靠沙箱执行。沙箱没有运行时,只有 claude-code 的读文件与搜索工具仍然受限制,命令、codex 与 pi 都能读到这些文件,见读取限制。
传入环境变量与密钥
agent 默认继承你当前 shell 的环境变量,但会去掉可能改变登录方式的变量,例如 claude-code 的 ANTHROPIC_ 开头的变量。要给 agent 额外的变量,用 --env 或 --env-file:
agentrun pi --env GREETING --env-file dev.env --prompt "..."
--env NAME 取你当前环境里的同名变量,--env NAME=VALUE 直接给值。env 文件每行一个 NAME=VALUE,可以有注释行。agentrun 不会自动读取工作目录里的 .env,因为 agent 能改写这个目录。
用 --dry-run 确认哪些变量会传进去。输出里只有变量名,没有值:
写了 --env NAME,环境里却没有这个变量时,agentrun 会拒绝运行,避免你以为变量已经传进去了:
限制运行时间
用 --timeout 给出秒数。到时 agentrun 停止运行时和它启动的所有进程,结果是 timeout,退出码 3:
[end] 行的最后写出你给的时限。按 Ctrl-C 的效果相同:agentrun 先让运行时自己退出,5 秒后还没退出就强制结束,然后输出 [end] interrupted。agent 在后台启动的命令也会一起结束。
限制轮数与 token
当你担心 agent 反复调用模型、用掉过多的 token 时,给出上限。--max-turns N 限制主 agent 调用模型的次数,subagent 的调用不计入;--max-tokens N 限制所有模型调用(包括 subagent)的 token 数之和。超过上限时 agentrun 停止运行时和它启动的所有进程,结果是 limit,退出码 4:
[end] 行的最后写出是哪个上限、你给的值和实际的值。主 agent 开始第 3 次调用时 agentrun 停止了运行,所以最后一个 tool 是这次调用请求的命令,它可能没有执行,也可能已经开始执行;这里 claude-code 在停止时把它报告为出错,所以带 (error)。--max-tokens 的结果写成 --max-tokens 5000 exceeded: 7389 tokens。agent 在超过上限时已经完成任务并正常退出的,结果仍是 finished。给了 --session-dir 时,超过上限的运行同样保存会话,你可以用 --resume 接着运行,见接着上一次运行继续。
codex 只在运行结束时报告用量,agentrun 无法在运行中停止它,所以 codex 不接受这两个选项,给出时直接报错。dsh 的输出里没有 subagent 的用量,--max-tokens 只数主 agent 的 token;你需要严格限制 dsh 的 token 数时,同时给出 --no-subagents。两个上限的计数方法见轮数与 token 上限。
接着上一次运行继续
默认每次运行都是新会话。想在上一次运行的基础上继续,例如「测试还是没过,接着修」,第一次运行时用 --session-dir 指定一个保存会话的目录:
[end] 行最后的 session 是会话 id;jsonl 格式下它是 end 事件的 session_id 字段。下一次运行给出同一个 --session-dir 和 --resume <会话 id>,agent 记得上一次做过什么:
用 dsh 时,继续会话要用与第一次相同的 --cwd,换了工作目录时 dsh 报错,这次运行失败,见常见问题。
继续后会话 id 不变,可以一直用同一个 id 接着运行。会话记录按运行时分开保存在 ~/agent-sessions/claude-code/ 这样的子目录里,只能用同一个子命令继续。--session-dir 放在工作目录之外,否则 agent 能改写保存的会话;放在工作目录里时运行照常进行,沙箱开启时 text 与 rich 格式输出的第一行是 [note] --session-dir … is inside the working directory. The agent can change the saved sessions。不要同时用同一个 id 运行两次。保存的方式见保存与继续会话。
在 docker 与 Cloud Managed 容器里运行
Cloud Managed 容器
在 Cloud Managed 容器(例如 Claude Code 的云端环境)里,沙箱的用法与本机 Linux 相同。在环境的 setup 脚本里安装 bubblewrap 与 socat,命令与本机完全相同。
docker 容器
默认权限的 docker 容器不允许 agentrun 启动沙箱,这时由容器负责隔离。启动容器时设 AGENTRUN_SANDBOX=off,并把登录信息作为环境变量传进去:
docker run --rm \
-e AGENTRUN_SANDBOX=off \
-e CLAUDE_CODE_OAUTH_TOKEN \
-e AGENTRUN_CODEX_AUTH="$(cat ~/.codex/auth.json)" \
-e AGENTRUN_PI_AUTH="$(cat ~/.pi/agent/auth.json)" \
-e DEEPSEEK_API_KEY \
-v "$PWD":/work -w /work \
my-agent-image \
agentrun claude-code --prompt "给 greet.py 写一个测试并运行"
镜像里要装好 agentrun 和你用的运行时。登录变量按需要传:
| 运行时 | 环境变量 | 内容 |
|---|---|---|
| claude-code | CLAUDE_CODE_OAUTH_TOKEN | 在本机运行 claude setup-token 得到的令牌 |
| codex | AGENTRUN_CODEX_AUTH | ~/.codex/auth.json 的内容 |
| pi | AGENTRUN_PI_AUTH | ~/.pi/agent/auth.json 的内容;用 API key 的服务商也可以直接传 key 变量,例如 DEEPSEEK_API_KEY |
| dsh | DEEPSEEK_API_KEY | DeepSeek 的 API key。dsh 只用这个变量登录,不读 ~/.dsh/.env |
agentrun 把 AGENTRUN_CODEX_AUTH 与 AGENTRUN_PI_AUTH 写成运行时的登录文件,然后从 agent 的环境里删掉这两个变量,agent 读不到它们。
没有设 AGENTRUN_SANDBOX=off 时,你会看到:
沙箱关闭后,每次运行的输出第一行会提醒你这一点:
在脚本与 CI 里判断成败
只看退出码就能区分这几类情况:0 是完成,1 是 agent 没完成,2 是环境或命令有问题,3 是超过 --timeout,4 是超过 --max-turns 或 --max-tokens,130 与 143 是 agentrun 被 Ctrl-C 或 SIGTERM 中断。退出码 2 时原样重试不会成功,适合让 CI 直接失败并提示去修环境。完整的退出码表见快速开始与运行。
在 CI 里建议显式写 --format jsonl 和 --timeout,并在作业开始时对你用的运行时运行一次 agentrun doctor,例如 agentrun doctor claude-code,让环境问题在第一步就暴露出来。
三种情况不会让结果变成失败:agent 的某次工具调用被拒绝,某次工具调用执行出错(例如命令的退出码不为 0),以及某个 subagent 失败。agent 会看到这些结果并决定下一步。如果你的流程需要把它们当作失败,从事件流里查:
jq -c 'select(.type == "tool" and .denied)' run.jsonl
jq -c 'select(.type == "tool" and .error)' run.jsonl
jq -c 'select(.type == "subagent_end" and .status == "failed")' run.jsonl
例如列出执行出错的调用:
被拒绝的调用的 error 为 false,只由第一条命令查出。运行时没有报告调用结果时 error 为 null,第二条命令不会查出这样的调用。字段的完整说明见事件与输出。
要记录每次运行的花费,从 end 事件读 usage.cost_usd,单位是美元:
codex 与 dsh 不报告费用,cost_usd 为 null;claude-code 没完成一轮就被中断时也为 null。金额由运行时按单价表计算,用订阅登录时它不是实际扣费。按模型拆分的金额与各运行时的差别见费用。
同时运行多个 agent
需要几个 agent 同时处理不同的任务时,在后台启动多个 agentrun,每个用自己的 --cwd,输出写到各自的文件,再用 wait 等它们都结束:
每个运行有自己的临时目录、网络代理和 network 事件,结束或被中断时只停止自己启动的进程,所以每个日志可以单独按上一节的方法判断成败。运行时可以不同,例如一个用 claude-code、一个用 pi。
同时运行时注意三点:
- 给每个 agent 一个单独的
--cwd。几个 agent 用同一个目录时,agentrun 不协调它们的写入,同一个文件被几个 agent 改写时,结果取决于写入的先后。 - 每个 agent 的标准输出写到单独的文件。几个运行写到同一个文件或同一个管道时,各自的事件会交错在一起。
- codex 的几个运行共用你的同一个登录。令牌恰好在它们启动时过期,其中一个运行可能因刷新令牌失败而结束,报
refresh token was already used。这时另一个运行通常已经把新令牌写进你的登录文件,重新运行失败的那一个;仍然失败时重新登录。原因见多个运行同时进行。pi 的几个运行刷新令牌时共用同一把锁,没有这个问题。
查看 agent 做了什么
| 写法 | 用途 |
|---|---|
--format rich | 在终端里看运行过程。输出是终端时默认就是这种格式 |
--format text | 每个事件一行,适合写日志和用 grep 过滤,例如 grep '^\[explore#1\]' 取出一个 subagent 的全部行 |
--format jsonl | 给程序读。输出不是终端时默认就是这种格式。字段见事件与输出 |
--raw FILE | 同时把运行时的原始输出写进文件,用于和 agentrun 的事件对照 |
--dry-run | 只做启动前的检查,打印将要执行的命令,不启动运行时 |
--debug | 在标准错误打印实际执行的命令、环境变量与沙箱检查的结果,并保留这次运行的临时目录 |
这些输出都只写变量名,不写变量的值,也不写提示词。
在你的程序里显示正在执行的工具
你的程序读 --format jsonl,想在一次工具调用执行期间显示 agent 正在做什么时,读 tool_start 事件。agentrun 在一次工具调用开始时输出 tool_start,在调用结束时输出同 id 的 tool:
命令开始时就输出了 tool_start,3 秒后命令结束时才输出 tool。收到 tool_start 时,把它的 summary 显示为正在执行的工具;收到同 id 的 tool 时,这次调用结束。主 agent 与 subagent 的调用可以同时进行,用 id 对应开始与结束,用 parent 区分是哪个 agent 的调用。每个 tool_start 之后都会有同 id 的 tool,运行被中断或超时也一样,在 end 之前给出。
两个事件的字段见事件与输出。
agent 能做什么、不能做什么
| 沙箱开启时(默认) | |
|---|---|
| 读文件 | 读不到存放密钥与账号的常见路径、运行时的登录文件和会话记录,--deny-read 可以再加,见不让 agent 读某些文件 |
| 写文件 | 只能写工作目录(--cwd,默认是当前目录)和一个临时目录,运行结束后临时目录会被删除 |
| 联网 | 按 --network,默认不能联网 |
| 你的配置 | 不读取你自己的运行时设置、插件、规则文件与会话记录。不用 --resume 时每次运行都从干净的状态开始。用 --session-dir 时,claude-code 的新会话在运行期间出现在你的 ~/.claude/projects/ 里,运行结束后移到 --session-dir |
| 你的登录 | 使用你已有的登录,不改动你的登录文件 |
agent 想写工作目录之外的文件时,调用会被拒绝,并在输出里标出 (denied):
三种情况下这些限制会变化:
--sandbox relax:沙箱能启动就用,启动不了就不用沙箱照常运行。--sandbox off:不用沙箱,也不限制网络与读取,只有 claude-code 的读文件与搜索工具仍然读不到不可读列表里的路径。只在容器之类已经隔离的环境里用。--之后的参数会原样交给运行时,可以覆盖 agentrun 的权限设置。agentrun 不阻止,这时安全由你负责。
每种组合剩下的风险见沙箱与网络。
常见问题
启动前发现的问题,agentrun 输出 [end] rejected 加原因,并以退出码 2 结束;格式是 jsonl,或者标准输出与标准错误不都是终端时(例如输出写到文件),标准错误另有一行 agentrun: 开头的同一说明。先运行一次 agentrun doctor,多数问题会在对应的一行里写明。
sandbox is not available: bwrap cannot start
沙箱启动不了。在 docker 容器里,设 AGENTRUN_SANDBOX=off,见在 docker 与 Cloud Managed 容器里运行。在本机 Linux 上,确认装了 bubblewrap 与 socat;Ubuntu 23.10 及以后的版本还要给 bwrap 加一个 AppArmor profile,做法见这里。
claude not found in PATH
agentrun 在 PATH 里找不到运行时。确认运行时已经安装;它装在 PATH 之外时,用 --path 把它所在的目录加进来:
agentrun codex --path ~/tools/codex/bin --prompt "..."
requires >= X.Y.Z
doctor 找到的运行时版本低于 agentrun 要求的最低版本。executable 一行写出路径、找到的版本和要求的版本:
升级这个路径上的运行时,或者用 --path 指向新版本所在的目录。各运行时的最低版本见准备运行时的表。
not logged in. Run claude login
doctor 发现 claude-code 没有登录。在本机运行 claude login;在容器里传入 CLAUDE_CODE_OAUTH_TOKEN:
codex login file ... not found
codex 要求登录信息保存在文件里。在本机运行 codex login;在容器里用 AGENTRUN_CODEX_AUTH 传入 auth.json 的内容:
pi 用的模型和你想的不一样
pi 遇到拼错的模型名会照样运行,没有设置默认模型时还会改用环境里其他可用的服务商。doctor 的 login 一行会报出这两种情况:
改正模型名,或者在 pi 的设置里选好默认模型。
No API key found for anthropic
pi 没有所选服务商的 key。这是 pi 自己的报错,结果是 failed,退出码 1。给 pi 登录这个服务商,或者用 --env 传入它的 key 变量:
no saved claude-code session ... in ...
--resume 给出的会话在 --session-dir 里找不到。确认 --session-dir 与保存时相同,子命令与保存时的运行时相同,会话 id 没有抄错:
会话是用另一个子命令保存的时,说明的末尾写出保存它的运行时,换成那个子命令继续:
只写了 id 的一部分时报 --resume "76393ad0" is not a session id,从 [end] 行或 end 事件复制完整的 id。
DEEPSEEK_API_KEY is not set in the session environment
用 dsh 时,会话环境里没有 DeepSeek 的 API key。agentrun 只从环境变量取这个 key,写在 ~/.dsh/.env 或工作目录 .env 里的 key 不起作用:
先 export DEEPSEEK_API_KEY=...,或者写成 --env DEEPSEEK_API_KEY=...。key 无效时运行会启动,结果是 failed,detail 以 AUTH: 开头;agentrun doctor dsh 的 login 一行也会报出同样的原因。
failed to observe session ... corrupt session log
用 dsh 继续会话时换了 --cwd。dsh 只能在第一次运行的工作目录里继续一个会话:
回到第一次运行时的目录再继续,保存的会话不受这次失败的影响。
--env NAME: not set in the caller's environment
你写了 --env NAME,但当前环境里没有这个变量。先 export NAME=...,或者写成 --env NAME=VALUE。