Decision Register
Consolidated decisions from 115 feature(s), 1 service(s), and 4 principle(s).
Summary
| ID | Decision | Status | Source |
|---|---|---|---|
| use-deps-not-inline | Use battle-tested CLI libraries, not hand-rolled inline helpers | accepted | usm/cli-color-output |
| respect-no-color | Honor NO_COLOR env var and non-TTY stdout/stderr by emitting plain text | accepted | usm/cli-color-output |
| palette | green=✓, red=✗, yellow=⚠, cyan=→/info, dim=secondary values | accepted | usm/cli-color-output |
| cjs-pin-versions | Pin dependency versions to CJS-compatible majors | accepted | usm/cli-color-output |
| outputs-from-config | All generators read output paths from usmconfig.json outputs section | accepted | usm/cli-config-outputs |
| generate-only-flag | Replace generate:xxx commands with generate --only <target> flag | accepted | usm/cli-config-outputs |
| scaffold-project-to-subcommand | Rename scaffold-project to 'scaffold project' (subcommand) | accepted | usm/cli-config-outputs |
| no-dependency | Implement port probing with Node.js built-in net module — no third-party depende | accepted | usm/docs-serve-port-check |
| auto-port-opt-in | Auto-port selection is opt-in via --auto-port flag, not the default. | accepted | usm/docs-serve-port-check |
| lsof-best-effort | Process detection via lsof is best-effort only — graceful degradation if lsof is | accepted | usm/docs-serve-port-check |
| pid-file-approach | Use a PID file (.usm-workspace/.vitepress.pid) for already-serving detection, no | accepted | usm/docs-serve-port-check |
| watch-in-process | Watch-mode regeneration runs usm generate --only docs in-process (calling the ge | accepted | usm/docs-serve-port-check |
| debounce-500ms | Watch-mode debounce is 500ms — a pragmatic balance between responsiveness and av | accepted | usm/docs-serve-port-check |
| vitepress-over-custom | Use VitePress as the rendering layer instead of building a custom server | accepted | usm/cli-docs |
| unified-docs-directory | All generated docs write to a single docs/ directory instead of scattered .agent | accepted | usm/cli-docs |
| sidebar-from-system-index | Auto-generate VitePress sidebar config from system.usm index + feature directory | accepted | usm/cli-docs |
| vitepress-optional-dependency | VitePress is an optional peer dependency, not bundled with USM | accepted | usm/cli-docs |
| dont-commit-generated-docs | Generated docs are not committed to the repo — served locally and deployed via C | accepted | usm/cli-docs |
| internal-over-external | Internal (host-language) DSL, not a custom grammar | — | usm/internal-dsl-builder |
| runtime-schema-validation | Enforce constraints by validating at build() rather than type-level branding | — | usm/internal-dsl-builder |
| all-35-in-docs | Generate per-editor setup pages for all 35 editors | accepted | usm/mcp-setup-guides |
| top-10-logos | Marketing site ToolLogos shows top 10 editors only | accepted | usm/mcp-setup-guides |
| index-plus-per-editor | Index page plus per-editor pages (shadcn pattern) | accepted | usm/mcp-setup-guides |
| rules-files-per-editor | Document rules/skills file installation on each editor page where supported | accepted | usm/mcp-setup-guides |
| stdio-config-pattern | Use the standard USM stdio pattern (usm mcp serve) for all editors | accepted | usm/mcp-setup-guides |
| manifest-based-detection | Detect services by language manifest files | accepted | usm/cli-multi-lang-scan |
| framework-specific-route-detection | Detect routes per-framework, not per-language | accepted | usm/cli-multi-lang-scan |
| configurable-in-usmconfig | Language/framework detection rules are configurable in usmconfig.json | accepted | usm/cli-multi-lang-scan |
| all-languages-from-start | Support all major languages from the initial implementation | accepted | usm/cli-multi-lang-scan |
| detectors-directory | Add .usm/detectors/*.yaml as a second auto-discovered extension surface alongsid | accepted | usm/cli-multi-lang-scan |
| script-escape-hatch | Allow routes.script in a detector to point at a .ts/.js file exporting extractRo | accepted | usm/cli-multi-lang-scan |
| generalized-orchestrator | Generalize structural.ts service detection so any detector manifest drives it, r | accepted | usm/cli-multi-lang-scan |
| infrastructure-as-detector | Treat infrastructure (Terraform today) as a detector kind rather than a hardcode | accepted | usm/cli-multi-lang-scan |
| precedence-order | Detector precedence is built-in defaults < .usm/detectors/ files < usmconfig.jso | accepted | usm/cli-multi-lang-scan |
| tiny-grammar-not-sql | A ~200-line recursive-descent grammar, not SQL/jq subset | — | usm/query-layer |
| missing-field-is-false | Unknown/absent fields make predicates false instead of erroring | — | usm/query-layer |
| capability-registry-pattern | Capabilities self-describe (detect + setup + introducedIn); upgrade orchestrates | accepted | usm/upgrade |
| usm-version-field-for-alignment | Use system.usm.usm_version for USM-tool alignment, NOT the project's own version | accepted | usm/upgrade |
| schema-version-independence | Schema $version moves independently of the package version: additive schema chan | accepted | usm/upgrade |
| setup-owned-by-capability | Each registry entry owns its own setup function (interactive + default); upgrade | accepted | usm/upgrade |
| interactive-with-flag-fallback | TTY prompts per capability; --apply uses defaults for CI/scripts; --check is rep | accepted | usm/upgrade |
| non-destructive | Upgrade only adds missing blocks and bumps usm_version; existing config is never | accepted | usm/upgrade |
| homepage-simplify-not-remove | Simplify the homepage by removing marketing content, not by removing the homepag | accepted | usm/vitepress-home-feedback-schema |
| feedback-as-generated-page | The feedback page is a generated markdown page (docs/feedback.md), not a custom | accepted | usm/vitepress-home-feedback-schema |
| agent-feedback-via-existing-mcp | The agent feedback path reuses the existing usm_report_feedback MCP tool (from u | accepted | usm/vitepress-home-feedback-schema |
| cross-links-in-generator | Cross-links and next-steps sections are added in the markdown generator, not han | accepted | usm/vitepress-home-feedback-schema |
| schema-as-single-source | The schema reference is generated entirely from schema/v1.json; terse field desc | accepted | usm/vitepress-schema-polish |
| homepage-from-system-usm | Homepage hero, tagline, principle cards, and CTAs are derived from system.usm (i | accepted | usm/vitepress-schema-polish |
| mermaid-dark-mode-aware | Inject a small theme-bridge script so Mermaid follows VitePress isDark instead o | accepted | usm/vitepress-schema-polish |
| declarative-sidebar-groups | Sidebar group order/names are driven by a declarative group-to-paths mapping whi | accepted | usm/vitepress-schema-polish |
| native-vitepress-containers | Use VitePress native containers and Mermaid code fences for visuals — no custom | accepted | usm/vitepress-schema-polish |
| priority-ordering | Deliver schema-reference and homepage/getting-started first; visuals/polish last | accepted | usm/vitepress-schema-polish |
| content-block-system | Define a content-block schema (heading, paragraph, code, mermaid, tabs, callout, | accepted | usm/gen-content-blocks |
| reference-pages-on-system | system.usm gains reference_pages[] for product-level reference pages (language s | accepted | usm/gen-content-blocks |
| reference-blocks-on-features | Feature specs gain an optional reference[] field for user-facing reference conte | accepted | usm/gen-content-blocks |
| block-level-audience-filter | The help-doc filter operates at content-block granularity (keep audience: public | accepted | usm/gen-content-blocks |
| preserve-schema-reading-generators | generateConfigReference and generateSchemaReference are preserved — they read JS | accepted | usm/gen-content-blocks |
| delete-after-migration | Hardcoded functions are deleted only after their content is migrated to specs an | accepted | usm/gen-content-blocks |
| emit-only-when-populated | Emit a templated page only when its source section is populated; never write a p | — | usm/docs-experience |
| togaf-as-architecture-section | Surface togaf output as the Architecture section of the docs site, not a separat | — | usm/docs-experience |
| css-not-config-for-width | Widen via generated theme CSS custom properties, not VitePress config knobs | — | usm/docs-experience |
| feature-cards-as-nav | Use the VitePress features grid as homepage navigation rather than forcing a sid | — | usm/docs-experience |
| voice-is-render-mode | Audience is a render mode (voice), not just a filter | — | usm/docs-experience |
| post-process-filtering | Generate full docs first, then filter for help audience | accepted | usm/gen-docs-split |
| visibility-field-optional | Add optional visibility field (public/internal) to features and services | accepted | usm/gen-docs-split |
| help-docs-simplified-features | Help docs show summary + intent + flows only, not contracts/tests/implementation | accepted | usm/gen-docs-split |
| review-mode-separate-from-reference | Add a review-oriented template alongside the existing overview template | accepted | usm/gen-feature-review |
| flows-as-numbered-steps | Render flows as numbered human-readable steps, not tables | accepted | usm/gen-feature-review |
| contracts-as-checklist | Render contracts as a markdown checklist the human can mentally tick | accepted | usm/gen-feature-review |
| tests-as-given-when-then | Render tests in given/when/then format | accepted | usm/gen-feature-review |
| default-upstream-hardcoded | Default upstream tracker is the canonical USM repo, overridable via feedback.ups | — | usm/feedback-upstream-routing |
| classification-instructions-not-detection | Teach scope classification via instructions rather than automatic detection in t | — | usm/feedback-upstream-routing |
| usage-in-feature-spec | Add usage/options/prerequisites to FeatureUsm schema (optional fields) | accepted | usm/gen-help-reference |
| config-reference-from-schema | Generate usmconfig reference from usmconfig-v1.json schema descriptions | accepted | usm/gen-help-reference |
| schema-reference-from-v1-json | Generate schema reference from v1.json schema descriptions | accepted | usm/gen-help-reference |
| logo-carousel | Use a clickable logo carousel, not tabs | accepted | usm/mkt-language-tabs |
| simple-icons | Use Simple Icons (simpleicons.org) for language and framework logos | accepted | usm/mkt-language-tabs |
| full-grid-in-docs | Full language/framework reference grid goes in help docs, not marketing site | accepted | usm/mkt-language-tabs |
| reuse-real-doc-structure | Model browser mock content on real generated feature docs | accepted | usm/mkt-mock-interfaces-v2 |
| file-explorer-sync | IDE file explorer reveals .usm files in sync with agent file-write actions | accepted | usm/mkt-mock-interfaces-v2 |
| reuse-cli-animation-pattern | Reuse the line-by-line reveal pattern from CliAnimation for both mocks | accepted | usm/mkt-mock-interfaces |
| two-command-cycle | Cycle two command/spec pairs: draft_feature then generate | accepted | usm/mkt-mock-interfaces |
| responsive-stack | Side-by-side on md+ screens, stacked on mobile | accepted | usm/mkt-mock-interfaces |
| instructions-plus-skill-not-plugin | Use opencode instructions array + skill, not a plugin with experimental.chat.sys | — | usm/opencode-integration |
| short-dedicated-file-not-agents-md | Generate a dedicated short instructions file rather than reusing AGENTS.md | — | usm/opencode-integration |
| skill-file-usm-owned | The skill and instructions files are fully USM-owned (wholesale regeneration); o | — | usm/opencode-integration |
| roadmap-links-to-features | Roadmap items can optionally reference a feature $id via a feature field | accepted | usm/gen-roadmap |
| shipped-in-optional | Add optional shipped_in field to roadmap items for version tracking | accepted | usm/gen-roadmap |
| sidebar-checks-file-existence | Sidebar generation should only include links to files that exist | accepted | usm/gen-roadmap |
| mermaid-via-vitepress-plugin | Use VitePress mermaid plugin instead of relying on native mermaid rendering | accepted | usm/gen-roadmap |
| one-generator-multiple-outputs | Single generator produces all tool-specific files in one pass | accepted | usm/gen-rules-files |
| workflow-instructions-not-just-context | Rules files contain behavioural instructions, not just system description | accepted | usm/gen-rules-files |
| smart-merge-for-rules-files | Reuse the smart-merge strategy from AGENTS.md generator | accepted | usm/gen-rules-files |
| cursor-uses-mdc-format | Generate .cursor/rules/usm.mdc in Cursor's rule format | accepted | usm/gen-rules-files |
| source-mapping-name | Name the feature source mapping rather than code navigator or file tree, because | accepted | usm/gen-source-mapping |
| reference-pages-sources | Source mapping views are reference_pages sources on system.usm, rendered through | accepted | usm/gen-source-mapping |
| no-new-schema-fields | Use existing spec fields only — service modules[] and feature implementation — n | accepted | usm/gen-source-mapping |
| filesystem-walk-for-completeness | The generator walks the filesystem within service paths[] to enumerate actual fi | accepted | usm/gen-source-mapping |
| json-import-first | Import the Structurizr workspace JSON format, not the DSL grammar | — | usm/structurizr-bridge |
| features-as-components | Export features as components inside their service container | — | usm/structurizr-bridge |
| generator-not-author | The technical design document is a generator (structured renderer), not an autho | — | usm/gen-technical-design |
| design-pages-parallel-to-reference-pages | system.usm gains a design_pages[] field parallel to reference_pages[]. Each entr | — | usm/gen-technical-design |
| suppress-empty-sections | Sections with no data are suppressed entirely — no empty stub pages, no sidebar | — | usm/gen-technical-design |
| five-group-sidebar | The sidebar is restructured into five groups: Getting Started, Design, Project M | — | usm/gen-technical-design |
| nav-template-definition | The nav template structure is the standard for all generated technical docs. It | — | usm/gen-technical-design |
| decision-register-consolidated | A Decision Register page consolidates all decisions from features, services, and | — | usm/gen-technical-design |
| features-as-project-management | Features are grouped under Project Management, not Design. Features with flows/c | — | usm/gen-technical-design |
| default-human-gate | human-gate is the default policy | — | usm/agent-feedback |
| feedback-as-first-class-usm-type | Feedback entries are $type: feedback .usm files in .usm/feedback, not a free-for | — | usm/agent-feedback |
| one-shared-protocol-block | A single Feedback Protocol block is rendered into all four rules files from one | — | usm/agent-feedback |
| setup-asks-two-questions | usm init asks exactly two questions: gh auth presence and policy choice | — | usm/agent-feedback |
| mcp-tool-respects-policy | usm_report_feedback consults system.feedback.policy before writing | — | usm/agent-feedback |
| write-tools-as-mcp-not-cli | Implement authoring as MCP tools rather than CLI commands only | accepted | usm/mcp-write |
| draft-returns-preview | draft_feature returns both YAML and generated markdown | accepted | usm/mcp-write |
| validate-before-write | All write operations validate against the v1 schema before persisting | accepted | usm/mcp-write |
| json-over-yaml | Use JSON for usmconfig (not YAML) because it is machine-generated and machine-re | — | usm/usm-config |
| structured-source-of-truth | Every system artifact is captured in YAML validated by a JSON Schema — no scatte | accepted | system.principles |
| agent-first | USM files are designed for AI agent consumption via MCP tools before human reada | accepted | system.principles |
| idempotent-generation | Scan and generate are safe to run repeatedly; smart-merge preserves human edits. | accepted | system.principles |
| one-source-many-outputs | A single .usm/ directory generates markdown, Mermaid, OpenAPI, ArchiMate, TOGAF, | accepted | system.principles |
Details
Feature Decisions
use-deps-not-inline [accepted]
Source: usm/cli-color-output
Decision: Use battle-tested CLI libraries, not hand-rolled inline helpers
Rationale: Libraries like picocolors, ora, cli-progress, and update-notifier are tiny, battle-tested by millions of downloads, and handle edge cases (Windows terminals, truecolor detection, spinner cleanup) that inline code would miss. Less code to maintain, better UX, and they auto-install via npm with no user action needed.
Alternatives:
- Strictly zero new deps (all inline) — rejected: More code to maintain, misses edge cases, reinvents wheels
Consequences: Adds ~5 small runtime dependencies to package.json, all pinned to CJS-compatible versions (ora@5, cli-progress@3, update-notifier@5 — newer majors are ESM-only and incompatible with the CJS package).
respect-no-color [accepted]
Source: usm/cli-color-output
Decision: Honor NO_COLOR env var and non-TTY stdout/stderr by emitting plain text
Rationale: Standard CLI convention (https://no-color.org) and CI hygiene. Piped/redirected output must stay plain so logs and grep work; colored escape codes in CI logs are noise. picocolors respects NO_COLOR natively; ora disables spinner in non-TTY.
Consequences: Color helpers short-circuit when process.stdout.isTTY is false or NO_COLOR is set. Spinner/progress bars suppressed in non-TTY.
palette [accepted]
Source: usm/cli-color-output
Decision: green=✓, red=✗, yellow=⚠, cyan=→/info, dim=secondary values
Rationale: Conventional semantic mapping that reads correctly in both light and dark terminals. Dim for file paths and counts keeps the primary message in foreground.
Consequences: Single palette in src/cli/colors.ts applied consistently
cjs-pin-versions [accepted]
Source: usm/cli-color-output
Decision: Pin dependency versions to CJS-compatible majors
Rationale: The package is CommonJS (no type field = module). Newer majors of ora (v6+) and update-notifier (v7+) are ESM-only and would break the CJS build. Pin to the last CJS-compatible major.
Consequences: package.json dependencies list exact major versions: picocolors (^1), ora (^5), cli-progress (^3), treeify (^0.1), update-notifier (^5).
outputs-from-config [accepted]
Source: usm/cli-config-outputs
Decision: All generators read output paths from usmconfig.json outputs section
Rationale: Users may want outputs in different locations (e.g. docs/ instead of .usm-workspace/docs/, or a custom build directory). Reading from config with sensible defaults means it works out of the box but is overridable.
Consequences: All generators need to call a shared getOutputPath() utility instead of hardcoding paths
generate-only-flag [accepted]
Source: usm/cli-config-outputs
Decision: Replace generate:xxx commands with generate --only <target> flag
Rationale: generate:help-docs, generate:togaf, generate:archimate use colon syntax which is inconsistent with docs serve, mcp serve (space syntax). Using --only flag keeps generate as a single command with a filter, which is simpler and more consistent.
Alternatives:
- Keep colon commands (generate:togaf, generate:archimate) — rejected: Inconsistent with space-syntax subcommands, clutters --help output
- Subcommands (generate togaf, generate archimate) — rejected: Makes generate a parent command, changes default behaviour, more complex Commander setup
Consequences: Breaking change — generate:xxx commands removed. Pre-public-release so acceptable.
scaffold-project-to-subcommand [accepted]
Source: usm/cli-config-outputs
Decision: Rename scaffold-project to 'scaffold project' (subcommand)
Rationale: Consistent with 'docs serve', 'mcp serve', 'scan infrastructure' — all use space syntax for subcommands.
Consequences: Breaking change — scaffold-project becomes 'scaffold project'
no-dependency [accepted]
Source: usm/docs-serve-port-check
Decision: Implement port probing with Node.js built-in net module — no third-party dependency like detect-port or chokidar.
Rationale: Keeps the dependency footprint zero. net.createServer().listen() for port probing and fs.watch for file watching are both built-in and sufficient.
auto-port-opt-in [accepted]
Source: usm/docs-serve-port-check
Decision: Auto-port selection is opt-in via --auto-port flag, not the default.
Rationale: Users expect --port 5173 to mean port 5173. Silently switching ports would break bookmarks, CORS configs, and automation scripts.
lsof-best-effort [accepted]
Source: usm/docs-serve-port-check
Decision: Process detection via lsof is best-effort only — graceful degradation if lsof is unavailable.
Rationale: lsof may not be installed in minimal Docker images or on Windows. The error message should still be clear without it, just omitting the process name.
pid-file-approach [accepted]
Source: usm/docs-serve-port-check
Decision: Use a PID file (.usm-workspace/.vitepress.pid) for already-serving detection, not port-sniffing alone.
Rationale: Port-sniffing can't distinguish between a VitePress server and another process on the same port. A PID file gives us certainty and enables usm docs stop.
watch-in-process [accepted]
Source: usm/docs-serve-port-check
Decision: Watch-mode regeneration runs usm generate --only docs in-process (calling the generator functions directly), not as a subprocess.
Rationale: Avoids the overhead and complexity of spawning a child process. The generator functions are already imported and callable.
debounce-500ms [accepted]
Source: usm/docs-serve-port-check
Decision: Watch-mode debounce is 500ms — a pragmatic balance between responsiveness and avoiding thrash on bulk writes.
Rationale: git checkout, usm scan, and editor auto-save can touch many files in rapid succession. 500ms is fast enough to feel instant but long enough to batch.
vitepress-over-custom [accepted]
Source: usm/cli-docs
Decision: Use VitePress as the rendering layer instead of building a custom server
Rationale: Building a custom markdown server with navigation, search, themes, and live reload is a whole separate product. VitePress is purpose-built for docs: markdown-native, Vite-powered HMR, built-in sidebar/search/dark mode, static build output. USM owns the content (generating markdown from .usm), VitePress owns the experience (rendering, nav, search). Clean separation of concerns. Used by Vue, Vitest, Pinia — battle-tested. Alternatives considered: custom Express+marked.js (rejected — reinventing the wheel, permanent maintenance burden), Docsify (rejected — client-side rendering, poor SEO), Nextra (rejected — heavyweight, pulls in Next.js).
unified-docs-directory [accepted]
Source: usm/cli-docs
Decision: All generated docs write to a single docs/ directory instead of scattered .agents-workspace/ paths
Rationale: Currently feature docs land in apps/<service>/.agents-workspace/docs/ and service docs in .agents-workspace/docs/shared-services/. This scattering makes navigation impossible and paths unpredictable. A unified docs/ directory with services/, features/, architecture/ subdirectories creates a clean hierarchy that maps 1:1 to the .usm file structure and works as VitePress input.
sidebar-from-system-index [accepted]
Source: usm/cli-docs
Decision: Auto-generate VitePress sidebar config from system.usm index + feature directory structure
Rationale: system.usm already has an index[] with feature id, name, ref, status, and tags. This is the authoritative source of what features exist and how they're grouped. Generating the sidebar from this index means the navigation is always in sync with the spec — no manual sidebar maintenance. Feature grouping (CLI, generators, mcp) comes from the directory structure of .usm/features/.
vitepress-optional-dependency [accepted]
Source: usm/cli-docs
Decision: VitePress is an optional peer dependency, not bundled with USM
Rationale: Not every USM user needs the docs server — some just want the CLI and MCP tools. Making VitePress optional keeps the core install lightweight. usm docs serve checks for VitePress and prints install instructions if missing, rather than failing at install time.
dont-commit-generated-docs [accepted]
Source: usm/cli-docs
Decision: Generated docs are not committed to the repo — served locally and deployed via CI
Rationale: Committing generated files creates diff noise and merge conflicts. The docs/ directory is gitignored. usm docs serve reads from the local generated output. CI runs usm generate && usm docs build for deployment. GitHub browsing links to the deployed site. This matches the current .gitignore strategy for .agents-workspace/.
internal-over-external [—]
Source: usm/internal-dsl-builder
Decision: Internal (host-language) DSL, not a custom grammar
Rationale: Fowler's cost test: inherit TS tooling and LLM fluency, skip parser maintenance forever. The semantic model (.usm) remains the asset.
runtime-schema-validation [—]
Source: usm/internal-dsl-builder
Decision: Enforce constraints by validating at build() rather than type-level branding
Rationale: Keeps the fluent API simple and the JSON Schema the single source of truth; builders cannot silently bypass the same validation MCP tools enforce.
all-35-in-docs [accepted]
Source: usm/mcp-setup-guides
Decision: Generate per-editor setup pages for all 35 editors
Rationale: Maximizes compatibility coverage. Any USM user using any MCP-ready editor can find their setup. Matches shadcn's coverage bar.
Consequences: 35 markdown files under .usm-workspace/docs/mcp-setup/ plus index.md
top-10-logos [accepted]
Source: usm/mcp-setup-guides
Decision: Marketing site ToolLogos shows top 10 editors only
Rationale: 35 logos would overwhelm the marketing hero area. Top 10 covers the most popular. Full 35 coverage lives in the docs.
Consequences: tool-logos.tsx updated with top 10, sorted by popularity
index-plus-per-editor [accepted]
Source: usm/mcp-setup-guides
Decision: Index page plus per-editor pages (shadcn pattern)
Rationale: Best UX. Users land on a grid, click their editor, get exact config. Matches the shadcn setup pattern users are familiar with.
Consequences: 1 index page + 35 editor pages = 36 markdown files
rules-files-per-editor [accepted]
Source: usm/mcp-setup-guides
Decision: Document rules/skills file installation on each editor page where supported
Rationale: The always-on rules file is a key USM differentiator. Editors that support always-on hooks (opencode, Claude Code, Cursor, Copilot, Codex) should document both the MCP config AND the rules file install.
Consequences: Per-editor pages include a Rules File section when the editor supports always-on hooks; pages for editors without hook support note this.
stdio-config-pattern [accepted]
Source: usm/mcp-setup-guides
Decision: Use the standard USM stdio pattern (usm mcp serve) for all editors
Rationale: USM's MCP server is stdio-based. Most editors accept the command/args JSON pattern. HTTP-only clients use mcp-remote as a bridge.
Consequences: Configs use command usm args mcp serve. HTTP-only editors get a mcp-remote bridge note.
manifest-based-detection [accepted]
Source: usm/cli-multi-lang-scan
Decision: Detect services by language manifest files
Rationale: Every language ecosystem has a standard manifest file. Detecting these files is reliable, language-specific, and doesn't require parsing source code. The manifest also tells us dependencies (framework detection).
Consequences: Scanner needs a manifest-to-language map. New languages added by adding a manifest entry.
framework-specific-route-detection [accepted]
Source: usm/cli-multi-lang-scan
Decision: Detect routes per-framework, not per-language
Rationale: Route patterns differ by framework, not language. Next.js uses app/page.tsx, FastAPI uses @app.get decorators, Spring uses @GetMapping annotations, Rails uses config/routes.rb, ASP.NET uses [HttpGet] attributes. Each framework needs its own route extractor.
Alternatives:
- Generic AST parsing per language — rejected: Too complex, requires language-specific parsers, fragile
- File-pattern matching only (no framework awareness) — rejected: Misses decorator/annotation-based routes (FastAPI, Spring, ASP.NET)
Consequences: Route detection is framework-by-framework. New frameworks need a route extractor.
configurable-in-usmconfig [accepted]
Source: usm/cli-multi-lang-scan
Decision: Language/framework detection rules are configurable in usmconfig.json
Rationale: Users can add custom manifest patterns, route patterns, and data model patterns for frameworks we don't support out of the box. Defaults cover common frameworks; advanced users can extend.
Consequences: usmconfig.json gains a 'detection' section with language/framework rules
all-languages-from-start [accepted]
Source: usm/cli-multi-lang-scan
Decision: Support all major languages from the initial implementation
Rationale: Rather than phasing, include all major languages (Python, Go, Rust, Java, Kotlin, C#, Ruby, PHP, Elixir, Swift, Scala, C/C++) from the start. The manifest detection is simple (file pattern matching) and route detection is regex-based per framework. The complexity is manageable.
Consequences: Larger initial implementation but no phased rollout complexity
detectors-directory [accepted]
Source: usm/cli-multi-lang-scan
Decision: Add .usm/detectors/*.yaml as a second auto-discovered extension surface alongside usmconfig.json detection
Rationale: usmconfig.json describes a single repo's shape and is per-project. Detector files are shareable across repos, versioned with the .usm source of truth, validatable like other USM artifacts, and agent-writable via MCP tools. Two surfaces with the same field shapes give users the cheap path (drop a file) and the config path (inline rules) without forcing one or the other.
Alternatives:
- usmconfig.json detection only (original accepted decision) — rejected: Config is per-project and not shareable; cannot express convention-based frameworks that need code
- .usm/detectors/ only, drop the config section — rejected: Reverses an accepted decision and removes the inline config ergonomics for small overrides
Consequences: Two surfaces to keep in sync; precedence rules must be deterministic. Built-in detectors migrate to the same shape as user detectors.
script-escape-hatch [accepted]
Source: usm/cli-multi-lang-scan
Decision: Allow routes.script in a detector to point at a .ts/.js file exporting extractRoutes(sourceDir, framework) for convention-based frameworks
Rationale: Regex cannot capture Next.js app/page.tsx convention routing, Remix, or SvelteKit file-based routes. These need real logic. A script field keeps the declarative detector file as the entry point but delegates extraction to code when needed. The script lives in the user's repo (not auto-loaded from third parties), bounding the trust surface.
Consequences: Detector files can reference local code; USM dynamically imports it. Only opt-in per detector; declarative regex remains the default.
generalized-orchestrator [accepted]
Source: usm/cli-multi-lang-scan
Decision: Generalize structural.ts service detection so any detector manifest drives it, removing the package.json hardcode
Rationale: Today a service directory without package.json is warned and skipped, making non-JS/TS stacks second-class. The whole point of multi-language scan is that a Go app (go.mod) or Zig app (build.zig.zon) is detected as a service without package.json. The orchestrator must ask detectors 'does your manifest match this directory' instead of assuming package.json.
Consequences: The Python pyproject.toml and Docker docker-compose special-case passes become built-in detectors. structural.ts shrinks to an orchestrator that iterates detectors.
infrastructure-as-detector [accepted]
Source: usm/cli-multi-lang-scan
Decision: Treat infrastructure (Terraform today) as a detector kind rather than a hardcoded separate subcommand
Rationale: infrastructure.ts only parses Terraform. Users with CloudFormation, Pulumi, or CDK get nothing. An infrastructure detector kind with the same manifest+pattern shape as other detectors makes IaC extensible without code, consistent with the rest of the plugin system.
Consequences: usm scan infrastructure subcommand continues to work (backed by the built-in Terraform detector); new formats add via detector files or detection.infrastructure in config.
precedence-order [accepted]
Source: usm/cli-multi-lang-scan
Decision: Detector precedence is built-in defaults < .usm/detectors/ files < usmconfig.json detection (last wins)
Rationale: Built-ins provide sane defaults out of the box. Detector files are project-level customizations shared across the team. usmconfig.json is the highest precedence so a user can override a detector file from config without editing the file (useful for one-off overrides). Deterministic order prevents merge ambiguity.
Consequences: Documented precedence; overrides by $id for detectors and by manifest pattern for config arrays.
tiny-grammar-not-sql [—]
Source: usm/query-layer
Decision: A ~200-line recursive-descent grammar, not SQL/jq subset
Rationale: Covers selector+predicate use cases agents actually have; keeps error messages precise and the surface teachable in one rules-file line.
missing-field-is-false [—]
Source: usm/query-layer
Decision: Unknown/absent fields make predicates false instead of erroring
Rationale: Queries like 'feedback where severity = high' must not explode on feature files that lack severity; absence is simply not a match.
capability-registry-pattern [accepted]
Source: usm/upgrade
Decision: Capabilities self-describe (detect + setup + introducedIn); upgrade orchestrates without hardcoding.
Rationale: Adding a future capability means one registry entry, zero changes to upgrade. Same extensibility principle as the generators target list.
usm-version-field-for-alignment [accepted]
Source: usm/upgrade
Decision: Use system.usm.usm_version for USM-tool alignment, NOT the project's own version field.
Rationale: The version field tracks the consuming project's own release (e.g. 5.2.0). Repurposing it would miscompare against the USM tool version. A dedicated usm_version field keeps project version and tool alignment separate and unambiguous.
Alternatives:
- Reuse the existing version field for alignment — rejected: Overwrites the consuming project's own release version; a project at 5.2.0 would be misread as 'ahead of' USM 0.1.0 and never offered upgrades.
- Use $version (schema format) for alignment — rejected: Conflates schema-format changes with feature additions; additive schema changes (like feedback) intentionally do not bump $version.
schema-version-independence [accepted]
Source: usm/upgrade
Decision: Schema $version moves independently of the package version: additive schema changes do NOT bump $version (still v1); breaking changes bump $version + CURRENT_SCHEMA_VERSION together and ship a migration in usm upgrade.
Rationale: Decouples the file format from the tool release cadence. A 0.2.0 release may still be schema v1. Additive changes (new optional fields) are backward compatible and must not force every consumer to migrate.
setup-owned-by-capability [accepted]
Source: usm/upgrade
Decision: Each registry entry owns its own setup function (interactive + default); upgrade just calls it.
Rationale: Avoids subprocess fragility (no need for the binary on PATH) and keeps each capability's setup logic co-located with its detection.
interactive-with-flag-fallback [accepted]
Source: usm/upgrade
Decision: TTY prompts per capability; --apply uses defaults for CI/scripts; --check is report-only.
Rationale: Composes with existing per-feature setup commands (e.g. usm feedback) while supporting non-interactive and CI use cases.
non-destructive [accepted]
Source: usm/upgrade
Decision: Upgrade only adds missing blocks and bumps usm_version; existing config is never overwritten.
Rationale: detect() returns true for configured capabilities → they are skipped. Safe to re-run idempotently.
homepage-simplify-not-remove [accepted]
Source: usm/vitepress-home-feedback-schema
Decision: Simplify the homepage by removing marketing content, not by removing the homepage entirely. Keep the spec-first diagram, quick stats, and quick start as the core reference content.
Rationale: The existing vitepress-schema-polish feature built a rich homepage. This feature refines it — removing the marketing duplication while keeping the technical reference value. The marketing content belongs on usm.dev (Next.js + shadcn), not docs.usm.dev (VitePress).
feedback-as-generated-page [accepted]
Source: usm/vitepress-home-feedback-schema
Decision: The feedback page is a generated markdown page (docs/feedback.md), not a custom Vue component. The nav bar link is added via VitePress themeConfig.nav.
Rationale: Keeps the build lightweight (no custom Vue components). The feedback page content is generated from system.usm (identity.repository for the issue tracker URL) and the USM version. The nav link is injected into the VitePress config during docs serve/build.
agent-feedback-via-existing-mcp [accepted]
Source: usm/vitepress-home-feedback-schema
Decision: The agent feedback path reuses the existing usm_report_feedback MCP tool (from usm/agent-feedback feature). The feedback page documents how agents should use it with page context.
Rationale: No new MCP tool needed. The existing agent-feedback protocol already handles structured feedback entries. The docs page teaches agents to include current page URL and .usm map context.
cross-links-in-generator [accepted]
Source: usm/vitepress-home-feedback-schema
Decision: Cross-links and next-steps sections are added in the markdown generator, not hand-edited into output.
Rationale: Dogfooding: all content must be generated from .usm. The generator already has access to system.usm index for building link maps.
schema-as-single-source [accepted]
Source: usm/vitepress-schema-polish
Decision: The schema reference is generated entirely from schema/v1.json; terse field descriptions are enriched in-place in the schema so the reference is self-generating and never drifts.
Rationale: schema/v1.json is already the authoritative source for type/required/constraints. Co-locating rich descriptions avoids a second hand-maintained doc and honors 'generated from .usm/schema'.
Alternatives:
- A separate .usm annotation file describing each field — rejected: duplicates the schema and will drift from it
homepage-from-system-usm [accepted]
Source: usm/vitepress-schema-polish
Decision: Homepage hero, tagline, principle cards, and CTAs are derived from system.usm (identity, summary, principles, repository) so every USM project gets a reflective homepage.
Rationale: Dogfooding: the generator must work for any project, not just USM's own docs.
mermaid-dark-mode-aware [accepted]
Source: usm/vitepress-schema-polish
Decision: Inject a small theme-bridge script so Mermaid follows VitePress isDark instead of the hardcoded 'default' theme.
Rationale: Hardcoded 'default' makes diagrams unreadable in dark mode.
declarative-sidebar-groups [accepted]
Source: usm/vitepress-schema-polish
Decision: Sidebar group order/names are driven by a declarative group-to-paths mapping while still only emitting links to pages that exist.
Rationale: Makes the requested group structure explicit and easy to evolve without breaking existence-checking that prevents dead links.
native-vitepress-containers [accepted]
Source: usm/vitepress-schema-polish
Decision: Use VitePress native containers and Mermaid code fences for visuals — no custom Vue components or heavy deps.
Rationale: Keeps the build lightweight and avoids custom-component maintenance.
priority-ordering [accepted]
Source: usm/vitepress-schema-polish
Decision: Deliver schema-reference and homepage/getting-started first; visuals/polish last.
Rationale: Schema reference + onboarding are the highest-leverage surfaces; polish is additive.
content-block-system [accepted]
Source: usm/gen-content-blocks
Decision: Define a content-block schema (heading, paragraph, code, mermaid, tabs, callout, table, steps, cards, badge, divider) that any .usm spec can use to express VitePress-rich content declaratively.
Rationale: The schema currently has no fields for reference content, onboarding prose, code snippets, Mermaid-as-doc, tabs, or callouts. When someone needed these, they hand-wrote them in generator code (LANGUAGE_SUPPORT, generateAgentSetupGuide, generateGettingStartedDoc prose). A content-block schema gives specs a structured way to express any VitePress content, making the generator a pure renderer and eliminating drift. This is the first-principles fix: make the schema expressive enough that docs content lives in specs.
Alternatives:
- Keep bespoke generators but make them read from specs/registry — rejected: Still one function per content type; doesn't scale; every new page needs a new generator function.
- Markdown-in-YAML (raw markdown strings in spec fields) — rejected: Not structured, not agent-writable via MCP tools, no audience filtering, defeats the point of structured source of truth.
- A separate .md file per reference page committed alongside .usm — rejected: Not generated from source; duplicates the spec; will drift.
Consequences: Schema gains content-block types (a new $def in v1.json). Generators gain one renderContentBlocks function. Hardcoded functions deleted after migration.
reference-pages-on-system [accepted]
Source: usm/gen-content-blocks
Decision: system.usm gains reference_pages[] for product-level reference pages (language support, getting started, agent setup) with inline content or runtime sources (detectors, schema, config).
Rationale: Some reference pages document the product, not a single feature. system.usm is the right home. source: detectors lets the language-support page render from the detector registry at generation time — always in sync, no constant. Inline content lets getting-started/agent-setup pages carry their prose as structured content blocks. This replaces the hardcoded functions that currently own these pages.
Consequences: system.usm schema gains an optional reference_pages field. The generator iterates reference_pages and renders each.
reference-blocks-on-features [accepted]
Source: usm/gen-content-blocks
Decision: Feature specs gain an optional reference[] field for user-facing reference content that survives the help filter.
Rationale: Some feature docs need reference tables that are NOT acceptance criteria (e.g. the multi-lang-scan spec's supported-languages table is user reference, not a developer contract). Today these live in contracts[] which the help filter strips. A reference[] field with audience: public gives feature specs a place for user-facing content that survives into help docs.
Consequences: Feature schema gains an optional reference field. The help filter is updated to keep public reference blocks. generateFeatureMarkdown appends rendered reference blocks after standard sections.
block-level-audience-filter [accepted]
Source: usm/gen-content-blocks
Decision: The help-doc filter operates at content-block granularity (keep audience: public, drop audience: internal) instead of section-level granularity (strip ## Contracts by heading name).
Rationale: The current filter strips entire sections by heading name, which is coarse and breaks if headings change. Block-level audience filtering is precise — each block declares its audience and the filter keeps or drops it. This also lets a single page mix public and internal content.
Consequences: simplifyFeatureDoc in docs.ts is rewritten to filter content blocks by audience. Contracts/tests/implementation/decisions continue to be stripped (they are developer-only by definition).
preserve-schema-reading-generators [accepted]
Source: usm/gen-content-blocks
Decision: generateConfigReference and generateSchemaReference are preserved — they read JSON schema files which ARE the source of truth for config/schema fields.
Rationale: These two functions read usmconfig-v1.json and v1.json respectively. The JSON schemas are the structured source of truth for those fields — reading them at runtime is spec-driven in spirit. Converting them to content blocks would mean duplicating the schema's field descriptions into a spec, which would drift. They stay as-is but can be invoked via reference_pages[source: config|schema].
Consequences: These two functions are wrapped as source renderers callable from reference_pages, not deleted. Their internal logic is unchanged.
delete-after-migration [accepted]
Source: usm/gen-content-blocks
Decision: Hardcoded functions are deleted only after their content is migrated to specs and the replacement is proven by tests.
Rationale: Deleting first risks breaking docs with no fallback. Migrate content to reference_pages/reference blocks, prove the generated output matches (or corrects) the old output, then delete. This is the cleanup pass, not the first step.
Consequences: The delete-hardcoded-generators flow runs last. LANGUAGE_SUPPORT, generateLanguageSupportDoc, generateAgentSetupGuide, and hardcoded prose in generateGettingStartedDoc are removed only after tests confirm the replacement works.
emit-only-when-populated [—]
Source: usm/docs-experience
Decision: Emit a templated page only when its source section is populated; never write a placeholder
Rationale: A placeholder promises depth and delivers nothing — worse than the page not existing. Omission is honest.
togaf-as-architecture-section [—]
Source: usm/docs-experience
Decision: Surface togaf output as the Architecture section of the docs site, not a separate target
Rationale: The detailed design already exists; the failure was discoverability. Wiring it into the nav fixes both the empty stubs and the orphaned output in one move.
css-not-config-for-width [—]
Source: usm/docs-experience
Decision: Widen via generated theme CSS custom properties, not VitePress config knobs
Rationale: CSS custom properties are the documented override path and survive VitePress minor bumps; config knobs for layout do not exist.
feature-cards-as-nav [—]
Source: usm/docs-experience
Decision: Use the VitePress features grid as homepage navigation rather than forcing a sidebar onto layout home
Rationale: Cards are the canonical landing-page nav pattern and keep the hero; forcing a sidebar means abandoning the home layout entirely.
voice-is-render-mode [—]
Source: usm/docs-experience
Decision: Audience is a render mode (voice), not just a filter
Rationale: Filtering alone produced two identical sites; the brief needs two different documents from one source.
post-process-filtering [accepted]
Source: usm/gen-docs-split
Decision: Generate full docs first, then filter for help audience
Rationale: Rather than modifying the core markdown generator with audience-aware logic, generate the full docs as usual then post-process for the help audience. This keeps the generator simple and puts audience filtering in the VitePress integration layer (docs.ts) where it belongs.
Alternatives:
- Audience-aware generator (pass audience through to all render functions) — rejected: Touches every render function, complex, hard to maintain
- Separate generator functions for help vs developer — rejected: Duplicates rendering logic, drifts over time
Consequences: Full docs generated first (slight overhead), then filtered — but filtering is fast and the full docs are useful anyway
visibility-field-optional [accepted]
Source: usm/gen-docs-split
Decision: Add optional visibility field (public/internal) to features and services
Rationale: Default visibility is internal (safe — nothing leaks unless explicitly marked public). Features marked public appear in help docs. Features with no visibility field appear in help docs only if status is built.
Consequences: Authors must opt-in features to public docs by setting visibility: public
help-docs-simplified-features [accepted]
Source: usm/gen-docs-split
Decision: Help docs show summary + intent + flows only, not contracts/tests/implementation
Rationale: Visitors don't need acceptance criteria checklists or Given/When/Then test cases. They need to understand what the feature does (summary), why it exists (intent), and how it works (flows as steps). Contracts and tests are developer concerns.
Consequences: Help docs are shorter and more readable for non-developers
review-mode-separate-from-reference [accepted]
Source: usm/gen-feature-review
Decision: Add a review-oriented template alongside the existing overview template
Rationale: The existing overview.md is useful as a structural reference (what fields exist, where files are). The review template serves a different purpose: human approval before implementation. Keeping both lets the overview remain a reference while the review doc is the approval artifact.
flows-as-numbered-steps [accepted]
Source: usm/gen-feature-review
Decision: Render flows as numbered human-readable steps, not tables
Rationale: A table of {id, action, target} is hard to read as a narrative. Numbered steps like "1. Receive structured feature fields → 2. Validate against schema → 3. Generate YAML + markdown" read like a procedure a human can follow and approve.
contracts-as-checklist [accepted]
Source: usm/gen-feature-review
Decision: Render contracts as a markdown checklist the human can mentally tick
Rationale: Contracts are guarantees the implementation must satisfy. A checklist (- [ ] ...) frames them as acceptance criteria, which is how a human naturally reviews a spec: "does this cover what I expect?"
tests-as-given-when-then [accepted]
Source: usm/gen-feature-review
Decision: Render tests in given/when/then format
Rationale: The .usm test schema already has setup (given), implied action (when), and expect (then). Making this explicit in the markdown helps the human understand what test cases will verify the feature.
default-upstream-hardcoded [—]
Source: usm/feedback-upstream-routing
Decision: Default upstream tracker is the canonical USM repo, overridable via feedback.upstream_tracker
Rationale: Consumers should not need configuration to get correct routing; forks/rebrands can override. Optional schema field only — no breaking change.
classification-instructions-not-detection [—]
Source: usm/feedback-upstream-routing
Decision: Teach scope classification via instructions rather than automatic detection in the MCP tool
Rationale: Classification requires judgment about blast radius; the agent (or human at the gate) is better placed than a heuristic on the summary string. The tool only nudges when a USM tool bug seems likely.
usage-in-feature-spec [accepted]
Source: usm/gen-help-reference
Decision: Add usage/options/prerequisites to FeatureUsm schema (optional fields)
Rationale: The .usm spec is the source of truth. If CLI usage examples and flag references live in the .usm feature specs, they're available to both the help doc generator and MCP tools (agents can query usage). The alternative — parsing --help output at generation time — is brittle and produces terse output.
Alternatives:
- Parse commander --help output at generation time — rejected: Terse output, brittle parsing, not available to MCP tools
- Hand-write reference pages in markdown — rejected: Not generated from source, will drift, not generic
Consequences: Feature specs for CLI commands need updating with usage/options fields — one-time effort
config-reference-from-schema [accepted]
Source: usm/gen-help-reference
Decision: Generate usmconfig reference from usmconfig-v1.json schema descriptions
Rationale: The JSON schema already has descriptions for every field. Generating a human-readable reference from the schema means it's always in sync. No need for a separate .usm spec for the config file.
Consequences: Config reference page is only as good as the schema descriptions — may need enriching
schema-reference-from-v1-json [accepted]
Source: usm/gen-help-reference
Decision: Generate schema reference from v1.json schema descriptions
Rationale: Same principle — the v1.json schema has descriptions for every field. Generate a human-readable reference showing required vs optional, types, and descriptions for each .usm file type.
Consequences: Schema reference is comprehensive but may be dense — could add examples later
logo-carousel [accepted]
Source: usm/mkt-language-tabs
Decision: Use a clickable logo carousel, not tabs
Rationale: Tabs hide breadth (only one visible at a time). A logo row shows all 12 languages instantly. Clicking reveals frameworks + code example for that language. Compact, interactive, visual.
Alternatives:
- Tabbed interface (one tab per language) — rejected: Hides breadth — visitor only sees one language at a time
- Full grid (all languages and frameworks visible) — rejected: Too much information for marketing — better in docs
Consequences: Need language logos (Simple Icons) and a carousel component
simple-icons [accepted]
Source: usm/mkt-language-tabs
Decision: Use Simple Icons (simpleicons.org) for language and framework logos
Rationale: Simple Icons has 3000+ monochrome SVG brand icons including all 12 languages and ~18 of the 30+ frameworks. Free, open source, SVG (crisp at all sizes). Monochrome by default — perfect for dark theme.
Consequences: Less popular frameworks (chi, gin, Axum, Crow, etc.) won't have logos — show as text chips
full-grid-in-docs [accepted]
Source: usm/mkt-language-tabs
Decision: Full language/framework reference grid goes in help docs, not marketing site
Rationale: Marketing site should be concise (carousel). Help docs should be comprehensive (full grid with all 12 languages and all 30+ frameworks). This matches the docs vs marketing split.
Consequences: New help docs page: 'Language Support' with full grid
reuse-real-doc-structure [accepted]
Source: usm/mkt-mock-interfaces-v2
Decision: Model browser mock content on real generated feature docs
Rationale: The actual VitePress docs render H1 + Usage + How it works + Guarantees. Matching this makes the mock instantly recognizable as the real docs site.
Consequences: Browser scenes use structured content blocks matching real doc layout
file-explorer-sync [accepted]
Source: usm/mkt-mock-interfaces-v2
Decision: IDE file explorer reveals .usm files in sync with agent file-write actions
Rationale: Shows the spec-first workflow visually — file appears in explorer as agent writes it
Consequences: File explorer state tied to chat animation phase
reuse-cli-animation-pattern [accepted]
Source: usm/mkt-mock-interfaces
Decision: Reuse the line-by-line reveal pattern from CliAnimation for both mocks
Rationale: CliAnimation already has a working scene/line/delay system with typewriter reveal. Reusing it keeps the two new mocks consistent and low-risk.
Consequences: A new ChatMock and BrowserMock component, each with their own scenes array
two-command-cycle [accepted]
Source: usm/mkt-mock-interfaces
Decision: Cycle two command/spec pairs: draft_feature then generate
Rationale: Shows the spec-first write flow (draft to spec appears in browser) and the docs flow (generate to docs page appears). Two scenes cover both halves of the USM value prop.
Consequences: Each mock has 2 scenes that loop
responsive-stack [accepted]
Source: usm/mkt-mock-interfaces
Decision: Side-by-side on md+ screens, stacked on mobile
Rationale: Standard responsive pattern for two-column comparisons. Both mocks should be fully visible side-by-side on desktop for the synced effect.
Consequences: grid grid-cols-1 md:grid-cols-2 gap-6 layout
instructions-plus-skill-not-plugin [—]
Source: usm/opencode-integration
Decision: Use opencode instructions array + skill, not a plugin with experimental.chat.system.transform
Rationale: Plugin system-transform hooks are experimental and require TypeScript runtime code in the consumer repo — fragile distribution. instructions injection is stable config, and the skill description is visible every message anyway. Together they cover the every-message requirement without shipping code.
short-dedicated-file-not-agents-md [—]
Source: usm/opencode-integration
Decision: Generate a dedicated short instructions file rather than reusing AGENTS.md
Rationale: opencode already injects AGENTS.md every message — the drift problem is dilution by length. A ≤30-line iron-rules file stays salient where the full AGENTS.md does not.
skill-file-usm-owned [—]
Source: usm/opencode-integration
Decision: The skill and instructions files are fully USM-owned (wholesale regeneration); opencode.json is merge-touched only in instructions
Rationale: Skills are single-purpose; unlike CLAUDE.md there is no human content to preserve inside them. opencode.json is user-authored config and must be treated as hand-written.
roadmap-links-to-features [accepted]
Source: usm/gen-roadmap
Decision: Roadmap items can optionally reference a feature $id via a feature field
Rationale: Not every roadmap item is a feature (some are refactors, infra, etc.), but when a roadmap item corresponds to a feature, linking them lets the generated roadmap page cross-link to the feature spec. The feature field is optional — roadmap items without a feature link still work.
shipped-in-optional [accepted]
Source: usm/gen-roadmap
Decision: Add optional shipped_in field to roadmap items for version tracking
Rationale: When a roadmap item ships, recording which package version it shipped in gives a release history without complex versioning machinery. The CHANGELOG already tracks release contents — shipped_in just annotates the roadmap item with the version number.
sidebar-checks-file-existence [accepted]
Source: usm/gen-roadmap
Decision: Sidebar generation should only include links to files that exist
Rationale: The sidebar currently includes links to /risks and /roadmap even when those pages aren't generated (empty content suppressed). The sidebar generator should check if the target file exists before adding the link. Same for feature links — only include features whose docs files exist.
mermaid-via-vitepress-plugin [accepted]
Source: usm/gen-roadmap
Decision: Use VitePress mermaid plugin instead of relying on native mermaid rendering
Rationale: VitePress doesn't render mermaid code blocks by default — they show as raw text. The vitepress-plugin-mermaid plugin (or MermaidMarkdown plugin) enables mermaid rendering. This is configured in the VitePress config.
one-generator-multiple-outputs [accepted]
Source: usm/gen-rules-files
Decision: Single generator produces all tool-specific files in one pass
Rationale: The workflow instructions are largely the same across tools; only the file path and format conventions differ. A single generator with per-tool templates avoids drift between instruction files.
workflow-instructions-not-just-context [accepted]
Source: usm/gen-rules-files
Decision: Rules files contain behavioural instructions, not just system description
Rationale: The current AGENTS.md generator outputs structural context (what apps exist, what packages exist). That's useful but passive. The rules files must actively instruct: "Before implementing a feature, draft a .usm spec and show the human the review markdown. After implementation, update the feature status." Behavioural instructions are what make USM a workflow, not just a reference.
smart-merge-for-rules-files [accepted]
Source: usm/gen-rules-files
Decision: Reuse the smart-merge strategy from AGENTS.md generator
Rationale: Teams may add tool-specific instructions (e.g. "use pnpm not npm") that must survive regeneration. The USM:START/USM:END marker strategy preserves human content outside the generated block.
cursor-uses-mdc-format [accepted]
Source: usm/gen-rules-files
Decision: Generate .cursor/rules/usm.mdc in Cursor's rule format
Rationale: Cursor rules (.mdc files) support frontmatter with globs and descriptions that control when the rule is injected. Generating in .mdc format means the rule auto-activates when agents work in .usm/ directories.
source-mapping-name [accepted]
Source: usm/gen-source-mapping
Decision: Name the feature source mapping rather than code navigator or file tree, because the capability is building a bidirectional source-to-spec mapping and rendering multiple views from it.
Rationale: Code navigator describes one view (the file tree). Source mapping describes the capability — the underlying file-to-feature-to-service relationship that powers file-tree, coverage-matrix, and orphan-report views. The name should reflect the general capability, not one output.
Consequences: The feature id is usm/gen-source-mapping. Reference page sources are file-tree, coverage-matrix, orphan-report.
reference-pages-sources [accepted]
Source: usm/gen-source-mapping
Decision: Source mapping views are reference_pages sources on system.usm, rendered through the generic content-block renderer.
Rationale: The content-block system already supports source-based reference pages (detectors, schema, config). Adding file-tree, coverage-matrix, and orphan-report as new sources keeps the architecture uniform — one generator, one renderer, multiple sources. No bespoke generator functions.
Consequences: system.usm declares which views to generate. The referencePages generator dispatches to source-specific builders.
no-new-schema-fields [accepted]
Source: usm/gen-source-mapping
Decision: Use existing spec fields only — service modules[] and feature implementation — no new schema fields.
Rationale: The data already exists. Adding schema fields would be unnecessary. The generator reads service.usm modules[].paths[] for directory grouping and feature.usm implementation.primary for file ownership. The filesystem walk fills the gap between specs and actual files.
Consequences: No v1.json changes. No migration needed. The generator is purely additive.
filesystem-walk-for-completeness [accepted]
Source: usm/gen-source-mapping
Decision: The generator walks the filesystem within service paths[] to enumerate actual files, not just the files mentioned in specs.
Rationale: Specs point at implementation files but don't list every file in a directory. To build a complete file tree and detect orphans, the generator must walk the filesystem. Files not mentioned in any spec are orphans — that's the coverage signal.
Consequences: The generator needs filesystem access at generation time. Exclude patterns (node_modules, dist, .git) are respected.
json-import-first [—]
Source: usm/structurizr-bridge
Decision: Import the Structurizr workspace JSON format, not the DSL grammar
Rationale: Structurizr serialises workspaces to JSON; parsing that is tractable, while the DSL grammar would need a real parser — deferred until demand is demonstrated (Fowler threshold).
features-as-components [—]
Source: usm/structurizr-bridge
Decision: Export features as components inside their service container
Rationale: Preserves the C4 hierarchy (system, container, component) and gives Structurizr users feature-level detail.
generator-not-author [—]
Source: usm/gen-technical-design
Decision: The technical design document is a generator (structured renderer), not an authored doc. All content comes from .usm specs, schema, or declared content blocks.
Rationale: Follows the first principle established by gen-content-blocks: generators are renderers, not authors. The mapping from USM data to the 13 sections is deterministic.
design-pages-parallel-to-reference-pages [—]
Source: usm/gen-technical-design
Decision: system.usm gains a design_pages[] field parallel to reference_pages[]. Each entry can declare inline content blocks for a section, enriching the structured data.
Rationale: Some sections need prose that doesn't fit structured fields (e.g. disaster recovery narrative, testing philosophy). Content blocks provide that escape hatch while keeping the generator as the primary renderer.
suppress-empty-sections [—]
Source: usm/gen-technical-design
Decision: Sections with no data are suppressed entirely — no empty stub pages, no sidebar links to pages that don't exist.
Rationale: Follows the docs-experience principle: a CLI tool shouldn't have a Database Design page. The template adapts to the project.
five-group-sidebar [—]
Source: usm/gen-technical-design
Decision: The sidebar is restructured into five groups: Getting Started, Design, Project Management, Developers, Exports. This replaces the current fragmented groups (Core Concepts, Workflows, Architecture, Deployment, Contributing).
Rationale: The current sidebar mixes concerns — architecture phases next to reference pages next to feature groups. Five clean groups by audience and purpose: onboarding, holistic design, project governance, developer reference, alternative framework exports.
nav-template-definition [—]
Source: usm/gen-technical-design
Decision: The nav template structure is the standard for all generated technical docs. It defines five top-level groups and the pages within each. The template is fixed in structure but adaptive in rendering — groups and pages only appear when data exists.
Getting Started
Home
Getting Started
Design
Project Overview
Project Name
Project Description
Stakeholders
Assumptions
Use-cases
Requirements
Functional Requirements
Non-Functional Requirements
Performance
Scalability
Security
Reliability
Maintainability
System Architecture
High-Level Diagram
Technology Stack
Frontend
Backend
Database
Infrastructure
System Components
Module Design
Module Name
Purpose
Inputs
Outputs
Dependencies
Flow
Database Design
ER Diagram
Schema Design
Indexes
Transactions
API Design
Endpoints
HTTP Method (GET/POST/PUT/DELETE)
URL Schemas / naming conventions
Request/Response structure
Authentication
Authorization (roles, resources, permissions)
Rate Limiting
Error Handling
Security Design
Authentication / Authorization
Data Encryption
Security Auditing
Vulnerabilities
Security Stack
Deployment Architecture
Deployment Diagram
Environment Setup
Development
Staging
Production
Scaling Strategy
Monitoring Stack
Testing Strategy
Unit Testing
Integration Testing
Acceptance Testing
Performance Testing
Security Testing
Automated Testing
Maintenance & Monitoring
Logging
Alerting
System Health Monitoring
Error Tracking
Backup & Recovery
Backup Strategy
Disaster Recovery
Risks & Mitigation
Technical Risks
Mitigation Strategies
Future Enhancements
Roadmap
Scalability Considerations
Project Management
Roadmap
Features (grouped by service/area)
Decision Register
Developers
Source Map
Test Coverage
Spec Coverage
API Reference
CLI Reference
Configuration
Exports (collapsed)
TOGAF Phases
ArchiMate ModelLevel 1 = sidebar group. Level 2 = sidebar page link. Level 3+ = page content sections (rendered as the page outline/TOC, not sidebar links). The sidebar is 2 levels deep (group > page). Groups and pages only appear when their data source exists — the template adapts to the project type.
Rationale: Capturing the full template structure as a decision ensures the generator has a single authoritative reference for what to render. The template is universal — it applies to any project type — but adapts by suppressing sections without data.
decision-register-consolidated [—]
Source: usm/gen-technical-design
Decision: A Decision Register page consolidates all decisions from features, services, and system principles into one page under Project Management.
Rationale: Decisions are currently scattered across feature docs and TOGAF Phase H. A single register is the project governance view — what was decided, why, and what alternatives were rejected.
features-as-project-management [—]
Source: usm/gen-technical-design
Decision: Features are grouped under Project Management, not Design. Features with flows/contracts/tests/status are work records, not design prose.
Rationale: Separating how the system is designed from how the project is managed is cleaner. Design is the system; Project Management is the work.
default-human-gate [—]
Source: usm/agent-feedback
Decision: human-gate is the default policy
Rationale: Matches USM's human-in-the-loop philosophy (ALWAYS show the human first). Prevents noisy autonomous issues and unreviewed files. Projects with confidence and gh auth can opt into direct modes.
feedback-as-first-class-usm-type [—]
Source: usm/agent-feedback
Decision: Feedback entries are $type: feedback .usm files in .usm/feedback, not a free-form markdown log
Rationale: Consistent with structured-source-of-truth principle. Validated, queryable via MCP, convertible to features/issues. Avoids the drift that made ad-hoc bugs.md useless.
one-shared-protocol-block [—]
Source: usm/agent-feedback
Decision: A single Feedback Protocol block is rendered into all four rules files from one code path
Rationale: Same rationale as the existing WORKFLOW_INSTRUCTIONS — one source, avoids drift between agent tools (Cursor/Claude/Codex/Copilot).
setup-asks-two-questions [—]
Source: usm/agent-feedback
Decision: usm init asks exactly two questions: gh auth presence and policy choice
Rationale: Minimal friction. gh_auth gates the direct-to-github option; policy drives everything else. Tracker and feedback_dir have sensible defaults.
mcp-tool-respects-policy [—]
Source: usm/agent-feedback
Decision: usm_report_feedback consults system.feedback.policy before writing
Rationale: In human-gate mode the tool returns a draft preview for the human instead of writing, keeping the agent honest even if it ignores the rules file.
write-tools-as-mcp-not-cli [accepted]
Source: usm/mcp-write
Decision: Implement authoring as MCP tools rather than CLI commands only
Rationale: Agents work through MCP in Cursor, Claude Desktop, and other tools. A CLI command requires the agent to shell out, parse output, and handle errors externally. An MCP tool returns structured JSON the agent can reason about directly. CLI wrappers can be added later for human use.
Alternatives:
- CLI commands only (usm feature draft, usm feature update) — rejected: Agents must shell out, parse stdout, handle errors externally — MCP returns structured JSON directly
- File system writes only (agent writes YAML directly) — rejected: No validation, no markdown preview, no status transition enforcement — agents would produce invalid .usm files
Consequences: MCP server gains write capability — needs careful validation to prevent corruption
draft-returns-preview [accepted]
Source: usm/mcp-write
Decision: draft_feature returns both YAML and generated markdown
Rationale: The human reviews the markdown, not the YAML. Returning both lets the agent show the human the readable preview immediately without a separate generate step. The agent can also iterate on the draft based on feedback before writing to disk.
Consequences: draft_feature is heavier than a pure YAML generator, but the review step is the whole point
validate-before-write [accepted]
Source: usm/mcp-write
Decision: All write operations validate against the v1 schema before persisting
Rationale: An invalid .usm file breaks downstream generators and MCP read tools. Validation at write time prevents corruption. The tool returns structured validation errors so the agent can fix them before retrying.
Consequences: Write operations are slower due to validation, but prevent corrupt .usm files from entering the system
Service Decisions
json-over-yaml [—]
Source: usm/usm-config
Decision: Use JSON for usmconfig (not YAML) because it is machine-generated and machine-read
Rationale: Config is produced by usm init and consumed by usm scan — no hand-editing required for initial creation
Architecture Principles (as decisions)
structured-source-of-truth
Decision: Every system artifact is captured in YAML validated by a JSON Schema — no scattered, stale docs.
agent-first
Decision: USM files are designed for AI agent consumption via MCP tools before human readability.
idempotent-generation
Decision: Scan and generate are safe to run repeatedly; smart-merge preserves human edits.
one-source-many-outputs
Decision: A single .usm/ directory generates markdown, Mermaid, OpenAPI, ArchiMate, TOGAF, AGENTS.md, and Vitest specs.