mcpField
O
orcareplay

orcareplay

本地服务
github.com/Continuum-AI-Corp开发工具2874 周前更新

关于 orcareplay

OrcaReplay 是一个命令行工具,用于记录、离线重放和分叉编码 Agent 的运行过程。它通过本地代理捕获模型请求与工具调用,无需修改 Agent 本身,适合排查 Agent 出错原因的开发者。

主要功能

  1. 01记录编码 Agent 的完整运行过程
  2. 02离线精确重放,不调用模型、不消耗 token
  3. 03从指定步骤切换到其他模型继续运行
  4. 04对比不同模型在同一检查点上的结果
  5. 05生成运行过程的时间线与因果关系图

适用场景

  1. 01排查 Agent 误删文件等意外操作的原因
  2. 02在相同上下文下比较多个模型的表现与成本
  3. 03导出运行过程的图像用于问题报告

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"continuum-ai-corp-orcareplay": {
"command": "npx",
"args": [
"-y",
"orcareplay"
]
}
}
}
启动命令npx -y orcareplay

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmorcareplay0.5.0

工具

6

收录的工具列表 · 更新于 2 周前

此工具无需参数。

详细介绍

OrcaReplay

English · 简体中文 · 日本語 · 한국어 · Deutsch · Français · Español · العربية

你的 Agent 凌晨 2 点弄坏了东西。早上 9 点重放——精确、离线,想重放多少次都行。

记录任意编码 Agent。逐字节重现运行过程,无需调用模型。从任意步骤分叉到另一个模型,看看谁能做对。

OrcaRouter

由 OrcaRouter 背后的团队打造——用一个 API 密钥和一个端点接入 Claude、GPT、Gemini、Grok、DeepSeek、Qwen 等模型。orca setup 默认指向它,orca compare 也因此只需一条命令,而不是准备四个服务商账户。

找到我们:OrcaRouter 全部模型 API

GitHub 仓库:OrcaCode Review · OrcaRouter Lite

联系:X · Discord · Hugging Face · Ollama


许可证 规范 Node Agent 适合新手的问题 收录于 Awesome Claude Code

录制一次 Claude Code 运行,离线重放,然后分叉到两个模型

来自一次真实会话的输出——录制一次 Claude Code 运行,与录制内容进行重放,然后在检查点 4 分叉到两个模型,并通过 npx tsc --noEmit 进行评估。这里没有任何模拟内容。

三条命令即可试用

一个名为 orcareplay 的 npm 包,会在 PATH 上提供一个名为 orca 的命令。没有单独名为“orca”的工具,也不会向你的 Agent 安装任何东西。

npm i -g orcareplay             # the package is orcareplay; the command it installs is orca

orca record claude              # your agent, unmodified, doing whatever it does
orca replay last                # the same run again — no network, no tokens, no charge
orca replay last --from 4 --model claude-haiku-4-5 --ui

第三条命令是大家愿意继续用下去的原因:文件相同、对话前缀相同,从第 4 步开始使用不同模型。模型是唯一变量,因此结果才有意义。

上面的三条命令需要已安装的 Agent、密钥、网络连接和实际 Token。如果这些你都还没有,也可以用一条命令自带所需内容:

orca quickstart

它会生成一个带有真实 Bug 的小型项目,以及一段 Agent 修复该 Bug 的录制内容,然后在不调用模型的情况下对该项目重放录制内容:修复前有两个测试失败,修复后四个测试通过,三个轮次由追踪记录提供,全程零开销。--full 会打印完整时间线和重放过程。

查看 Agent 自己的系统提示词

能看到完整交互循环的代理,也能看到运行框架在发送任何内容之前组装好的提示词。一条命令即可捕获提示词、清除其中的机器信息,并按模型归档:

node capture/capture.mjs claude --model claude-opus-5

交互式提示词和 -p 提示词并不相同,而且不同模型使用的提示词也各不相同。请参阅 capture/README.md,了解实测差异、注意事项和脱敏规则。

为何要做这个项目

如今,调试 Agent 就像考古。你在终端里翻来翻去,重新运行却遇到不同的失败,还要往别人的测试框架里加打印语句。现有工具都是可观测性工具:它们告诉你一次运行花了 4.12 美元、用了 61k 个 token,但这不是你真正想问的问题。你想知道的是,它为什么删掉了我的迁移文件?

OrcaReplay 让你重现这次运行,从而回答这个问题。

可观测性工具OrcaReplay
告诉你一次运行花了多少钱✅✅
告诉你是哪个工具调用删除了文件有时✅
再次运行 Agent 并得到相同答案❌✅ 从录制内容重现,逐字节一致
让你更改模型并从第 4 步重新运行❌✅
需要你修改 Agent通常需要 SDK 封装❌ 两个环境变量
关闭终端后仍能使用❌✅ 它是一个文件
能看到模型 API 之外的内容——shell 退出代码、文件写入❌✅ 每一轮都能
能录制没有可重定向 API 端点的 Agent❌✅ 可选启用 --tls-intercept

最后两行涉及 SDK 封装在结构上无法触及的内容。捕获发生在 Agent 下方——位于进程和套接字边界——因此 Agent 是否属于你、你能否编辑它,甚至它是否持有 API 密钥,都无关紧要:使用 ChatGPT 订阅登录的 Codex CLI 会通过 TLS 连接自己的后端,并使用只有该后端接受的凭据,因此无法将其指向别处并保持为同一会话——而 orca 仍然可以录制它。请参阅测试框架无法重定向时。

工作原理

模型 API 是无状态的,因此 Agent 每一轮都会重新发送整个对话——包括上一轮的工具结果。因此,位于模型前面的代理可以看到整个循环:每个请求、每个流式响应、模型发出的每次工具调用,以及测试框架产生的每个工具结果。这个特性是该工具的基础,也正因如此,OrcaReplay 不会修补你的 Agent——它会启动本地代理、设置两个环境变量,然后不再干预。

“阻止外发”究竟是什么意思。 重放时,代理不会转发任何无法从跟踪记录中提供的内容,因此不会调用模型,也不会花费 token——运行结果会显示 egress=blocked。--loose 会有意解除这一限制:未匹配的请求会交由提供商响应,并记录为重大偏差,同一行会显示 egress=live-on-unmatched。重放仍会实际执行录制的工具调用;自行打开套接字的工具——例如运行 curl 的 shell 命令或获取内容的 MCP 服务——无论如何都不在保证范围内。默认情况下,这类请求不会经过代理,而是照常访问网络。使用 --tls-intercept 时则会经过代理,因为该选项会为整个子进程设置 HTTPS_PROXY:不在拦截列表中的主机会通过隧道原样转发,但其主机名、端口和字节数仍会记录到跟踪中;在列表中的主机则会像其他未匹配的调用一样被拒绝。重放不是沙箱;如果你需要沙箱,请在沙箱中运行它。

另外三层会捕获协议无法看到的内容:退出代码、实际耗时、字节来自哪个流,以及未经告知便写入的文件。对于完全不读取基础 URL 变量的 Agent,还有第五层——请参阅哪些 Agent。第六层会读取 Agent 自身对结构的描述,适用于具有这类描述的测试框架:哪个子 Agent 运行了、哪个子 Agent 向哪个移交了任务、是否触发了防护措施、哪个图节点产生了什么,以及其中哪些节点完全没有调用模型——这些信息都不会传到线上。

