Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions docs/guide/scorers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> Part of the [TeamAI CLI Usage Guide](../usage-guide.md).

A scorer is a rubric a judge applies to a workflow step's work. It is a Markdown file at `scorers/<name>.md` in the team repo.
A scorer is a rubric a judge applies to a workflow step's work or to a finished agent session. It is a Markdown file at `scorers/<name>.md` in the team repo.

`scorers/review-quality.md`:

Expand Down Expand Up @@ -93,6 +93,8 @@ $ teamai score --lease s5d1e07c2a9b4/a91c0d7e --json '{"driver":{"kind":"local",

`samplingRate` picks the succeeded passes to judge, the same way on every machine. `workflow next` never hands out judge work. `--lease <ref>` judges here with the tool the lease names, in a [confined profile](#isolation), and settles the lease like any driver's answer. A failed judge leaves the lease open.

The label records `used.skills`, the team skills the pass or its subagents loaded, found as for [a session](#score-a-session) from what the checkout held as teamai delivered it when the pass started. A `workflow:` step's label lists every skill its child passes recorded, and has no `used` when none of them recorded one.

The evidence directory holds `evidence.json`, `prompt.md`, `diff.patch` when a range was recorded, `repo/` (tracked files at the judged commit, symlink targets stored as text), `transcripts/` (with readable subagents) and `outputs.json`. Every file is redacted, including the values of the secrets the team declares in `env/secrets.yaml`. A tracked file that is not text is left out and listed under `omitted`. Missing evidence is listed as gap codes. It is removed when the lease settles or lapses.

## Any driver
Expand All @@ -116,6 +118,14 @@ JSON

A label the scorer does not list is refused, and the lease stays open. `running` lists the refs you still judge, which renews them; a lease lapses 30 minutes after it was taken or renewed. Never list a judge ref in `workflow next`'s `running`. `teamai score --help` has every field.

Your driver names the team skills a pass loaded when it reports the pass, and the pass's labels carry them:

```console
$ teamai workflow report r3f9… --json '{"attempt":"…","revision":3,"outcome":"success","driver":{…},"used":{"skills":["review-notes"]}}'
```

Names only: a value that is not a skill name, such as a path, is dropped. A report without `used` gives labels without it; `"skills":[]` says the pass loaded no team skill.

## On demand

```console
Expand All @@ -125,6 +135,23 @@ $ teamai score --run r3f9… --step review --pass 2 --scorer review-quality --qu

Sampling does not apply, and judge work that failed or expired opens again. A scorer the run pinned judges with that rubric; any other scorer `teamai pull` cached, with its current one. Without `--queue`, the first judge tool on PATH runs, preferring the tool that ran the pass. An unknown run, step, pass or scorer fails and lists the ones that exist. A scorer whose model no judge tool here runs fails `judge_model_unavailable` and stays open. The error's `labels` lists what the other scorers labelled.

## Score a session

```console
$ teamai score --scorer review-quality # inside an agent session: scores that session
ℹ Scoring claude-code session 7c1e… in /work/app
ℹ First prompt: Add retries to the client
ℹ review-quality: bad (score 0, did not pass). Reasoning: ~/.teamai/scores/reasoning/9f2c….md
ℹ To share what went wrong, ask your agent to read ~/.teamai/scores/reasoning/9f2c….md and share it with the team (teamai contribute --session-id 7c1e…).
$ teamai score --session 7c1e… --source codex --scorer review-quality --push
```

Outside a session, pass `--session <id>`. Scoring never guesses the session. `--source` takes the platform names of `teamai session migrate --source`. Leave it out when an agent session variable such as `CLAUDE_CODE_SESSION_ID`, or the session's captures, name one platform. The judge reads the redacted session with its subagents' transcripts, and sampling does not apply.

The judge reads at most 200,000 characters of a session. A session scorer that names a cheaper [model alias](#choose-the-judges-model) keeps a long session cheap to judge.

The label is kept in the scope the session ran in, from whichever directory you score it. It records `agent`, what the session ran as, from the captures the session-start hook writes. It records `used.skills`, the team skills the session or its subagents loaded that its captures show teamai delivered, unchanged, when it started, including by the pull it runs at start. A later pull does not change that. A skill the captures cannot place, such as a member's own skill with a team skill's name, is left out. `--push` publishes every pending label of that scope. With [usage reporting](reporting.md) off, it prints `Usage reporting is off, so labels stay on this machine.` and the labels stay pending. An http team repo has no `teamai-reports`, so `--push` fails with `unsupported_repo` and the labels stay here. `teamai doctor` warns while a label waits to be published.

## Batching

```yaml
Expand Down Expand Up @@ -180,6 +207,7 @@ A `best-effort` tool cannot judge for a scorer that requires `verified`. Prompts
| `<dataHome>/scores/labels.jsonl` | Every label on this machine. |
| `<dataHome>/scores/reasoning/` | The judge's reasoning, one file per label. Never published. |
| `<dataHome>/scores/raw/` | A failed local judge's output, until a later attempt replaces it. |
| `scores/<member>/<YYYY-MM>.jsonl` on `teamai-reports` | Published labels, the newest per scorer, rubric, pass and judge kind. Labels wait in `<dataHome>/scores/pending/` until a push lands, and stay there while usage reporting is off. |
| `<dataHome>/sessions/captures/` | What each session started as, written by the session-start hook. Removed a day after the session's file is gone. |
| `scores/<member>/<YYYY-MM>.jsonl` on `teamai-reports` | Published labels, the newest per scorer, rubric, subject and judge kind. Labels wait in `<dataHome>/scores/pending/` until a push lands, and stay there while usage reporting is off. |

Labels never enter the run or its record. Workflow Runs shows each pass's labels, and what judging cost apart from the run's own tokens. For a run on this machine that counts every judge attempt; for a run a member published, only the labelled ones.
2 changes: 1 addition & 1 deletion docs/guide/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ teamai workflow next <run> --json '{"driver":{"kind":"local","machine":"host","w
teamai workflow report <run> --json '{"attempt":"<attempt>","revision":1,"outcome":"success","driver":{"kind":"local","machine":"host","workspace":"/work"}}'
```

`outcome` is `success`, `failed`, or `released`. `released` puts the step back to pending. It does not use up a retry. A report for an attempt that was already settled returns `repeated_report`, even when the revision is old. The run keeps recent settled attempts for that check. An older attempt uses the other checks: an old revision returns `stale_revision`, and a current revision that is not the leased attempt returns `wrong_attempt`. Another driver returns `wrong_driver`. `changes` whose `branch` or `base` differs from the lease returns `invalid_report`, and the step stays leased. A read-only step in a workspace reports `read` (`branch`, `base`, and the `commit` it read) in place of `changes`. `changes` from it, a success without `read`, `read` from any other step, or `read` that differs from the lease returns `invalid_report` too. A payload field the CLI does not read, such as a misspelled `tokens` written as `tokenz` or a field from a newer protocol version, is accepted but reported back: the success envelope of `next`, `report`, and `respond --json` carries `ignored` with those names — top-level fields first, then `driver.<field>` names — names only and never values. The key is left out when nothing was ignored, and an error envelope stays as it is.
`outcome` is `success`, `failed`, or `released`. `released` puts the step back to pending. It does not use up a retry. A report for an attempt that was already settled returns `repeated_report`, even when the revision is old. The run keeps recent settled attempts for that check. An older attempt uses the other checks: an old revision returns `stale_revision`, and a current revision that is not the leased attempt returns `wrong_attempt`. Another driver returns `wrong_driver`. `changes` whose `branch` or `base` differs from the lease returns `invalid_report`, and the step stays leased. A read-only step in a workspace reports `read` (`branch`, `base`, and the `commit` it read) in place of `changes`. `changes` from it, a success without `read`, `read` from any other step, or `read` that differs from the lease returns `invalid_report` too. `used` (`{"skills":["review-notes"]}`) names the team skills the pass loaded, for its [scorer labels](scorers.md#any-driver). A value that is not a skill name is dropped, and a `used` of another shape returns `invalid_report`. A payload field the CLI does not read, such as a misspelled `tokens` written as `tokenz` or a field from a newer protocol version, is accepted but reported back: the success envelope of `next`, `report`, and `respond --json` carries `ignored` with those names — top-level fields first, then `driver.<field>` names — names only and never values. The key is left out when nothing was ignored, and an error envelope stays as it is.

The run is stored in this scope's TeamAI data directory. The command exits when it finishes. A local run that ends `failed` or `cancelled` exits with status 1. No workflow process keeps running.

Expand Down
32 changes: 30 additions & 2 deletions docs/guide/zh-CN/scorers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 本文是 [TeamAI CLI 使用指南](../../usage-guide.zh-CN.md) 的一部分。

评分器(scorer)是评审者用来评判工作流步骤成果的评分标准。它是团队仓库里的 Markdown 文件 `scorers/<name>.md`。
评分器(scorer)是评审者用来评判工作流步骤成果或已结束的 agent 会话的评分标准。它是团队仓库里的 Markdown 文件 `scorers/<name>.md`。

`scorers/review-quality.md`:

Expand Down Expand Up @@ -93,6 +93,8 @@ $ teamai score --lease s5d1e07c2a9b4/a91c0d7e --json '{"driver":{"kind":"local",

`samplingRate` 决定评判哪些成功的执行轮次,在每台机器上结果相同。`workflow next` 从不分发评审任务。`--lease <ref>` 在本机用租约选定的工具、以[受限配置](#隔离)评判,并像任意 driver 的答案一样结算租约。评审失败时租约保持打开。

标签记录 `used.skills`,即该轮次或其子 agent 加载过的团队技能。判定方式与[会话](#为会话评分)相同,依据该轮次开始时检出目录中由 teamai 交付并未经修改的技能。`workflow:` 步骤的标签列出其子轮次记录的全部技能。若子轮次都未记录,标签没有 `used`。

证据目录包含 `evidence.json`、`prompt.md`、有记录范围时的 `diff.patch`、`repo/`(被评判提交中的跟踪文件,符号链接的目标以文本保存)、`transcripts/`(包含可读取的子代理)和 `outputs.json`。所有文件都经过脱敏,团队在 `env/secrets.yaml` 中声明的密钥值也会被遮蔽。不是文本的跟踪文件不会写入,并列在 `omitted` 里。缺失证据以 gap 代码列出。租约结算或过期后删除证据。

## 任意 driver
Expand All @@ -116,6 +118,14 @@ JSON

评分器未列出的标签会被拒绝,租约保持打开。`running` 列出你仍在评判的租约,从而续期;租约在领取或续期 30 分钟后过期。不要把评审租约放进 `workflow next` 的 `running`。所有字段见 `teamai score --help`。

你的 driver 在上报一个轮次时写明它加载过的团队技能,该轮次的标签会带上它们:

```console
$ teamai workflow report r3f9… --json '{"attempt":"…","revision":3,"outcome":"success","driver":{…},"used":{"skills":["review-notes"]}}'
```

只写名字:不是技能名的值(例如路径)会被丢弃。上报中没有 `used` 时,标签也没有;`"skills":[]` 表示该轮次没有加载团队技能。

## 按需评分

```console
Expand All @@ -125,6 +135,23 @@ $ teamai score --run r3f9… --step review --pass 2 --scorer review-quality --qu

不应用抽样,失败或过期的评审任务会重新打开。运行固定过的评分器使用固定的评分标准;`teamai pull` 缓存的其他评分器使用当前版本。不加 `--queue` 时,运行 PATH 上首个可用的评审工具,优先使用执行该轮的工具。未知的运行、步骤、执行轮次或评分器会失败,并列出存在的值。若本机没有评审工具能运行某个评分器的模型,该评分器以 `judge_model_unavailable` 失败并保持打开。错误的 `labels` 列出其他评分器已生成的标签。

## 为会话评分

```console
$ teamai score --scorer review-quality # 在 agent 会话内:为该会话评分
ℹ Scoring claude-code session 7c1e… in /work/app
ℹ First prompt: Add retries to the client
ℹ review-quality: bad (score 0, did not pass). Reasoning: ~/.teamai/scores/reasoning/9f2c….md
ℹ To share what went wrong, ask your agent to read ~/.teamai/scores/reasoning/9f2c….md and share it with the team (teamai contribute --session-id 7c1e…).
$ teamai score --session 7c1e… --source codex --scorer review-quality --push
```

在会话外运行时,传入 `--session <id>`。评分从不猜测会话。`--source` 使用 `teamai session migrate --source` 的平台名。`CLAUDE_CODE_SESSION_ID` 等 agent 会话环境变量或会话的捕获记录只指向一个平台时,可以省略。评审者读取脱敏后的会话及其子 agent 的记录,不应用抽样。

评审者最多读取会话的 200,000 个字符。会话评分器指定更便宜的[模型别名](#选择评审者的模型),长会话的评审成本也会更低。

无论在哪个目录评分,标签都保存在会话所在的作用域。标签记录 `agent`,即会话启动时的运行配置,来自会话启动 hook 写入的捕获记录。标签还记录 `used.skills`,即会话或其子 agent 加载过、且捕获记录显示会话启动时(包括启动时那次 pull)由 teamai 交付并未经修改的团队技能。之后的 pull 不会改变它。捕获记录无法确认来源的技能不记录,例如与团队技能同名的成员自有技能。`--push` 发布该作用域所有待发布的标签。关闭[用量上报](reporting.md)时,它输出 `Usage reporting is off, so labels stay on this machine.`,标签继续待发布。http 团队仓库没有 `teamai-reports`,因此 `--push` 以 `unsupported_repo` 失败,标签留在本机。有标签等待发布时,`teamai doctor` 会给出警告。

## 批量评审

```yaml
Expand Down Expand Up @@ -180,6 +207,7 @@ Judge tools here: claude 2.1.308 (Claude Code) is verified, codebuddy 2.3.0 is b
| `<dataHome>/scores/labels.jsonl` | 本机的所有标签。 |
| `<dataHome>/scores/reasoning/` | 评审者的理由,每个标签一个文件。从不发布。 |
| `<dataHome>/scores/raw/` | 本机评审失败时的输出,保留到之后的评审尝试取代它。 |
| `teamai-reports` 上的 `scores/<member>/<YYYY-MM>.jsonl` | 已发布的标签,每个评分器、评分标准、执行轮次和评审类型只保留最新一条。推送成功前标签留在 `<dataHome>/scores/pending/`;关闭用量上报时一直留在那里。 |
| `<dataHome>/sessions/captures/` | 每个会话启动时的运行配置,由会话启动 hook 写入。会话文件消失一天后删除。 |
| `teamai-reports` 上的 `scores/<member>/<YYYY-MM>.jsonl` | 已发布的标签,每个评分器、评分标准、评分对象和评审类型只保留最新一条。推送成功前标签留在 `<dataHome>/scores/pending/`;关闭用量上报时一直留在那里。 |

标签从不进入运行或它的记录。工作流运行页面显示每一轮的标签,以及评审开销,与运行本身的 token 分开统计。本机的运行统计每一次评审尝试;成员发布的运行只统计产生了标签的评审。
2 changes: 1 addition & 1 deletion docs/guide/zh-CN/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ teamai workflow next <run> --json '{"driver":{"kind":"local","machine":"host","w
teamai workflow report <run> --json '{"attempt":"<attempt>","revision":1,"outcome":"success","driver":{"kind":"local","machine":"host","workspace":"/work"}}'
```

`outcome` 可以是 `success`、`failed` 或 `released`。`released` 把步骤退回 pending,不消耗重试。已经上报过的 attempt 返回 `repeated_report`,revision 旧了也一样。运行状态会记住最近上报过的 attempt。更早的 attempt 走其余检查:revision 旧了返回 `stale_revision`,revision 是当前值但不是当前租约的 attempt 时返回 `wrong_attempt`。其他驱动返回 `wrong_driver`。`changes` 的 `branch` 或 `base` 与租约不符时返回 `invalid_report`,步骤仍处于租约中。工作区里的只读步骤上报 `read`(`branch`、`base` 和它读取的 `commit`),而不是 `changes`。它上报 `changes`、成功时没有 `read`、其他步骤上报 `read`,或 `read` 与租约不符时,同样返回 `invalid_report`。CLI 不读取的 payload 字段——例如把 `tokens` 拼成 `tokenz`,或来自更新协议版本的字段——会被接受但回报出来:`next`、`report` 和 `respond --json` 的成功信封会带上 `ignored`,先列顶层字段、再列 `driver.<字段>`,只有名字、没有值。没有未读字段时不带这个键,错误信封保持原样。
`outcome` 可以是 `success`、`failed` 或 `released`。`released` 把步骤退回 pending,不消耗重试。已经上报过的 attempt 返回 `repeated_report`,revision 旧了也一样。运行状态会记住最近上报过的 attempt。更早的 attempt 走其余检查:revision 旧了返回 `stale_revision`,revision 是当前值但不是当前租约的 attempt 时返回 `wrong_attempt`。其他驱动返回 `wrong_driver`。`changes` 的 `branch` 或 `base` 与租约不符时返回 `invalid_report`,步骤仍处于租约中。工作区里的只读步骤上报 `read`(`branch`、`base` 和它读取的 `commit`),而不是 `changes`。它上报 `changes`、成功时没有 `read`、其他步骤上报 `read`,或 `read` 与租约不符时,同样返回 `invalid_report`。`used`(`{"skills":["review-notes"]}`)写明该轮次加载过的团队技能,供它的[评分标签](scorers.md#任意-driver)使用。不是技能名的值会被丢弃,其他形状的 `used` 返回 `invalid_report`。CLI 不读取的 payload 字段——例如把 `tokens` 拼成 `tokenz`,或来自更新协议版本的字段——会被接受但回报出来:`next`、`report` 和 `respond --json` 的成功信封会带上 `ignored`,先列顶层字段、再列 `driver.<字段>`,只有名字、没有值。没有未读字段时不带这个键,错误信封保持原样。

运行状态保存在当前 scope 的 TeamAI 数据目录里。命令结束后进程就退出。本地运行以 `failed` 或 `cancelled` 结束时,退出码是 1。不会留下常驻的工作流进程。

Expand Down
Loading
Loading