关于 oars
oars 是面向编码 Agent 用户的本地会话记录与检索工具,可跨多种编码环境保存会话,并按错误、路径或上下文查找以往经验。会话回忆在本地进行,不调用模型;项目还提供会话统计卡片和可选的远程存储功能。
主要功能
- 01采集多种编码环境的会话
- 02按错误、路径和上下文检索
- 03本地保存会话记录
- 04生成周、月、年统计卡片
- 05可配置采集范围与遥测
适用场景
- 01重现错误前查找以往会话记录
- 02查看某仓库中反复出现的问题
- 03汇总不同编码环境的使用情况
- 04限制会话采集的项目或来源
MCP 相关
README 提到 MCP 工具会将检索文本加入正在运行的会话,但未说明服务暴露的具体工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
@manyoars/oars
oars 会在本地保存可搜索的编码 Agent 会话记录,涵盖 Claude Code、Cursor、Codex 和其他运行环境。询问它某个错误,它就会显示过去有多少个会话遇到过该错误、发生时间,以及之后使用了哪些工具。更多信息请访问 manyoars.com。
安装
npm install --global @manyoars/oars
需要 Node 22.23.4 或更高版本。仅支持 ESM。本地回忆功能无需账户。
也可以不安装,直接运行一次:
npx @manyoars/oars sessions try
示例输出(来自 oars sessions try 的虚构会话):
$ oars sessions recall --error "unexpected EOF while looking for matching quote"
Bash | bash: -c: line <n>: unexpected EOF while looking for matching quote
3 sessions, 3 errors, first 2026-10-06T10:00:15.000Z, last 2026-10-20T10:00:27.000Z
harness 2.1.300; followed by Bash x2, Read x1, Write x1; an edit followed 1 times
$ oars sessions recall --context --cwd C:\work\demo
oars recall: errors that recur in this repository's earlier sessions. Check these before retrying:
- Bash | bash: -c: line <n>: unexpected EOF while looking for matching quote (3 sessions in the last 300; next: Bash, Read, Write)
- Write | File has not been read yet. Read it first before writing to it. (2 sessions in the last 300; next: Read, Bash, Write)
还没有编码 Agent 历史记录?oars sessions try 会在临时文件夹下的临时存储中,使用虚构会话运行回忆、书籍和钩子行示例,并标记为合成数据,在退出时删除,绝不会接触你自己的存储。
命令
oars --help 会列出以下命令(oars help <command> 会显示某个命令的标志)。oars --version 会打印版本号。
以下标志适用于所有命令:
--json会在标准输出中打印一个 JSON 文档,而不是文本(见下文)。--api-url <url>设置平台 API。默认值为OARS_API_URL,否则为https://api.manyoars.com。--idempotency-key <key>指定幂等键的基础值(默认值:新生成的 UUID)。使用相同的键重试失败的命令即可重放该命令。
login
通过浏览器登录(RFC 8628 设备流程)并保存登录状态。
账户尚未开放:oars login 默认使用 Many Oars 颁发者,在 Many Oars 登录服务 login.manyoars.com 部署之前,命令会以错误退出,退出码为 2,并提示 login.manyoars.com。
--no-browser会打印链接和代码,但不打开浏览器。--issuer-url <url>是 Keycloak realm URL。默认值为OARS_ISSUER_URL。两者都未设置时,login会使用内置的 Many Oars 颁发者https://login.manyoars.com/realms/aor;无需事先启用任何内容。当内置颁发者无法响应发现请求时(可能尚未部署),如果未指定--issuer-url或OARS_ISSUER_URL,命令会打印“无法连接到 Many Oars 登录服务 login.manyoars.com(可能尚未部署)。传入 --issuer-url 或设置 OARS_ISSUER_URL 以使用其他颁发者。”并以退出码 2 退出。
logout
撤销并删除已保存的登录状态。
keys
oars keys 用于管理账户的 API 密钥。
oars keys create --name <name>会创建密钥并仅显示一次密钥密文;平台不会保留副本。默认权限为AGENT_OPERATE和AGENT_READ;--authority <name>(可重复指定)用于设置其他权限,--expires-in-days <n>用于设置过期时间。--expires-in-days的取值为 1 到 365;不指定时,由平台设置过期时间,oars keys list会显示该时间。请在密钥过期前更换。--workload <id>会将密钥限制为你创建的某个工作负载。此类密钥只能具有AGENT_OPERATE和AGENT_READ权限(更多权限会导致 400 错误API_KEY_WORKLOAD_SCOPE_EXCEEDS_CAP),且只能用于该工作负载。- 使用相同的
--idempotency-key重试时不会返回密钥密文:命令会以退出码 5 退出并提示密钥名称;你需要撤销该密钥并创建另一个。 - 创建或撤销密钥需要已登录的用户。如果设置了
OARS_API_KEY,任何 API 密钥都会收到 403 错误HUMAN_SESSION_REQUIRED(退出码 3);重新登录也无济于事:请取消设置该变量,并使用oars login会话。 oars keys list会列出密钥及其前缀、范围和过期时间。密钥密文不会再次显示。oars keys revoke <keyId>会立即停用密钥。没有rotate命令:请撤销密钥并创建另一个。
遥测
- 默认开启:每条命令都会在
<config>/oars/telemetry/下的本地暂存区留下一条事件,记录计数、大小和封闭词。它绝不会保存会话内容、提示词文本、文件路径、URL 或参数。 - oars 会批量发送事件,每天最多一次:如果你设置了
OARS_POOL_URL,则发送到该变量指定的池服务器;否则发送到 Many Oars 池(https://pool.manyoars.com),该服务目前已上线。每条事件都包含一个每次安装随机生成的 ID。如果机器的时区位于欧盟、欧洲经济区或英国,遥测会关闭,且不会提示你;任何开关都无法覆盖此设置。在其他地区,Many Oars Co. 可能会按照首次运行时的通知,对 Usage Data(即 oars 发送的事件)进行许可。 oars telemetry status会说明遥测是否开启以及原因;oars telemetry show会按存储内容打印暂存区;oars telemetry report会根据暂存区打印你自己的统计数据。oars telemetry off会停止记录和发送;oars telemetry on会恢复记录和发送。OARS_TELEMETRY=0或DO_NOT_TRACK=1会为当前进程关闭遥测,且优先于on。- 所有事件类型和字段,以及示例,均列于 docs/telemetry.md。
卡片
oars card --text # your week as a table, sized for a screenshot
oars card --month # the last 30 days as a picture: oars-card-month.png and .svg in this folder
oars card --year --out me.png # the last 365 days, saved as me.png and me.svg
oars card 会根据本地会话存储中的数据,为你自己生成一张可分享的卡片,涵盖所有 harness;默认统计最近一周(7 天),也可以统计一个月或一年。卡片会显示你的会话数和活跃天数、用过的 harness 和模型、按模型统计的令牌数、工具调用数、失败调用数及其中有多少次之后采取了不同的下一步操作、编辑经过验证的频率、提交数及其中有多少得以保留;仅当 harness 记录了费用时,才会显示费用。若计数低于 oars sessions books 使用的同一阈值,则会显示 too few。存款者这一行在你登录前显示 ashore: run oars pool login;登录后,则根据本地已发送记录显示这台机器发送过存款的周数,并注明这是这台机器的数据。
每周从周五起,你在终端运行的第一条命令会向 stderr 打印一行:Your week: N sessions, M strokes. \oars card --text` for the table.。但以下情况不会打印:使用 --json、通过钩子运行、通过 MCP 服务运行、通过 recall 运行、运行 oars sessions try,或运行 oars card本身;且仅当本周有会话时才会打印。约十分之一的安装永远不会看到这行;会话存储文件夹中的card-line.json会记录该周以及状态是shown、held还是not_due;card-line-id` 保存用于计算保留组哈希的 ID:若有遥测安装 ID,则从中复制一次,否则随机生成,因此分组不会改变。
不会上传任何内容,也不会向任何地方发送任何内容:该命令不会发起网络调用,只会打印一个预填好的 x.com 链接,链接文本是卡片自己的统计数据,你可以自行决定是否发布。卡片不会包含文件夹名称、路径、提示词或响应文本、仓库名称,也不会包含长尾工具或模型名称;发布卡片不会解锁任何内容。图片是字节稳定的 SVG,以及用内置字体从 SVG 绘制的 PNG;--text 会打印表格,且不会写入任何内容。--no-cost 会从图片、表格和 --json 中移除费用行。
会话
oars sessions 会在本地保存你自己的编码 Agent 会话的确定性记忆。会话命令不会调用模型或网络,但 gold arms 除外:它会通过你自己的 Claude 订阅发送已脱敏文本。oars 还会记录遥测事件(命令的路径、标志名称、耗时、退出代码和错误类别,以及随机安装 ID、oars 版本、操作系统和时间;绝不会记录会话内容、提示词、路径、URL 或参数值),并批量发送到 OARS_POOL_URL 中指定的池服务器;若未设置,则发送到 Many Oars 池(目前已上线)(遥测记录的内容及关闭方式)。
它会捕获什么:默认情况下,会捕获每个 Claude Code 项目文件夹的会话,以及 Cursor、Codex、Copilot CLI、Gemini CLI、Grok Build、OpenCode、Pi 和 VS Code Copilot Chat 的会话;如果存在 OpenTelemetry GenAI Agent 跟踪(OTLP JSON 文件),也会从 OARS_OTEL_TRACES 指定的文件夹(否则为 <config>/oars/otel-traces)捕获。--allow 会将范围缩小到你指定的文件夹和存储(--allow cursor、codex、copilot、gemini、grok、opencode、pi、vscode-copilot、otel 分别指定这些存储),而 --deny 可排除其中一项。存储位置:你设备上的 <config>/oars/sessions/(Windows 上的 <config> 是 %APPDATA%,其他系统上则是 $XDG_CONFIG_HOME 或 ~/.config)。其中的 raw/ 文件夹默认启用,用于保存原始记录(每份存入的记录都会以硬链接或副本形式保存)。密钥遮蔽仅应用于日志,不应用于 raw/:这些文件未经脱敏,会保留记录中的所有内容,包括密钥。它们会留在你的设备上:除了 gold arms 外,没有任何会话命令会上传它们,遥测也不会携带其中的内容;在你对原始记录提示选择是(oars pool raw)并接受公约后,发送器会上传每份记录的脱敏副本(绝不上传文件本身),但设为仅骨架或关闭的文件夹除外。要移除它们,请参阅移除所有内容。
替你存入记录的设备(云环境、VPS、CI 运行器)有自己的仅用于存入记录的密钥,该密钥在你的设备上登记和撤销。运行 oars pool enroll --host-class <vps|cloud|ci> --launcher <interactive|orchestrated|scheduled> --name <label> --allow-repos <owner/name,...> [--days <n>](需先运行 oars pool login)时,命令会拒绝任何无法确认是私有的存储库(需要 GH_TOKEN 或 GITHUB_TOKEN),随后会打印一次性登记令牌(需在 24 小时内激活)以及该设备读取的环境变量块;令牌仅由存储池提供,因此请将其作为环境密钥保存,而不要放进存储库。oars pool machines 会列出你的设备,以及每台设备最近一次存入记录的日期和到期时间;oars pool machines revoke <id> 会撤销指定设备。--hold-only 会在不提供存储池凭据和令牌的情况下打印变量块,并设置 OARS_HOLD_ONLY=1。请参阅 docs/pool.md。
除此之外,以及遥测(默认开启,可通过 oars telemetry off、OARS_TELEMETRY=0 或 DO_NOT_TRACK=1 关闭;遥测会发送到 OARS_POOL_URL 指定的存储池服务,否则发送到已上线的 Many Oars 存储池 pool.manyoars.com),oars 本身不会发送任何内容,除非你选择启用了存储池服务:接受其公约后,会话结束钩子或任何 oars 命令启动的分离式发送器每小时最多发送一次封闭词汇表的会话骨架;只有在你另行同意原始记录提示后,它才会发送每份完整记录经本地尽力脱敏后的副本。运行 oars pool outbox 时会打印当时排队的内容,但发送器会在同一次运行中构建新批次并发送,不会先行打印;会话结束至少一小时后才会离开你的设备;文件夹也可切换为仅骨架或关闭。钩子和 MCP 工具会将回忆文本添加到正在运行的会话中,你的运行框架会像发送其他上下文一样,将其发送给所用模型。
接受公约后,存入的记录可能会依据该公约获得许可。欧盟、欧洲经济区和英国不提供此存储池。
# Read every folder; or only the ones you name (a path, or its name under ~/.claude/projects); --deny keeps one out.
oars sessions deposit --redact-domain corp.example
oars sessions deposit --allow ~/work/app --allow ~/work/tools --deny ~/work/tools/secret
# Look up an error as printed, a file, or a prompt class.
oars sessions recall --error "unexpected EOF while looking for matching \`''"
oars sessions recall --path src/main.ts --since 30 # sees the first 100 sorted paths of a session
oars sessions recall --family recovery --class edit-verify --since 30 # a read family; only recovery and fit take --class and --since
oars sessions recall --entity Monitor # what is known about a public name: a package, a tool, an MCP server, an action, or a model
oars sessions recall --text "wrong input" # look for text in the local record (counts all time)
oars sessions recall --pattern <readId> --pattern <readId> # what happened from here, from the read IDs of your steps so far (repeatable; counts all time)
oars sessions recall --error "..." --session <id> # name the asking session, so what it did next can be read for this recall
oars sessions recall --error "..." --receipt # a paste-ready Markdown block for an issue on the failing tool: listed tool and harness names, the normalized signature, earlier sessions and weeks, what they did next (the next tools), redacted
# Serve the same query to a running agent as one MCP tool, oars_recall (stdio):
oars sessions recall --mcp
oars sessions recall --counts --day 2026-11-03 # push and pull, shown and held, as counts
oars sessions lineage <recallId or readId> # walk back through the evidence, one line per hop
oars sessions read # derived reads of your own sessions, largest sample first in each family, with what the store cannot read
oars sessions read --family version-boundary # order 2: what moved between two harness version buckets; also substitution, interaction, and day-move
oars sessions read --family lead-lag # order 3: a labeled experiment behind an out-of-time check
oars sessions read --family fit --slice model=claude-opus-5-5 --json
oars sessions books --by class --since 30 # tokens, wall time, turns, errors, verify-after-edit rate, and the outcome signals
oars sessions books --by pull # the same per package, MCP server, plugin, or skill a prompt pulled
oars sessions books --by harness # the same, grouped by Claude Code, Cursor, Codex, Copilot, Gemini, Grok Build, OpenCode, Pi, and VS Code Copilot Chat (deposit the others with --allow cursor, --allow codex, --allow copilot, --allow gemini, --allow grok, --allow opencode, --allow pi, --allow vscode-copilot, or --allow otel)
oars sessions measure --last 50 # recurring errors per 100 sessions, cache-write per session, recall calls per session
oars sessions measure --last 50 --repo <root> # the same, for one repository's sessions
oars sessions verify # consistency invariants on the stored skeletons and capture records
oars sessions exclusions # list sessions excluded by the local term file (counts only; OARS_EXCLUSION_TERMS names the file)
oars sessions gold sample # about 200 prompts to judge blind; needs the term file (`OARS_EXCLUSION_TERMS`), and `--exclude-term <text>` adds to it; `gold arms <file>` adds the claim and fresh readers on your Claude subscription; `gold score <file>` reads each arm against the judgments
deposit 是幂等的(只有当文件大小、mtime、捕获版本、salt 和 --redact-domain 集合全部未变时,才会跳过文件;由较旧捕获版本写入的存储会从 harness 的 transcript 或 raw/ 重新捕获,而由较新 oars 写入的存储则会被拒绝),并会追加到 <config>/oars/sessions/observations.jsonl:
每个 session、用户提示词、工具调用和失败的工具结果各有一条记录;每个工具调用还会以规范的操作词汇表记录其步骤,每条提示词则有一个 frame(harness、模型、日期和公开的栈名称);签名、提示词类别和恢复事件仅从该日志中派生,因此派生规则变更时不会重新读取 transcript。存储格式、每个字段及其类别、两个版本戳和原始归档见 docs/sessions-store.md;
类型定义位于 src/sessions/schema.ts。写入一行之前,会屏蔽机密信息(按模式和熵识别)、电子邮件地址以及你指定的域名(先对完整文本执行屏蔽,再截断文本);添加域名之前写入的行会留在只追加文件中,直到文件被压缩;读取方只使用每个 session 的最新版本。此日志是本地派生记录层:只包含经过屏蔽的文本,绝不包含原始内容。它只保留以下文本字段,不保留其他字段:每条提示词的前 300 个字符、工具错误的第一条有效信息行(错误行记录截断至 1,000 个字符,派生示例截断至 160 个字符)、助手文本中的 TLDR 行(400)和 Confidence 行(120)、WebSearch 查询、抓取的 URL、文件路径和 git 分支名称(最后四项没有长度限制),这些内容都会先经过屏蔽;此外还有项目文件夹 slug(不屏蔽,因此会包含你的用户名和目录名称;日志留在本地)、技能名称、effort 值、模型名称、harness 版本、工具名称(包括 MCP 服务名称)、shell 调用的程序和子命令,以及工具输入的键名称。工具调用的文件目标是加盐哈希值,绝不是路径。除了 gold arms,没有任何 oars sessions 命令会上传内容,遥测也不包含这些字段;oars pool 和 sender 会发送骨架,其中携带部分经过屏蔽的此类名称(技能、effort、模型、harness 版本、工具和 MCP 服务名称、shell 调用的程序、子命令和标志名称、工具输入键名称、调用值中的文件、目录和变量名称(名为 ledger-core 的文件夹会以 ledger-core 的形式发送;绝不会发送 session 根目录以上的文件夹,也不会发送路径或参数)、拉取的软件包名称(仅当公开列表中有其版本时才会发送版本),以及 Web 主机名(屏蔽后原样发送;pool 收到后会对其进行哈希处理);这些内容都会先经过屏蔽;详见 docs/pool.md 中的 “Wire field register”)。
子 Agent transcript(<project>/<session>/subagents/)会连同其父 session 和子 Agent 类型一起存入;books --by class 会在 delegated 列中显示其 token 数量,其错误会计入启动它们的 session 下的签名、measure 和 recall,因此每个 session 的计数仍按主 session 计算。每个存入的 transcript 也会通过硬链接(跨卷时则复制)放入 <config>/oars/sessions/raw/,因此其生命周期会长于 harness 自身的清理周期。对于每个 session,它还会写入一个骨架(包含 ID、时间戳、工具关联、token 数量、每个内容字段位置上的 SHA-256,以及基于原始行计算的 Merkle 根),由 verify 进行检查;骨架只包含哈希,绝不包含内容。
即使不变量存在异常,verify 也会以 0 退出;添加 --strict 则会以 4 退出。verify 还会单独报告每个 session(--json:sessionResults,每个 session 的十项检查及其 pass、fail 或 not run 状态),并根据原始文件审计每个 session(audit):检查硬链接和副本是否与原始文件匹配(大小不同的副本视为可能被篡改)、根据前 leaves 行重新计算 Merkle 根,以及计数绑定情况(leaves、session.lines,以及骨架中的 lines 加上 badLines 必须一致)。每个 session 会得到五种结果之一:root matches and the counts bind、changed since deposit、root mismatch、counts do not bind 或 not run(没有原始文件、没有骨架、没有捕获记录,或原始文件无法读取)。root mismatch 和 counts do not bind 会导致 --strict 失败;leaves 少于 10 的 session 会被标记。verify 还会根据操作员在同一 harness 上的其他周的数据对每个 session 进行评分(--json:selfBaseline,层 2,T0,本地):session 所属的 UTC 周是其 tsFirst 所在周;基线为该 harness 截至当前已结束、且工具调用至少 1,000 次的其他周,按调用次数合并;结果为七个直方图的中位数距离对应的 F(某个维度任一侧计数为零时会被舍弃)。若 tsFirst 为 null、该周调用次数少于 1,000,或基线周少于 4 周,则结果为 not run,不进行评分。较低的 F 会降低权重,但不会拒绝任何内容。verify 还会列出包含 transcript、但不在已保存允许列表中的项目文件夹,因此这些文件夹永远不会被读取(--json:scope,包含 folders、transcripts 和 names);这是范围提示,不是失败,也绝不会导致 --strict 失败。books 会打印相同的一行。measure 会打印每百个 session 中的重复错误数,并在第二行打印该时间窗口中的不同重复签名。
多个文件夹:--allow 前缀、glob 和 --allow-file
--allow 条目可以是文件夹(或其 slug)、带末尾斜杠的文件夹前缀(~/work/ 会读取该文件夹及其下的所有项目),也可以是 glob(* 匹配任意长度的字符序列,? 匹配一个字符;匹配 Claude Code 根据路径得出的项目文件夹名称)。--allow-file <list> 会从文件读取条目,每行一个(跳过空行和 # 注释),因此即使有数百个文件夹,也无需分批处理或使用很长的命令行。开头的 ~ 会展开为你的主文件夹,列表文件或带引号的条目中也一样。两者都可以重复使用并组合使用。如果两者都未指定,存入操作会读取所有文件夹。--deny <entry>(或列表文件中的 !<entry>)会以任意上述形式排除指定的文件夹;该设置会被保存,并且优先于所有 --allow,直到再次通过 --allow 指定完全相同的条目。再次指定条目会解除拒绝;当已保存的列表未指定任何文件夹时,不会产生其他影响(所有文件夹仍在范围内);当已保存的列表指定了文件夹时,该条目会加入其中。存入操作保存的条目会被 SessionEnd 钩子、发送方、oars pool deposit 和 oars gate replay 复用;如果没有保存条目,它们会读取所有文件夹。若 --allow-file 未指定任何条目,则会被拒绝。
在运行中的会话中回溯:钩子
oars sessions hook install 会在一个 Claude Code 设置文件中写入五个条目。使用 --machine 时,它只会写入 Stop 和 SessionEnd 条目(适用于 VPS 或云机器;同时使用 --env NAME=value 和 --terms-file <path>),具体说明见安装示例下方的段落。每个条目都会以确定性的方式在本地调用存储,并允许失败时继续(无模型、无网络);钩子内部出错时会以 0 退出且不输出内容,因此钩子不会阻塞会话,也不会导致会话失败。
| 事件 | 执行操作 | 安装时写入的超时 |
|---|---|---|
SessionStart | 将当前会话 cwd 对应的 oars sessions recall --context 注入为额外上下文:在仓库最近 300 个会话中,按会话数排序的前 5 个错误(即 measure --last 300 --repo 窗口),以及错误后通常发生的情况。然后,只要有符合条件的位置,就附上一张表,列出早先会话在下一步操作上出现分歧的位置(某个步骤领先,且占比为 20% 到 80%,至少有 20 条观察记录;仅显示名称和计数,最多 600 字节)。数据取自该会话所用 harness 和版本的保留池捆绑包,其次取自此存储的池(本地部分仅基于该 harness 和版本桶计算;如果转录内容未注明版本,则基于该 harness 的各个版本计算)。该表占 recalls.jsonl 的一行,并计入 10% 的保留比例 | 低于 500 ms |
UserPromptSubmit | 再次发送同一张表,但仅在它与本会话上次发送的表(已显示或已保留)不同时发送,因此表未变化时不会占用提示词。检查会读取召回日志末尾的 64 KB,该日志由所有会话共享;因此,在较长或并行的会话中,最后一行表格可能会移出窗口,导致再次发送未变化的表 | 低于 500 ms |
PreToolUse(无匹配器:适用于每个工具) | 此门控钩子的作用:它在调用已决定后触发,因此只是警告,不声称会改变下一步操作。对于工具及输入键名称与某个形态匹配的调用,如果该形态至少一半调用失败(至少涉及 3 个会话、至少 20 次调用),且失败频率至少是该操作本身的两倍,则将相关计数作为额外上下文注入;每个会话和形态仅注入一次(检查会读取召回日志末尾的 64 KB,约 44 行,因此极长的会话中可能会再次收到提示;索引移动时会重新抽取分组),并记录此次召回。此类会话和形态中有 10% 会被保留:被保留的分组会记录原本会显示的内容,但不会注入。每次调用都会启动 Node | 低于 500 ms |
PostToolUseFailure(匹配器:操作表映射的所有工具,以及 mcp__.*) | 恢复边:对于失败的调用,它会先从保留池捆绑包中读取此类失败(相同操作和错误类别)之后发生的情况;若没有,则从此存储中读取,并补充“在 X(代码)失败后,下一步是 Y,出现 xN 次”。如果最常见的下一步仍是再次执行失败的操作(重试),本地边后续步骤少于 5 个,或没有后续操作,则不会显示任何内容。表格未涵盖的调用仍显示旧句式“在 N 个会话中出现;后续操作:X”,并遵循相同的保留规则;如果严格来说重试是最常见的下一步,则不显示。每条已显示或已保留的内容都会作为一行写入 recalls.jsonl;10% 的会话会被保留。对于 Bash 和 PowerShell,已注册命令中的 shell 预过滤器会先读取事件,仅在事件包含 Exit code 时才启动 Node | 预过滤器:仅使用 shell 内建命令,不启动 Node;整个流程低于 1 s |
SessionEnd | 仅从保存的允许列表所包含的文件夹中存入该转录(按大小和 mtime 保证幂等);默认包含所有文件夹,直到某次存入操作指定了文件夹,并可用 --deny 排除。每个会话仅存入一次:Stop 会在每轮结束后触发,若使用它,每次都会追加不断增长的转录的新版本。对于未触发 SessionEnd 的 harness,会由下一轮扫描处理 | 低于 5 s |
Claude Code 仅会在成功时触发 PostToolUse;失败的 Bash 调用会以 PostToolUseFailure 事件到达,因此注册的是该事件。预过滤器是在 harness 运行钩子的 shell 中(Windows 上为 Git Bash)执行的 read、case 和 printf | node,因此不需要 findstr 或额外依赖。存储的写入方(SessionEnd、扫描任务、deposit)都会获取 store.lock,因此并行会话不会丢失彼此的 state.json 条目;超过十分钟的锁会被解除。
# The default is the user settings file; --scope project or --file names another.
oars sessions hook install # ~/.claude/settings.json (or $CLAUDE_CONFIG_DIR)
oars sessions hook install --scope file --file ./.claude/settings.local.json
oars sessions hook install --scope project # ./.claude/settings.json
oars sessions hook install --file my-settings.json --keep-retention
oars sessions hook status # user, project, and a task left by an earlier version
oars sessions hook uninstall --scope user # removes only the entries install wrote
安装时会合并配置:现有钩子(例如轮换会话的 Stop 钩子)会保留,即使它们位于也包含我们钩子的组中,或位于名称包含 hook-bin 的组下;重新运行时只会替换它自己的条目(命令以 hook-bin.js" <session-start|post-tool|stop> 结尾的条目),并会移除首次构建时添加的、每轮触发的 Stop 条目。设置文件若存在但无法读取,则会报错且不会更改任何内容。oars sessions hook install --machine 只会写入云 VM、VPS 或 runner 的 Stop 和 SessionEnd 条目(--scope project 或 --scope user);它与普通安装会各自保留对方的条目;--env NAME=value(用户范围)会将注册信息块写入该文件的 env,而 --terms-file <path> 会将内联排除词条移至仅所有者可读的文件中。参见 docs/sessions-store.md。harness 会在 cleanupPeriodDays 后删除原始转录(未设置时为 30 天),这会抹去 deposit 要读取的内容,因此安装时会将其在所写入的文件中提高到至少 365 天,显示旧值和新值,并且绝不会降低更高的值。--keep-retention 会保持原值不变并说明原因。卸载不会改动 cleanupPeriodDays。对于以 claude --settings <file> 启动的情况,请使用 --scope file 安装到该文件中。
发送操作由钩子和你的命令触发
oars 不会安装定时任务,也不会添加 cron 条目。会话结束后,SessionEnd 钩子会存入该转录,然后启动一个分离运行的发送器;其他任何 oars 命令也会启动发送器(oars gate hook、oars sessions hook uninstall 和 oars sessions try 除外),最多约每小时一次,以确保钩子保持快速。启动操作会先被标记,然后才执行;因此,如果启动失败,下一个触发操作会在每小时防抖间隔后重试。发送器会使用已保存的 --allow 和 --redact-domain 条目执行完整的存入流程,也会覆盖没有会话结束钩子的 harness(Cursor、Codex 等),刷新钩子读取的重复项索引,并且只有在满足 README 中的同意条件后才会发送。会话结束至少一小时后才会离开你的设备,因此你有时间执行 --deny 或删除操作。oars pool deposit --send <hash> 仍可用于手动发送。由早期版本注册的 Windows 任务 OarsSessionsNightly 会在执行 oars sessions hook install 或 uninstall 时移除;--schedule nightly 会被拒绝。--schedule off 会在该任务存在时将其移除,并关闭后台扫描和 pool 发送(遥测有独立的开关:oars telemetry off;该命令会在 <store>/schedule.json 中记录 {"schedule":"off"},钩子和每条命令都会读取此文件);--schedule on 会重新开启这些功能。
前后读取 measure
measure 没有截止时间,因此其时间窗口会随着每次存入而移动。若要固定“之后”的读数,请运行 oars sessions measure --last 300 --since <安装时间的 iso 时间>(添加 --repo <root> 可将窗口限定为一个代码库的会话):当前窗口是从该时间起启动的前 300 个会话,之前的窗口则是它前面的 300 个会话。不使用 --since 时,窗口为最近 N 个会话。measure 还会输出每个会话的钩子召回调用次数、钩子命中次数,以及钩子存入次数,这些数据来自存储区中的 hook-calls.jsonl。
移除所有内容
执行 oars sessions hook uninstall --scope user(或你安装时使用的作用域);执行 oars sessions hook install --schedule off;删除存储文件夹 <config>/oars/sessions/(其中包含观察记录、骨架、状态、钩子索引、hook-calls.jsonl,以及存放未脱敏转录内容的 raw/)。gold sample 还会将其提示词文件和配套文件写入 ~/.claude/session-commons/review/(或 $CLAUDE_CONFIG_DIR/session-commons/review/,或你的 --out-dir);也请删除这些文件。oars 还会写入 <config>/oars/telemetry/(遥测暂存区和安装 ID;也请删除),并在执行 oars login 后写入 <config>/oars/credentials.json(执行 oars logout 会将其删除)。cleanupPeriodDays 会保留安装时设置的值,除非你进行更改。
Gate:你的 Agent 选中了什么
oars gate replay # find installs, fetch-and-runs, MCP servers, and skills in logs on disk, and ask npm or pip what the registry holds
oars gate replay --no-registry-state # the same, without asking the registry
oars gate report # counts over crossings.jsonl, by who recorded each, and what replay cannot see
oars gate install # add the hook to Claude Code at user scope, so crossings are recorded as they happen
oars gate uninstall # remove only that hook entry
oars gate policy # print the policy in force (warn, block, or off per class)
重放在本地对你的转录内容进行只读操作;它会将 crossings.jsonl 和新颖性索引 gate-index.txt 写入 sessions 存储区,不会写入其他内容(npm 和 pip 也会保留各自的缓存,除非使用 --no-registry-state)。钩子(由 Claude Code 运行,而非由你运行)会在每次发生越界时将记录追加到 crossings.jsonl,并在同一存储区写入 gate-index.txt、gate-registry.jsonl 和空的 gate-ask-*.lock 文件(如果钩子必须中断一次注册表查询,该查询会由辅助进程完成;辅助进程会在自身超时后结束,而包管理器会将自己的缓存保存在存储区之外),并且始终以 0 退出。没有策略文件时,它会针对过去 30 天内首次发布的名称,或注册表中不存在的 npm 名称添加说明;gate-policy.json 可按类别更改此行为,而要阻止某项操作,则需要由你写入 block。阻止操作会标记为拒绝;除非你选择加入,否则越界操作不会执行(目前尚无选择加入机制)。report 只读取 crossings.jsonl。两者都会记录选择,但都不会对选择作出评判;说明或标签只陈述有关注册表的事实,不涉及其他内容。请参阅仓库中的 docs/gate.md。
pool
oars pool 使用 Many Oars 池 https://pool.manyoars.com,该池目前可用(在其契约发布前,暂不接受存款);你也可以通过 --server <url> 或 OARS_POOL_URL 指定池服务。其他所有命令均可在不使用它的情况下运行。
oars pool login --provider github|google会请求 pool 启动提供商的设备授权流程,打印用户代码和链接,并轮询 pool,直到你批准(轮询失败时会延长等待时间后重试,直到代码过期;如果没有排除条款文件,输出会指出这一点,而首次执行pool deposit时需要该文件);使用--verbose时,每个请求都会在发送前打印。OAuth 客户端及其密钥由 pool 持有,因此 CLI 无需客户端 ID 或密钥,提供商的令牌也不会到达这台机器。oars pool logout会在 pool 撤销这台机器的凭据,然后移除本地登录信息。如果无法连接 pool,它仍会移除本地登录信息,并说明 pool 未撤销该凭据。oars pool deposit会为符合文件夹允许列表和排除检查、且最后一行距今超过 6 小时的每个会话,将一批会话骨架(字段列表固定,每个值都会先脱敏;主机到达 pool 时会由 pool 哈希处理)写入待发送箱,然后停止:不会发送任何会话数据。账户接受 pool 公约后,--send <hash>会发送outbox打印过且磁盘上的内容未变的一批数据(由用户在终端输入公约屏幕显示的短语;--accept-covenant <version>只指定预期版本,不会接受公约;随后屏幕会询问“你是否在欧盟、欧洲经济区或英国?(是/否)”,并发送答案;使用--in-eu-eea-uk <yes|no>可直接回答,无需询问;当 pool 不向这些地区开放时,若回答是,或请求来自这些地区,则会被拒绝并返回region_closed,且不会接受任何内容);在此之前,它会读取公约,不发送数据,并以退出码 3 退出,返回covenant_not_accepted。从未显示过的哈希或已更改的数据批次会在发出任何请求前被拒绝。分离式发送器是另一种发送方式:pool 确认你的账户已接受公约后,它会发送新批次;只有当你对原始数据提示选择了同意时,才会发送原始副本(oars pool raw --consent yes,需在终端输入短语I consent to sending raw copies;选择是也会通知 pool,而--consent no会通知 pool 停止接收原始副本,无论后续请求如何声明(如果某台机器之前选择了是,但当前已退出登录,则会以非零状态退出:pool 尚未收到通知);随后 pool 的夜间任务会从当晚开始删除已持有的原始副本;大型账户可能需要不止一晚)。未登录、未接受公约或服务器无法连接时,它不会发送任何内容。deposit、outbox、export和fetch都需要先执行oars pool login;否则会以退出码 3 退出并指出服务器。oars pool coverage [--org-size <band>] [--repo-visibility public|private|unknown]会设置仅你能提供的两个覆盖范围档位,在本地读取,不会从网络读取;未设置的档位会以unknown发送。oars pool export --out <folder> [--raw]会以 JSON 格式保存 pool 持有的关于你账户的副本(GDPR 第 15(3) 条和第 20 条),每页一个文件,且仅你可读取。内容包括你的账户行(含原始数据同意记录)、登录信息的失效时间(不含凭据)、你接受公约的记录、你的机器(不含密钥,含每台机器最后一次存入的日期及其密钥使用天数)、你的存储库密钥、你的存入时间、当前显示的存入记录(含其来源机器、主机类别和启动器,以及批次声明的主机类别和启动器)、你的原始数据台账、暂存的存入部分、擦除审计行和遥测日期。--raw还会保存你存入且尚未擦除的每份原始转录,并校验其哈希。此命令需要先执行oars pool login,不会向 pool 写入任何内容,会打印所保存的内容;如果任何页面或对象保存失败,则会指出并以非零状态退出;重新运行会覆盖相同文件。pool 根据多个账户推导出的汇总数据不属于你的可导出数据,也不会包含在其中。- 在已注册的机器上,钩子子进程会在首次存入前激活其密钥,并在磁盘持久的环境(
vps、ci)中轮换密钥(密钥位于<store>/machine-key,仅所有者可访问),使用该密钥存入,并在接受公约后发送待发送箱中保存的批次;如果密钥将在 14 天内过期、已经过期或已被撤销,它会在下一次 Stop 时通知你(oars pool machines会列出该密钥)。cloud机器的密钥由网络代理持有,子进程不会发送自己的凭据。详情见docs/pool.md,“机器密钥”。 oars pool outbox会逐字打印每个待发送批次(与实际发送内容完全一致),并附上其 SHA-256;--explain会为每个字段补充规则说明。oars pool fetch --harness-version <version>会获取该版本的签名包,根据登录时固定的密钥验证签名,并在本地保存。它会打印包中声明的公开和披露下限(以及单独设定下限的任何读取系列),自身不设下限:下限由 pool 设定,因此更改下限属于部署,不会成为 oars 的新版本。
club
俱乐部会与持有其代码的人分享你的统计数据,仅此而已。成员可以看到你的昵称、划船周数、活跃天数、本周的训练次数和划桨次数。他们看不到你的训练、项目、提示词或令牌。你需要先运行 oars pool login,oars board 除外。
oars club create "Friday crew" --nickname skipper # prints the join code once
oars club join K7M2QX --nickname bow # a club you were invited to
oars club join open --nickname bow # the open board; your row shows once your account has standing
oars club show <club> # the members in the pool's order
oars club leave <club> # your row leaves view at once
oars board # the open board; no sign-in
创建和加入时会显示池的同意文本,并等待你在终端输入 yes。通过标准输入读取的脚本不能代替你同意,在你同意之前不会发送任何内容。只把代码发送给你希望加入俱乐部的人:代码可用于加入,成员也可以随时退出。
昵称须为 2 至 24 个字母、数字、空格、点、下划线或连字符,首尾不能有空格,不能包含 @ 或网址。每个账户每小时最多可输错代码 10 次,每天最多可创建俱乐部 5 次;超过限制后,你会收到 rate_limited 错误,并获知何时可以重试。每条命令都支持 --json。错误信息会先说明原因:not_signed_in、club_full、nickname_taken、nickname_invalid、rate_limited。
--json 约定
使用 --json 时,标准输出只包含一个 JSON 文档,成功时退出码为 0。
- 成功:
{"ok": true, ...}。其余内容取决于命令:login会添加email;keys create会添加key和secret,keys list会添加keys,keys revoke会添加keyId和revoked;sessions命令会添加各自的字段(deposit添加统计数据,recall添加matches,books添加rows,measure添加last和before,verify添加sessions、unreadable、invariants、sessionResults和audit)。 - 失败:
{"ok": false, "step": "...", "problem": {...}},其中problem是平台的问题文档(如果平台提供了title、detail、code和actionUrl,则会包含这些字段)。
不使用 --json 时,失败信息会改为输出到标准错误。
退出码:
| 代码 | 含义 |
|---|---|
| 0 | 成功 |
| 1 | 意外错误 |
| 2 | 用法错误 |
| 3 | 身份验证失败(登录已过期或被拒绝,HTTP 401 或 403) |
| 4 | 平台拒绝了输入,或 sessions verify --strict 发现异常 |
| 5 | 冲突(幂等键已被使用) |
| 7 | 请求过于频繁 |
| 8 | 无法连接服务器(平台、签发方或池服务器) |
| 10 | pool fetch 达到池的每周获取上限;磁盘上的数据包不会受影响,提示信息会告知何时可以重试 |
源码
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。