Architect (/mantis-architecture)
System Goal
Knowledge Base Synthesizer. Translates ephemeral insights from the learnings
queue (workspace/learnings.jsonl) and structural analysis of the codebase into
a canonical, interlinked Markdown Knowledge Base (workspace/kb/).
Command Definition
- Command:
/mantis-architecture
- Description: Builds the foundation of the KB by defining system
architecture, mapping specific entities (components), and categorizing
historical vulnerability patterns.
- Arguments (all optional; resolved by LOCATOR RESOLUTION / Block A):
--snapshot_root=<dir> (or the SNAPSHOT_ROOT env var) — the pinned code
snapshot to read target source from; --snapshot_id=<id> — the SNAPSHOT_ID
of that snapshot; --state_root=<dir> — the parent of workspace/ for all
state and KB paths; --target_root=<dir> — an already-prepared tree that
OVERRIDES the snapshot (rarely passed to this stage). When none are passed,
behavior is byte-for-byte today's (degraded/unpinned): read source from the
current directory and treat snapshot_pinned as false.
Input/Output Contract
- Reads:
workspace/learnings.jsonl (raw insights from the current round).
workspace/historical_learnings.jsonl (optional, past vulnerability
metadata).
- Codebase directory structure and key source files.
- Existing Markdown files in
workspace/kb/ (to validate/decay check).
workspace/.mantis_state.json (to retrieve pass count).
workspace/.mantis_state.json → active_snapshot (root, snapshot_id,
snapshot_pinned) and snapshot_history — provenance for the KB freshness
gate (step 0b). Read the snapshot from STATE ONLY; NEVER run a live VCS
command (git/hg/repo) to decide KB currency.
workspace/.mantis_state.json → kb_snapshot_id (the SNAPSHOT_ID the
current KB was last built against; absent on a first/legacy KB).
workspace/.mantis_state.json → changed_files and changed_files_status
(written by mantis-plan's Block E; consumed by the scoped KB invalidation in
step 0b outcome 3. Present from pass 2 on, but may be stale (written in a
prior pass) — the scoped path checks changed_files_pass against
state.pass_number and falls back to full rebuild if they differ.)
- Writes:
- Markdown files under
workspace/kb/ (architecture.md,
entities/[component_name].md, vulnerabilities/[CWE-ID].md, index.md).
workspace/kb/dependencies.json — a JSON map of import/dependency edges
extracted during architectural analysis (keys = source file paths relative
to CODE_ROOT; values = arrays of files that import/depend on the key file).
This is consumed by mantis-plan's dependency-aware fan-out (Phase 2). If
the codebase has no parseable import structure, write {}. Re-derive only
changed entries during scoped invalidation (see outcome 3 below).
- Archives
workspace/learnings.jsonl to
workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl.
- A
<!-- KB_SNAPSHOT: <SNAPSHOT_ID> --> marker as the FIRST line of every
(re)written KB file (index.md, each entities/*.md, each
vulnerabilities/*.md), plus kb_snapshot_id = SNAPSHOT_ID in
workspace/.mantis_state.json.
- An immutable per-pass copy of the whole KB tree to
workspace/archive/kb/kb_pass_${N}_${X}/ (so a later reverted fix cannot
silently erase the record of what the KB claimed at pass N).
- Preconditions:
workspace/learnings.jsonl must exist.
- Idempotency Guarantee:
- Transactional: moves
workspace/learnings.jsonl to archive only after
programmatically verifying all KB Markdown updates were written
successfully. KB files are overwritten in-place.
- Snapshot stamping is part of the same transaction: the
KB_SNAPSHOT
markers, the per-pass workspace/archive/kb/kb_pass_${N}_${X_kb}/ copy, and
the kb_snapshot_id state write complete before (or together with) the
learnings move. On any failure, leave workspace/learnings.jsonl intact.
Instructions
Analyze the codebase and pending learnings to construct a permanent,
Markdown-based memory for future agents.
Execute the architecture stage as follows:
- LOCATOR RESOLUTION (Block A, inlined below):
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.
This is a CODE-READING stage (steps 2 and 4 read target source), so Block A
steps 1-6 all apply; it is NOT findings-only. Resolve CODE_ROOT,
SNAPSHOT_ID, and snapshot_pinned from state BEFORE doing anything below. Per
Block A step 3, all workspace/kb/... paths are STATE-RELATIVE: read and write
them under state_root/workspace, NEVER under CODE_ROOT. Read all target
source under CODE_ROOT. Do NOT run any VCS command to decide KB freshness
(Block A step 5's carve-out is only for history/diff/blame, which this stage
does not use).
0b. KB SNAPSHOT FRESHNESS GATE (mechanical; STATE + KB marker only, NO live
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.
```
Read the Inbox (workspace/learnings.jsonl and
workspace/historical_learnings.jsonl):
- Parse the contents of
workspace/learnings.jsonl (and
workspace/historical_learnings.jsonl if it exists). Extract all
trajectory insights, discovered vulnerabilities, viable crash paths, and
verified patches.
Analyze Source Code Boundaries:
- Examine the directory structure and key source files under
CODE_ROOT
(the pinned snapshot resolved by Block A; use absolute paths per Block A
step 6, and do NOT run a VCS command). Dynamically identify the core
components, interfaces, and trust boundaries of the system based on the
repository's contents. This applies broadly across domains: whether it is a
software system (e.g., identifying parsers, controllers, or network
daemons), a hardware/RTL design (e.g., identifying IP blocks, JTAG
interfaces, or memory controllers), Infrastructure-as-Code (e.g.,
identifying cloud permissions, VPC perimeters, or deployment descriptors),
or data/ML pipelines (e.g., identifying data ingress points, model
serialization mechanisms, or training boundaries).
Build or Update the Knowledge Base (KB):
Create or update files in the workspace/kb/ directory using standard
Markdown. Follow these strict paths:
workspace/kb/architecture.md: High-level data flows, zone definitions,
system design, and overall availability/uptime requirements (if
documented or inferable from configuration like systemd, kubernetes, or
load balancers).
workspace/kb/entities/[component_name].md: Specific definitions for
components (e.g., auth_module.md). Must include links to associated
vulnerability classes and document known constraints (e.g., "This module
sanitizes input X"). Document the component's criticality and
availability requirements (classify as CRITICAL, STANDARD, or
LOW_CRITICALITY if applicable). Incorporate trajectory insights here.
workspace/kb/vulnerabilities/[CWE-ID_or_BugClass].md: Descriptions of
bug classes (e.g., CWE-79.md or Memory-Corruption.md) that have been
historically relevant to this codebase, including examples of what not
to do.
workspace/kb/index.md: A root catalog containing links and 1-line
summaries to every file created above. This is the map the Planner will
read.
Important Formatting Rules: Use relative links to cross-reference
entities and vulnerabilities (e.g.,
[Auth Module](entities/auth_module.md)). Ensure all markdown files are
concise and focused on actionable security context.
Snapshot stamping (REQUIRED on every (re)written KB file when running the
freshness gate, i.e. HALT or PINNED; never in MODE-OFF): Make the FIRST
line of index.md, each entities/*.md, and each vulnerabilities/*.md
exactly <!-- KB_SNAPSHOT: <SNAPSHOT_ID> --> (substitute CUR from step
0b; it is an HTML comment so it does not render). This is how the next
pass's freshness gate (step 0b) detects drift. MODE-OFF gate (3-state
rule): if active_snapshot is ABSENT (MODE-OFF — no --sync was
requested), do NOT stamp the per-file KB_SNAPSHOT marker: CUR is the
empty string (arch:145: "the empty string if active_snapshot was
absent"), so the mandated marker would be <!-- KB_SNAPSHOT: --> (empty
value) — a snapshot-era artifact that did not exist in Phase 1. The
per-file marker is ONLY consumed by step 0b's freshness gate, which
MODE-OFF skips entirely (arch:147-152: "SKIP the freshness gate
entirely... This is byte-for-byte today's behavior. Only HALT and PINNED
run the gate below."). This MODE-OFF gate mirrors the freshness gate logic
below and step 0b's outcome clauses, which mention per-file
KB_SNAPSHOT: CUR stamping only in HALT/PINNED outcomes (CURRENT :164,
scoped BUILD FRESH :178, full BUILD FRESH :195).
Per-file KB_SNAPSHOT stamping is the sole provenance mechanism for KB
assertions. Do NOT write per-assertion (AS_OF:<snapshot>) tags — the
AS_OF re-verification reader was never built, and staleness protection is
already provided by the freshness gate (step 0b) comparing kb_snapshot_id
to SNAPSHOT_ID, plus per-finding discovery_commit (enforced by
mantis-critic Block B). A later-reverted fix is caught by these
mechanisms, not by per-assertion tags.
Validate and Decay Knowledge (Drift Prevention):
- Knowledge becomes stale when code is patched or refactored. Before
finalizing the KB updates, spot-check the assertions in the existing
workspace/kb/entities/ against the source under CODE_ROOT (the
pinned snapshot — NOT a live VCS query, and NOT the live working tree). In
the BUILD FRESH outcome (step 0b) do NOT spot-check at all: discard the
prior assertions and re-derive every entity from CODE_ROOT this pass. In
the STALE / HALT outcome, spot-check only best-effort and keep the
STALE banner regardless of the result.
- If an entity file claims a variable is un-sanitized (based on an old
learning) but the live code now contains a sanitization function (because a
patch landed), delete or correct that outdated learning in the KB.
- If a learning is repeatedly proven wrong by the current trajectory
insights, actively correct it to prevent the "wrong learning" from
persisting and blinding future agents.
- When you correct or re-confirm a finding-derived assertion, re-stamp the
KB_SNAPSHOT marker on that KB file.
Transactional Inbox Clearing & Archiving:
- To prevent infinite loops and token bloat, you must clear the queue and
archive the learnings.
- Verify and Finalize: Programmatically verify that all Markdown KB
updates were successfully written to disk and that cross-references are
valid. Also verify, before committing, that every (re)written KB file
BEGINS with its
<!-- KB_SNAPSHOT: <SNAPSHOT_ID> --> marker and that every
finding-derived verdict is grounded in the current SNAPSHOT_ID.
- Commit by Moving: Only after verifying synthesis success, move
workspace/learnings.jsonl to the archive directory:
- Ensure the target directory exists (e.g.,
mkdir -p workspace/archive/learnings/).
- Determine the loop pass number
N by reading "pass_number" from
workspace/.mantis_state.json. If missing or invalid, scan
workspace/archive/ for folders matching findings_pass_N or
loopN_findings and resolve N to max_found + 1, defaulting to 1 if
no archives exist.
- Determine the sub-index
X by counting existing files matching
learnings_pass_${N}_*.jsonl in workspace/archive/learnings/ and
adding 1.
- Move the file:
mv workspace/learnings.jsonl workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl.
- Snapshot the KB (per-pass archive): After a successful synthesis, copy
the whole KB tree to a per-pass archive:
- Ensure the directory exists (
mkdir -p workspace/archive/kb/).
- Compute sub-index
X_kb = (count of existing kb_pass_${N}_*
directories in workspace/archive/kb/) + 1.
- Copy (do NOT move — the live
workspace/kb/ must persist for the next
pass): cp -a workspace/kb/. workspace/archive/kb/kb_pass_${N}_${X_kb}/.
- Stamp state: Write
kb_snapshot_id = SNAPSHOT_ID (CUR from step
0b) into workspace/.mantis_state.json. If active_snapshot was absent
(MODE-OFF), do NOT write kb_snapshot_id and do NOT prepend any STALE
banner (the freshness gate was skipped). In HALT mode, write
kb_snapshot_id = CUR and leave the STALE banner in index.md.
- If synthesis fails or is interrupted, leave
workspace/learnings.jsonl
intact in its original location to ensure no data is lost.
- If
workspace/learnings.jsonl is ABSENT on entry (e.g. the Stage-15
invocation, because the Stage-2 invocation already archived it this pass),
skip ONLY the learnings move; STILL run the freshness gate (step 0b), stamp
the KB_SNAPSHOT markers, write kb_snapshot_id, and copy the per-pass KB
archive. KB provenance must be recorded on every invocation.
When complete, notify the user.
1---2name: mantis-architecture3description: Synthesizes raw learnings and codebase analysis into an interlinked Markdown Knowledge Base (KB). Use at the beginning of a loop to build or update architecture.md, entities, and vulnerabilities. Don't use for generating threat models or formulating execution plans.4---5
6# Architect (/mantis-architecture)
7
8## System Goal
9
10Knowledge Base Synthesizer. Translates ephemeral insights from the learnings
11queue (`workspace/learnings.jsonl`) and structural analysis of the codebase into
12a canonical, interlinked Markdown Knowledge Base (`workspace/kb/`).
13
14## Command Definition
15
16- **Command:** `/mantis-architecture`
17- **Description:** Builds the foundation of the KB by defining system
18 architecture, mapping specific entities (components), and categorizing
19 historical vulnerability patterns.
20- **Arguments (all optional; resolved by LOCATOR RESOLUTION / Block A):**
21 `--snapshot_root=<dir>` (or the `SNAPSHOT_ROOT` env var) — the pinned code
22 snapshot to read target source from; `--snapshot_id=<id>` — the `SNAPSHOT_ID`
23 of that snapshot; `--state_root=<dir>` — the parent of `workspace/` for all
24 state and KB paths; `--target_root=<dir>` — an already-prepared tree that
25 OVERRIDES the snapshot (rarely passed to this stage). When none are passed,
26 behavior is byte-for-byte today's (degraded/unpinned): read source from the
27 current directory and treat `snapshot_pinned` as false.
28
29## Input/Output Contract
30
31- **Reads**:
32 - `workspace/learnings.jsonl` (raw insights from the current round).
33 - `workspace/historical_learnings.jsonl` (optional, past vulnerability
34 metadata).
35 - Codebase directory structure and key source files.
36 - Existing Markdown files in `workspace/kb/` (to validate/decay check).
37 - `workspace/.mantis_state.json` (to retrieve pass count).
38 - `workspace/.mantis_state.json` → `active_snapshot` (`root`, `snapshot_id`,
39 `snapshot_pinned`) and `snapshot_history` — provenance for the KB freshness
40 gate (step 0b). Read the snapshot from STATE ONLY; NEVER run a live VCS
41 command (`git`/`hg`/`repo`) to decide KB currency.
42 - `workspace/.mantis_state.json` → `kb_snapshot_id` (the `SNAPSHOT_ID` the
43 current KB was last built against; absent on a first/legacy KB).
44 - `workspace/.mantis_state.json` → `changed_files` and `changed_files_status`
45 (written by mantis-plan's Block E; consumed by the scoped KB invalidation in
46 step 0b outcome 3. Present from pass 2 on, but may be stale (written in a
47 prior pass) — the scoped path checks `changed_files_pass` against
48 `state.pass_number` and falls back to full rebuild if they differ.)
49- **Writes**:
50 - Markdown files under `workspace/kb/` (`architecture.md`,
51 `entities/[component_name].md`, `vulnerabilities/[CWE-ID].md`, `index.md`).
52 - `workspace/kb/dependencies.json` — a JSON map of import/dependency edges
53 extracted during architectural analysis (keys = source file paths relative
54 to CODE_ROOT; values = arrays of files that import/depend on the key file).
55 This is consumed by `mantis-plan`'s dependency-aware fan-out (Phase 2). If
56 the codebase has no parseable import structure, write `{}`. Re-derive only
57 changed entries during scoped invalidation (see outcome 3 below).
58 - Archives `workspace/learnings.jsonl` to
59 `workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl`.
60 - A `<!-- KB_SNAPSHOT: <SNAPSHOT_ID> -->` marker as the FIRST line of every
61 (re)written KB file (`index.md`, each `entities/*.md`, each
62 `vulnerabilities/*.md`), plus `kb_snapshot_id` = `SNAPSHOT_ID` in
63 `workspace/.mantis_state.json`.
64 - An immutable per-pass copy of the whole KB tree to
65 `workspace/archive/kb/kb_pass_${N}_${X}/` (so a later reverted fix cannot
66 silently erase the record of what the KB claimed at pass N).
67- **Preconditions**:
68 - `workspace/learnings.jsonl` must exist.
69- **Idempotency Guarantee**:
70 - Transactional: moves `workspace/learnings.jsonl` to archive only after
71 programmatically verifying all KB Markdown updates were written
72 successfully. KB files are overwritten in-place.
73 - Snapshot stamping is part of the same transaction: the `KB_SNAPSHOT`
74 markers, the per-pass `workspace/archive/kb/kb_pass_${N}_${X_kb}/` copy, and
75 the `kb_snapshot_id` state write complete before (or together with) the
76 learnings move. On any failure, leave `workspace/learnings.jsonl` intact.
77
78## Instructions
79
80Analyze the codebase and pending learnings to construct a permanent,
81Markdown-based memory for future agents.
82
83Execute the architecture stage as follows:
84
850. **LOCATOR RESOLUTION (Block A, inlined below):**
86
87```
88LOCATOR RESOLUTION (before reading ANY target code or artifact):
890. ROLE: If this skill NEVER reads target source (report, calibrate, reflect),
90 you are a FINDINGS-ONLY stage: skip steps 2-6; still read active_snapshot from
91 state for provenance/annotation; NEVER stop merely because a code root is unset.
921. Determine CODE_ROOT, in this priority order:
93 a. If --target_root is passed on THIS invocation, CODE_ROOT = --target_root.
94 It is AUTHORITATIVE and OVERRIDES SNAPSHOT_ROOT and the state fallback
95 (used when a caller hands you a prepared tree, e.g. a patched shadow).
96 b. Else if --snapshot_root (or SNAPSHOT_ROOT) is passed, use it.
97 c. Else read state_root/workspace/.mantis_state.json (state_root from
98 --state_root if passed, else ./workspace/... relative to the current dir)
99 -> active_snapshot.root / .snapshot_id / .snapshot_pinned.
100 d. Else (no arg AND no readable active_snapshot): CODE_ROOT = current directory,
101 treat snapshot_pinned = false (MODE-OFF). Do NOT stop.
1022. SENTINEL CHECK (only if snapshot_pinned is true AND you did NOT take path 1a):
103 verify CODE_ROOT/.mantis_snapshot_id exists and equals SNAPSHOT_ID. If missing
104 or different -> STOP "snapshot sentinel mismatch". (A --target_root tree (1a) is
105 deliberately mutated and is sentinel-EXEMPT.)
1063. PATH FIELDS:
107 - SNAPSHOT-RELATIVE (read under CODE_ROOT): code_paths entries; plan target_files
108 that are file paths. Strip ONLY a trailing ":<digits>". A code_paths entry
109 containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is
110 NOT of the form <existing-path>:<integer> is a non-source LOCATOR
111 (symbol/offset/endpoint): only check that the artifact/symbol exists; skip ALL
112 line-range and line-existence logic.
113 - STATE-RELATIVE (read/write under state_root/workspace, NEVER prefix CODE_ROOT):
114 kb_references, repro_file_path, reattack_file_path, helper scripts, report
115 files, and all state/findings JSON.
1164. Never WRITE under CODE_ROOT when snapshot_pinned is true. Any command that
117 compiles, generates, or writes artifacts MUST run in a PRIVATE SHADOW copy
118 (mktemp -d from CODE_ROOT), never with cwd=CODE_ROOT. Read-only inspection may
119 cd into CODE_ROOT.
1205. VCS-METADATA CARVE-OUT: history-log extraction and any VCS diff/blame command
121 run in the LIVE repository root (which still has .git/.hg/.repo), NOT CODE_ROOT
122 (the snapshot copy strips VCS metadata). Do NOT stop merely because CODE_ROOT
123 lacks .git/.hg/.repo.
1246. Every shell command uses ABSOLUTE paths and sets its own working directory on
125 that call. Do NOT assume the working directory persists between calls.
126```
127
128This is a CODE-READING stage (steps 2 and 4 read target source), so Block A
129steps 1-6 all apply; it is NOT findings-only. Resolve `CODE_ROOT`,
130`SNAPSHOT_ID`, and `snapshot_pinned` from state BEFORE doing anything below. Per
131Block A step 3, all `workspace/kb/...` paths are STATE-RELATIVE: read and write
132them under `state_root/workspace`, NEVER under `CODE_ROOT`. Read all target
133source under `CODE_ROOT`. Do NOT run any VCS command to decide KB freshness
134(Block A step 5's carve-out is only for history/diff/blame, which this stage
135does not use).
136
1370b. **KB SNAPSHOT FRESHNESS GATE (mechanical; STATE + KB marker only, NO live
138VCS):**
139
140````
141- `CUR` = `SNAPSHOT_ID` (resolved by Block A; the empty string if
142 `active_snapshot` was absent). `PINNED` = `snapshot_pinned` (false if absent).
143- **MODE-OFF short-circuit (3-state rule):** if `active_snapshot` is ABSENT
144 in state (no `--sync` was requested — MODE-OFF = today's default), SKIP the
145 freshness gate entirely: do a best-effort build/update against `CODE_ROOT`,
146 do NOT prepend any STALE banner, and do
147 NOT stamp `kb_snapshot_id`. This is byte-for-byte today's behavior. (Only
148 HALT and PINNED run the gate below.)
149- `KB_ID` = the `kb_snapshot_id` value in `.mantis_state.json` (primary); else the
150 text after `KB_SNAPSHOT:` on the FIRST line of
151 `state_root/workspace/kb/index.md` if that file exists (secondary fallback,
152 for legacy runs without state); else `""` (no prior KB). State is primary so
153 the file-marker parsing pitfall (comment-wrapped first line, no `-->`
154 stripping) can never strand `KB_ID` with the comment closer and force BUILD
155 FRESH every pass.
156- Choose EXACTLY ONE outcome by string checks, top to bottom, first match wins:
157 1. `PINNED` is false (HALT mode — `active_snapshot` present but unpinned)
158 -> **STALE / HALT.** Do a best-effort build/update against `CODE_ROOT`,
159 but PREPEND the STALE banner (below) as the first lines of `index.md`.
160 Do NOT claim currency: leave the
161 banner in place. Set `kb_snapshot_id` = `CUR` (a `live:` id).
162 2. Else `KB_ID` == `CUR` (both non-empty) -> **CURRENT.** Do the incremental
163 update + decay-check (step 4) as today. Re-stamp `KB_SNAPSHOT: CUR` on
164 every (re)written file. REMOVE any STALE banner previously prepended to
165 `index.md`.
166 3. Else (`PINNED` true AND (`KB_ID` is empty OR `KB_ID` != `CUR`)) ->
167 **BUILD FRESH (full or scoped re-architecture).** The pinned code advanced
168 since the KB was built (a sync / pass-boundary change), OR the KB is
169 unstamped / legacy. Choose full or scoped:
170 - **Scoped invalidation (Phase 2 incremental efficiency):** If
171 `changed_files_status` is known (not UNKNOWN) AND the KB already has a
172 `KB_SNAPSHOT` stamp (KB_ID was non-empty, just different) AND
173 `changed_files_pass` equals the current `state.pass_number` (the diff
174 is from THIS pass, not a stale prior pass — absent or different →
175 treat as UNKNOWN → full rebuild below), attempt a SCOPED rebuild: only
176 invalidate KB entries whose source files are in `changed_files`, plus
177 their parent-rollup dependents (KB entities that import/reference the
178 changed files). Re-derive ONLY those entries from `CODE_ROOT`; carry
179 forward all other KB entries unchanged (they were built against the
180 same code, just a different snapshot ID). Re-stamp `KB_SNAPSHOT: CUR`
181 on every (re)written file.
182 - **Parent-rollup (2-hop, matching plan's fan-out):** When
183 invalidating a KB entry for changed file F, also invalidate any KB
184 entry that REFERENCES F directly (1-hop) AND any entry that
185 references a 1-hop dependent of F (2-hop). This matches
186 `mantis-plan`'s dependency-aware fan-out (which expands up to 2
187 hops), ensuring that a grandchild entity (H imports G, G imports
188 changed F) is not carried forward stale and later fed as a
189 `kb_reference` while its dependency has changed.
190 - **Guardrail:** If ANY uncertainty arises (can't determine which KB
191 entries map to which source files, the KB structure is ambiguous, or
192 changed_files is empty but KB_ID != CUR), fall back to full rebuild
193 below. Never carry forward a stale entry for a changed file.
194 - **Full rebuild (Phase-1 fallback):** If KB_ID is empty (no prior KB),
195 OR `changed_files_status` is UNKNOWN, OR the scoped invalidation guardrail
196 fired, REBUILD every KB file from scratch against `CODE_ROOT`. Do NOT
197 carry forward any prior assertion you have not re-derived from
198 `CODE_ROOT` this pass. Stamp `KB_SNAPSHOT: CUR`. REMOVE any STALE banner.
199- STALE banner (paste verbatim, substituting `<KB_ID>` and `<CUR>`; keep the
200 leading `>` on every line so it renders as a visible blockquote):
201
202 ```
203 > **STALE KB WARNING — do not trust without re-verifying.**
204 > snapshot_pinned=false, or the KB was built against a different snapshot.
205 > KB_SNAPSHOT=<KB_ID> does not match active_snapshot.snapshot_id=<CUR>.
206 > Every SECURE/FIXED/NON_VIABLE/SAMPLE_OR_TEST claim below is UNVERIFIED
207 > against the current code. Re-verify before trusting; do NOT filter, skip,
208 > or down-prioritize work based on this KB.
209 ```
210````
211
2121. **Read the Inbox (`workspace/learnings.jsonl` and
213 `workspace/historical_learnings.jsonl`):**
214
215 - Parse the contents of `workspace/learnings.jsonl` (and
216 `workspace/historical_learnings.jsonl` if it exists). Extract all
217 trajectory insights, discovered vulnerabilities, viable crash paths, and
218 verified patches.
219
2202. **Analyze Source Code Boundaries:**
221
222 - Examine the directory structure and key source files **under `CODE_ROOT`**
223 (the pinned snapshot resolved by Block A; use absolute paths per Block A
224 step 6, and do NOT run a VCS command). Dynamically identify the core
225 components, interfaces, and trust boundaries of the system based on the
226 repository's contents. This applies broadly across domains: whether it is a
227 software system (e.g., identifying parsers, controllers, or network
228 daemons), a hardware/RTL design (e.g., identifying IP blocks, JTAG
229 interfaces, or memory controllers), Infrastructure-as-Code (e.g.,
230 identifying cloud permissions, VPC perimeters, or deployment descriptors),
231 or data/ML pipelines (e.g., identifying data ingress points, model
232 serialization mechanisms, or training boundaries).
233
2343. **Build or Update the Knowledge Base (KB):**
235
236 - Create or update files in the `workspace/kb/` directory using standard
237 Markdown. Follow these strict paths:
238
239 - `workspace/kb/architecture.md`: High-level data flows, zone definitions,
240 system design, and overall availability/uptime requirements (if
241 documented or inferable from configuration like systemd, kubernetes, or
242 load balancers).
243 - `workspace/kb/entities/[component_name].md`: Specific definitions for
244 components (e.g., `auth_module.md`). Must include links to associated
245 vulnerability classes and document known constraints (e.g., "This module
246 sanitizes input X"). Document the component's criticality and
247 availability requirements (classify as CRITICAL, STANDARD, or
248 LOW_CRITICALITY if applicable). Incorporate trajectory insights here.
249 - `workspace/kb/vulnerabilities/[CWE-ID_or_BugClass].md`: Descriptions of
250 bug classes (e.g., `CWE-79.md` or `Memory-Corruption.md`) that have been
251 historically relevant to this codebase, including examples of what *not*
252 to do.
253 - `workspace/kb/index.md`: A root catalog containing links and 1-line
254 summaries to every file created above. This is the map the Planner will
255 read.
256
257 - **Important Formatting Rules:** Use relative links to cross-reference
258 entities and vulnerabilities (e.g.,
259 `[Auth Module](entities/auth_module.md)`). Ensure all markdown files are
260 concise and focused on actionable security context.
261
262 - **Snapshot stamping (REQUIRED on every (re)written KB file when running the
263 freshness gate, i.e. HALT or PINNED; never in MODE-OFF):** Make the FIRST
264 line of `index.md`, each `entities/*.md`, and each `vulnerabilities/*.md`
265 exactly `<!-- KB_SNAPSHOT: <SNAPSHOT_ID> -->` (substitute `CUR` from step
266 0b; it is an HTML comment so it does not render). This is how the next
267 pass's freshness gate (step 0b) detects drift. **MODE-OFF gate (3-state
268 rule):** if `active_snapshot` is ABSENT (MODE-OFF — no `--sync` was
269 requested), do NOT stamp the per-file `KB_SNAPSHOT` marker: `CUR` is the
270 empty string (`arch:145`: "the empty string if `active_snapshot` was
271 absent"), so the mandated marker would be `<!-- KB_SNAPSHOT: -->` (empty
272 value) — a snapshot-era artifact that did not exist in Phase 1. The
273 per-file marker is ONLY consumed by step 0b's freshness gate, which
274 MODE-OFF skips entirely (`arch:147-152`: "SKIP the freshness gate
275 entirely... This is byte-for-byte today's behavior. Only HALT and PINNED
276 run the gate below."). This MODE-OFF gate mirrors the freshness gate logic
277 below and step 0b's outcome clauses, which mention per-file
278 `KB_SNAPSHOT: CUR` stamping only in HALT/PINNED outcomes (CURRENT `:164`,
279 scoped BUILD FRESH `:178`, full BUILD FRESH `:195`).
280
281 - **Per-file `KB_SNAPSHOT` stamping is the sole provenance mechanism for KB
282 assertions.** Do NOT write per-assertion `(AS_OF:<snapshot>)` tags — the
283 `AS_OF` re-verification reader was never built, and staleness protection is
284 already provided by the freshness gate (step 0b) comparing `kb_snapshot_id`
285 to `SNAPSHOT_ID`, plus per-finding `discovery_commit` (enforced by
286 `mantis-critic` Block B). A later-reverted fix is caught by these
287 mechanisms, not by per-assertion tags.
288
2894. **Validate and Decay Knowledge (Drift Prevention):**
290
291 - Knowledge becomes stale when code is patched or refactored. Before
292 finalizing the KB updates, spot-check the assertions in the existing
293 `workspace/kb/entities/` against the source **under `CODE_ROOT`** (the
294 pinned snapshot — NOT a live VCS query, and NOT the live working tree). In
295 the **BUILD FRESH** outcome (step 0b) do NOT spot-check at all: discard the
296 prior assertions and re-derive every entity from `CODE_ROOT` this pass. In
297 the **STALE / HALT** outcome, spot-check only best-effort and keep the
298 STALE banner regardless of the result.
299 - If an entity file claims a variable is un-sanitized (based on an old
300 learning) but the live code now contains a sanitization function (because a
301 patch landed), **delete or correct that outdated learning** in the KB.
302 - If a learning is repeatedly proven wrong by the current trajectory
303 insights, actively correct it to prevent the "wrong learning" from
304 persisting and blinding future agents.
305 - When you correct or re-confirm a finding-derived assertion, re-stamp the
306 `KB_SNAPSHOT` marker on that KB file.
307
3085. **Transactional Inbox Clearing & Archiving:**
309
310 - To prevent infinite loops and token bloat, you must clear the queue and
311 archive the learnings.
312 - **Verify and Finalize:** Programmatically verify that all Markdown KB
313 updates were successfully written to disk and that cross-references are
314 valid. Also verify, before committing, that every (re)written KB file
315 BEGINS with its `<!-- KB_SNAPSHOT: <SNAPSHOT_ID> -->` marker and that every
316 finding-derived verdict is grounded in the current `SNAPSHOT_ID`.
317 - **Commit by Moving:** Only after verifying synthesis success, move
318 `workspace/learnings.jsonl` to the archive directory:
319 - Ensure the target directory exists (e.g.,
320 `mkdir -p workspace/archive/learnings/`).
321 - Determine the loop pass number `N` by reading `"pass_number"` from
322 `workspace/.mantis_state.json`. If missing or invalid, scan
323 `workspace/archive/` for folders matching `findings_pass_N` or
324 `loopN_findings` and resolve `N` to `max_found + 1`, defaulting to 1 if
325 no archives exist.
326 - Determine the sub-index `X` by counting existing files matching
327 `learnings_pass_${N}_*.jsonl` in `workspace/archive/learnings/` and
328 adding 1.
329 - Move the file:
330 `mv workspace/learnings.jsonl workspace/archive/learnings/learnings_pass_${N}_${X}.jsonl`.
331 - **Snapshot the KB (per-pass archive):** After a successful synthesis, copy
332 the whole KB tree to a per-pass archive:
333 - Ensure the directory exists (`mkdir -p workspace/archive/kb/`).
334 - Compute sub-index `X_kb` = (count of existing `kb_pass_${N}_*`
335 directories in `workspace/archive/kb/`) + 1.
336 - Copy (do NOT move — the live `workspace/kb/` must persist for the next
337 pass): `cp -a workspace/kb/. workspace/archive/kb/kb_pass_${N}_${X_kb}/`.
338 - **Stamp state:** Write `kb_snapshot_id` = `SNAPSHOT_ID` (`CUR` from step
339 0b) into `workspace/.mantis_state.json`. If `active_snapshot` was absent
340 (MODE-OFF), do NOT write `kb_snapshot_id` and do NOT prepend any STALE
341 banner (the freshness gate was skipped). In HALT mode, write
342 `kb_snapshot_id` = `CUR` and leave the STALE banner in `index.md`.
343 - If synthesis fails or is interrupted, leave `workspace/learnings.jsonl`
344 intact in its original location to ensure no data is lost.
345 - If `workspace/learnings.jsonl` is ABSENT on entry (e.g. the Stage-15
346 invocation, because the Stage-2 invocation already archived it this pass),
347 skip ONLY the learnings move; STILL run the freshness gate (step 0b), stamp
348 the `KB_SNAPSHOT` markers, write `kb_snapshot_id`, and copy the per-pass KB
349 archive. KB provenance must be recorded on every invocation.
350
351When complete, notify the user.