%%{init: {'theme':'neutral'}}%%
flowchart LR
    A["<b>your agent</b><br/><i>unmodified</i>"]

    subgraph orca["orca · six capture layers"]
        direction TB
        P["<b>proxy</b><br/>base-URL env var"]
        SH["<b>PATH shim</b><br/>exit code · timing · streams"]
        MC["<b>JSON-RPC tee</b><br/>MCP config rewrite"]
        FS["<b>shadow git index</b><br/>workspace per turn"]
        FH["<b>fetch hook</b><br/>for a hardcoded origin"]
    end

    A --> P & SH & MC & FS & FH
    P -->|"forwarded, auth intact"| U["<b>the model API</b><br/><i>or OrcaRouter · any gateway</i>"]
    orca ==> T[("<b>one trace</b><br/>.orca/runs/run_a1b2c3")]

所有内容都会进入同一条时间线,并按照实际发生的时间排序,而不是按照 orca 读取它们的时间排序。

精确重放、分叉和比较其实是一回事

它们不是三个子系统,而是同一个代理,只是带有一个游标——记录流中的一个位置,代理从这里开始停止读取磁盘上的内容,并转而从网络获取响应。

%%{init: {'theme':'neutral'}}%%
flowchart LR
    subgraph disk["from disk · byte-for-byte · network blocked"]
        direction LR
        T1["turn 1"] --> T2["turn 2"] --> T3["turn 3"] --> T4["turn 4"]
    end
    T4 ==> CUR{{"<b>cursor</b>"}}
    CUR ==> T5
    subgraph net["from the network · any model you name"]
        direction LR
        T5["turn 5"] --> T6["turn 6"] --> T7["…"]
    end
命令游标位置你会得到什么
orca replay last末尾整次运行重放一遍,阻止网络访问——不消耗令牌、不产生费用、没有差异
orca replay last --from 4 --model X检查点 4截止第 4 个检查点的轮次保持一致,之后由另一个模型接管
orca compare last --from 4 --models a,b多次位于检查点 4一张表格,一个变量——模型

检查点不是录制出来的,而是推导出来的——也就是对话前缀完整且工作区已创建快照的任意位置。因此,每次分叉都从一个可以证明曾经存在的状态开始。

一次 Bug 排查的真实过程

你的 Agent 本该修复一个失败的身份验证测试。它以 0 退出,但测试仍然失败。先看看它实际做了什么:

$ orca show last
run_6473f858b59e  [email protected]  14 events  exit 0

SEQ  KIND   WHAT                                            DETAIL
0    RUN    run started                                     generic-openai
1    SNAP   tree 919d32ba037537b43814c83779963b2cc3023db7   0 changed
2    MODEL  claude-opus-5                                   1 messages
3    MODEL  claude-opus-5                                   stop: tool_use · 100 in · 20 out
4    TOOL   edit_file                                       {"path":"auth.ts",…}
5    SNAP   tree c6af62b75c0c8b8938bd6087328b5148f3dcd534   1 changed
6    FILE   auth.ts                                         modified +1 −3
7    TOOL   edit_file                                       ok
8    MODEL  claude-opus-5                                   3 messages
9    MODEL  claude-opus-5                                   stop: end_turn · 101 in · 5 out
10   SNAP   tree c6af62b75c0c8b8938bd6087328b5148f3dcd534   0 changed
11   SHELL  ["sh","-c","node --check nonexistent-file.ts"]  /tmp/hunt
12   SHELL  shell result                                    exit 1 · 43ms
13   RUN    run ended                                       exit 0

info usage input=201 output=25 cost=$0.004890

模型自身的记录无法告诉你的三个事实,却被运行的退出代码掩盖了:文件确实发生了变化(seq 6,+1 −3),Agent 运行的检查失败了(seq 12,exit 1),但它还是结束了。运行以 0 退出,是因为 Agent 以 0 退出了。

最后这个事实值得用一条独立命令查看。orca show 会列出事件发生的顺序;orca graph 则会展示事件之间的因果关系:

$ orca graph last
FROM              TO               KIND      WHY
3 model.response  4 tool.call      recorded  tool_use block in the response
4 tool.call       6 fs.change      inferred  changed path appears in tool input, same or previous turn
4 tool.call       7 tool.result    recorded  tool result answers its call
7 tool.result     8 model.request  recorded  tool_result block in the request
11 shell.exec     12 shell.result  recorded  shell result answers its exec

  1 inferred — derived from this trace, not recorded in it

两种边,区别很重要。已记录边在运行时写入,因为 tool_use 块实际包含在发出它的响应中。推断边则是刚刚根据其命名的规则推导出来的——文件系统快照是每轮采集一次,而不是每次工具调用都采集,因此把文件变更归因于某个特定调用只是一个合理猜测,并非事实。推断边永远不会写回追踪记录,就像检查点是派生出来的、从不记录一样,因此第三方读取者信任的字段里永远不会包含 orca 编造的内容。

--graph-card 会以这种方式绘制整个运行——时间从左到右,事件类型从上到下,并将导致失败的因果链从其他事件中突出显示:

同一次运行的因果图:模型、工具和效果轨道贯穿三轮对话,其中通往失败检查的因果链高亮显示,推断出的连接以虚线表示

这种结构才是重点。一次运行就是一个反复出现的模式——请求、响应、调用、效果、结果——因此任何打破这一模式的地方都值得一看;而一个没有任何边从它出发的事件,是列表完全无法展示的缺失。

orca export last --card bug.svg 只绘制这条因果链,适合放进 Issue 或消息中:

一条因果链:模型响应、它发出的 bash 工具调用、Shell 命令及其 exit 1

主体并非手动指定——没有传入 --to。卡片会附带图例,因为如果虚线脱离追踪记录单独传播,就会把猜测包装成事实;卡片还会打印可复现问题的命令。

SVG 可以在 GitHub Issue 中渲染,但在其他重要场景几乎都不行——X 不接受它作为上传文件,Slack 和 Discord 也不会提供预览——因此将文件命名为 .png 就能生成 PNG,命名为 .gif 则会让因果链逐步呈现。这条路径需要浏览器,而 orca 并不依赖浏览器:docs/media/README.md 将渲染工具链排除在 package.json 之外,这样运行 npm ci 的人就不必下载 Chromium;绘图命令也不是重新引入它的理由。如果没有所需依赖却要求生成栅格图,orca 会提示解决方法;无论如何,orca doctor 都会报告依赖情况,而 .svg 永远不需要任何依赖。

orca export last --card bug.png       # the chain, ready to post
orca export last --card bug.gif       # the same chain, one hop per frame
npm i --no-save playwright-core pngjs gifenc   # only needed for the two above

现在,你可以随心所欲地免费复现它:

$ orca replay last
info replay.done reused=2/2 exact=2 divergences=0 unmatched=0 exit=0

无需网络、令牌,也没有波动。然后问问你真正想知道的问题——换一个模型能处理好吗?

