关于 mantis-architecture
mantis-architecture 是用于仓库分析的安全知识库构建技能。它结合代码结构与当前及历史经验,维护相互链接的 Markdown 架构、组件和漏洞记录。
主要功能
- 01分析组件与信任边界
- 02构建相互链接的 Markdown 知识库文件
- 03记录架构及漏洞模式
- 04提取依赖关系
- 05归档经验及每轮知识库副本
适用场景
- 01为代码库创建安全文档
- 02使组件与漏洞记录随源代码变化更新
- 03在分析轮次间保存安全经验
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ mantis --skill mantis-architecture安装后在 Claude Code 中输入/mantis-architecture确认已加载。
详细介绍
Architect (/mantis-architecture)
系统目标
知识库综合器。将学习队列(workspace/learnings.jsonl)中的临时见解与代码库的结构分析,整合为规范化、相互关联的 Markdown 知识库(workspace/kb/)。
命令定义
- 命令:
/mantis-architecture - 描述: 通过定义系统架构、映射特定实体(组件)并归纳历史漏洞模式,为知识库奠定基础。
- 参数(均为可选;由 LOCATOR RESOLUTION / Block A 解析):
--snapshot_root=<dir>(或SNAPSHOT_ROOT环境变量)— 要读取目标源码的固定代码快照;--snapshot_id=<id>— 该快照的SNAPSHOT_ID;--state_root=<dir>— 所有状态和知识库路径所在的workspace/的父目录;--target_root=<dir>— 已准备好的目录树,用于覆盖快照(此阶段很少传入)。若未传入任何参数,行为将与今日完全一致(降级/未固定):从当前目录读取源码,并将snapshot_pinned视为 false。
输入/输出约定
- 读取:
workspace/learnings.jsonl(当前轮次的原始洞见)。workspace/historical_learnings.jsonl(可选,以往的漏洞元数据)。- 代码库目录结构和关键源文件。
workspace/kb/中现有的 Markdown 文件(用于验证/检查衰减)。workspace/.mantis_state.json(用于获取轮次计数)。workspace/.mantis_state.json→active_snapshot(root、snapshot_id、snapshot_pinned)和snapshot_history— KB 新鲜度门禁(步骤 0b)的来源信息。只能从 STATE 读取快照;绝不能运行实时 VCS 命令(git/hg/repo)来判断 KB 是否为最新。workspace/.mantis_state.json→kb_snapshot_id(当前 KB 上次构建所依据的SNAPSHOT_ID;首次构建或旧版 KB 中可能不存在)。workspace/.mantis_state.json→changed_files和changed_files_status(由 mantis-plan 的 Block E 写入;在步骤 0b 结果 3 中用于限定范围的 KB 失效处理。自第 2 轮起存在,但可能已过时(在之前的轮次写入)——限定范围路径会将changed_files_pass与state.pass_number进行比对;若不一致,则回退到完整重建。)
- 写入:
workspace/kb/下的 Markdown 文件(architecture.md、entities/[component_name].md、vulnerabilities/[CWE-ID].md、index.md)。workspace/kb/dependencies.json— 架构分析期间提取的导入/依赖关系边 JSON 映射(键 = 相对于 CODE_ROOT 的源文件路径;值 = 导入/依赖该键文件的文件数组)。此文件供mantis-plan在第二阶段使用依赖感知的扩散分析。如果代码库没有可解析的导入结构,则写入{}。限定范围失效处理期间仅重新推导变更条目(见下文结果 3)。- 将
workspace/learnings.jsonl归档至workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl。 - 在每个(重新)写入的 KB 文件(
index.md、每个entities/*.md、每个vulnerabilities/*.md)的首行写入一个 `` 标记,并在workspace/.mantis_state.json中将kb_snapshot_id设为SNAPSHOT_ID。 - 将整个 KB 目录树按轮次复制一份不可变副本至
workspace/archive/kb/kb_pass_${N}_${X}/(这样之后回退的修复不会悄然抹去 KB 在第 N 轮所记录的内容)。
- 前提条件:
workspace/learnings.jsonl必须存在。
- 幂等性保证:
- 事务性:仅在通过程序验证所有 KB Markdown 更新均已成功写入后,才将
workspace/learnings.jsonl移至归档。KB 文件会原位覆盖。 - 快照标记属于同一事务:
KB_SNAPSHOT标记、每轮的workspace/archive/kb/kb_pass_${N}_${X_kb}/副本,以及kb_snapshot_id状态写入,必须在(或与)learnings 移动之前完成。任何步骤失败时,都要保留workspace/learnings.jsonl。
- 事务性:仅在通过程序验证所有 KB Markdown 更新均已成功写入后,才将
说明
分析代码库和待处理的 learnings,为未来的 Agent 构建一份永久的、基于 Markdown 的记忆。
按以下步骤执行架构阶段:
- 定位器解析(Block A,内嵌如下):
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.
这是一个代码阅读阶段(步骤 2 和 4 会读取目标源代码),因此 Block A 的步骤 1-6 全部适用;这并非仅分析发现。开始以下任何操作前,先从状态中解析 CODE_ROOT、SNAPSHOT_ID 和 snapshot_pinned。根据 Block A 步骤 3,所有 workspace/kb/... 路径均相对于 STATE:在 state_root/workspace 下读取和写入,绝不能在 CODE_ROOT 下操作。所有目标源代码均在 CODE_ROOT 下读取。不要运行任何 VCS 命令来判断 KB 新鲜度(Block A 步骤 5 的例外仅适用于历史/差异/归责分析,本阶段不使用这些)。
0b. KB 快照新鲜度门禁(机械检查;仅使用 STATE 和 KB 标记,不使用实时 VCS):
- `CUR` = `SNAPSHOT_ID` (resolved by Block A; the empty string if
`active_snapshot` was absent). `PINNED` = `snapshot_pinned` (false if absent).
- **MODE-OFF short-circuit (3-state rule):** if `active_snapshot` is ABSENT
in state (no `--sync` was requested — MODE-OFF = today's default), SKIP the
freshness gate entirely: do a best-effort build/update against `CODE_ROOT`,
do NOT prepend any STALE banner, and do
NOT stamp `kb_snapshot_id`. This is byte-for-byte today's behavior. (Only
HALT and PINNED run the gate below.)
- `KB_ID` = the `kb_snapshot_id` value in `.mantis_state.json` (primary); else the
text after `KB_SNAPSHOT:` on the FIRST line of
`state_root/workspace/kb/index.md` if that file exists (secondary fallback,
for legacy runs without state); else `""` (no prior KB). State is primary so
the file-marker parsing pitfall (comment-wrapped first line, no `-->`
stripping) can never strand `KB_ID` with the comment closer and force BUILD
FRESH every pass.
- Choose EXACTLY ONE outcome by string checks, top to bottom, first match wins:
1. `PINNED` is false (HALT mode — `active_snapshot` present but unpinned)
-> **STALE / HALT.** Do a best-effort build/update against `CODE_ROOT`,
but PREPEND the STALE banner (below) as the first lines of `index.md`.
Do NOT claim currency: leave the
banner in place. Set `kb_snapshot_id` = `CUR` (a `live:` id).
2. Else `KB_ID` == `CUR` (both non-empty) -> **CURRENT.** Do the incremental
update + decay-check (step 4) as today. Re-stamp `KB_SNAPSHOT: CUR` on
every (re)written file. REMOVE any STALE banner previously prepended to
`index.md`.
3. Else (`PINNED` true AND (`KB_ID` is empty OR `KB_ID` != `CUR`)) ->
**BUILD FRESH (full or scoped re-architecture).** The pinned code advanced
since the KB was built (a sync / pass-boundary change), OR the KB is
unstamped / legacy. Choose full or scoped:
- **Scoped invalidation (Phase 2 incremental efficiency):** If
`changed_files_status` is known (not UNKNOWN) AND the KB already has a
`KB_SNAPSHOT` stamp (KB_ID was non-empty, just different) AND
`changed_files_pass` equals the current `state.pass_number` (the diff
is from THIS pass, not a stale prior pass — absent or different →
treat as UNKNOWN → full rebuild below), attempt a SCOPED rebuild: only
invalidate KB entries whose source files are in `changed_files`, plus
their parent-rollup dependents (KB entities that import/reference the
changed files). Re-derive ONLY those entries from `CODE_ROOT`; carry
forward all other KB entries unchanged (they were built against the
same code, just a different snapshot ID). Re-stamp `KB_SNAPSHOT: CUR`
on every (re)written file.
- **Parent-rollup (2-hop, matching plan's fan-out):** When
invalidating a KB entry for changed file F, also invalidate any KB
entry that REFERENCES F directly (1-hop) AND any entry that
references a 1-hop dependent of F (2-hop). This matches
`mantis-plan`'s dependency-aware fan-out (which expands up to 2
hops), ensuring that a grandchild entity (H imports G, G imports
changed F) is not carried forward stale and later fed as a
`kb_reference` while its dependency has changed.
- **Guardrail:** If ANY uncertainty arises (can't determine which KB
entries map to which source files, the KB structure is ambiguous, or
changed_files is empty but KB_ID != CUR), fall back to full rebuild
below. Never carry forward a stale entry for a changed file.
- **Full rebuild (Phase-1 fallback):** If KB_ID is empty (no prior KB),
OR `changed_files_status` is UNKNOWN, OR the scoped invalidation guardrail
fired, REBUILD every KB file from scratch against `CODE_ROOT`. Do NOT
carry forward any prior assertion you have not re-derived from
`CODE_ROOT` this pass. Stamp `KB_SNAPSHOT: CUR`. REMOVE any STALE banner.
- STALE banner (paste verbatim, substituting `<KB_ID>` and `<CUR>`; keep the
leading `>` on every line so it renders as a visible blockquote):
```
> **STALE KB WARNING — do not trust without re-verifying.**
> snapshot_pinned=false, or the KB was built against a different snapshot.
> KB_SNAPSHOT=<KB_ID> does not match active_snapshot.snapshot_id=<CUR>.
> Every SECURE/FIXED/NON_VIABLE/SAMPLE_OR_TEST claim below is UNVERIFIED
> against the current code. Re-verify before trusting; do NOT filter, skip,
> or down-prioritize work based on this KB.
```
-
读取收件箱(
workspace/learnings.jsonl和workspace/historical_learnings.jsonl):- 解析
workspace/learnings.jsonl的内容(如果存在workspace/historical_learnings.jsonl,也一并解析)。提取所有 轨迹洞察、已发现的漏洞、可行的崩溃路径,以及 已验证的补丁。
- 解析
-
分析源代码边界:
- 检查
CODE_ROOT下的目录结构和关键源文件 (由 Block A 解析出的固定快照;按 Block A 第 6 步使用绝对路径,且不要运行 VCS 命令)。根据 仓库内容,动态识别系统的核心组件、接口和信任 边界。这广泛适用于各个领域:无论是 软件系统(例如识别解析器、控制器或网络守护进程)、 硬件/RTL 设计(例如识别 IP 块、JTAG 接口或内存控制器)、基础设施即代码(例如 识别云权限、VPC 边界或部署描述符), 还是数据/ML 流水线(例如识别数据入口点、模型 序列化机制或训练边界)。
- 检查
-
构建或更新知识库(KB):
-
使用标准 Markdown 在
workspace/kb/目录中创建或更新文件。 严格遵循以下路径:workspace/kb/architecture.md:高层数据流、区域定义、 系统设计,以及整体可用性/正常运行时间要求(如果有 文档记录,或可从 systemd、kubernetes 或 负载均衡器等配置中推断)。workspace/kb/entities/[component_name].md:组件的具体定义 (例如auth_module.md)。必须包含指向相关 漏洞类别的链接,并记录已知约束(例如“此模块 会对输入 X 进行净化”)。记录组件的关键性和 可用性要求(如适用,分类为 CRITICAL、STANDARD 或 LOW_CRITICALITY)。在此处纳入轨迹洞察。workspace/kb/vulnerabilities/[CWE-ID_or_BugClass].md:对此代码库 历史上相关的缺陷类别(例如CWE-79.md或Memory-Corruption.md)的 描述,包括说明不应做什么的示例。workspace/kb/index.md:根目录索引,包含指向上述创建的每个文件的 链接和 1 行摘要。这是 Planner 将读取的 地图。
-
重要格式规则: 使用相对链接交叉引用 实体和漏洞(例如
[Auth Module](entities/auth_module.md))。确保所有 markdown 文件 简洁明了,并聚焦于可操作的安全上下文。 -
快照标记(在运行新鲜度门控时,即 HALT 或 PINNED,对每个(重新)写入的 KB 文件为必需; 在 MODE-OFF 下绝不使用): 使
index.md、每个entities/*.md和每个vulnerabilities/*.md的第一行恰好为(替换 第 0b 步中的 `CUR`;它是 HTML 注释,因此不会渲染)。这是下一 轮的新鲜度门控(第 0b 步)检测漂移的方式。**MODE-OFF 门控(3 态 规则):** 如果 `active_snapshot` 为 ABSENT(MODE-OFF — 未请求 `--sync`),则不要为每个文件标记 `KB_SNAPSHOT` 标记:`CUR` 是 空字符串(`arch:145`:“如果 `active_snapshot` 不存在,则为空字符串”), 因此强制要求的标记将是(空 值)— 这是 Phase 1 中不存在的快照时代产物。 每文件标记仅由第 0b 步的新鲜度门控消费,而 MODE-OFF 完全跳过该门控(arch:147-152:“完全跳过新鲜度门控... 这与今天的行为逐字节相同。只有 HALT 和 PINNED 运行下面的门控。”)。此 MODE-OFF 门控与下面的新鲜度门控逻辑 以及第 0b 步的结果子句相同,后者仅在 HALT/PINNED 结果中 提及每文件KB_SNAPSHOT: CUR标记(CURRENT:164, 限定作用域的 BUILD FRESH:178,完整 BUILD FRESH:195)。 -
**按文件标记
KB_SNAPSHOT是 KB 断言唯一的溯源机制。**不要添加逐条断言的(AS_OF:<snapshot>)标签——AS_OF重新验证读取器从未实现,而新鲜度门控(步骤 0b)通过比较kb_snapshot_id与SNAPSHOT_ID,以及每条发现的discovery_commit(由mantis-criticBlock B 强制执行),已经提供了过时保护。之后被撤销的修复由这些机制捕获,而非逐条断言标签。
-
-
验证并衰减知识(防止漂移):
- 代码经过修补或重构后,知识会过时。在最终确定 KB 更新之前,针对
CODE_ROOT下的源码(固定的快照——不是实时 VCS 查询,也不是实时工作树)抽查现有workspace/kb/entities/中的断言。在 BUILD FRESH 结果(步骤 0b)下,完全不要抽查:丢弃先前的断言,并在本轮从CODE_ROOT重新推导每个实体。在 STALE / HALT 结果下,仅尽力抽查,并且无论结果如何都保留 STALE 横幅。 - 如果实体文件声称某个变量未经清理(基于旧的学习),但当前实时代码中已有清理函数(因为补丁已合入),则在 KB 中删除或更正该过时的学习。
- 如果当前轨迹洞察反复证明某项学习有误,请主动更正,防止“错误的学习”持续存在并误导未来的 Agent。
- 更正或重新确认基于发现的断言时,重新在该 KB 文件上标记
KB_SNAPSHOT。
- 代码经过修补或重构后,知识会过时。在最终确定 KB 更新之前,针对
-
事务性收件箱清理与归档:
- 为防止无限循环和令牌膨胀,必须清空队列并归档学习成果。
- 验证并完成: 以编程方式验证所有 Markdown 知识库更新均已成功写入磁盘,且交叉引用有效。此外,在提交前验证每个被(重新)写入的知识库文件都以其 `` 标记开头,并且每项基于发现结果的判定都有当前
SNAPSHOT_ID作为依据。 - 通过移动文件来提交: 只有在验证综合整理成功后,才能将
workspace/learnings.jsonl移至归档目录:- 确保目标目录存在(例如,运行
mkdir -p workspace/archive/learnings/)。 - 通过读取
workspace/.mantis_state.json中的"pass_number",确定循环轮次编号N。如果缺失或无效,则扫描workspace/archive/中匹配findings_pass_N或loopN_findings的文件夹,并将N设为max_found + 1;如果不存在归档,则默认为 1。 - 通过统计
workspace/archive/learnings/中匹配learnings_pass_${N}_*.jsonl的现有文件数量并加 1,确定子索引X。 - 移动文件:
mv workspace/learnings.jsonl workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl。
- 确保目标目录存在(例如,运行
- 快照知识库(每轮归档): 综合整理成功后,将整个知识库目录树复制到每轮对应的归档目录:
- 确保目录存在(运行
mkdir -p workspace/archive/kb/)。 - 计算子索引
X_kb=workspace/archive/kb/中现有kb_pass_${N}_*目录的数量 + 1。 - 复制(切勿移动——实时的
workspace/kb/必须保留,以供下一轮使用):cp -a workspace/kb/. workspace/archive/kb/kb_pass_${N}_${X_kb}/。
- 确保目录存在(运行
- 写入状态标记: 将
kb_snapshot_id=SNAPSHOT_ID(步骤 0b 中的CUR)写入workspace/.mantis_state.json。如果active_snapshot不存在(MODE-OFF),则不要写入kb_snapshot_id,也不要在index.md前添加任何 STALE 标记(已跳过新鲜度检查)。在 HALT 模式下,写入kb_snapshot_id=CUR,并保留index.md中的 STALE 标记。 - 如果综合整理失败或被中断,请将
workspace/learnings.jsonl保留在原位置,以确保数据不会丢失。 - 如果进入时
workspace/learnings.jsonl不存在(例如 Stage-15 调用,因为 Stage-2 调用已在本轮将其归档),则只跳过学习成果文件的移动;仍需运行新鲜度检查(步骤 0b)、写入KB_SNAPSHOT标记、写入kb_snapshot_id,并复制每轮对应的知识库归档。每次调用都必须记录知识库来源信息。
完成后,通知用户。