/architecture-doc -- Standalone Architecture Documentation
Produces or maintains docs/ARCHITECTURE_AND_DESIGN.md for any codebase,
independent of the /project → /define → /design flow. Two modes:
- Create -- the document does not exist (or the user opted to overwrite).
A scan sub-agent reads the code; a synthesis sub-agent writes a fresh
document conforming to the canonical template at
skills/project/design/assets/architecture-template.md. - Audit -- the document already exists. The same scan runs, but the synthesis sub-agent preserves user-authored content by returning the full updated document inline for the orchestrator to write.
Both modes share the scan pipeline and diverge only in the synthesis sub-agent. The skill opportunistically uses any MCP servers detected in the session to enrich its scan and synthesis, and degrades gracefully when none are present.
The authoritative design for this skill lives in
docs/ARCHITECTURE_AND_DESIGN.md at the root of the agentic-ai repository
that hosts this skill -- not the docs/ARCHITECTURE_AND_DESIGN.md this
skill produces at target_path. The two files share a filename but are
unrelated artifacts. Maintainers editing this orchestrator should read the
former.
Rules
- Read fresh every time. Re-check the existing document on every invocation; never trust cached state from a prior run.
- Mode is user-confirmed when ambiguous. Existing-document detection must
always go through
AskUserQuestionbefore overwriting or editing an existing file. Absent files enter Create mode silently. - Path-bounded scan. The scan sub-agent reads only paths inside the
resolved
target_path. Symlinks intarget_pathitself are tolerated; symlinks encountered during scan-time enumeration are never followed (Decision #9). - Never modify source code. This skill is documentation-only. Output is
restricted to
docs/ARCHITECTURE_AND_DESIGN.mdand the ephemeral scratch directorydocs/.architecture-doc/. - Interactive prompts. Use
AskUserQuestionfor all user-facing choices (max 2-4 options, ≤12-character headers). - No auto-dispatch. Tell the user what to run next. Never auto-invoke another skill.
Prerequisites
- A directory containing source code, supplied as
target_pathor defaulted to the current working directory. - The canonical template at
skills/project/design/assets/architecture-template.mdand the canonical scan heuristics atskills/project/design/references/gate-2-design.mdmust be readable from the running session. The skill aborts with an explicit error if either is missing -- there is no vendored fallback (Decision #4, Decision #5).
Step 1 -- Resolve and validate target_path
- If the user supplied a positional argument to
/architecture-doc, take that astarget_path. Otherwise default to the current working directory. - Resolve
target_pathto its absolute, canonical form. Symlinks in the path itself are followed and tolerated (a user invoking the skill from a symlinked project root is supported -- Decision #9 relaxation, Data Flow step 2). - Confirm the resolved path:
- exists, and
- is a directory.
- If either check fails, abort with a one-line error explaining which check failed and the resolved path. Do not create the scratch directory; do not proceed to Step 2.
The resolved absolute path is the working target_path for every later step
and is the prefix used by the scan sub-agent for path-boundary enforcement.
Step 2 -- Existing-document detection and mode selection
This step runs before any other work -- before the MCP probe, before scratch setup, before spawning any sub-agent.
- Compute
doc_path = <target_path>/docs/ARCHITECTURE_AND_DESIGN.md. - Test whether
doc_pathexists.- Absent → set
mode = Createand proceed to Step 3. No prompt.
- Absent → set
- If present, attempt to read the file and apply the plausibly Markdown
heuristic:
- The file is readable as UTF-8 text, and
- the file is non-empty, and
- the first non-blank line begins with
#(Markdown ATX heading).
- Branch on the heuristic:
Plausibly Markdown → call
AskUserQuestionwith three options:- Create -- "Overwrite the existing document with a freshly produced one." (header:
Create) - Audit -- "Update the existing document in place, preserving user-authored content." (header:
Audit) - Abort -- "Stop without changing anything." (header:
Abort)
Set
modefrom the user's choice. On Abort, exit cleanly with a one-line message. On Create, the existing document will be overwritten by the synthesis sub-agent in a later step.- Create -- "Overwrite the existing document with a freshly produced one." (header:
Not plausibly Markdown (unreadable, empty, or does not begin with a Markdown heading) → call
AskUserQuestionwith only two options:- Overwrite -- "Replace the existing file with a freshly produced architecture document." (header:
Overwrite) - Abort -- "Stop without changing anything." (header:
Abort)
Audit is not offered in this branch because the file cannot be reliably parsed or extended. Set
mode = Createif the user chose Overwrite; exit cleanly on Abort.- Overwrite -- "Replace the existing file with a freshly produced architecture document." (header:
- After Step 2 completes,
mode ∈ {Create, Audit}and the orchestrator proceeds to Step 3.
Implementation notes:
- "Readable as UTF-8" is determined by attempting
Readon the file. A failure or a binary-content indication counts as not plausibly Markdown. - "First non-blank line" means the first line whose content, after stripping whitespace, is non-empty. Leading blank lines are ignored.
- Known limitation -- YAML frontmatter is rejected. A Markdown file that
opens with a YAML frontmatter block (
---\ntitle: ...\n---\n\n# Heading) fails the heuristic because its first non-blank line is---, not a Markdown ATX heading. Such files are routed to the Not plausibly Markdown branch and Audit is not offered. This is intentional: the canonical template atskills/project/design/assets/architecture-template.mddoes not use frontmatter, so the common case is unaffected. If a user needs Audit on a frontmatter-bearing doc, they can strip the frontmatter and re-run, or choose Overwrite. - Mode selection is recorded only in the orchestrator's in-context state for
this run. It is not written to disk in this step (
run.logdoes not yet exist -- it is created in the scratch-setup step that belongs to a later feature).
Step 3 -- MCP capability probe
This step runs after Step 2 (mode is set) and before Step 4 (scratch
setup). It does not write anything to disk because run.log has not yet
been created -- the deferred writes happen at the start of Step 4. Probe
results are held in orchestrator context throughout.
The probe discovers what enrichment tools are available in this session so that Step 4.0 (language-server enrichment opt-in) and Step 8 (diagram enrichment opt-in) can present accurate per-run opt-in prompts -- the two halves of Feature 9. Per Decision #12, the probe is performed in the orchestrator context with no probe sub-agent.
Enumerate
mcp__-prefixed tools. Inspect the set of tools currently available to the orchestrator in this session. List every tool whose name begins with the prefixmcp__. Claude Code's MCP integration surfaces each MCP tool as a function namedmcp__<server>__<tool>; the probe reads its own tool surface, not any external configuration file. The probe is intentionally dynamic -- it does not consult a hardcoded list of known servers, so new servers in the session are seen automatically and removed servers vanish from the result without code changes.If no
mcp__tools are present, set the in-context structure toprobe = { tools: [], categories: {} }. The skill must continue to produce a full document with Read / Glob / Grep / Bash only; no warning is shown to the user, no degradation banner appears in the output. Proceed directly to Step 4.Categorise. Read
references/mcp-probe.mdand apply its categorisation heuristics to each detected tool name. Each tool is assigned to exactly one category; the first matching category in the reference file's order wins; anything unmatched falls intoother. Comparison is case-insensitive over the fullmcp__<server>__<tool>name.Build the in-context probe structure in the orchestrator:
probe = { tools: ["mcp__mermaid-mcp__generate", ...], categories: { diagram: ["mcp__mermaid-mcp__generate", ...], language_server: [...], code_search: [...], repo_intel: [...], other: [...] } }Empty categories may be omitted from or kept in the structure -- both are acceptable. The categories that drive enrichment prompts in this iteration are
diagramandlanguage_server; the remaining categories are recorded for diagnostics only.Do not write to disk in this step. The probe entries that belong in
run.logare emitted by Step 4 immediately after the scratch directory andrun.logare created. The exactrun.logline format -- one entry per non-empty category plus a summary line, or a singlenone-detectedsummary line ifprobe.toolsis empty -- is specified inreferences/mcp-probe.mdunder "Run-log lines emitted by Step 4".Proceed to Step 4.
Implementation notes:
- Coupling risk (Decision #12): the probe relies on the
mcp__<server>__<tool>naming convention. If that convention changes upstream, both the probe enumeration and the categorisation heuristics inreferences/mcp-probe.mdbreak. This is the price of the cheapest-possible probe; the alternative -- a probe sub-agent making trial calls -- was rejected in Decision #12. - The categories
code_search,repo_intel, andotherare recorded for diagnostics inrun.logbut not consumed by either enrichment opt-in -- onlydiagram(consumed by Step 8) andlanguage_server(consumed by Step 4.0) drive enrichment prompts. This keeps the Feature 9 surface narrow without losing detection coverage; the unused categories remain available for future enrichments.
Step 4 -- Scratch setup, run.log init, and scan sub-agent spawn
This step closes the Feature 3 deferred-write contract (writing the MCP
probe results to run.log once run.log exists), fires the
language-server enrichment opt-in (Feature 9, half of the Decision #17
opt-ins), spawns the scan sub-agent via the Agent tool, handles
preflight aborts and monorepo confirmation, runs a post-hoc
path-boundary check, and runs a secrets redaction pass over
findings.md before handing off to synthesis.
The scan sub-agent itself follows
skills/architecture-doc/references/scan-agent-prompt.md. The
orchestrator constructs the spawn prompt from that file and never
in-lines the scan logic itself.
Step 4.0 -- Language-server enrichment opt-in (conditional)
This substep is the scan-side half of Feature 9. The diagram-side
half (Mermaid embedding) fires later in Step 9, after the review loop
has approved the textual content. Both opt-ins are governed by
Decision #17 (per-run opt-in) and use the canonical prompt copy in
references/mcp-probe.md (Per-run opt-in prompt text section).
The language-server opt-in MUST fire here, before Step 4.5
constructs the scan agent spawn prompt, because the opt-in result
gates whether language-server tool names are passed to the scan
agent via the {{MCP_TOOLS_LIST}} substitution marker.
- Inspect
probe.categories.language_serverfrom Step 3. - If the list is empty (no language-server MCP detected), set
enrichment_choices.language_server = falsein orchestrator state and skip the rest of this substep -- proceed directly to Step 4.1. No prompt is shown to the user; this preserves the "baseline path unchanged when no enriching MCPs are present" guarantee from PRD Feature 8. - If the list is non-empty, read the canonical prompt copy from
references/mcp-probe.mdunder the heading### \language_server` enrichment prompt. Use the question text and the two options (Use LSP/Skip`) verbatim -- the reference file is the single source of truth for prompt wording so future copy edits land in one place. - Call
AskUserQuestionwith that question and those two options. - Branch on the user's choice:
- Use LSP: set
enrichment_choices.language_server = true. Hold the comma-separated list of detected language-server tool names in orchestrator state for Step 4.5's substitution. - Skip: set
enrichment_choices.language_server = false. The scan agent will run with its baseline tool allowlist only.
- Use LSP: set
- The result is not written to
run.loghere --run.logdoes not exist yet (Step 4.2 has not run). Hold the choice in orchestrator state and let Step 4.3 emit the deferred log line alongside the deferred probe writes. The deferred-write pattern is already established by the Feature 3 probe; reusing it keeps Step 4 internally consistent.
Note that this substep does not depend on <scratch_dir> or
run.log existing. It runs cleanly even if Step 4.1 has not been
reached yet. The numbering (4.0) reflects "before everything else
in Step 4".
Step 4.1 -- Create scratch directory
Create <scratch_dir> = <target_path>/docs/.architecture-doc/
(Decision #6).
- If
<target_path>/docs/does not exist, create it (mkdir -p). Creatingdocs/here is harmless even in Audit mode -- the directory must exist for the existing document to have been detected in Step 2. - If
<scratch_dir>already exists from a prior aborted run, reuse it -- do not error. Cleanup at the end of Step 10 will remove it. - If creation fails (e.g.
docs/exists as a file, permissions denied), abort with the OS error and the resolved path. Do not proceed.
Step 4.2 -- Initialise run.log
Create <scratch_dir>/run.log and write a session-start entry per
Decision #18 (<ISO8601> <level> <phase> <message> format):
<ISO8601> INFO session start target_path=<target_path> mode=<Create|Audit>
<ISO8601> is the current UTC time in YYYY-MM-DDTHH:MM:SSZ form.
<Create|Audit> is the mode resolved by Step 2.
Step 4.3 -- Write deferred MCP probe results
Honour the Feature 3 contract from
references/mcp-probe.md ("Run-log lines emitted by Step 4"):
- For every non-empty category in the in-context
probe.categoriesstructure built by Step 3, append one line:<ISO8601> INFO probe <category>=<comma-separated tool names> - Append one summary line listing the names of categories that had at
least one detected tool:
<ISO8601> INFO probe summary categories=<comma-separated category names> - If
probe.toolswas empty, append a single line and skip the per-category lines:<ISO8601> INFO probe summary none-detected
These writes complete the Feature 3 deferred-write obligation. The
in-context probe structure is preserved in orchestrator state because
Step 8 (MCP-enriched synthesis) consumes probe.categories.diagram to
drive the diagram-enrichment opt-in.
Then append the deferred Step 4.0 opt-in result -- this completes the Feature 9 language-server deferred-write obligation, the same pattern Step 3 uses for the probe itself:
- If
probe.categories.language_serverwas non-empty AND the user was prompted in Step 4.0, append:
where<ISO8601> INFO probe enrichment_optin language_server=<accepted|skipped><accepted|skipped>reflects the user's choice in Step 4.0. - If
probe.categories.language_serverwas empty (no prompt was shown), do not write any line for this enrichment. Thenone-detectedsummary line above already conveys the absence.
Step 4.4 -- Read prompt template and canonical heuristics
Read both files:
skills/architecture-doc/references/scan-agent-prompt.md-- the scan sub-agent prompt template.skills/project/design/references/gate-2-design.md-- the canonical scan heuristics referenced by the prompt (Decision #4 -- read in place, no vendored fallback).
If either read fails, abort with an explicit error naming the missing file. The skill aborts with an explicit error if either canonical file is missing -- there is no vendored fallback (Decisions #4 and #5).
Step 4.5 -- Construct the scan agent spawn prompt
Take the contents of scan-agent-prompt.md, strip the preamble (the
"Substitution markers" section above the --- BEGIN PROMPT ---
marker), keep only the body between --- BEGIN PROMPT --- and
--- END PROMPT ---, and substitute these tokens:
| Marker | Value |
|---|---|
{{TARGET_PATH}} |
The absolute, canonical target_path resolved in Step 1. |
{{MCP_TOOLS_LIST}} |
Comma-separated names of the language-server MCP tools the user opted in to in Step 4.0 -- i.e. the contents of probe.categories.language_server IF enrichment_choices.language_server == true, otherwise the literal none. Diagram MCPs and other categories are NEVER passed to the scan agent, even if detected: scan-side enrichment is language-server-only by design (Decision #17, Feature 9 acceptance criteria). The diagram MCP is consumed later in Step 8, in the orchestrator context, after synthesis and before the review loop. |
{{MONOREPO_ACKNOWLEDGED}} |
The literal false on first spawn. On a re-spawn after the user confirmed the monorepo warning in Step 4.7, the literal true. |
{{SCRATCH_DIR}} |
<target_path>/docs/.architecture-doc (no trailing slash). |
After substitution, no marker may remain in the prompt body. Verify by
searching for the literal {{ -- if any remain, abort with an
internal error.
Step 4.6 -- Spawn the scan sub-agent
Spawn the scan sub-agent via the Agent tool:
subagent_type:general-purpose. The Claude Code Agent tool does not expose per-spawn tool allowlists, so the scan agent's tool restrictions are enforced by prompt-level discipline -- the prompt forbidsEdit,Writeoutside the scratch path,Agent, network tools, and anyBashcommand other thanls -Randgit log --oneline -20. This matches the house pattern inskills/project/design/.description:Architecture scan of <basename(target_path)>.prompt: the constructed prompt body from Step 4.5.
Log the spawn to run.log:
<ISO8601> INFO scan spawn subagent_type=general-purpose monorepo_acknowledged=<true|false>
Step 4.7 -- Handle agent return and write findings.md
The scan agent's return text begins with a STATUS: line. Parse the
first line of the return and branch:
STATUS: success files_scanned=<N_arch>+<N_docs>- Parse the two integers separated by
+.<N_arch>is the number of architecture files read by the scan agent in Steps 3-4 of its prompt (15-30 budget);<N_docs>is the number of doc files read by the harvest in Step 5 of its prompt (0-15 budget). - Log:
<ISO8601> INFO scan return status=success arch_files=<N_arch> doc_files=<N_docs>. - Extract findings content. Parse the agent's return text for the
literal markers
--- BEGIN FINDINGS ---and--- END FINDINGS ---. Extract everything between these markers (excluding the markers themselves). If either marker is missing or malformed, treat this as an error (see error branch below). - Write findings.md. Use the
Writetool to write the extracted content to<scratch_dir>/findings.md. Log:<ISO8601> INFO scan findings_written path=<scratch_dir>/findings.md. - Both counts are surfaced in the final session summary printed by Step 10 (cleanup) so the user knows how much architecture vs. documentation context fed the produced doc.
- Proceed to Step 4.8 (path-boundary post-validation).
- Parse the two integers separated by
STATUS: preflight_abort reason=<empty|binary_only>- Log:
<ISO8601> WARN scan return status=preflight_abort reason=<reason>. - Print a one-line user-facing message:
Scan aborted: <reason>. No document was produced. - Jump to Step 10 (cleanup) and exit.
- Log:
STATUS: monorepo_warning signal=<signal>- Log:
<ISO8601> WARN scan return status=monorepo_warning signal=<signal>. - Call
AskUserQuestionwith two options:- Continue -- "Treat the monorepo root as a single project and scan it." (header:
Continue) - Abort -- "Stop without producing a document." (header:
Abort)
- Continue -- "Treat the monorepo root as a single project and scan it." (header:
- On Abort: log
<ISO8601> INFO scan monorepo abort, jump to Step 10 (cleanup), and exit. - On Continue: log
<ISO8601> INFO scan monorepo acknowledged, re-spawn the scan agent by repeating Steps 4.5 through 4.7 with{{MONOREPO_ACKNOWLEDGED}}set totrue. The re-spawned agent will skip the monorepo check and proceed.
- Log:
STATUS: error reason=<description>(or any unparseable return, or missing--- BEGIN FINDINGS ---/--- END FINDINGS ---markers)- Log:
<ISO8601> ERROR scan return status=error reason=<description>. - Print:
Scan agent failed: <description>. No document was produced. - Jump to Step 10 (cleanup) and exit.
- Log:
Step 4.8 -- Path-boundary post-validation
Read <scratch_dir>/findings.md (written by Step 4.7). Locate the
## Files Cited section
at the tail of the file (the scan agent's prompt requires every cited
file to appear there exactly once, one path per line, with no leading
bullet, backtick, or commentary). For each path in that section:
- Resolve to its absolute, canonical form via
realpath(usingBash, the one place the orchestrator usesBashfor filesystem operations outside the scan agent). - Verify the resolved absolute path begins with
<target_path>/(with the trailing slash, to prevent prefix-matching escapes like<target>foo/). - If any cited path fails the check, log:
then print<ISO8601> ERROR scan path_boundary_violation cited=<original> resolved=<absolute>Path boundary violation in scan findings: <cited>, jump to Step 10 (cleanup), and exit. Do not proceed to synthesis with a tainted findings file.
This is a defence-in-depth check on top of the prompt-level boundary
rule in scan-agent-prompt.md. Decision #9 makes path boundary a
security control; the cost of post-hoc validation is acceptable.
Step 4.9 -- Secrets redaction pass
Read skills/architecture-doc/references/redaction-patterns.md for the
canonical pattern list and the application rules. For each pattern in
the listed order, apply a regex replace over findings.md, replacing
matches with the literal string [REDACTED]. Track the per-pattern hit
count.
Log the result to run.log:
<ISO8601> INFO scan redacted findings.md hits=<total>
If <total> is greater than zero, also log a list of the matched
pattern names so a post-mortem can identify what category of secret the
scan agent attempted to write:
<ISO8601> WARN scan redaction findings.md patterns=<name1,name2,...>
The pattern list, log-line format, application order, and known
limitations all live in redaction-patterns.md -- this step is the
caller, not the source of truth. Synthesis Steps 6 and 7 will run an
analogous redaction pass over the produced architecture document.
After Step 4.9 completes, control passes to Step 5.
Step 5 -- Existing-documentation harvesting
Runs inside the scan sub-agent, not in the orchestrator. The
orchestrator does nothing extra for this step -- the harvest is
encoded in references/scan-agent-prompt.md under "Step 5 --
Existing documentation enumeration". Operationally, after the scan
agent finishes Step 4 (read selected source files) it enumerates
in-repo documentation -- README*, ARCHITECTURE*, DESIGN*,
CONTRIBUTING*, CHANGELOG*, RUNBOOK*, ADR directories,
docs/**/*.md|.mdx|.rst, and diagram source files (.mmd,
.drawio, .puml, .plantuml) -- caps the harvest at 15 doc
files (a separate budget from the 15-30 architecture file scan in
Step 3), summarises each in 1-3 sentences, and writes the results to
findings.md under the ## Existing Documentation section in a
parseable bullet format.
Synthesis (Steps 6 and 7) consumes the ## Existing Documentation
section of findings.md and is expected to cite source doc files
(by relative path) when a Design Decision, Component, or Data Flow
entry is drawn from existing documentation rather than from source
code. The exact citation discipline lives in the synthesis prompt
template and the canonical architecture template; this step only
guarantees that the existing-doc inventory is present in
findings.md for synthesis to draw on.
Doc files cited in the harvest also appear in the ## Files Cited
tail of findings.md, which means the orchestrator's Step 4.8
path-boundary post-validation already covers them -- no separate
boundary pass is needed. The Step 4.9 secrets redaction pass over
findings.md likewise applies to harvest output, so a doc file that
embeds an example credential is sanitised before synthesis sees it.
Step 6 -- Synthesis sub-agent: Create mode
This step runs only when mode = Create (resolved by Step 2). When
mode = Audit, skip Step 6 entirely and proceed to Step 7.
Step 6 spawns a synthesis sub-agent that reads findings.md (the
Step 4 output, already redacted by Step 4.9) plus the canonical
template, and writes a fresh docs/ARCHITECTURE_AND_DESIGN.md from
scratch via a single Write call. The synthesis sub-agent prompt
template lives at
skills/architecture-doc/references/synthesis-agent-prompt.md; the
orchestrator selects the BEGIN CREATE / END CREATE block,
substitutes tokens, and passes the body to the Agent tool.
After the agent returns, the orchestrator runs the post-synthesis secrets redaction pass (Decision #8) and a structural validation pass (six required section headers must be present).
Step 6.1 -- Verify the canonical template exists
Decision #5 makes the canonical template a hard runtime dependency with no vendored fallback. Verify before paying any synthesis cost:
- Resolve the absolute path to
skills/project/design/assets/architecture-template.mdrelative to the running session's location of theagentic-airepo hosting this skill. Readthe file. If the read fails for any reason, abort with the explicit error:Canonical architecture template missing: <resolved path>. The architecture-doc skill requires skills/project/design/assets/architecture-template.md to be readable; there is no vendored fallback (Decision #5).- Log to
run.log:<ISO8601> INFO synthesis template_ok path=<resolved path>
The template's content is not held in orchestrator state -- the synthesis sub-agent will Read it itself. The orchestrator only verifies existence so the run fails fast rather than after the scan.
Step 6.2 -- Read the synthesis prompt template and select the CREATE block
Read skills/architecture-doc/references/synthesis-agent-prompt.md.- Locate the literal markers
## --- BEGIN CREATE ---and## --- END CREATE ---. Keep only the body between them; discard everything before## --- BEGIN CREATE ---(the substitution-marker preamble) and everything from## --- END CREATE ---onward (which includes the Audit block stub). - If either marker is missing, abort with an internal error naming the missing marker.
Step 6.3 -- Substitute tokens
Apply token replacement to the CREATE block body:
| Marker | Value |
|---|---|
{{TARGET_PATH}} |
The absolute, canonical target_path from Step 1. |
{{OUTPUT_DOC_PATH}} |
<target_path>/docs/ARCHITECTURE_AND_DESIGN.md. |
{{FINDINGS_PATH}} |
<scratch_dir>/findings.md. |
{{TEMPLATE_PATH}} |
The absolute path resolved in Step 6.1. |
{{SCRATCH_DIR}} |
<target_path>/docs/.architecture-doc (no trailing slash). |
After substitution, search for the literal {{ in the prompt body.
If any markers remain, abort with an internal error -- the spawn
prompt is malformed.
Step 6.4 -- Spawn the synthesis sub-agent
Spawn via the Agent tool:
subagent_type:general-purpose. Same rationale as Step 4.6 -- Claude Code's Agent tool does not expose per-spawn tool allowlists, so the synthesis agent's tool restrictions are enforced by prompt-level discipline (the HARD RULE blocks insynthesis-agent-prompt.md).description:Architecture synthesis (Create) for <basename(target_path)>.prompt: the substituted CREATE block body from Step 6.3.
Log the spawn to run.log:
<ISO8601> INFO synthesis spawn mode=Create subagent_type=general-purpose
Step 6.5 -- Handle agent return and write output document
The synthesis agent's return text begins with a STATUS: line.
Parse the first line and branch:
STATUS: success decisions=<N_dec> components=<N_comp>- Parse the two integers.
<N_dec>is the number of Design Decision rows produced;<N_comp>is the number of Component Inventory rows. - Log:
<ISO8601> INFO synthesis return status=success decisions=<N_dec> components=<N_comp>. - Extract document content. Parse the agent's return text for the
literal markers
--- BEGIN DOCUMENT ---and--- END DOCUMENT ---. Extract everything between these markers (excluding the markers themselves). If either marker is missing or malformed, treat this as an error (see error branch below). - Write the output document. Use the
Writetool to write the extracted content to<output_doc_path>. Log:<ISO8601> INFO synthesis document_written path=<output_doc_path>. - Both counts are surfaced in the final session summary printed by Step 10.
- Proceed to Step 6.6 (output verification).
- Parse the two integers.
STATUS: error reason=<description>(or any unparseable return, or missing--- BEGIN DOCUMENT ---/--- END DOCUMENT ---markers)- Log:
<ISO8601> ERROR synthesis return status=error reason=<description>. - Print:
Synthesis agent failed: <description>. No document was produced. - Jump to Step 10 (cleanup) and exit. Do not run Step 6.6 / 6.7 / 6.8.
- Log:
Step 6.6 -- Verify the output document is non-empty
Read <output_doc_path> (written by Step 6.5). If the file is empty
(zero bytes or whitespace only), log
<ISO8601> ERROR synthesis output_empty path=<output_doc_path>,
print Synthesis produced an empty document., and jump to Step 10.
Step 6.7 -- Secrets redaction pass over the output document
Read skills/architecture-doc/references/redaction-patterns.md for
the canonical pattern list and the application rules (Step 4.9 of
this orchestrator already uses the same file). For each pattern in
the listed order, apply a regex replace over the output document,
replacing matches with the literal string [REDACTED]. Track the
per-pattern hit count.
Log the result to run.log:
<ISO8601> INFO synthesis redacted ARCHITECTURE_AND_DESIGN.md hits=<total>
If <total> is greater than zero, also log the matched pattern names
(Decision #8 -- post-mortem visibility into what category of secret
the synthesis agent attempted to write):
<ISO8601> WARN synthesis redaction ARCHITECTURE_AND_DESIGN.md patterns=<name1,name2,...>
The post-synthesis pass is the second of the two redaction passes
specified by Decision #8 -- the first was Step 4.9 over findings.md.
This pass is defence-in-depth: the synthesis agent works from the
already-redacted findings file, so secrets should not normally appear
in the output, but the agent has Read access to source files for
citation verification (Step 6.3 in the prompt) and could in principle
re-introduce a secret it observed there.
Step 6.8 -- Structural validation
PRD Feature 5 acceptance criterion: "Populates all six required sections". After redaction, verify the output document contains all six required ATX section headers, exactly as written below, in any order:
## Design Decisions
## Component Inventory
## Data Flow
## File Organization
## Deployment & Operations
## Security Considerations
Each header must appear as a top-level ## ATX heading on its own
line. If any are missing, log:
<ISO8601> WARN synthesis structural_validation missing=<comma-separated section names>
Do not abort the run on a structural validation failure -- the review loop in Step 9 gives the user the opportunity to surface and fix the gap. Surface the missing section names in the Step 9 summary so the user can address them in the first review pass. If the validation passes, log:
<ISO8601> INFO synthesis structural_validation ok
After Step 6.8 completes, control passes to Step 8 (the diagram
enrichment opt-in -- conditional on a diagram MCP being detected --
then onward to Step 9 review). Audit-mode Step 7 is skipped because
mode = Create.
Step 7 -- Synthesis sub-agent: Audit mode
This step runs only when mode = Audit (resolved by Step 2). When
mode = Create, Step 6 ran instead and Step 7 is skipped entirely.
Step 7 spawns a synthesis sub-agent that reads findings.md (the
Step 4 output, already redacted by Step 4.9), reads the existing
docs/ARCHITECTURE_AND_DESIGN.md in full, and updates that file
in place via Edit calls. The agent never uses Write. The
substance of every Audit-mode rule lives in
skills/architecture-doc/references/audit-mode.md; the synthesis
prompt's AUDIT block is a thin caller. The orchestrator selects the
BEGIN AUDIT / END AUDIT block, substitutes tokens, and passes
the body to the Agent tool.
After the agent returns, the orchestrator runs the post-synthesis secrets redaction pass (Decision #8 -- defence-in-depth) and a soft-warn structural validation pass.
Step 7.1 -- Verify the canonical template and audit rules exist
Decision #5 makes the canonical template a hard runtime dependency with no vendored fallback. The Audit-mode rules file is the same class of dependency for Audit mode. Verify both before paying any synthesis cost:
- Resolve the absolute path to
skills/project/design/assets/architecture-template.mdrelative to the running session's location of theagentic-airepo hosting this skill. Readthe template. If the read fails for any reason, abort with the explicit error:Canonical architecture template missing: <resolved path>. The architecture-doc skill requires skills/project/design/assets/architecture-template.md to be readable; there is no vendored fallback (Decision #5).- Resolve the absolute path to
skills/architecture-doc/references/audit-mode.md. Readthe audit-mode rules. If the read fails for any reason, abort with the explicit error:Audit-mode rules file missing: <resolved path>. Audit mode requires skills/architecture-doc/references/audit-mode.md to be readable.- Log to
run.log:<ISO8601> INFO synthesis template_ok path=<resolved template path> <ISO8601> INFO synthesis audit_rules_ok path=<resolved audit-mode.md path>
Neither file's contents are held in orchestrator state -- the synthesis sub-agent will Read them itself. The orchestrator only verifies existence so the run fails fast rather than after the scan.
Step 7.2 -- Read the synthesis prompt template and select the AUDIT block
Read skills/architecture-doc/references/synthesis-agent-prompt.md.- Locate the literal markers
## --- BEGIN AUDIT ---and## --- END AUDIT ---. Keep only the body between them; discard everything before## --- BEGIN AUDIT ---(the substitution-marker preamble plus the entire CREATE block) and everything from## --- END AUDIT ---onward. - If either marker is missing, abort with an internal error naming the missing marker.
This is the mirror of Step 6.2, which selects the CREATE block.
Step 7.3 -- Substitute tokens
Apply token replacement to the AUDIT block body:
| Marker | Value |
|---|---|
{{TARGET_PATH}} |
The absolute, canonical target_path from Step 1. |
{{OUTPUT_DOC_PATH}} |
<target_path>/docs/ARCHITECTURE_AND_DESIGN.md -- the existing doc (must already exist; mode = Audit was set in Step 2 because it does). |
{{FINDINGS_PATH}} |
<scratch_dir>/findings.md. |
{{TEMPLATE_PATH}} |
The absolute path resolved in Step 7.1. |
{{AUDIT_RULES_PATH}} |
The absolute path to skills/architecture-doc/references/audit-mode.md resolved in Step 7.1. |
{{SCRATCH_DIR}} |
<target_path>/docs/.architecture-doc (no trailing slash). |
After substitution, search for the literal {{ in the prompt body.
If any markers remain, abort with an internal error -- the spawn
prompt is malformed.
Step 7.4 -- Spawn the synthesis sub-agent
Spawn via the Agent tool:
subagent_type:general-purpose. Same rationale as Step 6.4 -- Claude Code's Agent tool does not expose per-spawn tool allowlists, so the synthesis agent's tool restrictions are enforced by prompt-level discipline (the HARD RULE blocks in the AUDIT block ofsynthesis-agent-prompt.mdplus the rules inaudit-mode.md).description:Architecture synthesis (Audit) for <basename(target_path)>.prompt: the substituted AUDIT block body from Step 7.3.
Log the spawn to run.log:
<ISO8601> INFO synthesis spawn mode=Audit subagent_type=general-purpose
Step 7.5 -- Handle agent return and write output document
The synthesis agent's return text begins with a STATUS: line.
Parse the first line and branch:
STATUS: success new_decisions=<N_new> findings=<N_findings> contradictions=<N_contra>- Parse the three integers.
<N_new>is the number of new Design Decision rows appended to the existing table.<N_findings>is the total number of rows in the Audit Findings block (includingmissing-type rows for the appended decisions).<N_contra>is the subset of<N_findings>whoseTypeiscontradiction. In the empty case all three are0. - Log:
<ISO8601> INFO synthesis return status=success mode=Audit new_decisions=<N_new> findings=<N_findings> contradictions=<N_contra>. - Extract document content. Parse the agent's return text for the
literal markers
--- BEGIN DOCUMENT ---and--- END DOCUMENT ---. Extract everything between these markers (excluding the markers themselves). If either marker is missing or malformed, treat this as an error (see error branch below). - Write the output document. Use the
Writetool to write the extracted content to<output_doc_path>. Log:<ISO8601> INFO synthesis document_written path=<output_doc_path> mode=Audit. - All three counts are surfaced in the final session summary printed by Step 10. The contradictions count is highlighted in the Step 9 review prompt because it is the most actionable signal for the user.
- Capture optional post-document summary text. Per
references/audit-mode.md("After the document block, the agent MAY include a brief human-readable summary"), any text after the--- END DOCUMENT ---marker in the agent's return is held in orchestrator state asaudit_agent_summary(capped at 200 words; truncate silently if longer). Step 10.2 prints this verbatim under the fixed-shape summary block when it is non-empty. If the agent returned no text after the document block, leaveaudit_agent_summaryunset. - Proceed to Step 7.6 (output verification).
- Parse the three integers.
STATUS: error reason=<description>(or any unparseable return, or missing--- BEGIN DOCUMENT ---/--- END DOCUMENT ---markers)- Log:
<ISO8601> ERROR synthesis return status=error mode=Audit reason=<description>. - Print: `Audit synthesis agent failed: <descri
- Log:
…(truncated)