$ orca compare last --from 5 --models claude-opus-5,claude-haiku-4-5 --verify "npm test"
MODEL             VERDICT  TOKENS  COST       WALL  RUN
claude-opus-5     pass     201/25  $0.004890  0.3s  run_1457b35062ba
claude-haiku-4-5  pass     201/25  $0.000326  0.3s  run_b8ee08479fb6

两者都通过了。其中一个成本低 15 倍。文件相同,对话前缀相同,检查点相同——唯一改变的是模型,也只有这样,这个数字才有意义。

时间线

orca replay last --ui(或 orca ui)会将此次运行作为一个独立的 HTML 文件打开——无需持续运行服务器,无需联网,也无需安装任何东西。你可以筛选、逐步查看,或按空格键,按照运行实际发生的节奏回放。

OrcaReplay 时间线:将一次包含 42 个事件的运行筛选为工具循环

每一层都会显示在同一条时间线上,因此你可以将此次运行视为一个完整的故事来阅读,而不是分成四部分:模型轮次及其令牌数量、每次工具调用及其参数和结果、带有退出代码和耗时的 shell 命令,以及产生的目录树和文件系统变更。

orca export last -o bug.html 会将该页面原样写入一个文件,你可以将它附加到问题中。它不包含任何外部引用——CI 会对此进行断言——因此即使从下载文件夹中打开、在飞机上或五年后,它也能正常显示。

相同任务,不同模型

orca compare 会从同一个检查点将一次记录的运行分叉到多个模型,并为它们提供相同的文件和对话前缀,再用你选择的命令为每个模型评分。模型是唯一的变量,这样比较结果才有意义。

比较表:两个模型从同一检查点分叉后均通过,并显示实际令牌数量和费用

orca compare last --from 4 \
  --models claude-sonnet-5,claude-haiku-4-5 \
  --verify "npm test" \
  --share verdict.svg          # the card above, ready to paste into an issue
指定多个模型

比较模型意味着要连接多个提供商,而手动操作就得知道 --upstream-anthropic 和 --upstream-openai 的存在、一个网关可以同时提供这两种线路格式,以及密钥应该填在哪里。这些都是真实存在的配置,却无从得知,因此我们提供了一个命令来询问:

