mcpField
H
harness-tour

harness-tour

github.com/rheinmirAgent 工作流10179 次安装2 周前更新
代码仓库

关于 harness-tour

harness-tour 是面向 Claude 项目的交互式技能,通过故意触发违规来演示 harness 规则如何被 hook 实时拦截。它提供短版和完整巡览,并在结束时清理演示文件、保留审计记录。

主要功能

  1. 01短版演示 R1–R3,完整演示 R1–R10
  2. 02预检 harness 状态后再启动演示
  3. 03展示 hook 的实时拦截原因
  4. 04清理演示文件及对应索引行
  5. 05读取审计记录作为演示结果

适用场景

  1. 01向项目成员展示 harness 规则如何阻止违规操作
  2. 02检查 Claude 会话是否加载项目 hook
  3. 03用完整巡览查看阻止、记录和提醒类规则

MCP 相关

该技能使用 host hook 展示规则拦截,不是 MCP 服务;README 明确区分 hook 与 MCP。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rheinmir/setup --skill harness-tour

安装后在 Claude Code 中输入/harness-tour确认已加载。

详细介绍

技能:harness-tour

内容

目的与背景
  • 目的: 让用户亲眼看到(而不是阅读)harness 如何运作:你——Claude——在真实项目中故意违反规则,被 hook 实时拦截,并进行讲解。结束时不留下任何残留。
  • 触发条件(何时使用): 用户输入 /harness-tour,或说“harness tour”“看看 harness 有什么作用”“测试短版”“测试完整版”(disable-model-invocation: true——仅在用户调用时运行)。提供两种时长:SHORT(默认,R1·R2·R3)和 FULL(R1–R10)。
  • 非目标: 不安装/修改 harness(仅在 MISSING 时建议安装命令),没有 hook 时不进行演示,不触碰项目现有文件,不替代 demo.sh/test-broad.sh(无需会话的机器演示版本)。
心智模型

ARGUMENTS → 时长(SHORT|FULL)→ 预检查 harness(POC|PROD|MISSING)→ 每个场景:讲解 → 在 1-rule 路径映射上故意违规 → hook 实时拦截 → 原文摘录 → 修复 → 清理 tour-demo* + 同一轮中的索引行 → 结尾摘录 audit.jsonl。规则分为 3 组:实时拦截(R1、R2、R3、R5、R7、R9)· 记录/提醒但不拦截(R4、R8、R10)· 仓库层级(R6)。

