LLM-based architectural analysis that transforms raw project data into meaningful structure
Resources
2Install
npx skillscat add cuioss/plan-marshall/manage-architecture Install via the SkillsCat registry.
Manage Architecture Skill
Scope: hybrid means this skill manages both project-level data (.plan/project-architecture/) and integrates with plan-scoped workflows (solution-outline, task-plan).
Enforcement
Base contract: See manage-contract.md for shared enforcement rules, TOON output format, and error response patterns.
Skill-specific constraints:
- Execute all steps in sequence; only stop when all modules are enriched
- Do not leave
responsibilityorkey_packagesempty after enrichment - Do not skip
--reasoningparameters (traceability is required) - Enrichment must cover every discovered module before completion
- Discovery must run before enrichment (Step 1 before Steps 4-8)
Migration completeness — enumerate every read path before declaring a derivation migration done. This skill exposes derived structures (the build_map behind derive-verification, the resolve command envelope, the files/graph inventories) that multiple consumers read. When a change reshapes any such derivation — its schema, its command mapping, or the canonical accessor — the migration is NOT complete until EVERY read path of that derivation has been enumerated and updated. An incomplete fix that migrates the primary accessor while leaving a parallel raw-read consumer on the old shape is a defect, not a partial success: the unmigrated read path silently returns the old structure and corrupts its downstream branch. Before declaring such a migration done, enumerate every reader of the derivation (architecture find first, grep fallback for sub-module call sites) and confirm each one was migrated — a single surviving raw read of the pre-change shape fails the gate.
Scripts
| Script | Notation | Purpose |
|---|---|---|
| architecture | plan-marshall:manage-architecture:architecture |
Main CLI for all operations |
Command Groups
| Group | API | Purpose |
|---|---|---|
discover, init |
manage-api | Setup commands |
derived, derived-module |
manage-api | Read raw discovered data |
enrich * |
manage-api | Write enrichment data |
suggest-domains |
— | Suggest applicable skill domains for a module |
info, module, modules, commands, resolve |
client-api | Consumer queries |
derive-verification |
resolve-command | Derive the deterministic verification command set for a changed-artifact list (single build_map consumer) |
files, which-module, find, search |
client-api | Files-inventory readers (categorised paths, reverse lookup over a four-rung ladder ending in the Axis-D path-attribution seam, then the two search verbs: find is a path glob that never opens a file, search --content is the file-content reader) |
graph, path, neighbors, impact |
client-api | Dependency graph queries (full graph, shortest path, n-hop neighborhood, reverse-dep closure) |
capabilities |
client-api | Envelope capability report — which query capabilities are answerable right now (module edges, path attribution, content search), distinguishing cannot-derive from derived-nothing |
lsp hover, lsp references, lsp workspace-symbol, lsp definition |
client-api | Additive LSP-shaped facade over module / impact / find / resolve — addresses the query surface in editor/agent vocabulary; renames nothing (see client-api § "LSP-shaped query facade") |
overview |
client-api | Token-bounded markdown summary of the project architecture |
diff-modules |
client-api | Drift detection vs a pre-snapshot (added/removed/changed/unchanged buckets) |
Step 1: Discover Modules
Run extension API discovery:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture discover --forceOutput: .plan/project-architecture/_project.json plus per-module{module}/derived.json and an empty {module}/enriched.json stub for every
discovered module. The whole tree is staged under.plan/project-architecture.tmp/ and swapped into place atomically — an
interrupted run leaves either the old layout or the new layout intact.
Always overwrites the existing tree to ensure fresh discovery.
Step 2: Review Build Profiles (Maven Only)
Condition: Only if any module has build_systems containing maven.
Check each module's derived.json for NO-MATCH-FOUND profiles inmetadata.profiles.
If Maven modules exist AND unmatched profiles found:
Load skill pm-dev-java:manage-maven-profiles and follow its workflow to:
- Ask user about each unmatched profile (Ignore/Skip/Map)
- Apply configuration via
run_configcommands - Re-run discovery to apply changes
If no Maven modules OR no unmatched profiles → Skip to Step 3.
Step 3: Initialize Enrichment
Check whether per-module enriched.json stubs already exist:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture init --checkinit --check reports how many modules already carry an enriched.json
file under their per-module directory.
If stubs exist, ask user:
AskUserQuestion:
question: "Per-module enriched.json stubs already exist. What do you want to do?"
header: "Enrichment"
options:
- label: "Skip"
description: "Keep existing enrichments, continue to next step"
- label: "Replace"
description: "Discard existing enrichments, start fresh"
multiSelect: false| Choice | Command |
|---|---|
| Skip | Proceed to Step 4 |
| Replace | architecture init --force --reset (destructive — blanks all existing enrichment back to the empty stub) |
If file does not exist:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture initStep 4: Load Data & Enrich Project
Load the raw discovered data:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture derivedRead referenced READMEs for modules that have them. Based on the README and module descriptions, write a 1-2 sentence project description:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich project --description "{extracted project description}" \
--reasoning "{source: README.md introduction | inferred from module names}"Get the module list:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture modulesSteps 5-8: Per-Module Enrichment
For each module in the list, execute Steps 5-8 in order (dependencies: Step 5 feeds Steps 6-7, Step 8 runs last):
Get raw discovered data for the module:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture derived-module --module {module-name}Read the referenced documentation:
Read {paths.readme}
Read {package_info path} # for packages with package_infoIf no documentation available, sample 2-3 source files from packages.
Analyze to determine purpose value (see also architecture-persistence.md for full list):
| Signal | Purpose Value |
|---|---|
| packaging=jar, no runtime deps | library |
| Quarkus extension annotations | extension |
| Build-time processor, deployment | deployment |
| Main class, application entry | runtime |
| packaging=pom at root | parent |
| Bill of Materials POM | bom |
| Only test files | integration-tests |
| JMH benchmarks | benchmark |
Step 6: Write Responsibility
Write 1-3 sentences describing what the module does, with reasoning:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich module --name {module-name} \
--responsibility "{1-3 sentence description}" \
--responsibility-reasoning "{source}" \
--purpose {purpose-value} \
--purpose-reasoning "{signal}"Step 7: Key Packages & Dependencies
Select 2-4 architecturally significant packages per module (choose packages that represent the module's core abstractions, public API, or key implementation concerns):
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich package --module {module-name} \
--package {full.package.name} \
--description "{1-2 sentence description}"Identify key dependencies (both --key and --internal are optional — omit either when not applicable):
# External + internal dependencies
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich dependencies --module {module-name} \
--key "{comma-separated list of groupId:artifactId}" \
--internal "{comma-separated list of internal module names}" \
--reasoning "{why these are architecturally significant}"
# Internal dependencies only (no external deps)
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich dependencies --module {module-name} \
--internal "{comma-separated list of internal module names}" \
--reasoning "{why these are architecturally significant}"Step 8: Resolve Skill Domains
Get applicable domains for this module:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
suggest-domains --module {module-name}Present suggestions to user for confirmation:
AskUserQuestion:
question: "Which skill domains apply to '{module-name}'?"
header: "Skill Domains"
options: [{domain} ({confidence}) — {signals}]
multiSelect: trueFor each confirmed domain, add its default skills:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich add-domain --module {module-name} --domain {domain-key} \
--reasoning "{domain}: {signals}"For domains where optional skills also apply (e.g., CDI detected, Lombok used),
add with --include-optionals:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich add-domain --module {module-name} --domain {domain-key} \
--include-optionals --reasoning "{domain}: all skills apply based on {signals}"To override profile filtering for a specific module (e.g., force integration_testing on a module
that lacks automatic signals), use --profiles:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture \
enrich add-domain --module {module-name} --domain {domain-key} \
--profiles implementation,module_testing,integration_testing \
--reasoning "explicit IT profile for {reason}"Profile resolution order: --profiles flag > marshal.json active_profiles > extension signal detection > all defined profiles.
Batch: enrich all
Purpose: Batch-populate skills_by_profile for every module × every applicable extension in one call. Useful when you want to initialize (or back-fill) skills across the entire project without iterating enrich add-domain per module/domain pair.
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich allFlags:
| Flag | Purpose |
|---|---|
--include-optionals |
Include optional skills in addition to defaults |
--reasoning |
Shared rationale appended to every enriched module |
Notes:
- Idempotent — safe to re-run. Only new (module, domain) pairs increment
pairs_applied; already-present skills are not duplicated. - Returns a summary with
modules_enriched,pairs_applied,pairs_skipped, anderrorsfor traceability. - The
systemdomain is always skipped (reserved for internal use). - Prose may refer to this as the
enrich-allcommand; CLI invocations always use the space-separated formenrich all(same shape asenrich add-domain).
Step 9: Verify & Summarize
After all modules are enriched, verify completeness:
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture infoCheck that:
- Every module has non-empty
responsibility - Every module has valid
purpose - Every module has 2-4
key_packageswith descriptions - Every module has
key_dependenciesidentified (unless no compile-scope deps) - Every module has
skills_by_profilewith at leastimplementationandmodule_testing
If any module is incomplete → return to Steps 5-8 for that module.
Display completion summary:
Architecture analysis complete.
Project: {project name}
Modules enriched: {count}
Files created:
- .plan/project-architecture/_project.json
- .plan/project-architecture/{module}/derived.json (per module)
- .plan/project-architecture/{module}/enriched.json (per module)
Next steps:
- Solution outline will use this data for placement decisions
- Run 'architecture.py module --module X' to query module detailsCanonical invocations
The canonical argparse surface for architecture.py. The D4 plugin-doctor analyzer
(_analyze_manage_invocation.py) reads this section as source-of-truth for markdown
notation occurrences across the marketplace. Consuming skills xref this section by
name (e.g., "see manage-architecture Canonical invocations → files") instead of
restating the command inline.
All subcommands accept the mutually-exclusive routing pair --project-dir DIR (default.) and --plan-id PLAN_ID; see `plan-marshall:tools-script-executor/standards/cwd-policy.md`
for the Bucket A/B two-state contract.
discover
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture discover \
[--force]init
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture init \
[--check] [--force] [--reset]derived
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture derivedderived-module
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture derived-module \
--module MODULEinfo
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture infomodules
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture modules \
[--command FILTER_COMMAND]module
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture module \
[--module MODULE] [--full] [--budget LINES]overview
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture overview \
[--budget LINES]commands
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture commands \
[--module MODULE]resolve
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture resolve \
--command COMMAND [--module MODULE]derive-verification
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture derive-verification \
--changed-artifacts PATH1,PATH2,...Derives the deterministic verification command set for a comma-separated changed-artifact list. Each path is classified to a build_class via the tree-derived build_map (longest-glob-wins), grouped by class, and resolved to the architecture-command set. The build_class value names the canonical command directly — there is no indirection map between the class and the command it resolves (build_class: compile resolves compile, build_class: verify resolves verify). A docs-only changed set derives zero Python builds. See resolve-command.md § "Build-class → verification command" for the canonical mapping and Output example.
graph
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture graph \
[--full]path
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture path \
SOURCE TARGETneighbors
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture neighbors \
--module MODULE [--depth N]impact
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture impact \
--module MODULEsiblings
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture siblings \
--module MODULEsuggest-domains
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture suggest-domains \
--module MODULEprofiles
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture profiles \
[--modules MODULE_LIST]files
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture files \
--module MODULE [--category CATEGORY]--category is one of the declared file-inventory vocabulary: agent, build_file, command, doc, script, skill, skill_doc, source, standard, template, test. The vocabulary is declared once as FILE_CATEGORIES in scripts/_architecture_core.py; client-api.md is the authoritative client contract.
Coverage: inside a marketplace bundle, every file under skills/<skill>/ is inventoried regardless of its sub-directory name or its file extension — a file that is not a skill, script, standard, template, build_file or doc classifies as skill_doc. Outside a bundle, the generic classifier is extension-driven and inventories .md / .adoc / .asciidoc as doc.
Zero-result semantics: an unrecognised --category returns status: error, error: unknown_category carrying the valid vocabulary in valid_categories — it is never a confident empty list. A recognised category that this module does not populate returns status: success with files: [].
which-module
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture which-module \
--path PATHResolves --path to its owning module over a four-rung ladder — exact-inventory
match, paths.sources ∪ paths.tests containment, the Axis-D path-attribution
seam, then the root module. Every response carries the fail-closed pairstruncated / elided and attributors / attributor_count (plusattributor_notes), so attributor_count: 0 with module: null ("no attributor
ran") stays distinguishable from attributor_count: N with module: null ("N
ran and none claimed this path"). See
client-api.md § which-module for the full response
contract.
find
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture find \
--pattern PATTERN [--category CATEGORY]--pattern is a path glob (fnmatch syntax, case-sensitive, anchored to the full path). find matches the PATH only and never opens a file, so a token that exists solely inside a file body is invisible to it — that is the verb behaving exactly as designed, not a defect. For content questions ("which file contains X?") use search --content below.
--category takes the same vocabulary and the same zero-result semantics as the files verb above: an unrecognised name returns status: error, error: unknown_category, while a recognised-but-unpopulated category returns status: success with count: 0.
search
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture search \
--content --pattern PATTERN [--category CATEGORY] [--literal] [--ignore-case]Searches inventoried file bodies and reports the module-attributed files containing --pattern. This is the sanctioned content-search path for a dispatched leaf whose Grep / Glob tools are unavailable and whose Bash file-search commands are refused by the PreToolUse enforcement hook.
--content is the mode selector and is argparse-required — a bare search --pattern X is rejected at parse time rather than defaulting to a mode, so the mode stays explicit at every call site.
--pattern is a Python regex by default; --literal matches it verbatim (re.escape), which is what makes a pattern full of shell metacharacters safe and exact. No caller input ever reaches a shell. A pattern that fails to compile returns status: error, error: invalid_pattern carrying the compile message.
--ignore-case adds re.IGNORECASE and composes with --literal: a metacharacter-bearing pattern can be matched verbatim AND case-insensitively at once — the one combination the inline (?i) regex marker cannot express under --literal (re.escape neutralises it). Regex-mode (?i) still works. The echoed ignore_case boolean names the population the match set was computed over.
--category takes the same vocabulary and the same unknown-category semantics as the files verb above.
The result carries both count (result ROWS — one per module/category/path hit) and file_count (DISTINCT paths); they diverge only for an unclaimed cross-module duplicate. Read file_count for "how many files contain this?".
capabilities
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture capabilitiesReports which query capabilities are answerable right now, in the executing envelope — module_edges (graph/path/neighbors/impact), path_attribution (which-module), and content_search (files/find/search) — each distinguishing cannot-derive (no producer ran) from derived-nothing. Read from producers that actually ran (never the declaration), recomputed per call (never cached across dispatches), and scoped to the executing --project-dir. See client-api.md § capabilities for the full contract.
lsp
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture lsp hover \
--module MODULE [--full]
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture lsp references \
--module MODULE
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture lsp workspace-symbol \
--query QUERY [--category CATEGORY]
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture lsp definition \
--command COMMAND [--module MODULE]The additive LSP-shaped facade: lsp hover → module, lsp references → impact, lsp workspace-symbol → find, lsp definition → resolve. Each returns the underlying verb's answer unchanged — the facade adds LSP vocabulary over the existing verbs and renames nothing; the four traversal/inventory residue verbs (path, impact, find, which-module) stay reachable under their own names. See client-api.md § "LSP-shaped query facade" for the per-verb mapping table.
Anchors are per line: the pattern is compiled with re.MULTILINE, so ^ matches at the start of every LINE and $ at the end of every line — the same semantics grep, ripgrep, and the harness Grep tool give them. An anchored sweep such as --pattern '^Skill: plan-marshall:manage-files' therefore finds a directive on any line of a file, not only one starting at byte 0, and match_count counts every such line. The engine is Python re, not POSIX: write \s for whitespace, never a POSIX bracket class like [[:space:]] — Python still compiles that (as a nested set, emitting a FutureWarning on stderr) and it then silently over-matches, so the failure arrives as spurious hits rather than as an error or a zero.
Payload boundary: a hit carries exactly module, category, path, and match_count — the response never carries matching line text. match_count (the number of non-overlapping matches in that file) is the ranking signal: use it to decide which few files are worth a Read. Do not expect to see the matched lines.
Inventory-scope boundary: the search covers the crawled file inventory, which by construction excludes always-ignored directories (.git, node_modules, target, caches), dotfile trees outside the .gitignore / .editorconfig allowlist (so .claude/** and .github/** are NOT searched), and anything a .gitignore rule excludes. A zero result therefore means "not in any inventoried file", which is not the same as "not in the tree".
Zero-result semantics: count: 0 is never confident on its own. Every response also carries files_scanned (so "nothing was searched" stays distinguishable from "N files searched, genuinely absent"), unreadable[{path,reason}] (files skipped for a decode or OS error, rather than silently dropped), and the fail-closed truncated / elided pair.
See client-api.md § search for the full pattern contract, the worked TOON payloads, and every edge case.
diff-modules
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture diff-modules \
--pre PRE_SNAPSHOT_DIRenrich project
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich project \
--description TEXT [--reasoning TEXT]enrich module
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich module \
--name MODULE --responsibility TEXT \
[--purpose VALUE] [--reasoning TEXT] \
[--responsibility-reasoning TEXT] [--purpose-reasoning TEXT]enrich package
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich package \
--module MODULE --package PACKAGE --description TEXT \
[--components LIST]enrich skills-by-profile
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich skills-by-profile \
--module MODULE --skills-json JSON [--reasoning TEXT]enrich dependencies
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich dependencies \
--module MODULE [--key LIST] [--internal LIST] [--reasoning TEXT]enrich tip
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich tip \
--module MODULE --tip TEXTenrich insight
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich insight \
--module MODULE --insight TEXTenrich best-practice
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich best-practice \
--module MODULE --practice TEXTenrich add-domain
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich add-domain \
--module MODULE --domain DOMAIN \
[--include-optionals] [--reasoning TEXT] [--profiles PROFILE_LIST]enrich all
python3 .plan/execute-script.py plan-marshall:manage-architecture:architecture enrich all \
[--include-optionals] [--reasoning TEXT]Error Handling
| Error | Resolution |
|---|---|
| Extension API not found | Verify domain bundles installed, run /marshall-steward |
| No modules discovered | Verify build files exist and domain bundle matches project |
| Documentation not found | Analyze source code directly, note "Inferred from source analysis" |
| Partial discovery failure | Some extensions may fail while others succeed — check which modules are missing and re-run discover --force after fixing the failing extension |
| Interrupted enrichment | Safe to resume — enrich module overwrites per-module data; re-run Steps 5-8 for incomplete modules |
manage-maven-profiles skill unavailable |
Skip Step 2 entirely; unmatched profiles will remain as NO-MATCH-FOUND in each module's derived.json |
Post-Implementation Enrichment
During verification or after implementation, capture learnings:
| Command | Usage |
|---|---|
enrich tip |
--module {name} --tip "Use @ApplicationScoped for singleton services" |
enrich insight |
--module {name} --insight "Heavy validation happens in boundary layer" |
enrich best-practice |
--module {name} --practice "Always validate tokens before extracting claims" |
Deferred Loading
Load standards documents in the order listed — each builds on the previous:
| # | Reference | When to Load |
|---|---|---|
| 1 | manage-api.md | First — covers setup, raw data, enrich commands (Steps 1-8), and orchestration flow |
| 2 | architecture-persistence.md | When you need field schemas, purpose values, skills_by_profile structure, module graph format, or documentation source priorities |
| 3 | client-api.md | When consuming enriched data (Step 9 verification, or downstream skills) |
| 4 | arch-gate-fitness-functions.md | When working with arch-gate — the architectural-fitness-function canonical command, its per-domain tool binding, and the arch-constraint findings/lesson lifecycle |
| 5 | pm-dev-java:manage-maven-profiles |
Only during Step 2, only for Maven projects with unmatched profiles |
Integration
This skill is invoked by:
- marshall-steward wizard Step 13 (Project Structure Analysis)
- Direct activation when regenerating project structure
Output is consumed by:
- solution-outline Step 0 (module placement)
- task-plan (command resolution)
Related
manage-solution-outline— Consumes architecture data for placement decisionsmanage-config— Project-level configuration used during analysismanage-files— Generic file operations used during discovery