
rtk Claude Code Hook 深度解析透明改写 Agent 命令削减 60–90% Token 消耗【免费下载链接】rtkCLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies项目地址: https://gitcode.com/GitHub_Trending/rtk4/rtk本篇指南基于 rtk 仓库中hooks/claude/目录的 Claude Code Hook 文档展开讲解该 PreToolUse 钩子如何在 Agent 执行 shell 命令前将其透明改写为rtk等价命令例如git status→rtk git status从而在 Agent 工作流零改动的前提下削减进入 LLM 上下文的 bash 输出。读完后你将掌握该钩子的完整工作机制、退出码协议、rtk init的安装与完整性校验流程以及如何运行 60 断言的测试套件和审计日志来验证与调试钩子行为。一、定位一个薄委托的 PreToolUse 钩子hooks/claude/README.md 明确列出了 Claude Code Hook 的五个关键特性Shell 脚本实现的PreToolUse钩子依赖jq解析 JSON通过返回updatedInputJSON 完成透明命令改写Agent 全程不知道 RTK 的存在任何失败路径缺 jq、缺 rtk、rtk 版本过旧 0.23.0、无匹配规则都以退出码 0 静默结束绝不阻塞命令执行内置版本守卫将rtk --version与最低要求 0.23.0 比对配套的 rtk-awareness.md 是一个 10 行的精简指令文件由rtk init嵌入 CLAUDE.md。在整体架构中这个钩子属于hooks/目录管理的已部署钩子产物。按 hooks/README.md 的划分hooks/下的各 Agent 脚本shell 脚本、TypeScript 插件、规则文件都是薄委托thin delegates只负责解析 Agent 专属 JSON、以子进程方式调用rtk rewrite、再按 Agent 格式组织响应过滤与改写逻辑本身一行都不在这里。完整的命令改写注册表70 条模式位于 Rust 二进制的 src/discover/registry.rs。一次完整的改写链路如下Agent 发起命令如 cargo test --nocapture - PreToolUse 钩子拦截 - 读取 stdin JSON提取 command 字符串 - 调用 rtk rewrite cargo test --nocapture - 注册表匹配模式返回 rtk cargo test --nocapture - 钩子按 Claude Code 格式输出 JSON 响应 - Agent 实际执行 rtk cargo test --nocapture - 经过滤的输出进入 LLMbash 输出最多减少 90%二、目录产物清单hooks/claude/包含三个文件各自职责清晰文件作用rtk-rewrite.sh核心钩子脚本依赖检查、版本守卫、JSON 解析、委托rtk rewrite、组织 Claude Code 响应rtk-awareness.md10 行精简指令文件由rtk init写入~/.claude/RTK.md并在 CLAUDE.md 中以RTK.md引用test-rtk-rewrite.sh60 断言的测试套件模拟 PreToolUse 输入并验证改写结果与审计日志三、钩子脚本逐段解析rtk-rewrite.sh3.1 依赖与版本守卫脚本开头按顺序做三道检查全部遵循失败即 exit 0的非阻塞契约jq 检查command -v jq失败时向 stderr 打印警告并退出 0——没有 jq 就无法解析 Agent 输入命令按原样执行rtk 检查command -v rtk失败时同样警告后退出 0版本守卫rtk rewrite命令是 0.23.0 版本才引入的旧二进制没有该子命令。脚本执行rtk --version解析出 MAJOR/MINOR/PATCH 并校验MAJOR0 且 MINOR23版本过旧时警告并退出 0。为避免每次钩子调用都多开一个进程检查结果会缓存在${XDG_CACHE_HOME:-$HOME/.cache}/rtk-hook-version-ok这个标记文件中缓存存在则跳过校验。3.2 提取命令并委托 Rust 二进制INPUT$(cat) CMD$(jq -r .tool_input.command // empty $INPUT) [ -z $CMD ] exit 0 REWRITTEN$(rtk rewrite $CMD 2/dev/null) EXIT_CODE$?钩子从 stdin 读取 Claude Code 的 PreToolUse JSON 输入格式见第五节用 jq 提取.tool_input.command然后把全部改写与权限判断委托给rtk rewrite子进程。脚本注释中特别强调这是薄委托钩子增改改写规则应编辑 Rust 注册表而非本脚本。3.3 退出码协议0/1/2/3 四态语义rtk rewrite的退出码是钩子与 Rust 二进制之间的通信协议脚本头部注释与 src/hooks/rewrite_cmd.rs 的实现完全一致退出码stdout含义钩子行为0改写后的命令找到改写且无 deny/ask 规则命中自动放行输出含permissionDecision: allow1无无 RTK 等价命令原样透传无输出2无命中 Deny 规则透传交由 Claude Code 原生 deny 处理3改写后的命令命中 Ask 规则执行改写但不输出permissionDecision让 Claude Code 向用户弹出确认在 rewrite_cmd.rs 的 Rust 侧这一协议由RewriteOutcome枚举映射实现Allow打印改写命令后正常返回Ask打印后process::exit(3)Deny退出 2Passthrough退出 1。这里有一个安全设计值得注意源码测试注释直接标注了 SECURITY当 Claude Code 权限规则无任何规则命中时判定为PermissionVerdict::Default它必须映射到退出码 3ask而非 0allow——否则没有显式 allow 规则的命令会被钩子自动放行绕过 Claude Code 的最小权限默认策略。相关回归测试test_default_verdict_maps_to_ask_exit_code明确断言了这一点。另外src/discover/lexer.rs 会检测命令中的不可证明结构unattestable constructs反引号替换、$(...)命令替换、双引号内替换、文件重定向等一律直接透传不重写而文件描述符复制类重定向21仍可安全重写。测试unattestable_passthrough模块对此有完整覆盖。3.4 响应 JSONallow 与 ask 两种输出形态命中改写且可自动放行时exit 0且命令与改写结果不同时脚本用 jq 生成{ hookSpecificOutput: { hookEventName: PreToolUse, permissionDecision: allow, permissionDecisionReason: RTK auto-rewrite, updatedInput: { command: rtk git status } } }命中 Askexit 3时同样的改写会执行但省略permissionDecision字段Claude Code 因此会像对待未授权命令一样向用户请求确认——既享受了 token 收益又不降低权限门槛。一个细节exit 0 分支中若CMD REWRITTEN命令本身就是rtk git status这类已带 RTK 前缀的命令直接 exit 0 且无输出避免出现rtk rtk git status的双重前缀。3.5 二进制命令形态rtk hook claude从源码结构看较新的rtk init已经注册的是 Rust 二进制命令而非 shell 脚本src/hooks/constants.rs 定义了CLAUDE_HOOK_COMMAND rtk hook claude注释写明替代 rtk-rewrite.shsrc/hooks/init.rs 的migrate_old_hook_script()会在初始化时自动删除旧的~/.claude/hooks/rtk-rewrite.sh及其.rtk-hook.sha256哈希文件并清理 settings.json 中指向旧脚本的残留条目。本文分析的 shell 脚本仍是测试对象测试脚本默认路径即~/.claude/hooks/rtk-rewrite.sh二者共享同一套退出码协议与rtk rewrite决策核心。四、rtk-awareness.md嵌入 CLAUDE.md 的 10 行指令rtk-awareness.md 是rtk init默认模式写入~/.claude/RTK.md的精简指令见 init.rs 中RTK_SLIM常量通过include_str!内嵌该文件再由run_default_mode写入 RTK.md 并在 CLAUDE.md 追加RTK.md引用。其内容要点元命令始终直接用 rtkrtk gain # 查看 token 节省统计 rtk gain --history # 查看带节省数据的命令使用历史 rtk discover # 分析 Claude Code 历史找出漏掉的 RTK 使用机会 rtk proxy cmd # 不过滤地执行原始命令调试用安装验证rtk --version应显示rtk X.Y.Zrtk gain可正常运行而非 command not foundwhich rtk确认二进制。文件还特别提示了命名冲突风险若rtk gain失败可能误装了同名的 Rust Type Kit 工具Hook 用法其余命令全部由钩子自动改写例如git status→rtk git status透明、零 token 额外开销完整命令参考指向 CLAUDE.md。五、安装机制rtk init做了什么src/hooks/init.rs 的 Claude Code 默认模式run_default_mode依次执行以下步骤迁移旧钩子删除遗留的rtk-rewrite.sh、旧哈希文件与 settings.json 中的旧条目写入 RTK.md将rtk-awareness.md内容原子写入~/.claude/RTK.md10 行修补 CLAUDE.md追加RTK.md引用行若存在旧的 137 行 RTK 指令块!-- rtk-instructions --则自动移除并打印迁移成功提示修补 settings.json通过insert_hook_entry深合并写入hooks.PreToolUse数组条目形如{matcher: Bash, hooks: [{type: command, command: rtk hook claude}]}保留既有钩子条目写入前自动备份为settings.json.bak写入采用临时文件 rename 的原子方式防止中途崩溃损坏配置。关键行为参数幂等性hook_already_present会匹配新命令、rtk hook claude类命令或旧脚本路径重复执行rtk init安全无副作用PatchMode 三种模式默认Ask交互式[y/N]确认非 TTY 环境默认 No 并打印手工补丁说明、--auto-patchCI/脚本场景免确认、--no-patch只打印需手工添加的 JSON 片段过滤模板全局模式还会在~/.config/rtk/filters.toml生成用户级自定义过滤器模板本地模式则在项目下生成.rtk/filters.toml模板均带schema_version 1与注释示例遥测同意非 dry-run 场景最后会询问匿名遥测可用rtk telemetry disable关闭环境变量RTK_TELEMETRY_DISABLED1可整体跳过提示。六、完整性校验与卸载按 src/hooks/README.md 的描述钩子文件受 SHA-256 完整性体系保护安装时integrity::store_hash()计算脚本哈希并写入~/.claude/hooks/.rtk-hook.sha256只读 0o444运行时integrity::runtime_check()重算比对被篡改则阻止执行rtk verify可随时打印验证状态PASS/FAIL/WARN/SKIP共 Verified / Tampered / NoBaseline / NotInstalled / OrphanedHash 五种状态。卸载同样幂等rtk init对应的 uninstall 流程会依次移除旧钩子脚本、哈希侧车文件、RTK.md、CLAUDE.md 中的RTK.md引用与 rtk-instructions 块清理后为空则删除 CLAUDE.md、settings.json 钩子条目全部修改先备份再原子写入。七、覆盖控制哪些命令不被改写结合 hooks/README.md 与 rewrite_cmd.rs三层覆盖机制确保用户始终有最终控制权RTK_DISABLED1单命令级覆盖RTK_DISABLED1 git status按原样执行测试套件专门覆盖了这个场景包括FOO1 RTK_DISABLED1 git status这类多前缀组合exclude_commands配置于~/.config/rtk/config.toml列出永不改写的命令匹配时先剥离环境变量前缀再比对支持子命令模式git push会排除git push origin main以^开头的模式按正则处理已带 RTK 前缀rtk git status原样透传不会变成rtk rtk git。复合命令、||、;、|、|、由注册表统一处理管道中仅改写 pipeline-safe 的最终阶段如grep、rg、wcstderr 管道|整条保持原样/||/;两侧独立改写例如cargo fmt --all cargo test→rtk cargo fmt --all rtk cargo test。八、运行测试套件验证钩子README 给出的测试入口# 运行完整测试套件60 断言 bash hooks/test-rtk-rewrite.sh # 针对特定钩子路径测试 HOOK/path/to/rtk-rewrite.sh bash hooks/test-rtk-rewrite.sh # 测试期间开启审计日志 RTK_HOOK_AUDIT1 RTK_AUDIT_DIR/tmp bash hooks/test-rtk-rewrite.sh测试脚本 的工作方式是把 mock JSON{tool_name:Bash,tool_input:{command:...}}喂给钩子再断言hookSpecificOutput.updatedInput.command。用例分组覆盖了实际运维中最容易出错的边界回归组git status→rtk git status、gh pr list、ls -la、cat package.json→rtk read package.json、rg pattern src/→rtk grep pattern src/rg 归一到 rtk grep等既有模式环境变量前缀组GIT_PAGERcat git status→GIT_PAGERcat rtk git status环境变量前缀被保留而非破坏不该改写的反例组docker compose up -d子命令不受支持、heredoc、echo、cd、python3、node -e等均期望无输出透传RTK_DISABLED 组RTK_DISABLED1 git status期望不改写重定向组cargo test 21 | head保留重定向改写为rtk cargo test 21 | head而后台符不会被误判为重定向Vitest 去重组vitest run归一为rtk vitest修复了历史的双 run 拼接 bug审计日志组RTK_HOOK_AUDIT1时钩子在RTK_AUDIT_DIR下写入hook-audit.log每行为 4 个竖线分隔字段动作字段取值如rewrite、skip:already_rtk、skip:heredoc、skip:no_match未设置该变量时不应产生日志。审计日志正是线上排查我的命令为什么没被改写的第一手证据建议调试钩子行为时保持启用。九、优雅降级与排障对照表hooks/README.md 定义了所有 Agent 钩子必须遵循的退出码契约钩子绝不能阻塞命令执行——缺二进制、坏 JSON、改写失败等一切错误路径都退出 0让 Agent 命令原样运行无改写时不产生任何 stdout 输出。Claude 钩子具体降级行为故障场景行为jq 未安装stderr 警告 exit 0命令原样执行rtk 不在 PATHstderr 警告 exit 0rtk 版本 0.23.0stderr 警告 exit 0输入 JSON 非法/无 commandexit 0无输出rtk rewrite崩溃子进程错误被忽略exit 0命中 Deny 规则透传Claude Code 原生 deny 接管排障顺序建议先rtk --version与which rtk确认安装对照 rtk-awareness.md 的验证清单再rtk rewrite git status手动跑一次决策链观察 stdout 与退出码最后开RTK_HOOK_AUDIT1复现检查审计日志的动作字段。若怀疑钩子文件被改动运行rtk verify查看完整性状态确认损坏后重新rtk init -g即可幂等安全。小结rtk 的 Claude Code 钩子以极小的脚本体积实现了高可靠的透明改写所有改写与权限判断收敛在 Rust 二进制的单一注册表中shell 层只做协议翻译0/1/2/3 四态退出码协议在带来自动放行效率的同时用Default 必映射为 ask的设计守住了 Claude Code 最小权限底线rtk init的原子写、备份、幂等与旧脚本迁移机制保证了安装与升级的安全性60 断言的测试套件与审计日志则为行为验证提供了完整抓手。这一套薄委托 单一事实源 非阻塞契约的设计也是仓库中其余 10 个 Agent 集成共同遵循的范式。【免费下载链接】rtkCLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies项目地址: https://gitcode.com/GitHub_Trending/rtk4/rtk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考