Skip to content

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

ChallengeImpact
No standard schemaEach team invents their own frontmatter fields
Missing relationshipsAI cannot discover related documents
No validationInvalid references go undetected
Discovery by content onlyMust read entire documents to understand structure
Manual cross-referencingHumans 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

  1. Schema-First Metadata: All frontmatter fields follow a defined schema
  2. Explicit Relationships: Document links declared in frontmatter, not prose
  3. Machine-Readable Discovery: Tooling can build graphs without parsing content
  4. Human-Readable Authoring: Standard YAML that humans can write and review
  5. Validation at Commit: CI validates schema compliance and reference integrity

Frontmatter Schema Specification

Required Fields

Every specification document MUST include these fields:

yaml
# 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.com

Relationship Fields

Documents SHOULD declare relationships using these standardized fields:

yaml
# 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 endpoints

Scope and Classification Fields

yaml
# 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 | confidential

AI Guidance Fields

yaml
# 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 context

Relationship 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 overrides declared)
  • Changes to parent automatically affect children

Example:

yaml
id: web-device-management
inherits:
  - products/vsaas/features/device-management/requirement
  - org-specs/shared/components/design-system

Dependency (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:

yaml
id: device-management
depends_on:
  - features/authentication      # Same product
  - shared/integrations/sso      # Shared infrastructure

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:

yaml
id: device-management
related:
  - features/video-playback       # Often used together
  - features/device-monitoring    # Shared device concept

Cross-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:

yaml
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 model

Override (overrides)

Explicit modification of inherited requirements.

yaml
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-15

Semantics:

  • Must reference specific principle and requirement
  • Justification is required
  • Approval chain documented
  • Without explicit override, inheritance wins

Schema Validation

JSON Schema Definition

json
{
  "$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

yaml
# .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_on

Reference Integrity Validation

typescript
// 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

typescript
// 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

typescript
// 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

markdown
# 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 Context

For feature X in product Y:

  1. Find: products/{Y}/features/{X}/requirement.md
  2. Read frontmatter.inherits[] -> trace to org principles
  3. Read frontmatter.depends_on[] -> understand prerequisites
  4. Read frontmatter.cross_product_refs[] -> related products
  5. 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 specs

Implementation 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

MetricTargetMeasurement
Schema compliance100%All specs pass validation
Reference integrity100%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<100msFrontmatter-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

markdown
# 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: Global Requirement Store | Multi-Product Spec Management | Agent-Friendly Knowledge Base

References