--- name: mantis-architecture description: >- 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. --- # 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=` (or the `SNAPSHOT_ROOT` env var) — the pinned code snapshot to read target source from; `--snapshot_id=` — the `SNAPSHOT_ID` of that snapshot; `--state_root=` — the parent of `workspace/` for all state and KB paths; `--target_root=` — 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 `` 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: 0. **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 ":". A code_paths entry containing "://" is a URL/endpoint, NOT a file read. A code_paths entry that is NOT of the form : 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 `` and ``; 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= does not match active_snapshot.snapshot_id=. > 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. ``` ```` 1. **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. 2. **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). 3. **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 `` (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 `` (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:)` 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. 4. **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. 5. **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 `` 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.