关于 mantis-plan
mantis-plan 是安全审查规划技能,根据代码结构、威胁模型和历史问题梳理边界并安排定向调查。它既支持首次全面盘点,也可利用累积的审查记录制定后续计划。
主要功能
- 01审阅威胁模型背景
- 02盘点生产源码
- 03检查历史问题与重试情况
- 04跟踪各轮次间的文件变化
- 05生成定向调查计划
适用场景
- 01为陌生代码库制定初始审查计划
- 02依据历史问题和代码变更安排后续审查
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-plan安装后在 Claude Code 中输入/mantis-plan确认已加载。
详细介绍
策略师(/mantis-plan)
系统目标
安全架构师。分析代码结构、目录元数据和历史记录,以绘制外部边界并制定自适应审查路线图。
命令定义
- 命令:
/mantis-plan - 描述: 根据当前威胁模型和历史经验,制定有针对性的防御性安全审查计划。
- 参数(可选;由编排器提供,供 Block A 使用):
--snapshot_root/SNAPSHOT_ROOT:固定的只读代码快照的绝对路径(所有相对于快照的路径均以 CODE_ROOT 为根)。--snapshot_id/SNAPSHOT_ID:本轮快照标识符(哨兵 + Block B 比较)。--state_root:workspace/状态目录的绝对路径(plan.json、.mantis_state.json、findings/、kb/、archive/)。相对于状态目录 — 绝不以 CODE_ROOT 为前缀。- 所有标志均缺省 -> MODE-OFF/旧版模式(Block A 步骤 1d):行为与当前完全相同。
输入/输出约定
- 读取:
workspace/.mantis_state.json(用于跟踪当前循环轮次)。workspace/kb/THREAT_MODEL.md(如果存在)。workspace/kb/index.md(检查其是否存在,以确定 Mode A 还是 Mode B)。- Mode A:遍历生产目录和源文件,读取
mantis-summary.md(如果可用)。 - Mode B:读取
workspace/kb/index.md、workspace/kb/THREAT_MODEL.md、workspace/archive/.repro_attempts.json(如果存在)、版本控制系统(VCS)差异或文件时间戳/哈希值。 workspace/kb/structural_index/manifest.json(用于检查结构索引的可用性/状态)。workspace/helpers/query_structural_index.py(用于调用有界结构索引查询)。workspace/.mantis_state.json新字段:active_snapshot.{snapshot_id, snapshot_pinned, vcs_type}、snapshot_history(由元 Agent 读取和写入)。读取vcs_type是因为 Block E 会根据它分支。Plan 在实时仓库根目录运行 Block E,以计算changed_files/changed_files_status(COMPUTED 或 UNKNOWN),并将其写回状态。
- 写入:
workspace/plan.json。- 将符合重试条件的发现 JSON 文件从
workspace/archive/findings_pass_K/或workspace/archive/loopK_findings/(K 为其归档时所在的轮次)复制到workspace/findings/(保留其原始 UUID 文件名)。
- 前提条件:
- 代码库必须可访问。
- 幂等性保证:
- 直接覆盖
workspace/plan.json。在 Mode B 中,仅当 Block B 为 MATCHED 且文件未更改并存在时,才会原样复制发现文件;否则会安排重新发现调查。按照缓存读取规则查询.repro_attempts.json。
- 直接覆盖
说明
步骤 0:定位符解析(先于其他所有操作执行)
LOCATOR RESOLUTION (before reading ANY target code or artifact):
0. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
state for provenance/annotation; NEVER stop merely because a code root is unset.
1. Determine CODE_ROOT, in this priority order:
a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
(used when a caller hands you a prepared tree, e.g. a patched shadow).
b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
c. Else read state_root/workspace/.mantis_state.json (state_root from
--state_root if passed, else ./workspace/... relative to the current dir)
-> active_snapshot.root / .snapshot_id / .snapshot_pinned.
d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
2. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
deliberately mutated and is sentinel-EXEMPT.)
3. PATH FIELDS:
- SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
NOT of the form <existing-path>:<integer> is a non-source LOCATOR
(symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
line-range and line-existence logic.
- STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
kb_references, repro_file_path, reattack_file_path, helper scripts, report
files, and all state/findings JSON.
4. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
(mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
cd into CODE_ROOT.
5. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
(the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
lacks .git/.hg/.repo.
6. Every shell command uses ABSOLUTE paths and sets its own working directory on
that call. Do NOT assume the working directory persists between calls.
说明
**当前轮次检查(防御性检查;绑定保证由
mantis-pipeline-adapterScenario 2 中的 harness 提供):**如果存在active_snapshot,且active_snapshot.pass != state.pass_number,则将该快照视为 本轮的过期快照 — 停止并报告 "stale active_snapshot: pass mismatch",或降级为 HALT(snapshot_pinned实际为 false:不产生权威判定,Block B 为 NOT_MATCHED,reproduce 为not_attempted)。这可以捕获在 Stage 15 递增轮次后 保留了active_snapshot、却未重新固定快照的自定义 harness。参考元 Agent 每轮都会 重新固定快照,因此不会触发此检查。Block B 本身无法检测此情况(它只检查snapshot_id,不检查pass)。
策略师专属说明:
- Plan 是 Mode A 中的代码阅读阶段(会遍历生产目录);仅分析发现的跳过规则不适用。
- Mode A 的遍历和每个
target_files路径都相对于快照:在 CODE_ROOT 下遍历并解析这些路径。 workspace/kb/、workspace/plan.json、workspace/.mantis_state.json、workspace/archive/和workspace/findings/都相对于状态目录:在 --state_root 下读写这些路径,绝不可在 CODE_ROOT 下读写。- 绝不可在 CODE_ROOT 下写入、编译或生成内容(Block A step 4)。计划脚本只写入 workspace/plan.json(相对于状态目录)。Block E 中的 VCS diff 按照 Block A step 5 在实时仓库根目录下运行,而非在 CODE_ROOT 下运行。
分析仓库结构,并制定详细的防御性安全审查计划;避免重复以往工作,同时深入检查复杂的进程间路径和未扫描的代码边界。
目标无关性指令: 你评估的目标可能是原始源代码、已编译二进制文件、固件镜像,或实时的预发布/开发端点。规划时应以目标当前所处的格式为依据。你获准并鼓励使用手头任何合适的工具(例如标准 Unix 工具、
unblob、radare2、angr、objdump、Ghidra、qemu、unicorn)来探索工件结构。如果没有源代码,请勿强行采用源代码工作流(例如搜索.c或.py文件);应根据当前工件调整方法,采取行之有效的做法。
按以下步骤执行规划阶段:
-
检查威胁模型上下文: 检查知识库目录中是否存在
workspace/kb/THREAT_MODEL.md文件。如果存在,请完整阅读该文件,以了解程序官方定义的安全边界、威胁主体、资产、高风险接口和可信输入。 -
确定模式并获取经验: 检查知识库索引
workspace/kb/index.md是否存在。-
模式 A:首次全面审查模式(未找到
workspace/kb/index.md): 如果这是首次运行,请确保完整覆盖代码库。为避免大型仓库触及输出 Token 限制,请勿在文本回复中手动生成workspace/plan.json。而应执行 shell 命令,运行一段用你偏好的语言编写的简短脚本,该脚本需:- 使用
find或os.walk遍历所有生产目录。如果某个目录中存在mantis-summary.md文件,则使用其内容了解该目录结构,而不是逐个读取所有源文件。否则,遍历所有生产源代码文件(例如.c、.cpp、.py、.js、.go、.rs、.java)。 - 忽略测试文件夹、构建产物和供应商依赖项(例如
node_modules、.git、tests/)。 - 以编程方式将列表格式化为
workspace/plan.json架构,并直接写入磁盘。由于这是自动化脚本,请指示脚本在"question"字段中使用通用的总体基线问题(例如“开展基线审计,以检查内存安全和逻辑缺陷”),将高度贴合上下文的自定义问题留给模式 B。
- 使用
-
模式 B:战略学习模式(存在
workspace/kb/index.md): 阅读workspace/kb/index.md和workspace/kb/THREAT_MODEL.md,以回顾代码库积累的历史知识,包括信任边界、漏洞类别和架构组件。调整审查重点,为曾有漏洞记录的组件和文件设计新的、有针对性的深度审查和回归审查。在此模式下,你可以使用文件写入工具手动生成workspace/plan.json,因为审查范围会窄得多。-
针对性重新评估与重试:检查 KB 索引、实体文件和复现尝试缓存文件 (如果存在,则为
workspace/archive/.repro_attempts.json)。你必须 找出需要重新评估或重试的发现:还要读取
workspace/.mantis_state.json中的快照上下文:active_snapshot.{snapshot_id, snapshot_pinned}和snapshot_history(两者均由元 Agent 写入)。然后通过在实时仓库根目录中运行下方的 Block E, 为本轮计算changed_files/changed_files_status(依据 Block A 第 5 步中的 VCS 元数据例外规则;固定的--snapshot_root会剥离 .git/.hg/.repo,因此 diff 必须针对实时树运行)。将计算得出的changed_files(仓库相对路径数组)和changed_files_status(COMPUTED或UNKNOWN)写回workspace/.mantis_state.json,然后在本阶段剩余步骤中使用它们。 同时写入changed_files_pass= 状态中的当前pass_number,以便使用方检测是否使用了 过期的(上一轮)diff。使用以下规则确定自上一轮以来更改的文件:自上次以来的更改:在实时仓库根目录(而非 SNAPSHOT_ROOT)中运行。CUR = 当前提交/修订版; PREV = 本轮之前的
snapshot_history条目。如果 PREV 缺失,或vcs_type属于 {none,unknown},或 prev 或 cur 的 SNAPSHOT_ID 是 content:/live:/+content_hash 回退值,或 diff 命令出错 ->changed_files_status = UNKNOWN。 将每个文件都视为已更改。绝不能视为未更改。绝不能丢弃。(注意:snapshot_pinned false本身不会触发 UNKNOWN —— 在 HALT 模式下,active_snapshot存在且snapshot_history中有 PREV 条目,因此仍可运行 diff。 在 MODE-OFF 模式下 —— 没有active_snapshot—— 不存在 PREV 条目,因此 PREV 缺失, diff 状态降级为 UNKNOWN,但这不会强制执行完整的 Mode-A 遍历;参见下方的 Mode-A 触发条件。)否则,git:git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR(-M标志用于检测重命名;-C用于检测复制;--name-status会为重命名输出R<score>\told_path\tnew_path,因此旧路径和新路径都会显示;--diff-filter=RAMDCT包含重命名、新增、修改、删除、复制和类型变更的文件)hg:hg status -C --rev PREV:CUR(-C/--copies会在后续行中显示重命名/复制文件的源路径; hg 状态码:A=新增,R=删除,M=修改)multi-vcs:repo forall -c 'git diff --name-status -M -C --diff-filter=RAMDCT PREV CUR'(任何错误 -> UNKNOWN)。如果某个发现的任意一个code_paths(路径部分)属于该集合, 或其路径是重命名后的路径或重命名前的路径,则该发现的文件视为已更改(解析R<score>\told\tnew行:旧路径和新路径都属于更改集合)。如果某个发现的主文件 出现在重命名源文件(旧路径)中,也将新路径视为已更改 —— 缺陷很可能随文件一起移动。 检查workspace/archive/.repro_attempts.json时,也要应用此缓存读取规则。首先,完全按照mantis-reproduce写入的方式选择缓存键:如果发现项有signature字段,则该键就是signature;否则,该键为stable_key = normalized_title + "@" + primary_file_path(标题需转为小写并移除所有非字母数字字符;primary_file_path=code_paths中第一个去除末尾:line的条目)。然后读取该键下的值 V:如果 V 是整数,则 count=V 且 last_snapshot=UNKNOWN;如果 V 是对象,则 count=V.count 且 last_snapshot=V.last_snapshot(默认值为 UNKNOWN)。如果所选键下没有条目,在判定 count=0 之前,也要尝试另一种键形式,以免使用 signature 键的写入方和使用 stable_key 键的读取方彼此错过,导致错误重置尝试预算。(迁移期间,缓存混合了两种值形式和两种键样式。)-
安排研究: 对于档案中标记为
"NEEDS_RESEARCH"的发现项,在workspace/plan.json中安排有针对性的调查(收集缺失的上下文,并将其判定为"VALID"或"FALSE_POSITIVE")。 -
复制以重试(受快照检查控制)或重新发现: 对于每个原本符合重试条件的档案发现项(尚未尝试复现,或根据上述缓存读取规则,
failed_to_reproduce且尝试次数少于 2 次,或patch_status为 {VERIFICATION_FAILED,ERROR,VERIFICATION_INCOMPLETE}),运行:针对发现项 F 进行 SNAPSHOT MATCH CHECK(判定为 MATCHED 还是 NOT_MATCHED): 1. 如果 snapshot_pinned 为 false -> NOT_MATCHED。停止。 2. 读取 F.discovery_commit: - 缺失、为空或为字面值 "MIXED" -> NOT_MATCHED。 - 与 SNAPSHOT_ID 不完全相等 -> NOT_MATCHED。 - 与 SNAPSHOT_ID 完全相等 -> MATCHED。 除此之外,没有其他方式能得到 MATCHED;绝不进行模糊比较。全局的“为字段设默认值并继续”向后兼容规则不适用于 discovery_commit: 缺失 = NOT_MATCHED。(不存在单独的“dirty”门槛:dirty 树的 SNAPSHOT_ID 已包含工作树内容哈希,因此同一轮次内的发现项 MATCH,而跨轮次的裸提交发现项不 MATCH。)然后按规则判定:
-
原样复制(快速重试)仅当以下条件全部成立时:该发现项的 Block B 为 MATCHED,且其主文件(
code_paths中第一个条目,去除行号后)不在changed_files中,并且该文件在 CODE_ROOT 下存在。将档案中的<uuid>.json复制回workspace/findings/<uuid>.json,保留 UUID 和原始discovery_commit(不要重新盖戳——必须继续能够检测到漂移)。 -
**MODE-OFF 绕过(3 状态规则):**如果状态中不存在
active_snapshot(MODE-OFF — 未请求--sync),Block B 始终返回 NOT_MATCHED (snapshot_pinned is false -> NOT_MATCHED),因此上方的 COPY-VERBATIM 门控永远不会触发,每个符合重试条件的发现都会被重新发现——这会导致行为 退化,相较于当前行为(如今,当文件仍然存在时,第 ≥2 次通过会原样保留 未更改的发现)。在 MODE-OFF 下,如果发现的主要文件(第一个code_paths, 去除行首空白)存在于 CODE_ROOT 下,则 COPY-VERBATIM(去掉Block B MATCHED和file NOT in changed_files这两个条件——MODE-OFF 下本来就没有changed_files差异)。这与mantis-patch的 LEGACY 模式例外 一致(patch:133-138、patch:172-174)。不要将绕过条件设为snapshot_pinned==false——这也会匹配 HALT 模式,而在该模式下,STALE 横幅 会合理地标记发现为需要重新验证。仅当不存在active_snapshot时才启用。 (不要更改 Block B——根据README_AGENTS.md:711-718的块一致性警告, 各技能中的 Block B 必须逐字符一致;修复应放在计划中使用 Block B 的 CONSUMERS,而不是 Block B 本身。) -
在所有其他情况下重新发现(Block B 为 NOT_MATCHED,或文件在
changed_files中,或文件缺失,或changed_files_status==UNKNOWN):不要复制回去。应改为向workspace/plan.json追加新的调查,其中包含该发现的title、description和repro_hints,将target_files设为旧code_paths的目录子树,以及覆盖整个仓库的符号/关键词 搜索(搜索该发现的函数/结构体/标题词语),以便重新找到已移动/重命名的 bug,并要求研究人员在当前快照上重新推导确切行号。此外,在归档的发现上 记录历史备注unconfirmed-regression-pending,这样在某次通过重新发现它或人工将其 驳回之前,它绝不会被悄然丢弃。 -
**行号/AST 重新锚定(第 2 阶段增量效率):**在退回到完整的重新发现之前, 尝试使用向前行号跟踪(反向 blame 或 diff 块偏移)将发现的行号重新锚定到 当前快照。这是一项优化:如果发现的主要函数/符号仍在附近,重新锚定会生成 行号提示,以便聚焦重新发现调查——但它不能取代重新验证(快照已更改,因此 下游仍需重新研究该发现)。
- How(方法): 将 finding 的旧行号从 PREV 向前映射到 CUR
(不要单独 blame PREV——那样只会返回截至 PREV 的行号,不会向前映射)。在 LIVE 仓库根目录中运行(Block A
step 5 carve-out):git:
git blame --reverse <PREV>..<CUR> -L <old_line>,<old_line> -- <file>(反向 blame 会沿着该行向前追踪到 CUR),或者将git diff <PREV> <CUR> -- <file>中的区块偏移量加到<old_line>上。 然后在 CODE_ROOT(当前固定的快照)中读取映射后的行,并确认 finding 的主要函数/符号存在于其 ±50 行范围内。这样只会得到一个 CANDIDATE 新行号——仅供 RE-DISCOVER 使用的搜索提示,绝不能视为可信的重新验证结果。 - 重新锚定成功时(在映射后的行找到符号):
使用新行号来 FOCUS 此 finding 的 RE-DISCOVER 调查(优先将研究人员指向映射后的
code_paths位置)。不要将 finding 转为 COPY-VERBATIM,也不要跳过重新验证:Block B 为 NOT_MATCHED,因此后续仍会重新研究/复现该 finding(符号可能仍存在于映射后的行,但问题可能已经 FIXED)。保持discovery_commit、signature和lineage_id不变;添加历史记录:re-anchored: <old_line> -> <new_line> (search hint)。 - 重新锚定失败时(函数已删除、未找到符号、diff 过大、blame 出错,或旧行处的代码完全不同):按上述方式回退到完整的 RE-DISCOVER。这是保守的防护措施:只要存在任何不确定性,就重新发现。
- 绝不要使用重新锚定来压下或丢弃 finding。 这只是快速更新行号的途径;若失败,仍须通过常规流程重新发现该 finding。
- 与 VCS 无关: 对于 hg,比较
PREV:CUR(hg diff --rev PREV:CUR -- <file>),并将区块偏移量应用于<old_line>,以获得向前映射后的行号。对于无 VCS/二进制目标,不适用重新锚定;始终回退到 RE-DISCOVER。
- How(方法): 将 finding 的旧行号从 PREV 向前映射到 CUR
(不要单独 blame PREV——那样只会返回截至 PREV 的行号,不会向前映射)。在 LIVE 仓库根目录中运行(Block A
step 5 carve-out):git:
-
绝不要复制回
"status"为"FALSE_POSITIVE"、"patch_status"为"VERIFIED_SECURE"、或"repro_status"为"reproduced"的 finding(除非 patch 如上所述失败),也不要复制回已达到当前快照 2 次尝试上限的 finding。但如果此类 finding 的文件在changed_files中,或 Block B 为 NOT_MATCHED,则将其视为可能的回归:重新发现它(不要将针对已更改代码的旧终局判定视为可信)。MODE-OFF 例外: 如果active_snapshot不存在(MODE-OFF),则移除上文中的or Block B is NOT_MATCHED条件——在 MODE-OFF 下,每个 finding 的 Block B 都是 NOT_MATCHED(这是没有快照所致,并非发生漂移的信号),若保留该条件,每次都会重新打开所有终局判定(FALSE_POSITIVE/VERIFIED_SECURE/reproduced)。在 MODE-OFF 下,仅依赖file IS in changed_files(这在 MODE-OFF 下恒为假——没有changed_filesdiff),因此终局 finding 会原样沿用。这就是当前的行为。
-
-
-
变更 / 新增攻击面覆盖(MANDATORY): 对
changed_files中的每个路径,都必须添加一项标题为Exhaustive Review: <path>的调查,无论其是否对应已归档的发现。如果changed_files_status==UNKNOWN,且active_snapshot存在(HALT 或 PINNED 模式——本轮请求了同步),或者本轮发生了同步(snapshot_id!=snapshot_history中前一条记录的 id),则不能信任范围狭窄的文件集:本轮必须回退到完整的 Mode A 穷尽式扫描,即使kb/index.md存在也不例外(这是发现新增文件的唯一方式)。但是,在 MODE-OFF 模式(没有active_snapshot——没有--sync)下,即使changed_files_status==UNKNOWN,也不要在第 2 轮及后续轮次强制进行完整的 Mode-A 扫描:这是当前的默认行为;在每一轮 MODE-OFF 的第 2 轮及后续轮次强制进行 Mode-A 扫描会造成回归。在 MODE-OFF 模式下,像现在一样,依靠现有的kb/index.md(Mode B)缩小范围。 -
依赖感知的扩展覆盖(Phase 2 增量效率): 当
changed_files_status已知(不是 UNKNOWN)且依赖关系图可用时,将调查范围扩展到变更文件本身之外。目标是找出导入或依赖变更文件的文件,以便规划器为变更代码的使用方安排有针对性的调查,而不只是调查变更代码本身。- 方式: 以文件级依赖关系图(
workspace/kb/dependencies.json或实体关系 Markdown)作为强制基线:对每个变更文件 F,找出所有导入 F 的文件(直接导入或最多跨 2 层传递导入)。将这些依赖文件以Exhaustive Review: <dependent_file>条目的形式加入调查范围。然后再加入结构索引中的调用方:如果可用,使用查询辅助工具(workspace/helpers/query_structural_index.py)进行函数级精确查询——对变更文件导出的函数调用resolve_symbol(),再调用find_callers()枚举符号级别的依赖方。安排调查时,取依赖关系图找到的依赖方与结构索引找到的调用方的并集——两者互为补充,不能互相替代。如果结构索引不存在(没有manifest.json)、为空,或缺少查询辅助工具,则依赖关系图仍是基线。 - 使用条件: 仅当
changed_files_status已知且知识库包含依赖信息时使用。如果知识库缺少导入 / 构建图,或知识库已过期(检查workspace/.mantis_state.json中的kb_snapshot_id是否与SNAPSHOT_ID一致——如果不同,则知识库是基于不同快照构建的,可能已过期),请回退到 Phase 1 的行为(完整 Mode-A 扫描或 Mode-B 缩小范围)。 - 护栏: 如果依赖关系图不完整、已过期,或出现任何不确定情况,则回退到 Phase 1 的重新发现(将所有文件视为可能受影响)。绝不能用依赖关系缩小范围来删除调查项——它只能为依赖文件新增有针对性的调查。变更文件本身始终必须调查。
- 与 VCS 无关: 依赖关系图源自知识库的架构分析,而非 VCS 元数据。对于知识库已索引其 import/include/use 语句的任何语言,此方法都适用。
- 方式: 以文件级依赖关系图(
-
结构索引查询(仅作提示的增强): 如果结构索引可用(存在
workspace/kb/structural_index/manifest.json),则使用它来补充上述依赖感知的扩展覆盖,精准发现符号级别的调用方。结构索引只决定调查的优先顺序,绝不决定审计集合的成员范围。-
优先解析协议(MANDATORY): 查询调用方之前,先解析符号:
python3 workspace/helpers/query_structural_index.py resolve_symbol --name "<function_name>" [--language "<lang>"] [--file "<path>"] --state_root <state_root>如果响应包含
ambiguous: true,请勿默默选择某个匹配项。 使用--file/--language缩小范围,或为所有匹配的符号安排调查。 -
有界调用方查询: 解析完成后,使用明确的边界查询调用方:
python3 workspace/helpers/query_structural_index.py find_callers --symbol_id "<resolved_id>" --limit 100 --offset 0 --state_root <state_root>如果
has_more为 true,请使用--offset翻页。 -
考虑覆盖范围的结果解读: 检查每个结构索引响应中的
coverage.partition_status:complete+precision == semantic+ 无调用方 =“没有已索引的 调用方”——该分区已完整索引,且使用语义后端,因此空结果对于已索引代码具有权威性。仍须按仅作提示的规则运行 grep(grep 可以捕获基于宏的调用、函数指针和动态分派)。complete+precision != semantic+ 无调用方 =“没有已索引的 调用方”——该分区已完整索引,但精度低于语义级,因此空结果不具有权威性。必须运行穷尽式 grep 回退。partial/empty/failed+ 无调用方 =“未完全索引”——该分区并不完整,因此应扩大调查范围,并且必须运行穷尽式 grep 回退。
-
防护措施:
- 仅作提示:结构索引结果决定顺序,而非成员范围。 它们只用于优先调查哪些依赖文件;绝不能导致任何文件被排除在审计范围之外。
- 每个结果都带有
precision和backend字段——使用precision(semantic>typecheck>ast>symbol-only>heuristic>deferred>coverage-only)来衡量对结果的信任度。 - 如果结构索引不存在(没有
manifest.json)、为空,或缺少查询辅助工具:回退到基于 grep 的发现方式(当前行为)。结构索引仅作覆盖范围提示。
-
-
上下文注入(
kb_references): 对于计划开展的每项调查,你必须确定workspace/kb/目录中的哪些文件(例如,workspace/kb/entities/auth_module.md或workspace/kb/vulnerabilities/CWE-79.md)能为研究人员提供必要的上下文。在该调查的"kb_references"数组中填写这些 Markdown 文件的确切路径。这样可以免去研究人员收集上下文的负担。 -
探索性/不受约束的调查(中等概率): 在计划过程中,以中等概率 (例如,每次规划有 25-50% 的概率)加入一次不受约束的对抗性扫描或随机探索:
-
对抗性扫描: 选择威胁模型当前标记为安全、低风险或范围外的组件或目录。指示研究人员进行不受约束的扫描,不采纳
workspace/kb/THREAT_MODEL.md中的安全假设。 -
随机探索: 在代码库中随机选择一个起点(文件或目录)。这项调查的问题应尽量简短且开放,只需指示研究人员“深入查看”或“探索”所选区域,不提供特定的威胁模型背景或预定义的漏洞类别。将这项调查的
kb_references设为空列表,以确保以全新的视角进行调查。 令牌优化: 无论使用脚本(模式 A)还是文件写入工具(模式 B),都应将计划直接写入磁盘,不要在聊天回复中打印 JSON 内容。
-
-
-
-
模式校验: 无论使用哪种模式,最终写入磁盘的
workspace/plan.json文件都应符合以下模式,以确保下游审计 Agent 能够正确解析:
计划模式格式
{
"investigations": [
{
"title": "Exhaustive Review: [relative_file_path]",
"target_files": ["[relative_file_path_1]", "[relative_file_path_2]"],
"kb_references": ["workspace/kb/entities/auth_module.md", "workspace/kb/vulnerabilities/CWE-79.md"],
"question": "Detailed reviewing prompt instructions asking the researcher to trace specific input pathways, variables, memory allocations, or function constraints."
}
]
}
确保已成功写入 workspace/plan.json。完成后,请通知用户。