Claude Skill

compact-bensz-skills

当用户明确要求“压缩/瘦身/精简某个 Agent Skill 的 Markdown 文档”“在不改变功能前提下降低 skill 上下文开销”时使用。先理解目标 skill 的真实能力与安全边界,再在忽略 `tests/`、`plans/` 以及目标 skill 的 `README.md`、`CHANGELOG.md` 的前提下,压缩 `SKILL.md`、`references/*.md` 等工作型 Markdown,并把中间产物隔离到 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skill

LLM Mart · 0 points · 21 views 5 listing impressions 0 install-command copies

#agent-skills

Virus-scanned Reviewed automatically before listing.

Full trust report

Download huangwb8-skills-skills_alpha_compact-bensz-skills-dd1fab8.zip · 20 KB
Part of huangwb8/skills — 22 skills

Install

skills CLI npx skills add https://github.com/huangwb8/skills/tree/main/skills/alpha/compact-bensz-skills
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install huangwb8-skills@llmmart
Git git clone https://github.com/huangwb8/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole huangwb8/skills collection as a plugin from our marketplace. Git is the plain clone.

README

compact-bensz-skills

compact-bensz-skills 用来压缩某个 Agent Skill 里的工作型 Markdown 文档,目标是在不改变原有功能的前提下,显著降低上下文体积。

最推荐用法

请使用 compact-bensz-skills skill 压缩这个 Agent Skill 的工作型 Markdown 文档。
输入:/path/to/target-skill
输出:更新后的 skill 源文件;所有中间文件保存在目标目录下的 .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/