输入和输出约定
字段必填?含义
输入ARGUMENTS否包含 full/10/"完整" → FULL;否则 → SHORT
输入会话在已安装 harness 的项目根目录中打开是必须加载 .claude/settings.json,否则为 MISSING
输出讲解 + 每个场景拦截信息的 stderr 原文摘录是例如 [R1 no-write-raw] …、[R3 index-sync] …
输出项目整洁是删除所有已 PASS 的 tour-demo* + 对应索引行;保留 harness 产物
输出结尾是总结刚才拦截的规则 + cat .claude/audit/*.jsonl 的最后几行;FULL 还会附上 10 条规则的表格
规则与能力
  • RULE-01(MUST):每个场景都要:讲解 → 违规 → 原文摘录拦截原因 → 修复。不可简略。
  • RULE-02(MUST):只操作名为 tour-demo* 的文件;绝对不能修改/删除项目现有文件。
  • RULE-03(MUST):某个本应拦截的场景却未被拦截 → 停止演示,报告“rule X 的防护栏失效”——这是需要处理的真实 bug。 (不适用于不拦截组 R4/R6/R8/R10——这些规则本来就不会拦截。)
  • 能力:在 llmwiki/ 中写入/删除演示文件 tour-demo* + 修改 wiki/index.md(演示行);读取审计产物;运行本地 harness 脚本。依赖宿主的 hook(PreToolUse/Stop)——没有 hook 就不演示。
失败边界
  • 预检查没有任何输出 → 被阻止(MISSING):停止,建议安装 PoC 的命令并在根目录打开新会话,不进行演示。
  • 本应拦截的场景却未被拦截 → 失败:停止演示,报告“rule X 的防护栏失效”(R4/R6/R8/R10 除外)。
  • 清理时删除文件却漏掉索引行 → Stop hook R3 会拦截本轮清理 → 在同一轮中删除残留行,然后结束。

操作方式

主要工作流
步骤类型输入操作输出/退出失败/下一步
W01确定性ARGUMENTS选择演示时长SHORT 或 FULL—
W02确定性根目录会话预检查 harness(使用下方的 grep/test 命令)POC / PROD没有输出 → MISSING,停止
W03有副作用路径 → 规则映射按顺序演示 SHORT(3 个场景)或 FULL(R1–R10)剧本,每个场景开始前先讲解拦截信息的 stderr 原文摘录 + PASS 文件未被拦截 → 停止,报告防护栏失效
W04有副作用已 PASS 的 tour-demo* 文件在同一轮中清理:删除文件 + 索引行项目整洁Stop R3 拦截 → 删除残留行
W05确定性audit结尾:总结规则 + cat .claude/audit/*.jsonl报告—

各步骤详情(W01–W05 的事实来源):

选择演示时长(读取 ARGUMENTS)
  • 包含 full / 10 / "完整" → FULL(R1–R10)。
  • 其他情况(默认,或 short/3)→ SHORT(3 个场景:R1 · R2 · R3)。
预检查 — 检测当前会话中正在运行的 harness

在会话的 ROOT 目录运行:

{ grep -q llmwiki-validate .claude/settings.json 2>/dev/null && test -f harness/poc-vendor-neutral/bin/llmwiki-validate.py && echo POC; }
test -f llmwiki/.claude/hooks/pre_tool_use.py && echo PROD
  • 输出 POC → 主推方式。PoC 现已覆盖 R1–R10(5 条规则在 PreToolUse 阶段拦截,R3/R4/R8/R10 通过事件 hook 实现)。
  • 输出 PROD → production harness。R1–R10 相同,以下 short/full 场景也相同;区别仅在于 hook 脚本名称 (pre_tool_use.py/post_tool_use.py/stop.py),且 R1 也可能通过 permissions.deny 拦截。演示方式完全相同。
  • 没有任何输出 → MISSING。停止。(不要假装演示),建议安装(主推 PoC):
    curl -fsSL https://raw.githubusercontent.com/Rheinmir/setup/orca/harness/poc-vendor-neutral/bootstrap.sh | bash
    
    然后在该项目的 root 新开 Claude 会话(以便加载 .claude/settings.json)→ 重新输入 /harness-tour。

Hook 只有在会话**从已安装配置的正确项目 root 加载 .claude/settings.json**时才会拦截。在源代码仓库 / 其他 root 中打开会话 → 没有 hook → tour 不会触发(演示时没有拦截 = 作秀,禁止)。

Harness 是 HOOK,不是 MCP(用户问“为什么 /mcp 里看不到”时解释)

拦截层是 PreToolUse hook → 通过 /hooks 或 .claude/settings.json 中的 hooks 块检查,不在 /mcp 中。 MCP 是另一回事(供模型调用的工具)。PoC:hook 调用 llmwiki-validate claude-hook。Production:pre_tool_use.py……


路径 → 规则映射表(使用正确路径,确保每个场景只触发 1 条规则)

多条规则都会检查 wiki/ → 路径选错会导致 2 条规则同时拦截,造成混乱。标准映射如下(依据 policy.yaml):

规则用于触发违规的文件为什么只有该规则会触发
R1 no-write-rawllmwiki/raw/tour-demo.mddeny_write glob raw/**
R2 origin-requiredllmwiki/wiki/sources/draft/tour-demo.md = ---\ntype: draft\n---\n# Tour Demo(有 frontmatter,没有 ## Origin,没有 ## Plan)frontmatter → R9 通过;缺少 Origin → R2 拦截
R3 index-sync(Stop)刚创建的 R2 文件,尚未加入 wiki/index.mdm_stop 扫描 concepts/entities/sources/draft,并与 index 对比
R5 folder-structurellmwiki/wiki/tour-demo.md(就在 wiki/ 下,basename 异常)forbid_root:wiki/*.md 不在允许列表中
R7 proposal-completellmwiki/wiki/sources/draft/tour-demo-proposal.md — 有 frontmatter + ## Origin + ## Plan + proposed,缺少 ## Agent Task Assignment 和 Sequence diagramfrontmatter → R9 通过,Origin → R2 通过 → R7 拦截
R9 okf-frontmatterllmwiki/wiki/concepts/tour-demo.md — 有 ## Origin,但没有 YAML frontmatter有 Origin,因此 R2 通过;缺少 type: → R9 拦截

⚠️ R9 现在覆盖 sources/ + draft/ 两者(与 global production 一致 — 草稿也需要 frontmatter)。由于 R2/R9 都会检查所有 content dir → 通过内容而非路径进行隔离:文件有 frontmatter 但缺少 Origin → 只有 R2;文件有 Origin 但缺少 frontmatter → 只有 R9。

实时不拦截(仅供查看 artifact,明确说明“不会拦截”):R4(.claude/audit/audit.jsonl + log.md)、 R8(SessionStart 时的 [harness] N rule… 行)、R10(.claude/audit/.docs-gate.json 统计 prompt)。 仓库层:R6(pre-commit + CI .github/workflows/harness.yml + skill /verify-before-commit)。


简短剧情(默认)——3 个场景,按顺序演示,每个场景前先旁白

开场:“我会故意违反 3 条规则。看看 hook 如何实时拦截我——不是我主动让步。”

场景 1 — R1(PreToolUse · 拒绝写入 raw/):

  • 旁白:“raw/ 是人类的收件箱,Agent 不能写入。”
  • Write llmwiki/raw/tour-demo.md → exit 2 → 拦截。逐字引用 stderr [R1 no-write-raw] …。不要重试。文件不会创建。

场景 2 — R2(PreToolUse · 强制要求 ## Origin):

  • 旁白:“创建来源文件时‘忘记’ ## Origin → 就无法追溯来源。”
  • Write llmwiki/wiki/sources/draft/tour-demo.md = ---\ntype: draft\n---\n# Tour Demo(包含 frontmatter,以便通过 R9,但没有 ## Origin)→ exit 2 → 拦截。引用 [R2 origin-required] …。
  • 修复:将正确内容重新写入同一文件,添加 ## Origin\n- harness-tour demo(保留原 frontmatter)→ 这次通过,文件写入成功。

场景 3 — R3(Stop · 索引说谎):

  • 旁白:“刚创建了 tour-demo 文件,但我故意没有把它写入 wiki/index.md。现在尝试结束本轮。”
  • 在此结束 response,不更新 index → Stop hook(harness-events.py stop)返回 exit 2,并给出不匹配项列表。
  • 被拦截时:逐字引用 [R3 index-sync] wiki/index.md 未列出:…,然后在 wiki/index.md 中只为 tour-demo 添加 1 行,接着清理。

→ 接下来是清理(见下文)。


完整剧情(当 ARGUMENTS 包含 full 时)——依次演示 R1–R10

演示 6 个实时拦截规则(R1、R2、R3、R5、R7、R9)+ 3 个不拦截、展示产物的规则(R4、R8、R10)+ 1 个仓库级规则(R6)。 在介绍不拦截的规则组之前明确说明:“接下来的 3 条规则不会在输入时拦截——它们会记录/提醒;我会展示产物作为证据。”

R1 — Write llmwiki/raw/tour-demo.md → 拦截(拒绝写入 raw/)。引用错误,不重试。

R2 — Write llmwiki/wiki/sources/draft/tour-demo.md(包含 frontmatter ---\ntype: draft\n---,以便通过 R9,但缺少 ## Origin)→ 拦截 → 添加 ## Origin → 通过。

**R3 —(Stop)**在 R2 文件尚未加入 index.md 时结束本轮 → Stop 拦截 → 添加 index 行 → 继续。 (在 FULL 中,为了保持流程连贯,可以把 R3 合并到最后:创建以下通过检查的文件后,尝试结束一轮,此时 index 仍有遗漏 → 拦截 → 更新 index。)

**R4 — log-append(不拦截):**一次 Write 通过后,只有 .claude/audit/audit.jsonl 新增一行(tool+path+timestamp),并重新生成 .claude/audit/log.md。用 cat 查看末尾几行作为证据——“机器记录,我删不掉。”

R5 — Write llmwiki/wiki/tour-demo.md(直接位于 wiki/ 下)→ 拦截 [R5 folder-structure] …(wiki 文件必须位于 concepts/entities/… 下)。不重试。

**R6 — verify-before-commit(仓库级,不实时拦截):**展示提交门禁,包括 pre-commit hook + CI .github/workflows/harness.yml(对变更的 .md 调用核心 files mode)+ skill /verify-before-commit(Claude 在提交前自行检查新代码)。这是仓库级机制,不属于 session——不直接演示拦截。

R7 — Write llmwiki/wiki/sources/draft/tour-demo-proposal.md,包含 frontmatter + ## Origin + ## Plan + proposed,但缺少 ## Agent Task Assignment 和 Sequence diagram → 拦截 [R7 proposal-complete] … → 补上这 2 个部分 → 通过。

**R8 — pattern-health(不拦截):**运行 python3 harness/poc-vendor-neutral/bin/harness-events.py session,显示 [harness] N 条规则正在守护…(若 policy 与 remote 不一致,还会显示 drift 警告)。这是 SessionStart 时打印的内容。

R9 — Write llmwiki/wiki/concepts/tour-demo.md,包含 ## Origin,但没有 YAML frontmatter → 拦截 [R9 okf-frontmatter] …(缺少 type)→ 在文件顶部补上 ---\ntype: concept\n--- → 通过。

R10 — docs-gate(不拦截):cat .claude/audit/.docs-gate.json 可显示 prompt 计数器;说明每隔 LLMWIKI_DOCS_GATE_EVERY(默认 5)轮,UserPromptSubmit 会插入指令,建议调用 /docs-site-macos。

**完整剧情结束:**列出 10 条规则的表格——哪些实时拦截,哪些记录/提醒,哪些属于仓库级;引用 .claude/audit/*.jsonl 作为证据。


清理(必须——在同一轮中完成,否则 R3 会拦截)

删除所有已 PASS(已创建)的 tour-demo* 文件,并且在同一轮中删除 wiki/index.md 中对应的行 (删除文件却保留行 → 索引不一致 → Stop hook 会拦截本次清理):

  • SHORT:wiki/sources/draft/tour-demo.md + 对应行。
  • FULL:另外删除 wiki/sources/draft/tour-demo-proposal.md、wiki/concepts/tour-demo.md + 对应行。
  • 被拦截的文件(raw/tour-demo、wiki/tour-demo R5)不存在 → 无需删除。
  • Harness 工件(audit.jsonl、log.md、.docs-gate.json)是有效的机器记录 → 保留,不要删除。
  • 绝对不要碰项目中其他已有文件。

**结束语:**用一段话总结刚才拦截的规则 + “刚才所有工具调用都在 .claude/audit/*.jsonl 中——机器记录下来了,我不会忘记”(cat 最后几行)。机器演示版无需会话:bash harness/poc-vendor-neutral/demo.sh(13 条断言)· test-broad.sh(63 条断言)。

分支
ID类型条件行为跳过 / 失败汇合
B01user_optionalARGUMENTS 含 full / 10 / “完整”用 FULL R1–R10 脚本替代 SHORT默认 → SHORTW04
B02conditional_requiredpre-check 输出 PROD完全照常演示,仅 hook 脚本名称不同(pre_tool_use.py/post_tool_use.py/stop.py),R1 可能通过 permissions.deny 拦截—W03
B03recoverypre-check 无输出(MISSING)停止,建议执行 PoC bootstrap.sh 的 curl 命令(Pre-check 块),然后在项目根目录开启新会话不演示结束
B04user_optional用户询问“为什么 /mcp 看不到”解释 harness 是 HOOK(检查 /hooks),不是 MCP—W03
验证与停止条件

每个实时拦截场景只有在 hook 实际返回 exit 2 且 stderr 原样摘录时才计入;拦截后不重试(已指定的修复步骤除外)。任何实时拦截规则未能拦截时,立即停止 Tour。全部完成的条件是不存在 tour-demo*,且 wiki/index.md 内容匹配。

示例
  • **正向:**在已安装 PoC 的项目上运行 /harness-tour → pre-check 输出 POC → Write llmwiki/raw/tour-demo.md 被 [R1 no-write-raw] … 拦截 → R2 拦截,添加 ## Origin 后通过 → 本轮结束时被 Stop [R3 index-sync] … 拦截 → 添加对应行 → 在同一轮中清理 wiki/sources/draft/tour-demo.md + 对应行。
  • **边界情况/失败:**在源代码仓库中运行 /harness-tour full(未加载项目的 .claude/settings.json)→ pre-check 无输出 → MISSING,停止,建议执行 curl bootstrap 命令并开启新会话;不演示任何场景。

评论

支持 Markdown