ADR Schema
Every Archgate ADR is a Markdown file stored in .archgate/adrs/ with YAML frontmatter that defines the decision’s identity and scope. This page documents the frontmatter schema, markdown section structure, and validation behavior.
Frontmatter Schema
Section titled “Frontmatter Schema”The YAML frontmatter block sits between --- delimiters at the top of the file.
---id: ARCH-001title: Command Structuredomain: architecturerules: truefiles: ["src/commands/**/*.ts"]---Fields
Section titled “Fields”| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique identifier. Must be non-empty. Convention: PREFIX-NNN (e.g., ARCH-001). |
title | string | Yes | Human-readable title of the decision. Must be non-empty. |
domain | enum | Yes | Domain category. One of: backend, frontend, data, architecture, general. |
rules | boolean | Yes | Whether this ADR has a companion .rules.ts file with automated checks. |
files | string[] | No | Glob patterns that scope which files the rules apply to. |
The ADR identifier. By convention, it uses the domain prefix followed by a zero-padded sequence number (e.g., ARCH-001, BE-003). The archgate adr create command generates IDs automatically.
Any non-empty string is valid, but following the prefix convention keeps ADRs organized and sortable.
A short, descriptive name for the architectural decision. Displayed in archgate adr list output and used as the heading when AI agents reference the ADR.
domain
Section titled “domain”Groups related ADRs together. The domain also determines the ID prefix used by archgate adr create.
Set to true when this ADR has a companion .rules.ts file. When archgate check runs, it skips ADRs where rules is false.
An optional array of glob patterns that scope the rule’s file coverage. When present, ctx.scopedFiles in the rules file only contains files matching these patterns. When absent, all project files are in scope.
files: ["src/commands/**/*.ts"]Multiple patterns can be specified:
files: ["src/api/**/*.ts", "src/middleware/**/*.ts"]Domain Prefixes
Section titled “Domain Prefixes”Each domain maps to a prefix used in the ADR ID convention.
| Domain | Prefix | Example ID |
|---|---|---|
backend | BE | BE-001 |
frontend | FE | FE-001 |
data | DATA | DATA-001 |
architecture | ARCH | ARCH-001 |
general | GEN | GEN-001 |
The archgate adr create command uses this mapping to auto-generate IDs.
File Naming Convention
Section titled “File Naming Convention”ADR files follow a naming convention that encodes the ID and a human-readable slug:
{ID}-{slug}.md # The document{ID}-{slug}.rules.ts # The companion rules file (optional)For example:
ARCH-001-command-structure.mdARCH-001-command-structure.rules.tsThe slug is a kebab-case version of the title, auto-generated by archgate adr create.
Markdown Sections
Section titled “Markdown Sections”After the frontmatter, the ADR body follows a standard section structure. While Archgate does not enforce specific sections, the following structure is recommended for consistency.
Context
Section titled “Context”Describes the problem or situation that prompted the decision. Include alternatives that were considered and why they were rejected.
## Context
The CLI returns errors in inconsistent formats. Some commands print rawstack traces, others print nothing, and a few use `console.error()` withcustom formatting.
**Alternatives considered:**
- **No standard** -- Let each command handle errors its own way. Simple but leads to an inconsistent user experience.- **Try/catch wrapper** -- A global try/catch at the CLI entry point. Loses context about which command failed.Decision
Section titled “Decision”States the decision itself and its key constraints. This is the primary section AI agents read before writing code.
## Decision
All commands MUST use `logError()` from `src/helpers/log.ts` for erroroutput. Commands MUST NOT call `console.error()` directly.Do’s and Don’ts
Section titled “Do’s and Don’ts”Concrete, actionable guidance split into two sub-sections. These act as a quick-reference checklist for developers and AI agents.
## Do's and Don'ts
### Do
- Use `logError(message, detail?)` for all error output- Include a suggested fix in the detail parameter when possible- Exit with code 1 for user errors, code 2 for internal errors
### Don't
- Don't call `console.error()` directly in command files- Don't print stack traces to users- Don't exit without printing an error message firstConsequences
Section titled “Consequences”Split into three sub-sections that document trade-offs.
## Consequences
### Positive
- Consistent error formatting across all commands- Machine-parseable error output when combined with `--json`
### Negative
- Requires importing `logError` in every command file- Cannot use built-in error formatting from libraries
### Risks
- New contributors may use `console.error()` by habit. Mitigated by the automated rule that scans for direct `console.error()` calls.Compliance and Enforcement
Section titled “Compliance and Enforcement”Describes how the decision is enforced through automated rules and manual review.
## Compliance and Enforcement
### Automated Enforcement
- **Archgate rule** ARCH-002/no-console-error: Scans command files for `console.error()` calls. Severity: error.
### Manual Enforcement
Code reviewers MUST verify:
1. Error messages are actionable and include context2. Exit codes match the error type (1 for user, 2 for internal)References
Section titled “References”Links to related ADRs, external documentation, or design documents.
## References
- [ARCH-001 -- Command Structure](./ARCH-001-command-structure.md)- [Node.js process.exit documentation](https://nodejs.org/api/process.html#processexitcode)Companion Rules File
Section titled “Companion Rules File”When rules: true, Archgate looks for a companion file with the same name but .rules.ts extension.
ARCH-002-error-handling.md # rules: true in frontmatterARCH-002-error-handling.rules.ts # companion rules fileThe rules file must export a default RuleSet created via defineRules():
import { defineRules } from "archgate/rules";
export default defineRules({ "no-console-error": { description: "Use logError() instead of console.error()", async check(ctx) { for (const file of ctx.scopedFiles) { const matches = await ctx.grep(file, /console\.error\(/); for (const match of matches) { ctx.report.violation({ message: "Use logError() instead of console.error()", file: match.file, line: match.line, fix: "Import logError from src/helpers/log and use it instead", }); } } }, },});See the Rule API for the complete TypeScript API reference.
Validation
Section titled “Validation”The YAML frontmatter is validated at parse time using a Zod schema. Invalid frontmatter causes a parse error with a descriptive message.
Required fields
Section titled “Required fields”If a required field is missing, the ADR fails to parse:
Invalid ADR frontmatter in ARCH-001-example.md: - domain: RequiredInvalid enum values
Section titled “Invalid enum values”If domain is not one of the valid values:
Invalid ADR frontmatter in ARCH-001-example.md: - domain: Invalid enum value. Expected 'backend' | 'frontend' | 'data' | 'architecture' | 'general', received 'security'Type mismatches
Section titled “Type mismatches”If rules is a string instead of a boolean:
Invalid ADR frontmatter in ARCH-001-example.md: - rules: Expected boolean, received stringADRs that fail validation are skipped by archgate check and reported as errors.