@principled/cairn
v1.0.13-beta
Published
Cairn — decision traceability framework. Trace every decision back to what drives it.
Maintainers
Readme
Cairn — Goals, Values, and Principles
A decision traceability framework. Define your goals, values, and principles in YAML. Trace every decision back to what drives it. Link decisions to the code, documents, and artifacts they produce.
Install
npm install -g @principled/cairnNote:
gvpis available as an alias forcairn.
Quick Start
# Initialize a GVP library
mkdir -p .gvp/library
cat > .gvp/library/project.yaml << 'EOF'
meta:
name: my-project
scope: project
goals:
- id: G1
name: Ship reliable software
statement: Deliver software that works correctly.
tags: []
maps_to: []
values:
- id: V1
name: Simplicity
statement: Complexity must earn its place.
tags: []
maps_to: [my-project:G1]
decisions:
- id: D1
name: Use TypeScript
rationale: Type safety and npm ecosystem.
tags: []
maps_to: [my-project:G1, my-project:V1]
refs:
- file: src/index.ts
identifier: main
role: implements
EOF
# Validate
cairn validate
# Export
cairn export --format json
cairn export --format markdownCommands
| Command | Description |
|---------|-------------|
| cairn validate | Validate the GVP library |
| cairn validate --coverage | Include coverage checks (orphan identifiers, decisions without refs) |
| cairn validate --scope staged | Scope validation to staged git changes |
| cairn export --format <fmt> | Export catalog to json, csv, markdown, or dot |
| cairn add <category> <name> | Add a new element with auto-assigned ID |
| cairn edit <element> --field key=value | Modify an existing element |
| cairn review | Find stale elements needing review |
| cairn review <element> | Review a specific element |
| cairn inspect <element> | View element details |
| cairn inspect <element> --trace | Trace element to its goals and values |
| cairn inspect --ref file::identifier --trace | "Why does this code exist?" |
| cairn query --category decision | Filter elements by category, tag, status |
| cairn query --refs-file src/foo.ts | Find elements referencing a file |
| cairn diff <commitA> <commitB> | Trace code changes back to decisions |
| cairn analyze | Detect unmapped relationships via similarity |
Global Options
| Flag | Description |
|------|-------------|
| --config <path> | Load specific config file |
| --no-config | Skip all config files |
| -c key=value | Inline config override |
| --strict | Promote warnings to errors |
| -v / -vv / -vvv | Verbose output |
Validation Codes
Errors
| Code | Name | Description |
|------|------|-------------|
| E001 | BROKEN_REFERENCE | maps_to target not found |
| E002 | DUPLICATE_ELEMENT_ID | Duplicate element ID within a document |
| E003 | BROKEN_INHERITANCE | Inherited document not found |
| E004 | SCHEMA_VALIDATION | Element fails schema validation |
| E005 | DUPLICATE_STEP_ID | Duplicate step ID within a procedure |
Warnings
| Code | Name | Description |
|------|------|-------------|
| W001 | EMPTY_MAPS_TO | Non-root active element has no maps_to |
| W002 | EMPTY_DOCUMENT | Document has no active elements |
| W003 | MAPPING_RULES_VIOLATION | Element doesn't satisfy category mapping rules |
| W004 | ORPHAN_ELEMENT | Isolated element (no incoming or outgoing edges) |
| W005 | SELF_DOCUMENT_MAPPING | Element maps only within its own document |
| W006 | STALE_ELEMENT | Element has unreviewed updates |
| W007 | UNDEFINED_TAG | Element uses tag not in definitions |
| W008 | DUPLICATE_CATEGORY_DEF | Duplicate category definition within library siblings |
| W009 | ID_SEQUENCE_GAP | Gap in element ID sequence |
| W010 | REF_FILE_MISSING | Ref points to nonexistent file |
| W011 | REF_IDENTIFIER_MISSING | Ref identifier not found in file |
| W012 | ORPHAN_IDENTIFIER | Identifier not referenced by any element (coverage pass) |
| W013 | DECISION_NO_REFS | Decision has no refs (coverage pass) |
| W014 | NO_ROOT_TRACE | Element cannot trace to any root element transitively |
| W015 | AUTO_ASSIGNED_STEP_ID | Procedure has steps without explicit IDs; auto-numbered at load time |
Config
Config files are discovered in this order (closer scope wins):
/etc/gvp/config.yaml(system)~/.config/gvp/config.yaml(global).gvp/config.yaml(project).gvp.yaml(local, gitignored)
Environment variables: GVP_CONFIG_SYSTEM, GVP_CONFIG_GLOBAL, GVP_CONFIG_PROJECT, GVP_CONFIG_LOCAL
# .gvp/config.yaml
user:
name: "Your Name"
email: "[email protected]"
strict: false
suppress_diagnostics: []
default_timezone: "America/New_York"
priority:
elements: ancestor # ancestor-wins for elements
definitions: descendant # descendant-wins for definitions
# Coverage settings (patterns use glob syntax via minimatch: *, **, ?)
coverage:
exclude:
- "README.md"
- ".gvp/**"
- "**/*.test.ts"
- "docs/**"Built-in Categories
| Category | Prefix | Root | Primary Field | |----------|--------|------|---------------| | goal | G | yes | statement | | value | V | yes | statement | | constraint | C | yes | impact | | principle | P | no | statement | | rule | R | no | statement | | heuristic | H | no | statement | | decision | D | no | rationale | | milestone | M | no | description | | procedure | S | no | description |
Cross-Repo Inheritance
GVP libraries can inherit from other libraries hosted in git repositories.
Documents reference external sources in meta.inherits:
meta:
name: my-project
inherits:
- source: "@github:company/[email protected]"
as: org
- source: "@azure:myorg/myproject/[email protected]"
as: sharedSupported providers:
| Provider | Format | Resolves to |
|----------|--------|-------------|
| GitHub | @github:user/repo@tag | https://github.com/user/repo.git |
| Azure DevOps | @azure:org/project/repo@tag | https://dev.azure.com/org/project/_git/repo |
| GitLab | @gitlab:user/repo@tag | https://gitlab.com/user/repo.git |
| Bitbucket | @bitbucket:user/repo@tag | https://bitbucket.org/user/repo.git |
The commit-ish must be an immutable reference (tag or SHA) — branches are not
allowed. Sources are cached at ~/.cache/cairn/sources/ and only cloned once.
Elements in inherited libraries are accessible via aliased references:
decisions:
- id: D1
name: Follow org coding standards
maps_to: [org:values:V1, my-project:G1]Refs — Linking Decisions to Artifacts
Any element can have refs linking it to external files:
refs:
- file: src/catalog/catalog.ts
identifier: Catalog
role: implements # defines | implements | uses | extendsThe refs system is domain-agnostic — it works with any file type that has a registered parser (TypeScript, Markdown, YAML built-in).
Documentation
- Getting Started — Set up GVP on a new project
- Command Reference — Command reference
- Workflow Guide — End-to-end design → implementation → review workflow
- Lightweight Capture — ~5 min decision capture after brainstorming sessions
