Team Reports¶
Team Reports 将 GitHub 组织活动和可选的 Discord 讨论收集为每日、每周和每月报告。它在 Gateway 上保存报告历史,并在 Control UI 中添加一个报告标签页。报告包括活动计数、按人员的历史记录、来源警告以及可选的模型撰写的摘要。
Team Reports 是一个官方外部包:它不是核心 openclaw npm 包的一部分,而是按需从 ClawHub 或 npm 安装。仓库的源代码检出会直接从 extensions/team-reports 加载它。在您启用之前,它保持禁用状态。报告页面使用 Gateway 身份验证。它们的默认 HTTP 路由是 /plugins/team-reports/;Control UI 标签页在 /reports 打开,并带有任何已配置的 Control UI 基础路径前缀。
开始之前¶
您需要一个能够读取您配置的组织、仓库和团队成员身份的 GitHub token。收集只能包含该 token 可以访问的数据。对于 Discord,请使用一个能够访问所选服务器、频道、话题和消息历史的 bot token。只有明确配置的频道及其话题才计算在内。
支持细粒度 GitHub token。Issue 搜索始终指定 is:issue 或 is:pull-request,合并搜索仅限于 pull request。
模型撰写的摘要使用 agent 配置的模型和凭据。发送给该模型的证据可以包括仓库活动和已选择加入的 Discord 摘录。设置 summaries.enabled: false 可生成具有确定性文本且不调用摘要模型的报告。
安装并启用 Team Reports¶
除非您从源代码检出运行 Gateway(该检出已包含此包),否则请安装此包:
然后将以下内容添加到您的 OpenClaw 配置中,将示例组织、团队和登录名替换为您自己的:
{
plugins: {
entries: {
"team-reports": {
enabled: true,
config: {
github: {
token: {
source: "env",
provider: "default",
id: "TEAM_REPORTS_GITHUB_TOKEN",
},
orgs: ["example-org"],
teams: [{ org: "example-org", slug: "maintainers" }],
},
people: [{ github: ["example-member"], display: "Example Member" }],
summaries: { enabled: false },
},
},
},
},
}
确保引用的环境变量对 Gateway 进程可用。有关其他密钥提供程序,请参阅密钥管理。如果您使用 plugins.allow,请将 team-reports 包含在该列表中。
插件配置更改会在默认的混合重载模式下自动应用。如果 Gateway 处于离线状态,请在其配置的密钥可用的情况下启动它。如果您更改了其进程环境,请使用更新后的环境重新启动它。然后检查插件:
启动时,如果尚未在该日收盘的 UTC 午夜或之后启动过一次包含该日的成功运行,就会在 60 秒后对昨天触发一次补跑。收盘后完成的手动运行也满足补跑条件,包括在启动延迟或延迟等待期间完成的运行。在该日尚未收盘时启动的成功运行不满足已收盘日期的补跑要求。重试部分失败的运行时,补跑会复用同一组织范围内健康的已收盘每日报告,并收集剩余日期。手动生成仍会刷新所请求的日期。周报和月报使用存储的每日活动。收集和聚合在 worker 中运行,有界的批次会暂存在插件的 SQLite 连接中。当该连接关闭时,临时活动消失;已接受的报告历史和保留策略不变。
状态显示运行、已存储的时间段、下次计划时间和来源警告。要立即请求报告,请使用:
生成会在记录运行之后、收集和摘要完成之前返回一个运行 ID。检查 status 以获取结果,然后在 Control UI 中打开报告。
在 Control UI 中阅读报告¶
当插件已启用且 Control UI 连接具有 operator.read 权限时,报告标签页会出现。它将报告页面嵌入到沙箱化框架中。Gateway 提供并续期作用域限定的身份验证 cookie;不会向报告 URL 添加 Gateway token。
每个报告路由都需要 operator.read;operator.write 和 operator.admin 也满足该要求。Control UI 标签页通过其作用域限定的 cookie 授予 operator.read。CLI 的 Gateway RPC 方法已经声明了它们所需的读取或生成作用域。
请使用 HTTPS、Tailscale Serve 或浏览器信任的回环来源。局域网主机名上的纯 HTTP 无法对该框架进行身份验证。阻止所有第三方 cookie 的浏览器也可能导致该标签页不可用。
GitHub 和其他外部链接可能无法在沙箱化框架内打开。每个页面都包含在新窗口中打开,使用该页面自身的 URL。如果浏览器也阻止该操作,请将链接复制到新标签页中。Gateway 身份验证在那里仍然适用。
工作会话¶
概览会显示此 Gateway 上最近的工作会话。打开所有工作会话(或报告导航中的工作会话)以分页浏览当前会话列表。每个条目都链接到对话,并显示其当前所有者、运行状态以及项目(如果存在)。会话按最近活动排序。
每个人的历史页面以及每日、每周和每月报告中的每个成员部分也会显示当前工作 / 名下会话,包括按人员筛选报告时。这些直接对话链接反映的是当前所有权,而不是历史报告时间窗口。所有名下会话会打开一个分页目录,该目录在分页前已筛选到该成员。
成员匹配不区分大小写,使用他们配置的和报告中的 GitHub 别名,与 Gateway 个人资料上关联的 GitHub 身份进行匹配。合并后的个人资料会解析为其规范所有者。未关联或模糊的身份会与您看不到任何会话的已关联成员分别标注。显示名称绝不会用于推断所有权。
The list is read when you open or refresh the page, using your existing session permissions. Archived, incognito, automation, system, and hidden subagent sessions are excluded. Session owners are not guessed from GitHub handles or display names. This is a current-work view, not a historical contribution count: it does not change daily totals, model summaries, Markdown or JSON exports, or stored report history. Session transcripts are not copied into the reports database.
Inside the Control UI, selecting a session opens its chat through the host navigation. Outside the embedded tab, session links are ordinary Control UI links. If session discovery fails, the page shows Work sessions unavailable while stored reports remain usable.
Pages mirror the maintainer report site layout: a banner and activity dateline, latest-period quick cards, day/week/month history, people timelines, and a per-person calendar. The generation panel shows scheduler and source health. Closed and partial periods remain distinct, with coverage and summary warnings alongside the report.
The theme choice follows you through in-tab navigation via the page fragment
(#theme=light or #theme=dark). Inside the sandboxed Reports tab, it lasts for
that visit. It persists per browser only where storage is available, such as in
a separate window. Pages choose the theme from the fragment first, then browser
storage when available, then the operating system's light or dark preference,
independently of the Control UI theme.
Relative times and open-day countdowns refresh with a small inline script that the Content Security Policy allows by nonce. The same script enables history toggles, member filtering, and the quiet-member switch. Pages still work without JavaScript: all history rows and members remain available, and timestamps have server-rendered fallbacks.
The crab artwork and icon are served from the plugin's own assets route under
the same authentication and scope checks as report pages. Those assets use
a private one-day cache; report pages and exports remain uncached.
Roster members and other GitHub actors show GitHub avatars from
avatars.githubusercontent.com, using the primary GitHub login. Images load
lazily without sending a referrer. Initials remain visible when an image cannot
load; invalid logins use initials only. Display names and Discord IDs are never
used to construct avatar URLs. The pages bundle their styles and use system
fonts, so no external stylesheets, web fonts, or scripts are needed.
Configuration¶
All keys below live under plugins.entries.team-reports.config. Unknown keys
are rejected. Configuration changes reload the running plugin with the default
hybrid reload mode; see Hot reload. Secrets
resolve when the report service starts. After rotating a file, exec, or store
secret, run openclaw plugins reload team-reports. Environment changes require
restarting the Gateway with the updated environment.
| Key | Default | Behavior |
|---|---|---|
basePath |
"/plugins/team-reports" |
Absolute route root with nonempty path segments using letters, digits, ., _, and -. It must not use . or .. segments, the /api/channels prefix, or equal or sit below an explicitly configured Control UI base path. Trailing slashes are normalized away. |
displayTimezone |
"UTC" |
IANA timezone for displayed timestamps. Report windows always use UTC. |
github |
required | GitHub collection configuration, described below. |
discord |
unset | Optional Discord collection configuration. Omit it to collect GitHub only. |
people |
unset | Inline identity entries. Mutually exclusive with peopleFile. |
peopleFile |
unset | Absolute path to a regular JSON file of at most 2 MiB, shaped as { "people": [...] } and using the identity fields below. |
summaries |
defaults below | Model selection and summary enablement. |
schedule |
defaults below | UTC collection times and aggregate refreshes. |
| 键 | 默认值 | 行为 |
|---|---|---|
retention.days |
400 |
在闭日运行后,删除存储时间超过该天数的报告;0 表示保留所有历史记录。 |
GitHub¶
| 键 | 默认值 | 行为 |
|---|---|---|
github.token |
必填 | 非空 token 字符串或 SecretRef { source, provider, id }。Secret 来源包括 env、file、exec 和 store。建议优先使用 SecretRef。 |
github.orgs |
必填 | 要收集的组织名称的非空数组。 |
github.teams |
[] |
名册来源,形状为 { org, slug }。 |
github.includeDirectCollaborators |
false |
将具有 push、maintain 或 admin 访问权限的直接仓库协作者添加到名册。 |
github.excludeRepos |
[] |
要跳过的仓库名称,格式为 owner/name。已归档的仓库也会被跳过。 |
github.apiBaseUrl |
"https://api.github.com" |
HTTPS API 基础 URL;对于 GitHub Enterprise Server,请设置此项。 |
github.ignoreCommentPatterns |
[] |
正则表达式源字符串。匹配的 issue 评论和 PR 审查评论将被排除。无效的模式会被拒绝。 |
Discord¶
以下是一个可选的部分配置示例。ID 仅用于说明:
```json5 validate=false discord: { token: { source: "env", provider: "default", id: "TEAM_REPORTS_DISCORD_TOKEN", }, guildId: "123456789012345678", channels: [ { id: "234567890123456789", excerpts: true }, { id: "345678901234567890" }, ], excerptMaxChars: 260, },
| 键 | 默认值 | 行为 |
| ----------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `discord.token` | 配置 Discord 时必填 | Bot token 字符串或 SecretRef,形状与 `github.token` 相同。 |
| `discord.guildId` | 配置 Discord 时必填 | Guild ID。 |
| `discord.channels` | 配置 Discord 时必填 | 频道条目的非空数组,每个条目包含 `id` 和可选的 `excerpts`。它们的线程也会被计入。 |
| `discord.channels[].excerpts` | `false` | 在报告和摘要证据中包含长度受限的消息摘录。当此项为 `false` 时,消息计数仍会计入。 |
| `discord.excerptMaxChars` | `260` | 每个摘录的最大字符数;`1` 到 `4000` 之间的整数。 |
### 人员与身份 {#people-and-identity}
名册会合并 GitHub 团队成员、活跃身份条目,以及在启用时的直接协作者。使用身份条目可将某个人的 GitHub 别名和 Discord 用户 ID 关联起来:
```json5 validate=false
people: [
{
github: ["example-member", "example-member-old"],
display: "Example Member",
affiliation: "Example Company",
roleGroup: "core",
roleLabel: "Maintainer",
access: ["release"],
areas: ["documentation"],
discordUserId: "456789012345678901",
discordUsername: "example-member",
status: "active",
},
],
| 字段 | 必填 | 行为 |
|---|---|---|
github |
是 | 非空登录名数组。第一个登录名是主要身份;其余登录名是别名。 |
display |
否 | 显示名称;默认为主要登录名。 |
affiliation |
否 | 可选的隶属标签。 |
| 字段 | 必填 | 行为 |
|---|---|---|
roleGroup |
否 | 组标签,例如 core、volunteer 或 readonly;接受自定义字符串。 |
roleLabel |
否 | 人类可读的角色标签。 |
access |
否 | 自由格式标签,例如 release 或 moderation;默认为空列表。这些标签不授予权限。 |
areas |
否 | 所属领域;默认为空列表。 |
discordUserId |
否 | 用于将消息归属到此人的 Discord 身份。 |
discordUsername |
否 | 可选的 Discord 用户名元数据。 |
status |
否 | active 或 archived;省略的条目视为 active。已归档人员会从当前报告中排除,但存储的历史记录仍可用。 |
archivedAt |
否 | 归档日期,格式为 YYYY-MM-DD。 |
摘要¶
| 键 | 默认值 | 行为 |
|---|---|---|
summaries.enabled |
true |
生成由模型编写的概述、亮点和按人员划分的摘要。false 使用确定性回退文本。 |
summaries.model |
未设置 | 请求的 provider/model 引用;否则使用目标代理的默认模型。需要下方主机策略才能生效。 |
summaries.reasoning |
未设置 | 请求的思考级别:off、minimal、low、medium、high、xhigh、adaptive、max 或 ultra。主机会针对所选模型对其进行规范化。 |
summaries.agentId |
未设置 | 使用其模型和凭据的代理。跨代理选择受主机的 llm.allowAgentIdOverride 策略约束。 |
若要允许使用已配置的摘要模型,请设置
plugins.entries.team-reports.llm.allowModelOverride: true。llm 对象
是 config 的同级对象,而不是其中的字段:
```json5 validate=false "team-reports": { enabled: true, llm: { allowModelOverride: true }, config: { // Keep your github and identity configuration here. summaries: { enabled: true, model: "openai/gpt-6-astra", reasoning: "high", }, }, },
如果没有该显式选择,Team Reports 将使用目标代理的默认模型。
主机模型允许列表仍然适用。有关这些策略,请参阅
[插件 LLM 运行时](sdk-runtime.md)。
摘要基于有界的证据摘要:总计、主要
仓库和频道、选定的活动项以及已选择加入的摘录。
它们描述观察到的活动,而不是推断绩效、雇佣
或私人事实。不活跃成员仍会保留在报告中,并附低活动量说明。
插件会验证模型的 JSON 响应,并重试一次以修复
无效输出或缺失成员。如果重试失败,它会保留已收集的
报告,并显示带有可见回退横幅的确定性摘要。
输出预算随名册规模扩展;失败的模型尝试会在报告、Markdown 导出、最新一天状态和 Gateway 日志中包含一个有界的、不含凭据的原因。
未变化的证据会复用已存储的摘要,而不是再次调用模型。
收集会在摘要生成之前存储,摘要生成可能需要几分钟。
### 计划 {#schedule}
| 键 | 默认值 | 行为 |
| ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------------- |
| `schedule.closedDayUtc` | `"00:05"` | 每日运行时间,格式为 `HH:MM` UTC,在抖动之前。生成昨天的已关闭报告和今天的部分报告。 |
| `schedule.intradayEveryHours` | `4` | 在对齐的 UTC 小时边界刷新今天的报告;整数从 `0` 到 `24`。`0` 禁用日内运行。 |
| `schedule.jitterMinutes` | `5` | 添加到计划运行的最大随机延迟;整数从 `0` 到 `59`。 |
| `schedule.weekly` | `true` | 在每日收集后刷新当前 ISO 周聚合。 |
| `schedule.monthly` | `true` | 在每日收集后刷新当前月份聚合。 |
同一时间只执行一个运行。计划工作会等待活动运行;
当另一个运行处于活动状态时,手动生成会被拒绝。运行有
45 分钟截止时间。停止服务会取消其计时器,并最多等待
30 秒让活动工作完成,然后取消远程收集和摘要生成。
任何已在进行中的数据库操作以及最终运行结果都会在存储关闭前完成。
## 理解报告窗口和计数 {#understand-report-windows-and-counts}
每日窗口从 UTC 午夜到下一个 UTC 午夜,
结束时间不包含在内。今天的报告标记为 **部分**。ISO 周从
周一开始,并使用诸如 `2026-W34` 的键;月份使用诸如 `2026-08` 的键。
`displayTimezone` 仅更改时间戳标签,绝不会更改事件归属的报告。
每周和每月报告汇总已存储的每日报告。它们不会从 API 重新收集同一时间段的数据。缺失的日期会产生源警告;在依赖聚合报告的完整性之前,请先生成缺失的每日报告。
当 UTC 日期跨越周期边界时,关闭日运行也会完成包含昨天的周或月。
GitHub 合并活动计入合并该 PR 的人。提交计入作者,并且每位已映射的共同作者每人只计一次。同一操作者和同一评论类型内的相同评论在窗口内只计一次。机器人活动会被排除,非成员 GitHub 操作者会单独显示且仅显示计数。没有活动的成员仍会出现在名册中。
PR 评审提交(包括批准和请求修改的正文)不会被收集;内联评审评论会被包含。
Discord 总数包含未映射的作者,但未匹配条目仅包含作者 ID 和计数,不包含消息内容。摘录仅来自设置了 `excerpts: true` 的频道,使用折叠空白,并保留每人最新的八条。当某人的 GitHub 或 Discord 计数非零时,该人被视为活跃。
报告每人最多保留 200 条 GitHub 项目和 8 条 Discord 摘录,聚合顶级项目最多 80 条。存储的报告 JSON 上限为 2 MiB;项目列表会确定性截断,优先保留最新项目,并且报告会指示截断。因此计数可能超过显示的项目数。
## CLI 与导出 {#cli-and-exports}
CLI 与正在运行的 Gateway 通信,并支持 `--json` 以及标准 [Gateway 客户端选项](../cli/gateway.md)。读取需要 `operator.read`;生成需要 `operator.admin`。
```bash
openclaw team-reports status --json
openclaw team-reports list --json
openclaw team-reports show day 2026-08-20
openclaw team-reports show week 2026-W34 --markdown
openclaw team-reports generate --date 2026-08-20
openclaw team-reports generate --intraday
如果没有日期或 --intraday,生成会选择昨天。--intraday 选择今天;--date 接受过去的日期或今天。今天的报告仍为部分报告。未来日期,或将 --intraday 与过去日期组合使用,会被拒绝。
Reports 侧边栏选项卡会在 Control UI 外壳中打开 /reports,并前置任何已配置的 Control UI 基础路径。固定 basePath: "/reports" 会遮蔽根挂载的 Control UI /reports 页面,因此侧边栏会回退到通用的 /plugin?plugin=team-reports&id=team-reports 选项卡 URL。
使用默认 basePath 时,经过身份验证的读取者可以使用:
| 路径 | 结果 |
|---|---|
/plugins/team-reports/ |
报告索引和近期活动趋势。 |
/plugins/team-reports/latest/ |
重定向到最新的已关闭每日报告。 |
/plugins/team-reports/day/<key>/ |
每日 HTML 报告;将 day 替换为 week 或 month 以获取聚合报告。 |
/plugins/team-reports/day/<key>/report.md |
Markdown 导出;周和月也可用。 |
/plugins/team-reports/day/<key>/data.json |
结构化报告;周和月也可用。 |
/plugins/team-reports/sessions/ |
当前工作会话,并包含指向其对话的链接。 |
/plugins/team-reports/people/ |
名册索引。 |
/plugins/team-reports/people/<login>/ |
每人的历史记录、日历和 30 天趋势。 |
/plugins/team-reports/index.json |
最新键和存储周期索引。 |
/plugins/team-reports/status |
以 JSON 形式提供运行状态、计划和源警告。 |
报告和导出路由仅接受 GET 和 HEAD,并发送 Cache-Control: private,
no-store。使用 CLI 或经过身份验证的 Gateway 方法来生成报告;读取报告页面不会触发收集。
报告和运行记录位于插件拥有的数据库中,路径为 <state-dir>/plugins/team-reports/team-reports.sqlite。插件在禁用或重启时会关闭它。保留策略在关闭日生成后运行;设置 retention.days: 0 以保留所有报告历史。
故障排除¶
Reports 选项卡缺失或不可用。 确认插件已启用,如果存在 plugins.allow 则被其允许,并且 Control UI 会话具有 operator.read。配置更改会自动重新加载插件。如果修复配置后仍不可用,请运行 openclaw plugins reload team-reports。对于不可用的框架,请检查 HTTPS 或受信任的环回访问以及第三方 Cookie 策略。
尚无报告。 运行 openclaw team-reports status --json。启动追赶会等待 60 秒,并且收集或模型调用可能仍在运行。使用 generate --intraday 获取今天的部分报告。/latest/ 至少需要一个已关闭的每日报告。
某个源存在警告或报告看起来不完整。 读取状态和报告中的警告。失败运行的错误会列出每个受影响的周期和源(例如 day/2026-08-20/github)。检查 GitHub token 访问权限、组织/团队名称、排除的仓库,以及 Discord 机器人对每个已配置频道及其历史的访问权限。速率限制可能会延迟运行。在访问权限或速率限制恢复后,重新生成受影响的日期,然后刷新聚合报告。轮换文件、exec 或存储密钥后,运行 openclaw plugins reload team-reports;环境更改需要使用更新后的环境重启 Gateway。
仓库建议是可选的。返回 HTTP 403 或 404 的建议请求会计入 GitHub 源统计中的 advisoriesSkipped,而不会添加警告或将该日期标记为过期。速率限制响应仍会等待并重试;其他建议失败会保留其警告。
Discord 收集包括活跃和已归档的线程,包括论坛和媒体帖子。私有归档需要 MANAGE_THREADS 和 READ_MESSAGE_HISTORY;如果 Discord 返回 HTTP 403,收集将回退到机器人已加入的私有线程,并使用 READ_MESSAGE_HISTORY。如果两个私有归档端点都返回 HTTP 403,该频道会计入 Discord 源统计中的 privateArchivesSkipped,不产生警告或过期状态;其他失败仍保留其警告。机器人无法访问的私有线程不在报告覆盖范围内。
当名册、仓库、问题搜索、提交、评论/公告以及 Discord 收集阶段完成时,长时间运行的任务会在 Gateway 日志中输出 team-reports: 进度行。这些行包含计数和提交策略,不包含令牌或消息内容。
成员缺失或 Discord 活动未匹配。 检查 GitHub 团队名册和身份条目。将别名放在同一个 github 数组中,使用该人员的 Discord 用户 ID,并确保该条目未被归档。仅凭 discordUsername 无法将消息映射到某个人。
摘要显示回退横幅或忽略请求的模型。 检查目标代理的身份验证和默认模型、摘要设置以及主机 LLM 策略。请求的模型需要在 config 之外设置 llm.allowModelOverride: true。当模型被禁用、不可用或返回无效输出时,回退文本会保留报告。
生成提示已有运行处于活动状态。 检查 status 并等待该运行的结果。调度器会防止重叠的收集,并且每个运行都受其截止时间约束。
另请参阅:插件配置、Control UI 和 Secret 管理。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw