# Ledger Schema Ledger documents are Markdown files with YAML frontmatter. This document defines the initial schema. It is intentionally practical rather than exhaustive. Projects can add fields, but Ledger should validate and index the fields listed here first. ## Shared Frontmatter All Ledger documents should include: ```yaml id: "0001" title: "Short title" date: "2026-06-29" updated: "2026-06-29" status: "landed" areas: ["cli", "docs"] ``` Shared fields: | Field | Type | Required | Purpose | | --- | --- | --- | --- | | `id` | string | yes | Stable document id. | | `title` | string | yes | Human-readable title. | | `date` | date string | yes | Creation or landing date. | | `updated` | date string | no | Latest material update date. | | `status` | string | yes | Lifecycle state. | | `areas` | string array | no | Workstream or surface tags. | | `commits` | string array | no | Git commits associated with the document. | | `prs` | string array | no | Pull requests associated with the document. | | `release` | string | no | Release version that carried the work. | | `files` | string array | no | Touched or relevant paths. | | `symbols` | string array | no | Functions, components, schemas, or anchors. | | `tags` | string array | no | Lightweight facets for filtering records, for example `dogfood` or `migration`. | | `decisions` | string array | no | Decision IDs this document realizes or depends on. | | `backlog` | string array | no | Backlog item IDs this document promotes or relates to. | | `supersedes` | string array | no | Documents superseded by this one. | | `related` | string array | no | Other related Ledger document IDs. | | `docs` | string array | no | Durable docs related to this record. | | `staleRefs` | string array | no | Missing historical path references that have been acknowledged. Use `path` or `files:path`. | Projects can allow local strict metadata through `.ledger/config.yaml`: ```yaml schema: allowedFrontmatterFields: - compatibility extensions: phaseId: string releaseId: string productAreas: string[] deferredMigrationNotes: string ``` Supported extension types are `string`, `string[]`, `number`, `boolean`, `date`, `object`, and `array`. ## Change Entry File path: ```txt .ledger/entries/NNNN-kebab-title.md ``` Frontmatter: ```yaml id: "0001" kind: "change" title: "Bootstrap Ledger" date: "2026-06-29" updated: "2026-06-29" status: "landed" areas: ["docs", "cli"] files: - "README.md" - "src/cli.ts" symbols: - "run" commits: [] release: null ``` Required sections: ```markdown # 0001: Bootstrap Ledger ## Summary ## Why ## Changed Files ## Behavior And UX Impact ## Invariants ## Verification ## Notes ``` Optional but recommended sections: ```markdown ## Conflict Rules ## Follow-ups ## Migration Notes ## Agent Digest ``` ### Changed Files Section The file section should list changed files and the reason each file matters. Recommended shape: ```markdown ### src/cli.ts - What changed: Adds the CLI entry point. - Anchor: `run` - On conflict: Keep the command dispatch behavior and preserve the exit-code contract. ``` For broad mechanical work: ```markdown ### Pattern: generated index paths - Files: `.ledger/indexes/*.json` - Rule: These files are generated by `ledger index`. - On conflict: Regenerate from source Markdown. ``` The frontmatter `files` list may also use broad coverage references: ```yaml files: - "src/runtime/session.ts" - "src/features/**" - "prefix:docs/architecture" - "glob:packages/*/src/**" ``` Exact paths are preferred for ordinary changes. Patterns are intended for large migrations, generated surfaces, or directory-wide changes where listing every file would make entries less useful. ### Invariants Section Invariants should be testable when possible. Good: ```markdown - Markdown files under `.ledger/entries` remain the source of truth. - `ledger validate` fails on duplicate entry ids. ``` Weak: ```markdown - Keep this good. ``` ### Verification Section Verification should contain exact commands or checks. ```markdown - `npm test` - `npm run typecheck` - `node dist/cli.js validate` ``` ## Backlog Item File path: ```txt .ledger/backlog/B001-kebab-title.md ``` Frontmatter: ```yaml id: "B001" kind: "backlog" title: "Git-aware entry drafting" date: "2026-06-29" status: "accepted" areas: ["cli", "git"] ``` Required sections: ```markdown # B001: Git-Aware Entry Drafting ## Problem ## Desired Outcome ## Scope ## Acceptance Checks ## Risks ## Promotion Notes ``` ## Decision File path: ```txt .ledger/decisions/D001-kebab-title.md ``` Frontmatter: ```yaml id: "D001" kind: "decision" title: "Markdown is the source of truth" date: "2026-06-29" status: "accepted" areas: ["architecture"] ``` Required sections: ```markdown # D001: Markdown Is The Source Of Truth ## Context ## Decision ## Consequences ## Revisit Criteria ``` ## Release File path: ```txt .ledger/releases/v0.1.0.md ``` Frontmatter: ```yaml id: "v0.1.0" kind: "release" title: "Ledger 0.1.0" date: "2026-06-29" status: "planned" entries: ["0001"] ``` Required sections: ```markdown # Ledger 0.1.0 ## Summary ## Public Notes ## Changes ## Verification ## Known Issues ``` ## Status Vocabulary Common statuses include `draft`, `landed`, `shipped`, `planned`, `released`, `accepted`, `proposed`, `captured`, and `historical`. `historical` records are kept queryable but are excluded from missing path reference warnings by default. ## Product Note Or Feedback File path: ```txt .ledger/entries/NNNN-kebab-title.md ``` Frontmatter: ```yaml id: "0021" kind: "product-note" title: "Improve changelog migration receipt" date: "2026-06-30" updated: "2026-06-30" status: "captured" areas: ["cli"] tags: ["dogfood"] ``` Required sections: ```markdown # 0021: Improve Changelog Migration Receipt ## Context ## Finding ## Impact ## Recommendation ## Follow-ups ``` Change entries: - `draft` - `landed` - `shipped` - `superseded` Backlog items: - `proposed` - `accepted` - `in-progress` - `landed` - `rejected` - `superseded` Decisions: - `proposed` - `accepted` - `superseded` - `rejected` Releases: - `planned` - `released` - `superseded` ## Normalized Manifest Shape `ledger index` writes `.ledger/indexes/manifest.json`. ```json { "schemaVersion": 1, "generatedAt": "2026-06-29T00:00:00.000Z", "projectRoot": "/path/to/repo", "documents": [ { "id": "0001", "kind": "change", "title": "Bootstrap Ledger", "status": "landed", "date": "2026-06-29", "updated": "2026-06-29", "areas": ["docs", "cli"], "files": ["README.md"], "symbols": [], "docs": [], "path": ".ledger/entries/0001-bootstrap-ledger.md", "sections": ["Summary", "Why", "Verification"] } ] } ``` ## Compatibility Promise Ledger should prefer additive schema changes. Existing source documents should remain readable unless they are malformed. New fields should not break old entries. Deprecated fields should produce warnings before they become errors. ## Coverage Config `git.requireEntryFor` and `git.ignore` define which changed paths require Ledger coverage. ```yaml git: requireEntryFor: - src/** - test/** - docs/** ignore: - .ledger/indexes/** - .ledger/reports/** - .ledger/dist/** - docs/llm/manifest.json - node_modules/** - dist/** ``` `ledger coverage` uses this config to compare Git changed files against paths listed by Ledger entries. `ledger validate` also uses `git.ignore` when warning about missing `files` or `docs` references, so generated outputs can stay out of source-control and validation churn. ## Config Validation `.ledger/config.yaml` must be a YAML object. Known nested config sections must use the expected primitive shapes: - path fields are non-empty strings - booleans are actual YAML booleans - numeric fields are numbers - glob lists are arrays of strings - `validation.requiredSections.` values are non-empty arrays of strings Ledger merges valid partial config files with defaults, but malformed nested values fail during workspace discovery instead of being silently ignored.