context-mode 强制路由规则解析:在 Kiro 上守护 AI 编码 Agent 的上下文窗口
【免费下载链接】context-modeContext window optimization for AI coding agents. Sandboxes tool output (98% reduction), persists session memory, and enforces routing across 17 platforms via MCP + hooks.项目地址: https://gitcode.com/GitHub_Trending/cl/context-mode
导读
configs/kiro/KIRO.md是 context-mode 为 Kiro 平台(IDE/CLI)准备的强制路由规则文件,它规定了 Agent 在 Kiro 上必须遵循的工具调用纪律:未加路由的原始命令可能一次性向上下文窗口倾倒约 56 KB 数据,而本规则把"分析"从"读取"中剥离出来,用沙箱工具只把最终答案送进上下文。读完本文,你将掌握 KIRO.md 的完整规则体系(Think in Code、BLOCKED/REDIRECTED 清单、五级工具选择层级、并发批处理与记忆检索约定),并理解它在仓库中对应的适配器与 Hook 实现原理,可直接把该文件部署到~/.kiro/steering/中获得确定性注入。
为什么 Kiro 需要强制路由规则
AI 编码 Agent 的上下文窗口是有限资源。每一次工具调用的原始输出——命令回显、HTTP 响应体、搜索结果、文件全文——都会完整进入对话记忆,并在会话剩余时间里持续占用推理容量。在 Kiro 上,一次未路由的命令输出可以膨胀到约56 KB,多次累积就会让窗口迅速被噪声填满,模型在关键决策点反而"看不清"真正重要的内容。
KIRO.md 的定位正是解决这个问题的强制纪律文件(MANDATORY routing rules)。它通过与 context-mode 的 MCP 工具集配合,把「分析数据」的职责从 Agent 的上下文窗口转移到沙箱进程:原始字节留在沙箱里,只有console.log()的派生结果进入对话。
从源码看,这个文件的部署方式由适配器直接支持:src/adapters/kiro/index.ts的getInstructionFiles()返回["KIRO.md"],getRoutingInstructions()则从仓库configs/kiro/KIRO.md读取该文件全文作为默认路由指令;KiroAdapter的注释明确说明,用户可以把该文件复制到.kiro/steering/以选择确定性注入(deterministic injection)。
Think in Code:强制分析纪律
KIRO.md 开篇第一条硬性规则:
凡是分析/计数/过滤/比较/搜索/解析/转换数据,必须写代码:通过
@context-mode/ctx_execute(language, code)完成,只用console.log()输出答案。不要直接把原始数据读进上下文。
核心思想是"PROGRAM the analysis, not COMPUTE it"——用程序做分析,而不是把数据读进来"人工计算"。规范要求:
- 使用纯 JavaScript,仅限 Node.js 内置模块(
fs、path、child_process); - 必须
try/catch,正确处理null/undefined; - 一条脚本可以替代十次工具调用。
这一规则在运行时被注入到每次会话的指令块中。hooks/routing-block.mjs的createRoutingBlock()生成的<priority_instructions>中写有同样表述:"Every byte a tool returns enters your conversation memory and costs reasoning capacity for the rest of the session",并把 Think-in-Code 定义为最高优先级指令。在 Kiro 上,工具名的命名空间由 hooks/core/tool-naming.mjs 统一管理,Kiro 的 MCP 工具以@context-mode/<tool>形式呈现(见TOOL_PREFIXES["kiro"]),这也是整个 KIRO.md 中所有@context-mode/ctx_*工具名的来源。
BLOCKED:被拦截、禁止重试的操作
KIRO.md 明确列出了一类"不要尝试,重试也无用"的操作,它们会被 PreToolUse Hook 直接拦截:
| 操作 | 替代方案 |
|---|---|
Shellcurl/wget | @context-mode/ctx_fetch_and_index(url, source)或@context-mode/ctx_execute(language: "javascript", code: "const r = await fetch(...)") |
内联 HTTP(fetch('http、requests.get(、requests.post(、http.get(、http.request() | @context-mode/ctx_execute(language, code)——只有 stdout 进入上下文 |
| 直接 Web 抓取 | @context-mode/ctx_fetch_and_index(url, source)后接@context-mode/ctx_search(queries) |
这些拦截不是文档纸面声明,而是路由层的真实行为。在 hooks/core/routing.mjs 中可以看到实现细节:检测先剥离引号内内容以避免误报(如gh issue edit --body "text with curl in it",Issue #63),再匹配(^|\s|&&|\||\;)(curl|wget)\s模式;对 curl/wget 采取"允许静默文件下载、拦截 stdout 洪泛"策略(Issue #166)——只有非静默(缺少-s/--silent、-q/--quiet)的 stdout 输出才会被重定向,被拦时返回的引导消息会明确建议改用ctx_execute或ctx_fetch_and_index,并注明二者都具备完整网络访问能力,遇到瞬时 DNS 错误(EAI_AGAIN、ETIMEDOUT、ENETUNREACH)可重试同一次调用。
拦截语义在 Kiro 上通过退出码落地:pretooluse.mjs中deny分支向 stderr 写入原因并以退出码 2 结束(block),allow则以退出码 0 放行,stdout 内容注入 Agent 上下文。
REDIRECTED:被引导进入沙箱的操作
第二类操作不会直接报错,但会被重定向到沙箱工具,取决于 Agent 的使用意图:
Shell(输出 >20 行)——Shell 仅保留给:git、mkdir、rm、mv、cd、ls、npm install、pip install。其余场景应使用@context-mode/ctx_batch_execute(commands, queries)或@context-mode/ctx_execute(language: "javascript", code: "...");只有当代码确实匹配宿主 shell 时才用language: "shell"。路由块中的<when_not_to_use>给出了精确判据:意图处理输出(过滤/计数/解析/聚合)→ 用批处理或沙箱执行;意图观察固定短输出(clean tree 上的git status、whoami、pwd)或变更状态(git、mkdir、rm、mv、导航)→ 继续用 Shell。
fs_read / read(用于分析)——读取是为了编辑→ fs_read 正确;读取是为了分析/探索/总结→ 用@context-mode/ctx_execute_file(path, language, code)。原因很实际:编辑工具需要在上下文里匹配精确字节,而分析只需要结论。routing-block.mjs的createReadGuidance()把这句话做成了一条在读取工具被调用时注入的轻量提示(<context_guidance><tip>)。
grep / search(结果过大)——用@context-mode/ctx_execute(language: "javascript", code: "...")在沙箱里做可移植的过滤与计数。createGrepGuidance()提示:当要计数、过滤或聚合匹配结果(而非抽查一条)时,把搜索放进沙箱执行,原始匹配列表留在沙箱,只有派生答案进入上下文;language: "shell"仅在代码匹配宿主 shell 时使用(Windows 用 PowerShell,Unix 用 POSIX shell)。
五级工具选择层级
KIRO.md 给出了一套优先级明确的工具选择流程,对应注入指令块中的<tool_selection_hierarchy>:
- MEMORY(记忆):
@context-mode/ctx_search(sort: "timeline")—— 恢复会话后,先查历史上下文,再决定是否询问用户; - GATHER(收集):
@context-mode/ctx_batch_execute(commands, queries)—— 一次并行运行所有命令、自动建立索引并返回搜索结果,一次调用替代 30+ 次;每个命令形如{label: "header", command: "..."},label 会成为 FTS5 分块标题,描述性 label 能改善后续检索质量; - FOLLOW-UP(追问):
@context-mode/ctx_search(queries: ["q1", "q2", ...])—— 把所有问题放进数组一次调用(默认相关性模式),排名流水线按查询逐个执行,往返开销只付一次; - PROCESSING(处理):
@context-mode/ctx_execute(language, code)或@context-mode/ctx_execute_file(path, language, code)—— 沙箱内执行,只有 stdout 进入上下文; - WEB(网络):
@context-mode/ctx_fetch_and_index(url, source)后接@context-mode/ctx_search(queries)—— 原始 HTML 永远不进入上下文; - INDEX(索引):
@context-mode/ctx_index(content, source)—— 把内容存入 FTS5 供后续检索。
这六步(文档编号 0–5)构成了完整的"先查记忆 → 批量收集 → 批量追问 → 沙箱处理 → 网络检索 → 主动建索引"闭环,几乎覆盖了 Agent 在真实开发会话中的全部数据消费路径。
并行 I/O 批处理与并发度控制
多 URL 抓取或多 API 调用场景下,KIRO.md 要求始终携带concurrency: N(1–8):
@context-mode/ctx_batch_execute(commands: [3+ network commands], concurrency: 5)—— 适用于 gh、curl、dig、docker inspect、多区域云查询;@context-mode/ctx_fetch_and_index(requests: [{url, source}, ...], concurrency: 5)—— 多 URL 批量抓取。
并发度的选择原则非常具体:
- I/O 密集型(网络调用、API 查询)→ 用4–8;
- CPU 密集型(npm test、build、lint)或共享状态的命令(端口、锁文件、同一仓库写入)→ 保持1;
- GitHub API 速率限制:
gh调用并发上限为4。
这一规则的价值在于把"批处理工具"从"能用"提升到"用得对":并行度太低浪费往返,太高则踩 API 限流或造成端口/锁冲突。
输出规范与会话连续性
输出(Output):产物(代码、配置、PRD 等)必须写入文件,绝不内联输出;返回时只给"文件路径 + 一行描述"。同时为search(source: "label")提供描述性 source 标签,让后续检索能按来源过滤。这正是路由块中<artifact_policy>的表述:Write artifacts to files. Return only: file path + 1-line description。
会话连续性(Session Continuity):技能、角色与决策在整个会话期间持续有效,不能随对话增长而丢弃。不过路由块的<session_continuity>对这一点做了更精细的限定:早前捕获的技能/角色/决策是记忆辅助而非常设命令,用户的最新消息始终优先,如果捕获的指令与当前请求冲突,以用户为准——"过去的措辞不约束你"。
Memory:先搜索,再提问
会话历史是持久化且可检索的。恢复会话后,KIRO.md 要求先搜索再问用户:
| 需求 | 命令 |
|---|---|
| 我们之前决定了什么? | @context-mode/ctx_search(queries: ["decision"], source: "decision", sort: "timeline") |
| 存在哪些约束? | @context-mode/ctx_search(queries: ["constraint"], source: "constraint") |
明确禁止问"我们之前在做什么?"——先搜。若搜索返回 0 条结果,才按全新会话处理。这个机制在运行时由agentspawn.mjs落地:当事件源为compact或resume时,Hook 会加载 SessionDB、读取该会话的持久化事件,写入事件文件并追加buildSessionDirective(source, eventMeta, toolNamer)生成的会话恢复指令;startup时会清理过期会话(cleanupOldSessions(7))并建立新的 session 记录。
ctx 命令表
KIRO.md 内嵌了一套可直接对用户使用的命令表,全部通过 MCP 工具实现:
| 命令 | 行为 |
|---|---|
ctx stats | 调用statsMCP 工具,原样显示完整输出 |
ctx doctor | 调用doctorMCP 工具,执行返回的 shell 命令,以清单形式展示 |
ctx upgrade | 调用upgradeMCP 工具,执行返回的 shell 命令,以清单形式展示 |
ctx purge | 调用purgeMCP 工具并传confirm: true,清空知识库前给出警告 |
特别约定:执行/clear或/compact之后,知识库与会话统计被保留;如需全新开始,使用ctx purge。路由块中的<ctx_commands>还补充了命令变体与行为细节(如ctx-stats、/ctx-stats、context savings 问题均触发 stats),并规定/clear、/compact后应告知用户"context-mode knowledge base preserved. Usectx purgeto start fresh"。
仓库中的实现:适配器、Hook 与配置文件
适配器与平台能力
Kiro 的支持由 src/adapters/kiro/index.ts 中的KiroAdapter实现,其关键平台事实:
- Hook 范式:
json-stdio,Hook 注册在 Agent 配置文件~/.kiro/agents/<name>.json的hooks键下; - 配置:
~/.kiro/settings/mcp.json(JSON 格式),MCP 通过其中的mcpServers完整支持; - Hook 退出码:
0=allow,2=block; - 能力边界:
canModifyArgs: false——Kiro CLI 只用退出码,无法修改工具输入,因此路由的modify分支在pretooluse.mjs中会把更新后的命令拆出提示文本写入 stderr 并以退出码 2 拒绝("deny with redirect message"); - 会话目录:
~/.kiro/context-mode/sessions/; - 路由文件:
KIRO.md。
测试 tests/adapters/kiro.test.ts 验证了这些契约:agentSpawn被映射为 SessionStart(supports sessionStart via agentSpawn)、parsePreToolUseInput解析execute_bash工具名、generateHookConfig生成的 matcher 同时包含execute_bash与@context-mode/ctx_execute、HOOK_SCRIPTS将agentSpawn映射到agentspawn.mjs。
Hook 类型与匹配器
src/adapters/kiro/hooks.ts 定义了四种 Hook 类型:preToolUse、postToolUse、agentSpawn、userPromptSubmit,分别映射到hooks/kiro/下的pretooluse.mjs、posttooluse.mjs、agentspawn.mjs、userpromptsubmit.mjs。
PreToolUse 的匹配器数组(PRE_TOOL_USE_MATCHERS)包括:execute_bash、fs_read、@context-mode/ctx_execute、@context-mode/ctx_execute_file、@context-mode/ctx_batch_execute,以及一个特殊的外部 MCP 路由匹配器@(?!context-mode/)。这个负向前瞻模式针对 Issue #529:Kiro 的 MCP 工具在线路上形如@<server>/<tool>,该模式会对任何非 context-mode 前缀的外部 MCP 工具(如 slack / telegram / gdrive / notion 类)触发 PreToolUse——否则这些服务器返回的大体积负载(频道历史、文件内容、搜索结果)会绕过路由提示、在 PostToolUse 阶段"为时已晚"地涌入上下文窗口。routing.mjs的isExternalMcpTool也相应扩展识别@<server>/前缀形状。
示例配置文件
仓库提供了可直接对照的完整配置:
- configs/kiro/agent.json:Agent 配置文件示例,
preToolUse使用管道符合并的匹配器(含外部 MCP 负向前瞻),postToolUse用*全匹配,命令为context-mode hook kiro pretooluse/posttooluse; - configs/kiro/mcp.json:MCP 注册示例,把
context-mode服务器指向command: "context-mode"。
各 Hook 脚本职责
- agentspawn.mjs:Kiro 的
agentSpawn等价于 Claude Code 的 SessionStart,在 Agent 加载时触发一次,负责注入路由块(createRoutingBlock,其中工具名经由createToolNamer("kiro")生成@context-mode/ctx_*形式)以及恢复/压缩场景下的会话恢复指令;输出形状为{ hookSpecificOutput: { hookEventName: "agentSpawn", additionalContext } }; - pretooluse.mjs:调用
routePreToolUse(tool, toolInput, projectDir, "kiro", sessionId)得到决策,按deny(退出码 2 + stderr 原因)、modify(Kiro 无法改输入 → 拆出提示文本后以退出码 2 拒绝)、context(stdout 注入附加上下文,退出码 0)、ask(Kiro 无 ask 概念 → 直接放行)分发; - posttooluse.mjs:非阻塞的会话事件捕获,注释明确要求必须在 20ms 内完成——不联网、不调 LLM,只做 SQLite 写入;
extractEvents从工具名/输入/响应中抽取事件后经attributeAndInsertEvents落库; - userpromptsubmit.mjs:捕获用户提示用于连续性,自动跳过
<task-notification>、<system-reminder>、<context_guidance>、<tool-result>等系统消息,其余提示作为user_prompt事件入库并做项目归属解析。
安装与使用前提
要将这套规则投入 Kiro 环境,前提是完成 context-mode 在 Kiro 上的安装与注册(配置示例见上文两个文件):
- 将 context-mode 注册到 Kiro 的 MCP 配置(
~/.kiro/settings/mcp.json的mcpServers,命令为context-mode),使@context-mode/ctx_*工具可用; - 在
~/.kiro/agents/<name>.json的hooks下配置preToolUse、postToolUse、agentSpawn、userPromptSubmit(agentSpawn与preToolUse为必需项,postToolUse与userPromptSubmit为可选项,见hooks.ts的REQUIRED_HOOKS/OPTIONAL_HOOKS); - 可选:把本文件复制到
.kiro/steering/启用确定性注入;Hook 未配置时,KiroAdapter.validateHooks()会给出context-mode upgrade的修复提示,checkPluginRegistration()则检查 MCP 注册状态。
完成上述部署后,Kiro 上的 Agent 将在每次启动时收到路由指令块,遵循本文所述的强制规则:原始输出留在沙箱,只有派生答案进入上下文窗口。
【免费下载链接】context-modeContext window optimization for AI coding agents. Sandboxes tool output (98% reduction), persists session memory, and enforces routing across 17 platforms via MCP + hooks.项目地址: https://gitcode.com/GitHub_Trending/cl/context-mode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考