适用场景

  • 目标 skill 的 SKILL.mdreferences/*.md 明显冗长
  • 你希望节省上下文,但不想动脚本逻辑
  • 你需要先理解 skill,再做保守压缩

默认行为

  • 工作区根:<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/
  • 每次运行目录:<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/
  • 最近一次运行指针:<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt
  • 测试区:<skill_root>/tests/compact-bensz-skills/
  • 自动忽略:tests/plans/、目标 skill 根目录下的 README.mdCHANGELOG.md
  • 优先保留:frontmatter、输入输出契约、安全边界、命令与路径
  • 如果你显式指定外部 workspace_dir,脚本会接受,但验证报告会提示“中间文件已离开 skill 根目录”

常用示例

示例 1:压缩单个 skill

请使用 compact-bensz-skills skill 压缩 `git-pr-review` 这个 skill 的工作型 Markdown 文档。
输入:/workspace/skills/git-pr-review
输出:原 skill 目录内更新后的 Markdown;中间文件放到 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/`

示例 2:指定额外约束

请使用 compact-bensz-skills skill 压缩这个 skill 的工作型 Markdown。
输入:/workspace/skills/my-skill
输出:更新后的 skill 源文件
另外,还有下列参数约束:
- 只压缩 Markdown,不改 Python/Bash 脚本
- 默认不要动 README.md / CHANGELOG.md
- 不要改变 SKILL.md frontmatter 的 name
- 压缩完成后要输出压缩前后统计

运行时会生成什么

  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/file-inventory.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/compaction-plan.md
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-before.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-after.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-delta.md
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/validation.json

备选用法(脚本)

python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill
python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --phase after
python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill

如果你想显式锁定某一轮:

python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill
# 记下输出里的 run_id
python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --run-id 2026-03-28-15-52 --phase after
python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill --run-id 2026-03-28-15-52

WHICHMODEL

最后核对:2026-03-28。

  • OpenAI 路线:
    • 复杂 skill 压缩、跨多份 references/ 去重、需要保守保留约束时,优先 gpt-5.4;OpenAI 官方把它列为复杂推理、coding 和 agentic workflows 的起点。
    • 如果你主要在 Codex 里工作,且任务是“读文档 + 改文档 + 跑脚本验证”的 agentic coding 流程,可优先 gpt-5-codex;官方说明它是面向 Codex 一类环境优化的 agentic coding 模型。
    • 只做轻量统计、跑 helper scripts、整理测试记录时,可降到 gpt-5.4-mini 或同级快模型。
  • Anthropic 路线:
    • 最复杂的压缩任务优先 Opus;Anthropic 官方建议复杂任务先从 Opus 开始。
    • 日常 skill 压缩、文档改写和一般验证优先 Sonnet;官方将其定位为速度与智能的最佳平衡,并在 Claude Code 中作为日常 coding 默认推荐档位。
    • 只做简单检查或批量轻任务时可用 Haiku
  • 长上下文优先级:
    • 如果目标 skill 很大,优先选支持更长上下文的模型。OpenAI 当前前沿模型页给 gpt-5.4 标注了 1M context;Anthropic 也为 Sonnet/Opus 提供了 1M context 选项或长会话模式。

参考:

FAQ

它会改 tests/plans/ 吗?

不会。这个 skill 默认忽略目标 skill 里的 tests/plans/

它会处理 README.mdCHANGELOG.md 吗?

默认不会。这个 skill 只把工作型 Markdown 视为主要目标;目标 skill 根目录下的 README.mdCHANGELOG.md 一般属于面向人类的说明或发布记录,不纳入默认压缩范围。

它会自动改脚本代码吗?

默认不会。它的核心目标是压缩 Markdown 文档;只有当文档与脚本明显不一致时,才应先指出风险,再做最小修正。

它怎么保证不破坏功能?

它要求先理解 SKILL.mdconfig.yamlscripts/,然后再压缩文档,并在最后运行统计和校验脚本。

为什么现在要用 `

因为这个 skill 可能会反复执行。按分钟级 run 目录隔离后,每一轮的快照、统计和验证结果都能独立追溯,不会被下一轮覆盖;同一分钟重复运行时脚本会自动追加后缀。

它会检查相对链接是否越界吗?

会。validate_compaction.py 现在不仅检查链接是否存在,也会拒绝链接跳出目标 skill 根目录。

Skill manifest

compact-bensz-skills

目标

当用户明确要求“压缩/瘦身/精简某个 Agent Skill 的 Markdown 文档”“在不改变功能前提下降低 skill 上下文开销”时使用。先理解目标 skill 的真实能力与安全边界,再在忽略 tests/plans/ 以及目标 skill 的 README.mdCHANGELOG.md 的前提下,压缩 SKILL.mdreferences/*.md 等工作型 Markdown,并把中间产物隔离到 .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/。⚠️ 不适用:用户主要想新增功能、修复脚本逻辑、批量改代码、或只想压缩非 skill 文档。

流程

输入

输入

  1. skill_root(必需)
    • 目标 Agent Skill 根目录
  2. workspace_dir(可选)
    • 默认把本轮工作区建在 <skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/
    • 如果用户显式指定其它目录,则把它视为“run 容器根目录”,本轮仍落到其中的 {yyyy-mm-dd-hh-mm}/
  3. run_id(可选)
    • 用于在 init -> measure -> validate 间显式复用同一轮工作区
  4. test_dir(可选)
    • 默认 <skill_root>/tests/compact-bensz-skills/

执行步骤

核心原则

  • 先理解,再压缩:先读 SKILL.mdconfig.yamlscripts/ 和必要的 references/,再判断哪些 Markdown 可以缩短。
  • 不改行为,只改表达:压缩的是文档体积,不是功能边界;不得擅自新增、删除或扭曲目标 skill 的能力。
  • 保护触发语义SKILL.md frontmatter 的 name 必须保持不变;description 只能等价压缩,不能丢失关键触发条件。
  • 保护硬约束:输入、输出、默认路径、安全限制、必跑脚本、失败条件、与其它 skill 的协作约定都必须保留。
  • 只动源工作文件:忽略目标 skill 的 tests/plans/ 及其内容,不把它们视为待压缩源文件。
  • 默认不动说明文档:目标 skill 根目录下的 README.mdCHANGELOG.md 一般属于面向人类的说明或发布记录,不视为默认压缩目标。
  • 中间文件隔离:分析、快照、统计、验证结果都写到隐藏目录 .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/;除非用户另有指定,不向外泄露中间文件。
  • 按轮次隔离:每次运行都应在 .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/ 内工作,避免多次压缩会话互相覆盖。
  • 链接不能越界:压缩后保留的本地 Markdown 链接必须仍位于目标 skill 根目录内,不能借相对路径跳到 skill 外部。

标准工作流

1. 初始化隐藏工作区

优先使用确定性脚本创建工作区、快照和 Markdown 清单:

python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill

脚本会:

  • 创建 <skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/
  • 在隐藏根目录写入 latest-run.txt
  • 扫描待压缩 Markdown(忽略 tests/plans/README.mdCHANGELOG.md
  • 生成 analysis/file-inventory.json
  • 备份原文到 snapshots/before/
  • 生成 analysis/compaction-plan.md
  • 记录压缩前统计到 reports/size-before.json
2. 理解目标 skill 的真实功能

最低阅读范围:

  • SKILL.md
  • config.yaml(如存在)
  • scripts/(如存在)
  • references/ 中与核心流程直接相关的文档
  • 仅当 README.mdCHANGELOG.md 与核心行为边界强相关时才辅助阅读;默认不把它们纳入压缩目标

理解时重点确认:

  • 技能触发条件与不适用范围
  • 输入输出契约
  • 默认工作区 / 测试区 / 中间文件路径
  • 安全边界与只读/只写限制
  • 任何“必须执行”“不得省略”的步骤
3. 执行 Markdown 压缩

优先顺序:

  1. 删重复:移除跨文件、跨章节重复解释
  2. 缩长句:把啰嗦描述改成短句、表格或清单
  3. 主从分离:SKILL.md 只保留触发逻辑、主流程、硬约束;细节下沉到 references/
  4. 压示例:保留最小可用命令和最关键示例,删除低价值变体

默认优先处理:

  • SKILL.md
  • references/ 中真正承载执行细则的 Markdown

默认不处理:

  • 目标 skill 根目录下的 README.md
  • 目标 skill 根目录下的 CHANGELOG.md

压缩时必须保留:

  • SKILL.md frontmatter 与关键词可发现性
  • 关键命令、路径、文件名、配置键
  • 输入/输出、默认目录、安全限制
  • 会改变行为的条件分支
  • bensz-collect-bugs 等跨 skill 约定

压缩时禁止:

  • 把“必需”改成“可选”
  • 删除失败条件、边界条件、路径约束
  • 删除唯一的命令示例或唯一的输出说明
  • 只为了省字而制造歧义
4. 复测压缩收益

完成文档修改后重新统计:

python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --phase after

如需显式复用某一轮:

python3 compact-bensz-skills/scripts/measure_markdown.py \
  --skill-root /path/to/target-skill \
  --run-id 2026-03-28-15-52 \
  --phase after

该脚本会输出:

  • reports/size-after.json
  • reports/size-delta.md
5. 校验压缩后仍可用
python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill

默认会复用 latest-run.txt 指向的最近一轮;如果你在多个 run 之间切换,显式传 --run-id 更稳妥。

至少检查:

  • SKILL.md frontmatter 是否完整
  • metadata.author 是否保留
  • metadata.keywords 是否仍包含 skill 名
  • 本地 Markdown 相对链接是否仍有效且没有越出目标 skill 根目录
  • 压缩后的总字数是否低于压缩前
  • description 有改动,确认只是等价压缩而非改坏触发语义

何时读取参考文档

  • 需要决定“哪些内容必须保留”时,读 references/preservation-checklist.md
  • 需要具体压缩手法时,读 references/compaction-playbook.md
  • 做收尾校验时,读 references/validation-checklist.md

输出

输出

对用户的主要交付:

  • 更新后的目标 skill 工作型 Markdown 源文件

隐藏工作区产物:

  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/file-inventory.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/compaction-plan.md
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-before.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-after.json
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-delta.md
  • .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/validation.json

输出管理

BenszAPI 任务工作区

校验

至少检查 frontmatter、metadata.author、技能关键词、相对链接、关键命令/路径/失败条件和触发语义均保留;压缩后的 Markdown 总量应低于压缩前,且 validate_compaction.py 与引用检查通过。不能证明语义等价时不得交付压缩版本。

失败与恢复

快照、统计、链接或语义校验失败时保留 snapshots/before/、报告和错误日志,停止写回正式 Skill;可在同一 run 目录修正后重试,若收益或保真无法满足阈值则恢复基线并报告原因。

约束

公共硬约束

本块由 docs/templates/skill-common-constraints.md 统一维护;每个 SKILL.md## 约束 必须逐字同步本块,不得在副本中改写公共规则。

  • 任务需要落盘时,使用唯一的 ./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/ 根目录;共享材料放入 shared/,Skill 专属材料放入该 Skill 的 input/output/log/
  • 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
  • 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
  • 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
  • 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
  • Skill 版本唯一记录在自身 config.yaml:skill_info.version;公开 API、协议、目录或配置变更同步文档与 CHANGELOG.md
  • bensz-collect-bugs 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 ~/.bensz-skills/bugs/,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
Files (skills)
  • references
    • compaction-playbook.md 1.7 KB
      # 压缩操作手册
      
      ## 目标
      
      把一个 Agent Skill 的工作型 Markdown 文档压短,但不破坏:
      - 触发语义
      - 输入输出契约
      - 安全边界
      - 默认路径与关键命令
      
      ## 推荐顺序
      
      1. 先压 `SKILL.md`
      2. 再压 `references/` 中真正会被频繁读取的文档
      3. 默认不要把目标 skill 根目录下的 `README.md`、`CHANGELOG.md` 当成压缩目标
      
      ## 常用压缩手法
      
      ### 1. 删除重复解释
      
      - 同一条规则只保留在最合适的一处
      - `SKILL.md` 里保留摘要,细节放 `references/`
      - 面向人类的说明文档默认不纳入压缩范围;若只为省字而改它们,往往是在压错对象
      
      ### 2. 缩短句子
      
      - 一段只表达一个决策
      - 把“原因 + 例外 + 重复铺垫”改成短句
      - 长段落优先改为 3-5 条扁平 bullet
      
      ### 3. 合并低价值示例
      
      - 保留最小可用示例
      - 删除只是在换措辞、没有新增约束的信息
      - 多个相近命令只保留主路径,其他写成“按需替换参数”
      
      ### 4. 主从分离
      
      - `SKILL.md`:触发条件、主流程、硬约束、关键命令
      - `references/`:详细检查清单、延伸案例、设计哲学
      
      ### 5. 把软建议和硬约束分开
      
      - 硬约束必须留在主文档
      - 经验性建议可以下沉到 `references/`
      
      ## 常见误伤
      
      - 删除唯一的默认路径说明
      - 把“不适用”删掉,导致 skill 误触发
      - 把“必须执行”缩成“建议执行”
      - 把输出文件名删掉,导致无法验收
      
      ## 简单判断标准
      
      如果删掉一句话后,会让以下任一问题变得更难回答,就不要删:
      - 什么时候触发这个 skill?
      - 输入是什么?
      - 输出是什么?
      - 中间文件去哪?
      - 哪些事不能做?
      
    • preservation-checklist.md 891 B
      # 保留清单
      
      压缩前后,至少逐项确认以下信息没有丢失。
      
      ## SKILL.md frontmatter
      
      - `name`
      - `description`
      - `metadata.author`
      - `metadata.keywords`
      - `metadata.keywords` 仍包含 skill 名
      
      ## 触发与边界
      
      - 什么时候应该用这个 skill
      - 什么时候不该用
      - 用户最小输入是什么
      - 最终输出是什么
      
      ## 行为约束
      
      - 默认工作区 / 隐藏目录
      - 测试区或测试约束
      - 只读/只写边界
      - 必须执行的步骤
      - 失败时的处理方式
      
      ## 关键实现信息
      
      - 唯一或主要命令示例
      - 关键脚本路径
      - 配置文件路径或关键配置键
      - 会影响行为的文件命名规则
      - 默认待压缩范围是否仍限定在工作型 Markdown,而非 `README.md` / `CHANGELOG.md`
      
      ## 跨 skill 约定
      
      - 与 `bensz-collect-bugs` 的协作约定
      - 与 `parallel-vibe`、`auto-test-skill` 等强依赖 skill 的衔接方式
      
    • validation-checklist.md 902 B
      # 校验清单
      
      ## 结构校验
      
      - `SKILL.md` 仍然存在
      - frontmatter 合法
      - 关键 Markdown 链接未失效,且没有跳出目标 skill 根目录
      - `checked_files` 没有把目标 skill 根目录下的 `README.md`、`CHANGELOG.md` 当成默认压缩对象
      - 中间文件都在 `.compact-bensz-skills/run-{timestamp}/`
      - `latest-run.txt` 指向的是本次验证对应的 run
      
      ## 语义校验
      
      - 触发条件没有变窄或变偏
      - 不适用范围仍然存在
      - 安全限制仍然清楚
      - 输入/输出/默认目录仍然可回答
      
      ## 收益校验
      
      - 总字数下降
      - 最大文件的字数明显下降,或有合理解释
      - `SKILL.md` 比修改前更短、更聚焦
      
      ## 风险提示
      
      如果出现以下情况,应停止并回看快照:
      - frontmatter 被改坏
      - 关键命令消失
      - 输出文件名或路径说明消失
      - 只读/只写限制被删
      - 关键链接改成了越界相对路径
      
  • scripts
    • common.py 9.9 KB
      from __future__ import annotations
      
      import fnmatch
      import json
      import re
      import shutil
      from datetime import datetime
      from pathlib import Path
      from typing import Any
      
      try:
          import yaml
      except ModuleNotFoundError as exc:  # pragma: no cover - import guard
          raise SystemExit(
              "缺少 PyYAML 依赖,无法读取 compact-bensz-skills/config.yaml。请先安装 pyyaml。"
          ) from exc
      
      
      FRONTMATTER_RE = re.compile(r"\A---\n(.*?)\n---\n?", re.DOTALL)
      WORD_RE = re.compile(r"[A-Za-z0-9_]+|[\u4e00-\u9fff]")
      HEADING_RE = re.compile(r"^#{1,6}\s", re.MULTILINE)
      FENCE_RE = re.compile(r"^```", re.MULTILINE)
      LOCAL_LINK_RE = re.compile(r"\[[^\]]+\]\(([^)]+)\)")
      
      
      def skill_dir() -> Path:
          return Path(__file__).resolve().parent.parent
      
      
      def load_config() -> dict[str, Any]:
          config_path = skill_dir() / "config.yaml"
          return yaml.safe_load(config_path.read_text(encoding="utf-8"))
      
      
      def resolve_skill_root(skill_root: str) -> Path:
          path = Path(skill_root).expanduser().resolve()
          if not path.is_dir():
              raise SystemExit(f"skill_root 不存在或不是目录: {path}")
          if not (path / "SKILL.md").exists():
              raise SystemExit(f"目标目录缺少 SKILL.md: {path}")
          return path
      
      
      def resolve_workspace_root(
          target_skill_root: Path,
          config: dict[str, Any],
          workspace_dir: str | None = None,
          run_id: str | None = None,
          create: bool = False,
      ) -> Path:
          workspace_base, explicit_run_id = resolve_workspace_base(target_skill_root, config, workspace_dir)
          effective_run_id = run_id or explicit_run_id
          if effective_run_id is None:
              if create:
                  effective_run_id = allocate_unique_run_id(workspace_base, config, generate_run_id(config))
              else:
                  effective_run_id = read_latest_run_id(workspace_base, config)
                  if effective_run_id is None:
                      raise SystemExit(
                          "未找到可复用的 run 目录。请先运行 init_workspace.py,或显式传入 --run-id。"
                      )
          return workspace_base / effective_run_id
      
      
      def resolve_workspace_base(
          target_skill_root: Path,
          config: dict[str, Any],
          workspace_dir: str | None = None,
      ) -> tuple[Path, str | None]:
          if workspace_dir:
              candidate = Path(workspace_dir).expanduser().resolve()
              if is_run_dir_name(candidate.name, config):
                  return candidate.parent, candidate.name
              return candidate, None
          return target_skill_root / config["workspace"]["hidden_dir"], None
      
      
      def generate_run_id(config: dict[str, Any]) -> str:
          prefix = config["workspace"]["run_prefix"]
          timestamp_format = config["workspace"]["timestamp_format"]
          return f"{prefix}{datetime.now().strftime(timestamp_format)}"
      
      
      def is_run_dir_name(name: str, config: dict[str, Any]) -> bool:
          prefix = config["workspace"]["run_prefix"]
          timestamp_format = config["workspace"]["timestamp_format"]
          sample = datetime(2000, 1, 2, 3, 4, 5).strftime(timestamp_format)
          digit_pattern = "".join(r"\d" if ch.isdigit() else re.escape(ch) for ch in sample)
          pattern = rf"^{re.escape(prefix)}{digit_pattern}(?:-\d{{2}})?$"
          return re.match(pattern, name) is not None
      
      
      def allocate_unique_run_id(workspace_base: Path, config: dict[str, Any], base_run_id: str) -> str:
          if not (workspace_base / base_run_id).exists():
              return base_run_id
          for idx in range(2, 100):
              candidate = f"{base_run_id}-{idx:02d}"
              if not (workspace_base / candidate).exists():
                  return candidate
          raise SystemExit(f"无法在 {workspace_base} 下分配唯一 run 目录: {base_run_id}")
      
      
      def latest_run_pointer_path(workspace_base: Path, config: dict[str, Any]) -> Path:
          return workspace_base / config["workspace"]["latest_run_pointer"]
      
      
      def write_latest_run_id(workspace_base: Path, config: dict[str, Any], run_id: str) -> None:
          pointer = latest_run_pointer_path(workspace_base, config)
          pointer.parent.mkdir(parents=True, exist_ok=True)
          pointer.write_text(run_id + "\n", encoding="utf-8")
      
      
      def read_latest_run_id(workspace_base: Path, config: dict[str, Any]) -> str | None:
          pointer = latest_run_pointer_path(workspace_base, config)
          if not pointer.exists():
              return None
          run_id = pointer.read_text(encoding="utf-8").strip()
          return run_id or None
      
      
      def path_within(base_dir: Path, target: Path) -> bool:
          try:
              target.resolve().relative_to(base_dir.resolve())
              return True
          except ValueError:
              return False
      
      
      def workspace_subpaths(config: dict[str, Any], workspace_root: Path) -> dict[str, Path]:
          subpaths = {name: workspace_root / name for name in config["workspace"]["subdirs"]}
          subpaths["workspace_root"] = workspace_root
          subpaths["workspace_base"] = workspace_root.parent
          subpaths["before_snapshot_dir"] = workspace_root / config["workspace"]["before_snapshot_dir"]
          for key, relative_path in config["reports"].items():
              subpaths[key] = workspace_root / relative_path
          return subpaths
      
      
      def ensure_workspace(config: dict[str, Any], workspace_root: Path) -> dict[str, Path]:
          paths = workspace_subpaths(config, workspace_root)
          for path in paths.values():
              if path == paths["workspace_base"]:
                  path.mkdir(parents=True, exist_ok=True)
                  continue
              if path.suffix:
                  path.parent.mkdir(parents=True, exist_ok=True)
              else:
                  path.mkdir(parents=True, exist_ok=True)
          return paths
      
      
      def should_ignore_path(relative_path: Path, config: dict[str, Any]) -> bool:
          ignore_dirs = set(config["source_files"]["ignore_dirs"])
          if any(part in ignore_dirs for part in relative_path.parts[:-1]):
              return True
          ignore_file_names = set(config["source_files"].get("ignore_file_names", []))
          if relative_path.name in ignore_file_names:
              return True
          ignore_globs = config["source_files"]["ignore_globs"]
          return any(fnmatch.fnmatch(relative_path.name, pattern) for pattern in ignore_globs)
      
      
      def iter_markdown_files(
          target_skill_root: Path,
          config: dict[str, Any],
          workspace_root: Path,
      ) -> list[Path]:
          markdown_exts = set(config["source_files"]["markdown_extensions"])
          files: list[Path] = []
          for path in sorted(target_skill_root.rglob("*")):
              if not path.is_file():
                  continue
              if path.suffix.lower() not in markdown_exts:
                  continue
              try:
                  relative_path = path.relative_to(target_skill_root)
              except ValueError:
                  continue
              if workspace_root in path.parents or path == workspace_root:
                  continue
              if should_ignore_path(relative_path, config):
                  continue
              files.append(path)
          return files
      
      
      def read_text(path: Path) -> str:
          return path.read_text(encoding="utf-8")
      
      
      def compute_text_stats(text: str) -> dict[str, int]:
          return {
              "chars": len(text),
              "words": len(WORD_RE.findall(text)),
              "lines": text.count("\n") + (0 if not text else 1),
              "headings": len(HEADING_RE.findall(text)),
              "fence_markers": len(FENCE_RE.findall(text)),
          }
      
      
      def compute_file_record(target_skill_root: Path, path: Path) -> dict[str, Any]:
          text = read_text(path)
          record = {"path": str(path.relative_to(target_skill_root))}
          record.update(compute_text_stats(text))
          return record
      
      
      def build_totals(records: list[dict[str, Any]], phase: str) -> dict[str, Any]:
          return {
              "phase": phase,
              "file_count": len(records),
              "total_chars": sum(int(record["chars"]) for record in records),
              "total_words": sum(int(record["words"]) for record in records),
              "total_lines": sum(int(record["lines"]) for record in records),
              "total_headings": sum(int(record["headings"]) for record in records),
              "total_fence_markers": sum(int(record["fence_markers"]) for record in records),
              "files": records,
          }
      
      
      def write_json(path: Path, payload: dict[str, Any] | list[Any]) -> None:
          path.parent.mkdir(parents=True, exist_ok=True)
          path.write_text(
              json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=False) + "\n",
              encoding="utf-8",
          )
      
      
      def write_text(path: Path, text: str) -> None:
          path.parent.mkdir(parents=True, exist_ok=True)
          path.write_text(text, encoding="utf-8")
      
      
      def snapshot_files(target_skill_root: Path, files: list[Path], snapshot_root: Path) -> None:
          if snapshot_root.exists():
              shutil.rmtree(snapshot_root)
          for file_path in files:
              relative_path = file_path.relative_to(target_skill_root)
              destination = snapshot_root / relative_path
              destination.parent.mkdir(parents=True, exist_ok=True)
              shutil.copy2(file_path, destination)
      
      
      def parse_frontmatter(text: str) -> tuple[dict[str, Any], str]:
          match = FRONTMATTER_RE.match(text)
          if not match:
              return {}, text
          data = yaml.safe_load(match.group(1)) or {}
          body = text[match.end() :]
          return data, body
      
      
      def nested_get(data: dict[str, Any], dotted_key: str) -> Any:
          value: Any = data
          for part in dotted_key.split("."):
              if not isinstance(value, dict) or part not in value:
                  return None
              value = value[part]
          return value
      
      
      def normalize_link_target(target: str) -> str | None:
          cleaned = target.strip()
          if not cleaned or cleaned.startswith("#"):
              return None
          if "://" in cleaned or cleaned.startswith("mailto:"):
              return None
          return cleaned.split("#", 1)[0]
      
      
      def find_local_link_issues(
          base_file: Path,
          text: str,
          target_skill_root: Path,
      ) -> list[str]:
          issues: list[str] = []
          for raw_target in LOCAL_LINK_RE.findall(text):
              normalized = normalize_link_target(raw_target)
              if not normalized:
                  continue
              resolved = (base_file.parent / normalized).resolve()
              if not path_within(target_skill_root, resolved):
                  issues.append(f"本地链接越出 skill 根目录 -> {raw_target}")
                  continue
              if not resolved.exists():
                  issues.append(f"本地链接不存在 -> {raw_target}")
          return issues
      
    • init_workspace.py 3.8 KB
      #!/usr/bin/env python3
      from __future__ import annotations
      
      import argparse
      
      from common import (
          build_totals,
          compute_file_record,
          ensure_workspace,
          iter_markdown_files,
          load_config,
          path_within,
          resolve_skill_root,
          resolve_workspace_root,
          snapshot_files,
          write_latest_run_id,
          write_json,
          write_text,
      )
      
      
      def build_plan(records: list[dict[str, object]]) -> str:
          top_records = sorted(records, key=lambda item: item["words"], reverse=True)[:5]
          lines = [
              "# 压缩计划",
              "",
              "## 当前判断",
              "",
              "- 先阅读 `SKILL.md`、`config.yaml` 与关键脚本,再决定哪些文档可以缩短。",
              "- `tests/`、`plans/`、`README.md`、`CHANGELOG.md` 已被排除,不作为默认待压缩源文件。",
              "- 优先压缩字数最高、重复解释最多的 Markdown 文件。",
              "",
              "## 优先处理文件",
              "",
          ]
          if not top_records:
              lines.append("- 暂无待处理 Markdown 文件")
          else:
              for record in top_records:
                  lines.append(f"- `{record['path']}`:约 {record['words']} 词,{record['chars']} 字符")
          lines.extend(
              [
                  "",
                  "## 必保留信息",
                  "",
                  "- frontmatter 中的 `name`、`description`、`metadata.author`",
                  "- 关键命令、关键路径、默认输出",
                  "- 安全限制与不适用范围",
                  "",
                  "## 完成后必做",
                  "",
                  "- 重新运行 `measure_markdown.py --phase after`",
                  "- 运行 `validate_compaction.py`",
              ]
          )
          return "\n".join(lines) + "\n"
      
      
      def main() -> None:
          parser = argparse.ArgumentParser(description="初始化 compact-bensz-skills 隐藏工作区")
          parser.add_argument("--skill-root", required=True, help="目标 skill 根目录")
          parser.add_argument("--workspace-dir", help="自定义隐藏工作区")
          parser.add_argument("--run-id", help="显式指定 run 目录名,例如 run-20260328194500")
          args = parser.parse_args()
      
          config = load_config()
          target_skill_root = resolve_skill_root(args.skill_root)
          workspace_root = resolve_workspace_root(
              target_skill_root,
              config,
              args.workspace_dir,
              run_id=args.run_id,
              create=True,
          )
          paths = ensure_workspace(config, workspace_root)
          write_latest_run_id(paths["workspace_base"], config, workspace_root.name)
      
          markdown_files = iter_markdown_files(target_skill_root, config, workspace_root)
          snapshot_files(target_skill_root, markdown_files, paths["before_snapshot_dir"])
          records = [compute_file_record(target_skill_root, path) for path in markdown_files]
          inventory = {
              "skill_root": str(target_skill_root),
              "workspace_base": str(paths["workspace_base"]),
              "workspace_root": str(workspace_root),
              "run_id": workspace_root.name,
              "workspace_inside_skill_root": path_within(target_skill_root, workspace_root),
              "file_count": len(records),
              "files": records,
          }
          totals = build_totals(records, phase="before")
      
          write_json(paths["inventory_json"], inventory)
          write_json(paths["size_before_json"], totals)
          write_text(paths["plan_markdown"], build_plan(records))
      
          print(f"workspace_base={paths['workspace_base']}")
          print(f"workspace_root={workspace_root}")
          print(f"run_id={workspace_root.name}")
          print(f"inventory={paths['inventory_json']}")
          print(f"snapshot_dir={paths['before_snapshot_dir']}")
          print(f"size_before={paths['size_before_json']}")
          if not inventory["workspace_inside_skill_root"]:
              print("warning=workspace_dir 位于目标 skill 根目录之外;这只应在用户明确指定时使用")
      
      
      if __name__ == "__main__":
          main()
      
    • measure_markdown.py 2.9 KB
      #!/usr/bin/env python3
      from __future__ import annotations
      
      import argparse
      
      from common import (
          build_totals,
          compute_file_record,
          ensure_workspace,
          iter_markdown_files,
          load_config,
          resolve_skill_root,
          resolve_workspace_root,
          write_json,
          write_text,
      )
      
      
      def format_delta(before: dict[str, int], after: dict[str, int]) -> str:
          delta_words = after["total_words"] - before["total_words"]
          delta_chars = after["total_chars"] - before["total_chars"]
          lines = [
              "# 压缩统计对比",
              "",
              f"- 压缩前总词数:{before['total_words']}",
              f"- 压缩后总词数:{after['total_words']}",
              f"- 词数变化:{delta_words}",
              f"- 压缩前总字符数:{before['total_chars']}",
              f"- 压缩后总字符数:{after['total_chars']}",
              f"- 字符变化:{delta_chars}",
              "",
              "## 当前最大文件",
              "",
          ]
          for record in sorted(after["files"], key=lambda item: item["words"], reverse=True)[:5]:
              lines.append(f"- `{record['path']}`:{record['words']} 词,{record['chars']} 字符")
          return "\n".join(lines) + "\n"
      
      
      def main() -> None:
          parser = argparse.ArgumentParser(description="统计目标 skill Markdown 体积")
          parser.add_argument("--skill-root", required=True, help="目标 skill 根目录")
          parser.add_argument(
              "--phase",
              default="after",
              choices=["before", "after"],
              help="写入前/后统计文件",
          )
          parser.add_argument("--workspace-dir", help="自定义隐藏工作区")
          parser.add_argument("--run-id", help="复用 init_workspace.py 创建的 run 目录名")
          args = parser.parse_args()
      
          config = load_config()
          target_skill_root = resolve_skill_root(args.skill_root)
          workspace_root = resolve_workspace_root(
              target_skill_root,
              config,
              args.workspace_dir,
              run_id=args.run_id,
          )
          paths = ensure_workspace(config, workspace_root)
          markdown_files = iter_markdown_files(target_skill_root, config, workspace_root)
          records = [compute_file_record(target_skill_root, path) for path in markdown_files]
          totals = build_totals(records, phase=args.phase)
      
          output_key = "size_before_json" if args.phase == "before" else "size_after_json"
          write_json(paths[output_key], totals)
      
          before_path = paths["size_before_json"]
          after_path = paths["size_after_json"]
          if before_path.exists() and after_path.exists():
              import json
      
              before = json.loads(before_path.read_text(encoding="utf-8"))
              after = json.loads(after_path.read_text(encoding="utf-8"))
              write_text(paths["size_delta_markdown"], format_delta(before, after))
      
          print(f"workspace_root={workspace_root}")
          print(f"run_id={workspace_root.name}")
          print(f"{args.phase}_stats={paths[output_key]}")
          if paths["size_delta_markdown"].exists():
              print(f"delta_report={paths['size_delta_markdown']}")
      
      
      if __name__ == "__main__":
          main()
      
    • validate_compaction.py 4.7 KB
      #!/usr/bin/env python3
      from __future__ import annotations
      
      import argparse
      import json
      from pathlib import Path
      
      from common import (
          build_totals,
          compute_file_record,
          ensure_workspace,
          find_local_link_issues,
          iter_markdown_files,
          load_config,
          nested_get,
          path_within,
          parse_frontmatter,
          read_text,
          resolve_skill_root,
          resolve_workspace_root,
          write_json,
      )
      
      
      def main() -> None:
          parser = argparse.ArgumentParser(description="校验压缩后的 skill Markdown")
          parser.add_argument("--skill-root", required=True, help="目标 skill 根目录")
          parser.add_argument("--workspace-dir", help="自定义隐藏工作区")
          parser.add_argument("--run-id", help="复用 init_workspace.py 创建的 run 目录名")
          args = parser.parse_args()
      
          config = load_config()
          target_skill_root = resolve_skill_root(args.skill_root)
          workspace_root = resolve_workspace_root(
              target_skill_root,
              config,
              args.workspace_dir,
              run_id=args.run_id,
          )
          paths = ensure_workspace(config, workspace_root)
          markdown_files = iter_markdown_files(target_skill_root, config, workspace_root)
      
          errors: list[str] = []
          warnings: list[str] = []
          skill_md = target_skill_root / "SKILL.md"
          frontmatter, skill_body = parse_frontmatter(read_text(skill_md))
      
          for dotted_key in config["preservation"]["required_skill_frontmatter_fields"]:
              if nested_get(frontmatter, dotted_key) in (None, "", []):
                  errors.append(f"SKILL.md frontmatter 缺少必需字段: {dotted_key}")
      
          if nested_get(frontmatter, "name") != target_skill_root.name:
              warnings.append(
                  "SKILL.md frontmatter.name 与目录名不一致;若这是历史兼容设计可忽略,否则建议修正"
              )
      
          keywords = nested_get(frontmatter, "metadata.keywords") or []
          if config["preservation"]["required_skill_keywords_include_name"] and nested_get(
              frontmatter, "name"
          ) not in keywords:
              errors.append("metadata.keywords 未包含 skill 名")
      
          if not path_within(target_skill_root, workspace_root):
              warnings.append("workspace_dir 位于目标 skill 根目录之外;只有用户明确指定时才应这样做")
      
          for path in markdown_files:
              issues = find_local_link_issues(path, read_text(path), target_skill_root)
              errors.extend(
                  [f"{path.relative_to(target_skill_root)}: {issue}" for issue in issues]
              )
      
          if not skill_body.strip():
              errors.append("SKILL.md 正文为空")
      
          before_stats_path = paths["size_before_json"]
          after_stats_path = paths["size_after_json"]
          if before_stats_path.exists():
              before = json.loads(before_stats_path.read_text(encoding="utf-8"))
              if not after_stats_path.exists():
                  current_records = [compute_file_record(target_skill_root, path) for path in markdown_files]
                  write_json(after_stats_path, build_totals(current_records, phase="after"))
              after = json.loads(after_stats_path.read_text(encoding="utf-8"))
              if after["total_words"] >= before["total_words"]:
                  warnings.append(
                      "压缩后总词数未下降;如果这是有意保留,请在报告中说明原因"
                  )
      
          snapshot_skill_md = paths["before_snapshot_dir"] / "SKILL.md"
          if snapshot_skill_md.exists():
              snapshot_frontmatter, _ = parse_frontmatter(read_text(snapshot_skill_md))
              if nested_get(snapshot_frontmatter, "name") != nested_get(frontmatter, "name"):
                  errors.append("SKILL.md frontmatter.name 与压缩前快照不一致")
              if nested_get(snapshot_frontmatter, "description") != nested_get(frontmatter, "description"):
                  warnings.append("SKILL.md frontmatter.description 与压缩前快照不同;请确认只是等价压缩")
      
          result = {
              "skill_root": str(target_skill_root),
              "workspace_base": str(paths["workspace_base"]),
              "workspace_root": str(workspace_root),
              "run_id": workspace_root.name,
              "workspace_inside_skill_root": path_within(target_skill_root, workspace_root),
              "checked_files": [str(path.relative_to(target_skill_root)) for path in markdown_files],
              "error_count": len(errors),
              "warning_count": len(warnings),
              "errors": errors,
              "warnings": warnings,
          }
          write_json(paths["validation_json"], result)
      
          print(f"workspace_root={workspace_root}")
          print(f"run_id={workspace_root.name}")
          print(f"validation={paths['validation_json']}")
          if warnings:
              print(f"warnings={len(warnings)}")
          if errors:
              for error in errors:
                  print(f"ERROR: {error}")
              raise SystemExit(1)
      
      
      if __name__ == "__main__":
          main()
      
  • CHANGELOG.md 2.5 KB
    # compact-bensz-skills - 变更日志
    
    遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与语义化版本规范。
    
    ## [Unreleased]
    
    ### Added(新增)
    - 新增 `workspace_inside_skill_root` 诊断字段到初始化清单与校验结果,便于识别用户显式指定的外部工作区
    - 新增 `latest-run.txt` 与 `--run-id` 机制,支持 `measure_markdown.py` / `validate_compaction.py` 复用指定 run
    
    ### Changed(变更)
    - 默认待压缩范围收紧为工作型 Markdown:目标 skill 根目录下的 `README.md`、`CHANGELOG.md` 不再纳入 `file-inventory.json`、快照和体积统计;`SKILL.md`、README、参考清单与测试夹具已同步改为这一口径
    - `validate_compaction.py` 现在会在缺少 `size-after.json` 时自动补算当前统计,降低验证顺序对结果的影响
    - `README.md`、`SKILL.md`、`references/validation-checklist.md` 同步补充“外部工作区会被警告”和“本地链接不得越出 skill 根目录”的口径
    - 默认工作区从单一 `.compact-bensz-skills/` 切换为按运行隔离的 `.compact-bensz-skills/run-{timestamp}/`
    - `init_workspace.py` 会输出 `workspace_base` / `run_id` 并刷新 `latest-run.txt`,后续脚本默认复用最近一次运行
    - `config.yaml` 版本号 `0.2.0 -> 0.3.0`
    
    ### Fixed(修复)
    - 修复本地 Markdown 链接校验只检查“是否存在”而不检查“是否越出目标 skill 根目录”的缺口
    - 修复压缩后 `SKILL.md` frontmatter.name 可能与压缩前快照悄然漂移而未被校验的问题
    - 修复多次连续运行时中间文件可能被同一隐藏目录相互覆盖、导致不同会话互相污染的问题
    
    ## [0.1.0] - 2026-03-28
    
    ### Added(新增)
    - 初始化 `compact-bensz-skills` skill,用于压缩 Agent Skill 的 Markdown 文档,同时保留触发语义、输入输出契约与安全边界
    - 新增 `scripts/init_workspace.py`:创建目标 skill 的 `.compact-bensz-skills/` 隐藏工作区,生成 Markdown 清单、快照与压缩计划骨架
    - 新增 `scripts/measure_markdown.py`:统计压缩前后字数/字符数/标题数/代码块数,并输出对比报告
    - 新增 `scripts/validate_compaction.py`:校验 `SKILL.md` frontmatter、相对 Markdown 链接、忽略目录约束与压缩收益
    - 新增 `references/compaction-playbook.md`、`references/preservation-checklist.md`、`references/validation-checklist.md` 三份参考文档
    - 新增 `tests/compact-bensz-skills/fixture-skill/` 轻量夹具,用于验证文件发现、工作区隔离与压缩校验流程
    
  • config.yaml 1.6 KB
    skill_info:
      name: "compact-bensz-skills"
      version: "0.3.0"
      description: "压缩 Agent Skill 中的工作型 Markdown 文档,在不改变功能与安全边界的前提下降低上下文体积。"
      author: "Bensz Conan"
      category: "skill-maintenance"
    
    workspace:
      hidden_dir: ".bensz-api/skills/compact-bensz-skills"
      run_prefix: ""
      timestamp_format: "%Y-%m-%d-%H-%M"
      latest_run_pointer: "latest-run.txt"
      keep_intermediates_inside_hidden_dir: true
      subdirs:
        - "input"
        - "output"
        - "log"
        - "snapshots"
        - "analysis"
        - "reports"
      before_snapshot_dir: "snapshots/before"
    
    directories:
      default_test_dir: "tests/compact-bensz-skills"
    
    source_files:
      markdown_extensions:
        - ".md"
      ignore_dirs:
        - "tests"
        - "plans"
        - ".compact-bensz-skills"
        - ".bensz-api"
        - ".git"
        - "__pycache__"
      ignore_globs:
        - ".DS_Store"
        - "*.pyc"
      ignore_file_names:
        - "README.md"
        - "CHANGELOG.md"
    
    preservation:
      required_skill_frontmatter_fields:
        - "name"
        - "description"
        - "metadata.author"
      required_skill_keywords_include_name: true
      keep_code_blocks: true
      keep_commands_and_paths: true
      keep_safety_constraints: true
      keep_user_visible_outputs: true
    
    reports:
      inventory_json: "analysis/file-inventory.json"
      plan_markdown: "analysis/compaction-plan.md"
      size_before_json: "reports/size-before.json"
      size_after_json: "reports/size-after.json"
      size_delta_markdown: "reports/size-delta.md"
      validation_json: "reports/validation.json"
    
    scripts:
      init_workspace: "scripts/init_workspace.py"
      measure_markdown: "scripts/measure_markdown.py"
      validate_compaction: "scripts/validate_compaction.py"
    
  • README.md 6.3 KB
    # compact-bensz-skills
    
    `compact-bensz-skills` 用来压缩某个 Agent Skill 里的工作型 Markdown 文档,目标是在**不改变原有功能**的前提下,显著降低上下文体积。
    
    ## 最推荐用法
    
    ```text
    请使用 compact-bensz-skills skill 压缩这个 Agent Skill 的工作型 Markdown 文档。
    输入:/path/to/target-skill
    输出:更新后的 skill 源文件;所有中间文件保存在目标目录下的 .bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/
    ```
    
    ## 适用场景
    
    - 目标 skill 的 `SKILL.md`、`references/*.md` 明显冗长
    - 你希望节省上下文,但不想动脚本逻辑
    - 你需要先理解 skill,再做保守压缩
    
    ## 默认行为
    
    - 工作区根:`<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/`
    - 每次运行目录:`<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/`
    - 最近一次运行指针:`<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt`
    - 测试区:`<skill_root>/tests/compact-bensz-skills/`
    - 自动忽略:`tests/`、`plans/`、目标 skill 根目录下的 `README.md`、`CHANGELOG.md`
    - 优先保留:frontmatter、输入输出契约、安全边界、命令与路径
    - 如果你显式指定外部 `workspace_dir`,脚本会接受,但验证报告会提示“中间文件已离开 skill 根目录”
    
    ## 常用示例
    
    ### 示例 1:压缩单个 skill
    
    ```text
    请使用 compact-bensz-skills skill 压缩 `git-pr-review` 这个 skill 的工作型 Markdown 文档。
    输入:/workspace/skills/git-pr-review
    输出:原 skill 目录内更新后的 Markdown;中间文件放到 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/`
    ```
    
    ### 示例 2:指定额外约束
    
    ```text
    请使用 compact-bensz-skills skill 压缩这个 skill 的工作型 Markdown。
    输入:/workspace/skills/my-skill
    输出:更新后的 skill 源文件
    另外,还有下列参数约束:
    - 只压缩 Markdown,不改 Python/Bash 脚本
    - 默认不要动 README.md / CHANGELOG.md
    - 不要改变 SKILL.md frontmatter 的 name
    - 压缩完成后要输出压缩前后统计
    ```
    
    ## 运行时会生成什么
    
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/file-inventory.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/compaction-plan.md`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-before.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-after.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-delta.md`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/validation.json`
    
    ## 备选用法(脚本)
    
    ```bash
    python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill
    python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --phase after
    python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill
    ```
    
    如果你想显式锁定某一轮:
    
    ```bash
    python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill
    # 记下输出里的 run_id
    python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --run-id 2026-03-28-15-52 --phase after
    python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill --run-id 2026-03-28-15-52
    ```
    
    ## WHICHMODEL
    
    最后核对:2026-03-28。
    
    - OpenAI 路线:
      - 复杂 skill 压缩、跨多份 `references/` 去重、需要保守保留约束时,优先 `gpt-5.4`;OpenAI 官方把它列为复杂推理、coding 和 agentic workflows 的起点。
      - 如果你主要在 Codex 里工作,且任务是“读文档 + 改文档 + 跑脚本验证”的 agentic coding 流程,可优先 `gpt-5-codex`;官方说明它是面向 Codex 一类环境优化的 agentic coding 模型。
      - 只做轻量统计、跑 helper scripts、整理测试记录时,可降到 `gpt-5.4-mini` 或同级快模型。
    - Anthropic 路线:
      - 最复杂的压缩任务优先 `Opus`;Anthropic 官方建议复杂任务先从 Opus 开始。
      - 日常 skill 压缩、文档改写和一般验证优先 `Sonnet`;官方将其定位为速度与智能的最佳平衡,并在 Claude Code 中作为日常 coding 默认推荐档位。
      - 只做简单检查或批量轻任务时可用 `Haiku`。
    - 长上下文优先级:
      - 如果目标 skill 很大,优先选支持更长上下文的模型。OpenAI 当前前沿模型页给 `gpt-5.4` 标注了 1M context;Anthropic 也为 Sonnet/Opus 提供了 1M context 选项或长会话模式。
    
    参考:
    - OpenAI Models: https://developers.openai.com/api/docs/models
    - OpenAI GPT-5-Codex: https://developers.openai.com/api/docs/models/gpt-5-codex
    - Anthropic Models Overview: https://platform.claude.com/docs/en/about-claude/models/overview
    
    ## FAQ
    
    ### 它会改 `tests/` 和 `plans/` 吗?
    
    不会。这个 skill 默认忽略目标 skill 里的 `tests/` 和 `plans/`。
    
    ### 它会处理 `README.md` 或 `CHANGELOG.md` 吗?
    
    默认不会。这个 skill 只把工作型 Markdown 视为主要目标;目标 skill 根目录下的 `README.md`、`CHANGELOG.md` 一般属于面向人类的说明或发布记录,不纳入默认压缩范围。
    
    ### 它会自动改脚本代码吗?
    
    默认不会。它的核心目标是压缩 Markdown 文档;只有当文档与脚本明显不一致时,才应先指出风险,再做最小修正。
    
    ### 它怎么保证不破坏功能?
    
    它要求先理解 `SKILL.md`、`config.yaml`、`scripts/`,然后再压缩文档,并在最后运行统计和校验脚本。
    
    ### 为什么现在要用 `{yyyy-mm-dd-hh-mm}`?
    
    因为这个 skill 可能会反复执行。按分钟级 run 目录隔离后,每一轮的快照、统计和验证结果都能独立追溯,不会被下一轮覆盖;同一分钟重复运行时脚本会自动追加后缀。
    
    ### 它会检查相对链接是否越界吗?
    
    会。`validate_compaction.py` 现在不仅检查链接是否存在,也会拒绝链接跳出目标 skill 根目录。
    
  • SKILL.md 9.9 KB
    ---
    name: compact-bensz-skills
    description: 当用户明确要求压缩、瘦身或精简 Agent Skill 文档、降低上下文开销且不改变功能时使用。⚠️ 不适用:新增功能、修复脚本逻辑、批量改代码或压缩普通文档。
    
    metadata:
      author: Bensz Conan
      short-description: 在不改变功能的前提下压缩 Agent Skill 的 Markdown 上下文
      keywords:
        - compact-bensz-skills
        - skill compaction
        - markdown compression
        - context reduction
        - Agent Skills
    ---
    
    # compact-bensz-skills
    
    ## 目标
    
    当用户明确要求“压缩/瘦身/精简某个 Agent Skill 的 Markdown 文档”“在不改变功能前提下降低 skill 上下文开销”时使用。先理解目标 skill 的真实能力与安全边界,再在忽略 `tests/`、`plans/` 以及目标 skill 的 `README.md`、`CHANGELOG.md` 的前提下,压缩 `SKILL.md`、`references/*.md` 等工作型 Markdown,并把中间产物隔离到 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/`。⚠️ 不适用:用户主要想新增功能、修复脚本逻辑、批量改代码、或只想压缩非 skill 文档。
    
    ## 流程
    
    ### 输入
    
    #### 输入
    
    1. `skill_root`(必需)
       - 目标 Agent Skill 根目录
    2. `workspace_dir`(可选)
       - 默认把本轮工作区建在 `<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/`
       - 如果用户显式指定其它目录,则把它视为“run 容器根目录”,本轮仍落到其中的 `{yyyy-mm-dd-hh-mm}/`
    3. `run_id`(可选)
       - 用于在 `init -> measure -> validate` 间显式复用同一轮工作区
    4. `test_dir`(可选)
       - 默认 `<skill_root>/tests/compact-bensz-skills/`
    
    ### 执行步骤
    
    #### 核心原则
    
    - **先理解,再压缩**:先读 `SKILL.md`、`config.yaml`、`scripts/` 和必要的 `references/`,再判断哪些 Markdown 可以缩短。
    - **不改行为,只改表达**:压缩的是文档体积,不是功能边界;不得擅自新增、删除或扭曲目标 skill 的能力。
    - **保护触发语义**:`SKILL.md` frontmatter 的 `name` 必须保持不变;`description` 只能等价压缩,不能丢失关键触发条件。
    - **保护硬约束**:输入、输出、默认路径、安全限制、必跑脚本、失败条件、与其它 skill 的协作约定都必须保留。
    - **只动源工作文件**:忽略目标 skill 的 `tests/`、`plans/` 及其内容,不把它们视为待压缩源文件。
    - **默认不动说明文档**:目标 skill 根目录下的 `README.md`、`CHANGELOG.md` 一般属于面向人类的说明或发布记录,不视为默认压缩目标。
    - **中间文件隔离**:分析、快照、统计、验证结果都写到隐藏目录 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/`;除非用户另有指定,不向外泄露中间文件。
    - **按轮次隔离**:每次运行都应在 `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/` 内工作,避免多次压缩会话互相覆盖。
    - **链接不能越界**:压缩后保留的本地 Markdown 链接必须仍位于目标 skill 根目录内,不能借相对路径跳到 skill 外部。
    
    #### 标准工作流
    
    ##### 1. 初始化隐藏工作区
    
    优先使用确定性脚本创建工作区、快照和 Markdown 清单:
    
    ```bash
    python3 compact-bensz-skills/scripts/init_workspace.py --skill-root /path/to/target-skill
    ```
    
    脚本会:
    - 创建 `<skill_root>/.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/`
    - 在隐藏根目录写入 `latest-run.txt`
    - 扫描待压缩 Markdown(忽略 `tests/`、`plans/`、`README.md`、`CHANGELOG.md`)
    - 生成 `analysis/file-inventory.json`
    - 备份原文到 `snapshots/before/`
    - 生成 `analysis/compaction-plan.md`
    - 记录压缩前统计到 `reports/size-before.json`
    
    ##### 2. 理解目标 skill 的真实功能
    
    最低阅读范围:
    - `SKILL.md`
    - `config.yaml`(如存在)
    - `scripts/`(如存在)
    - `references/` 中与核心流程直接相关的文档
    - 仅当 `README.md`、`CHANGELOG.md` 与核心行为边界强相关时才辅助阅读;默认不把它们纳入压缩目标
    
    理解时重点确认:
    - 技能触发条件与不适用范围
    - 输入输出契约
    - 默认工作区 / 测试区 / 中间文件路径
    - 安全边界与只读/只写限制
    - 任何“必须执行”“不得省略”的步骤
    
    ##### 3. 执行 Markdown 压缩
    
    优先顺序:
    1. 删重复:移除跨文件、跨章节重复解释
    2. 缩长句:把啰嗦描述改成短句、表格或清单
    3. 主从分离:`SKILL.md` 只保留触发逻辑、主流程、硬约束;细节下沉到 `references/`
    4. 压示例:保留最小可用命令和最关键示例,删除低价值变体
    
    默认优先处理:
    - `SKILL.md`
    - `references/` 中真正承载执行细则的 Markdown
    
    默认不处理:
    - 目标 skill 根目录下的 `README.md`
    - 目标 skill 根目录下的 `CHANGELOG.md`
    
    压缩时必须保留:
    - `SKILL.md` frontmatter 与关键词可发现性
    - 关键命令、路径、文件名、配置键
    - 输入/输出、默认目录、安全限制
    - 会改变行为的条件分支
    - 与 `bensz-collect-bugs` 等跨 skill 约定
    
    压缩时禁止:
    - 把“必需”改成“可选”
    - 删除失败条件、边界条件、路径约束
    - 删除唯一的命令示例或唯一的输出说明
    - 只为了省字而制造歧义
    
    ##### 4. 复测压缩收益
    
    完成文档修改后重新统计:
    
    ```bash
    python3 compact-bensz-skills/scripts/measure_markdown.py --skill-root /path/to/target-skill --phase after
    ```
    
    如需显式复用某一轮:
    
    ```bash
    python3 compact-bensz-skills/scripts/measure_markdown.py \
      --skill-root /path/to/target-skill \
      --run-id 2026-03-28-15-52 \
      --phase after
    ```
    
    该脚本会输出:
    - `reports/size-after.json`
    - `reports/size-delta.md`
    
    ##### 5. 校验压缩后仍可用
    
    ```bash
    python3 compact-bensz-skills/scripts/validate_compaction.py --skill-root /path/to/target-skill
    ```
    
    默认会复用 `latest-run.txt` 指向的最近一轮;如果你在多个 run 之间切换,显式传 `--run-id` 更稳妥。
    
    至少检查:
    - `SKILL.md` frontmatter 是否完整
    - `metadata.author` 是否保留
    - `metadata.keywords` 是否仍包含 skill 名
    - 本地 Markdown 相对链接是否仍有效且没有越出目标 skill 根目录
    - 压缩后的总字数是否低于压缩前
    - 若 `description` 有改动,确认只是等价压缩而非改坏触发语义
    
    #### 何时读取参考文档
    
    - 需要决定“哪些内容必须保留”时,读 `references/preservation-checklist.md`
    - 需要具体压缩手法时,读 `references/compaction-playbook.md`
    - 做收尾校验时,读 `references/validation-checklist.md`
    
    ### 输出
    
    #### 输出
    
    对用户的主要交付:
    - 更新后的目标 skill 工作型 Markdown 源文件
    
    隐藏工作区产物:
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/latest-run.txt`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/file-inventory.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/analysis/compaction-plan.md`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-before.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-after.json`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/size-delta.md`
    - `.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/compact-bensz-skills/{yyyy-mm-dd-hh-mm}/reports/validation.json`
    
    ### 输出管理
    
    #### BenszAPI 任务工作区
    
    
    ### 校验
    
    至少检查 frontmatter、`metadata.author`、技能关键词、相对链接、关键命令/路径/失败条件和触发语义均保留;压缩后的 Markdown 总量应低于压缩前,且 `validate_compaction.py` 与引用检查通过。不能证明语义等价时不得交付压缩版本。
    
    ### 失败与恢复
    
    快照、统计、链接或语义校验失败时保留 `snapshots/before/`、报告和错误日志,停止写回正式 Skill;可在同一 run 目录修正后重试,若收益或保真无法满足阈值则恢复基线并报告原因。
    
    
    ## 约束
    
    <!-- BEGIN COMMON CONSTRAINTS -->
    <!-- Source-Hash: sha256:15120201e9e0c7569517261d57ecefb63ac279c26ed13876f8e95b6dc35854d3 -->
    <!-- Template-ID: skill-common-constraints; Template-Version: 1; Sync-Policy: exact-block -->
    
    ### 公共硬约束
    
    本块由 `docs/templates/skill-common-constraints.md` 统一维护;每个 `SKILL.md` 的 `## 约束` 必须逐字同步本块,不得在副本中改写公共规则。
    
    - 任务需要落盘时,使用唯一的 `./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/` 根目录;共享材料放入 `shared/`,Skill 专属材料放入该 Skill 的 `input/`、`output/`、`log/`。
    - 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
    - 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
    - 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
    - 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
    - Skill 版本唯一记录在自身 `config.yaml:skill_info.version`;公开 API、协议、目录或配置变更同步文档与 `CHANGELOG.md`。
    - `bensz-collect-bugs` 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 `~/.bensz-skills/bugs/`,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
    
    <!-- End of canonical common constraints. -->
    <!-- END COMMON CONSTRAINTS -->
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related