Community生产力与协作github.com

shimo4228/agent-stocktake

审计 Claude Code 工作目录(~/.claude/agents 或仓库的 .claude/agents)中的代理定义,并为每个代理给出评价。

agent-stocktake 是什么?

`agent-stocktake` 是一个用于审计 Claude Code 工作目录下代理定义质量的技能。它会评估每个代理定义文件(`*.md`),并给出 `保留/改进/更新/合并/降级为技能/解散/淘汰` 等评价。该技能的核心动机源于代理的双层成本模型:其描述像规则一样在会话中始终加载(驻留成本),而主体只在代理被调用时加载(调用成本)。因此,审计分为两阶段:第一阶段收集证据(包括运行脚本生成 JSON 报告、检查门禁、解析引用、统计使用量),第二阶段对每个代理进行完整评估,包括八个二进制筛选问题和针对非保留候选者的压力测试问题。该技能支持 `full`(全部审计)和 `changed`(仅审计变更文件)两种模式,并且能在同一上下文中完成所有改进,无需代理交接(除了降级为技能的情况)。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/shimo4228/harness-stocktake/tree/HEAD/skills/agent-stocktake

Installed? Explore more 生产力与协作 skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

agent-stocktake — 代理定义质量审计

评估 <harness>/agents/*.md 下的每个代理定义,并给出评价: 保留 / 改进 / 更新 / 合并 / 降级为技能 / 解散 / 淘汰。审计单位是文件,但成本单位跨越两个层级——这种分割正是此技能作为 skill-stocktake 和 rules-stocktake 之间的第三个兄弟技能存在的原因。

设计说明——混合成本模型。技能的成本是触发污染(概率性触发会降低选择精度);规则的成本是驻留(始终加载)。代理则同时具备两者:其 description 通过“可用代理类型”列表注入到每个会话中(驻留,类似规则),而其主体仅在代理被调用时加载(调用,类似技能——但由 Claude 的委托判断触发,而非通过描述匹配用户的话语)。因此,描述根据驻留密度审计,主体根据调用质量审计,每个层面都有不同的问题。

设计说明 2——批准的编辑由该技能本身在 apply 分支上应用。与 rules-stocktake 同理:不存在针对代理定义的改进引擎,并且语料库足够小,可以在一个上下文中读取——委托将会是过度工程。唯一的例外是“降级为技能”(创建技能是 skill-writer 的工作)。

根目录。 下面的 <harness> 是该审计覆盖的工作目录:默认为 ~/.claude,或者当技能 harness-stocktake 在项目模式下运行时为仓库的 .claude/(其 Roots 部分映射路径,命名那里为 n/a 的证据,并说明哪些约定检查适用)。分类账 <ledger> 属于该工作目录:当该技能的目录位于 <harness> 内时(工作目录携带其自身的技能副本),则为 ${CLAUDE_SKILL_DIR}/results.json,否则为 <harness>/stocktake/agent-stocktake.json(已安装的插件,或项目模式)。无论哪种情况,它都会在工作目录的其他更改一起在 apply 分支上提交。

模式($ARGUMENTS)

参数行为
无 / full读取并评估每个代理定义(默认)
changed仅重新评估 mtime 早于 <ledger> 的 evaluated_at 的文件;其余从分类账中沿用

changed 检测内联变更(无脚本):

以下路径以 ${CLAUDE_SKILL_DIR} 开头,即此 SKILL.md 所在的目录;不替换该变量的代理将其读取为该目录。

find <harness>/agents -name "*.md" -newermt "$(jq -r .evaluated_at "<ledger>")"

与 rules-stocktake 一样,阶段 1 的完整性检查始终在整个集合上运行——静默地淘汰技能或钩子会破坏未修改的代理主体内部的引用,而 mtime 无法察觉这一点。任何引用检查(下面的步骤 3)新失败的代理都会加入重新评估集。该脚本也没有 changed 模式,原因不同:近重复对和驻留总量是集合属性,因此部分语料库会给出错误数字,而不是更少的数字。

阶段 1——证据、清单、使用情况

步骤 1——运行证据脚本(不要手动计数)

uv run --frozen --project "${CLAUDE_SKILL_DIR}" \
       --directory "${CLAUDE_SKILL_DIR}" \
       python scripts/agent_evidence.py --root <harness>

证据模式:JSON 输出到 stdout,无论找到多少发现都退出码为 0(仅在语料库不可读时退出码为 2)。它测量和枚举;它从不分配评价。

将 JSON 转录为发现——切勿通过眼动重新测量。 它提供的内容:

JSON 字段替代内容
desc_words / body_lines / total_desc_wordswc -w / wc -l 流程
tools.items[].status + registry.known_toolsbuiltin / unverified / mcp。unverified 表示“不在脚本的日期列表中”,而非“不存在”——你拥有实时工具注册表,而脚本没有,因此在将其称为 Update 证据之前,请对照你自己的工具列表确认 unverified。registry.known_tools.as_of 是该列表的日期(当 --known-tools 替换它时为 null)
tools.items[].server_in_config + registry.mcp_config_files不是评价。 它仅说明服务器是否出现在列出的本地配置文件中——由连接器提供的服务器永远不会出现在那里,因此 false 不是“已淘汰”。null 表示未解析配置源。在使用此字段之前,请检查每个源的 status;非 ok 源旁边的 false 不是证据
unreadable扫描无法打开的文件,附有原因。非空表示扫描不完整——命名它们并在声明任何总数之前修复,因为未读文件内部的抑制指令现在被认定为不存在
tools_unparsabletools: 行未解析的代理(例如 YAML 流样式)。它们的 items 是 [],看起来与没有 tools: 键的代理相同——即无限制。但实际上并非如此;只是列表未被读取
description_near_duplicates近相同描述检查;孪生对分散了委托流量,因此每对都输入阶段 1 的重叠问题
suppression_candidates阶段 1 抑制问题的行号候选(目录是双语的,因为语料库是双语的)
always_never_candidates过度约束问题的行号候选,仅限主体——描述是委托触发器,而非对代理的指令

最后两个是候选,而非发现——在写入之前,请阅读每个引用的行。目录也是下限,而非普查:它包含从一个语料库中提取的五种措辞,因此以其他方式编写的抑制指令(“跳过你不确定的内容”、“避免仅仅成为噪音的发现”)不会出现在任何 JSON 字段中。继续阅读这些内容;空列表并非清白。

测量的假阳性比例存储在此文件之外,因此此步骤不携带会过时的数字。

步骤 2——读取已经拥有其余部分的门禁

三项检查保留在脚本之外,因为在工作目录具有 lint 门禁(<harness>/scripts/hooks/harness_lint.py)时,该门禁拥有它们。当它存在时读取其输出;没有它时,通过读取/搜索进行这三项检查:

  • 前页解析并携带 name、description、origin、model,并且 model 是别名→lint 脚本的 lint_agents(在作者的工作目录中,它在 .claude/verify.sh 和预提交钩子中运行)。在工作目录声明了来源约定的情况下,缺少来源仍然是一个完整性发现,会输入 Improve。
  • name 等于文件名主干→同一个 lint_agents。它不容许判断,并且委托注册表以它作为键,因此它属于阻止提交的门禁——而不是供读者可能转录或不转录的证据。这里的发现是阻止的提交,而不是 stocktake 评价。
  • 代理主体内部的 Markdown 链接可解析→同一个脚本的 lint_markdown_links(其范围包括 agents)。

步骤 3——解析裸路径引用(其他人都没有的检查)

lint_markdown_links 仅看到链接语法,而 skill-health 的 scan_refs.py 扫描技能树。以散文形式写在代理主体内部的路径(<harness>/hooks/foo.sh、skills/foo/SKILL.md)两者都不覆盖。使用 Grep 搜索语料库中的它们,并使用 ls 检查每个路径。

步骤 4——清单

使用 Glob 枚举:<harness>/agents/*.md。将每个文件读取到一个上下文中(语料库很小)。驻留和主体列来自步骤 1 的 JSON——切勿信任文档(包括此文档)中写入的数字。

步骤 5——使用次数

证据输入:低使用次数提名一个候选,内容决定评价。当设置保留代理使用日志(<harness>/metrics/agent-usage.jsonl;缺失 = 使用次数 n/a)时,内联读取它(使用日志记录钩子,例如 log-agent-usage.sh,每次 Agent 工具启动时追加一个 invoke 事件,以其 agent 字段为键,其值为 subagent_type)并按代理计算 7/30/90 天内的每个代理事件。使用一次性的 python3/jq 单行代码聚合。

  • 如果日志缺失或其第一个事件早于 90 天,将使用次数渲染为 —(未测量)。切勿将其渲染为 0——未测量和未使用是不同的情况。
  • 计数是下限:仅捕获 Agent(Task)工具启动。Workflow agent() 工作器、插件内部分发以及绕过工具调用的内置机制不会到达钩子。低使用次数的代理进入阶段 1 作为 Retire/Dissolve 候选;其价值可能是偶发性的(例如论文审阅者仅在存款附近触发),因此内容决定评价。
  • 日志自 2026-07-27 起存在;在该日期之前没有任何测量。

首先说明扫描结果,从步骤 1 的 JSON 中获取计数:agents_total 减去 unreadable 中的任何内容,必须命名,total_desc_words(列表的每次会话驻留税),完整性失败,以及使用次数是否可测量。将失败结果作为预先计算的证据带入阶段 1。

阶段 2——评估(完全内联,整体)

阅读每个主体同时查看整个集合。

阶段 1——二进制筛选(每个代理)。 每项明确的是/否;仅输出“否”的答案。前两个问题审计描述层(驻留),其余问题审计主体层(调用):

  • 描述值得其驻留?——在始终加载的列表中密集、独特且支持选择;说明何时委托以及何时不委托
  • 描述与主体一致?——描述承诺的内容正是主体所做的(过时的描述会在每个会话中错误地引导委托,即使主体本身没问题)
  • 主体中是否包含抑制指令?——从此代理在阶段 1 JSON 中的 suppression_candidates 开始,按步骤 1 处理。哪些算抑制指令:置信度阈值(“仅报告你 ≥ N% 确定的发现”、“为每个发现分配置信度并丢弃低置信度的”)、严重性下限(“仅高严重性”)、“保守”框架。当前的指导是:报告所有内容,在单独的步骤中过滤——抑制指令会被字面遵循并静默地丢弃发现。这里的“否”是一个通过反转改进的候选:以相反方向重写指令,切勿仅删除该部分(删除会留下抑制框架;反转会替换它)
  • 外部来源副本是最新的?——对于 origin 是外部仓库且主体是逐字复制(例如内置覆盖,如 Explore)的代理,主体开头注释中命名的源版本与已安装的工具(claude --version)匹配;不匹配则是 Update(与捆绑包进行差异比较并重新复制)。对于此类副本,跳过抑制和过度约束问题——主体是供应商的,不是我们的
  • 主体中是否包含上一代过度约束?——当前模型原生持有的详尽分步判断过程、重复强调、应由周围上下文判断拥有的 ALWAYS/NEVER 对。阶段 1 的 always_never_candidates 定位了这些标记;判断命中是直接指令还是仅仅引用这些词是这个问题的工作
  • 是否已被基底吸收?——工作目录现在是否原生覆盖了该代理的工作(原生审查机制、计划模式、内置斜杠命令)?吸收→Dissolve 候选;声明必须具体命名其吸收器。使用新鲜/丰富上下文轴进行判断:受益于新鲜上下文的角色(审查、对抗性验证、本质评估——与提议者的沉没成本去相关)合法地存在于子代理中;受益于丰富上下文的角色(规划、生成、实现——用户意图、会话内约束)是主循环工作,因此对于它们,主循环本身算作吸收器。两个辅助理由合法地覆盖丰富上下文拉力:冻结输入渲染契约——调用者在调用前冻结一个自包含包,因此会话上下文按设计不需要(prompt-forager,它特意获得一行)——以及批量上下文隔离——工作读取或产生的量会污染主上下文(researcher,每次运行一个网页搜索角度)
  • 技术引用是否最新?——无条件验证主体命名的每个工件:对每个引用路径执行 ls,对命名的命令、标志、模型名称和工具列表执行 --help/版本检查。“如果看起来过时则验证”是被禁止的措辞——条件才是稀释的东西;可确定性检查的声明每次都得到确定性检查
  • 集合内是否唯一?——没有其他代理(或技能)拥有相同的工作;有文档记录的编排器→子代理拆分不是重叠

恰好八个问题,不再增加——进一步分解会降低整体判断(见参考文献)。

阶段 2——评价压力测试(仅限非 Keep 候选)。 生成 1-3 个针对特定代理的原子化是/否问题,旨在反驳草案评价,每个问题用一行证据(文件读取、路径检查、--help、WebSearch、工作目录文档检查)回答。对于 Dissolve 候选,一个问题必须存在:“吸收性工作目录功能是否可以具体命名——是/否”——无法命名其吸收器的吸收声明即被反驳。并且当 Dissolve 即将被基底对应物所缺乏的能力(工具、已连接的子代理)反驳时,在接受反驳之前必须回答一个反问题:“子代理是使用该能力的正确位置吗——还是主循环无论如何都持有它?” 能力存在是必要但不充分的;新鲜/丰富上下文轴决定了能力属于哪里(先例:规划器反驳失败,因为主循环持有完整的 Agent 工具)。Keep 绑定代理不会获得动态问题。

评估是完整且内联的。

极少数情况的进一步阐述。 当阶段 2 问题未能引出一个干净的评价时,以下阐述适用于罕见的子案例。

“降级为技能”的路径

当代理的核心逻辑很简单(一个提示模板,没有工具路由或子代理)并且其描述与技能的 description 字段没有显著不同时,Demote to skill 是候选。此路径要求技能作者的注意:创建该技能是单独的改进。

通信层

最大引用深度为 1(直接的,非传递的)。完整性检查跟随所有已知协议:hook、技能、技能的选择文档、子技能、规则、子规则、提示文件。外部参考仅在说“来源 X 现在做 Y”时被检查——即,直接链接到工具的发布说明或已知的 API 变更。

输出结构

每个工作目录一个有效的 JSON 对象。写入 <ledger>。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能