$ orca setup
Gateway URL (serves the model APIs) [https://api.orcarouter.ai]:
  get a key at https://www.orcarouter.ai/console/token — OrcaRouter keys start sk-orca-
API key (stored 0600; leave blank for none):
  info config.saved path=~/.config/orca/config.json mode=0600 gateway=https://api.orcarouter.ai auth=stored

  6 models available:
    anthropic/claude-opus-5
    anthropic/claude-haiku-4-5
    openai/gpt-5.2
    ...

$ orca models
MODEL                      $/MTOK IN  $/MTOK OUT
anthropic/claude-opus-5    15         75
anthropic/claude-haiku-4-5 1          5
openai/gpt-5.2             1.25       10
some-local-model           —          —

orca setup 会询问网关实际提供哪些服务,而不仅仅是写入配置文件。因此,错误的 URL 或失效的密钥会立即得到反馈,而不是等到比较过程中才收到 401。它还会保存你选择的模型,因此之后运行 orca compare last --verify "npm test" 时,无需提供模型列表,也无需任何上游标志。orca models 会为它能识别的模型标出价格,对无法识别的模型则显示短横线,因为为未知模型捏造价格,会导致比较表列出一个根本不存在的费用。

OrcaRouter 是第一个问题的默认答案——按 Enter 键即可使用一个源站和一个密钥来调用 Claude、GPT、Gemini、Grok、DeepSeek、Qwen 等模型,这正是 orca compare 所需的配置形式。它的模型 ID 按提供商命名空间区分(anthropic/claude-sonnet-4.6、openai/gpt-4o-mini),orca 会处理这一格式:命名空间用于选择线路格式,并会在定价前去除。

它只是一个默认选项,而非唯一选择:你可以直接替换它,或传入 --gateway <url>;任何支持 OpenAI 兼容的 /v1/models 和 chat 端点的服务都同样适用,无论是其他托管网关,还是你自行运行的服务。

它也始终只会作为你主动要求发送流量时的默认选项。如果未配置网关,orca record 会代理 Agent 自己的调用,直接发往它原本使用的提供商,并使用 Agent 自己的密钥。Orca 不会擅自改变你未配置过的录制流向:否则按下录制按钮,就会作为副作用将你的源代码发送给第三方。

非交互模式:orca setup --key <k> 使用默认网关,orca setup --gateway <url> --key <k> 指定其他网关,而 --key-env <VAR> 则从环境变量读取密钥,而不是将凭据保存在磁盘上。

密钥绝不会进入追踪记录。它只会附加到出站请求中,而录制内容则由剥离了身份验证信息的传入请求生成——因此密钥在机制上就不会出现在录制内容中,无需依赖任何人记住某条规则。如果某个标志会将流量发送到签发密钥的网关以外的位置,则不会发送该密钥。

运行的另一半:orca push 和 orca pull

本地录制和网关录制看到的内容各不相同,而且都不能呈现完整情况。 orca record 在你的机器上运行,因此能看到 Shell、文件系统和 MCP——也就是副作用。 OrcaRouter 网关运行在线路上,因此能看到任何笔记本电脑都看不到的内容:每个密钥、每位同事、 每个 CI 任务,以及每次调用背后的路由决策。两者写入的都是同一种 orca-trace v0,因此 真正值得关注的方向从来不是二选一,而是在它们之间移动一次运行。

此前,这种往返操作需要通过浏览器下载和表单上传。现在只需三个命令:

$ orca list --remote  # what the gateway is holding
$ orca push [run]     # this machine  ->  the gateway
$ orca pull <run>     # the gateway   ->  this machine

orca push 将本地录制的运行发送到网关,随后 orca pull 将其拉取到另一个工作区,而 orca show 则读取拉取的副本

真实输出。此卡片由 scripts/render-sync-card.mjs 根据 docs/media/sync-transcript.txt 生成,该文件记录了一次实际往返操作——orca record,然后 push,再 pull 到 另一个 工作区,最后由 orca show 读取拉取的副本。没有任何一行是手动编写的。 这里的网关是一个本地存根,它提供相同的两个端点,因此地址是一个回环地址。

和其他所有接收运行作为参数的命令一样,push 默认处理最近一次运行。pull 则不会:对于 尚未见过该运行的机器来说,“最近一次”毫无意义,因此它需要一个 ID。

这就是 orca list --remote 的用途。你没有的 ID 不能作为默认值提供,而过去唯一能读取 ID 的地方 是浏览器中的控制台——因此需要 ID 的命令被困在终端无法打开的标签页里。--remote 会向网关提出 与 orca list 向当前目录提出的相同问题,通过 push 已经 POST 到的路径执行 GET:

$ orca list --remote --limit 3
RUN                           STARTED           SOURCE   APP             TURNS  TOOLS  LAYERS       MODELS                           OUTCOME
run_3d9e61a07b52              2026-09-21 09:36  upload   generic-openai  1      0      model,fs     m                                exit 0
run_8c14f2e9a07d3b6150e2c49a  2026-09-20 04:21  gateway  Unknown         1      0      model,route  deepseek/deepseek-v4-flash-free  end_turn
run_f07a5c2e91d4468bb3e0a17c  2026-09-20 02:02  gateway  curl            1      0      model,route  deepseek/deepseek-v4.1-flash     error

  orca pull <run>      # fetch one into this machine’s store

应看 LAYERS 列。 这正是本页两部分要讲的内容:model 和 route 来自网关,它能看到笔记本电脑看不到的路由决策;fs、shell、mcp 和 net 来自这里录制的运行。它会在你花费下载资源之前,告诉你运行中包含什么。SOURCE 列与它并列,因为运行的来源和运行包含的内容是两个不同的问题。

STARTED 是运行的第一个事件,并非网关存储该运行的时刻——对于 push 的运行,这两个时间相差 你等待后才执行 push 的时长。OUTCOME 是网关对其录制的运行给出的结果(end_turn、error), 对于从这里 push 的运行,则表示退出状态。网关未报告的信息会显示为 —,而非留空;较旧的部署 完全不发送时间戳,因此 STARTED 会保持未设置,而不是显示为 1970 年。--source gateway 将结果 限定为网关录制的内容;--source upload 则限定为 push 到网关的内容——这两个选项都可用, 如果拼错则会报错,而不会返回空列表;不加此选项时,两者都会显示。--limit 设置数量上限 (默认为 20)。--gateway 对 push 和 pull 仍然是原来的用途——可选地覆盖目标主机——而不是兼作 开关,因此已指定目标的命令无需再输入 URL。这三个选项都属于 --remote:不带它们时会报错, 而非忽略,因为如果 orca list --gateway <url> 返回当前目录中的运行,看起来就像是该主机返回的结果。

--json 也能提出相同的问题:orca list --remote --json 会将网关上的运行作为一个 JSON 文档输出到 stdout;当没人查看表格时,orca pull <run> 所需的 ID 就可以从这里获取。

所需条件

需要一个具有 replay 范围的密钥,可在 Console → API Keys → replay 中获取。该范围可以读取和推送 Sessions 运行记录,但不能中继,因此它不是换了个名目的模型流量凭证——replay 密钥会被中继路由直接拒绝。上传功能也默认按工作区关闭,可在 Settings → request logs 下启用;网关只记录、不接受上传是正常状态。

$ export ORCA_GATEWAY_URL=https://api.orcarouter.ai   # or your own gateway
$ read -rs ORCA_GATEWAY_KEY && export ORCA_GATEWAY_KEY   # not typed on the command line
$ orca push last

这两个导出变量都会在当前 shell 会话中持续有效,这正是上述规则的用意:在同一 shell 中稍后运行 orca push --gateway <somewhere-else> 会被拒绝,而不会悄悄使用你为自己的网关导出的密钥。

它不会做什么
  • 绝不会使用默认目标。 orca setup 可能会将 OrcaRouter 设为 模型 网关,因为代理 Agent 已经发起的调用并不构成信息披露。但运行记录不同:其中包含源代码、shell 输出和工作区快照,这些内容会以内容寻址 blob 的形式随记录一起传输。因此,push 没有默认主机。只有当你明确指定了网关时,它才算目标——通过 --gateway、ORCA_GATEWAY_URL,或在 orca setup 中输入的 URL;orca setup 在你按 Enter 时为你填写的那个地址不算,无论它处理你的模型流量有多出色。直接运行 orca setup,然后运行 orca push last 会被拒绝,并说明原因。push.packed 也会在发出请求之前报告文件数量和字节大小,而不是事后报告。
  • 绝不会发送工作区快照,除非你主动要求。 orca scrub 会重写 events.jsonl 和 blob,但无法重写 fs/ 下的影子 git 存储——其中的对象经过 deflate 压缩,并以其内容的哈希寻址,因此它会搜索这些对象,告知你其中仍有哪些内容,并提供 --drop-fs 选项。因此,push 默认会将 fs/ 留在本地:如果 scrub 报告“对象中仍有这些内容”,之后就不应再 push 并把它们一并发送。需要这些内容时,可使用 --fs 发送——例如队友需要基于该树复现问题的情况;发送完成时会明确告知,因为这是两端扫描都无法读取的唯一部分载荷(对象经过压缩,因此明文扫描看不到任何内容)。
  • 绝不会把密钥交给未为其配置的主机。 每个凭证都有归属主机——存储的密钥归 orca setup 设置的网关所有,导出的密钥归 ORCA_GATEWAY_URL 所指向的主机所有,而旁边没有 URL 的导出密钥则没有归属主机——只有当目标与归属主机匹配时,才会附带该密钥。--gateway 会更改运行记录的去向,而不会更改密钥的签发用途,因此将它指向其他地方会导致 push 被拒绝,而不是使用别人的凭证进行身份验证。唯一能通过的情况是:某个密钥的唯一目标就是本次调用所指定的目标;此前没有任何操作将它关联到某台主机,这正是 CI 的使用方式。
  • 绝不会匿名发送。 没有密钥时,不会尝试这三种操作中的任何一种。未经过身份验证的请求,恰恰是配置错误的公共端点会响应的内容;用一个 200 来得知你的运行记录去了无人负责的地方,或某个列表显示给你的内容其实从未限定为你所有,都不是好办法。
  • 绝不会进行不完整替换。 pull --force 会在旧副本旁写入新副本,再通过重命名进行切换,因此即使发生崩溃,任一时刻都至少保留一份完整运行记录;下次 pull 会完成切换,或回滚上次遗留的操作。--force 表示请求替换一份记录,并不意味着可以销毁它后再操作失败。
网关收到数据后会做什么

它会重新计算 events.jsonl 的完整性根,并拒绝根值与清单不匹配的推送——这就是为什么推送会发送磁盘上已有的字节,而不会进行任何转换。它还会扫描归档中的明文机密信息,发现后便拒绝接收。这正是 --force 的作用,也是 --force 采用可选启用的原因:默认行为可以防止密钥泄露到共享服务。

这里不会重新执行脱敏。TraceWriter 会让每个事件在写入磁盘前依次经过 溢写、脱敏、校验、追加,正是为了确保没有调用方能够绕过这一流程,因此推送读取的字节已经过脱敏;再次清理会改写完整性根所覆盖的字节,而这恰恰会导致归档无法推送。网关的扫描是第二道独立防线,并非重复第一道检查。

支持哪些 Agent

有两件事决定了能否记录某个测试框架:一是能否将其指向代理,二是数据到达后,orca 是否理解它所使用的线路格式。

Agent捕获方式状态
Claude CodeANTHROPIC_BASE_URL可用 — 已通过实际 Bug 修复验证,详细说明
Codex CLI(API 密钥)OPENAI_BASE_URL → Responses API可用
Codex CLI(ChatGPT 登录)--tls-intercept → Responses API可用,但需要做出选择
OpenAI Agents SDKOPENAI_BASE_URL → Responses API可用 — SDK 本身使用其默认的 Responses API,在 exact=1 下记录和回放,CI 中的测试;其自身的追踪是第二个出站请求,详见
Vercel AI SDK通过 @ai-sdk/openai 使用 OPENAI_BASE_URL(从 2.0.41 开始)— orca record generic-openai --;当源代码中编译了目标源站时,使用 fetch hook(orca record node --)可用 — 通过 generic-openai 使用可读取环境变量的 SDK 客户端,在 exact=1 下记录和回放,CI 中的测试;向编译在 Agent 源代码中的目标源站发送请求的 Agent,可在 exact=1 下记录和回放
grok-cli(及其 Telegram 机器人)orca record grok — GROK_BASE_URL,以及用于其子 Agent 的 hook可用
OpenClaworca record openclaw — 用于网关的 hook,以及供其启动的 Agent 继承的变量可用
opencodeorca record opencode适配器已发布,两个源站均已重定向
goose(Block)orca record goose — OPENAI_HOST 和 OPENAI_BASE_URL,ANTHROPIC_HOST → Responses API可用 — 已针对 goose 1.49.0 进行端到端测试,了解它有何不同
LangGraph / LangChainOPENAI_BASE_URL、ANTHROPIC_BASE_URL可用 — 一个包含两个节点、使用流式传输和工具的图,在 exact=2 下记录和回放,并可实时分叉,CI 中的测试;pip install orcareplay-langgraph 还会记录图 — 包括运行了哪个节点、在哪个 superstep 中运行,以及哪些节点没有调用模型
Haystackorca record generic-openai -- python your_pipeline.py — 其 OpenAIChatGenerator 会将 base_url 留给 OpenAI SDK 处理,而后者会读取 OPENAI_BASE_URL可用 — 包含 ChatPromptBuilder 和 OpenAIChatGenerator 的 Pipeline 在 exact=1 下记录和回放,CI 中的测试
OpenHandsorca record generic-openai -- python your_agent.py — 其 SDK 封装了 LiteLLM,并会读取 OPENAI_API_BASE可用 — SDK 自身的 LLM 层在 exact=1 下记录和回放,CI 中的测试
CrewAIorca record generic-openai -- python your_crew.py — 从 1.x 开始使用其自有 provider,并读取 OPENAI_API_BASE 和 OPENAI_BASE_URL可用 — 一个真实的 Agent、Task 和 Crew 在 exact=1 下记录和回放,CI 中的测试;了解 1.x 有何变化
Aiderorca record generic-openai -- python your_agent.py — 通过 LiteLLM 路由,后者会读取 OPENAI_API_BASE可用 — LiteLLM 层在 exact=1 下记录和回放,CI 中的测试
browser-useorca record generic-openai -- python your_task.py — 其 ChatOpenAI 会将未设置的 base_url 直接传递下去可用 — 在 exact=1 下记录和回放,CI 中的测试;仅限 LLM 层,不会驱动浏览器
Hermes(Nous Research)ORCA_BASE_URL_VARS=… orca record generic-openai -- hermes …应该可用 — 它会按 provider 覆盖设置;指定变量名
IndexRAGorca record indexrag -- --data-dir dataset/<name>/documents — 将整个流水线作为一次运行:聊天使用 OPENAI_BASE_URL,第二个源站使用 INDEXRAG_EMBEDDING_BASE_URL可用 — 已针对真实流水线进行端到端测试:索引、嵌入和回答均可离线回放,结果为 exact=11/11 retrieval=3/3;分叉时会保留记录的索引,了解流水线有何不同
RAG 流水线(LlamaIndex、GraphRAG、LightRAG)orca record generic-openai -- <cmd> — 嵌入和重排回放无需方言可用 — 并发构建索引并批量生成嵌入,在 exact=5 retrieval=2 下记录和回放,CI 中的测试
IDE 中的 Codexorca record exec --tls-intercept -- code .可用 — 扩展会启动 Agent,且 Agent 会继承捕获配置
源站硬编码的机器人orca record exec --tls-intercept -- <cmd>可用 — 一个向其自身源代码中 URL 发送请求的 Grok 机器人,详细说明
沙盒中或另一台机器上的 Agentorca attach可用 — orca 可访问,并会打印需要导出的内容,详细说明
其他任何情况orca record generic-openai -- <cmd>如果它读取 base URL 变量,则可用;如果不读取,则使用 orca record node -- <cmd>
Claude Code、Hermes 和 goose 都已使用真实运行器进行端到端测试,而且它们各自都导致了一些问题。Claude Code 导致了四个问题;Hermes 发现代理完全丢弃了一种流式交互;goose 又导致了两个问题,而且都不在适配器中——一个出在回放匹配器,另一个是运行器面对全是错误的跟踪记录,却报告成功。其余客户端均受适配器契约和测试夹具约束,夹具会记录每个客户端设置的确切变量,因此,如果运行器把它读取的变量改了,检查就会报红,而不是生成空跟踪记录。
读取不同变量的运行器

此表中其他符合 OpenAI 格式的客户端都会读取 OPENAI_BASE_URL。goose 也会读取它,但会优先读取 OPENAI_HOST;至于 Anthropic,它只读取 ANTHROPIC_HOST。

这种组合造成的问题比听起来更严重,因为两种情况都会静默失败:

  • 只设置 OPENAI_BASE_URL,在用户已经为其他用途导出 OPENAI_HOST 之前都能正常工作。此时用户自己的值会优先生效,运行会发往他们的目标地址,而 orca 则会在空跟踪记录上生成一份看似正常的录制。
  • ANTHROPIC_BASE_URL——generic-openai 设置的变量,也是生态系统中其他客户端读取的变量——在这里完全不起作用。仅通过它指定的接收端不会收到任何请求。

因此,适配器会将 OPENAI_HOST、OPENAI_BASE_URL 和 ANTHROPIC_HOST 全部设为同一个代理地址,测试夹具也会固定这三个变量。到达代理的流量使用 Responses API——启动时会发送 POST /v1/responses 和一个 GET /v1/models 请求——代理已有的 openai-responses 方言已覆盖此协议。

GOOSE_PROVIDER=openai GOOSE_MODEL=<model> orca record goose -- run -t "fix the failing test"

GOOSE_PROVIDER 和 GOOSE_MODEL 会原样传递,不会凭空设定:goose 对自定义端点没有默认值,替你选择会启动一个与直接运行 goose 不同的 Agent。

使用前有两项限制值得了解。goose 运行 shell 时不会经过 orca 的 PATH 垫片,因此,shell 工具调用会连同其输出一起记录,但不会记录真实退出代码、耗时或 stdout/stderr 分流——使用 --no-shell 录制,宁可不声明这些信息,也不要给出不准确的信息。此外,goose 会在对话进行过程中调用第二个模型来生成会话标题,因此,该调用会与第一个真实轮次发生竞争;回放匹配器可以处理两者以任意顺序到达的情况,而在 goose 成为第一个这样做的运行器之前,它还不支持这一点。

启动编码 Agent 的网关

OpenClaw 本身不负责编码:它会将 Claude Code、Codex 或 opencode 作为子进程运行,并通过聊天应用驱动它们,因此,一次运行会产生两类模型流量。网关自身的调用由 fetch 钩子捕获。编码 Agent 的调用则由常规变量捕获——并不是因为 OpenClaw 会读取这些变量,而是因为子进程会继承父进程的环境,所以它启动的 Claude Code 会看到 ANTHROPIC_BASE_URL,就像你亲自运行它时一样。

orca record openclaw

这种继承是操作系统的特性,而不是 orca 的特性。这类机制看起来显而易见,直到中间某一层清理了环境变量。因此,我们为此设置了一项测试:一个网关测试夹具,它自身不调用模型,而是启动一个会调用模型的 Agent,然后通过其孙进程的流量进行离线录制和回放。

什么也不读取的 Agent

如果 Bot 的源码里写死了 https://api.x.ai/v1,它就不会读取任何变量,因此也无从重定向。这也是人们编写的 Agent 中最常见的形式。可以在 Agent 下方、套接字处捕获它:

orca record exec --tls-intercept -- python bot.py
orca record exec --tls-intercept -- ./my-agent --task "fix the test"

exec(或 any)会启动你的命令,但不设置任何内容——既不设置源地址,也不设置凭据——因此 Bot 仍会与原本通信的对象通信,而 orca 会在途中读取对话。api.x.ai 在默认解密列表中,因此 Grok Bot 无需指定主机名。

只要 orca 启动的某个进程是它的祖先进程,同一条命令也能捕获一个并非由 orca 启动的 Agent。这就是 IDE 中的 Codex 这种形式:扩展会将 Agent 作为子进程启动,因此录制编辑器时,也会捕获其下方的 Agent。

orca record exec --tls-intercept -- code .
orca record exec --tls-intercept -- cursor .

重放时无需重复指定标志。通过拦截录制的运行会记录解密过的主机,orca replay 会读取这些记录并重新建立相同的策略——如果你不希望拦截 TLS,可使用 --no-tls-intercept。

若要解密默认列表未涵盖的端点,可将其添加进去,而不是替换整个列表:

orca record exec --tls-intercept --tls-hosts '+my-gateway.internal' -- ./my-agent

单独使用 --tls-hosts a,b 仍表示“只解密这些主机”,与以往一样。混用这两种形式时,程序会拒绝执行,而不是自行猜测。

不在这台机器上的 Agent

开发容器、VPS 或他人的 CI 中的 Agent 无法由 orca 启动,因此也无法为其构建环境。orca attach 会反过来操作:orca 保持代理运行,打印出可粘贴到远端的代码块,并持续记录收到的内容,直到你停止它。

orca attach --for claude
orca attach --for claude --bind 0.0.0.0 --advertise host.docker.internal
orca attach --tls-intercept          # for an agent over there that reads no variable either
info attached run=run_e3d64e15ee8f proxy=http://127.0.0.1:33437 for=claude-code

  # in the sandbox, before starting your agent:
  export ANTHROPIC_BASE_URL='http://127.0.0.1:33437'

  Recording. Press ctrl-C when the agent is done.

这些变量来自与 orca record 相同的适配器,因此沙箱录制不会与本地录制产生偏差。绑定到通配地址时必须指定 --advertise:0.0.0.0 表示监听地址,而不是任何设备都能连接的地址;orca 不会打印无法使用的 URL。

重放此类运行时也会遇到相反的问题——Agent 可能不存在于这台机器上——因此重放也支持 attach:

orca attach --replay <run>

它会在阻止出站连接的情况下提供录制内容,并直接从录制中获取测试框架。让同一个远程 Agent 指向它,即可离线再次运行,且不会调用任何模型。

orca 从未听说过的基础 URL 变量

要一一列举它们是不可能的。Hermes 会按提供商分别覆盖设置,其 .env.example 文件中就包含 NOVITA_BASE_URL、GLM_BASE_URL、KIMI_BASE_URL、MINIMAX_BASE_URL、HF_BASE_URL、NEBIUS_BASE_URL 等十多个变量。把变量列表写死在 orca 中,发布不到一周就会过时,因此只需指定变量名:

ORCA_BASE_URL_VARS='OPENROUTER_BASE_URL' orca record generic-openai -- hermes
ORCA_BASE_URL_VARS='GLM_BASE_URL,KIMI_BASE_URL' orca record generic-openai -- my-agent
ORCA_BASE_URL_VARS='SOMETHING_BASE_URL=/' orca record node -- node agent.mjs

每个变量都会指向追加了 /v1 的代理地址,这是 OpenAI 兼容覆盖设置所需的格式;=<path> 可覆盖该路径,而 =/ 则会使用不带路径的基础地址。

如果以这种方式录制 Agent 后运行正常,编写一个适配器只需大约 20 行代码——docs/plugins.md。如果运行不正常,最有用的内容就是跟踪记录:orca export last -o run.html。

当运行框架无法重定向时

基础 URL 注入可以捕获所有读取基础 URL 变量的运行框架,而 fetch 钩子则覆盖不读取该变量的 Node 运行框架。不过,使用 ChatGPT 订阅登录的 Codex CLI 两者都不适用——但原因并非本节先前所述。

它确实会读取提供方基础 URL,而显式指定的 URL 会覆盖 ChatGPT 后端;两条路径甚至使用相同的线协议。与该后端绑定的是凭据:已登录的订阅会携带 ChatGPT 后端接受、但 api.openai.com 不接受的套餐令牌。把 URL 指向别处,Codex 就会改为要求 API 密钥——你记录的不再是订阅会话,而是另一个会话。Codex 使用 Rust 编写,因此我们没有 fetch 可以触及其中任何一条路径。

--tls-intercept 可以解决这个问题;它被刻意设计为一项单独的选择,因为它会签发一个证书颁发机构。

orca record codex --tls-intercept
orca record codex --tls-intercept --tls-hosts 'api.openai.com,*.chatgpt.com'

该 CA 为每次运行单独生成,只通过子进程自身的环境信任它启动的 Agent,而不会加入系统或浏览器信任库;运行结束后即会删除。Orca 不会提出在任何地方安装它。允许列表以外的主机将通过隧道传输,不会被读取;记录内容仅包括地址和字节数,不含路径或正文,因为 orca 从未持有明文。若请求拦截所有内容,系统会拒绝,而不会照做。

经由它返回的内容并非日志行。被拦截的请求会像其他请求一样,按照相同的线协议方言进行解析,因此会作为普通交互写入跟踪记录——可离线重放,也可分叉到不同的模型;整个运行从未使用过你的 API 密钥。

orca replay --model、orca fork 和 orca compare 也适用,因为它们出于相同原因会启动实时 Agent。

面向 Agent、脚本或 CI

跟踪记录是一个文件,而这是可观测性仪表板无法做到的——因此,针对运行失败,最有用的问题是Agent可以提出的:*重放我上一次运行,并告诉我哪里出现了差异。*每条命令都以数据形式作答,而 orca 通过 MCP 提供自身服务。

$ orca replay last --json
{"runId":"run_a278eea7b535","mode":"exact","traceRunId":"run_687e3f84b208","matchedExact":2,"divergences":0,"unmatched":0,"liveCalls":0,"exitCode":0}

$ orca show last --json | jq '.events[] | select(.kind == "TOOL")'
$ orca checkpoints last --json | jq '.[-1].seq'

stdout 上只有一份 JSON 文档,诊断信息写入 stderr——包括记录中的 Agent 自身输出,因此即使运行正在输出内容,文档仍可解析。失败时也会以 JSON 作答,并返回非零退出码。--json 适用于 list、show、events、checkpoints、graph、record、replay、compare 和 doctor。

作为工具。orca mcp 会通过 stdio 向 Agent 提供跟踪记录存储:

{ "mcpServers": { "orca": { "command": "orca", "args": ["mcp"] } } }

orca_list_runs、orca_show_run、orca_checkpoints、orca_graph、orca_replay 和 orca_compare。重放免费且离线;orca_compare 会在自身描述中说明它会消耗实际令牌,因为选择工具的模型只会读取这段文字——同理,orca_graph 也会用描述说明 recorded 和 inferred 的含义。

在代码中,如果你更愿意不通过 Shell 调用:

import { Orca } from 'orcareplay';

const orca = new Orca({ cwd: process.cwd() });
const { unmatched, divergences } = await orca.replay('last');
const timeline = await orca.show('last');

它绝不会写入你的 stdout,也绝不会调用 process.exit——这两点都有断言保障,因为任何一项不满足的库都无法作为构建基础。

状态

早期阶段。v0 是上述三个命令的基础骨架。以下所有内容均通过了 1,393 项测试、跟踪格式一致性检查和插件 API 中立性检查,并在 Node 20 和 22 上完成验证。

能力状态
Trace 格式 v0 + JSON Schema可用
Anthropic / OpenAI 兼容模型捕获可用
OpenAI Responses API 捕获可用 — OpenAI Agents SDK 和 Codex CLI 默认使用的格式。可记录、离线重放和分叉;分叉会保留 Agent 使用的线上格式
不读取 base-URL 变量的 Agent可用 — orca record node -- <cmd> 会将 preload 写入运行目录,并为允许列表中的提供商主机重定向 globalThis.fetch。Node 和 Bun 均适用,因为 Bun 会忽略 NODE_OPTIONS 中的 --require。当源代码中编译了源站地址时,请使用此方式;遵循 OPENAI_BASE_URL 的常规 @ai-sdk/openai 客户端则使用 generic-openai
orca 无法读取的调用可用 — 会转发而非拒绝,并记录为 net.request / net.response:这是证据,而非可重放的轮次。若录制未捕获任何内容,会发出警告,而不是正常退出
机器可读输出(--json)可用 — stdout 输出一份 JSON 文档,stderr 输出诊断信息,失败时输出 JSON
因果图(orca graph)可用 — 以表格或 JSON 展示因果关系。每条边都会说明是 trace 记录的,还是 orca 此刻推导出的,并在两种情况下都注明规则。--to N 可缩小范围,仅显示产生某个事件的链
可分享卡片可用 — orca export --card 绘制一条因果链,--graph-card 绘制整个运行并突出显示该链,compare --share 绘制判定表。始终支持 .svg;安装可选渲染工具链后也支持 .png 和 .gif。orca doctor 会报告该工具链,且 npm ci 绝不会安装它
首次运行,无需 Agent(orca quickstart)可用 — 包中附带真实录制内容及其对应的项目,并离线重放该录制内容,因此初次体验无需密钥、网络或令牌
MCP 服务(orca mcp)可用 — 通过 stdio 提供六种工具,让 Agent 能读取、解释和重放自己的运行记录
程序化 API(Orca)可用 — 命令会呈现其返回的内容,因此终端只是单一事实来源的一个视图
重放手动输入的会话可用,但只是近似重放 — 具体含义
带偏差报告的精确重放可用 — 将录制时的文件系统还原到工作树,然后恢复原状;使用 --worktree 可创建临时副本,使用 --in-place 则不进行还原。会单独生成一份运行记录,记录重放发现的内容 — 偏差、未匹配的请求;对于仅仅重复的内容,则指向父运行记录;使用 --no-trace 可跳过
从检查点分叉重放可用 — 分叉会记录自己的文件系统快照,因此分叉后的运行也可以再次分叉
跨模型比较可用 — orca setup 会保存网关(默认使用 OrcaRouter,也可以指定任意 URL)、密钥和模型列表,因此 orca compare 无需任何标志
文件系统快照和差异可用
单文件 HTML 导出可用
MCP 调用录制可用 — 使用 --mcp-config <path> 启用。重放和分叉会根据录制时使用的配置重新插桩,因此该层不会在分叉点终止
事后脱敏(orca scrub)可用
Shell 捕获(PATH shim)可用 — 捕获退出码、持续时间以及 stdout/stderr 的拆分。使用 --no-shell 可跳过
非模型网络捕获可用 — 使用 --tls-intercept 启用;为每次运行签发仅由被启动的 Agent 信任的 CA,解密允许列表中的主机,对其余流量进行不可读隧道转发,并在运行结束时删除密钥
Codex 订阅模型捕获/重放可用 — 可识别 /backend-api/codex/responses HTTPS 回退接口,解码 zstd 请求体以进行匹配,并在重放期间提供录制的 SSE 响应,而不连接源站
已通过真实 Agent 验证使用 Claude Code 录制了针对真实错误的真实修复:完成录制、端到端离线重放、从检查点分叉并导出。它暴露出四个测试夹具无法触发的问题,这些问题现已全部修复 — 真实 Agent 发现的问题
订阅认证测试环境Claude Code 可用。使用 ChatGPT 订阅登录的 Codex CLI 会携带只有其自身后端接受的套餐凭据,因此重定向 URL 会录制另一段会话,而非原会话:需要使用 --tls-intercept。使用 API 密钥则无需特殊处理

回放手动输入的会话

以 orca record claude 启动并手动操作的运行,其提示词不会出现在传输内容中。Orca 会从宿主程序自身的转录记录中恢复提示词,并通过在没有终端的情况下重新传入这些提示词来回放会话——这会重现对话,但不会逐字节重现运行。两处差异是固有的,并非缺陷;Orca 会明确说明这两处差异,而不是掩盖它们:

  • 宿主程序会自行发起调用。 首轮之前的配额探测、为会话命名的请求、为子 Agent 新编写的委派提示词。回放不会重复这些调用。匹配器会跳过它们,继续寻找下一个真正的匹配项,并报告数量。因此,交互式录制中显示 reused=3/5,表示你要求的内容已完整回放,而不是只回放了一部分。
  • 终端会话可以使用回放无法提供的工具。 AskUserQuestion、EnterPlanMode、ExitPlanMode、EndConversation 都需要有人在场,因此在没有人参与的情况下驱动同一个 Agent 时,这些工具不会出现。它们的 schema 很大,因此携带这些工具的请求可能与录制的请求相差甚远,以至于回放中止;中止信息会说明缺少哪些工具,以及原因。

通过 argv 传入提示词进行录制——orca record claude -- -p "…"——不会遇到这两个问题,因为回放启动方式与录制时完全相同。若要精确回放某次运行,请使用这种方式。无论采用哪种方式,查看运行记录都不受影响:orca show 和查看器都能完整呈现两种运行。

安装

npm i -g orcareplay
orca doctor                       # checks node, git, and which agents it can find

需要 Node 20 或更高版本。没有原生依赖,因此无需编译,也不会在安装时下载除 tarball 本身之外的内容。

从 0.1.1 开始发布的每个版本,均由 RELEASING.md 中带标签的工作流发布,并附有注明构建版本所用提交和运行的来源证明——npm 会在软件包页面上显示该证明,npm audit signatures 可对其进行验证。

从源代码安装,用于开发或运行尚未发布的提交:

git clone https://github.com/Continuum-AI-Corp/OrcaReplay && cd OrcaReplay
npm ci && npm run build
npm install -g ./packages/cli     # puts `orca` (and `orcareplay`) on PATH

在仓库根目录运行 npm install -g . 不会安装任何内容:根目录是一个工作区,本身没有可执行文件,而 orca 位于 packages/cli 中。

运行需要 Node 20+(CLI 自身的 engines 声明为 >=20.0.0)。贡献代码需要 ^20.19.0 || >=22.12.0,因为测试工具链需要此版本;根目录的 package.json 会单独声明这一要求,因此 npm ci 会提前告知你。无需账户、注册或更改 API 密钥。

在 Windows 上,shell 捕获会在 sh.exe 和 bash.exe 前写入 .cmd 垫片(Git for Windows 会提供这两个程序),而 Windows 只能通过 shell 运行 .cmd。因此,它能捕获通过 cmd.exe 或 PowerShell 启动的 shell,但无法捕获 Agent 自行启动的 shell:Node 宿主程序的 child_process.spawn('bash') 会直接调用真正的 bash.exe,而 Claude Code 无需查询 PATH 就能找到自己的 shell。orca doctor 会说明此机器上属于哪种情况;如果某次运行的工具调用执行了垫片未捕获到的命令,orca record 就会发出 shell.ineffective 警告——请使用 --no-shell 录制这些运行。如果 PATH 中没有 POSIX shell,doctor 会发出警告,此时应使用 --no-shell 进行录制。

运行记录的保存位置

所有内容都会写入录制时所在项目中的 .orca/runs/——按项目分别保存,绝不会存入全局目录,因此运行记录会与所属的检出副本一起移动。每个运行目录都是一个可自我说明的整体:

.orca/
  .gitignore          # just `*` — the store excludes itself, so a trace cannot be committed by accident
  runs/run_d0a2ee7ce615/
    manifest.json     # who, when, which adapter, the git commit, counts, integrity digest
    events.jsonl      # the timeline, one JSON object per line, append-only
    blobs/            # content-addressed payloads over 4 KB, deduplicated
    fs/               # shadow git index: the workspace at every turn
    shims/            # the PATH shims this run used; written by orca, read by nothing
    py/               # bootstrap for the agent-structure layer, when the agent is Python
    redactions.json   # what was removed, by rule and count — never by value

查找旧会话:

orca list                       # every run here, newest first, with what it was forked from
orca list --remote              # and what the gateway is holding, without opening a browser
orca show run_d0a2ee7ce615      # the timeline in the terminal
orca replay last                # `last` = newest recording (it skips replay traces)
orca replay run_d0a2ee7ce615    # or name one outright
orca gc --older-than 7d --dry-run   # what would be reclaimed, before anything is

orca list 会直接读取运行目录,因此也适用于别人发给你的跟踪记录:将其放入 .orca/runs/,所有命令都能看到它。没有任何索引,也没有数据库可供损坏。--remote 是唯一例外,但它也不是索引:它会请求网关并打印响应,不会保存任何内容。

隐私

追踪记录保存在本地,权限为 0600,记录器本身不会建立网络连接。写入时会对机密信息进行脱敏:环境变量捕获默认采用拒绝策略,不会写入身份验证标头,已知的密钥格式和高熵字符串会替换为稳定的占位符。

脱敏只能尽力降低风险,并非保证。请将追踪记录视为敏感信息——其敏感程度大致相当于 Shell 历史记录加堆转储。

orca export last -o bug.html          # prints exactly what it is about to write
orca scrub last --match my-hostname   # remove something after the fact

orca scrub 会重写 events.jsonl、清单和每个文本数据块,重新运行标准检测器,刷新完整性摘要,并保持二进制数据块的字节内容不变。

它无法重写文件系统快照。Git 对象以自身内容的哈希寻址,因此编辑对象会改变其 ID,进而迫使所有引用它的树都重写,以及之后所有引用这些树的事件也都重写——这相当于改写历史,一旦失败,运行记录将无法再恢复。因此,scrub 会搜索快照存储,并在其中仍包含你的字符串时告知你,而不是谎称它已清理干净。--drop-fs 会直接删除存储,但代价是无法再分叉此运行记录。

哪些内容开源,哪些不开放

以下内容始终以 Apache-2.0 许可证开源:追踪格式、核心、CLI、查看器、适配器和提供方接口。

OrcaReplay 由构建 OrcaRouter 的团队开发,这一点体现在两处,都是你要求的内容。未指定网关时,orca setup 会推荐它——这是一个你可以查看并覆盖的默认选项,只有在你选择回答的问题中才会出现,不会自行决定任何请求的路由。你明确生成的内容——例如导出文件或 --share 卡片——也会标注“由 OrcaRouter.ai 团队构建”,就像图表会注明其来源一样。

每条模型路径都是一个普通 URL,你可以将其指向任何位置;代码中没有任何路径会区别对待该来源;署名也不会将任何内容路由到任何地方。

供应商不会获得特权。插件——包括 OrcaRouter 的插件——只能使用 @orcareplay/plugin-api 中公开的 Provider 接口,不能使用任何私有 API。目前还没有供应商插件,因此负责执行此规则的 CI 任务(scripts/check-neutrality.mjs)会如实报告这一点,并以空操作通过;一旦有插件加入,它就会开始基于已发布的程序包构建,而不是基于工作区源码。如果某个插件需要某项能力,该能力必须先加入公开接口,并提供第二种实现,以证明接口并非围绕某一家供应商设计。

文档

如果你现在就遇到了问题,请从这里开始:

参考资料:

欢迎贡献

格式处于 v0 阶段,最小可运行骨架已经完成——这是项目发展过程中很有意思的阶段: 此时调整决策的成本仍然很低,而且已经列出了许多显而易见、可以着手处理的文件任务。

  • 十二个适合新手的优先事项,每项都注明了文件和测试。
  • 编写一个适配器。 一个文件,一个 fixture。如果你的测试框架读取 base-URL 变量,大约只需二十行——docs/plugins.md。如果不读取,node 可能已经能满足需求;如果某个未列在上文的测试框架生成的录制内容为空,无论哪种情况,都值得提交一个 issue。
  • 在集成检查中添加一个框架。 test/integrations/ 会针对 stub origin 运行一个真实框架,关闭 origin 后再重放。当前覆盖了八个;AutoGen、LlamaIndex、Pydantic AI 和 smolagents 尚未覆盖。新增一个框架只需编写一个脚本并添加一行记录。
  • 重新实现读取器。 规范采用 CC BY 4.0 许可是有意为之。Python 读取器已经存在;Go 和 Rust 版本欢迎贡献。
  • 找出重放的问题。 匹配阶梯是此项目的核心;改进它最快的方法,就是提供一份能让它出错的真实录制内容。提交 issue 时附上 orca export last -o bug.html 的结果——这是一个独立文件,你可以先用 orca scrub 处理其中需要清理的内容。

如果它为你省下了一个下午,点个 ⭐ 能帮助更多人找到它。

许可证

代码采用 Apache-2.0 许可。轨迹规范采用 CC BY 4.0 许可,因此任何人都可以重新实现。


OrcaReplay 由 OrcaRouter 团队打造 · orcarouter.ai · 所有模型 · OrcaCode Review · X · Hugging Face

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。