Introduction
This book contains the governance documentation for govctl, an opinionated CLI for RFC-driven software development.
How This Book Is Organized
Specifications
RFCs (Requests for Comments) are the normative specifications that define govctl’s behavior. They are constitutional law — implementation must conform to them.
- RFC-0000: The governance framework itself. Start here to understand the core concepts: RFCs, Clauses, ADRs, and Work Items.
- RFC-0001: Lifecycle state machines for all artifact types.
Decisions
ADRs (Architectural Decision Records) document significant design choices. They explain why things are built a certain way.
Work Items
Work Items track units of work from inception to completion. They provide an audit trail of what was done and when.
The Data Model
All governance artifacts have a Single Source of Truth (SSOT) in the gov/ directory:
gov/
├── config.toml # govctl configuration
├── rfc/ # RFC-NNNN/rfc.json + clauses/
├── adr/ # ADR-NNNN-*.toml
└── work/ # WI-YYYY-MM-DD-NNN-*.toml
The markdown files in this book are rendered projections — generated from the SSOT by govctl render. Each includes a SHA-256 signature for tampering detection.
Phase Discipline
govctl enforces a strict phase lifecycle:
spec → impl → test → stable
- spec: Defining what will be built. No implementation work permitted.
- impl: Building what was specified.
- test: Verifying implementation matches specification.
- stable: Released for production use.
Phases cannot be skipped. This discipline ensures specifications precede implementation.
Getting Started
- Read RFC-0000 to understand the governance model
- Follow the Getting Started guide to install and initialize
- Learn about RFCs, ADRs, and Work Items
Getting Started
This guide walks you through installing govctl and creating your first governed artifact.
Requirements
- Rust 1.85+ (uses edition 2024)
Installation
# From crates.io
cargo install govctl
# With TUI dashboard feature
cargo install govctl --features tui
# Or build from source
git clone https://github.com/govctl-org/govctl
cd govctl
cargo build --release
# Binary at ./target/release/govctl
# Build with TUI
cargo build --release --features tui
Optional Features
| Feature | Description | Dependencies |
|---|---|---|
tui | Interactive terminal dashboard (govctl tui) | ratatui, crossterm |
Initialize a Project
govctl init
This creates the governance directory structure:
gov/
├── config.toml # Configuration
├── rfc/ # RFC sources
├── adr/ # ADR sources
├── work/ # Work item sources
├── schema/ # JSON schemas
└── templates/ # New artifact templates
Create Your First RFC
govctl new rfc "Feature Title"
This creates gov/rfc/RFC-0000/rfc.json with the RFC metadata.
Add a Clause
RFCs are composed of clauses — atomic units of specification:
govctl new clause RFC-0000:C-SCOPE "Scope" -s "Specification" -k normative
Edit Clause Content
govctl edit RFC-0000:C-SCOPE --stdin <<'EOF'
The feature MUST do X.
The feature SHOULD do Y.
EOF
Validate Everything
govctl check
This validates all governance artifacts against the schema and phase rules.
Render to Markdown
govctl render
Generates human-readable markdown in docs/rfc/RFC-0000.md.
Next Steps
- Working with RFCs — Full RFC lifecycle
- Working with ADRs — Decision records
- Working with Work Items — Task tracking
- Validation & Rendering — Quality gates
Working with RFCs
RFCs (Requests for Comments) are the normative specifications in govctl. They define what will be built before implementation begins.
Creating RFCs
# Auto-assign next available ID
govctl new rfc "Feature Title"
# Specify ID manually
govctl new rfc "Feature Title" --id RFC-0010
RFC Structure
An RFC consists of:
- Metadata (
rfc.json) — ID, title, status, phase, version - Clauses — Atomic units of specification
Working with Clauses
Create a Clause
govctl new clause RFC-0010:C-SCOPE "Scope" -s "Specification" -k normative
Options:
-s, --section— Section name (e.g., “Specification”, “Rationale”)-k, --kind—normative(binding) orinformative(explanatory)
Edit Clause Text
# From stdin
govctl edit RFC-0010:C-SCOPE --stdin <<'EOF'
The system MUST validate all inputs.
The system SHOULD log validation failures.
EOF
# Open in editor
govctl edit RFC-0010:C-SCOPE
List Clauses
govctl list clause
govctl list clause --rfc RFC-0010
Status Lifecycle
RFCs have three statuses:
draft → normative → deprecated
Finalize to Normative
When the spec is complete and approved:
govctl finalize RFC-0010 normative
This makes the RFC binding — implementation must conform to it.
Deprecate
When an RFC is superseded or obsolete:
govctl finalize RFC-0010 deprecated
Phase Lifecycle
RFCs progress through four phases:
spec → impl → test → stable
Advance Phase
govctl advance RFC-0010 impl # Ready for implementation
govctl advance RFC-0010 test # Implementation complete, ready for testing
govctl advance RFC-0010 stable # Tested, ready for production
Phase transitions are gated:
spec → implrequiresstatus = normative- Each phase has invariants that must be satisfied
Versioning
RFCs use semantic versioning:
# Bump version with changelog entry
govctl bump RFC-0010 --patch -m "Fix typo in clause C-SCOPE"
govctl bump RFC-0010 --minor -m "Add new clause for edge case"
govctl bump RFC-0010 --major -m "Breaking change to API contract"
Listing RFCs
govctl list rfc
govctl list rfc --status normative
govctl list rfc --phase impl
Working with ADRs
ADRs (Architectural Decision Records) document significant design choices. They explain why things are built a certain way.
Creating ADRs
govctl new adr "Use Redis for caching"
This creates a TOML file in gov/adr/ with the decision context.
ADR Structure
ADRs contain:
- Context — The situation requiring a decision
- Decision — What was decided
- Consequences — Expected outcomes (positive and negative)
- Status —
proposed,accepted,deprecated, orsuperseded
Editing ADRs
ADRs are TOML files — edit them directly or use govctl:
govctl edit ADR-0003
Status Lifecycle
proposed → accepted → deprecated
↘ superseded
Accept a Decision
When consensus is reached:
govctl accept ADR-0003
Deprecate
When a decision is no longer relevant:
govctl deprecate ADR-0003
Supersede
When a new decision replaces an old one:
govctl supersede ADR-0001 --by ADR-0005
This marks ADR-0001 as superseded and records ADR-0005 as its replacement.
Listing ADRs
govctl list adr
govctl list adr --status accepted
Why TOML?
ADRs use TOML (not JSON or YAML) because:
- Comments allowed — Humans can annotate inline
- Multi-line strings — Clean
"""blocks for prose - No YAML ambiguity —
NOstaysNO, notfalse - Round-trip stable — Deterministic serialization
Working with Work Items
Work Items track units of work from inception to completion. They provide an audit trail of what was done and when.
Creating Work Items
# Create in queue (pending)
govctl new work "Implement caching layer"
# Create and activate immediately
govctl new work --active "Urgent bug fix"
Work items are automatically assigned IDs like WI-2026-01-17-001.
Work Item Structure
Work items contain:
- Title — Brief description
- Notes — Detailed context (array of strings)
- Acceptance Criteria — Checkable completion criteria
- Refs — Links to related RFCs, ADRs, or external resources
Status Lifecycle
queue → active → done
↘ blocked
↘ cancelled
Move Between States
# By ID
govctl mv WI-2026-01-17-001 active
govctl mv WI-2026-01-17-001 done
# By filename (without path)
govctl mv implement-caching.toml active
Acceptance Criteria
Add Criteria
govctl add WI-2026-01-17-001 acceptance_criteria "Unit tests pass"
govctl add WI-2026-01-17-001 acceptance_criteria "Documentation updated"
Mark Criteria Complete
govctl tick WI-2026-01-17-001 acceptance_criteria "Unit tests" -s done
The pattern matches case-insensitively by substring.
Notes
Add context or progress notes:
govctl add WI-2026-01-17-001 notes "Discovered edge case in validation"
Removing Items
Remove items from array fields using flexible matching:
# Substring match (default, case-insensitive)
govctl remove WI-2026-01-17-001 notes "edge case"
# Exact match
govctl remove WI-2026-01-17-001 notes "Discovered edge case in validation" --exact
# By index (0-based)
govctl remove WI-2026-01-17-001 notes --at 0
# Negative index (from end)
govctl remove WI-2026-01-17-001 notes --at -1
# Regex pattern
govctl remove WI-2026-01-17-001 refs "RFC-.*" --regex
# Remove all matches
govctl remove WI-2026-01-17-001 refs "obsolete" --all
Listing Work Items
govctl list work
govctl list work queue # Pending items
govctl list work active # In progress
govctl list work done # Completed
Why TOML?
Like ADRs, work items use TOML for human-friendly editing with comments and clean multi-line strings.
Validation & Rendering
govctl provides tools to validate governance artifacts and render them to human-readable formats.
Validation
Check All Artifacts
govctl check
This validates:
- Schema conformance (all required fields present)
- Phase discipline (no invalid state transitions)
- Cross-references (refs point to existing artifacts)
- Clause structure (normative clauses in spec sections)
Check Specific Types
govctl check rfc
govctl check adr
govctl check work
Exit Codes
0— All validations passed1— Validation errors found
Rendering
Render governance artifacts to markdown for documentation.
Render RFCs
# All RFCs (committed to repo)
govctl render
# Specific RFC
govctl render --rfc-id RFC-0010
Output goes to docs/rfc/RFC-NNNN.md.
Render Other Artifacts
ADRs and work items render to .gitignored local files by default:
govctl render adr # → docs/adr/
govctl render work # → docs/work/
govctl render all # Everything
Hash Signatures
Rendered markdown includes a SHA-256 signature for tampering detection:
<!-- govctl:signature sha256:abc123... -->
If the source changes, the signature won’t match — indicating the rendered doc is stale.
Statistics
Get a summary of your governance state:
govctl stat
Shows:
- RFC counts by status and phase
- ADR counts by status
- Work item counts by status
- Any validation warnings
Building Documentation
For mdbook integration:
./scripts/build-book.sh # Build static site
./scripts/build-book.sh --serve # Live preview
This renders all artifacts and generates the book structure.
RFC-0000: govctl Governance Framework
Version: 1.0.0 | Status: normative | Phase: stable
1. Summary
[RFC-0000:C-SUMMARY] Framework Summary (Informative)
govctl is a governance CLI that manages four artifact types:
- RFCs: Normative specifications that define intent and constraints
- Clauses: Individual requirements within RFCs
- ADRs: Architectural Decision Records documenting design choices
- Work Items: Units of work tracking implementation progress
All artifacts follow explicit lifecycle states and phase gates to ensure disciplined development.
Since: v1.0.0
2. RFC Specification
[RFC-0000:C-RFC-DEF] RFC Definition (Normative)
An RFC (Request for Comments) is a normative document that defines intent, constraints, or decisions governing implementation.
An RFC is not a suggestion. It is law.
Every RFC MUST be stored as a JSON file (rfc.json) containing:
rfc_id: Unique identifier (e.g., RFC-0001)title: Human-readable titleversion: Semantic version (MAJOR.MINOR.PATCH)status: Lifecycle state (draft | normative | deprecated)phase: Work stage (spec | impl | test | stable)owners: List of responsible partiessections: Ordered list of sections with clause referenceschangelog: Version history
Since: v1.0.0
[RFC-0000:C-STATUS-LIFECYCLE] RFC Status Lifecycle (Normative)
RFC status follows this lifecycle:
draft → normative → deprecated
draft: Under discussion. Implementation MUST NOT depend on draft RFCs.
normative: Frozen and ratified. Implementation MUST conform to normative RFCs.
deprecated: Superseded or obsolete. Implementation SHOULD migrate away.
Transition rules:
- draft → normative: Requires explicit finalization
- normative → deprecated: Requires a superseding RFC or explicit deprecation
- Reverse transitions are FORBIDDEN
Since: v1.0.0
[RFC-0000:C-PHASE-LIFECYCLE] RFC Phase Lifecycle (Normative)
RFC phase follows this lifecycle:
spec → impl → test → stable
spec: Defining what will be built. No implementation work permitted.
impl: Building what was specified. Implementation proceeds per spec.
test: Verifying implementation matches specification.
stable: Released for production use.
Phase rules:
- Phases MUST proceed in order; skipping is FORBIDDEN
- Each phase transition requires the previous phase gate to pass
- draft + stable is FORBIDDEN (cannot stabilize unratified work)
- deprecated + impl/test is FORBIDDEN (no new work on deprecated specs)
Since: v1.0.0
3. Clause Specification
[RFC-0000:C-CLAUSE-DEF] Clause Definition (Normative)
A clause is an individual requirement or statement within an RFC.
Every clause MUST be stored as a JSON file containing:
clause_id: Unique identifier within the RFC (e.g., C-PHASE-ORDER)title: Human-readable titlekind: normative | informativestatus: active | superseded | deprecatedtext: The clause contentsince: Version when the clause was introduced
Clause kinds:
- normative: Defines a requirement. Implementations MUST comply.
- informative: Provides context. No compliance requirement.
Deprecation is a lifecycle state (in status), not a document kind.
Since: v1.0.0
4. ADR Specification
[RFC-0000:C-ADR-DEF] ADR Definition (Normative)
An ADR (Architectural Decision Record) documents a significant design decision.
Every ADR MUST be stored as a TOML file containing:
[govctl]section with: id, title, status, date, refs[content]section with: context, decision, consequences
ADR status lifecycle:
proposed → accepted → superseded
→ rejected
proposed: Under consideration. Not yet binding.
accepted: Ratified. Design SHOULD follow this decision.
rejected: Declined after consideration. Reason documented in decision field.
superseded: Replaced by a newer ADR. Listed in superseded_by field.
Since: v1.0.0
5. Work Item Specification
[RFC-0000:C-WORK-DEF] Work Item Definition (Normative)
A Work Item tracks a unit of work from inception to completion.
Every Work Item MUST be stored as a TOML file containing:
[govctl]section with: id, title, status, refs[content]section with: description, acceptance_criteria, decisions, notes
Work Item status lifecycle:
queue → active → done
↘ ↘ cancelled
queue: Planned but not started.
active: Currently in progress. Only one active item recommended per focus area.
done: Completed. All acceptance criteria met.
cancelled: Abandoned from queue or active. Reason documented in notes.
A Work Item MUST NOT transition to done if any acceptance_criteria are pending.
Since: v1.0.0
Changelog
v1.0.0 (2026-01-17)
Initial stable release of the govctl governance framework.
Added
- RFC specification with status and phase lifecycle
- Clause specification for normative and informative requirements
- ADR specification for architectural decisions
- Work Item specification for task tracking
RFC-0001: Lifecycle State Machines
Version: 0.1.0 | Status: normative | Phase: stable
1. Summary
[RFC-0001:C-SUMMARY] Summary (Informative)
This RFC defines the lifecycle state machines for all governed artifacts in govctl.
Each artifact type has a finite state machine that governs its lifecycle:
- RFC: status (draft/normative/deprecated) and phase (spec/impl/test/stable)
- Work Item: status (queue/active/done/cancelled)
- ADR: status (proposed/accepted/superseded)
- Clause: status (active/deprecated/superseded)
Key principles:
- State machines are acyclic (no going backward)
- Terminal states are final (done, cancelled, superseded, stable)
- Transitions may have gate conditions beyond state validity
- All transitions are explicit commands (no implicit state changes)
This specification documents what is already implemented in govctl v0.1.0.
Since: v0.1.0
2. Specification
[RFC-0001:C-RFC-STATUS] RFC Status Transitions (Normative)
An RFC MUST have exactly one of the following status values:
- draft — Initial state. The RFC is under development and not yet binding.
- normative — The RFC defines required behavior. Implementations MUST conform.
- deprecated — The RFC is no longer recommended. Existing conforming implementations MAY continue, but new implementations SHOULD NOT use this RFC.
Valid transitions:
- draft → normative (via
finalizecommand) - normative → deprecated (via
deprecatecommand)
Invalid transitions (MUST be rejected):
- normative → draft (no “un-finalize”)
- deprecated → normative (no resurrection)
- deprecated → draft (no resurrection)
- Any skip (e.g., draft → deprecated directly)
Since: v0.1.0
[RFC-0001:C-RFC-PHASE] RFC Phase Transitions (Normative)
An RFC MUST have exactly one of the following phase values:
- spec — Specification phase. The RFC text is being written. No implementation work.
- impl — Implementation phase. Code is being written to conform to the RFC.
- test — Testing phase. Implementation is complete; tests are being written and validated.
- stable — Stable phase. Implementation and tests are complete. No further changes expected.
Valid transitions (forward only, via advance command):
- spec → impl
- impl → test
- test → stable
Invalid transitions (MUST be rejected):
- Any backward transition (e.g., impl → spec)
- Any skip (e.g., spec → test, spec → stable)
- stable → any (stable is terminal for phase)
Rationale: Phase discipline ensures specification precedes implementation, and testing validates implementation before stabilization.
Since: v0.1.0
[RFC-0001:C-WORK-STATUS] Work Item Status Transitions (Normative)
A Work Item MUST have exactly one of the following status values:
- queue — Initial state. The work item is defined but not yet started.
- active — The work item is currently being worked on.
- done — The work item is complete. All acceptance criteria are satisfied.
- cancelled — The work item was abandoned. No further work will be done.
Valid transitions (via move command):
- queue → active (start work)
- queue → cancelled (abandon before starting)
- active → done (complete work)
- active → cancelled (abandon in progress)
Invalid transitions (MUST be rejected):
- done → any (done is terminal)
- cancelled → any (cancelled is terminal)
- queue → done (cannot complete without being active)
- active → queue (no “un-start”)
Timestamp behavior:
- queue → active: Sets
starteddate if not already set - active → done: Sets
completeddate - active → cancelled: Sets
completeddate
Since: v0.1.0
[RFC-0001:C-ADR-STATUS] ADR Status Transitions (Normative)
An ADR MUST have exactly one of the following status values:
- proposed — Initial state. The decision is under consideration.
- accepted — The decision has been accepted and is in effect.
- superseded — The decision has been replaced by another ADR.
Valid transitions:
- proposed → accepted (via
acceptcommand) - accepted → superseded (via
supersedecommand, requires--byto specify replacement)
Invalid transitions (MUST be rejected):
- proposed → superseded (cannot supersede without first accepting)
- accepted → proposed (no “un-accept”)
- superseded → any (superseded is terminal)
When an ADR is superseded:
- The
superseded_byfield MUST be set to the ID of the replacing ADR - The replacing ADR SHOULD reference the superseded ADR
Since: v0.1.0
[RFC-0001:C-CLAUSE-STATUS] Clause Status Transitions (Normative)
A Clause MUST have exactly one of the following status values:
- active — Default state. The clause is in effect.
- deprecated — The clause is no longer recommended but still valid.
- superseded — The clause has been replaced by another clause.
Valid transitions:
- active → deprecated (via
deprecatecommand) - active → superseded (via
supersedecommand, requires replacement clause) - deprecated → superseded (already deprecated, now replaced)
Invalid transitions (MUST be rejected):
- deprecated → active (no resurrection)
- superseded → any (superseded is terminal)
When a clause is superseded:
- The
superseded_byfield MUST be set to the ID of the replacing clause - The replacing clause SHOULD have a
sincefield indicating the version it was introduced
Since: v0.1.0
[RFC-0001:C-GATE-CONDITIONS] Transition Gate Conditions (Normative)
Certain transitions have additional gate conditions beyond the state machine rules.
Work Item → done:
- The work item MUST have at least one acceptance criterion defined
- All acceptance criteria MUST have status “done” or “cancelled” (no “pending”)
Rationale: Prevents marking work as complete without defined success criteria.
RFC draft → normative:
- No additional gates (policy decision, not structural)
RFC phase spec → impl:
- RFC status SHOULD be normative (warning if draft)
Rationale: Implementation should follow finalized specification.
RFC phase impl → test:
- No additional gates
RFC phase test → stable:
- No additional gates (assumes tests are passing externally)
Future gates MAY be added via RFC amendment, but MUST NOT break existing valid workflows.
Since: v0.1.0
Changelog
v0.1.0 (2026-01-17)
Initial draft
ADR-0001: Use TOML for ADRs and Work Items
Status: accepted | Date: 2026-01-17
References: RFC-0000:C-ADR-DEF, RFC-0000:C-WORK-DEF
Context
ADRs and Work Items need a human-readable, machine-parseable format. JSON is verbose and hard to edit manually. YAML has implicit typing issues. TOML provides explicit typing, clean multiline strings, and good tooling support.
Decision
Use TOML for ADRs and Work Items instead of JSON. Structure follows [govctl] metadata section and [content] body section. This aligns with Rust ecosystem conventions (Cargo.toml).
Consequences
Positive: Easier manual editing, cleaner diffs, natural multiline support. Negative: Different format from RFC clauses (which remain JSON for richer structure). Migration: Existing JSON-based work items would need conversion.
ADR-0002: Fix artifact lifecycle design flaws
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
Analysis of the artifact lifecycle state machines revealed several design flaws:
-
Clause
kindvsstatusduplication: Thekindenum includesdeprecatedalongsidenormativeandinformative, butstatusalso hasdeprecated. This creates confusion about where deprecation state belongs. -
ADR missing
rejectedstate: The ADR lifecycle isproposed → accepted → superseded. If a proposal is rejected rather than accepted, there is no state to record this outcome. The alternative is leaving it asproposedforever or deleting it, both of which lose information. -
Work Item forced activation before cancellation: The lifecycle
queue → active → done|cancelledimplies you must start work before abandoning it. This is illogical - planned work can be abandoned before starting. -
RFC status×phase constraint rules undocumented: The 3×4 matrix of valid/invalid status×phase combinations exists implicitly but is not formally documented in SCHEMA.md.
Decision
We will fix all four lifecycle design flaws:
-
Remove
deprecatedfrom Clausekind: Thekindfield should only contain semantic categories (normative,informative). Deprecation is a lifecycle state that belongs instatus. -
Add
rejectedto ADR lifecycle: The new lifecycle becomes:proposed → accepted → superseded → rejectedThis allows recording when a proposal was considered but declined.
-
Allow Work Item
queue → cancelled: The new lifecycle becomes:queue → active → done ↘ ↘ cancelledWork can be abandoned at any stage.
-
Document RFC constraint rules: Add explicit invariant rules to SCHEMA.md stating when status×phase combinations are forbidden.
Consequences
Positive:
- Cleaner separation of concerns (kind = category, status = lifecycle)
- Complete lifecycle coverage for all artifact types
- Explicit rules prevent confusion about valid state combinations
Negative:
- Existing tools validating
kind: deprecatedwill need updating - Schema version bump required for breaking changes
Migration:
- Any clause with
kind: deprecatedshould change tokind: normative, status: deprecated - Currently no such clauses exist in the codebase
ADR-0003: Deterministic hash signatures for rendered projections
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
govctl renders markdown files from authoritative JSON/TOML sources (RFCs, ADRs, Work Items). These rendered markdown files are projections — read-only views intended for human consumption.
Problem: Without a mechanism to detect tampering, someone could edit docs/rfc/RFC-0000.md directly. This edit would:
- Be overwritten on next
govctl render - Create confusion about which version is authoritative
- Violate the Single Source of Truth (SSOT) principle
We need a mechanism to:
- Mark rendered files as generated (not authoritative)
- Detect when a rendered file has been edited directly
- Ensure verification is deterministic (same source always produces same hash)
Decision
Implement deterministic hash signatures embedded in rendered markdown.
Signature Format:
<!-- GENERATED: do not edit. Source: RFC-0000 -->
<!-- SIGNATURE: sha256:<64-hex-chars> -->
Hash Computation:
- Collect all source JSON content (RFC metadata + clauses, or ADR/Work Item TOML)
- Canonicalize JSON/TOML: sort object keys recursively, normalize whitespace
- For RFCs: sort clauses by
clause_idbefore hashing - Compute SHA-256 of the canonical representation
- Include a signature version prefix for future-proofing
Determinism Requirements:
- Object keys sorted alphabetically at all nesting levels
- Arrays preserve order (only objects get key-sorted)
- Consistent string escaping and number formatting
- No dependency on file modification times or filesystem order
Verification:
govctl checkextracts signature from rendered markdown- Recomputes hash from current source files
- Reports mismatch as a diagnostic error
Consequences
Positive:
- Enforces “edit the source, not the projection” discipline
- Tampered markdown is detected automatically by
govctl check - Deterministic hashes enable reproducible builds
- Clear provenance: every rendered file traces back to its source
Negative:
- Existing rendered markdown will fail verification until re-rendered
- Minor source reformatting (whitespace) changes the hash
- Adds complexity to the render pipeline
Migration:
- Run
govctl renderto regenerate all markdown with signatures - Commit the updated files
ADR-0004: Adopt Keep a Changelog format for RFC changelogs
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
RFC changelogs use a flat changes array. This makes it difficult to categorize changes by type (additions, fixes, removals). The Keep a Changelog format (keepachangelog.com) is a widely-adopted standard that organizes changes into semantic categories aligned with semver.
Decision
Replace the flat changes array with categorized arrays: added, changed, deprecated, removed, fixed, security. Keep summary field as optional notes. Migrate existing RFC-0000 changelog (trivial: one entry).
Consequences
Positive: Standard format, better scanability, semver-aligned categories. Negative: More verbose schema, breaking change to ChangelogEntry model. Migration cost is minimal (RFC-0000 has only one entry).
ADR-0005: CLI output color scheme and formatting
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
CLI output uses plain text with no visual hierarchy. Users cannot quickly distinguish success from failure, or identify important values. Status messages blend together making output hard to scan.
Decision
Adopt semantic color scheme: Green for success, Red for errors, Yellow for warnings, Cyan for paths/IDs, Bold for emphasis. Use owo-colors crate (zero-cost, no deps). Auto-detect terminal color support. All output via ui module for consistency.
Consequences
Positive: Better UX, faster scanning, clearer status. Negative: One new dependency (owo-colors). Migration: All eprintln! calls routed through ui module.
ADR-0006: Global dry-run support for content-modifying commands
Status: accepted | Date: 2026-01-17
References: RFC-0000:C-WORK-DEF
Context
All content-modifying commands (new, set, add, remove, edit, tick, bump, finalize, advance, accept, deprecate, supersede, move) write files immediately with no way to preview changes. Only render commands support –dry-run. Users and agents need a way to preview what changes will be made before committing to disk, especially for destructive or complex operations.
Decision
Add global -n/–dry-run flag at CLI level. Create WriteOp enum with Preview/Execute variants in write.rs. All write functions accept WriteOp. In Preview mode: serialize, display via ui::dry_run_preview, skip fs::write. Read-only commands ignore the flag.
Consequences
Positive: Unified dry-run UX, follows Unix -n convention, DRY write logic. Negative: Signature changes for write functions. Migration: Update all write callsites to use WriteOp.
ADR-0007: Ergonomic array field matching for remove and tick commands
Status: accepted | Date: 2026-01-17
References: RFC-0000:C-WORK-DEF, RFC-0000:C-ADR-DEF
Context
The remove command requires exact string match, which is fragile for long strings like URLs. The tick command uses substring matching but remove does not. Checklist fields (acceptance_criteria, decisions, alternatives) require separate semantics from string fields, leading to confusion about when to use remove vs tick.
Decision
Unify matching semantics: (1) Default to case-insensitive substring matching for remove and tick. (2) Add –exact flag for exact matching. (3) Add --at <index> for positional removal. (4) Add –regex flag for pattern matching. (5) Add –all flag for bulk removal. (6) Single match proceeds; multiple matches error with guidance. (7) remove works on all array types including checklists; tick only changes status.
Consequences
Positive: Ergonomic default matching, safe bulk operations, unified semantics. Negative: Breaking change for scripts relying on exact match. Migration: Existing exact-match callers should add –exact flag.
ADR-0008: Add refs field to RfcSpec for artifact cross-referencing
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
RFCs are the supreme governance documents in govctl, yet they cannot formally reference other artifacts (ADRs, other RFCs, work items). Meanwhile, ADRs and Work Items both have a refs field for cross-referencing.
This asymmetry creates problems:
- RFCs cannot declare dependencies on ADRs that informed their design
- No way to trace which ADRs led to an RFC’s creation
- Validation cannot check RFC references for consistency
- Impact analysis for deprecation is incomplete
The existing pattern in AdrMeta and WorkItemMeta is: refs: Vec<String> with validation against known artifact IDs.
Decision
Add refs field to RfcSpec following the same pattern as AdrMeta and WorkItemMeta:
- Add
refs: Vec<String>to RfcSpec model (serde skip_serializing_if empty) - Add diagnostic code E0105RfcRefNotFound for validation errors
- Extend validate_artifact_refs() to include RFC refs validation
- Support add/remove/get refs operations in edit commands for RFCs
- Validate RFC supersedes field against known RFCs (currently unvalidated)
This creates consistency across all artifact types and enables complete cross-reference tracking.
Consequences
Positive:
- RFCs can now reference ADRs, other RFCs, and work items
- Complete artifact graph for impact analysis
- Consistent API across all artifact types
- Existing RFCs remain valid (refs is optional, defaults to empty)
Negative:
- Minor schema change to RfcSpec
- Slightly more validation overhead on check
Neutral:
- Existing RFCs do not need migration (empty default)
ADR-0009: Configurable source code reference scanning
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
Source code often contains references to governance artifacts (RFCs, clauses, ADRs) in comments. These references can become stale when artifacts are deprecated, superseded, or renamed.
Currently govctl validates internal artifact references (refs fields) but has no mechanism to detect broken references in source code comments. This creates a gap where documentation in code can drift from the actual governance state.
neotex-spec implements this via a hardcoded comment scanning pattern, but govctl needs a generalized solution with configurable patterns to work across different projects and conventions.
Decision
Add configurable source code scanning with:
-
New [source_scan] config section with:
- enabled: bool (default false)
roots: Vec<PathBuf>(directories to scan)exts: Vec<String>(file extensions to include)- pattern: String (regex with capture group for artifact ID)
-
Default pattern matches RFC-0001:C-NAME and ADR-0001 style references
-
Scanner walks configured directories, applies pattern, validates extracted IDs against ProjectIndex
-
New diagnostics: E0107SourceRefUnknown (error), W0107SourceRefOutdated (warning for deprecated/superseded)
-
Scanner runs during ‘govctl check’ when source_scan.enabled = true
Consequences
Positive:
- Dead link detection in source code comments
- Configurable pattern supports different project conventions
- Disabled by default - opt-in for projects that want it
- Catches outdated references to deprecated/superseded artifacts
Negative:
- Adds walkdir dependency
- Additional check time when scanning large codebases
Neutral:
- Pattern configuration requires regex knowledge
- Projects must explicitly enable and configure
ADR-0010: Validate work item descriptions for placeholder content
Status: accepted | Date: 2026-01-17
References: RFC-0000:C-WORK-DEF
Context
Work items are created with a placeholder description template: “Describe the work to be done. What is the goal? What are the acceptance criteria?” This placeholder is meant to be replaced with actual content, but 21 of 24 existing work items still have this placeholder text.
Empty or placeholder descriptions provide no value for audit trails, make it hard to understand what was actually done, and defeat the purpose of structured governance.
Decision
Add a warning diagnostic (W0106) for work items with placeholder or empty descriptions.
Detection patterns:
- Description matches the exact template text
- Description is empty or whitespace-only
- Description contains only generic phrases like “TODO”, “TBD”, “Fill in later”
This is a warning (not error) because:
- Existing work items should not block
govctl check - It’s advisory during development, not a hard gate
- Users can address warnings incrementally
Consequences
Positive:
- Encourages meaningful documentation of completed work
- Improves audit trail quality
- Catches forgotten placeholders before they become permanent
Negative:
- Existing 21 work items will trigger warnings until fixed
- Minor noise during
govctl checkuntil addressed
Migration: Fix existing work items by adding meaningful descriptions based on their titles and acceptance criteria.
ADR-0011: Inline reference expansion in rendered content
Status: accepted | Date: 2026-01-17
References: RFC-0000
Context
Content fields (description, context, decision, consequences) are rendered as-is with no link expansion. The refs field gets expanded to markdown links, but inline references like [RFC-0000](../rfc/RFC-0000.md) in text remain as literal strings.
This creates an inconsistency:
- The
source_scanfeature uses[[artifact-id]]pattern to detect references in source code - Users might expect the same pattern to work in content fields
- Without expansion, content authors must write full markdown links manually
The source_scan config already defines a customizable pattern field for reference format.
Decision
Add inline reference expansion to content fields during rendering:
- Use the same pattern from
source_scan.patternconfig (defaults to[[RFC-NNNN]]format) - Expand matched references using existing
ref_link()function - Apply to: description, context, decision, consequences, notes, acceptance_criteria text
- Pattern is evaluated at render time, so config changes apply on next render
This creates consistency between source code scanning and content rendering — the same reference format works everywhere.
Consequences
Positive:
- Inline references in content become clickable links
- Consistent with
source_scanpattern format - No new config needed (reuses
source_scan.pattern) - Works with custom patterns if configured
Negative:
- Couples rendering to source_scan config (even if source_scan.enabled is false)
- Literal
[[text]]in content will be matched if it looks like an artifact ID
Migration: Existing content with literal [[...]] that happens to match artifact patterns will now become links. This is likely the desired behavior.
ADR-0012: Prefix-based changelog category parsing
Status: accepted | Date: 2026-01-17
References: ADR-0013
Context
The govctl bump command supports adding changelog entries via -c flags, but all changes are hardcoded to the added category. The ChangelogEntry model supports 6 categories (added, changed, deprecated, removed, fixed, security) per Keep a Changelog format, but users must manually edit JSON to use any category other than added.
Decision
Parse conventional-commit-style prefixes from change strings to route to the correct changelog category. Supported prefixes: add:, fix:, changed:, deprecated:, removed:, security:. Unknown prefixes produce a validation error. No prefix defaults to added for backward compatibility.
Example: govctl bump RFC-0001 --patch -m "Bug fixes" -c "fix: memory leak" -c "security: patched CVE"
Consequences
Users can populate all changelog categories via CLI without JSON editing. The prefix syntax follows conventional commits, reducing learning curve. Invalid prefixes are caught early with helpful error messages listing valid options.
ADR-0013: Add category field to acceptance criteria for changelog generation
Status: accepted | Date: 2026-01-17
References: ADR-0012
Context
Work items track implementation work (features, fixes, refactoring), but lack categorization that maps to Keep a Changelog format. RFC changelog entries already use Keep a Changelog categories (Added, Changed, Deprecated, Removed, Fixed, Security). To generate a repo-level CHANGELOG.md from completed work items, we need the same categorization. Acceptance criteria are the natural atomic unit for changelog entries - each criterion represents one deliverable.
Decision
Add a category field to ChecklistItem (acceptance criteria) using the existing ChangelogCategory enum (added, changed, deprecated, removed, fixed, security). Default to added for backward compatibility. Reuse ADR-0012 prefix parsing: govctl add WI-xxx acceptance_criteria "fix: memory leak" parses to category=fixed, text="memory leak". This consolidates ChangelogCategory from write.rs into model.rs for reuse across RFC changelogs and work item criteria.
Consequences
Acceptance criteria can be grouped by category when rendering CHANGELOG.md. Each criterion becomes one changelog entry. Work items can span multiple categories without being split. Existing work items remain valid (criteria default to added). Single ChangelogCategory enum used for both RFC changelog entries and work item criteria.
Alternatives Considered
Add category field to WorkItemMeta (work-item level)- Add category field to ChecklistItem (criterion level) with prefix parsing
ADR-0014: Release management with releases.toml
Status: accepted | Date: 2026-01-17
References: ADR-0013, RFC-0000:C-WORK-DEF
Context
To generate a CHANGELOG.md from work items, we need version information. Work items have completed dates but no version. Version is a release-time concept, not a work-time concept. We need a way to track which work items belong to which release without mutating completed work items.
Decision
Store release history in a single gov/releases.toml file with explicit work item references:
[[releases]]
version = "0.2.0"
date = "2026-01-17"
refs = ["WI-2026-01-17-029", "WI-2026-01-17-008"]
The govctl release <version> command collects all done work items not yet in any release and adds them to a new release entry. The govctl render changelog command generates CHANGELOG.md grouped by release version and category.
Consequences
Completed work items remain immutable. Explicit refs list eliminates ambiguity about release membership. Single file is simpler than per-release artifacts. Unreleased work items appear under [Unreleased] section in changelog.
Alternatives Considered
Add version field to work items after release- Store releases in single
gov/releases.tomlwith explicit refs
ADR-0015: Context-aware self-describing CLI for agent discoverability
Status: accepted | Date: 2026-01-18
References: RFC-0000
Context
AI coding agents (Claude, Cursor, Codex, etc.) can invoke shell commands, making govctl immediately usable. However, agents lack semantic understanding of when to use which command and why.
User feedback: “I need to tell the agent in my prompt what this tool is and when to run it.”
Current solutions:
- MCP (Model Context Protocol) — adds structured tool definitions, but requires server setup, process management, and creates a parallel interface to maintain
- Agent guide files (
.claude/CLAUDE.md) — static, requires manual updates, doesn’t reflect current project state --helpoutput — describes syntax, not semantics or workflow context
The core problem: discovery and context-awareness, not invocation. Agents need to understand govctl’s philosophy, command purposes, and what actions are relevant given current project state.
Decision
Add a govctl describe command with two modes:
1. Static mode (default):
govctl describe --json
Outputs machine-readable JSON containing:
version: govctl versionpurpose: one-line description of govctl’s rolephilosophy: core principles (RFC supremacy, phase discipline)commands[]: for each command:name: command name (e.g., “new rfc”, “advance”)purpose: what it doeswhen_to_use: semantic guidance on when to invokeexample: concrete usageprerequisites: what must be true before running
workflow: typical command sequence for common tasks
2. Context-aware mode:
govctl describe --context --json
Reads current project state and outputs:
project_state: current RFCs, ADRs, work items with their statuses/phasessuggested_actions[]: contextually relevant commands with reasons- Example: “RFC-0001 is in impl phase. If implementation complete, run
govctl advance RFC-0001 test”
- Example: “RFC-0001 is in impl phase. If implementation complete, run
warnings[]: governance issues detected (stale items, blocked transitions)
Implementation:
- Command metadata derived from existing clap
#[command(about = "...")]attributes where possible - Semantic guidance (
when_to_use) defined as static data - Context mode reuses
statusandlistlogic for project state - Output format follows JSON Schema for predictable parsing
Consequences
Positive:
- Agents gain semantic understanding without MCP complexity
- Single interface (CLI) — no parallel implementation to maintain
- Context-aware mode reduces agent trial-and-error
- Works with any shell-capable agent (not limited to MCP-compatible tools)
- Self-documenting:
govctl describeoutput stays in sync with actual commands - Distribution unchanged:
cargo install govctlis all users need
Negative:
- Additional ~200-300 lines of code for command metadata and describe logic
- Semantic guidance (
when_to_use) must be manually authored and maintained - JSON output format becomes a compatibility surface (changes need care)
Neutral:
- Agents must call
govctl describeonce per session (cacheable) - Plain
--helpremains available for human users - Does not preclude future MCP integration if demand materializes
Comparison to MCP:
| Aspect | govctl describe | MCP |
|---|---|---|
| Distribution | cargo install govctl | Server config + process mgmt |
| Agent compatibility | Any shell-capable agent | MCP-compatible agents only |
| Maintenance | Single codebase | CLI + MCP server |
| Context awareness | Built-in | Separate implementation |
| Works offline | Yes | Depends |