Frontmatter-Based Spec Coordination
This proposal establishes a standardized frontmatter schema for coordinating markdown documents across specification systems. By leveraging YAML frontmatter metadata, AI agents and tooling can discover relationships, validate consistency, and navigate complex specification hierarchies without custom parsing or external databases.
Key Insight: Markdown frontmatter is the natural coordination layer for specification documents. When standardized across an organization, frontmatter becomes a queryable graph of relationships, enabling AI agents to traverse specifications, detect conflicts, and maintain consistency without proprietary tooling.
Problem Statement
Current State: Inconsistent Metadata
Evidence from Documentation Challenges
| Challenge | Impact |
|---|---|
| No standard schema | Each team invents their own frontmatter fields |
| Missing relationships | AI cannot discover related documents |
| No validation | Invalid references go undetected |
| Discovery by content only | Must read entire documents to understand structure |
| Manual cross-referencing | Humans maintain links that drift out of sync |
The Fundamental Problem
Without standardized frontmatter:
- AI agents cannot build a document graph
- Validation requires parsing prose, not metadata
- Changes to one document cannot automatically notify dependents
- Search requires full-text matching instead of structured queries
- Tooling must be custom-built for each project
Proposed Solution: Frontmatter Coordination Schema
Target Architecture
Core Principles
- Schema-First Metadata: All frontmatter fields follow a defined schema
- Explicit Relationships: Document links declared in frontmatter, not prose
- Machine-Readable Discovery: Tooling can build graphs without parsing content
- Human-Readable Authoring: Standard YAML that humans can write and review
- Validation at Commit: CI validates schema compliance and reference integrity
Frontmatter Schema Specification
Required Fields
Every specification document MUST include these fields:
# Identity (required)
id: unique-document-identifier # kebab-case, globally unique
title: Human Readable Title # Display name
type: spec | principle | guideline | decision | proposal
# Lifecycle (required)
status: draft | review | approved | deprecated | archived
version: 1.0.0 # Semantic versioning
created: 2025-01-15 # ISO 8601 date
updated: 2025-11-28 # ISO 8601 date
# Ownership (required)
owner: team-name | email@company.comRelationship Fields
Documents SHOULD declare relationships using these standardized fields:
# Hierarchical relationships
inherits: # Parent specs this inherits from
- org-specs/principles/api-design
- products/vsaas/domains/device
# Peer relationships
related: # Non-hierarchical related documents
- features/video-playback
- features/device-monitoring
# Dependencies
depends_on: # Must exist/be implemented first
- shared/integrations/sso
- features/authentication
# Cross-product references
cross_product_refs: # Specs in other products
- vortex/features/device-sync
- shared/domains/user-identity
# Overrides
overrides: # Higher-level specs being modified
- principle: org-specs/principles/api-design
requirement: REQ-API-001
justification: Video streaming requires action-based endpointsScope and Classification Fields
# Scope
scope: organization | product | feature | platform | implementation
level: 0 | 1 | 2 | 3 | 4 # Multi-level hierarchy position
product: vsaas | vortex | cloud-portal
feature: device-management
platform: web | ios | android | backend
# Classification
tags:
- api
- device
- core-feature
domain: device | video | user | billing
# Audience
audience:
- ai-agent
- developer
- product-manager
visibility: public | internal | confidentialAI Guidance Fields
# AI-specific metadata
ai_hints:
- Use cursor-based pagination for all list endpoints
- Device status must use DeviceStatus enum
- Always check permissions before device operations
ai_context:
priority: high # How important for AI to read
summary: | # Brief description for AI context
Device management API contract defining CRUD operations
for devices within sites. Uses cursor pagination.
ai_exclude: false # Set true to exclude from AI contextRelationship Types
Inheritance (inherits)
Hierarchical relationship where child document extends parent.
Semantics:
- Child inherits all requirements from parent
- Child may extend but not contradict parent (unless
overridesdeclared) - Changes to parent automatically affect children
Example:
id: web-device-management
inherits:
- products/vsaas/features/device-management/requirement
- org-specs/shared/components/design-systemDependency (depends_on)
Implementation ordering constraint.
Semantics:
- Dependent spec cannot be implemented until dependencies exist
- Circular dependencies are validation errors
- Tooling can compute implementation order
Example:
id: device-management
depends_on:
- features/authentication # Same product
- shared/integrations/sso # Shared infrastructureRelated (related)
Non-hierarchical association for context.
Semantics:
- Documents share context but don't inherit
- Changes may warrant review of related docs
- Bidirectional by convention (if A relates to B, B should relate to A)
Example:
id: device-management
related:
- features/video-playback # Often used together
- features/device-monitoring # Shared device conceptCross-Product Reference (cross_product_refs)
References spanning product boundaries.
Semantics:
- Documents in different products or shared domains
- Changes require cross-team coordination
- AI agents must read referenced docs for full context
Example:
id: device-management
product: vsaas
cross_product_refs:
- vortex/features/device-sync # Related feature in another product
- shared/domains/user-identity # Global domain concept
- shared/domains/permissions # Permission modelOverride (overrides)
Explicit modification of inherited requirements.
id: vsaas-api-contract
overrides:
- principle: org-specs/principles/api-design
requirement: REQ-API-001
justification: Video streaming requires action-based endpoints
approved_by: architecture-guild@company.com
approved_date: 2025-10-15Semantics:
- Must reference specific principle and requirement
- Justification is required
- Approval chain documented
- Without explicit override, inheritance wins
Schema Validation
JSON Schema Definition
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://company.com/schemas/spec-frontmatter.json",
"title": "Spec Frontmatter Schema",
"type": "object",
"required": ["id", "title", "type", "status", "version", "created", "updated", "owner"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
"description": "Unique identifier in kebab-case"
},
"title": {
"type": "string",
"minLength": 3,
"maxLength": 100
},
"type": {
"enum": ["spec", "principle", "guideline", "decision", "proposal"]
},
"status": {
"enum": ["draft", "review", "approved", "deprecated", "archived"]
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"inherits": {
"type": "array",
"items": { "type": "string" }
},
"depends_on": {
"type": "array",
"items": { "type": "string" }
},
"related": {
"type": "array",
"items": { "type": "string" }
},
"cross_product_refs": {
"type": "array",
"items": { "type": "string" }
},
"overrides": {
"type": "array",
"items": {
"type": "object",
"required": ["principle", "requirement", "justification"],
"properties": {
"principle": { "type": "string" },
"requirement": { "type": "string" },
"justification": { "type": "string" },
"approved_by": { "type": "string" },
"approved_date": { "type": "string", "format": "date" }
}
}
}
}
}CI Validation Pipeline
# .github/workflows/validate-frontmatter.yml
name: Validate Spec Frontmatter
on:
pull_request:
paths:
- '**/*.md'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate frontmatter schema
run: |
npx frontmatter-validator \
--schema .schema/spec-frontmatter.json \
--glob "specs/**/*.md" \
--glob "products/**/features/**/*.md"
- name: Validate reference integrity
run: |
npx spec-ref-validator \
--check-inherits \
--check-depends-on \
--check-related \
--check-cross-product-refs
- name: Check for circular dependencies
run: |
npx spec-graph-validator \
--detect-cycles \
--relationship depends_onReference Integrity Validation
// scripts/validate-refs.ts
interface ValidationResult {
valid: boolean;
errors: RefError[];
warnings: RefWarning[];
}
interface RefError {
source: string;
field: string;
target: string;
error: 'not_found' | 'circular' | 'invalid_format';
}
async function validateReferences(specPath: string): Promise<ValidationResult> {
const spec = await parseSpec(specPath);
const errors: RefError[] = [];
// Validate inherits references
for (const ref of spec.inherits || []) {
if (!await specExists(ref)) {
errors.push({
source: specPath,
field: 'inherits',
target: ref,
error: 'not_found'
});
}
}
// Validate depends_on references
for (const ref of spec.depends_on || []) {
if (!await specExists(ref)) {
errors.push({
source: specPath,
field: 'depends_on',
target: ref,
error: 'not_found'
});
}
}
// Check for circular dependencies
const cycles = await detectCycles(specPath, 'depends_on');
for (const cycle of cycles) {
errors.push({
source: specPath,
field: 'depends_on',
target: cycle.join(' -> '),
error: 'circular'
});
}
return {
valid: errors.length === 0,
errors,
warnings: []
};
}AI Agent Integration
Document Graph Construction
// AI agents can construct a document graph from frontmatter
interface SpecNode {
id: string;
path: string;
frontmatter: SpecFrontmatter;
children: SpecNode[]; // Documents that inherit from this
parents: SpecNode[]; // Documents this inherits from
dependencies: SpecNode[]; // Documents this depends on
dependents: SpecNode[]; // Documents that depend on this
related: SpecNode[]; // Related documents
}
async function buildSpecGraph(rootPath: string): Promise<Map<string, SpecNode>> {
const specs = await glob(`${rootPath}/**/*.md`);
const graph = new Map<string, SpecNode>();
// First pass: parse all frontmatter
for (const specPath of specs) {
const frontmatter = await parseFrontmatter(specPath);
if (frontmatter.id) {
graph.set(frontmatter.id, {
id: frontmatter.id,
path: specPath,
frontmatter,
children: [],
parents: [],
dependencies: [],
dependents: [],
related: []
});
}
}
// Second pass: build relationships
for (const [id, node] of graph) {
// Link inheritance
for (const parentId of node.frontmatter.inherits || []) {
const parent = graph.get(resolveId(parentId));
if (parent) {
node.parents.push(parent);
parent.children.push(node);
}
}
// Link dependencies
for (const depId of node.frontmatter.depends_on || []) {
const dep = graph.get(resolveId(depId));
if (dep) {
node.dependencies.push(dep);
dep.dependents.push(node);
}
}
// Link related
for (const relId of node.frontmatter.related || []) {
const rel = graph.get(resolveId(relId));
if (rel) {
node.related.push(rel);
}
}
}
return graph;
}MCP Resource Provider
// MCP server exposing spec graph
const specGraphServer = {
resources: {
// List all specs with their frontmatter
'spec://list': async () => {
const graph = await buildSpecGraph(SPEC_ROOT);
return Array.from(graph.values()).map(node => ({
uri: `spec://${node.id}`,
name: node.frontmatter.title,
mimeType: 'text/markdown',
metadata: {
type: node.frontmatter.type,
status: node.frontmatter.status,
version: node.frontmatter.version,
parentCount: node.parents.length,
childCount: node.children.length,
dependencyCount: node.dependencies.length
}
}));
}
},
tools: {
// Get full inheritance chain
getInheritanceChain: async ({ specId }) => {
const graph = await buildSpecGraph(SPEC_ROOT);
const spec = graph.get(specId);
if (!spec) return { error: 'Spec not found' };
const chain = [];
let current = spec;
const visited = new Set();
while (current.parents.length > 0 && !visited.has(current.id)) {
visited.add(current.id);
for (const parent of current.parents) {
chain.push({
id: parent.id,
title: parent.frontmatter.title,
level: parent.frontmatter.level
});
}
current = current.parents[0]; // Follow primary inheritance
}
return { chain };
},
// Analyze change impact
analyzeImpact: async ({ specId }) => {
const graph = await buildSpecGraph(SPEC_ROOT);
const spec = graph.get(specId);
if (!spec) return { error: 'Spec not found' };
const impacted = {
directChildren: spec.children.map(c => c.id),
directDependents: spec.dependents.map(d => d.id),
transitiveImpact: []
};
// BFS for transitive impact
const queue = [...spec.children, ...spec.dependents];
const visited = new Set([specId]);
while (queue.length > 0) {
const node = queue.shift();
if (visited.has(node.id)) continue;
visited.add(node.id);
impacted.transitiveImpact.push(node.id);
queue.push(...node.children, ...node.dependents);
}
return impacted;
},
// Find specs by criteria
querySpecs: async ({ type, status, product, tags }) => {
const graph = await buildSpecGraph(SPEC_ROOT);
return Array.from(graph.values())
.filter(node => {
if (type && node.frontmatter.type !== type) return false;
if (status && node.frontmatter.status !== status) return false;
if (product && node.frontmatter.product !== product) return false;
if (tags && !tags.every(t => node.frontmatter.tags?.includes(t))) return false;
return true;
})
.map(node => ({
id: node.id,
title: node.frontmatter.title,
path: node.path
}));
}
}
};CLAUDE.md Integration
# Frontmatter-Based Navigation - AI Instructions
## Understanding Frontmatter
All specification documents use standardized YAML frontmatter.
Use frontmatter to navigate relationships, not prose content.
## Before Reading Any Spec
1. Parse frontmatter first
2. Check `inherits` for parent context
3. Check `depends_on` for prerequisites
4. Check `cross_product_refs` for related products
5. Then read content with full context
## Building ContextFor feature X in product Y:
- Find: products/{Y}/features/{X}/requirement.md
- Read frontmatter.inherits[] -> trace to org principles
- Read frontmatter.depends_on[] -> understand prerequisites
- Read frontmatter.cross_product_refs[] -> related products
- Now read content with full relationship context
## Validating Changes
When modifying a spec:
1. Check frontmatter.version -> increment appropriately
2. Update frontmatter.updated -> today's date
3. If adding dependency -> add to depends_on[]
4. If overriding parent -> add to overrides[] with justification
## Querying the Graph
Use MCP tools to query spec relationships:
- `getInheritanceChain(specId)` -> trace to root principles
- `analyzeImpact(specId)` -> find affected documents
- `querySpecs({type, status, product})` -> find related specsImplementation Workflow
Document Creation Flow
Migration Strategy
Phase 1: Schema Definition (Week 1)
- [ ] Define frontmatter JSON schema
- [ ] Create validation tooling
- [ ] Document schema specification
- [ ] Create document templates
Phase 2: Pilot Migration (Week 2-3)
- [ ] Select pilot product/feature
- [ ] Add frontmatter to existing specs
- [ ] Validate reference integrity
- [ ] Train team on schema
Phase 3: Tooling Integration (Week 4-5)
- [ ] Implement CI validation pipeline
- [ ] Create MCP resource provider
- [ ] Build spec graph visualization
- [ ] Integrate with AI agent workflows
Phase 4: Full Rollout (Week 6-8)
- [ ] Migrate remaining products
- [ ] Update CLAUDE.md files
- [ ] Monitor validation metrics
- [ ] Iterate on schema based on feedback
Success Metrics
| Metric | Target | Measurement |
|---|---|---|
| Schema compliance | 100% | All specs pass validation |
| Reference integrity | 100% | No broken links in frontmatter |
| Relationship coverage | >80% | Specs with explicit relationships |
| AI navigation accuracy | >90% | Correct context traversal |
| Change impact accuracy | >95% | Predicted vs actual affected docs |
| Discovery latency | <100ms | Frontmatter-based queries |
Anti-Patterns to Avoid
1. Relationships in Prose Only
Problem: Writing "See also: device-management" in content without frontmatter.
Why It Fails: AI and tooling cannot detect the relationship.
Instead: Use related: or cross_product_refs: in frontmatter.
2. Duplicate Information
Problem: Repeating inherited content in child specs.
Why It Fails: Content drifts; updates miss duplicates.
Instead: Reference via inherits: and extend only with new content.
3. Implicit Dependencies
Problem: Assuming implementation order without declaration.
Why It Fails: Parallel work breaks; AI suggests wrong order.
Instead: Explicitly declare in depends_on: array.
4. Unversioned Changes
Problem: Modifying specs without updating version/updated fields.
Why It Fails: Cannot track changes; caches serve stale content.
Instead: Always update version: and updated: fields.
5. Over-Nested Inheritance
Problem: Creating 10+ level inheritance chains.
Why It Fails: Difficult to trace; inheritance resolution becomes slow.
Instead: Keep inheritance depth under 5 levels; use related: for lateral connections.
Template
Spec Document Template
# Identity (required)
id: feature-name
title: Feature Name
type: spec
# Lifecycle (required)
status: draft
version: 0.1.0
created: {{DATE}}
updated: {{DATE}}
# Ownership (required)
owner: team-name
# Scope
scope: feature
level: 2
product: product-name
feature: feature-name
# Relationships
inherits:
- products/{{product}}/principles/domain
- org-specs/principles/api-design
depends_on:
- features/authentication
related:
- features/related-feature
cross_product_refs:
- shared/domains/user-identity
# Classification
tags:
- tag1
- tag2
# AI Guidance
ai_hints:
- Hint for AI implementation
ai_context:
priority: medium
summary: Brief description for AI context
# Feature Name
## Overview
Brief description of the feature.
## Requirements
### REQ-001: Requirement Name
The system SHALL...
#### Scenario: Success case
- **WHEN** condition
- **THEN** expected result
## AI Implementation Notes
@ai-hint Implementation guidance here.Related Principles
- G2: Version-Controlled Documentation - Metadata in version-controlled files
- G4: Unified Product Management - Cross-product spec coordination
Related: Global Requirement Store | Multi-Product Spec Management | Agent-Friendly Knowledge Base
References
- YAML Frontmatter - Standard frontmatter format
- JSON Schema - Schema validation specification
- Model Context Protocol (MCP) - AI-tool integration protocol
- OpenSpec - Specification-driven development framework