Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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.toml + clauses/*.toml
├── adr/                  # ADR-NNNN-*.toml
├── work/                 # WI-YYYY-MM-DD-NNN-*.toml
├── guard/                # GUARD-*.toml verification guards
└── releases.toml         # Release history

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

  1. Read RFC-0000 to understand the governance model
  2. Follow the Getting Started guide to install and initialize
  3. Read the Recommended Workflows guide to choose the right path for each change
  4. 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.96+ (per Cargo.toml rust-version)

Installation

# From crates.io (includes TUI by default)
cargo install govctl

# Without TUI
cargo install govctl --no-default-features

# Or build from source
git clone https://github.com/govctl-org/govctl
cd govctl
cargo build --release
# Binary at ./target/release/govctl

Features

FeatureDefaultDescriptionDependencies
tuiYesInteractive terminal dashboard (govctl tui)ratatui, crossterm

Shell Completion

Generate completion scripts for your shell:

# Bash
govctl completions bash > ~/.local/share/bash-completion/completions/govctl

# Zsh (add to your .zshrc or install to completion directory)
govctl completions zsh > ~/.zsh/completions/_govctl
# Then add to fpath: fpath=(~/.zsh/completions $fpath)

# Fish
govctl completions fish > ~/.config/fish/completions/govctl.fish

# PowerShell (add to your profile)
govctl completions powershell >> $PROFILE

Restart your shell or source the configuration to enable tab completion.

Initialize a Project

govctl init

This creates the governance directory structure:

gov/
├── config.toml       # Configuration (project name, schema version, guards)
├── rfc/              # RFC sources (TOML)
├── adr/              # ADR sources (TOML)
├── work/             # Work item sources (TOML)
├── guard/            # Verification guards (TOML)
├── schema/           # JSON schemas for validation
└── releases.toml     # Release history

All governance artifacts use TOML with #:schema comment headers for IDE discoverability:

#:schema ../schema/adr.schema.json

[govctl]
id = "ADR-0001"
title = "My Decision"
status = "proposed"
...

Create Your First RFC

govctl rfc new "Feature Title"

This creates gov/rfc/RFC-0000/rfc.toml with the RFC metadata.

Add a Clause

RFCs are composed of clauses — atomic units of specification:

govctl clause new RFC-0000:C-SCOPE "Scope" -s "Specification" -k normative

Edit Clause Content

govctl clause edit RFC-0000:C-SCOPE text --stdin <<'EOF'
The feature MUST do X.
The feature SHOULD do Y.
EOF

View Artifacts

# Styled markdown to stdout
govctl rfc show RFC-0000
govctl adr show ADR-0001
govctl work show WI-2026-01-17-001
govctl clause show RFC-0000:C-SCOPE

# Interactive TUI dashboard
govctl tui

Search Artifacts

Search looks across RFCs, clauses, ADRs, work items, and verification guards:

govctl search cache
govctl search "schema migration" --type rfc --type adr
govctl search RFC-0002 --output json
govctl search cli --tag validation -n 5
govctl search loop --reindex

Search keeps any persisted index under .govctl/ as disposable local state. Artifacts under gov/ remain authoritative; --reindex forces a rebuild before returning results.

Validate Everything

govctl check

This validates all governance artifacts against JSON schemas, phase rules, cross-references, and source code annotations.

Before using govctl on non-trivial work, read the Recommended Workflows guide. It explains when to use RFCs, ADRs, Work Items, execution loops, reviewer agents, and verification guards together.

Render to Markdown

govctl render

Generates human-readable markdown in docs/.

Interactive TUI

govctl includes an optional read-only terminal cockpit:

govctl tui

The cockpit is for human inspection: overview, artifact lists, search, loop state and dependency DAGs, guards, releases, tags, and check diagnostics. State-changing operations remain CLI commands.

TUI Keyboard Shortcuts

KeyAction
1 / rRFC list
2 / cClause list
3 / aADR list
4 / wWork item list
5 / gGuard list
6 / sSearch view
7 / lLoop list and loop DAG inspector
8 / dDiagnostics view
9Release list
tTag list
j / Navigate down
k / Navigate up
EnterOpen selected detail or search result
EscGo back or leave input mode
/Filter lists; edit query in search view
eEdit query in search view
n / pNext/previous filtered match
g / GJump to top/bottom in lists
Ctrl+d / uScroll half page in detail views
PageDown / PageUpScroll page in detail views
?Toggle help overlay
qQuit

Cutting a Release

When a set of work items is complete and ready for release:

# Collect all unreleased done work items into a version
govctl release 0.2.0

# Specify a custom date
govctl release 0.2.0 --date 2026-04-15

This records the release in gov/releases.toml and makes those work items available for changelog generation.

Adopting govctl in an Existing Project

govctl init is safe to run in existing repositories — it only creates the gov/ directory structure alongside existing files.

For AI-assisted migration, use the /migrate skill to systematically discover undocumented decisions, backfill ADRs, and annotate source code with [[...]] references.

govctl migrate vs the /migrate Skill

govctl migrate/migrate skill
WhatUpgrade existing govctl artifacts to current formatAdopt govctl in an existing project
WhenAfter updating govctl versionWhen starting governance in a brownfield repo
EffectRewrites TOML files in gov/ and syncs schemasDiscovers decisions, backfills ADRs, annotates source
RiskLow — transactional, reversibleMedium — requires human review of generated ADRs

Run govctl migrate when govctl reports an outdated schema version. If a repository still contains legacy RFC or clause JSON storage, migrate it with govctl <0.9 before upgrading. Use the /migrate skill when bringing a legacy project under governance for the first time.

Canonical Edit Surface

All artifact fields are accessible through a unified path-based edit interface:

# Set a scalar value
govctl rfc edit RFC-0010 version --set 1.2.0

# Add to an array
govctl adr edit ADR-0003 refs --add RFC-0010

# Remove by index
govctl work edit WI-2026-01-17-001 content.acceptance_criteria[0] --remove

# Tick checklist items
govctl adr edit ADR-0003 content.alternatives[0] --tick accepted
govctl work edit WI-2026-01-17-001 content.acceptance_criteria[0] --tick done

Nested object fields use dot-delimited paths:

govctl adr edit ADR-0003 content.decision --set "We will use Redis"
govctl adr edit ADR-0003 "content.alternatives[0].pros" --add "Low latency"
govctl work edit WI-2026-01-17-001 "content.acceptance_criteria[0].category" --set fixed

CLI Self-Description

govctl provides a machine-readable command catalog:

govctl describe
govctl describe --context   # Includes project context
govctl describe --output json

This is designed for agent discoverability — agents can inspect available commands and their semantics without hardcoded knowledge.

Next Steps

Recommended Workflows

govctl is a governance tool, not a single enforced process. The recommended workflow is upstream-first: clarify requirements before design, design before execution, and execution before release.

Use this page as the default operating model when you are working with an AI agent or coordinating changes across a team.

The Default Path

For non-trivial product work, prefer:

RFC -> ADR -> Work Item -> Code -> Verification -> Release

Each layer has a different job:

ArtifactRoleGood contentBad content
RFCDefines obligationsBehavior, interfaces, lifecycle rules, compatibility, validation semanticsPrivate module layout, helper names, current implementation plan
ADRExplains decisionsAlternatives, trade-offs, chosen approach, consequencesNew product requirements, task checklists, progress logs
Work ItemTracks executionTask scope, acceptance criteria, dependencies, durable notesNormative behavior, design rationale, transient progress
LoopCoordinates local executionRound evidence, blockers, changed paths, next local actionProduct requirements, durable design decisions

When in doubt, ask what the text is trying to do:

  • “What must be true?” belongs in an RFC.
  • “Why this option?” belongs in an ADR.
  • “What are we doing in this task?” belongs in a Work Item.
  • “What happened in this round?” belongs in loop state or the final response.

Small Changes

Not every change needs every artifact.

Use the smallest path that still leaves a useful record:

ChangeTypical path
Typo, comment, small docs fixEdit directly, run govctl check
Bug fix for already specified behaviorWork Item -> Code -> Verification
New user-visible behaviorRFC -> ADR if needed -> Work Item -> Code
New architecture or trade-offADR -> Work Item -> Code
Deprecation or removalRFC amendment -> Work Item -> Code
Mechanical cleanupNo Work Item, or one coarse Work Item if the outcome is durable

Do not create work items for helper extraction, file moves, fixture sharing, formatting, or other low-level steps whose durable record is the diff.

Discovery And Drafting

Use /discuss when the problem is still unclear. Good /discuss output is a draft RFC, a proposed ADR, or a decision that no new artifact is needed.

During discovery:

  • Keep RFCs focused on externally relevant obligations.
  • Keep ADRs focused on trade-offs and decisions.
  • Do not start implementation while the governing RFC is still ambiguous.
  • Use reviewer agents before treating RFC or ADR drafts as settled.

RFC and ADR drafting should remain human-in-the-loop. Agents can produce strong drafts, but semantic review is still necessary because govctl check validates structure, not judgment.

Upstream-First Refinement

RFCs and ADRs may change as you learn. The important rule is direction:

Update upstream artifacts first, then implement downstream work.

If implementation reveals that a requirement is wrong, incomplete, or ambiguous, do not silently make the code diverge. Amend the RFC or ADR first, then continue the Work Item.

Avoid the reverse pattern:

Code first -> patch RFC/ADR afterward to match what happened

That pattern turns governance into a log of implementation choices instead of a source of authority.

Work Item Execution

Use Work Items for non-trivial implementation even when no new RFC or ADR is needed. A good Work Item says what will be completed and how closure is checked.

Before implementation:

govctl work new --active "Implement stale search index refresh"
govctl work add WI-YYYY-MM-DD-NNN refs RFC-0002
govctl work add WI-YYYY-MM-DD-NNN acceptance_criteria "changed: Search refreshes stale derived indexes before querying"
govctl work add WI-YYYY-MM-DD-NNN acceptance_criteria "chore: govctl check passes"
govctl check --has-active

During execution:

  • Tick acceptance criteria as they become true.
  • Add notes only for durable constraints or retry rules.
  • Do not put progress updates, command output, review status, next actions, or temporary blockers in notes.

After execution:

govctl work tick WI-YYYY-MM-DD-NNN acceptance_criteria "Search refreshes" -s done
govctl work tick WI-YYYY-MM-DD-NNN acceptance_criteria "govctl check passes" -s done
govctl work move WI-YYYY-MM-DD-NNN done

Moving to done runs verification guards when verification is enabled.

When To Use Loops

Use a loop when non-trivial execution needs resumable local round evidence, including single-Work-Item work.

Good loop use cases:

  • A batch has multiple independently meaningful Work Items.
  • Work Items have depends_on edges and need ready-item planning.
  • You expect several implementation/review/verification rounds.
  • You need local evidence for changed paths, blockers, note candidates, or validation results without polluting Work Item fields.

Do not use a loop to justify over-splitting one task into mechanical Work Items. Do not create a separate loop for every tiny cleanup.

Typical loop flow:

govctl loop list open
govctl loop start WI-YYYY-MM-DD-001 WI-YYYY-MM-DD-002
govctl loop run LOOP-YYYY-MM-DD-NNN
# implement, verify, and fill the opened round evidence
govctl loop run LOOP-YYYY-MM-DD-NNN

Important boundaries:

  • loop run advances local round state only.
  • It does not implement code.
  • It does not tick acceptance criteria.
  • It does not add Work Item notes.
  • It does not move Work Items to done.

If batch scope changes, keep the same loop identity:

govctl loop add LOOP-YYYY-MM-DD-NNN work WI-YYYY-MM-DD-003
govctl loop remove LOOP-YYYY-MM-DD-NNN work WI-YYYY-MM-DD-002
govctl loop replan LOOP-YYYY-MM-DD-NNN

If loop show or loop list reports a stale plan, the current Work Item dependency closure differs from the stored loop plan. Run govctl loop replan LOOP-YYYY-MM-DD-NNN before opening another round.

Loop state is local execution memory under .govctl/loops/. Work Items remain the durable task record.

Agent Goals And Loops

Some agent runtimes provide session-level goal features, such as /goal. These work well with batched Work Items in a loop when the boundaries stay clear:

LayerRole
Work ItemDurable outcome and acceptance criteria
LoopBatch coordination, ready-work planning, and round evidence
Agent goalCurrent session focus, budget, and resume target

For a batched loop, set the agent goal to the current loop or round instead of duplicating the Work Item list:

Goal: Complete the current round for LOOP-YYYY-MM-DD-NNN.

That goal gives the agent a narrow execution target while the loop remains the source of truth for ready Work Items, blockers, changed paths, validation evidence, and note candidates.

Use a simpler goal for simple work:

  • For one small Work Item, a goal may point directly at that Work Item.
  • For a multi-Work-Item batch, prefer one goal for the active loop or current round.
  • Do not create one goal per mechanical substep.

Do not store agent goals in RFCs, ADRs, or Work Item notes. Goals are runtime focus. Loop state is local execution memory. Work Items are the durable task record.

Review And Verification

Use both structural and semantic checks:

govctl check
govctl verify

govctl check validates schemas, references, lifecycle rules, tags, source annotations, and other deterministic constraints. It does not decide whether an RFC is too implementation-specific or whether an ADR is intellectually honest.

Use reviewer agents for semantic checks:

  • rfc-reviewer catches vague requirements and implementation details inside RFCs.
  • adr-reviewer catches missing alternatives, dishonest consequences, and ADRs that invent requirements.
  • wi-reviewer catches vague criteria, transient notes, local requirements, and over-split Work Items.
  • compliance-checker audits implementation against normative RFC clauses and accepted ADR decisions.

Treat reviewer findings as design feedback, not just formatting feedback.

Project-Specific Guards

Domain projects often need extra checks. For example:

  • Requirement ID tracing from RFC clauses to tests and source comments.
  • Generated-code or assembler inspection for low-level performance work.
  • Protocol conformance suites.
  • Language-specific lint or style checks.

Model these as verification guards when they can be automated:

govctl guard new "Requirement trace"
govctl guard edit GUARD-REQUIREMENT-TRACE check.command --set "cargo run --bin trace-check"
govctl work edit WI-YYYY-MM-DD-NNN verification.required_guards --add GUARD-REQUIREMENT-TRACE

Keep the guard domain-specific. govctl provides the governance structure; your project owns the language, framework, and protocol-specific checks.

Common Pitfalls

  • Writing implementation details into RFCs because they are easy to describe.
  • Writing new requirements into ADRs because the decision needs justification.
  • Writing current plans or validation output into Work Item notes.
  • Creating many tiny Work Items for one coherent refactor.
  • Treating loops as mandatory ceremony instead of local execution coordination.
  • Treating an agent goal as durable governance state.
  • Treating govctl check as a substitute for human or agent semantic review.

The goal is not to maximize artifact count. The goal is to keep authority, decision rationale, execution state, and verification evidence in the right places.

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 rfc new "Feature Title"

# Specify ID manually
govctl rfc new "Feature Title" --id RFC-0010

RFC Structure

An RFC consists of:

  • Metadata (rfc.toml) — ID, title, status, phase, version, owners
  • Clauses (clauses/*.toml) — Atomic units of specification

The TOML files use #:schema headers and a [govctl] + [content] layout:

#:schema ../../schema/rfc.schema.json

[govctl]
id = "RFC-0010"
title = "Feature Title"
version = "0.1.0"
status = "draft"
phase = "spec"
owners = ["@you"]
created = "2026-03-17"
refs = []

[content]
summary = "Brief summary of this RFC."

Tagging RFCs

Once tags are registered in the project vocabulary, apply them to RFCs:

govctl rfc edit RFC-0010 tags --add caching
govctl rfc edit RFC-0010 tags --add api

Filter lists by tag:

govctl rfc list --tag caching
govctl rfc list --tag caching,api

Canonical Edit Surface

All RFC and clause fields are accessible through path-based editing:

# Lifecycle-managed fields use dedicated verbs
govctl rfc bump RFC-0010 --minor -m "Add new clause for edge case"
govctl rfc finalize RFC-0010 normative

# Add to array fields
govctl rfc edit RFC-0010 refs --add RFC-0001
govctl rfc edit RFC-0010 owners --add "@co-maintainer"

# Remove by index or pattern
govctl rfc edit RFC-0010 refs --at 0 --remove
govctl rfc edit RFC-0010 owners --remove "@old-owner" --exact

# Edit clause text
govctl clause edit RFC-0010:C-SCOPE text --stdin <<'EOF'
New clause text here
EOF

Working with Clauses

Create a Clause

govctl clause new RFC-0010:C-SCOPE "Scope" -s "Specification" -k normative

Options:

  • -s, --section — Section name (e.g., “Specification”, “Rationale”)
  • -k, --kindnormative (binding) or informative (explanatory)

Clause files use the same [govctl] + [content] layout:

#:schema ../../../schema/clause.schema.json

[govctl]
id = "C-SCOPE"
title = "Scope"
kind = "normative"
status = "active"
since = "0.1.0"

[content]
text = """
The system MUST validate all inputs."""

Edit Clause Text

# From stdin (recommended for multi-line)
govctl clause edit RFC-0010:C-SCOPE text --stdin <<'EOF'
The system MUST validate all inputs.
The system SHOULD log validation failures.
EOF

# Inline text
govctl clause edit RFC-0010:C-SCOPE text --set "The system MUST validate all inputs."

# From file
govctl clause edit RFC-0010:C-SCOPE text --stdin < clause-text.md

Delete a Clause

Accidentally created clauses can be deleted from draft RFCs only:

govctl clause delete RFC-0010:C-MISTAKE -f

Safety: Deletion is only allowed when:

  • The RFC status is draft (normative RFCs are immutable)
  • No other artifacts reference the clause

For normative RFCs, use govctl clause deprecate RFC-0010:C-OLD instead.

List Clauses

govctl clause list
govctl clause list RFC-0010
govctl clause list --tag core    # Filter by tag

View a Clause

govctl clause show RFC-0010:C-SCOPE

Status Lifecycle

RFCs have three statuses:

draft → normative → deprecated

Finalize to Normative

When the spec is complete and approved:

govctl rfc finalize RFC-0010 normative

This makes the RFC binding — implementation must conform to it.

Deprecate

When an RFC is superseded or obsolete:

govctl rfc finalize RFC-0010 deprecated

Phase Lifecycle

RFCs progress through four phases:

spec → impl → test → stable

Advance Phase

govctl rfc advance RFC-0010 impl    # Ready for implementation
govctl rfc advance RFC-0010 test    # Implementation complete, ready for testing
govctl rfc advance RFC-0010 stable  # Tested, ready for production

Phase transitions are gated:

  • spec → impl requires status = normative
  • Each phase has invariants that must be satisfied

Versioning

RFCs use semantic versioning:

# Bump version with changelog entry
govctl rfc bump RFC-0010 --patch -m "Fix typo in clause C-SCOPE"
govctl rfc bump RFC-0010 --minor -m "Add new clause for edge case"
govctl rfc bump RFC-0010 --major -m "Breaking change to API contract"

Listing and Viewing

govctl rfc list
govctl rfc list normative    # Filter by status
govctl rfc list impl         # Filter by phase
govctl rfc list --tag api    # Filter by tag
govctl rfc show RFC-0010     # Styled markdown to stdout

Working with ADRs

ADRs (Architectural Decision Records) document significant design choices. They explain why things are built a certain way.

Creating ADRs

govctl adr new "Use Redis for caching"

This creates a TOML file in gov/adr/ with the decision context.

ADR Structure

ADRs are TOML files with #:schema headers:

#:schema ../schema/adr.schema.json

[govctl]
id = "ADR-0003"
title = "Use Redis for caching"
status = "proposed"
date = "2026-03-17"
refs = ["RFC-0001"]

[content]
context = "We need a caching layer for..."
decision = "We will use Redis because..."
consequences = "Positive: faster reads. Negative: operational complexity."

[[content.alternatives]]
text = "Memcached"
pros = ["Simpler"]
cons = ["No persistence"]
rejection_reason = "Persistence is required for our use case"

ADRs contain:

  • Context — The situation requiring a decision
  • Decision — What was decided
  • Consequences — Expected outcomes (positive and negative)
  • Alternatives — Options considered with pros, cons, and rejection reasons (per [[ADR-0027]])
  • Statusproposed, accepted, rejected, or superseded

Editing ADRs

Use govctl to get/set fields:

# Get specific field
govctl adr get ADR-0003 status

# Set content field value
govctl adr set ADR-0003 decision "We will use Redis because..."

# Set multi-line content from stdin
govctl adr set ADR-0003 context --stdin <<'EOF'
We need a caching layer that can handle
10k requests per second with sub-millisecond latency.
EOF

Canonical Edit Paths

All ADR fields are accessible through a unified path-based edit interface:

# Scalar fields
govctl adr edit ADR-0003 content.decision --set "We will use Redis"
govctl adr edit ADR-0003 content.context --stdin < context.md

# Array fields — add, remove, tick
govctl adr edit ADR-0003 refs --add RFC-0010
govctl adr edit ADR-0003 refs --at 0 --remove

# Nested alternatives
govctl adr edit ADR-0003 content.alternatives --add "Option C: Use etcd"
govctl adr edit ADR-0003 "content.alternatives[0].pros" --add "Fast reads"
govctl adr edit ADR-0003 "content.alternatives[0].cons" --add "Operational cost"
govctl adr edit ADR-0003 "content.alternatives[0].status" --set accepted
govctl adr edit ADR-0003 "content.alternatives[0].rejection_reason" --set "Too complex"

# Tick alternative status
govctl adr edit ADR-0003 content.alternatives --tick accepted --at 0

Path aliases are available for common fields:

AliasResolves to
decisioncontent.decision
contextcontent.context
consequencescontent.consequences
altcontent.alternatives
procontent.alternatives[i].pros
concontent.alternatives[i].cons
reasoncontent.alternatives[i].rejection_reason

Legacy Set/Add/Remove Verbs

The original verbs remain available and compile into the same edit pipeline:

govctl adr set ADR-0003 decision "We will use Redis because..."
govctl adr add ADR-0003 alternatives "Option C"
govctl adr remove ADR-0003 refs RFC-0001

Tagging ADRs

Once tags are registered in the project vocabulary, apply them to ADRs:

govctl adr edit ADR-0003 tags --add caching
govctl adr edit ADR-0003 tags --add performance

Filter lists by tag:

govctl adr list --tag caching
govctl adr list --tag caching,performance

Status Lifecycle

proposed → accepted → superseded
         ↘ rejected

Accept a Decision

Before accepting, the ADR must have at least 2 alternatives with 1 accepted and 1 rejected per [[ADR-0042]]:

govctl adr edit ADR-0003 "content.alternatives[0].status" --set accepted
govctl adr edit ADR-0003 "content.alternatives[1].status" --set rejected

govctl adr accept ADR-0003

Use --force for historical backfills where alternatives cannot be reconstructed:

govctl adr accept ADR-0003 --force

When consensus is reached:

govctl adr accept ADR-0003

Reject a Proposal

When a proposed ADR should not proceed:

govctl adr reject ADR-0003

Accepted ADRs are not deprecated. When a newer decision replaces an accepted ADR, supersede it instead.

Supersede

When a new decision replaces an old one:

govctl adr supersede ADR-0001 --by ADR-0005

This marks ADR-0001 as superseded and records ADR-0005 as its replacement.

Listing and Viewing

govctl adr list
govctl adr list accepted    # Filter by status
govctl adr show ADR-0003    # Styled markdown to stdout

Working with Work Items

Work Items track durable units of work from inception to completion, including scope, lifecycle state, acceptance criteria, references, dependencies, and durable notes. Round-by-round execution trace belongs in local loop state and round artifacts.

See also: Tags, TUI, Canonical Edit

Creating Work Items

# Create in queue (pending)
govctl work new "Implement caching layer"

# Create and activate immediately
govctl work new --active "Urgent bug fix"

Work items are automatically assigned IDs like WI-2026-01-17-001.

Work Item Structure

Work items are TOML files with #:schema headers:

#:schema ../schema/work.schema.json

[govctl]
id = "WI-2026-01-17-001"
title = "Implement caching layer"
status = "active"
started = "2026-01-17"
refs = ["RFC-0010", "ADR-0003"]
depends_on = ["WI-2026-01-16-001"]

[content]
description = "Add Redis caching for the query endpoint."
notes = ["Do not retry the old validation path"]

[[content.acceptance_criteria]]
text = "Cache invalidation on write"
status = "pending"
category = "added"

[[content.acceptance_criteria]]
text = "govctl check passes"
status = "pending"
category = "chore"

Work items contain:

  • Title — Brief description
  • Description — Task scope declaration
  • Notes — Durable learnings and constraints
  • Acceptance Criteria — Checkable completion criteria with changelog category
  • Refs — Links to related RFCs, ADRs, or external resources
  • Depends On — Blocking dependencies on other work items

Status Lifecycle

queue → active → done
    ↘        ↘ cancelled

Move Between States

# By ID
govctl work move WI-2026-01-17-001 active
govctl work move WI-2026-01-17-001 done

# By filename (without path)
govctl work move implement-caching.toml active

Moving to done requires all verification guards to pass (see Validation).

Acceptance Criteria

Add Criteria

govctl work add WI-2026-01-17-001 acceptance_criteria "chore: Unit tests pass"
govctl work add WI-2026-01-17-001 acceptance_criteria "add: Documentation updated"

Category prefixes (add:, fix:, change:, chore:, etc.) are required and drive changelog generation. Conventional-commit aliases like feat:, refactor:, test:, docs: are also accepted.

Canonical changelog categories are still the preferred form in stored artifacts. The conventional-commit aliases are accepted as input sugar and normalized into the changelog model.

Mark Criteria Complete

govctl work tick WI-2026-01-17-001 acceptance_criteria "Unit tests" -s done

The pattern matches case-insensitively by substring.

Canonical Edit Paths

Most work item fields are accessible through the unified path-based edit interface. Lifecycle-managed fields (such as status) are excluded — use govctl work move for status transitions instead.

# Set scalar fields
govctl work edit WI-2026-01-17-001 content.description --stdin <<'EOF'
New description here
EOF

# Add to array fields
govctl work edit WI-2026-01-17-001 refs --add RFC-0010
govctl work edit WI-2026-01-17-001 depends_on --add WI-2026-01-16-001
govctl work edit WI-2026-01-17-001 acceptance_criteria --add "fix: Handle edge case"

# Remove by index
govctl work edit WI-2026-01-17-001 content.acceptance_criteria[0] --remove

# Tick checklist items
govctl work edit WI-2026-01-17-001 content.acceptance_criteria[0] --tick done
govctl work edit WI-2026-01-17-001 content.acceptance_criteria[1] --tick cancelled

Path aliases are available for common fields:

AliasResolves to
descriptioncontent.description
accontent.acceptance_criteria
notescontent.notes
categorycontent.acceptance_criteria[i].category

Dependencies and Execution Loops

Use depends_on for hard execution ordering between work items. Keep refs for informational links to RFCs, ADRs, clauses, guards, or related work.

govctl work edit WI-2026-01-17-002 depends_on --add WI-2026-01-17-001
govctl check

govctl check validates dependency targets and rejects dependency cycles. A work item should only depend on another work item when the dependent work cannot start until the blocker has completed.

For a batch with multiple independently meaningful work items, create one local execution loop and let govctl generate the loop ID:

govctl loop list open
govctl loop start WI-2026-01-17-001 WI-2026-01-17-002
govctl loop run <LOOP-ID>

Loop state and round evidence live under .govctl/loops/<LOOP-ID>/. loop run opens or validates local rounds; it does not implement code, tick acceptance criteria, add notes, or move work items to done.

When batch scope changes, keep the same loop identity:

govctl loop add <LOOP-ID> work WI-2026-01-17-003
govctl loop remove <LOOP-ID> work WI-2026-01-17-002
govctl loop replan <LOOP-ID>

Use work item notes only for durable lessons or constraints. Put transient execution trace, failed attempts, blockers, next actions, and round summaries in loop state and round artifacts.

Tagging Work Items

Once tags are registered in the project vocabulary, apply them to work items:

govctl work edit WI-2026-01-17-001 tags --add backend
govctl work edit WI-2026-01-17-001 tags --add performance

Filter lists by tag:

govctl work list --tag backend
govctl work list --tag backend,performance

Per-Work-Item Guards

Work items can require extra verification guards in addition to the project’s default guard set.

Example:

[verification]
required_guards = ["GUARD-CLIPPY"]

This means:

  • GUARD-CLIPPY is required for this work item even if it is not a project default
  • project defaults from gov/config.toml still apply when verification is enabled
  • the work item cannot move to done until the effective required guards pass or are explicitly waived

To run the effective guard set for a single work item:

govctl verify --work WI-2026-01-17-001

Waiving A Guard

If a specific guard must be waived for this work item, record that in the artifact with a reason:

[[verification.waivers]]
guard = "GUARD-CARGO-TEST"
reason = "Temporarily flaky on macOS runners; tracked in issue #123"

Waivers are per-work-item only. They do not disable the guard globally, and they should remain rare and justified.

Notes

Add closure-worthy durable notes for constraints or retry rules that should remain useful after the work item is done:

govctl work add WI-2026-01-17-001 notes "Do not retry the old validation path; it fails on missing refs"

Do not use notes for progress updates, commands run, validation output, current plans, next actions, temporary blockers, or TODOs. Put transient execution trace in local loop state and round artifacts instead.

Nested path edits are also available for structured fields:

govctl work edit WI-2026-01-17-001 "content.acceptance_criteria[0].category" --set fixed

Removing Items

Remove items from array fields using flexible matching:

# Substring match (default, case-insensitive)
govctl work remove WI-2026-01-17-001 notes "edge case"

# Exact match
govctl work remove WI-2026-01-17-001 notes "Discovered edge case in validation" --exact

# By index (0-based)
govctl work remove WI-2026-01-17-001 notes --at 0

# Negative index (from end)
govctl work remove WI-2026-01-17-001 notes --at -1

# Regex pattern
govctl work remove WI-2026-01-17-001 refs "RFC-.*" --regex

# Remove all matches
govctl work remove WI-2026-01-17-001 refs "obsolete" --all

Deleting Work Items

Accidentally created work items can be deleted if they’re still in queue status:

govctl work delete WI-2026-01-17-999 -f

Safety: Deletion is only allowed when:

  • The work item status is queue (never activated)
  • No other artifacts reference it

For work items that have been activated, use status transitions instead:

govctl work move WI-2026-01-17-001 cancelled

Listing and Viewing

govctl work list
govctl work list queue      # Pending items
govctl work list active     # In progress
govctl work list done       # Completed
govctl work show WI-2026-01-17-001  # Styled markdown to stdout

Validation & Rendering

govctl provides tools to validate governance artifacts, enforce completion gates, and render human-readable documentation.

Validation

Check All Artifacts

govctl check

This validates:

  • Schema conformance — All required fields present, correct types
  • Phase discipline — No invalid state transitions
  • Cross-referencesrefs and [[...]] annotations point to existing artifacts
  • Controlled-vocabulary tags — All artifact tags are registered in gov/config.toml [tags] allowed
  • Clause structure — Normative clauses in spec sections
  • Source code scanning[[RFC-0001]] annotations in source files are verified

Exit Codes

  • 0 — All validations passed
  • 1 — Validation errors found

Source Code Scanning

govctl scans source files for [[artifact-id]] annotations and verifies they reference existing, non-deprecated artifacts:

#![allow(unused)]
fn main() {
// Implements [[RFC-0001:C-VALIDATION]]
fn validate() { ... }

// Per [[ADR-0005]], we use semantic colors
}

Configure scanning in gov/config.toml:

[source_scan]
enabled = true
include = ["src/**/*.rs"]
exclude = []

Controlled-Vocabulary Tags

Tags provide cross-cutting categorization across all governance artifacts. Every tag must be registered in a project-level allow list before use.

Managing the Tag Registry

# List all registered tags with usage counts
govctl tag list

# Register a new tag
govctl tag new caching

# Remove a tag (fails if any artifact still uses it)
govctl tag delete caching

Tagging Artifacts

Once a tag is registered, apply it to any artifact via the standard edit command with --add:

govctl rfc edit RFC-0010 tags --add caching
govctl adr edit ADR-0003 tags --add caching
govctl work edit WI-2026-01-17-001 tags --add caching

Filtering by Tag

List commands support --tag to filter by one or more tags (comma-separated, AND logic):

govctl rfc list --tag caching
govctl adr list --tag caching,performance
govctl work list --tag breaking-change

Tags are validated at govctl check time — any tag not in the allow list produces error E1105.

Verification Guards

Guards are executable completion checks that run automatically when a work item moves to done. They prevent work items from closing unless all configured checks pass.

How Guards Work

When you run govctl work move <WI-ID> done, govctl executes each guard defined in gov/config.toml:

[verification]
enabled = true
default_guards = ["GUARD-GOVCTL-CHECK", "GUARD-CARGO-TEST"]

Each guard is a TOML file in gov/guard/:

#:schema ../schema/guard.schema.json

[govctl]
id = "GUARD-CARGO-TEST"
title = "cargo test passes"
refs = ["RFC-0000"]

[check]
command = "cargo test"
timeout_secs = 300

Guard Subcommands

Guards are first-class resources with their own CRUD verbs:

# Create a new guard
govctl guard new "My Lint Check"

# List all guards
govctl guard list

# Show guard definition
govctl guard show GUARD-MY-LINT

# Set guard fields
govctl guard edit GUARD-MY-LINT check.command --set "npm run lint"
govctl guard edit GUARD-MY-LINT check.timeout_secs --set 60

# Delete a guard (blocked if still referenced by work items or project defaults)
govctl guard delete GUARD-MY-LINT

Guard Fields

FieldRequiredDescription
idYesUnique guard identifier (e.g., GUARD-LINT)
titleYesHuman-readable description
refsNoRelated RFCs/ADRs
commandYesShell command to execute from project root
timeout_secsNoMax execution time (default: 300s)
patternNoRegex pattern that must match stdout+stderr

Guard Behavior

  • A guard passes when its command exits with code 0 (and matches pattern if specified)
  • A guard fails when the command exits non-zero, times out, or doesn’t match the pattern
  • All guards must pass before govctl work move <WI-ID> done succeeds

Running Guards Independently

Use govctl verify to run guards without moving a work item:

# Run all project default guards
govctl verify

# Run specific guards
govctl verify GUARD-CARGO-TEST GUARD-GOVCTL-CHECK

# Run guards required by a specific work item
govctl verify --work WI-2026-01-17-001

Per-Work-Item Guards

Project-level default_guards are only part of the picture. A work item can also require additional guards of its own:

[verification]
required_guards = ["GUARD-CLIPPY"]

This is useful when one work item needs an extra check that should not become a project-wide default.

The effective required guard set for a work item is:

  • the project-level default_guards when verification is enabled
  • plus the work item’s verification.required_guards
  • minus any explicitly waived guards

Guard Waivers

If a guard must be waived for a specific work item, record that explicitly with a reason:

[[verification.waivers]]
guard = "GUARD-CARGO-TEST"
reason = "Flaky on CI runner image; tracked in issue #123"

Waivers are scoped to a single work item. They do not disable verification globally, and they should be treated as an exception that must be explained.

Rendering

Render governance artifacts to markdown for documentation.

Render All

govctl render            # RFCs to docs/rfc/
govctl render adr        # ADRs to docs/adr/
govctl render work       # Work items to docs/work/
govctl render all        # Everything
govctl render changelog  # CHANGELOG.md

Render Single Items

govctl rfc render RFC-0010
govctl adr render ADR-0005
govctl work render WI-2026-01-17-001

View Without Writing Files

The show commands render styled markdown to stdout without writing files:

govctl rfc show RFC-0010
govctl adr show ADR-0005
govctl work show WI-2026-01-17-001
govctl clause show RFC-0010:C-SCOPE

Hash Signatures

Rendered markdown includes a SHA-256 signature for tampering detection:

<!-- SIGNATURE: sha256:abc123... -->

If the source changes, the signature won’t match — indicating the rendered doc is stale.

Project Status

govctl status

Shows RFC/ADR/work item counts by status, phase breakdown, and active work items.

govctl search cache
govctl search "work item" --type work
govctl search RFC-0002 --output json
govctl search migration --tag cli -n 5
govctl search cache --reindex

Search is project-wide discovery across RFCs, clauses, ADRs, work items, and verification guards. Use repeated --type flags to restrict artifact kinds and repeated --tag flags to require all listed tags.

Supported output formats are table (default), json, and plain. If govctl persists a search index, it lives under .govctl/ as derived local state. The command establishes index freshness before returning results; --reindex forces a full rebuild.

CLI Self-Description

govctl provides a machine-readable command catalog for agent discoverability:

govctl describe
govctl describe --context   # Includes project context (RFCs, ADRs, active work items)
govctl describe --output json

Self-Update

Update govctl to the latest release:

govctl self-update          # Download and replace binary
govctl self-update --check  # Check for newer version without downloading

Supports GITHUB_TOKEN environment variable for authenticated API requests.

Agent Skill Installation

Install or update govctl’s agent skills and reviewer agents for your AI coding tool:

# Claude Code (default)
govctl init-skills

# Codex CLI
govctl init-skills --format codex

# Custom output directory
govctl init-skills --dir /path/to/agent-config

This writes bundled workflow skills, writer/helper skills, and reviewer agents to the configured agent directory. Use --format codex when the destination expects Codex agent-role TOML files instead of Claude-style Markdown agents.

Schema Migration

When the governance schema evolves between govctl versions, artifact files may need format upgrades:

govctl migrate

This upgrades TOML artifact file formats (e.g., adding #:schema headers or normalizing schema metadata) with transactional safety — changes are staged, backed up, and committed atomically.

govctl migrate vs the /migrate Workflow

These are related but serve different purposes:

govctl migrate/migrate skill
WhatUpgrade existing govctl artifacts to current formatAdopt govctl in an existing project
WhenAfter updating govctl versionWhen starting governance in a brownfield repo
EffectSyncs TOML artifacts, schemas, and govctl local-state .gitignore entriesDiscovers decisions, backfills ADRs, annotates source
RiskLow — transactional, reversibleMedium — requires human review of generated ADRs

Run govctl migrate when govctl reports an outdated schema version, missing or stale bundled schema files, or missing govctl-managed local-state .gitignore entries such as .govctl.lock and .govctl/. If a repository still contains legacy RFC or clause JSON storage, migrate it with govctl <0.9 before upgrading. Use the /migrate skill when bringing a legacy project under governance for the first time.

RFC-0000: govctl Governance Framework

Version: 1.3.2 | Status: normative | Phase: stable


1. Summary

[RFC-0000:C-SUMMARY] Framework Summary (Informative)

govctl is a governance CLI that manages six 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
  • Releases: Published versions and the work items included in each version
  • Verification Guards: Reusable executable checks that turn completion requirements into auditable pass/fail gates

All artifacts follow explicit lifecycle states, phase gates, or immutability rules to ensure disciplined development.

Tags: core

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.

The canonical RFC storage format is TOML. Repositories MUST store each RFC as a TOML file (rfc.toml) containing:

  • [govctl] section with: id, title, version, status, phase, owners, created
  • optional [govctl] fields: updated, supersedes, refs, signature
  • [[sections]] array with ordered section definitions and clause references
  • [[changelog]] array for version history

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Entries in sections[].clauses MUST reference clause TOML files by relative path (for example clauses/C-EXAMPLE.toml).

Implementations MUST reject legacy RFC JSON storage files (rfc.json) during normal operations. The diagnostic MUST instruct users to migrate those repositories with a govctl version earlier than 0.9 before upgrading to a TOML-only govctl release.

Rationale: This removes the last storage-format split from RFC handling while preserving a clear upgrade path for repositories that still contain legacy JSON sources.

Tags: core, schema

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

Tags: core, lifecycle

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)

Tags: core, lifecycle

Since: v1.0.0

[RFC-0000:C-REFERENCE-HIERARCHY] Artifact Reference Hierarchy (Normative)

Governance artifacts follow a strict authority hierarchy. References between artifact types MUST respect this hierarchy.

Authority Order (highest to lowest):

  1. RFC — Constitutional law. Defines what the system does.
  2. ADR — Interpretation. Documents decisions implementing RFCs.
  3. Work Item — Execution. Tracks work implementing ADRs and RFCs.

Structured reference rules:

Implementations MUST validate these rules during project validation (for example govctl check).

  • RFC refs entries, [[...]] link targets, and known artifact-ID mentions in governed RFC clause text MUST NOT identify an ADR or a Work Item.

  • ADR refs entries, [[...]] link targets, and known artifact-ID mentions in governed ADR content fields MUST NOT identify a Work Item.

  • Work Item refs entries and [[...]] link targets MAY identify any artifact type.

This clause only defines the RFC/ADR/Work Item authority hierarchy. It does not impose additional target-kind restrictions for artifact types outside that hierarchy.

Rationale:

This hierarchy prevents circular dependencies and maintains clear authority chains. An RFC that links to or names an ADR or Work Item as a governed reference inverts the dependency direction — lower layers become authorities over the specification.

Prose outside governed reference surfaces:

Normative RFC clause text SHOULD remain self-contained. Non-governed explanatory text MAY mention artifact identifier shapes as examples, but known lower-authority artifact identifiers in governed RFC clause text and governed ADR content fields are validated as references even without [[...]] delimiters.

Tags: core, validation

Since: v1.0.1


3. Clause Specification

[RFC-0000:C-CLAUSE-DEF] Clause Definition (Normative)

A clause is an individual requirement or statement within an RFC.

The canonical clause storage format is TOML. Repositories MUST store each clause as a TOML file containing:

  • [govctl] section with: id, title, kind, status
  • optional [govctl] fields: since, superseded_by, anchors
  • [content] section with: text

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Implementations MUST reject legacy clause JSON storage files (gov/rfc/<RFC-ID>/clauses/*.json) during normal operations. The diagnostic MUST instruct users to migrate those repositories with a govctl version earlier than 0.9 before upgrading to a TOML-only govctl release.

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.

Rationale: This aligns clause storage with RFC, ADR, Work Item, and Release storage while removing the legacy JSON compatibility path from normal operation.

Tags: core, schema

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
  • optional [govctl] field: superseded_by
  • [content] section with: context, decision, consequences

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Implementations MUST define a machine-readable JSON Schema for the ADR file structure and MUST validate ADR files against that schema during project validation.

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.

Tags: core, schema

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, created, refs
  • optional [govctl] fields: started, completed
  • [content] section with: description, acceptance_criteria, notes
  • optional [verification] section with: required_guards, waivers

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Implementations MUST define a machine-readable JSON Schema for the Work Item file structure and MUST validate Work Item files against that schema during project validation.

When present, verification.required_guards MUST be an array of Verification Guard IDs defined by RFC-0000:C-GUARD-DEF. These guard IDs augment project-level default guard requirements when project verification is enabled.

When present, each verification.waivers entry MUST be an object with exactly two fields: guard and reason.

The guard field MUST name exactly one Verification Guard ID.

The reason field MUST be a non-empty string.

Waiver entries MUST reference only guards that appear in the work item’s effective required guard set. Duplicate waivers for the same guard MUST be rejected during validation.

A waiver MUST suppress only the named guard. A Work Item MUST NOT disable the verification system globally.

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, and any required verification guards have passed or been explicitly waived.

cancelled: Abandoned from queue or active. Reason documented in notes.

A Work Item MUST NOT transition to done if any acceptance_criteria are pending.

Tags: core

Since: v1.0.0


6. Release Specification

[RFC-0000:C-RELEASE-DEF] Release Definition (Normative)

A Release tracks a published version and the set of work items included in that version.

Release data MUST be stored as a TOML file at gov/releases.toml containing:

  • [[releases]] array with entries containing: version, date, refs

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Each releases[].version MUST be a valid semantic version.

Each releases[].date MUST use ISO 8601 calendar date format YYYY-MM-DD.

Each releases[].refs entry MUST reference an existing Work Item ID.

A release entry has no lifecycle and MUST be treated as immutable once created.

Implementations MUST define a machine-readable JSON Schema for the release file structure and MUST validate gov/releases.toml against that schema during project validation.

Rationale: Releases are first-class governance artifacts because changelog generation and release membership depend on them. Giving releases a defined TOML structure and required JSON Schema removes the remaining schema-less storage special case.

Tags: core, release

Since: v1.0.2


7. Verification Guard Specification

[RFC-0000:C-GUARD-DEF] Verification Guard Definition (Normative)

A Verification Guard defines a reusable executable completion check for a govctl project.

Every Verification Guard MUST be stored as a TOML file under gov/guard/ containing:

  • [govctl] section with: id, title
  • optional [govctl] field: refs
  • [check] section with: command
  • optional [check] fields: timeout_secs, pattern

Format evolution is tracked by the project-level [schema] version in gov/config.toml, not per-artifact fields.

Implementations MUST define a machine-readable JSON Schema for the Verification Guard file structure and MUST validate guard files during project validation.

Verification Guard IDs MUST be unique within a repository.

A guard check MUST execute its command non-interactively from the project root.

If timeout_secs is absent, implementations MUST use a default timeout of 300 seconds.

A guard check that exceeds its timeout MUST fail.

A guard check MUST evaluate pattern, when present, against the combined standard output and standard error streams using case-insensitive regular-expression matching.

A guard check MUST pass only when the command exits successfully. If pattern is provided, the combined output MUST also match that pattern.

Rationale: Verification Guards make completion rules explicit, reusable, and machine-executable so agents cannot satisfy them with checklist text alone.

Tags: core, validation

Since: v1.1.0


Changelog

v1.3.2 (2026-06-04)

Align reference hierarchy wording

Changed

  • reference hierarchy wording now describes only the RFC-to-ADR-or-Work Item and ADR-to-Work Item prohibitions

v1.3.1 (2026-06-04)

Close plain-text reference hierarchy loophole

Changed

  • Known lower-authority artifact IDs in governed RFC/ADR prose are validated even without [[…]] delimiters

v1.3.0 (2026-06-04)

Remove legacy JSON artifact storage compatibility

Removed

  • legacy RFC and clause JSON storage is no longer supported in normal operation

v1.2.0 (2026-05-31)

Remove a legacy execution-history field from Work Item field operations

Changed

  • historical execution entries may still be parsed for Work Item rendering

Removed

  • legacy execution-history field is no longer path-addressable per ADR-0047

v1.1.1 (2026-03-22)

Clarify machine-validated reference hierarchy for refs and [[…]]

Added

  • Structured rules: RFC must not link ADR/WI; ADR must not link WI

v1.1.0 (2026-03-17)

Add verification guards and work-item verification metadata

Added

  • Added Verification Guard artifact definition and work-item verification fields

v1.0.2 (2026-03-17)

Record release artifact clause and migration amendments

v1.0.1 (2026-01-26)

Add artifact reference hierarchy clause

Added

  • Add C-REFERENCE-HIERARCHY clause defining that RFCs must not reference ADRs

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.3.0 | Status: normative | Phase: stable


1. Summary

[RFC-0001:C-SUMMARY] Summary (Informative)

This RFC defines state machines governing RFC, ADR, Work Item, and Clause lifecycles, including the additional transition gates that control when work may be treated as complete.

Tags: lifecycle

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:

  1. draft — Initial state. The RFC is under development and not yet binding.
  2. normative — The RFC defines required behavior. Implementations MUST conform. Normative RFCs MAY be amended via version bumping; amendments MUST include a changelog entry documenting the change.
  3. 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 finalize command)
  • normative → deprecated (via deprecate command)

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)

Tags: lifecycle

Since: v0.1.0

[RFC-0001:C-RFC-PHASE] RFC Phase Transitions (Normative)

An RFC MUST have exactly one of the following phase values:

  1. spec — Specification phase. The RFC text is being written. No implementation work.
  2. impl — Implementation phase. Code is being written to conform to the RFC.
  3. test — Testing phase. Implementation is complete; tests are being written and validated.
  4. 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.

Tags: lifecycle

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:

  1. queue — Initial state. The work item is defined but not yet started.
  2. active — The work item is currently being worked on.
  3. done — The work item is complete. All acceptance criteria are satisfied, and any required verification guards have passed or been explicitly waived.
  4. 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 started date if not already set
  • active → done: Sets completed date
  • active → cancelled: Sets completed date

Tags: lifecycle

Since: v0.1.0

[RFC-0001:C-ADR-STATUS] ADR Status Transitions (Normative)

An ADR MUST have exactly one of the following status values:

  1. proposed — Initial state. The decision is under consideration.
  2. accepted — The decision has been accepted and is in effect.
  3. rejected — The decision was considered and explicitly declined.
  4. superseded — The decision has been replaced by another ADR.

Valid transitions:

  • proposed → accepted (via accept command)
  • proposed → rejected (via reject command)
  • accepted → superseded (via supersede command, requires --by to specify replacement)

Invalid transitions (MUST be rejected):

  • proposed → superseded (cannot supersede without first accepting)
  • accepted → proposed (no “un-accept”)
  • accepted → rejected (accepted decisions must be superseded, not retroactively rejected)
  • rejected → any (rejected is terminal)
  • superseded → any (superseded is terminal)

When an ADR is superseded:

  • The superseded_by field MUST be set to the ID of the replacing ADR
  • The replacing ADR SHOULD reference the superseded ADR

When an ADR is rejected:

  • The ADR MUST remain available as historical record
  • The superseded_by field MUST NOT be set

Tags: lifecycle

Since: v0.1.0

[RFC-0001:C-CLAUSE-STATUS] Clause Status Transitions (Normative)

A Clause MUST have exactly one of the following status values:

  1. active — Default state. The clause is in effect.
  2. deprecated — The clause is no longer recommended but still valid.
  3. superseded — The clause has been replaced by another clause.

Valid transitions:

  • active → deprecated (via deprecate command)
  • active → superseded (via supersede command, 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_by field MUST be set to the ID of the replacing clause
  • The replacing clause SHOULD have a since field indicating the version it was introduced

Tags: lifecycle

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:

  1. The work item MUST have at least one acceptance criterion defined
  2. All acceptance criteria MUST have status “done” or “cancelled” (no “pending”)
  3. Every guard named in the work item’s verification.required_guards MUST pass or be explicitly waived with a reason
  4. If project verification is enabled, every project-level default guard MUST also pass or be explicitly waived with a reason

The effective required verification guards are the union of the work item’s verification.required_guards and, only when project verification is enabled, the project’s configured default guards. Only guards covered by explicit waivers are removed from that set.

Rationale: Prevents marking work as complete without defined success criteria or executable completion proof.

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. Project verification MUST default to disabled when the project config does not opt into it.

Tags: lifecycle, validation

Since: v0.1.0


Changelog

v0.3.0 (2026-03-17)

Add executable verification gates to work completion

Added

  • Added required verification guard gate conditions for work completion

v0.2.1 (2026-01-26)

Remove ADR reference from C-RFC-STATUS; RFCs are self-contained and should not reference ADRs

Added

  • Inline amendment rule in C-RFC-STATUS clause (was referencing ADR-0016)

v0.2.0 (2026-01-19)

Clarify that normative RFCs may be amended via version bumping

v0.1.0 (2026-01-17)

Initial draft

RFC-0002: CLI Resource Model and Command Architecture

Version: 0.10.2 | Status: normative | Phase: test


1. Summary

[RFC-0002:C-SUMMARY] Summary (Informative)

This RFC defines the resource-first command architecture for the govctl CLI. It establishes normative requirements for command structure, resource types, verb semantics, and project-level verification commands to ensure consistency and discoverability.

The design follows established patterns from Docker, kubectl, and other modern CLIs where commands are grouped by resource type (noun-first) rather than operation type (verb-first).

Scope: This RFC specifies the structural contract (which commands exist, how they’re organized, what resources they operate on). Implementation details (flag syntax, help text formatting, terminal colors) are left to ADRs.

Rationale: A stable command structure enables:

  1. Predictable UX across all resource types
  2. Agent/script automation via consistent patterns
  3. Scoped help and command discovery
  4. Future extensibility without namespace pollution

Tags: cli

Since: v0.1.0


2. Specification

[RFC-0002:C-RESOURCE-MODEL] Resource-First Command Structure (Normative)

The govctl CLI MUST use a resource-first command structure of the form:

govctl <resource> <verb> [arguments] [flags]

Where:

  • <resource> is a governance artifact type (rfc, adr, work, clause, release, guard)
  • <verb> is an operation on that resource (new, list, get, edit, delete, or resource-specific lifecycle operations)
  • [arguments] are positional parameters (typically IDs, titles, or values)
  • [flags] are optional modifiers (–filter, –output, –stdin, etc.)

Rationale:

The resource-first structure (noun-first) provides several advantages over verb-first (operation-first):

  1. Scoped Discovery: govctl rfc --help shows only RFC operations, not all 30+ global commands
  2. Namespace Clarity: govctl rfc finalize is unambiguous; govctl finalize requires knowing it only applies to RFCs
  3. Mental Model Alignment: Users think “I want to work with RFCs” then “What can I do?”, not “I want to finalize something, what can be finalized?”
  4. Extensibility: Adding govctl rfc validate doesn’t pollute the global namespace
  5. Industry Convention: Docker, kubectl, git, cargo all use resource-scoping or similar patterns

Exceptions:

Global command exceptions are governed by RFC-0002:C-GLOBAL-COMMANDS. A command MAY remain at the global namespace when it operates across multiple resource types, performs project-level or CLI-level work, or manages local execution state that coordinates governed resources without becoming a governed artifact resource.

Resource-specific CRUD, field-editing, and lifecycle operations MUST remain resource-first unless an RFC explicitly defines a global command exception.

Implementation Note:

For backwards compatibility during migration, verb-first aliases MAY be supported but MUST emit deprecation warnings. Full verb-first syntax MUST be removed in a major version release.

Tags: cli

Since: v0.1.0

[RFC-0002:C-RESOURCES] Resource Types (Normative)

The following resource types MUST be supported as top-level command namespaces:

1. rfc - Request for Comments

Manages RFC specifications (normative documents defining system behavior).

  • ID Format: RFC-NNNN (e.g., RFC-0001)
  • Lifecycle: draft → normative → deprecated (per RFC-0001:C-RFC-STATUS)
  • Phase: spec → impl → test → stable (per RFC-0001:C-RFC-PHASE)

2. adr - Architecture Decision Record

Manages ADRs (records of architectural decisions).

  • ID Format: ADR-NNNN (e.g., ADR-NNNN-style IDs)
  • Lifecycle: proposed → accepted → superseded, or proposed → rejected (per RFC-0001:C-ADR-STATUS)

3. work - Work Item

Manages work items (tasks, features, bugs).

  • ID Format: WI-YYYY-MM-DD-NNN (e.g., WI-YYYY-MM-DD-NNN)
  • Lifecycle: queue → active → done, with cancellation at any stage (per RFC-0001:C-WORK-STATUS)

4. clause - RFC Clause

Manages individual clauses within RFCs.

  • ID Format: RFC-NNNN:C-NAME (e.g., RFC-0001:C-SUMMARY)
  • Lifecycle: active → deprecated → superseded (per RFC-0001:C-CLAUSE-STATUS)

Clause Namespace vs Storage:

Clauses remain at the CLI top-level namespace despite being child resources of RFCs because their ID format (RFC-NNNN:C-NAME) is self-scoping and unambiguous.

The CLI namespace is independent of filesystem layout. Implementations MAY store clause files nested under RFC directories (e.g., gov/rfc/RFC-0001/clauses/C-NAME.toml) while maintaining the flat CLI command structure (govctl clause get RFC-0001:C-NAME).

5. guard - Verification Guard

Manages reusable executable completion checks defined by RFC-0000:C-GUARD-DEF.

  • ID Format: GUARD-NAME (e.g., GUARD-CARGO-TEST)
  • Storage: gov/guard/ as individual TOML files
  • No lifecycle (guards are either present or removed)

6. release - Release Version

Manages published versions and their included work item references.

  • ID Format: Semantic version (e.g., 1.0.0)
  • Storage: gov/releases.toml as defined by RFC-0000:C-RELEASE-DEF
  • No lifecycle (immutable once created)

Resource Identification:

Each resource type MUST have a unique, predictable ID format that:

  1. Is stable across filesystem operations
  2. Can be referenced in other artifacts
  3. Clearly identifies the resource type without context
  4. Supports lexicographic sorting where meaningful
  5. Is case-sensitive (RFC-0001 ≠ rfc-0001)

Date Format:

All date-valued resource metadata fields (such as created, updated, started, completed, and date) MUST use ISO 8601 calendar date format YYYY-MM-DD.

Tags:

RFCs, clauses, ADRs, work items, and guards MAY include an optional tags array in the [govctl] section. Each tag MUST be a string from the project’s controlled vocabulary defined in gov/config.toml under [tags] allowed. Tags MUST match the pattern [a-z][a-z0-9-]* (lowercase kebab-case). Releases do not carry tags. govctl check MUST reject any artifact that references a tag not present in the allowed set.

Future Extensions:

Additional resource types MAY be added via RFC amendment. New resource types MUST follow the same structural patterns defined in RFC-0002:C-CRUD-VERBS.

Tags: cli, schema

Since: v0.1.0

[RFC-0002:C-CRUD-VERBS] Universal CRUD Verbs (Normative)

All resource types MUST support the following CRUD (Create, Read, Update, Delete) verbs where applicable:

1. new - Create Resource

Syntax: govctl <resource> new <arguments>

Creates a new instance of the resource. Required arguments vary by resource type but typically include a title or primary identifier.

MUST support for: rfc, adr, work, clause, release, guard Behavior:

  • Generates unique ID if not provided
  • Initializes resource with default values
  • Creates necessary filesystem structure
  • Validates inputs per resource schema

Guard-specific: govctl guard new "<title>" scaffolds a new guard TOML file under gov/guard/. The generated ID is derived from the slugified title with a GUARD- prefix. The command SHOULD print a hint about adding the guard to verification.default_guards in gov/config.toml.

2. list - List Resources

Syntax: govctl <resource> list [filter] [--tag <tag>[,<tag>...]]

Lists all instances of the resource type. Optional filter narrows results.

MUST support for: rfc, adr, work, clause, release, guard Behavior:

  • Returns tabular output by default
  • Supports filtering (exact match or substring)
  • Sorted by ID (lexicographic order)
  • MUST respect RFC-0002:C-OUTPUT-FORMAT flags
  • With --tag: filters results to artifacts that carry ALL specified tags. MUST support comma-separated tag values. Applies to rfc, clause, adr, work, and guard (releases do not carry tags).

3. get - Read Resource

Syntax: govctl <resource> get <id> [field]

Retrieves a resource by ID. If field is specified, returns only that field value.

MUST support for: rfc, adr, work, clause, guard Behavior:

  • Returns full resource if no field specified
  • Returns field value if field specified
  • MUST respect RFC-0002:C-OUTPUT-FORMAT flags
  • MUST error if resource or field does not exist

Field Name Stability:

Field names exposed via get <id> <field> MUST be stable identifiers defined by the resource schema. Field names MAY NOT be renamed without a major version bump of govctl.

4. edit - Update Resource

Syntax: govctl <resource> edit <id> <path> --set <value> or govctl <resource> edit <id> <path> --set --stdin

Updates a single field addressed by a deterministic path expression. Values can be provided through an explicit mutation flag or via stdin for multiline content.

MUST support for: rfc, adr, work, clause, guard Behavior:

  • Simple fields: replace the value at the addressed path
  • Arrays and nested fields: MUST use deterministic path-based addressing, including indexed path expressions such as content.alternatives[0].text
  • MUST validate path syntax and reject unknown fields, invalid indices, and paths whose operation is not allowed by the resource schema
  • MUST validate values per field type before writing
  • MUST support --stdin with the explicit set operation for multiline content

5. delete - Delete Resource

Syntax: govctl <resource> delete <id>

Removes a resource permanently.

MUST support for: work, clause, guard MUST NOT support for: rfc, adr (use lifecycle verbs instead)

Deletion Safety Constraints:

For guards:

  • MUST verify no work items reference the guard ID in verification.required_guards or verification.waivers[*].guard before deletion
  • MUST verify the guard is not listed in verification.default_guards in gov/config.toml before deletion
  • MUST error with list of referencing artifacts/config if any references exist

For clauses:

  • MUST only allow deletion if containing RFC is in draft status
  • MUST verify no other artifacts reference the clause ID before deletion
  • MUST error with list of referencing artifacts if references exist

For work items:

  • MUST only allow deletion if status is queue
  • MUST verify no other artifacts reference the work item ID before deletion
  • MUST error with list of referencing artifacts if references exist

General Deletion Behavior:

  • SHOULD require confirmation unless --force flag provided
  • MUST be atomic (either fully succeeds or fully fails)

Rationale: Permanent deletion breaks referential integrity. These constraints ensure deletions are safe and don’t leave dangling references in the governance graph.

Consistency Requirements:

  1. All CRUD verbs MUST use the same flag names across resource types
  2. Error messages MUST follow the same format across all verbs
  3. Exit codes MUST be consistent (0 = success, non-zero = error)
  4. Stdin handling MUST work identically across all verbs that accept it

Forbidden Variations:

  • MUST NOT use different verb names for the same operation (e.g., “show” vs “get”)
  • MUST NOT reorder arguments between resource types (ID always comes before field)
  • MUST NOT have resource-specific flags for universal operations. Flags that filter by a cross-resource metadata field (e.g., --tag) are permitted on resources that carry that field and silently ignored or unavailable on resources that do not.

Tags: cli, editing

Since: v0.1.0

[RFC-0002:C-LIFECYCLE-VERBS] Resource-Specific Lifecycle Verbs (Normative)

Resource-specific lifecycle verbs implement state transitions defined in RFC-0001. These verbs MUST be scoped to their resource namespace.

RFC Lifecycle Verbs:

  1. govctl rfc finalize <id> <normative|deprecated>

  2. govctl rfc advance <id> <spec|impl|test|stable>

  3. govctl rfc bump <id> <patch|minor|major> -m <message>

    • Version bumping per semantic versioning
    • Updates changelog automatically
    • Optional: --change <description> for additional changelog entries
  4. govctl rfc supersede <id> --by <replacement-id>

    • Marks RFC as superseded by another RFC
    • Both RFCs must exist

ADR Lifecycle Verbs:

  1. govctl adr accept <id>

  2. govctl adr reject <id>

  3. govctl adr supersede <id> --by <replacement-id>

Work Lifecycle Verbs:

  1. govctl work move <id> <queue|active|done|cancelled>
    • Implements RFC-0001:C-WORK-STATUS transitions
    • Validates gate conditions (e.g., acceptance criteria for done)
    • Updates timestamp fields automatically

Clause Lifecycle Verbs:

  1. govctl clause deprecate <id>

  2. govctl clause supersede <id> --by <replacement-id>

Consistency Requirements:

  1. All lifecycle verbs MUST validate transitions per RFC-0001
  2. All lifecycle verbs MUST update timestamp fields where applicable
  3. All lifecycle verbs MUST be atomic (no partial state changes)
  4. All lifecycle verbs MUST support global --dry-run flag
  5. Invalid transitions MUST error with clear explanation of valid transitions

Rationale:

Lifecycle verbs are resource-specific because:

  • RFCs have status AND phase (two dimensions of state)
  • ADRs can be rejected (not applicable to RFCs)
  • Work items have gate conditions (acceptance criteria)
  • Each resource has different valid transitions

Scoping these verbs to resources makes their applicability explicit and prevents confusion.

Tags: cli, lifecycle

Since: v0.1.0

[RFC-0002:C-OUTPUT-FORMAT] Output Format Control (Normative)

All commands that output resource data MUST support the --output (or -o) flag with the following format options:

Required Output Formats:

  1. table (default for human use)

    • Formatted tables with headers and aligned columns
    • MAY use colors when terminal supports them
    • MUST be readable in plain text (no control codes in non-TTY)
  2. json

    • Valid JSON output
    • Pretty-printed with 2-space indentation
    • MUST be parseable by standard JSON tools
  3. yaml

    • Valid YAML output
    • Formatted for readability
    • MUST be parseable by standard YAML tools
  4. toml

    • Valid TOML output (native format for governance artifacts)
    • MUST be parseable by standard TOML tools
  5. plain

    • Plain text values with no formatting
    • One value per line for lists
    • Single value (no newline) for scalar fields
    • Suitable for shell scripting and piping

Applicability:

Commands MUST support output formats as follows:

  • get with no field: table, json, yaml, toml
  • get with field: plain (default), json, yaml
  • list: table (default), json, yaml

Commands MAY add format-specific flags (e.g., --format-json-compact) but MUST NOT remove or change behavior of standard formats.

Format Selection:

  1. Explicit --output <format> takes precedence
  2. If not specified:
    • For TTY: default is table
    • For non-TTY: default MUST be json
  3. Invalid format names MUST error with list of valid formats

Exceptions:

govctl status is exempt from output format requirements and always produces human-readable tabular output intended for interactive use only.

Consistency Requirements:

  1. JSON/YAML/TOML output MUST match the internal schema exactly
  2. Table format MAY omit fields for readability but MUST show all critical fields
  3. Plain format MUST output stable, parseable text (no decorations)
  4. Output format MUST NOT affect command semantics (same data, different representation)

Rationale:

Universal output format control enables:

  • Human readability (table)
  • Script automation (json/yaml)
  • Integration with standard tools (jq, yq)
  • Native format inspection (toml for governance artifacts)

This pattern follows kubectl and Docker conventions where -o json works on all read operations.

Tags: cli

Since: v0.1.0

[RFC-0002:C-GLOBAL-COMMANDS] Global Commands (Normative)

The following commands operate at the project or CLI level and MUST remain at the global namespace level rather than under an artifact resource namespace:

1. govctl init

Initializes a new govctl project in the current directory.

Syntax: govctl init [--force]

Behavior:

  • Creates gov/ directory structure
  • Generates gov/config.toml
  • Creates subdirectories for rfcs, adrs, work items, and verification guards
  • Installs bundled JSON Schema files under gov/schema/
  • MUST error if already initialized (unless --force)
  • MUST NOT install agent skills or agents (see init-skills)
  • SHOULD print a hint about govctl init-skills and plugin installation

2. govctl check

Validates all governance artifacts across the project.

Syntax: govctl check [--deny-warnings]

Behavior:

  • Validates RFCs, ADRs, clauses, work items, releases, and verification guards
  • Implementations MUST define a corresponding machine-readable JSON Schema for each governance artifact type: RFC, clause, ADR, work item, release, and verification guard
  • These schemas MUST be JSON files stored under gov/schema/
  • For TOML artifacts, MUST validate structure against the corresponding JSON Schema after parsing and normalization
  • Checks state machine invariants
  • Verifies cross-references
  • Validates the semantic correctness of the optional [verification] section in gov/config.toml, including that configured default guard IDs resolve
  • Scans source code for references (if enabled in config)
  • If legacy JSON RFC or clause storage files are detected, MUST fail with a migration-required diagnostic that instructs users to run govctl migrate with a govctl version earlier than 0.9 before upgrading
  • If any bundled JSON Schema file under gov/schema/ is missing or differs from the current bundled schema, MUST report a schema-outdated diagnostic that instructs users to run govctl migrate
  • If any govctl-managed local-state .gitignore entry is missing or outdated, MUST report a project-support-outdated diagnostic that instructs users to run govctl migrate
  • Returns exit code 0 if valid, non-zero if errors
  • With --deny-warnings: treats warnings as errors

3. govctl status

Shows summary counts of all artifacts grouped by status.

Syntax: govctl status

Behavior:

  • Displays counts by status/phase for each resource type
  • Highlights active work items
  • Shows pending decisions (proposed ADRs, draft RFCs)
  • Uses colors in TTY mode for visual scanning
  • No output format flag (always human-readable table)

4. govctl render

Generates markdown documentation from source-of-truth governance artifacts.

Syntax: govctl render [targets...] [--output-dir PATH] [--dry-run]

Behavior:

  • Renders RFCs from TOML to markdown (published)
  • Renders ADRs from TOML to markdown (local only)
  • Renders work items from TOML to markdown (local only)
  • Generates CHANGELOG.md from releases
  • Default: renders RFCs only
  • With targets: rfc, adr, work, changelog, all
  • MUST validate before rendering

5. govctl describe

Outputs machine-readable CLI metadata for agent/tool integration.

Syntax: govctl describe [--context]

Behavior:

  • Outputs JSON with command catalog
  • Includes workflow information
  • With --context: adds current project state and suggested actions
  • Enables machine agents and automation to discover capabilities safely

Stability Contract:

The JSON schema of govctl describe output MUST be versioned. The schema version MUST be included in the output. Backward-incompatible changes to the schema require a major version bump of govctl.

This ensures agents and automation tools can rely on stable introspection.

6. govctl completions

Generates shell completion scripts.

Syntax: govctl completions <bash|zsh|fish|powershell>

Behavior:

  • Outputs completion script for specified shell
  • Can be sourced or installed per shell conventions

7. govctl migrate

Performs versioned repository-local format migration for governance artifacts.

Syntax: govctl migrate [--dry-run]

Behavior:

  • Reads the current schema version from gov/config.toml [schema] version
  • Runs all pending migration steps from the current version to the latest
  • Each step produces a set of file operations executed transactionally
  • Bumps [schema] version in gov/config.toml after successful migration
  • MUST leave the repository unchanged if any step fails
  • MUST be safe to run on an already-migrated repository and report a no-op result
  • MUST NOT perform heuristic project discovery or broad adoption tasks
  • MUST ensure all bundled JSON Schema files exist in gov/schema/, overwriting with the latest version regardless of schema version
  • MUST ensure local govctl state ignore entries are present in .gitignore, including .govctl.lock and .govctl/, regardless of schema version
  • In govctl 0.9 and later, MUST NOT convert legacy JSON RFC or clause storage; repositories with those files MUST be migrated with a govctl version earlier than 0.9 before upgrading

8. govctl verify

Executes reusable verification guards.

Syntax:

  • govctl verify [GUARD-ID ...]
  • govctl verify --work WI-ID

Behavior:

  • Loads Verification Guard artifacts from gov/guard/
  • Explicit GUARD-ID arguments and --work WI-ID MUST NOT be combined in the same invocation
  • With explicit GUARD-ID arguments: runs those guards
  • With --work WI-ID: runs the effective required guards for that work item after applying project defaults and work-item waivers
  • With no explicit guards and no --work: runs the project-level default guards from gov/config.toml
  • Reads project-level verification policy from RFC-0002:C-VERIFY-CONFIG
  • Executes each guard command non-interactively from the project root
  • Reports pass/fail per selected guard
  • Returns non-zero if any selected guard fails, if no guards are selected, or if a requested guard ID is unknown

9. govctl init-skills

Installs agent skills and agents into the project’s agent directory.

Syntax: govctl init-skills [--force] [--format <claude|codex>] [--dir PATH]

Behavior:

  • --dir overrides the output directory for this invocation. Resolution order: --dir flag > agent_dir from config > format-implied default (.claude for claude, .codex for codex)
  • --format selects the output format for agent definitions (default claude):
    • claude: skills as full skills/*/ bundles rooted at SKILL.md, agents as agents/*.md with YAML frontmatter (compatible with Claude Code, Cursor, Windsurf, and similar editors)
    • codex: skills as full skills/*/ bundles rooted at SKILL.md (same format), agents as agents/*.toml with developer_instructions field (compatible with Codex CLI)
  • Skill bundle resources under directories such as references/, assets/, and scripts/ MUST be installed with their parent skill; agent output remains format-specific
  • Skips files that already exist unless --force is used
  • Reports created/updated/skipped counts
  • This command is separate from init because plugin users receive skills globally and do not need local copies

10. govctl tag

Manages the project’s controlled tag vocabulary.

Syntax:

  • govctl tag new <tag>
  • govctl tag delete <tag>
  • govctl tag list

Behavior:

  • new: registers a new tag in gov/config.toml under [tags] allowed. Tags MUST match [a-z][a-z0-9-]* (lowercase kebab-case). MUST error if the tag already exists.
  • delete: removes a tag from the allowed list. MUST error if any artifact still references the tag.
  • list: displays all registered tags with usage counts (how many artifacts reference each tag).

Artifact-level tagging uses existing resource verbs on taggable types (rfc, clause, adr, work, guard):

  • govctl {rfc|clause|adr|work|guard} add <ID> tags <tag> - assign a tag to an artifact
  • govctl {rfc|clause|adr|work|guard} remove <ID> tags <tag> - remove a tag from an artifact

11. govctl self-update

Updates the govctl binary to the latest release.

Syntax: govctl self-update [--check]

Behavior:

  • Downloads and replaces the running binary from GitHub Releases
  • With --check: prints version comparison without downloading
  • Full specification in RFC-0002:C-SELF-UPDATE

12. govctl loop

Manages project-local loop execution state for driving work items through iterative rounds.

Syntax: govctl loop <subcommand> [arguments] [flags]

Behavior:

  • Operates on local execution state under .govctl/loops/, not on a governed artifact resource
  • Coordinates work items, verification guards, and local loop state according to RFC-0006
  • MUST NOT expose universal CRUD field-editing verbs for loop state
  • MUST keep work item lifecycle transitions routed through govctl work semantics
  • MUST use stable subcommand and argument semantics defined by RFC-0006:C-LOOP-COMMAND-SURFACE

13. govctl search

Searches governed artifacts across the project by user-provided query text.

Syntax: govctl search <query>... [--type <rfc|clause|adr|work|guard>]... [--tag <tag>]... [-n <limit>] [-o <table|json|plain>] [--reindex]

Behavior:

  • Operates across RFCs, clauses, ADRs, work items, and verification guards according to RFC-0002:C-SEARCH-COMMAND
  • MUST remain at the global namespace because it is project-level discovery across multiple governed resource types, not a resource-specific CRUD operation
  • MUST NOT be required as a universal resource verb under each artifact namespace unless a future RFC amendment explicitly adds scoped search aliases

Rationale:

These commands are global because they:

  1. Operate on multiple resource types simultaneously
  2. Don’t fit the <resource> <verb> pattern semantically
  3. Are project-level operations, not resource-level
  4. Match user mental model of “project commands” vs “resource commands”
  5. May manage local execution state that coordinates governed resources without becoming a governed resource itself

govctl migrate qualifies because it operates across the governance repository as a whole and changes multiple resource types in one coordinated step.

govctl verify qualifies because it executes project-level completion checks that may be required by multiple work items and by the project configuration.

govctl init-skills qualifies because it performs project-level initialization of agent assets (criterion 2).

govctl tag qualifies because it manages project-level configuration that applies across all resource types (criterion 1).

govctl self-update qualifies because it provides meta-information about the CLI itself and performs binary lifecycle management (criterion 3).

govctl loop qualifies because it manages local execution state that coordinates work items and verification guards without making loop state a governed resource (criterion 5).

govctl search qualifies because it performs project-level discovery across multiple governed resource types (criterion 1).

Future Additions:

New global commands MAY be added via RFC amendment. They MUST meet at least one criterion:

  1. Operate on multiple resource types
  2. Perform project-level initialization or cleanup
  3. Provide meta-information about the CLI itself
  4. Manage local execution state that coordinates governed resources without becoming a governed resource itself

Tags: cli

Since: v0.1.0

[RFC-0002:C-VERIFY-CONFIG] Verification Configuration (Normative)

The project config file gov/config.toml MAY include an optional [verification] section.

When present, the section MUST support the following fields:

  • enabled — boolean, default false
  • default_guards — array of Verification Guard IDs, default []

If the section is absent, the implementation MUST behave as if enabled = false and default_guards = [].

Every guard ID listed in default_guards MUST resolve to an existing Verification Guard defined by RFC-0000:C-GUARD-DEF. Unknown IDs MUST cause validation failure.

When enabled = false, project-level default guards MUST NOT be applied automatically by govctl verify or by Work Item completion checks.

Work Item verification.required_guards remain effective regardless of the project-level enabled value.

Rationale: The project config controls whether shared default guard policy is active. Explicit Work Item requirements remain local and auditable instead of becoming inert metadata.

Tags: cli, validation

Since: v0.3.0

[RFC-0002:C-SELF-UPDATE] Self-Update Command (Normative)

11. govctl self-update

Updates the govctl binary to the latest release.

Syntax: govctl self-update [--check]

Behavior:

  • Queries the GitHub Releases API for the govctl-org/govctl repository to determine the latest published version
  • Compares the latest version against the running binary’s compiled version
  • Without --check: downloads the platform-appropriate binary asset, verifies integrity, and replaces the running executable. MUST print the old and new version on success. MUST exit with code 0 if already up to date, printing a message indicating no update is needed.
  • With --check: prints current version and latest available version without downloading. MUST exit with code 0 if up to date, exit with code 1 if a newer version is available.
  • MUST detect the current platform target at compile time and select the matching release asset
  • MUST display download progress when connected to a TTY
  • MUST error with a clear message if the binary lacks write permission to its install location
  • MUST error with a clear message if the GitHub API is unreachable or rate-limited
  • SHOULD support GITHUB_TOKEN environment variable for authenticated API requests to avoid rate limits

Rationale:

A self-update command provides a single canonical update path that works regardless of how govctl was originally installed (cargo install, cargo binstall, or direct binary download). This meets criterion 3 of RFC-0002:C-GLOBAL-COMMANDS (meta-information about the CLI itself).

Tags: cli, release

Since: v0.8.0

[RFC-0002:C-SEARCH-COMMAND] Search Command (Normative)

govctl search searches governed artifacts by user-provided query text.

Syntax:

  • govctl search <query>... [--type <rfc|clause|adr|work|guard>]... [--tag <tag>]... [-n <limit>] [-o <table|json|plain>] [--reindex]

Behavior:

  • The command MUST operate at the global command namespace as an explicit RFC-0002:C-RESOURCE-MODEL exception listed in RFC-0002:C-GLOBAL-COMMANDS, because it searches across multiple governed resource types and is project-level discovery rather than a resource-specific CRUD operation.
  • The command MUST search RFCs, clauses, ADRs, work items, and verification guards unless one or more --type filters are provided.
  • Positional <query>... values MUST be interpreted as user search terms by default, not as backend-specific raw query syntax.
  • The command MUST support artifact ID lookup as a search use case. A query containing an existing artifact ID SHOULD rank that artifact ahead of lower-confidence full-text matches.
  • The command MUST support --tag <tag> filters. When multiple tags are provided, returned artifacts MUST contain all requested tags.
  • The command MUST support -n, --limit <limit> and MUST apply a finite default limit when the flag is omitted.
  • The command MUST support --reindex, which forces a rebuild of any local derived search index before returning results.
  • The command MUST NOT modify governed artifact files or rendered documentation.
  • If the implementation persists a search index, it MUST store that index under .govctl/ local state and MUST NOT store it under gov/ or the rendered docs directory.
  • A persisted search index is derived local state and MUST NOT be treated as an authoritative artifact source. TOML governance artifacts remain the source of truth.
  • The command MUST establish index freshness before returning indexed results. If freshness cannot be established, the command MUST rebuild the index, perform an uncached authoritative scan, or return a diagnostic. It MUST NOT silently return stale indexed results.
  • Search index synchronization MAY mutate .govctl/ local state. This local-state mutation MUST NOT require the RFC-0004 gov-root exclusive write lock because it does not mutate governed artifacts or rendered documentation.
  • Output rows MUST include at least artifact kind, artifact ID, title, source path, and a match snippet or equivalent human-readable context.
  • JSON output MUST expose stable result fields including kind, id, title, path, and snippet. It MAY include ranking score and status metadata.
  • Plain output MUST emit one artifact ID per line in result order.

Rationale:

Search is discovery across the governance corpus, not a resource-specific CRUD operation. Keeping indexes under .govctl/ preserves the boundary between authoritative governed artifacts and disposable local execution or cache state. Requiring freshness before returning results prevents the local index from becoming a misleading second source of truth.

Since: v0.10.1


Changelog

v0.10.2 (2026-06-08)

Clarify init-skills skill bundle installation

Changed

  • init-skills installs full skill bundles rooted at SKILL.md, including bundled references/assets/scripts

v0.10.1 (2026-06-04)

Set search clause version metadata

Fixed

  • C-SEARCH-COMMAND has derived since version metadata

v0.10.0 (2026-06-04)

Add search command contract

Added

  • C-SEARCH-COMMAND clause for govctl search

v0.9.4 (2026-06-04)

Narrow project support diagnostics

Changed

  • project-support diagnostics are scoped to govctl-managed local-state .gitignore entries

v0.9.3 (2026-06-04)

Clarify edit path addressing

Changed

  • edit operations use deterministic path-based addressing for arrays and nested fields

v0.9.2 (2026-06-04)

Clarify project support file sync

Changed

  • govctl check and migrate cover project support file freshness

v0.9.1 (2026-06-04)

Require check to surface stale bundled schemas

Changed

  • govctl check reports missing or stale bundled schema files and instructs users to run govctl migrate

v0.9.0 (2026-06-04)

Remove legacy JSON migration support

Removed

  • govctl migrate no longer converts legacy RFC or clause JSON storage in v0.9 and later

v0.8.0 (2026-04-13)

Add self-update global command (ADR-0041)

Added

  • C-SELF-UPDATE clause for govctl self-update command

Changed

  • C-GLOBAL-COMMANDS updated with entry 11 and rationale for self-update

v0.7.0 (2026-04-09)

Add controlled-vocabulary tags: tags field on RFC/clause/ADR/work/guard, –tag filter on list, govctl tag new/delete/list for registry management (ADR-0040)

v0.6.1 (2026-04-08)

Add –dir flag to init-skills for one-step directory override without config editing

v0.6.0 (2026-04-08)

Add –format flag to init-skills for cross-platform agent format support (claude/codex)

v0.5.0 (2026-03-27)

Add guard as a resource type with CRUD verbs

Added

  • Added guard to C-RESOURCES as resource type 5 (renumbered release to 6)
  • Updated C-CRUD-VERBS with guard-specific verb applicability
  • Updated C-RESOURCE-MODEL to include guard in resource list

v0.4.0 (2026-03-17)

Add init-skills command, update init and migrate per ADR-0035

Added

  • init-skills global command for explicit agent asset installation

Changed

  • init no longer installs skills/agents
  • migrate now ensures schema JSON files are up to date

v0.3.0 (2026-03-17)

Add project-level verification command and config semantics

Added

  • Added global verify command and verification config contract

v0.2.0 (2026-01-19)

Incorporate review feedback: add deletion safety constraints, field name stability, output format defaults, describe schema versioning, and editorial clarifications

Added

  • Added deletion safety constraints requiring draft RFCs and reference checks
  • Added field name stability guarantee for get command
  • Specified json as default output format for non-TTY
  • Added status command exception to output format requirements
  • Added describe command schema versioning contract
  • Clarified clause namespace vs filesystem storage independence
  • Added case-sensitivity and timestamp format requirements

v0.1.0 (2026-01-19)

Initial draft

RFC-0003: TUI UX improvements

Version: 0.1.0 | Status: normative | Phase: stable


1. Summary

[RFC-0003:C-SUM] Summary (Informative)

  • Define a consistent TUI navigation frame with shared header and footer.
  • Add list filtering and quick-jump for faster browsing.
  • Improve detail view readability with consistent layout and scroll position.

Tags: tui

Since: v0.1.0


2. Specification

[RFC-0003:C-NAV] Shared header/footer navigation (Normative)

  • The TUI MUST render a persistent header and footer across all views.
  • The header MUST show the current view hierarchy (breadcrumb) and basic counts for the active view.
  • The footer MUST provide the current keymap for primary navigation, including quit and back.
  • Existing navigation keys MUST remain functional.

Tags: tui

Since: v0.1.0

[RFC-0003:C-FILTER] List filtering and quick-jump (Normative)

  • List views MUST support an inline filter mode that matches ID, title, or status.
  • Filter mode MUST be entered with a single key and exited without leaving the list view.
  • When a filter is active, the list MUST show only matching items and navigation MUST operate over the filtered set.
  • List views MUST support quick-jump to top and bottom and allow stepping through matches.

Tags: tui

Since: v0.1.0

[RFC-0003:C-DETAIL] Detail view readability (Normative)

  • Detail views MUST present metadata and content sections consistently across artifact types.
  • Detail views MUST show scroll position to indicate where the user is within the content.
  • Scrolling MUST not lose the current view context or selection.

Tags: tui

Since: v0.1.0


Changelog

v0.1.0 (2026-02-07)

Initial draft

RFC-0004: Concurrent write safety for governance artifacts

Version: 0.1.0 | Status: normative | Phase: stable


1. Summary

[RFC-0004:C-SUMMARY] Summary (Informative)

This RFC specifies that govctl MUST preserve integrity of governance artifacts when multiple processes invoke write operations concurrently (e.g. agent-triggered parallel tasks creating or editing RFCs, ADRs, or work items).

Scope: Applies to any command that modifies files under the gov root or writes rendered output under the docs root. The concrete mechanism to satisfy this requirement is an implementation detail.

Backward compatibility: Existing command invocations and arguments remain valid. This RFC adds only coordination and failure behaviour; it does not change command semantics.

Specification outline: The RFC defines terms (write command, read-only command, concurrent invocations, corrupted file); requires that every write command participate in a single global concurrency mechanism and that read-only commands never block on it; requires that concurrent writes never produce corrupted files, duplicate work item IDs, or lost read-modify-write updates; and requires predictable failure behaviour (bounded wait, then either proceed or fail with an actionable error) when the mechanism cannot be acquired.

Rationale: Concurrent writes without coordination cause file corruption, duplicate IDs, and lost updates. Agents and scripts often run multiple govctl invocations in parallel; the implementation must prevent observable corruption and provide clear behaviour on conflict.

Tags: safety

Since: v0.1.0


2. Specification

[RFC-0004:C-CONCURRENT-WRITE] Concurrent write safety (Normative)

Commands that modify the governance tree or rendered output MUST use a concurrency mechanism such that:

  1. No two concurrent invocations (across processes) produce corrupted artifact files. Corrupted means: invalid JSON/TOML, truncated content, or interleaved content from different writes.
  2. Work item creation MUST NOT assign the same ID to two items created by concurrent invocations when both use the same ID prefix (e.g. same date under sequential or author-hash strategy). The scenario is same repository, concurrent processes (distinct from branch-merge ID collision).
  3. Read-modify-write operations (e.g. edit, set, bump) MUST NOT lose updates from another concurrent invocation modifying the same artifact.

This RFC requires the observable behaviour: artifact integrity and no duplicate IDs under concurrent write load. The concrete mechanism (e.g. process-level filesystem locking) is an implementation detail.

Rationale: Agents and CI may run multiple govctl write commands in parallel. Without a defined concurrency strategy, races are observable in practice (file corruption, duplicate WI IDs). The normative requirement ensures implementors address this.

Tags: safety

Since: v0.1.0

[RFC-0004:C-DEFINITIONS] Definitions (Informative)

Write command: A govctl invocation that may create, modify, or delete files under the gov root, or write files under the docs root (e.g. render output). Any invocation that writes files under the docs root is a write command regardless of command name. Examples: rfc new, adr new, work new, rfc set, adr set, work set, rfc edit, adr edit, work edit, clause new, clause edit, rfc bump, rfc finalize, rfc advance, adr accept, work tick, work move, render.

Read-only command: A govctl invocation that does not modify gov or docs. Examples: rfc list, adr list, work list, rfc get, adr get, work get, check, status. The commands show and describe are read-only when they do not write to gov or docs (e.g. when they output only to stdout).

Concurrent invocations: Two or more govctl processes running at the same time, such that their execution may overlap (e.g. multiple agent tasks, or a script spawning parallel govctl calls).

Corrupted artifact file: A file under gov or docs that does not conform to the expected schema (invalid JSON or TOML), or that contains truncated or interleaved content from more than one logical write.

Rationale: These definitions make the scope and guarantees of this RFC testable and unambiguous.

Tags: safety

Since: v0.1.0

[RFC-0004:C-FAILURE-BEHAVIOUR] Behaviour when concurrency mechanism is unavailable (Normative)

When a write command cannot obtain exclusive access (e.g. because another write command is in progress), the implementation MUST either wait for a bounded time and then proceed, or wait for a bounded time and then fail. The maximum wait time is implementation-defined and MUST be documented. Implementations SHOULD use a default maximum wait of at least 30 seconds for interoperability and testability. The maximum wait time MAY be configurable.

If the implementation chooses to fail after waiting, it MUST exit with a non-zero status and MUST emit an actionable error message that indicates that another govctl write is in progress and that the user or agent should retry later. The message MUST NOT assume a specific concurrency mechanism (e.g. must not require the word “lock”).

If the implementation waits until access is granted, it MUST eventually proceed; it MUST NOT deadlock.

Implementations SHOULD ensure that exclusive access is released on process exit or that time-based expiry or stale-lock cleanup applies, so that a crashed process does not block writers indefinitely.

Rationale: Predictable failure behaviour allows agents and scripts to retry or serialise writes; clear errors avoid confusion. A documented, implementation-defined bound makes conformance testable; the 30-second SHOULD gives implementations and tests a shared expectation. The stale-lock note supports the “MUST NOT deadlock” requirement when a holder crashes.

Tags: safety

Since: v0.1.0

[RFC-0004:C-SCOPE] Scope of write commands (Normative)

Every write command MUST participate in the concurrency mechanism before performing any mutation of the gov tree or docs output. Participation means acquiring exclusive access (or equivalent) for the duration of the write operations performed by that invocation.

Read-only commands MUST NOT acquire exclusive access and MUST NOT block on the concurrency mechanism. They MAY run concurrently with each other and with at most one write command.

The concurrency mechanism SHALL apply to the entire gov root (and, when a command writes rendered output, to the docs root) as a single unit. Exclusive access MUST NOT be held by more than one write command at the same time.

Rationale: Defining scope ensures that all mutation paths are covered and that read-only usage is never blocked by writers.

Tags: safety

Since: v0.1.0


Changelog

v0.1.0 (2026-02-15)

Initial draft

RFC-0006: Loop Execution Model

Version: 0.4.0 | Status: normative | Phase: impl


1. Summary

[RFC-0006:C-SUMMARY] Summary (Informative)

This RFC defines the loop execution model for coordinating local agent execution rounds around one or more Work Items.

A loop is a first-class local execution concept that tracks one or more Work Items through dependency-aware rounds of implementation, verification evidence collection, and refinement. Loops support:

  • Single Work Item execution context: Create resumable local round state for one Work Item
  • Multi-Work Item batch execution context: Coordinate several Work Items with dependency resolution and deterministic readiness ordering
  • Failure and blocker propagation: Represent failed, blocked, or cancelled loop-level outcomes without adding new Work Item lifecycle states
  • Resumption: Resume interrupted execution from loop state and round artifacts

The loop model maintains clear separation between:

  • Work Items: Durable outcome artifacts that contain scope (description), success criteria (acceptance_criteria), durable memory (notes), references, dependencies, and verification policy
  • Loop state: Local execution state that tracks rounds, selected work, summary evidence, blockers, and next action

This separation ensures Work Items remain clean outcome artifacts while enabling rich local execution traceability for debugging and resumption.

Loops interact with Work Item lifecycle exclusively through existing govctl work semantics. govctl loop run advances local round state; it does not implement code, tick acceptance criteria, add notes, or mark Work Items done on behalf of the agent.

Tags: core

Since: v0.1.0


2. Specification

[RFC-0006:C-LOOP-DEFINITION] Loop Definition (Normative)

A loop is a local execution session that coordinates one or more Work Items through iterative rounds of agent implementation, verification evidence collection, and refinement.

Each loop MUST:

  1. Be initialized from an explicit, finite root set of Work Items
  2. Resolve the transitive dependency closure before execution begins
  3. Recompute the transitive dependency closure after any successful scope mutation defined by RFC-0006:C-LOOP-SCOPE-MUTATION
  4. Track execution state independently of Work Item files
  5. Store transient round evidence in loop-local artifacts rather than Work Item fields
  6. Terminate when all Work Items in the current resolved loop set reach terminal loop-level outcomes or a failure condition is met

A loop MAY support explicit scope mutation after start. A scope mutation MUST be requested through loop commands; implementations MUST NOT treat unrelated Work Item file edits as implicit loop scope changes.

A loop MUST NOT:

  1. Modify Work Item files directly except by invoking existing govctl work command semantics where explicitly required
  2. Persist execution trace to Work Item fields; execution trace belongs in loop state and round artifacts
  3. Assume a specific implementation order (sequential or parallel) beyond dependency readiness
  4. Introduce parallel replacements for Work Item notes, depends_on, acceptance criteria, or verification guards

Rationale: Loops are a first-class execution concept that coordinates Work Item completion without becoming a second Work Item model. By keeping loops separate from Work Item files, govctl preserves the boundary between local execution trace (ephemeral) and governance artifacts (durable). Work Item notes hold durable constraints and learnings that should survive future work; loop state holds transient execution evidence. Explicit scope mutation lets long cleanup loops adapt without replacing the execution session identity.

Tags: core

Since: v0.1.0

[RFC-0006:C-LOOP-LIFECYCLE] Loop Lifecycle (Normative)

A loop MUST have exactly one of the following lifecycle states:

  1. pending — Initial state. The loop is defined but execution has not started.
  2. active — The loop is currently executing rounds on work items.
  3. paused — Execution stopped before a terminal outcome and may be resumed.
  4. completed — All work items in the resolved loop set reached non-failed terminal loop outcomes (done or cancelled) without any failed or blocked loop outcomes.
  5. failed — A failure condition was met (max rounds exceeded, critical error, failed work item, or blocked dependency chain).

Valid transitions:

  • pending → active (loop execution begins)
  • active → paused (loop pauses for resumption)
  • paused → active (loop execution resumes)
  • active → completed (all work items finish without failed or blocked outcomes)
  • active → failed (failure condition met)
  • paused → failed (resumption detects unrecoverable state)

Invalid transitions (MUST be rejected):

  • completed → any (terminal state)
  • failed → any (terminal state)
  • pending → completed (cannot complete without being active)
  • pending → failed (cannot fail without being active)
  • paused → completed (completion requires active execution)

Rationale: The loop lifecycle provides clear semantics for tracking execution progress and enables resumption after interruption. A distinct paused state avoids overloading pending, which means execution has not started. Terminal states (completed, failed) indicate the loop has finished and cannot be restarted.

Tags: lifecycle, core

Since: v0.1.0

[RFC-0006:C-DEPENDENCY-SEMANTICS] Work Item Dependency Semantics (Normative)

Work items MAY declare dependencies on other work items using the depends_on field in the [govctl] section. The depends_on field MUST contain a list of work item IDs.

The depends_on field is an optional Work Item metadata field for repositories implementing this RFC. Implementations that validate Work Items against a JSON Schema MUST include govctl.depends_on as an optional array of Work Item IDs in that schema.

At loop start, and after every scope mutation, the loop MUST resolve the dependency closure for the current explicit root set. The resolved loop set MUST include every transitive depends_on dependency needed by the current root set. If any dependency ID does not identify an existing Work Item, the loop start or scope mutation MUST be rejected before the new state becomes authoritative.

Dependency rules:

  1. Acyclicity: The dependency graph MUST be acyclic. Implementations MUST detect cycles at loop start and after scope mutation and reject the operation before the new state becomes authoritative. The diagnostic MUST include at least one Work Item ID from the detected cycle.

  2. Selection readiness: A work item MUST NOT be selected for new round work until every dependency has a terminal loop-level outcome.

  3. Outcome checking: After a dependency reaches a terminal loop-level outcome, the loop MUST check that outcome:

    • If all dependencies are done: the dependent work item MAY be selected for round work
    • If any dependency is cancelled, failed, or blocked: the dependent work item MUST be marked as blocked in loop state and MUST NOT be selected
  4. Distinction from refs: The depends_on field is distinct from refs:

    • refs: informational cross-references to related artifacts (RFCs, ADRs, work items)
    • depends_on: blocking execution dependencies (work items only)
  5. Failure propagation: When a work item is marked as blocked, all work items that depend on it (directly or transitively) MUST also be marked as blocked.

Loop-level status tracking: The blocked, failed, and cancelled states are loop-level execution statuses tracked in loop state, not additional Work Item status field values. Work Items maintain their own lifecycle states (queue, active, done, cancelled) per RFC-0001:C-WORK-STATUS. A Work Item with Work Item status cancelled MUST be represented as cancelled in loop state when it is part of the resolved loop set.

Rationale: Dependencies enable complex workflows where work items must be selected in a specific order. By keeping depends_on separate from refs, we maintain clear semantics: refs are informational, depends_on are blocking. Resolving a dependency closure preserves an explicit root set while ensuring the loop has every prerequisite needed for deterministic planning. Re-resolving after explicit scope mutation lets a long-running loop adapt to corrected or newly discovered work without losing its execution session. Loop-level status tracking avoids polluting the Work Item status field with execution-specific states.

Tags: lifecycle, validation, work-items

Since: v0.1.0

[RFC-0006:C-ROUND-EXECUTION] Round Execution (Normative)

Loop rounds are local execution-protocol checkpoints for one loop, not automatic implementation performed by govctl.

A loop round MAY cover one or more work items from the loop’s current resolved dependency closure. The selected work set for a round MUST be derived from the loop state, dependency readiness, and any explicit --work selector accepted by RFC-0006:C-LOOP-COMMAND-SURFACE.

Round lifecycle:

Each round MUST have one of these local round states:

  1. open — govctl has created the round skeleton and the agent is expected to implement, verify, and fill the summary evidence.
  2. submitted — the round summary evidence has been provided but has not yet been incorporated into authoritative loop state.
  3. closed — govctl has validated the round evidence and updated loop state.

govctl loop run LOOP-ID MUST advance the local round protocol. It MUST NOT implement repository changes itself. It MUST NOT mark a Work Item done directly merely because loop-local criteria appear satisfied. Work Item lifecycle transitions remain owned by govctl work move per RFC-0002:C-LIFECYCLE-VERBS.

Opening a round:

When no open round exists, loop run MUST:

  1. Load and validate the loop state.
  2. Re-read current Work Item files for the selected work set.
  3. Verify dependency readiness using RFC-0006:C-DEPENDENCY-SEMANTICS.
  4. Create a loop-level round artifact under the loop directory.
  5. Write a summary skeleton that records where the agent MUST provide actions, changed paths, verification evidence, blockers, and note candidates.
  6. Display the round artifact path and the next required agent action.

Opening a round MAY update loop-local item statuses and round counters, but MUST NOT write transient execution trace into Work Item files.

Closing a round:

When an open round exists, loop run MUST validate the round summary before advancing loop state. A round summary MUST distinguish:

  • actions performed during the round
  • changed paths or explicitly state that no file changes were made
  • verification evidence, including existing govctl verify --work WI-ID or project guard output when applicable
  • blockers or open questions
  • note candidates that may become durable Work Item notes through explicit govctl work add <WI-ID> notes ...

If required summary evidence is missing, loop run MUST return a Diagnostic that names the round artifact to complete and MUST leave loop state unchanged.

If blockers prevent progress, loop run MUST keep the loop non-terminal and record the next action in loop state. Durable retry rules MAY be added to Work Item notes, but only through explicit Work Item commands.

If the relevant Work Items have already reached terminal Work Item lifecycle states through govctl work move, loop run MUST reflect those lifecycle states in loop-local item status and MAY mark the loop completed when every current resolved item is terminal without failed or blocked loop outcomes.

Rationale: govctl can coordinate local execution state, Work Item metadata, dependency readiness, and verification evidence, but the agent performs implementation work. This keeps loop execution trace in local loop artifacts, preserves Work Items as durable outcome artifacts, and reuses existing notes, depends_on, verify, and work move mechanisms instead of inventing parallel systems.

Tags: core, validation

Since: v0.1.0

[RFC-0006:C-WORK-ITEM-INTERACTION] Work Item Interaction (Normative)

Loops interact with work items by reading Work Item lifecycle state, mapping it into loop-local item state, and recording local execution evidence. Loops MUST NOT own Work Item lifecycle transitions.

Lifecycle ownership:

  1. Work Items in the resolved loop set MUST remain valid Work Items whose lifecycle state is one of queue, active, done, or cancelled.
  2. govctl loop run MUST NOT transition a Work Item from queue to active.
  3. govctl loop run MUST NOT transition a Work Item from active to done.
  4. Work Item lifecycle transitions remain owned by govctl work move and its existing acceptance-criteria and verification-guard gates.
  5. A Work Item with lifecycle state done MUST be represented as done in loop state when reflected by a loop operation.
  6. A Work Item with lifecycle state cancelled MUST be represented as cancelled in loop state when reflected by a loop operation and MUST NOT be selected for new round work.

Validation requirements:

Before a Work Item is transitioned to done, the Work Item lifecycle command MUST verify the existing gate conditions defined by RFC-0001:C-GATE-CONDITIONS. A loop MAY record verification evidence in round summary artifacts, but that evidence does not replace the Work Item lifecycle gate.

Durable work item context:

The work item notes field is reserved for durable context that should persist across sessions:

  • Key decisions made during implementation
  • Blockers encountered and how they were resolved
  • Important technical insights

Execution trace, including round-by-round progress, MUST be tracked in loop state and round artifacts, not in Work Item fields.

Loop-level work item status:

The loop tracks additional execution status for each work item in loop state:

  • pending: Work item has not been selected or reflected as active/done/cancelled in this loop
  • active: Work item is selected for local execution protocol or remains in progress
  • done: Work item completed successfully through Work Item lifecycle state
  • failed: Local loop execution evidence records an unrecoverable failure and dependents must not be selected
  • blocked: Work item cannot be selected because dependencies failed, blocked, or were cancelled
  • cancelled: Work item has Work Item status cancelled and is not selected

The loop-level statuses are independent of Work Item status field values except where explicitly mapped above. done, failed, blocked, and cancelled are terminal loop-level outcomes for dependency planning.

Rationale: Existing Work Item commands already provide lifecycle validation, acceptance criteria, verification guards, and durable governance history. Loops provide resumable local execution protocol state around those commands without becoming a second Work Item lifecycle engine. Separating loop-level status from Work Item status and notes maintains clear boundaries between execution state and governed artifacts.

Tags: lifecycle, validation, work-items

Since: v0.1.0

[RFC-0006:C-LOOP-RESUMPTION] Loop Resumption (Normative)

A loop MAY be paused and resumed across CLI invocations or agent sessions.

If a loop implementation supports resumption, it MUST:

  1. Persist loop state using the storage contract defined by RFC-0006:C-LOOP-STATE-STORAGE
  2. Resume existing loop operations by positional LOOP-ID as defined by RFC-0006:C-LOOP-COMMAND-SURFACE
  3. Resume from the last recorded state and open round artifact rather than starting fresh when the requested loop state exists and is non-terminal
  4. Reject operations that require a non-terminal loop when the loop is terminal

Discovery semantics:

Loop discovery MUST be separate from loop execution. Implementations MAY discover existing loops by listing persisted state, by filtering list output, or by reusing an existing non-terminal loop during loop start [--id LOOP-ID] WI-ID... when the requested work set matches exactly.

A stored loop matches a requested work set when its current editable work field contains the same Work Item IDs as the request, ignoring order. If a command performs work-set discovery and exactly one matching non-terminal loop exists, the implementation MAY select that loop. If more than one matching non-terminal loop exists, the implementation MUST reject the discovery attempt as ambiguous and require a positional LOOP-ID.

loop run MUST NOT perform work-set discovery and MUST NOT start a new loop.

Resumption semantics:

When resuming a loop:

  • Work items in done loop state MUST NOT be selected for new round work
  • Work items in active loop state MAY be selected again only through the local round protocol
  • Work items in blocked, failed, or cancelled loop state MUST remain terminal for dependency planning unless an explicit scope mutation recomputes a dependency-derived blocked outcome
  • Work items in pending loop state MAY be selected in dependency order when opening a round unless an explicit run selector narrows execution per RFC-0006:C-LOOP-COMMAND-SURFACE
  • If loop.current_round points at an open round artifact, loop run MUST validate or reject that artifact before opening another round

State preservation:

The loop state MUST preserve:

  • Execution status of each current work item (pending, active, done, failed, blocked, cancelled)
  • Round count for each current work item
  • Last selected round for each current work item when known
  • Current editable work field values
  • Dependency graph at last planning time
  • Current loop-level round number when known
  • Next required action when known

The loop state MAY preserve:

  • Detailed round history
  • Guard execution result summaries
  • Agent context and decision history inside local round artifacts

Rationale: Resumption enables long-running multi-WI loops to survive agent session boundaries without losing progress. Positional loop IDs provide precise lookup that matches the CLI’s noun/verb/object shape. Work-set matching remains a discovery convenience for start/list workflows, not an execution command mode. By persisting state independently of work item files, we maintain the separation between execution state and governed artifacts. Scope mutation makes the stored work set current rather than historical, so discovery continues to match the loop the user intends to resume.

Tags: lifecycle

Since: v0.1.0

[RFC-0006:C-LOOP-STATE-STORAGE] Loop State Storage (Normative)

Loop execution state MUST be stored under .govctl/loops/<loop-id>/.

A loop ID is local execution-state identity, not a governed resource ID. A generated loop ID MUST match ^LOOP-\d{4}-\d{2}-\d{2}-\d{3}$. The date component MUST use ISO 8601 calendar date format YYYY-MM-DD for the local date when the ID is generated. The sequence component MUST be a three-digit positive sequence starting at 001 for each date. Implementations MUST choose the first available sequence for the date that does not collide with an existing .govctl/loops/<loop-id>/ directory. Implementations MUST generate a loop ID when one is omitted. Implementations MUST reject explicit loop IDs that do not match the canonical loop ID pattern. A loop ID MUST NOT contain /, \, or .. path traversal segments.

Each loop directory MUST contain state.toml as its authoritative current-state file. The state.toml file MUST use the following top-level shape:

[loop]
id = "<loop-id>"
state = "pending|active|paused|completed|failed"
work = ["WI-YYYY-MM-DD-NNN"]
resolved = ["WI-YYYY-MM-DD-NNN"]
current_round = 0
next_action = "start|write_summary|continue|resolve_blocker|complete"

[dependencies]
"WI-YYYY-MM-DD-NNN" = ["WI-YYYY-MM-DD-NNN"]

[items."WI-YYYY-MM-DD-NNN"]
status = "pending|active|done|failed|blocked|cancelled"
round_count = 0
last_round = 0

The loop.id value MUST match the <loop-id> directory name. The loop.state value MUST be one of the loop lifecycle states defined by RFC-0006:C-LOOP-LIFECYCLE. The loop.work array MUST preserve the current explicit work item set for the loop. The loop.resolved array MUST contain the current resolved dependency closure and MUST include every loop.work entry. The loop.work and loop.resolved arrays MUST NOT contain duplicate Work Item IDs.

The optional loop.current_round value records the latest loop-level round number known to state. The optional loop.next_action value records the next required human or agent action. Older state files that omit these fields MAY be upgraded in place when written.

The [dependencies] table MUST contain one entry for each work item in loop.resolved. Each dependency entry MUST be an array of Work Item IDs. Each dependency ID MUST also appear in loop.resolved. Dependency arrays MUST NOT contain duplicate Work Item IDs.

The [items.<WI-ID>] table MUST contain one entry for each work item in loop.resolved. Each item status MUST be one of the loop-level work item statuses defined by RFC-0006:C-WORK-ITEM-INTERACTION. Each round_count MUST be a non-negative integer. The optional last_round value records the last loop-level round that selected or updated the item.

Loop state storage MUST be keyed by loop ID, not by work item ID. A multi-work-item loop MUST have one shared loop state root so dependency planning, failure propagation, and resumption use the same authoritative state.

Loop round artifacts MUST be stored under .govctl/loops/<loop-id>/rounds/round-NNN.toml, where NNN is the three-digit loop-level round number. A round artifact MUST identify the loop ID, round number, selected work item IDs, round state, summary evidence, blockers, and note candidates. Round artifacts are local execution trace and MUST NOT be written to Work Item fields.

Round artifacts MAY mention Work Item IDs when evidence applies to specific work, but the storage root is loop-level. Implementations MUST NOT require per-work-item round directories for the canonical state model.

Loop state is local execution state, not a governed artifact. Deleting .govctl/loops/ MUST NOT invalidate RFCs, ADRs, Work Items, Guards, or rendered governance projections, but MAY remove resumability and local execution trace.

Rationale: A loop can drive multiple work items, so a per-work-item state root cannot represent the loop lifecycle, dependency graph, aggregate outcome, or round evidence. A single loop directory keeps execution state separate from Work Item files while preserving enough protocol state for resumption. Canonical generated loop IDs follow the existing artifact style of a type prefix, date, and sequence while avoiding collision-prone plain-text IDs.

Tags: core

Since: v0.1.0

[RFC-0006:C-LOOP-SCOPE-MUTATION] Loop Scope Mutation (Normative)

A loop implementation MAY support explicit scope mutation for a non-terminal loop. A scope mutation changes or refreshes the loop’s current editable work field and recomputes the resolved dependency closure without creating a new loop ID.

Scope mutation MUST support these operations:

  1. Replan: keep the current editable work field and recompute its dependency closure from the current work item files.
  2. Add work: add one Work Item ID to the current editable work field, then recompute the dependency closure.
  3. Remove work: remove one Work Item ID from the current editable work field, then recompute the dependency closure.

Implementations MUST reject scope mutation for terminal loops. Implementations MUST reject scope mutation that would leave the editable work field empty. Implementations MUST validate added or removed work values as Work Item IDs. Implementations MUST store the explicit work set without duplicates.

A scope mutation MUST build a candidate loop state before replacing the stored state. The candidate state MUST use the current explicit work set after the requested add/remove/replan operation. The candidate state MUST resolve dependencies using the rules in RFC-0006:C-DEPENDENCY-SEMANTICS. If dependency resolution fails, the implementation MUST leave the previously stored loop state unchanged.

For work items that remain in the resolved dependency closure, scope mutation MUST preserve round_count. Scope mutation MUST preserve explicit terminal execution outcomes done, failed, and cancelled. Scope mutation MUST recompute blocked outcomes from the current dependency graph and current terminal dependency outcomes; a previously blocked work item MAY return to pending when its current dependencies no longer require blocking. Non-terminal work items MUST NOT be selected for a new round until their current dependencies satisfy RFC-0006:C-DEPENDENCY-SEMANTICS.

For newly introduced work items, scope mutation MUST initialize loop-level item state using the same Work Item status mapping used at loop start. For work items that no longer appear in the resolved dependency closure, scope mutation MUST remove their entries from loop.resolved, [dependencies], and [items] in state.toml. Removing a work item from current loop state MUST NOT undo any Work Item lifecycle transitions that already happened through govctl work commands. Optional historical round artifacts for removed work items MAY remain under the loop directory, but they MUST NOT be treated as part of the current loop state.

Rationale:

Long-running cleanup and implementation loops often discover that the original batch is missing work, contains unnecessary work, or needs dependency files re-read after edits. Scope mutation keeps one execution session identity while making the current work field and dependency closure explicit, validated, and recoverable. Modeling this as a field mutation keeps loop commands aligned with the existing edit model while preserving loop-specific replanning behavior.

Since: v0.2.0

[RFC-0006:C-LOOP-LISTING] Loop Listing (Normative)

If provided, the listing command MUST enumerate persisted loop state from .govctl/loops/*/state.toml without requiring a caller to know a loop ID or work item set first. The command MUST validate each canonical loop state it lists using the storage contract in RFC-0006:C-LOOP-STATE-STORAGE.

The listing command MUST produce deterministic output ordered by loop ID. Each listed loop MUST include at least the loop ID, lifecycle state, editable work field values, resolved work item count, and aggregate round count across current loop items. Machine-readable output, when supported, MUST expose the same user-facing fields.

The listing command MAY support filters by lifecycle state, loop ID substring, or work item ID substring. Filtering MUST NOT mutate loop state and MUST NOT select a loop for execution by itself.

Rationale: Work-set discovery is useful only after the caller has a stable loop identity. A listing command gives agents and humans a stable discovery entrypoint for interrupted or long-running batch loops while preserving the rule that loop state remains local execution state rather than a governed artifact. The caller can then pass the listed loop ID as the positional object to commands such as loop run, loop show, or loop resume.

Since: v0.3.0

[RFC-0006:C-LOOP-COMMAND-SURFACE] Loop Command Surface (Normative)

Implementations that expose a govctl loop command MUST treat it as a project-level local execution-state command namespace as defined by RFC-0002:C-GLOBAL-COMMANDS. Loop state is not a governed artifact resource, so loop commands MUST NOT expose unrestricted resource CRUD field-editing verbs for arbitrary loop state. Loop commands MAY expose specified editable fields whose semantics are defined by this RFC.

Argument roles:

Loop command arguments MUST have stable roles:

  1. A positional LOOP-ID argument identifies an existing persisted local loop state directory.
  2. A --id LOOP-ID flag MAY be used only by commands that create a loop state, where it requests the ID to create or reuse.
  3. Positional WI-ID... arguments identify explicit loop work field values for loop creation or field mutation.
  4. Positional WI-ID... arguments MUST NOT mean an execution target subset.
  5. Execution target selection MUST use an explicit selector flag.
  6. Loop field mutation MUST use the same add and remove field-position shape used by governed artifact resources.

Canonical subcommands:

The canonical loop subcommands are:

  1. loop list [filter]: read persisted loop states. This command MUST be read-only.
  2. loop show LOOP-ID: read one persisted loop state by loop ID. This command MUST be read-only.
  3. loop start [--id LOOP-ID] WI-ID...: create or reuse a loop for an explicit work field set.
  4. loop resume LOOP-ID: select and display an existing non-terminal loop by loop ID. This command MUST be read-only and MUST NOT advance rounds.
  5. loop run LOOP-ID [--work WI-ID ...] [--max-rounds N]: advance the local round protocol for an existing loop state.
  6. loop replan LOOP-ID: recompute the dependency closure for the current explicit work field set.
  7. loop add LOOP-ID work WI-ID: add a Work Item ID to the loop’s editable work field and replan.
  8. loop remove LOOP-ID work WI-ID: remove a Work Item ID from the loop’s editable work field and replan.

The work field is the only canonical user-facing field name for the loop’s explicit work set. Implementations MUST accept wi as a shorthand alias for work. User-facing help SHOULD prefer loop add LOOP-ID work WI-ID and loop remove LOOP-ID work WI-ID while documenting the alias.

Discovery semantics:

loop start [--id LOOP-ID] WI-ID... MAY reuse an existing non-terminal loop with the same current explicit work field set instead of creating a new loop. If more than one non-terminal loop matches the requested work set, the implementation MUST reject the operation as ambiguous and require the caller to use loop list and then pass a positional LOOP-ID to the desired operation.

loop list [filter] MUST support discovering loop state without requiring a caller to know a loop ID first per RFC-0006:C-LOOP-LISTING. Work-set discovery is a discovery behavior, not an execution selector.

loop run MUST NOT start a new loop and MUST NOT discover a loop by positional Work Item IDs. It operates only on the positional LOOP-ID argument.

Run selection semantics:

The --work WI-ID flag selects execution targets inside the loop identified by the positional LOOP-ID. Implementations MUST reject duplicate --work values. Implementations MUST reject any --work value that is not a Work Item ID in the current loop.resolved array. These validations MUST complete before writing loop state.

If no --work selector is provided, loop run LOOP-ID MUST consider every current work item in the loop’s resolved dependency closure when opening a round, subject to dependency readiness.

If one or more --work selectors are provided, loop run LOOP-ID --work WI-ID... MUST restrict the opened or advanced round to the selected target work items and their current in-loop transitive dependencies. The implementation MUST NOT select unrelated work items for that round. The implementation MAY update derived loop-level dependency outcomes, such as blocked dependents, when required to keep loop state consistent with RFC-0006:C-DEPENDENCY-SEMANTICS.

Targeted run selection MUST NOT replace, shrink, expand, or otherwise mutate the loop’s editable work field. Scope changes MUST use replan, add, or remove.

loop run MUST NOT silently perform repository implementation work, tick acceptance criteria, add Work Item notes, or move Work Items to done. Agents and humans MUST perform those operations through the existing Work Item and verification command surfaces. loop run records and validates local round evidence so those existing operations have resumable execution context.

Rationale:

The loop command namespace coordinates several governed resources but stores its own local execution state, so it is neither a governed artifact resource nor a simple single global command. Existing-loop operations use positional LOOP-ID arguments to match the rest of the CLI’s noun/verb/object shape. Stable argument roles prevent hidden mode switches: positional work item IDs in add and remove are field values for the loop’s work field, while --work is the explicit work-item execution selector. Keeping the field position visible preserves the CLI edit model while making loop-specific replanning a domain side effect of changing the field. Reusing run as the round-protocol advancement command preserves existing skill guidance while removing the misleading interpretation that govctl itself implements code.

Since: v0.4.0


3. Rationale

[RFC-0006:C-UNIFIED-MODEL] Unified Model Rationale (Informative)

The unified loop model (single primitive for both single-WI and multi-WI execution) was chosen over separate /loop and /batch skills because:

  1. Work items naturally form DAGs: Agents frequently create multiple related work items with dependencies, then iterate through them as a batch. Separate skills would force users to choose between /loop WI-001 and /batch WI-001 WI-002 WI-003 when the underlying mechanism is identical.

  2. Simpler mental model: “A loop drives work items to completion” is one concept. “A loop drives one work item, a batch drives multiple” is two concepts with overlapping semantics.

  3. Consistent state model: .govctl/loops/<loop-id>/ works the same whether the loop contains one work item or ten. Execution logs, state file, and round logs scale naturally.

  4. Downstream flexibility: The loop does not prescribe sequential or parallel execution. Downstream applications (agents, CI systems) can choose the execution model that fits their constraints.

Tags: core

Since: v0.1.0

[RFC-0006:C-EXECUTION-STATE-SEPARATION] Execution State Separation Rationale (Informative)

Execution state lives in .govctl/loops/<loop-id>/ (not in work item TOML) because:

  1. Work items are outcome artifacts: They should contain scope (description), success criteria (acceptance_criteria), and durable context (notes). They should not accumulate execution logs during active work.

  2. Rich execution traceability: Loops need to track round-by-round progress, guard results, criteria addressed per round, and detailed logs. This is too much data for a work item TOML file.

  3. Clean diffs: Work item TOML files remain stable and reviewable. Execution state changes frequently during a loop and is not meant for code review.

  4. Ephemeral by design: Loop state is local to the developer’s machine. It can be deleted without losing governance artifacts. The work item’s notes field captures durable learnings.

  5. Shared loop coordination: Multi-work-item loops need one state root for lifecycle, dependency graph, failure propagation, and resumption. A per-work-item state root would force the loop to reconstruct shared state from fragments.

Tags: core

Since: v0.1.0

[RFC-0006:C-DEPENDENCY-SEPARATION] Dependency Separation Rationale (Informative)

The depends_on field is separate from refs because they serve different purposes:

  • refs: Informational cross-references (“this work item is related to that RFC”). Does not block execution. Used for traceability and navigation.

  • depends_on: Execution dependencies (“this work item cannot start until that work item completes”). Blocks execution. Used for dependency resolution and failure propagation.

Conflating these would force the loop to guess whether a ref is a hard dependency or just a related artifact. Separate fields make intent explicit.

Tags: core, work-items

Since: v0.1.0


Changelog

v0.4.0 (2026-06-03)

Define loop command surface

Added

  • Loop command surface defines canonical loop subcommands and argument roles

Changed

  • Loop run advances an existing local round protocol by LOOP-ID with explicit –work target selection

v0.3.0 (2026-06-01)

Define loop listing discovery

Added

  • Loop listing command discovers persisted local loop state

v0.2.0 (2026-06-01)

Define loop scope mutation and canonical loop IDs

Added

  • Loop scope mutation supports replan plus add/remove of the editable work field

Changed

  • Loop IDs use LOOP-YYYY-MM-DD-NNN canonical format

v0.1.0 (2026-05-31)

Initial draft

RFC-0007: TUI v2 read-only cockpit

Version: 0.2.0 | Status: normative | Phase: test

References: RFC-0003, RFC-0006, RFC-0002


1. Summary

[RFC-0007:C-SUMMARY] Summary (Informative)

This RFC defines TUI v2 as a human-first, read-only cockpit for understanding a governed project.

TUI v2 builds on the baseline browsing behavior in RFC-0003, the global search contract in RFC-0002:C-SEARCH-COMMAND, and the loop state model in RFC-0006. It focuses on project overview, artifact discovery, loop state visualization, diagnostics, and readable navigation.

Scope: This RFC covers externally visible TUI behavior and interaction constraints. It does not specify private Rust module layout, ratatui widget internals, or a full interactive artifact editor.

Rationale: The existing TUI is useful for browsing RFCs, ADRs, and work items, but it does not expose newer governance concepts such as search, loop local state, dependency DAGs, guards, releases, or check diagnostics. TUI v2 should help a human understand project state quickly without creating a second mutation surface parallel to the CLI.

Since: v0.1.0


2. Specification

[RFC-0007:C-READ-ONLY] Read-only cockpit boundary (Normative)

TUI v2 MUST be read-only for governed project state in its first implementation phase.

TUI v2 MUST NOT create, edit, delete, move, finalize, accept, reject, supersede, deprecate, render, or otherwise mutate governed artifacts.

TUI v2 MUST NOT mutate persisted loop state or round artifacts under .govctl/loops/.

TUI v2 MAY refresh disposable derived local indexes under .govctl/ only when doing so follows the freshness and local-state rules defined by RFC-0002:C-SEARCH-COMMAND.

When TUI v2 presents an operation that would mutate state, it MUST present it as a suggested CLI command or help text rather than executing it.

Rationale: The CLI already owns mutation semantics, dry-run behavior, diagnostics, lock handling, and lifecycle gates. Keeping the first TUI v2 phase read-only gives humans a richer project cockpit without creating a second, weaker edit model.

Since: v0.1.0

[RFC-0007:C-RESPONSIBILITY-BOUNDARIES] TUI responsibility boundaries (Normative)

TUI v2 MUST keep terminal I/O, input dispatch, data loading, and rendering as separate responsibilities.

The terminal adapter MUST be limited to terminal lifecycle, event polling, event reading, frame drawing, and shutdown handling.

Input dispatch MUST translate keyboard input into in-memory TUI state transitions.

Input dispatch MUST NOT perform filesystem I/O, database access, command execution, terminal drawing, or governed artifact mutation.

Renderers MUST read already-loaded TUI state and draw frames.

Renderers MUST NOT load project artifacts, refresh indexes, execute commands, mutate governed state, or mutate persisted loop state.

Data-loading code MUST convert filesystem, schema, search-index, and loop-state failures into visible diagnostic state rather than hiding them from the cockpit.

New primary views or key-routing behavior SHOULD be covered by focused state-transition tests, renderer tests using a terminal test backend, or both.

Rationale: These boundaries keep TUI v2 human-facing, read-only, and testable without creating a second hidden execution model beside the CLI.

Since: v0.2.0

[RFC-0007:C-COCKPIT-VIEWS] Cockpit view model (Normative)

TUI v2 MUST provide a top-level human navigation model with visible entry points for overview, artifact browsing, search, loops, and diagnostics.

The overview view MUST summarize at least RFCs, ADRs, work items, and verification guards when those artifacts are available.

The artifact browsing views MUST preserve the existing RFC, ADR, and Work Item browsing capabilities required by RFC-0003.

The artifact browsing views SHOULD include verification guards, clauses, releases, and tags when those data sources can be loaded without violating RFC-0007:C-READ-ONLY.

The current view, selection context, active filter or query, and primary key bindings MUST remain visible or discoverable without leaving the TUI.

Rationale: A cockpit should orient a human before asking them to drill into details. The top-level model makes newer governance concepts discoverable while preserving the older RFC/ADR/Work browsing workflows.

Since: v0.1.0

[RFC-0007:C-LOOP-VIEWS] Loop state views (Normative)

TUI v2 MUST provide a loop list view that discovers persisted loop states according to RFC-0006:C-LOOP-LISTING.

Each listed loop MUST show the loop ID, lifecycle state, editable work roots, resolved work item count, aggregate round count, and next action when those values are present in valid loop state.

TUI v2 MUST provide a loop inspector for a selected loop.

The loop inspector MUST show the selected loop’s lifecycle state, current round, next action, editable work roots, resolved work set, loop-level item statuses, round counts, and dependency information.

If a loop state file is invalid, TUI v2 MUST present a readable diagnostic for that loop and MUST NOT treat invalid loop state as authoritative.

TUI v2 MUST NOT repair, replan, resume, run, or otherwise mutate loop state while rendering loop views.

Rationale: Loop state is local but highly useful to humans resuming or auditing work. The TUI should expose this state directly while preserving RFC-0006 ownership of loop execution semantics.

Since: v0.1.0

[RFC-0007:C-LOOP-DAG] Loop dependency DAG visualization (Normative)

TUI v2 MUST render a selected loop’s dependency graph as a visual DAG derived from the loop state’s dependencies table.

The DAG view MUST represent every work item in the loop state’s resolved work set unless viewport constraints require an explicit neighborhood or layer-limited fallback.

The DAG view MUST distinguish loop-level item statuses such as pending, active, done, failed, blocked, and cancelled using readable text and semantic styling.

The DAG view MUST make the selected work item visually distinct and MUST show its direct dependencies and direct dependents when that information is available.

The DAG layout MUST be deterministic for the same loop state.

When the graph is too large or the terminal viewport is too small for a full DAG, TUI v2 MUST degrade to a readable representation that still exposes ordering, dependencies, selected item context, and hidden item counts.

Rationale: A plain topological list is not enough for humans to understand batch execution. A visual DAG exposes why work is ready, blocked, or downstream of another item while still allowing terminal-size fallbacks.

Since: v0.1.0

[RFC-0007:C-SEARCH] TUI search (Normative)

TUI v2 MUST provide a search view for governed artifacts.

The search view MUST interpret query text according to RFC-0002:C-SEARCH-COMMAND rather than exposing backend-specific raw query syntax.

The search view SHOULD support artifact type filtering and tag filtering when the terminal interaction model can expose those filters clearly.

Search results MUST show at least artifact kind, ID, title, and enough snippet or metadata context for a human to choose a result.

Selecting a search result MUST navigate to the corresponding TUI detail view when that artifact kind is supported by TUI v2.

Search result loading MUST follow the read-only boundary in RFC-0007:C-READ-ONLY.

Rationale: Search is the fastest way for humans to recover context in a large governed repository. Reusing the CLI search contract prevents TUI search from drifting into a separate discovery model.

Since: v0.1.0

[RFC-0007:C-DIAGNOSTICS] Diagnostics view (Normative)

TUI v2 MUST provide a diagnostics view that presents project check diagnostics to a human.

The diagnostics view MUST show diagnostic severity, code, message, and target context when those fields are available.

The diagnostics view SHOULD group or filter diagnostics by severity and artifact target.

When a diagnostic target corresponds to an artifact that TUI v2 can display, selecting the diagnostic SHOULD navigate to that artifact’s detail view or an equivalent contextual view.

The diagnostics view MUST NOT automatically apply migrations, edit artifacts, render documents, or run mutation commands to resolve diagnostics.

Rationale: govctl check is the central safety signal for governed work. TUI v2 should make those diagnostics easier for a human to triage without turning validation into an implicit repair workflow.

Since: v0.1.0

[RFC-0007:C-HUMAN-UX] Human-first terminal UX (Normative)

TUI v2 MUST optimize rendered screens for human comprehension rather than machine parsing.

TUI v2 MUST use consistent semantic styling for artifact kind, lifecycle status, phase, diagnostic severity, loop item status, selection, and muted secondary information.

TUI v2 MUST preserve keyboard-only navigation across all primary views.

TUI v2 MUST expose view-specific key bindings through persistent footer text, help overlay, or an equivalent discoverable mechanism.

TUI v2 MUST avoid layouts where essential text overlaps, truncates without context, or becomes unreadable on common narrow terminal widths.

When a terminal is too small for the preferred layout, TUI v2 MUST fall back to a simpler readable layout rather than preserving a broken multi-pane layout.

Rationale: A human-facing terminal UI succeeds when state, hierarchy, and next steps are quickly legible. Visual polish should come from semantic consistency and resilient layout, not from decorative complexity.

Since: v0.1.0


Changelog

v0.2.0 (2026-06-07)

Specify TUI responsibility boundaries

Added

  • Require terminal I/O, input dispatch, data loading, and rendering to remain separate testable responsibilities

v0.1.0 (2026-06-06)

Initial draft

ADR-0001: Use TOML for ADRs and Work Items

Status: superseded | Date: 2026-01-17 Superseded by: ADR-0034

Tags: schema

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

Tags: lifecycle

References: RFC-0000

Context

Analysis of the artifact lifecycle state machines revealed several design flaws:

  1. Clause kind vs status duplication: The kind enum includes deprecated alongside normative and informative, but status also has deprecated. This creates confusion about where deprecation state belongs.

  2. ADR missing rejected state: The ADR lifecycle is proposed → accepted → superseded. If a proposal is rejected rather than accepted, there is no state to record this outcome. The alternative is leaving it as proposed forever or deleting it, both of which lose information.

  3. Work Item forced activation before cancellation: The lifecycle queue → active → done|cancelled implies you must start work before abandoning it. This is illogical - planned work can be abandoned before starting.

  4. 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:

  1. Remove deprecated from Clause kind: The kind field should only contain semantic categories (normative, informative). Deprecation is a lifecycle state that belongs in status.

  2. Add rejected to ADR lifecycle: The new lifecycle becomes:

    proposed → accepted → superseded
             → rejected
    

    This allows recording when a proposal was considered but declined.

  3. Allow Work Item queue → cancelled: The new lifecycle becomes:

    queue → active → done
        ↘        ↘ cancelled
    

    Work can be abandoned at any stage.

  4. 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: deprecated will need updating
  • Schema version bump required for breaking changes

Migration:

  • Any clause with kind: deprecated should change to kind: 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

Tags: validation

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:

  1. Be overwritten on next govctl render
  2. Create confusion about which version is authoritative
  3. 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:

  1. Collect all source JSON content (RFC metadata + clauses, or ADR/Work Item TOML)
  2. Canonicalize JSON/TOML: sort object keys recursively, normalize whitespace
  3. For RFCs: sort clauses by clause_id before hashing
  4. Compute SHA-256 of the canonical representation
  5. 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 check extracts 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 render to 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

Tags: release

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

Tags: cli

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

Tags: cli

References: RFC-0000:C-WORK-DEF, ADR-0019

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

Tags: editing

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

Tags: schema

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:

  1. RFCs cannot declare dependencies on ADRs that informed their design
  2. No way to trace which ADRs led to an RFC’s creation
  3. Validation cannot check RFC references for consistency
  4. 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:

  1. Add refs: Vec<String> to RfcSpec model (serde skip_serializing_if empty)
  2. Add diagnostic code E0105RfcRefNotFound for validation errors
  3. Extend validate_artifact_refs() to include RFC refs validation
  4. Support add/remove/get refs operations in edit commands for RFCs
  5. 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

Tags: validation

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:

  1. 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)
  2. Default pattern matches RFC-0001:C-NAME and ADR-0001 style references

  3. Scanner walks configured directories, applies pattern, validates extracted IDs against ProjectIndex

  4. New diagnostics: E0107SourceRefUnknown (error), W0107SourceRefOutdated (warning for deprecated/superseded)

  5. 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

Tags: validation

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:

  1. Description matches the exact template text
  2. Description is empty or whitespace-only
  3. 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 check until 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

Tags: editing

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:

  1. The source_scan feature uses [[artifact-id]] pattern to detect references in source code
  2. Users might expect the same pattern to work in content fields
  3. 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:

  1. Use the same pattern from source_scan.pattern config (defaults to [[RFC-NNNN]] format)
  2. Expand matched references using existing ref_link() function
  3. Apply to: description, context, decision, consequences, notes, acceptance_criteria text
  4. 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_scan pattern 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

Tags: release

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

Tags: schema

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) (rejected)

Add category field to ChecklistItem (criterion level) with prefix parsing (accepted)

ADR-0014: Release management with releases.toml

Status: accepted | Date: 2026-01-17

Tags: release

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-YYYY-MM-DD-029", "WI-YYYY-MM-DD-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 (rejected)

Store releases in single gov/releases.toml with explicit refs (accepted)

ADR-0015: Context-aware self-describing CLI for agent discoverability

Status: accepted | Date: 2026-01-18

Tags: cli

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:

  1. MCP (Model Context Protocol) — adds structured tool definitions, but requires server setup, process management, and creates a parallel interface to maintain
  2. Agent guide files (.claude/CLAUDE.md) — static, requires manual updates, doesn’t reflect current project state
  3. --help output — 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 version
  • purpose: one-line description of govctl’s role
  • philosophy: core principles (RFC supremacy, phase discipline)
  • commands[]: for each command:
    • name: command name (e.g., “new rfc”, “advance”)
    • purpose: what it does
    • when_to_use: semantic guidance on when to invoke
    • example: concrete usage
    • prerequisites: 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/phases
  • suggested_actions[]: contextually relevant commands with reasons
    • Example: “RFC-0001 is in impl phase. If implementation complete, run govctl advance RFC-0001 test
  • 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 status and list logic 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 describe output stays in sync with actual commands
  • Distribution unchanged: cargo install govctl is 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 describe once per session (cacheable)
  • Plain --help remains available for human users
  • Does not preclude future MCP integration if demand materializes

Comparison to MCP:

Aspectgovctl describeMCP
Distributioncargo install govctlServer config + process mgmt
Agent compatibilityAny shell-capable agentMCP-compatible agents only
MaintenanceSingle codebaseCLI + MCP server
Context awarenessBuilt-inSeparate implementation
Works offlineYesDepends

ADR-0016: Allow RFC amendments via versioning during implementation

Status: accepted | Date: 2026-01-19

Tags: lifecycle

References: RFC-0001, ADR-0004

Context

Real-world governance experience from the neotex-v2 project shows that RFCs often need amendments during implementation. This conflicts with the current govctl mental model that treats normative status as “frozen” — the documentation (CLAUDE.md:79) states “normative: Frozen. Implementation MUST conform.”

This creates a false dichotomy:

  • Theory: Spec everything perfectly, then implement
  • Practice: You discover spec bugs, ambiguities, and wrong assumptions during implementation

The problem is not with RFC-0001:C-RFC-STATUS (which only says “normative” means “binding”), but with the interpretation that “binding” implies “immutable.” This forces workarounds: draft ADRs, inline comments, or ignoring governance entirely.

The infrastructure for RFC evolution already exists: versioning (version field) and changelog (changelog array per ADR-0004). We’re just not using it for governance.

Decision

Clarify the semantics of “normative”:

  • normative means binding (code must conform to current version)
  • normative does NOT mean frozen (spec can evolve with version bumps)

Operational changes:

  1. Remove “normative = frozen” messaging from all documentation
  2. Document that normative RFCs MAY be amended via version bumping
  3. When amending a normative RFC:
    • Bump version according to semantic versioning
    • Add changelog entry documenting the change
    • Rationale and audit trail live in git/jj history

Precedent: Linux kernel APIs are both binding (drivers must conform) and evolving (with deprecation, versioning, compatibility) simultaneously.

Consequences

Easier:

  • Amending RFCs during implementation (matches real workflow)
  • Iterative spec refinement (discover-fix-document cycle)
  • Honest governance (no pretending specs are perfect)

More difficult:

  • Reviewers must check RFC changelog to see what changed
  • Multiple versions of an RFC might exist during development (but this is reality anyway)

No breaking changes:

  • Existing RFCs remain valid
  • No data model changes required
  • Validation rules simplified (remove frozen assumption)

ADR-0017: CLI Command Implementation Details

Status: accepted | Date: 2026-01-19

Tags: cli

References: RFC-0002, ADR-0037

Context

RFC-0002 defines the structural contract for govctl CLI commands: resource-first organization, universal CRUD verbs, lifecycle operations, and output format control. However, RFC-0002 intentionally defers implementation details to preserve flexibility while maintaining a stable interface contract.

Implementation requires decisions on:

  • Exact flag syntax and naming conventions
  • Array field editing notation (how to add/remove items)
  • Help text formatting and structure
  • Error message templates and exit codes
  • Terminal capability detection (colors, interactive prompts)
  • Confirmation prompt behavior
  • Progress indicators for long-running operations

Without documented conventions, implementers would make inconsistent choices, leading to:

  • Flags named differently across commands (–filter vs –query)
  • Array editing syntax that varies by resource type
  • Inconsistent help text structure
  • Error messages with different formats
  • Terminal behavior that breaks in non-interactive contexts

This ADR establishes implementation conventions that realize RFC-0002’s structural contract with consistent UX.

Decision

We adopt the following implementation conventions:

1. Flag Syntax and Naming

Long flags: Always use double-dash with kebab-case

  • --output, --filter, --dry-run, --force

Short flags: Single letter aliases for common flags only

  • -o for --output
  • -f for --force
  • -n for --limit (per ADR-0019, aligns with head/tail convention)

No short flag for --dry-run: Safety flags benefit from explicit long form.

No short flags for domain-specific options to avoid collision:

  • --filter has no short form
  • --rfc-id has no short form

Flag values:

  • Space-separated: --output json (preferred)
  • Equals accepted: --output=json (clap auto-supports)
  • No colons: avoid --output:json

2. Field Editing Commands

govctl uses distinct verbs for different mutation operations. Each verb is clear and discoverable via --help.

Scalar fields: Use set

govctl rfc set RFC-0001 title "New Title"
govctl work set WI-001 description "Updated description"
govctl adr set ADR-001 status accepted

Array fields - append: Use add

govctl work add WI-001 refs RFC-0001
govctl rfc add RFC-0001 owners @alice
govctl work add WI-001 acceptance_criteria "New criterion"

Array fields - remove: Use remove

govctl work remove WI-001 refs RFC-0001
govctl rfc remove RFC-0001 owners @bob

Checklist status: Use tick

govctl work tick WI-001 acceptance_criteria "Tests pass" -s done
govctl work tick WI-001 acceptance_criteria "Docs" -s pending

Pattern matching for array operations: Same semantics as ADR-0007

  • Default: case-insensitive substring match
  • Use --exact for exact match
  • Use --regex for pattern match
  • Use --at N for index-based access

Rationale: Distinct verbs (set, add, remove, tick) are more intuitive and discoverable than a unified edit command with prefix notation. Users immediately understand what each command does.

3. Help Text Structure

All commands follow this template:

USAGE:
    govctl <resource> <verb> [OPTIONS] <ARGS>

ARGS:
    <required>     Description
    [optional]     Description

OPTIONS:
    -o, --output <FORMAT>    Output format [default: table] [possible: json, yaml, toml, plain]
    --filter <EXPR>          Filter results (KEY=VALUE)
    --dry-run                Preview changes without writing
    -h, --help               Print help

EXAMPLES:
    govctl rfc list draft
    govctl rfc get RFC-0001 -o json
    govctl rfc set RFC-0001 title "New Title"

Ordering:

  1. Universal flags first (output, filter, dry-run)
  2. Resource-specific flags second
  3. Help/version last

4. Error Messages and Exit Codes

Exit codes:

  • 0 - Success
  • 1 - General error (validation, not found, invalid transition)
  • 2 - Usage error (wrong arguments, unknown flag)

Error format:

error[CODE]: <message>
  --> <location>
  |
  | <context>

Example:

error[E0102]: RFC not found: RFC-9999
  --> gov/rfc/RFC-9999
  |
  | Run 'govctl rfc list' to see available RFCs

Diagnostic codes: Use existing govctl error taxonomy (E0xxx, W0xxx).

5. Terminal Capability Detection

Color output:

  • Auto-detect TTY with atty or is-terminal crate
  • Respect NO_COLOR environment variable
  • Respect --color <always|never|auto> flag (future)

Interactive prompts:

  • Only show in TTY mode
  • Skip if --force flag provided
  • Skip if stdin is not TTY

Progress indicators:

  • Use indicatif crate for long operations (>2s expected)
  • Show progress for: render, check, bulk operations
  • Suppress if --quiet or non-TTY

6. Confirmation Prompts

Destructive operations require confirmation unless --force:

  • delete (clauses, work items)
  • deprecate (RFCs, clauses)
  • supersede (RFCs, ADRs, clauses)

Prompt format:

Delete work item WI-YYYY-MM-DD-NNN? [y/N]

Behavior:

  • Default to “no” (capital N)
  • Accept: y, Y, yes, Yes, YES
  • Reject: n, N, no, No, NO, empty, anything else
  • Timeout: none (wait indefinitely)

7. Filter Syntax

Per RFC-0002:C-CRUD-VERBS, list commands support filtering.

Simple filter (shorthand):

govctl rfc list draft          # filter by status
govctl work list active        # filter by status

Explicit filter (future extension):

govctl rfc list --filter status=draft
govctl rfc list --filter phase=impl,status=normative

Implementation: Start with simple substring matching, defer explicit expressions to future ADR.

8. Stdin Handling

When --stdin flag is present:

  • Read entire stdin to EOF
  • Trim trailing newline only (preserve internal newlines)
  • Empty stdin is valid (allows heredocs with empty content)

HEREDOC pattern (recommended for multi-line):

govctl clause set RFC-0001:C-SCOPE text --stdin <<'EOF'
This clause defines the scope.
EOF

9. Dry-Run Behavior

Global --dry-run flag:

  • Shows what would be written
  • Prints diff or file preview
  • Exits with 0 (success simulation)
  • No short flag (safety flags should be explicit)

Output format:

[DRY RUN] Would write: gov/rfc/RFC-0001/rfc.json
--- before
+++ after

10. Subcommand Organization (clap)

Structure:

Use nested Subcommand enums for resource-first organization.
Resource commands contain their own verb subcommands.
Global commands remain at top level.

Backward compatibility aliases: Emit deprecation warning when old verb-first commands are used.

Consequences

Positive:

  1. Consistent UX: All commands follow the same patterns. Users learn once, apply everywhere.

  2. Agent-friendly: Predictable flags, stable error codes, machine-readable output defaults make automation reliable.

  3. Maintainable: Implementation conventions documented, not scattered across code comments.

  4. Discoverable: Distinct verbs (set, add, remove, tick) are immediately understandable. Users can explore via --help without reading documentation.

  5. Safe: Confirmation prompts prevent accidental destructive actions. Dry-run mode enables testing before committing.

  6. Debuggable: Structured error messages with codes and locations make issues easy to diagnose.

Negative:

  1. Multiple verbs: Users must learn four verbs for mutation operations (set, add, remove, tick) instead of one. However, each verb’s meaning is immediately clear.

  2. Testing complexity: Need tests for TTY detection, confirmation prompts, dry-run mode, error formatting, etc.

Trade-offs Accepted:

  • Clarity over brevity: Distinct verbs are more verbose than a unified edit command, but much easier to understand. add and remove are clearer than edit +value and edit -value.

  • Discoverability over uniformity: Four clear verbs are better than one verb with special syntax that requires documentation.

  • Safety over speed: Confirmation prompts slow down destructive operations. This is intentional to prevent accidents.

Alternatives Considered

Document shared CLI implementation conventions. (accepted)

  • Pros: Keeps command behavior consistent across resources
  • Cons: Requires maintaining a single convention document

Leave CLI implementation details undocumented per command. (rejected)

  • Pros: No extra ADR maintenance
  • Cons: Commands drift in flags, prompts, errors, and help shape
  • Rejected because: Inconsistent command behavior undermines RFC-0002’s stable interface contract.

ADR-0018: Global Command Shortcuts vs Strict Resource-First Syntax

Status: accepted | Date: 2026-01-19

Tags: cli

References: RFC-0002, ADR-0017

Context

During implementation of RFC-0002, we successfully built the resource-first command structure (govctl <resource> <verb>). However, a design question emerged about backward compatibility with existing verb-first shortcuts.

Current Implementation

Both syntaxes currently work:

# Resource-first (RFC-0002 canonical)
govctl rfc list
govctl work new "title"
govctl adr accept ADR-0001

# Verb-first shortcuts (legacy)
govctl list rfc
govctl new work "title"

The Tension

RFC-0002:C-GLOBAL-COMMANDS explicitly defines which commands should remain global:

  • init, check, status, render, describe, completions

Notably absent from this list: list, new, and all resource-specific operations like move, tick, accept, etc.

This suggests the RFC intentionally designed these as resource-scoped operations, not global commands.

Problem Statement

Should we:

  1. Keep list and new as convenient global shortcuts that delegate to resource-first implementations?
  2. Remove them entirely and enforce strict resource-first syntax per RFC-0002?
  3. Keep them with deprecation warnings for gradual migration?

User Impact

We have ~40 completed work items and governance workflows that use the old syntax. Scripts, documentation, and muscle memory are built around patterns like govctl list rfc and govctl new work.

However, we are pre-1.0 (currently 0.2.0), which traditionally allows breaking changes.

Implementation Complexity

Current implementation maintains both paths through the canonical command pattern, adding ~40 lines of delegation code. This works but violates the “one way to do it” principle.

Decision

Decision: Remove shortcuts immediately (Option 2)

We will remove govctl list and govctl new shortcuts entirely, enforcing strict resource-first syntax per RFC-0002.

Rationale

  1. RFC Compliance: RFC-0002:C-GLOBAL-COMMANDS deliberately defines the exhaustive list of global commands. list and new are not on that list, indicating they should be resource-scoped.

  2. Design Clarity: The resource-first pattern (govctl <resource> <verb>) provides a clear, predictable structure:

    • govctl rfc list - list RFCs
    • govctl work new - create work item
    • govctl adr accept - accept ADR

    Having two ways (govctl list rfc vs govctl rfc list) violates the “one obvious way” principle.

  3. Reduced Complexity: Maintaining both patterns adds ~40 lines of delegation code and increases cognitive load for users (“which way should I use?”).

  4. Pre-1.0 Window: We’re at version 0.2.0, which traditionally allows breaking changes before stabilizing at 1.0.

  5. Shell Aliases Sufficient: Users who want shortcuts can add personal aliases:

    alias gl='govctl rfc list'
    alias gw='govctl work'
    alias ga='govctl adr'
    

    This moves convenience to where it belongs—user preference—rather than mandating it in the tool.

  6. Consistency: If we keep list and new as globals, why not move, tick, accept, reject? The line becomes arbitrary. Resource-first is consistent across all operations.

Migration Plan

Since this is a breaking change:

  1. Update all documentation to use resource-first syntax ✅ (done)
  2. Update internal workflows (gov.md, .claude/CLAUDE.md) ✅ (done)
  3. Remove from Commands enum in main.rs
  4. Remove delegation logic from command_router.rs
  5. Update CHANGELOG.md noting the breaking change
  6. Consider: Add migration guide in docs showing the mapping

Non-breaking Alternative Considered

We could keep shortcuts with deprecation warnings (Option 3), but this:

  • Extends the transition period indefinitely
  • Keeps dual-path complexity in codebase
  • Delays the inevitable

Given pre-1.0 status, clean break is preferable.

Consequences

Positive

  • Single Canonical Syntax: Only one way to invoke commands reduces confusion
  • RFC Compliance: Aligns perfectly with RFC-0002:C-GLOBAL-COMMANDS
  • Simpler Codebase: ~40 fewer lines of delegation logic to maintain
  • Clearer Documentation: Examples show only one pattern, easier to teach
  • Predictable: govctl <resource> <verb> works for all operations without exceptions
  • Tab Completion: Clearer completion tree (type govctl → see resources, not mix of resources + verbs)

Negative

  • Breaking Change: Existing scripts using govctl list or govctl new will break
    • Mitigation: We’re pre-1.0, document in CHANGELOG
  • More Keystrokes: govctl rfc list is longer than govctl list rfc
    • Mitigation: Shell aliases for personal shortcuts
  • Learning Curve: Users familiar with old syntax need to adjust
    • Mitigation: Clear error messages suggesting correct syntax

Migration Required

Users need to update:

# Old → New
govctl list rfc        → govctl rfc list
govctl list adr        → govctl adr list
govctl list work       → govctl work list
govctl list clause     → govctl clause list
govctl new rfc "..."   → govctl rfc new "..."
govctl new adr "..."   → govctl adr new "..."
govctl new work "..."  → govctl work new "..."
govctl new clause ...  → govctl clause new ...

Future Extension

This decision does NOT prevent adding convenience aliases later if user demand warrants it. However, any such addition would require an RFC amendment to RFC-0002:C-GLOBAL-COMMANDS.

Recommendation for Users

Add personal shell aliases for frequently used commands:

# In ~/.bashrc or ~/.zshrc
alias gr='govctl rfc'
alias ga='govctl adr'
alias gw='govctl work'
alias gc='govctl clause'

# Usage becomes:
gr list        # govctl rfc list
gw new "task"  # govctl work new "task"

This provides the convenience without coupling it to the tool.

Alternatives Considered

Keep both syntaxes permanently

Remove shortcuts immediately (strict RFC-0002)

Phased deprecation (warnings now, remove in 1.0)

Expand shortcuts to all common operations

ADR-0019: Change -n from dry-run to limit for better Unix convention alignment

Status: accepted | Date: 2026-01-19

Tags: cli

References: ADR-0006, ADR-0017

Context

ADR-0006 and ADR-0017 assigned -n as the short flag for --dry-run, following rsync’s convention. However, this conflicts with the more universal Unix convention where -n means “number” or “limit”:

Standard Unix tools using -n for number/limit:

  • head -n 10 (limit to N lines)
  • tail -n 10 (limit to N lines)
  • grep -n (show line numbers)
  • sort -n (numeric sort)
  • ls -n (numeric IDs)

Tools using -n for dry-run:

  • rsync -n (dry-run) - notable exception
  • Very few other standard tools

Current problem: We need to add --limit flag to all list commands to control result count. The natural short flag would be -n, but it’s already taken by dry-run. This forces us to either:

  1. Use no short flag for limit (verbose, less ergonomic)
  2. Change -n to mean limit (breaks ADR-0006/ADR-0017)

Impact of current design:

  • govctl work list --limit 5 is verbose (no short option)
  • Inconsistent with head -n 5 / tail -n 5 muscle memory
  • Dry-run is a safety flag (verbose is acceptable)
  • Limit is used frequently in interactive sessions (short flag valuable)

Decision

Reassign -n from dry-run to limit:

  1. Remove -n short flag from --dry-run (keep long form only)

    • Dry-run remains accessible as --dry-run
    • This is a safety flag - verbosity is appropriate
  2. Add -n short flag to --limit on all list commands

    • govctl rfc list -n 10
    • govctl work list -n 5
    • Aligns with head -n / tail -n conventions
  3. Amend ADR-0006 and ADR-0017 to reflect this change

Rationale:

  • Unix convention alignment: -n for “number” is far more common
  • Ergonomics: Limit is used frequently, dry-run less so
  • Safety: Dry-run benefits from being explicit (--dry-run)
  • Pre-1.0 window: Breaking changes are acceptable now
  • Consistency: Follows head/tail patterns users know

Consequences

Positive:

  • Natural -n for limit matches Unix expectations
  • More ergonomic interactive use: govctl work list -n 5
  • Explicit --dry-run is clearer for safety-critical flag
  • Consistent with standard tooling (head, tail, etc.)

Negative:

  • Breaking change: Scripts using -n for dry-run will break
  • Requires updating ADR-0006 and ADR-0017
  • Requires updating any documentation mentioning -n

Migration:

  • All uses of -n must change to --dry-run
  • Update .claude/CLAUDE.md and other docs
  • Add to CHANGELOG as breaking change
  • Search codebase for any hardcoded -n usage

Affected ADRs:

  • ADR-0006: Originally defined -n for dry-run
  • ADR-0017: Documents -n as global dry-run flag

ADR-0020: Configurable work item ID strategies for multi-person collaboration

Status: accepted | Date: 2026-01-26

Tags: collaboration, work-items

References: RFC-0000

Context

The current work item ID format (WI-YYYY-MM-DD-NNN) uses local sequential numbering. The govctl work new command scans gov/work/ to find the max sequence number for today’s date, then increments by 1.

Problem: When multiple people work on parallel branches and both create work items on the same day, they get the same ID:

Alice: scans → max=002 → creates WI-YYYY-MM-DD-003
Bob:   scans → max=002 → creates WI-YYYY-MM-DD-003 (collision!)

On merge, these IDs collide. This blocks multi-person teams from adopting govctl.

Options considered:

StrategyFormatProsCons
Author namespaceWI-2026-01-26-alice-001Clear ownership, sequential per authorRequires config
Git identity hashWI-2026-01-26-a7f3-001Auto from git email, no configLess readable
Random suffixWI-2026-01-26-a7f3Simple, no coordinationNon-sequential
TimestampWI-2026-01-26-143257Natural orderingClock skew issues
Merge-time renumberKeep currentMinimal changeBreaks refs on rename

govctl is primarily single-contributor but must support multi-person teams as external adopters.

Decision

Add opt-in ID strategies via gov/config.toml, keeping current behavior as default.

  1. Default: sequential (current behavior)

    • Format: WI-YYYY-MM-DD-NNN
    • Solo projects keep simple, readable IDs
    • No breaking change for existing users
  2. Opt-in: author-hash (recommended for teams)

    • Format: WI-YYYY-MM-DD-{hash4}-NNN
    • {hash4} = first 4 chars of sha256(git config user.email)
    • Example: WI-2026-01-26-a7f3-001
    • Each contributor gets their own sequence namespace
    • Zero configuration (auto-derived from git identity)
  3. Opt-in: random (simple uniqueness)

    • Format: WI-YYYY-MM-DD-{rand4}
    • {rand4} = 4 random hex chars (65,536 possibilities per day)
    • Example: WI-2026-01-26-b2c9
    • No sequence number, just unique suffix

Configuration:

# gov/config.toml
[work_item]
id_strategy = "author-hash"  # or "sequential" (default), "random"

Rationale:

  • Backward compatible: default remains sequential
  • Teams explicitly opt-in to collision-safe strategy
  • author-hash is recommended because it preserves sequential numbering within author namespace
  • Uses git identity (already required for commits) — zero additional config

Consequences

Positive:

  • Multi-person teams can adopt govctl without ID collision risk
  • Existing single-contributor projects unchanged
  • author-hash provides both collision safety AND sequential ordering
  • Zero configuration for author-hash (uses git email)

Negative:

  • New ID formats (WI-...-a7f3-001) are less human-memorable
  • Cannot easily tell “who created this” without looking up the hash
  • Projects must explicitly configure for team use

Implementation:

  • Add id_strategy to Config struct
  • Modify src/cmd/new.rs::create_work_item() to dispatch based on strategy
  • Add validation that all work items follow configured strategy
  • Update gov/schema/SCHEMA.md to document new formats

Migration for teams:

  1. Set [work_item] id_strategy = "author-hash" in gov/config.toml
  2. Existing work items retain their IDs (no renaming required)
  3. New work items use the new format

ADR-0021: Resource-scoped render commands for single-item rendering

Status: accepted | Date: 2026-01-29

Tags: cli

References: RFC-0002, ADR-0018

Context

The global govctl render command currently has an --rfc-id flag for rendering a single RFC, but no equivalent flags for ADRs or work items. This creates an asymmetry in the CLI.

Problem Statement

When users want to render a single artifact, the current options are:

ArtifactCurrent SyntaxWorks?
RFCgovctl render rfc --rfc-id RFC-0001✅ Yes
ADR(none)❌ No
Work Item(none)❌ No

Options Considered

  1. Add --adr-id and --work-id flags — Proliferates flags on global command
  2. Add resource-scoped render verbs — Clean separation of bulk vs single
  3. Leave as-is — Accept asymmetry

Constraints

Decision

We will add resource-scoped render commands and remove the --rfc-id flag from the global render command.

New Commands

govctl rfc render <RFC-ID>    # Render single RFC
govctl adr render <ADR-ID>    # Render single ADR
govctl work render <WI-ID>    # Render single work item

Modified Command

# Global render now ONLY does bulk operations
govctl render [rfc|adr|work|changelog|all]  # No --rfc-id flag

Rationale

  1. Clean separation: Global render = bulk operations, resource-scoped = single-item
  2. No flag proliferation: Avoids --rfc-id, --adr-id, --work-id on global command
  3. Discoverable: govctl rfc --help shows render alongside other verbs
  4. Noun-first for single items: Consistent with govctl rfc get, govctl rfc list
  5. RFC-0002 compatible: render remains global for bulk; adding resource verbs doesn’t violate this

Implementation Notes

  • Resource-scoped render shares implementation with global render (just filters to single ID)
  • Error handling: if ID not found, return clear error message
  • Output: same format as bulk render, just for one item

Consequences

Positive

  • Symmetric API: All resource types support single-item render equally
  • Cleaner global command: No proliferation of --*-id flags
  • Intuitive mental model: “Work with RFC” → govctl rfc render RFC-0001
  • Better discoverability: govctl rfc --help shows all RFC operations including render

Negative

  • Breaking change: Scripts using govctl render --rfc-id must update
    • Mitigation: Pre-1.0, document in CHANGELOG
  • Two entry points for render: Global (bulk) and resource-scoped (single)
    • Mitigation: Clear purpose split makes this a feature, not a bug

Migration

# Old syntax (removed)
govctl render rfc --rfc-id RFC-0001

# New syntax
govctl rfc render RFC-0001

Alternatives Considered

Add –adr-id and –work-id flags to global render: Proliferates flags, violates ‘one way’ principle

Leave as-is with only –rfc-id: Asymmetric, inconsistent UX

ADR-0022: Add show command for stdout rendering

Status: accepted | Date: 2026-02-07

Tags: cli

References: RFC-0002, ADR-0021

Context

Agents (Claude, Cursor, etc.) intuitively try govctl rfc show RFC-0001 to read an RFC’s rendered content, but this command doesn’t exist. The error unrecognized subcommand 'show' is a recurring failure mode.

Problem Statement

The current CLI has an asymmetry in read operations:

VerbPurposeOutput
getRead individual field valuestdout
renderGenerate full markdownfile (side effect)
(missing)Read full rendered contentstdout

The gap: there’s no way to get the full rendered representation to stdout without writing a file.

Current Workarounds

  1. govctl rfc render RFC-0002 --dry-run — shows preview, but semantically wrong (dry-run is for previewing writes)
  2. Read docs/rfc/RFC-0002.md directly — requires knowing the configurable output path

Both are awkward for agents who just want to “see” an artifact.

Constraints

Mental Model

Unix convention: commands that read data print to stdout; commands that generate files write to filesystem. show fits the “read and display” pattern like cat, kubectl get -o yaml, or docker inspect.

Decision

We will add a show verb to all renderable resources that outputs content to stdout.

New Commands

govctl rfc show <RFC-ID>       # Print rendered RFC to stdout
govctl adr show <ADR-ID>       # Print rendered ADR to stdout
govctl work show <WI-ID>       # Print rendered work item to stdout
govctl clause show <CLAUSE-ID> # Print clause content to stdout

Output Format

  • Default: Markdown text (the human-readable rendered form)
  • With --output json: Structured JSON (equivalent to get with no field)
  • Respects RFC-0002:C-OUTPUT-FORMAT conventions

Semantic Distinction

CommandPurposeSide Effects
showRead and display to stdoutNone
renderGenerate and write to fileWrites file
getRead single field valueNone

Rationale

  1. Agent-friendly: Natural command that agents try first (show = “let me see this”)
  2. Unix convention: Read operations → stdout; write operations → filesystem
  3. Minimal implementation: Reuses existing render logic, just changes output target
  4. Symmetric with render: show is to render as cat is to cp
  5. Format flexibility: --output json gives structured access when needed

Consequences

Positive

  • Fixes agent failures: govctl rfc show RFC-0001 will work as expected
  • Cleaner semantics: Clear separation between read (show) and write (render)
  • Pipeable: govctl rfc show RFC-0002 | less or | grep pattern just works
  • Consistent UX: All renderable resources get the same show verb

Negative

  • New verb to learn: Users must understand show vs render distinction
    • Mitigation: Intuitive naming makes this self-evident
  • Slight command surface growth: 4 new subcommands
    • Mitigation: Natural extension of existing pattern, improves discoverability

Neutral

  • --output json on show is functionally equivalent to get with no field argument — this redundancy is acceptable for discoverability

Alternatives Considered

Extend get with –rendered flag: Overloads get semantics, less discoverable

Use view instead of show: Equally valid, but show is more common in CLIs (docker inspect, kubectl describe)

Use cat as the verb: Unix-y but loses semantic meaning (cat is for concatenation)

ADR-0023: Organize assets into commands, skills, and agents subdirectories

Status: accepted | Date: 2026-02-11

Tags: skills-agents

References: ADR-0024

Context

The assets/ directory currently contains a flat mix of files: four command workflow definitions (gov.md, quick.md, discuss.md, status.md) and four logo SVGs. As we prepare to add skill definitions (specialized AI agent capabilities) and agent definitions (agent role/behavior configurations), the flat structure becomes ambiguous — it conflates three distinct categories of assets.

Problem Statement

With new asset types incoming, a flat assets/ directory provides no semantic separation. Developers (and tools like sync-commands.sh) must rely on conventions or file extensions to distinguish command templates from skills from agents.

Constraints

  • govctl init copies command templates via include_str! in src/cmd/new.rs — paths are compile-time constants
  • build.rs tracks command files for rebuild — paths must stay in sync
  • scripts/sync-commands.sh and sync-commands.ps1 glob assets/*.md — pattern must be updated
  • Logo SVGs are referenced from README.md and are a fourth category (static images)

Decision

Organize assets/ into three subdirectories by category:

  • assets/commands/ — AI workflow command definitions (gov.md, quick.md, discuss.md, status.md)
  • assets/skills/ — Skill definitions (new, initially empty)
  • assets/agents/ — Agent definitions (new, initially empty)

Logo SVGs remain at the assets/ root since they are static images, not AI-consumable definitions.

All compile-time paths (include_str!), build system paths (build.rs), and script globs are updated to reference assets/commands/.

Rationale

  1. Semantic clarity — the directory name tells you what kind of asset it is
  2. Minimal blast radius — logos stay put, only command .md files move one level deeper
  3. Future-proof — skills and agents get their own home from day one

Consequences

Positive

  • Clear separation of concerns for three distinct asset categories
  • New skills/agents have a designated location from the start
  • Scripts and tooling can target specific subdirectories

Negative

  • One-time update to all paths referencing command assets (4 files)
  • Test snapshots that reference output paths may need updating

Neutral

  • Logo SVGs stay at assets/ root — no change to README references

Alternatives Considered

Flat with naming conventions: Keep flat assets/ and use prefixes like cmd-gov.md, skill-foo.md. Rejected: naming conventions are fragile and don’t scale.

ADR-0024: Writers as skills, reviewers as agents for governance artifacts

Status: accepted | Date: 2026-02-11

Tags: skills-agents

References: ADR-0023

Context

govctl manages three governance artifact types — RFCs, ADRs, and work items. We need to add AI-assisted capabilities for both creating (writing) and reviewing these artifacts.

Per ADR-0023, the assets/ directory is organized into commands/, skills/, and agents/ subdirectories. Skills and agents are synced to .claude/skills/ and .claude/agents/ respectively.

Problem Statement

Each artifact type needs writing guidance (structure, conventions, quality patterns) and review criteria (completeness checks, quality gates). The question: should each capability be a skill (augments the main agent inline) or an agent (runs as isolated subagent with its own system prompt)?

Key Distinction

  • Skills run in the main agent’s context. They have full access to the conversation and codebase. They augment what the main agent knows.
  • Agents run in isolated contexts with custom system prompts. They receive delegated tasks and return results. They have no access to the main conversation.

Constraints

  • Skills MUST be <250 lines per SKILL.md (progressive disclosure via references/)
  • Agents MUST have focused system prompts
  • Each capability should follow “one skill, one capability” principle
  • The existing /discuss and /gov commands orchestrate workflows that need writing knowledge

Decision

Writers are skills. Reviewers and auditors are agents. Seven items total:

Skills (in assets/skills/)

SkillPurpose
rfc-writerHow to write well-structured RFCs: normative language (MUST/SHOULD/MAY), clause structure, versioning, since fields
adr-writerHow to write effective ADRs: context/decision/consequences, trade-off analysis, alternatives documentation
wi-writerHow to write good work items: acceptance criteria with category prefixes, description quality

Agents (in assets/agents/)

AgentPurpose
rfc-reviewerReview RFC drafts for completeness, normative language quality, clause coverage, cross-references
adr-reviewerReview ADR drafts for context quality, decision clarity, alternatives, honest consequences
wi-reviewerReview work items for acceptance criteria structure, category correctness, description quality
compliance-checkerVerify code conforms to normative RFC clauses and ADR decisions — detect spec violations in implementation

Rationale

  1. Writers need conversation context. An RFC writer must know why the user is creating the RFC — what problem, what constraints, what existing artifacts relate. Skills run inline and have full context.

  2. Reviewers benefit from cognitive isolation. When the main agent writes an artifact and then reviews it, confirmation bias is unavoidable. An isolated review agent has no memory of authoring — it evaluates purely on quality criteria.

  3. Compliance checking is auditing, not writing. The compliance-checker agent cross-references source code against normative RFC clauses (MUST/MUST NOT) and ADR decisions. It is distinct from artifact reviewers — those check if an artifact is well-written, this checks if code follows what artifacts specify. Isolation ensures no “I wrote this code so it must conform” bias.

  4. Seven separate, not consolidated. Each capability is genuinely different. Each stays well under 250 lines. The ~15% shared knowledge (govctl commands, [[ref]] syntax) is 3-5 lines of duplication — not worth coupling distinct capabilities to eliminate.

Integration

  • /discuss and /gov commands will reference writer skills for quality guidance
  • Review agents can be invoked at quality gates (e.g., after drafting, before finalization)
  • compliance-checker can be invoked during /gov Phase 4 (testing) or on demand
  • sync-assets.sh already syncs both skills/ and agents/ directories

Consequences

Positive

  • Writers augment the main agent with domain knowledge while preserving conversation context
  • Reviewers provide unbiased quality checks through cognitive isolation
  • Compliance checker catches spec violations that govctl check cannot (it validates references exist; the agent validates semantic conformance)
  • Seven focused items follow “one skill, one capability” — each stays under 250 lines
  • Future artifact types get their own skill + agent pair without touching existing files
  • sync-assets.sh already supports the directory structure (ADR-0023)

Negative

  • 7 files to maintain (mitigation: each is small and focused, changes are rare)
  • ~15% knowledge duplication across items (mitigation: 3-5 lines per file, not worth abstracting)
  • Review/audit agents lack conversation context (mitigation: they evaluate on merit, which is the point)
  • Compliance checking is inherently imprecise — agent may flag false positives (mitigation: output is advisory, not blocking)

Neutral

  • Existing /discuss and /gov commands continue to work unchanged initially; skills/agents integration is additive
  • govctl check continues to handle structural validation; compliance-checker handles semantic validation — complementary, not competing

Alternatives Considered

All skills: Make both writers and reviewers skills. Rejected: reviewers lose cognitive isolation, confirmation bias when main agent reviews its own work.

All agents: Make both writers and reviewers agents. Rejected: writers lose conversation context, cannot access why the user is creating the artifact.

4 consolidated items (governance-writer + wi-writer, governance-reviewer + wi-reviewer): Rejected: RFC and ADR capabilities are genuinely different, merging creates a skill that branches on artifact type — special cases we want to eliminate.

2 consolidated items (one writer, one reviewer): Rejected: work items differ fundamentally from RFCs/ADRs, no shared domain knowledge worth coupling.

ADR-0025: Concurrent write safety for agent-driven parallel tasks

Status: accepted | Date: 2026-02-15

Tags: safety

References: RFC-0002, ADR-0020

Context

When an agent (e.g. Cursor, Claude Code) runs multiple tasks in parallel that each invoke govctl to create or modify RFCs, ADRs, or work items, concurrent writes to the same files or to the same directory can cause:

  1. File corruption — Two processes write to the same file; interleaved writes or truncate-then-write races produce partial or invalid content.
  2. ID collision — Work item creation uses find_max_sequence(work_dir, id_prefix) then writes a new file. Two processes can read the same max, both write the same ID or overwrite the same path (same date-slug).
  3. Lost updates — Read-modify-write (e.g. edit, set, bump) without coordination: one process overwrites the other’s write.

This is distinct from ADR-0020, which addresses ID collision across branches (merge-time). Here the scenario is same repository, multiple concurrent processes (e.g. multiple agent tasks in one workspace).

Constraints: govctl is a CLI; no daemon. Implementation must work across processes. No network or external services. Must remain portable (Unix/macOS/Windows where feasible).

Decision

Use process-level filesystem locking so that only one govctl process mutates the governance tree at a time.

  1. Scope of locking

    • Any command that modifies gov/ or writes to docs/ (render, new, set, add, edit, tick, bump, finalize, advance, accept, move, etc.) MUST acquire a lock before performing mutations and release it when done.
    • Read-only commands (list, get, check, status, show) do NOT need to hold the lock.
  2. Lock mechanism

    • A single gov-root lock file (e.g. gov/.govctl.lock or a lock in a well-known location under gov root). One lock for the entire gov tree.
    • Acquire: exclusive (write) lock on that file (e.g. flock(LOCK_EX) on Unix; equivalent on Windows).
    • Blocking: if lock is held by another process, wait with optional timeout; on timeout, fail with a clear error instructing the user to retry or avoid parallel govctl writes.
  3. Granularity

    • Coarse-grained (one lock per gov root) is chosen over per-artifact or per-directory locks to avoid deadlock and to keep implementation and behavior simple. Parallel agents serialize at the gov root; throughput is traded for correctness and simplicity.

Consequences

Positive

  • Prevents file corruption and ID collision under concurrent agent tasks.
  • Single lock file: no deadlock, no lock ordering, easy to reason about.
  • Portable: file locking is available on all supported platforms (flock/cfg with fallbacks).

Negative

  • Parallel govctl write commands serialize; one task may block until another finishes. Mitigation: agents can be designed to queue writes or run write commands sequentially; CLI documents the locking behavior.
  • Stale lock if process crashes without releasing. Mitigation: lock is process-scoped (OS releases on exit); optional timeout + clear error message for “stuck” waiters.
  • Slight complexity in CLI entrypoint: acquire lock early for write commands, release on all exit paths.

Neutral

  • Render (writing to docs/) is included in the lock scope so that render + new/edit from two processes do not interleave.

Alternatives Considered

File lock (gov-root): One exclusive lock for entire gov/ tree. Blocks concurrent writers until release. Chosen for simplicity and no deadlock.

Per-artifact lock: Lock only the file or directory being written. Rejected: deadlock risk (e.g. A holds rfc/ B holds adr/; A needs adr/ B needs rfc/), more complex lock ordering.

Write queue / single-writer daemon: One process accepts write requests over a socket or FIFO. Rejected: requires a long-running daemon, contradicts CLI-only design.

Documentation-only: Tell users/agents not to run write commands in parallel. Rejected: does not prevent races; agents and scripts often parallelize by default.

Atomic write + retry: Write to temp then rename; for work item ID, retry on collision. Rejected: avoids partial writes but does not fix read-modify-write races or deterministic ID collision from find_max_sequence.

ADR-0026: Add journal field to WorkItem for execution tracking

Status: accepted | Date: 2026-02-22

Tags: editing

References: RFC-0000

Context

During agent-driven governance workflows, agents naturally use work items as “working memory” to track execution progress. Currently, this working memory is stored in the description field, mixing multiple semantic purposes:

  1. Task declaration — “What needs to be done” (static scope definition)
  2. Execution tracking — Progress updates, bug fixes, verification results (dynamic, frequently updated)
  3. Planning adjustments — Next steps, design decisions (evolves during execution)

This mixing causes description to become very long (4000+ characters in observed cases) and conflates declarative “what” with imperative “how it’s going.”

Example: In WI-2026-02-21-004, the description field contains:

  • Initial implementation plan (Steps 1-6)
  • Multiple “Progress update (YYYY-MM-DD, scope)” sections with detailed execution notes
  • Bug fix records, verification results, and next-step planning

The notes field exists but is underutilized because its original intent (“observations and decisions made during work”) was not clear enough, and agents naturally reached for description as the primary writing surface.

Reference: RFC-0000:C-CONTENT defines the content model but does not distinguish between declaration and tracking semantics.

Decision

Add a new journal field to WorkItemContent as a structured array for execution tracking, distinct from description (task declaration) and notes (ad-hoc points).

TOML structure:

Each journal entry has three fields:

  • date (required): ISO date string “YYYY-MM-DD”
  • scope (optional): Topic/module identifier for this entry
  • content (required): Markdown text with progress details

Example work item with journal:

[content]
description = "Big-bang AST/IR v2 migration with 6 implementation steps..."

[[content.journal]]
date = "2026-02-21"
scope = "typub-html"
content = "v2 parse + serialize paths active; fixed footnote issues"

[[content.journal]]
date = "2026-02-21"
scope = "typub-markdown"
content = "Migrated renderer tests to v2 fixtures; fixed footnote refs"

Data structure (Rust):

pub struct JournalEntry {
    pub date: String,
    pub scope: Option<String>,
    pub content: String,
}

Semantic boundaries:

FieldPurposeUpdate Pattern
descriptionTask scope declarationDefine once, rarely change
journalExecution process trackingAppend on each progress
notesAd-hoc key pointsAdd anytime, concise
acceptance_criteriaCompletion criteriaDefine then tick

Backward compatibility: The journal field is optional with #[serde(default)]. Existing work items remain valid without migration. New work items can adopt the field incrementally.

Changes required:

  1. Update WorkItemContent struct in src/model.rs
  2. Update gov/schema/work.schema.toml
  3. Update render logic in src/render.rs to include journal section
  4. Update wi-writer skill documentation

Consequences

What becomes easier:

  • Clear separation of concerns: description stays focused on task scope; execution details go to journal
  • Better readability: Rendered markdown shows a clean structure with dedicated sections
  • Agent ergonomics: Agents have a designated place for execution tracking without polluting description
  • Historical traceability: journal entries preserve the execution timeline

What becomes more difficult:

  • None significant. The field is optional and additive.

Migration impact:

  • No migration required for existing work items
  • Agents may gradually adopt journal for new or active work items
  • Old work items with “progress updates” in description remain valid

Documentation updates:

  • wi-writer skill updated with field usage guidelines
  • work.schema.toml updated with journal field definition
  • Rendered markdown includes “## Journal” section after description

ADR-0027: Extend Alternative structure with pros, cons, and rejection_reason

Status: accepted | Date: 2026-02-22

Tags: schema

References: RFC-0000:C-ADR-DEF

Context

The current Alternative structure in ADRs only has two fields: text and status. This is insufficient for capturing structured decision rationale:

  1. No pros/cons tracking: When comparing options, the advantages and disadvantages are key decision factors, but they cannot be structured.

  2. No rejection reason: When an alternative is rejected, the reason is often scattered in the decision or context fields instead of being directly attached to the alternative.

  3. Manual workarounds: Current practice requires authors to write Markdown tables in the context field to compare options, which is not structured and cannot be processed programmatically.

Example of current limitation:

[[content.alternatives]]
text = "Option A: Sequential IDs"
status = "rejected"
# Where do I put the pros/cons? In context as markdown table?

Comparison with other fields:

  • WorkItem has structured acceptance_criteria with status and category
  • RFC has structured changelog with categorized entries
  • ADR alternatives should have similar structure for decision tracking.

Decision

Extend the Alternative structure with three new optional fields:

pub struct Alternative {
    pub text: String,
    pub status: AlternativeStatus,
    pub pros: Vec<String>,              // NEW: advantages
    pub cons: Vec<String>,              // NEW: disadvantages
    pub rejection_reason: Option<String>, // NEW: why rejected
}

Field semantics:

  • pros: List of advantages for this alternative
  • cons: List of disadvantages for this alternative
  • rejection_reason: If status is rejected, explains why

Backward compatibility: All new fields use #[serde(default)] and skip_serializing_if_empty, so existing ADRs remain valid without migration.

Consequences

What becomes easier:

  • Structured comparison: Each alternative has its own pros/cons attached
  • Clearer rendering: Rendered output can show options with their trade-offs
  • Better tooling: CLI can display alternatives in a structured format (e.g., comparison table)
  • Self-documenting decisions: The reason for rejection is directly linked to the alternative

What becomes more difficult:

  • None significant. The fields are optional and additive.

Migration impact:

  • No migration required
  • Existing ADRs with simple alternatives continue to work
  • New ADRs can opt into the extended structure

Rendering example:

## Alternatives Considered

### Sequential IDs (rejected)
- Pros: Simple, Readable
- Cons: Collisions in teams
- Rejected because: Does not solve the collision problem

### Author hash namespace (accepted)
- Pros: Auto isolation, Zero config
- Cons: Slightly less readable

ADR-0028: Migrate commands to skills format for cross-platform compatibility

Status: accepted | Date: 2026-02-22

Tags: skills-agents

References: ADR-0024, ADR-0023

Context

The project currently has two mechanisms for AI agent capabilities:

  1. Commands (.claude/commands/): Slash commands for workflow orchestration
  2. Skills (.claude/skills/): Knowledge augmentation for the main agent

Industry trend: Major AI coding platforms are converging on skills as the standard format:

  • Claude/Cursor: Skills can be triggered via slash commands (commands and skills are functionally equivalent)
  • Codex: Only supports skills, no commands

Current structure:

.claude/commands/
├── discuss.md    # Design discussion workflow
├── gov.md        # Governed implementation workflow
├── quick.md      # Fast path workflow
└── status.md     # Governance status (rarely used)

.claude/skills/
├── rfc-writer/
├── adr-writer/
└── wi-writer/

Problem:

  • Two similar concepts (commands vs skills) create confusion
  • Commands are not portable to Codex
  • status command has very low usage frequency

Decision

Migrate all workflow commands to skills format:

Migration:

SourceTargetAction
commands/discuss.mdskills/discuss/SKILL.mdMigrate
commands/gov.mdskills/gov/SKILL.mdMigrate
commands/quick.mdskills/quick/SKILL.mdMigrate
commands/status.mdDelete (low usage)

Format change:

Extend skill frontmatter to include command-specific fields:

---
name: gov
description: "Execute governed workflow — work item, RFC/ADR, implement, test, done"
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
argument-hint: <what-to-do>
---

Why keep current names:

  • discuss - Clear intent for design discussion phase
  • gov - Established shorthand for governed workflow
  • quick - Clear intent for fast path

Why delete status:

  • Very low usage frequency observed
  • Equivalent information available via govctl status CLI
  • Reduces maintenance burden

Consequences

Positive:

  • Single unified format for all agent capabilities
  • Portable across Claude, Cursor, and Codex
  • Reduces conceptual overhead (one concept instead of two)
  • Eliminates underutilized status command

Negative:

  • One-time migration effort (minimal: 3 files)
  • Breaking change for users who reference commands directly
  • Need to update any documentation referencing commands/

Migration steps:

  1. Create skill directories for discuss, gov, quick
  2. Convert command files to skill format (add name field, preserve allowed-tools/argument-hint)
  3. Delete commands/ directory
  4. Update ADR-0023 to reflect new structure

Future structure:

.claude/skills/
├── discuss/
│   └── SKILL.md
├── gov/
│   └── SKILL.md
├── quick/
│   └── SKILL.md
├── rfc-writer/
│   └── SKILL.md
├── adr-writer/
│   └── SKILL.md
└── wi-writer/
    └── SKILL.md

ADR-0029: Path-based nested field addressing for artifact edits

Status: accepted | Date: 2026-02-25

Tags: editing

References: RFC-0002, ADR-0007, ADR-0017, ADR-0027

Context

govctl currently edits artifacts with resource-scoped verbs (set, add, remove, tick), matching ADR-0017.

Problem Statement

The current CLI shape becomes verbose and awkward when users need to edit deeply nested fields, especially ADR alternatives extended by ADR-0027 (pros, cons, rejection_reason).

Concrete pain point today:

# Create or replace whole alternative entries
govctl adr add ADR-0001 alternatives "Option 3: Use Raft" --pro "Strong consistency"

# Remove by match or index
govctl adr remove ADR-0001 alternatives "Option 3" --exact

What is missing is direct nested addressing, for example: update only the second pro of the second alternative without rewriting the entire object.

Constraints

  • Preserve resource-first command architecture from RFC-0002.
  • Preserve verb semantics from ADR-0017 instead of replacing everything with a new universal verb.
  • Reuse existing array matching behavior from ADR-0007 where possible.
  • Keep backward compatibility for existing scripts and habits.

Options Considered

  • Option 1: Keep current field-only operations and rely on manual TOML edits for nested changes.
  • Option 2: Introduce a new universal edit command with JSONPath-like syntax.
  • Option 3: Keep current verbs, but allow a path expression in the field position for nested addressing.

Decision

We will introduce path-based nested field addressing as an additive capability, while keeping existing resource-scoped verbs (set, add, remove, tick) defined in ADR-0017.

This decision is primarily motivated by ADR-0027, which introduced structured ADR alternatives (pros, cons, rejection_reason) that need precise nested edits.

Path expressions will be accepted where a field name is currently accepted for get, set, add, and remove.

Path Syntax (proposed)

  • Grammar (strict): path := segment ('.' segment | "[" index "]")*
  • Segment token: segment := [a-z_][a-z0-9_]*
  • Index token: index := -?[0-9]+
  • Dot notation for object traversal: content.alternatives
  • Bracket notation for array indexing: alternatives[2].pros[2]
  • Index semantics: 0-based, with optional negative index for from-end addressing (aligned with ADR-0007 --at semantics)
  • Aliases for ergonomics:
    • alt -> alternatives
    • pro -> pros
    • con -> cons
    • reason -> rejection_reason

Alias Collision Rule

Canonical field names take precedence. Alias expansion applies only when the token is not an exact field name in the current object scope. This keeps future schema evolution safe and predictable.

Verb Semantics

  • get: existing read verb, now path-aware for scalar/object/array reads
  • set: replace scalar value at resolved path
  • add: append into array resolved by path
  • remove: remove by explicit indexed path, or by existing matcher options when path resolves to an array
  • remove conflict rule: explicit indexed paths and matcher flags (--exact, --regex, --all, pattern args) are mutually exclusive; the CLI MUST fail fast with a usage error when mixed.
  • tick: unchanged behavior; only checklist roots are supported (alternatives for ADR, acceptance_criteria for work item). Nested paths for tick are invalid.

Before and After Example

# Before: remove and re-add an entire alternative to change one nested value
govctl adr remove ADR-0001 alternatives "Option 3" --exact
govctl adr add ADR-0001 alternatives "Option 3: Use Raft" --pro "Updated pro"

# After: direct nested edit
govctl adr set ADR-0001 alt[2].pro[0] "Updated pro"

Validation Timing

  • Eager validation (parse time): path grammar, token class, alias normalization
  • Resolution-time validation: field existence, index bounds, target type compatibility for verb

Compatibility and Convergence

  • Existing top-level field syntax remains valid.
  • Existing adr add ... alternatives --pro/--con/--reject-reason remains supported during migration.
  • Convergence plan: docs and examples immediately prefer path syntax; legacy alternative-specific flags receive deprecation warnings after rollout stabilizes (target: two minor releases), then are removed only in a major release.

Consequences

Positive

  • Enables concise, direct nested edits such as alt[2].pro[2] without editing raw TOML.
  • Preserves current mental model (set/add/remove/tick) and command discoverability.
  • Reuses existing match semantics from ADR-0007, reducing conceptual fragmentation.
  • Creates a reusable abstraction for nested fields across ADRs and work items.

Negative

  • Adds parser and resolver complexity in the edit pipeline.
    • Mitigation: strict grammar, bounded depth, and dedicated parser tests (including fuzz/property tests).
  • Requires broader validation and diagnostics coverage.
    • Mitigation: explicit diagnostic matrix for parse/resolution/type errors and snapshot tests for representative failures.
  • Dual syntax during migration (--pro/--con and path syntax) can confuse users.
    • Mitigation: docs prefer path syntax immediately, deprecation warnings for legacy flags after rollout, and a published convergence timeline.
  • Documentation and examples require coordinated updates across guides and help text.
    • Mitigation: track doc updates in implementation work items and gate release on docs parity checks.

Neutral

  • No data migration is required for existing ADR files; the change is CLI-surface and parser behavior.
  • Alias set is intentionally small and closed (alt, pro, con, reason); future alias additions require explicit schema/governance update to avoid accidental drift.

Alternatives Considered

Option 1: Keep current field-only operations and use manual TOML edits for nested changes (rejected)

  • Pros: No new parser or resolver, Lowest immediate implementation risk
  • Cons: Poor CLI ergonomics for nested edits, Hard to script precise updates for ADR-0027 nested fields
  • Rejected because: Does not address the primary usability gap

Option 2: Add a universal edit verb with JSONPath-like expressions (rejected)

  • Pros: Single conceptual mutation entry point, Potentially expressive for advanced operations
  • Cons: Conflicts with verb separation rationale in ADR-0017, Higher migration and discoverability cost
  • Rejected because: Overlaps existing verbs and weakens current command architecture

Option 3: Keep verbs and add path-based field addressing (accepted)

  • Pros: Compatible with existing command model, Directly solves nested edit ergonomics, Supports incremental rollout with low script breakage
  • Cons: Introduces parser and resolver complexity, Creates temporary dual-syntax cognitive load during migration

ADR-0030: Parser strategy for path-based field expressions

Status: accepted | Date: 2026-02-25

Tags: editing

References: ADR-0029, ADR-0017, ADR-0007, RFC-0002

Context

govctl recently introduced path-based field addressing in ADR-0029 for commands like get/set/add/remove. During implementation review, we identified parser correctness risks in the current hand-written parser flow (for example, extra trailing segments being ignored, and some path-shape rules enforced inconsistently by verb).

Problem Statement

We need a parser design that guarantees strict grammar handling, full-input consumption, and stable diagnostics, while preserving existing CLI compatibility behavior for legacy field forms.

Scope

This ADR focuses on parser architecture for field-path expressions only:

  • grammar parsing and AST shape
  • parser technology choice
  • legacy compatibility policy (content.*, govctl.*, aliases)
  • validation layering (parse-time vs verb/resolution-time)

It does not decide broader CLI command architecture, which remains governed by RFC-0002 and ADR-0017.

Constraints

  • Maintain resource-first and verb-separated CLI semantics from RFC-0002 and ADR-0017.
  • Keep compatibility commitments from ADR-0029 for legacy dotted prefixes and short aliases.
  • Preserve deterministic diagnostic behavior (E0814 to E0818) for automation and tests.
  • Keep parser dependency and complexity proportionate to grammar size.

Options Considered

  • Option 1: Keep manual parser and harden it.
  • Option 2: Use a parser combinator library (winnow) with a typed AST.
  • Option 3: Use a PEG/grammar generator approach (pest/similar).

Decision

We will adopt winnow-based strict parsing with a typed FieldPath AST, replacing the ad-hoc character-walk parser for path expressions.

Technical Selection

winnow is selected because it gives us:

  • explicit grammar composition in Rust types
  • full-input consumption checks by default pattern (terminated(parser, eof))
  • precise, testable parse failures without introducing a full external DSL/toolchain
  • lower operational overhead than a separate grammar generator for this small grammar

Grammar Contract

  • path := segment (("." segment) | ("[" index "]"))*
  • segment := [a-z_][a-z0-9_]*
  • index := -?[0-9]+

Parsing MUST fail if any trailing tokens remain unconsumed.

Legacy Field Compatibility Policy

Compatibility is preserved as a normalization layer after parse, before resolution:

  • canonical field names always win over aliases in the same scope
  • supported aliases remain: ac, alt, desc, pro, con, reason
  • legacy two-segment prefixes remain: content.<field>, govctl.<field>
  • prefix collapse is limited to compatibility-allowed roots and known simple fields; invalid combinations fail with diagnostics

Validation Layering

  • Parse-time validation: lexical/grammar correctness, token class, full consumption
  • Normalization-time validation: alias/prefix compatibility rules
  • Resolution-time validation: existence, index bounds, verb/path shape constraints, type mismatch

Non-Goals

  • No expression language expansion (wildcards, slices, recursive descent) in this ADR
  • No change to command verbs or lifecycle semantics

Migration Plan

  1. Introduce winnow parser behind current parse_field_path API.
  2. Keep current diagnostics mapping (E0814/E0815/E0816/E0817/E0818).
  3. Add golden tests for legacy compatibility inputs.
  4. Add negative tests for over-deep/over-specified paths and verb-shape violations.
  5. Remove old parser implementation after parity tests pass.

Consequences

Positive

  • Eliminates a class of silent-acceptance bugs via full-input consumption.
  • Makes grammar behavior explicit and easier to reason about during review.
  • Provides a stable foundation for future extensions without reintroducing ad-hoc state logic.
  • Improves confidence in diagnostics by separating parse/normalize/resolve phases.

Negative

  • Adds a third-party parsing dependency.
    • Mitigation: keep dependency surface small and isolate parser module behind a narrow API.
  • Introduces a learning curve for maintainers unfamiliar with parser combinators.
    • Mitigation: document grammar and parser module invariants with examples and tests.
  • Migration requires careful parity testing to avoid compatibility regressions.
    • Mitigation: snapshot parity suite for legacy field forms and aliases before rollout.

Neutral

  • Runtime cost is expected to be negligible for CLI-scale path strings; this should be verified by micro-benchmarks in CI but is not expected to be user-visible.

Alternatives Considered

Option 1: Keep manual parser and harden it (rejected)

  • Pros: No new dependencies, Minimal refactor scope
  • Cons: Higher long-term maintenance risk for state-machine edge cases, Harder to prove full-consumption and grammar invariants
  • Rejected because: Recent review findings indicate brittle behavior under malformed or over-specified paths

Option 2: Use winnow parser combinators with typed AST (accepted)

  • Pros: Strict grammar with full-input consumption, Rust-native and testable composition, Balanced complexity for small grammar
  • Cons: Adds dependency and parser-combinator learning curve

Option 3: Use PEG/grammar generator approach (rejected)

  • Pros: Clear formal grammar artifacts, Good for larger language evolution
  • Cons: Heavier tooling/runtime surface for current grammar size, Additional integration overhead without near-term need
  • Rejected because: Overkill for current path grammar scope

ADR-0031: Unified Artifact Edit Engine with SSOT and Format Adapters

Status: accepted | Date: 2026-02-27

Tags: editing

References: ADR-0029, ADR-0030, ADR-0001, ADR-0017, ADR-0007, RFC-0002

Context

govctl artifact editing has evolved from simple field updates into nested path edits (per ADR-0029) with parser hardening work (per ADR-0030). The current implementation now mixes parser logic, alias/legacy normalization, verb-path validation, dispatch generation, and artifact-specific read/write behavior across large files.

Problem Statement

We currently pay complexity twice:

  1. We maintain substantial command semantics in hand-written Rust control flow.
  2. We effectively treat JSON and TOML as separate operational paths in parts of the stack, even though the underlying operation is the same: read structured document, modify addressed node, validate, write.

This increases code volume, review difficulty, and risk of behavioral drift between artifacts and formats.

Before/After (architecture intent)

  • Before: parser + routing + validation + handlers are coupled, with format concerns leaking into command logic.
  • After: one semantic edit engine (parse -> canonicalize -> resolve -> plan -> validate -> execute) with thin format adapters.

Constraints

  • Preserve resource-first and verb semantics from RFC-0002 and ADR-0017.
  • Preserve index and matcher semantics from ADR-0007 (0-based indexing, negative indices from end, existing conflict diagnostics).
  • Preserve user-facing path syntax and compatibility promises from ADR-0029 and ADR-0030.
  • Respect storage decisions from ADR-0001: ADR/Work artifacts remain TOML at rest unless separately decided.
  • Keep deterministic diagnostics and stable error codes for automation scripts.

Options Considered

  • Option A: Continue incremental cleanup of current architecture.
  • Option B: Standardize internal editing on JSON only (convert TOML at boundaries, no dedicated TOML adapter contract).
  • Option C: Introduce a single SSOT-driven semantic edit engine with explicit JSON/TOML adapters.

Decision

We will adopt Option C: a single SSOT-driven semantic edit engine with explicit format adapters.

Core Architecture

  1. Single semantic pipeline for all artifacts and formats:
    • parse -> canonicalize -> resolve -> plan -> validate -> execute
  2. Single SSOT model (edit-model.json + JSON Schema) defines:
    • field tree, indexability, verb capability matrix
    • alias/legacy mapping and conflict policy
    • validator bindings and handler IDs
  3. Single execution engine consumes typed EditPlan operations.
  4. Thin format adapters implement storage-specific read/write behavior:
    • JsonAdapter
    • TomlAdapter

Parser Selection

Per ADR-0030, parser implementation will use winnow (not a grammar generator), while grammar remains documented in PEG/EBNF style.

Field-token acceptance is strict:

  • parser accepts syntactic segments
  • resolver accepts only SSOT-known canonical fields/aliases
  • unknown fields fail with deterministic diagnostics

Compatibility and Convergence Policy

  • Existing path syntax and legacy forms from ADR-0029 remain supported during migration.
  • Canonical names take precedence over aliases on conflict.
  • Documentation will prefer canonical path syntax; legacy forms are compatibility-only.
  • Legacy form deprecation warnings begin after full V2 parity is reached.

Migration Plan

  1. Phase 1 (foundation): Introduce V2 SSOT, parser, typed EditPlan, and adapter interfaces behind feature-gated path.
  2. Phase 2 (shadow mode): Run V1 and V2 for ADR/Work operations; compare planned ops and rendered outcomes in tests.
  3. Phase 3 (cutover): Switch ADR/Work to V2, then RFC/Clause.
  4. Phase 4 (cleanup): Remove V1 dispatch branches, remove hand-written artifact/field/verb matches, tighten lint/test gates.

Completion Criteria

V2 is considered complete only when:

  • adding a new editable field requires SSOT changes only (no manual dispatch branching)
  • JSON and TOML share one semantic engine
  • compatibility test suite for legacy paths passes in V2 mode

Consequences

Positive

  • Reduces long-term maintenance cost by centralizing edit semantics in one engine.
  • Eliminates JSON/TOML behavioral drift risk by sharing the same plan/validation pipeline.
  • Makes parser and resolver behavior auditable through SSOT and generated tables.
  • Improves extensibility: new fields and verbs are primarily SSOT additions.

Negative

  • Migration complexity is significant because V1 and V2 must coexist temporarily.
    • Mitigation: enforce a bounded coexistence window (max two releases) with explicit phase exit criteria and deletion checklist.
  • Generator/SSOT errors can affect many paths at once.
    • Mitigation: schema validation at build-time, generated-table snapshot tests, and golden command fixtures per artifact/verb.
  • Temporary dual operation styles (legacy vs canonical path forms) can confuse users.
    • Mitigation: docs prefer canonical syntax immediately; legacy usage prints guidance warnings after V2 parity milestone.
  • Documentation and contributor onboarding work increases initially.
    • Mitigation: track docs updates as required migration work items and block V2 cutover completion until docs/tests are updated.

Neutral

  • Runtime overhead should remain negligible for CLI-scale paths, but this will be measured with parser and end-to-end micro-benchmarks before finalizing ADR status.

Alternatives Considered

Option A: Continue incremental cleanup on current architecture (rejected)

  • Pros: Lowest immediate implementation risk, No major migration event required
  • Cons: Continues structural duplication and code growth, Does not solve JSON/TOML semantic divergence risk
  • Rejected because: It optimizes short-term churn but leaves the root architecture problem unsolved.

Option B: Standardize internal editing on JSON only (rejected)

  • Pros: Maximizes reuse of mature JSON tooling and standards, Simplifies internal document mutation mechanics
  • Cons: Introduces conversion boundary risk for TOML-only semantics and formatting expectations, Weakens direct TOML-at-rest operational clarity established by ADR-0001
  • Rejected because: It shifts complexity to conversion boundaries and does not provide a first-class TOML contract.

Option C: SSOT-driven semantic engine with explicit JSON/TOML adapters (accepted)

  • Pros: Preserves storage-format independence while unifying semantic behavior, Enables SSOT-driven extensibility with lower long-term maintenance cost
  • Cons: Requires staged migration and temporary dual-path operation, Demands high-quality generator and parity tests to avoid systemic regressions

ADR-0032: Migration skill for adopting govctl in existing projects

Status: accepted | Date: 2026-03-02

Tags: migration

References: ADR-0023, ADR-0024, ADR-0028

Context

govctl currently assumes greenfield projects — govctl init creates the governance directory structure from scratch, and all workflows (skills, agents) assume artifacts exist from day zero.

Problem Statement

The majority of real-world projects that would benefit from govctl are existing codebases that lack formal governance. These projects have:

  • Undocumented architectural decisions embedded in code, comments, and tribal knowledge
  • Existing specifications scattered across markdown docs, wikis, or issue trackers
  • In-progress work tracked informally (GitHub Issues, Jira, sticky notes)
  • No artifact cross-references in source code

Adopting govctl today requires teams to either:

  1. Start fresh (losing existing context), or
  2. Manually create dozens of ADRs, RFCs, and work items — a tedious process that discourages adoption

Requirements

A migration skill should:

  • Guide an AI agent through systematically discovering and codifying existing decisions
  • Use only existing govctl CLI commands (no new CLI capabilities needed)
  • Support incremental migration (not all-or-nothing)
  • Produce well-structured artifacts that pass govctl check
  • Add [[...]] references to existing source code where decisions are implemented

Decision

We will create a migrate skill (.claude/skills/migrate/SKILL.md) that guides the agent through a multi-phase migration workflow using existing govctl commands only.

Migration Phases

Phase 0: Scaffold — Initialize govctl in the existing project.

  • Run govctl init (safe alongside existing files)
  • Read project structure (README, docs, config files) to understand the codebase

Phase 1: Discover — Systematically scan the project for implicit governance artifacts.

  • Decisions: Read architecture docs, README sections, config comments, and code patterns to identify undocumented architectural decisions
  • Specifications: Find existing specs, API contracts, or design docs that could become RFCs
  • Work in progress: Check issue trackers, TODO comments, and branch names for active work

Phase 2: Backfill ADRs — Create ADRs for discovered decisions.

  • For each significant decision found, create an ADR using govctl adr new
  • Populate context (what prompted the decision), decision (what was chosen), consequences
  • Add alternatives where the rejected options are known
  • Accept the ADR immediately (govctl adr accept) since these are historical records

Phase 3: Backfill RFCs (optional) — Create RFCs for existing specifications.

  • Only for projects that have existing specification documents
  • Create RFC + clauses from existing spec content
  • Finalize as normative and advance to stable (these specs are already implemented)

Phase 4: Annotate source — Add [[...]] references to existing code.

  • Scan source files for implementations of newly-created ADRs/RFCs
  • Insert // Implements [[ADR-NNNN]] or // Per [[RFC-NNNN:C-NAME]] comments
  • Run govctl check to verify references resolve

Phase 5: Establish baseline — Create work items for any in-progress work.

  • Create work items for known active tasks
  • Going forward, all new work uses the /gov workflow

Skill Properties

  • Interactive: The skill prompts the user at each phase to confirm discoveries and prioritize what to backfill
  • Incremental: Each phase can be run independently; partial migration is valid
  • Non-destructive: Never overwrites existing files; only adds governance artifacts alongside existing content
  • Idempotent: Running the skill again skips already-created artifacts

Consequences

Positive

  • Lowers adoption barrier — Existing projects can adopt govctl without starting from scratch.
  • Preserves institutional knowledge — Undocumented decisions get codified as searchable, cross-referenced ADRs.
  • Gradual onboarding — Teams can migrate incrementally, one module or decision at a time.
  • Agent-native — The skill leverages Claude Code’s ability to read codebases and synthesize decisions, making backfill practical.

Negative

  • Quality depends on agent understanding — Auto-discovered decisions may be incomplete or inaccurately described.
    • Mitigation: Interactive confirmation at each step; user reviews all generated artifacts.
  • Source annotation churn — Adding [[...]] references to existing code creates a large diff.
    • Mitigation: Phase 4 is optional and can be done incrementally per-module.
  • Historical ADRs may lack alternatives — Old decisions often don’t have documented rejected options.
    • Mitigation: The skill accepts “considered” as the only alternative when history is unclear.

Neutral

  • No new govctl CLI commands are needed — the skill composes existing commands.
  • The skill is bundled with govctl and installed via govctl sync, like other skills.

Alternatives Considered

Agent-assisted skill using existing govctl commands (accepted)

  • Pros: Zero new CLI code needed, Ships immediately as a bundled skill
  • Cons: Requires an AI agent to execute the workflow

New govctl migrate CLI command with auto-detection (rejected)

  • Pros: Works without AI agent, Deterministic output
  • Cons: Significant new CLI code to write and maintain, Auto-detection heuristics are brittle across project types
  • Rejected because: The discovery and synthesis tasks are inherently judgment-heavy — an AI agent handles ambiguity better than heuristic code. CLI commands can be added later if common patterns emerge.

ADR-0033: Distribute govctl agent integration as Claude Code plugin

Status: accepted | Date: 2026-03-04

Tags: plugin

References: ADR-0015, ADR-0024, ADR-0028

Context

govctl has a mature agent integration layer: 8 skills (gov, quick, discuss, commit, migrate, rfc-writer, adr-writer, wi-writer) and 4 agents (compliance-checker, adr-reviewer, wi-reviewer, rfc-reviewer) in .claude/. This works well for developing govctl itself, but creates a distribution problem for adopters.

Problem Statement

Every project that adopts govctl must manually recreate the agent configuration: copy skills, agents, and CLAUDE.md into their .claude/ directory. govctl init scaffolds a basic CLAUDE.md, but the full skill/agent suite requires manual setup and ongoing maintenance when govctl updates its workflows.

Claude Code’s plugin system (introduced in v1.0.33, documented at https://docs.claude.com/en/plugins) solves exactly this: a standardized package format with skills, agents, hooks, and MCP servers that can be installed once and used across all projects.

Constraints

  • ADR-0015 decided against MCP in favor of CLI-based agent discoverability — maintaining two interfaces (CLI + MCP) is a maintenance burden
  • ADR-0024 established writers as skills and reviewers as agents — this architecture maps directly to the plugin format
  • ADR-0028 migrated commands to skills for cross-platform compatibility — the unified skill format is already plugin-compatible
  • The plugin must work with any shell-capable agent, not just Claude Code (graceful degradation)
  • Plugin skills are namespaced (e.g., /govctl:gov instead of /gov)

Decision

We will package govctl’s agent integration as a Claude Code plugin with enforcement hooks, following the oh-my-claudecode pattern. The .claude/ directory IS the plugin content. The marketplace catalog at the repo root points to it.

Structure

govctl/
├── .claude-plugin/
│   └── marketplace.json      ← source: "./.claude"
├── .claude/                   ← plugin content (auto-discovered)
│   ├── skills/                ← already exists
│   ├── agents/                ← already exists
│   ├── hooks/
│   │   └── hooks.json
│   ├── scripts/
│   │   ├── post-edit-check.sh
│   │   ├── session-start.sh
│   │   └── pre-stop-check.sh
│   └── settings.local.json   ← gitignored, not copied
├── src/
├── gov/
└── Cargo.toml

No plugin.json inside .claude/ — the marketplace entry provides all metadata, and Claude Code auto-discovers skills/, agents/, hooks/ from the plugin directory.

Hook Enforcement

Three hooks provide automatic governance enforcement:

  1. PostToolUse (matcher: Write|Edit): Inspects the edited file path. If under gov/, runs govctl check and surfaces validation errors.

  2. SessionStart: Runs govctl status for context. Checks govctl binary availability.

  3. Stop: Runs govctl check. Warns about pending failures before session ends.

Distribution

cargo install govctl
/plugin marketplace add govctl-org/govctl
/plugin install govctl@govctl
/govctl:gov "implement feature X"
  • Zero duplication: .claude/ is the SSOT for skills, agents, and plugin content
  • One .claude-plugin/: marketplace.json at repo root, no nested manifest
  • Versioning: just stamp-plugin-version updates marketplace.json from Cargo.toml

Consequences

Positive

  • Zero duplication: .claude/ is both the local dev config and the plugin content
  • One-step installation for adopters: /plugin install govctl@govctl
  • Automatic governance enforcement via hooks
  • No build step, no sync task, no symlinks — just files in .claude/
  • No MCP server complexity — single codebase, single distribution, per ADR-0015
  • Plugin format is the Claude Code standard — compatible with marketplace distribution

Negative

  • Plugin skills are namespaced (/govctl:gov vs /gov) when installed as plugin (mitigation: only affects plugin users, not in-repo developers)
  • Hook scripts are shell-only — Windows users need WSL or Git Bash (mitigation: hooks are additive enforcement, not required functionality)
  • Binary dependency: plugin requires govctl installed separately (mitigation: SessionStart hook checks and provides install instructions)
  • Plugin format is Claude Code-specific — non-Claude-Code agents cannot use hooks or plugin metadata (mitigation: skills and agents are plain markdown, usable by any agent)
  • .claude/ directory gains additional files (hooks/, scripts/, .claude-plugin/) that are plugin-specific (mitigation: these are small, clearly organized, and don’t interfere with local dev)

Neutral

  • govctl init still works for non-Claude-Code users
  • Future MCP integration remains possible per ADR-0015 — the plugin format supports .mcp.json
  • Developers working on govctl see .claude/ as both their local config and the plugin source — this is a feature, not a bug

Alternatives Considered

Option A — Thin Plugin (skills + agents only, no hooks): Simplest approach, zero new code, but no automatic enforcement. Agent must remember to run govctl check manually. (rejected)

  • Pros: Zero new code, No shell scripts to maintain
  • Cons: No automatic governance enforcement, Agent must remember validation
  • Rejected because: Hooks are the high-leverage differentiator between ‘works with Claude Code’ and ‘great Claude Code plugin’. Without them, the plugin is just a file distribution mechanism.

Option C — Plugin + MCP Server: Full structured integration wrapping govctl CLI as MCP tools. Richest agent experience but doubles the API surface. (rejected)

  • Pros: Structured tool interface with typed parameters, Richer error handling
  • Cons: Two interfaces to maintain (CLI + MCP), MCP server is a separate process to manage, Significant new code (~1000+ lines)
  • Rejected because: Per ADR-0015, maintaining two interfaces is a maintenance nightmare for marginal parsing convenience. The CLI works. Shell-capable agents invoke it fine. The door remains open if demand materializes.

Option D — Separate repository (govctl-plugin): Independent repo with its own release cycle. (rejected)

  • Pros: Independent versioning, Smaller repo for plugin contributors
  • Cons: Sync between repos is error-prone, Skills and agents drift from main codebase
  • Rejected because: The skills and agents ARE the govctl agent layer. Splitting them into a separate repo creates a sync problem that doesn’t need to exist.
  • Cons: File duplication or symlink fragility, Requires build/sync step, Extra directory to maintain
  • Rejected because: The .claude/ directory already has the exact structure a Claude Code plugin expects (skills/, agents/). Adding a second directory is solving a problem that doesn’t exist.

ADR-0034: Use TOML as the canonical storage format for all governance artifacts

Status: accepted | Date: 2026-03-16

Tags: schema

References: ADR-0001, ADR-0014, ADR-0031, ADR-0032, RFC-0000, RFC-0002

Context

govctl currently stores ADRs, work items, and releases as TOML, while RFCs and RFC clauses remain JSON. In this ADR, “governance artifacts” means RFCs, clauses, ADRs, work items, and releases. Project config is out of scope. That split is no longer buying us anything useful.

Problem Statement

The format split leaks into loaders, writers, adapters, schema docs, help text, and migration behavior. ADR-0031 already had to introduce explicit JSON and TOML adapters just to keep one semantic edit engine honest. Keeping RFCs and clauses on JSON forever would preserve that special case in the exact place we are trying to simplify.

We also lack real schema validation for generated TOML artifacts. Today TOML artifacts are parsed structurally and then checked semantically, but they are not validated against machine-readable artifact schemas. That means malformed or drifted TOML can survive longer than it should. Before this change, release data was the worst special case: it lived in gov/releases.toml without a first-class artifact definition in RFC-0000 or an explicitly required JSON Schema contract.

Finally, existing repositories already contain JSON RFC and clause files. If we switch formats without an explicit migration boundary, we either keep dual-format support indefinitely or break existing repositories silently. Both are bad designs.

Constraints

  • Preserve the normative meaning of existing governance artifacts and references under RFC-0000 and RFC-0002.
  • Keep normal operation simple: after migration, the main load/edit/render paths should be TOML-only.
  • Respect ADR-0032 by keeping this migration command narrow and deterministic. This is not a heuristic project-adoption workflow.
  • Preserve auditability and deterministic failures for automation and agent workflows.

Options Considered

  • Keep the mixed JSON/TOML storage model and improve adapters further.
  • Standardize all governance artifacts on JSON instead.
  • Standardize all governance artifacts on TOML with an explicit repository migration step.

Decision

We will use TOML as the canonical on-disk source-of-truth format for governance artifacts because it removes a persistent storage-format special case, matches the existing direction of ADR/work/release storage, and gives humans a format they can read and edit without carrying JSON-only baggage forward.

  1. One storage format: RFCs, clauses, ADRs, work items, and releases will all be stored as TOML at rest.
  2. One normal code path: After explicit repository migration, steady-state govctl operations will treat TOML as the only supported artifact storage format.
  3. One compatibility boundary: Legacy JSON support and deterministic TOML shape upgrades will exist only inside a migration command that converts existing JSON RFC and clause files to TOML and applies govctl-managed structural upgrades such as release-file metadata normalization.
  4. One validation model: RFC, clause, ADR, work item, and release artifacts will each have a corresponding machine-readable JSON Schema, and generated or edited TOML will be validated against that schema after parsing and normalization.

Implementation Notes

  • RFC and clause definitions should converge on the same [govctl] metadata pattern already used by ADRs and work items, including a required schema field.
  • gov/releases.toml should stop being a schema-less special case. It should carry explicit file-level metadata, including a required schema field, alongside the [[releases]] collection.
  • The schema contract should be explicit rather than implied: one JSON Schema file per artifact type, stored under gov/schema/, with the TOML govctl.schema field selecting the corresponding version.
  • The migration command should be narrow by design: convert legacy JSON governance files already recognized by govctl. It must not become a general project-discovery tool or overlap with the broader migration skill from ADR-0032.
  • Post-migration normal operation should not keep a permanent dual-read compatibility layer. Legacy JSON handling belongs in the migration path, not in every loader and writer.
  • Before migration, normal commands should fail with an explicit migration-required diagnostic rather than guessing or partially operating on mixed-format repositories.
  • The migration command should rewrite only govctl-managed storage references. Arbitrary repo docs, tests, and scripts remain user-owned follow-up changes.
  • If accepted, this decision supersedes the storage split recorded in ADR-0001.

Consequences

Positive

  • Removes the last major on-disk format split in governance artifacts.
  • Makes storage expectations easier to explain: governance artifacts are TOML, rendered docs are projections.
  • Creates a clean place to contain legacy JSON support instead of spreading it across the whole codebase.
  • Enables real schema validation for all TOML governance artifacts, including releases, using one existing validation technology (jsonschema) after TOML parsing.

Negative

  • Existing repositories with JSON RFCs and clauses will require an explicit migration step before normal TOML-only operation. (mitigation: normal commands should emit a dedicated govctl migrate diagnostic instead of attempting mixed-format behavior.)
  • RFC and clause path conventions will change from .json to .toml, so docs, tests, and direct file-path tooling must be updated carefully. (mitigation: govctl migrate rewrites govctl-managed clause-path references, but user-maintained references remain explicit follow-up work.)
  • gov/releases.toml will need a small structural migration to add explicit metadata for schema validation. (mitigation: keep the release-entry payload shape stable and migrate the file automatically with deterministic rewrite rules.)
  • External scripts, CI glue, and older govctl versions that assume .json RFC paths will break after migration. (mitigation: this is an intentional compatibility drop that must be documented plainly in release notes and migration docs.)
  • A broad format migration touches foundational governance definitions, so review and rollout discipline matter. (mitigation: require draft review plus full govctl check validation before rollout.)

Neutral

  • This does not replace the broader project-adoption migration workflow in ADR-0032; it only adds a deterministic repository-format migration boundary.
  • The semantic meaning of RFCs, clauses, ADRs, and work items does not change. Only their canonical storage format and validation contract change.

Alternatives Considered

Keep mixed JSON/TOML storage with format adapters (rejected)

  • Pros: Lowest immediate disruption to existing RFC storage, Avoids a repo-wide format migration in the short term
  • Cons: Preserves storage-format branching in loaders, writers, docs, and tests, Keeps JSON/TOML drift as a permanent maintenance cost
  • Rejected because: This keeps the special case alive instead of deleting it.

Standardize all governance artifacts on JSON (rejected)

  • Pros: Would reuse the existing RFC and clause storage model, Could lean on mature JSON tooling and schemas
  • Cons: Moves ADRs, work items, and releases away from the format already chosen for human editing, Fights the existing TOML direction established across most governance artifacts
  • Rejected because: It optimizes around legacy RFC storage instead of the current human-facing workflow.

Standardize all governance artifacts on TOML with explicit migration (accepted)

  • Pros: Eliminates the on-disk format split in normal operation, Keeps compatibility code confined to a single migration boundary
  • Cons: Requires a carefully specified migration command, Creates one-time churn in paths, docs, and tests

ADR-0035: Decouple skill and agent installation from project initialization

Status: accepted | Date: 2026-03-17

Tags: skills-agents

References: RFC-0002, ADR-0033, ADR-0028

Context

govctl init currently bundles three concerns into one command: governance directory scaffolding (gov/), JSON Schema deployment, and agent asset installation (skills + agents to .claude/). ADR-0033 introduced plugin distribution, giving users a second path to receive skills and agents — globally, via the Claude Code plugin system.

Problem Statement

  1. Redundant local copies for plugin users. Users who install govctl as a Claude Code plugin receive skills and agents globally. govctl init also writes them locally, creating two copies with unclear authority.
  2. Missing schemas for old projects. Projects initialized with earlier govctl versions lack gov/schema/*.json files. The #:schema relative-path comments in TOML artifacts resolve to nonexistent files, breaking IDE validation. Neither govctl sync nor govctl migrate fills this gap.
  3. Unclear sync naming. govctl sync only syncs agent assets (skills + agents), but the name implies general synchronization.

Constraints

  • RFC-0002:C-GLOBAL-COMMANDS specifies init with “optionally creates .claude/commands/” — the skill dump was always optional.
  • RFC-0002:C-GLOBAL-COMMANDS requires new global commands to be added via RFC amendment and meet at least one criterion (multi-resource, project-level init/cleanup, or meta-information).
  • govctl sync is not specified in RFC-0002 — it exists only as an implementation convenience.

Decision

We will separate the three concerns as follows:

  1. govctl init creates governance structure (gov/ directories, config.toml, JSON Schemas). It no longer installs skills or agents. After completion, it prints a hint about govctl init-skills and plugin installation.

  2. govctl init-skills (replaces govctl sync) explicitly installs skills and agents into the configured agent_dir. This is the opt-in command for users who do not use the plugin. Supports -f to overwrite existing files.

  3. govctl migrate ensures all bundled JSON Schema files exist in gov/schema/, always overwriting with the latest version. This fills the gap for projects initialized with older govctl versions.

Implementation Notes

  • init removes the skill/agent writing loop and the hardcoded .claude path.
  • init-skills reuses the existing sync_commands() implementation unchanged.
  • migrate adds a schema-sync step that runs unconditionally (not gated by schema version), writing all ARTIFACT_SCHEMA_TEMPLATES entries to config.schema_dir().
  • RFC-0002:C-GLOBAL-COMMANDS is amended to add init-skills and update the init and migrate descriptions.

Consequences

Positive

  • Plugin users no longer get redundant local skill/agent copies from init
  • Old projects get working #:schema comments after running govctl migrate
  • Command names are self-documenting: init = governance, init-skills = agent assets
  • The hardcoded .claude path in init is eliminated; init-skills uses the configured agent_dir

Negative

  • Users who had govctl init in onboarding docs will find .claude/ empty after upgrading (mitigation: init prints a hint, and the changelog documents the change)
  • Two commands instead of one for full setup (mitigation: plugin users need zero commands for agent assets; CLI-only users run init then init-skills)

Neutral

  • govctl sync is removed as a command name; init-skills replaces it
  • Schema files are now overwritten on every migrate run, even if unchanged — this is safe since they are generated artifacts

Alternatives Considered

Keep init bundled: init continues to dump skills/agents alongside governance structure (rejected)

  • Cons: Redundant for plugin users, Hardcoded .claude path ignores agent_dir config
  • Rejected because: Plugin distribution per ADR-0033 makes unconditional local dumping obsolete

Add –skills flag to init instead of separate command: govctl init –skills dumps agent assets (rejected)

  • Cons: Discovery problem: users must know the flag exists, Couples governance init with agent concerns
  • Rejected because: Separate command is more discoverable and aligns with single-responsibility

ADR-0036: Restructure ADR chosen-option and migration semantics

Status: superseded | Date: 2026-04-06 Superseded by: ADR-0038

Tags: editing

References: ADR-0034, ADR-0031, ADR-0027, ADR-0032

Context

The current ADR model stores the chosen option as an accepted entry inside content.alternatives[]. That shape creates two related problems:

  1. It duplicates the decision itself. The chosen path is already described in decision, but tooling also expects an accepted alternative.
  2. It leaks checklist-style status semantics into decision options. govctl adr tick accepts done|pending|cancelled, which are internally mapped to accepted|considered|rejected for alternatives. This is implementation-centric rather than domain-centric and confuses both users and bundled skill examples.
  3. It makes migration and rendering harder. Historical ADRs may have incomplete alternative metadata, yet the current model has no explicit place to record migration gaps while keeping the artifact renderable.

We need a cleaner ADR model that:

  • makes the chosen option explicit without duplicating it as an alternative,
  • keeps alternatives focused on non-selected options,
  • structures consequences so mitigations attach to negative outcomes,
  • allows migration to produce schema-valid, renderable ADRs even when some historical intent cannot be fully recovered.

Decision

We will redesign ADR storage around four principles:

  1. Chosen option is first-class. ADR content gains an explicit selected_option field. The chosen path is no longer represented as an accepted alternative.
  2. Alternatives only model non-selected options. content.alternatives[] remains for options that were not chosen. Each alternative may keep pros, cons, and rejection_reason, but no longer carries a status field.
  3. Consequences become structured. content.consequences becomes a structured object with positive, neutral, and negative entries. Negative consequences may include mitigations.
  4. Migration state is explicit metadata. govctl.migration records whether an ADR needs post-migration review and carries warning entries describing unresolved historical gaps.

Migration semantics

  • Legacy accepted alternatives migrate into selected_option and are removed from alternatives.
  • Legacy rejected alternatives remain alternatives.
  • Legacy considered alternatives in accepted or superseded ADRs are migrated into alternatives with synthesized rejection rationale and a migration warning.
  • If migration cannot determine the chosen option, the migrated ADR remains renderable and schema-valid, but govctl.migration.state = "needs_review" and govctl check emits warnings until a human resolves it.

CLI semantics

govctl adr tick ... alternatives ... no longer participates in ADR option state. ADR editing uses direct field paths such as selected_option and alternatives[0].rejection_reason. tick remains checklist-oriented and continues to apply to work item acceptance criteria.

Recovered Selected-Option Advantages

  • Eliminates accepted-alternative duplication
  • Keeps unresolved migrations renderable

Consequences

Positive

  • The chosen option becomes explicit and no longer needs to be duplicated as an accepted alternative.
  • ADR CLI and skills can use domain language directly instead of checklist-style status remapping.
  • Migration gains a principled place to record unresolved historical gaps without breaking rendering.
  • Negative outcomes and mitigations become attachable data rather than prose hidden inside a markdown block.

Negative

  • This is a breaking schema change for ADR files, renderer output, and edit semantics.
  • Existing ADRs require a versioned migration and some will still need manual follow-up.
  • Bundled skills, reviewer guidance, and examples all need coordinated updates.
  • Requires a schema migration.

Neutral

  • decision remains a prose field; the redesign adds structure around it rather than replacing it with a fully object-shaped decision document.
  • The migration pipeline becomes responsible for one more schema step.

Alternatives Considered

Keep alternative status as considered/accepted/rejected (rejected)

  • Pros: Minimal data-model churn
  • Cons: Preserves confusing tick-to-status mapping, Continues duplicating the chosen option inside alternatives
  • Rejected because: Keeps the same semantic collision between checklist state and decision state.

Use a fully object-shaped decision document instead of keeping decision prose (rejected)

  • Pros: Captures rationale in more machine-readable form
  • Cons: Much larger writer, renderer, and documentation rewrite, Makes the redesign harder to adopt in one migration step
  • Rejected because: The immediate problem is chosen-option and migration semantics, not replacing ADR narrative writing with a new decision DSL.

Explicit selected_option field, structured consequences, and migration metadata (accepted)

  • Pros: Makes the chosen option explicit rather than implicit in prose and option status., Provides a dedicated place for migration-only review state.
  • Cons: Introduces a breaking schema change for ADRs., Requires coordinated migration and ecosystem updates.

ADR-0037: Canonical edit surface for nested artifact mutation

Status: accepted | Date: 2026-04-06

Tags: editing

References: ADR-0031, ADR-0029, ADR-0017, ADR-0030, ADR-0007, RFC-0002

Context

govctl currently exposes artifact mutation through resource-first verbs such as set, add, remove, and tick, with path-based field addressing layered in via ADR-0029 and strict parsing via ADR-0030. The semantic engine behind those commands is being unified per ADR-0031.

Problem Statement

The current CLI surface is still too shape-dependent for reliable agent use:

  1. Whether an operation uses set, add, remove, or tick depends on the target field’s storage shape rather than the user’s intent alone.
  2. Nested editing support is asymmetric. Some paths behave like true field paths, while others still rely on special-case command semantics.
  3. The CLI surface leaks artifact-specific implementation details, which increases agent failure rates and makes help text harder to generalize.
  4. Upcoming schema work, including richer ADR structures, will increase nested object/array combinations and amplify the problem if the edit surface remains verb-fragmented.

Constraints

  • Preserve resource-first command organization from RFC-0002.
  • Preserve the SSOT-driven engine direction from ADR-0031.
  • Keep a stable migration path for existing human users and scripts.
  • Make the canonical mutation interface regular enough that agents can synthesize commands from field paths without artifact-specific guessing.
  • Avoid introducing a new batch-specific input language unless single-operation ergonomics prove insufficient.

Options Considered

  • Option A: Keep set/add/remove/tick as the only mutation interface and continue expanding path support.
  • Option B: Introduce a canonical edit command with path-first operation flags, and keep existing verbs as compatibility sugar.
  • Option C: Replace existing verbs completely with a JSONPatch-like or DSL-heavy mutation language.

Decision

We will introduce a canonical path-oriented edit surface for governed artifact mutation:

govctl <resource> edit <ID> <path> --set <value>
govctl <resource> edit <ID> <path> --add <value>
govctl <resource> edit <ID> <path> --remove <pattern>
govctl <resource> edit <ID> <path> --tick <status>

where:

  • <path> is a canonical fully qualified field path
  • exactly one mutation flag is provided per invocation
  • existing resource-first verbs (set, add, remove, tick) remain available as human-friendly sugar that compile into the same semantic edit plan

Canonical Interface Rules

  1. Canonical path syntax is fully regular. It MUST support nested object and array traversal for arbitrary depth, subject to SSOT validation.
  2. Canonical paths prefer explicit field names. Aliases remain compatibility-only, but documentation and agent examples prefer full canonical paths.
  3. edit is the authoritative mutation interface. New nested-field capabilities are specified first against edit; shorthand verbs are layered on top.
  4. tick remains checklist-oriented. It stays available only where the schema marks a status-bearing checklist item. It is not the canonical mechanism for arbitrary state mutation.
  5. Path semantics are SSOT-defined. The engine resolves paths and operation legality from generated schema/rules, not from artifact-specific handwritten branching.
  6. This ADR standardizes single-operation editing only. Multi-step orchestration remains the responsibility of the calling agent or shell layer for now.

Compatibility Strategy

  • Existing commands such as govctl adr set ..., govctl adr add ..., and govctl work tick ... remain supported during migration.
  • Help text, docs, and agent-facing examples will progressively move to the canonical edit form.
  • Compatibility verbs are treated as sugar over the same EditPlan, not as separate semantic implementations.
  • No new YAML/JSON patch language is introduced in this phase.

Examples

govctl adr edit ADR-0001 content.decision --set "We will ..."
govctl adr edit ADR-0001 content.alternatives --add "Option A"
govctl adr edit ADR-0001 content.alternatives[0].pros --add "Readable"
govctl work edit WI-YYYY-MM-DD-NNN content.acceptance_criteria[0] --tick done

This keeps resource-first organization intact while giving both humans and agents a single canonical grammar for mutation.

Recovered Selected-Option Advantages

  • Gives humans and agents one stable canonical mutation grammar
  • Lets existing verbs converge onto the same EditPlan without immediate breakage
  • Keeps the target path visually primary when reading or typing commands

Consequences

Positive

  • Agents can synthesize mutation commands from one regular shape instead of guessing between multiple top-level verbs.
  • The CLI surface aligns with the SSOT edit engine in ADR-0031, reducing semantic drift.
  • Nested object/array edits can be documented once and reused across ADRs, RFCs, work items, and future artifact types.
  • Existing human-friendly verbs can remain as convenience entrypoints without blocking engine regularization.
  • The design does not add a separate patch document format, so the CLI remains focused on a single mutation grammar.

Negative

  • The CLI surface grows: users must understand that edit is canonical even if shorthand verbs still exist.
  • Help text, docs, examples, and tests require a coordinated rewrite.
  • Compatibility layering adds temporary maintenance cost until sugar commands fully delegate to the canonical path.
  • Multi-step batch edits are not made atomic by this ADR; callers still need orchestration logic when applying a series of mutations.
  • Requires dual-surface docs during migration.

Neutral

  • Resource-first organization is unchanged; only the mutation entrypoint is normalized.
  • This ADR does not itself redesign artifact schemas such as ADR consequences or alternatives. It defines the edit surface that future schema work can rely on.
  • If transactional batch mutation becomes necessary later, it can be addressed in a separate ADR with clearer evidence of need.

Alternatives Considered

Keep set/add/remove/tick as the only mutation interface and continue expanding path support (rejected)

  • Pros: Lowest immediate CLI churn, Keeps current verb-first UX intact
  • Cons: Agents still need field-shape-specific verb selection, Does not establish a single canonical mutation grammar
  • Rejected because: It fixes capability gaps incrementally but leaves the core ergonomics problem unresolved for automation.

Replace current verbs with a JSONPatch-like or DSL-heavy universal mutation language (rejected)

  • Pros: Maximum expressiveness in one command family
  • Cons: Higher cognitive load for humans, Too large a break from current resource-first mutation ergonomics
  • Rejected because: Over-corrects toward a mini language and sacrifices discoverability for power we do not currently need.

Add a canonical edit command with path-first operation flags, while preserving current verbs as sugar (accepted)

  • Pros: Establishes one canonical mutation grammar without breaking existing workflows., Keeps nested mutation semantics centered on field paths instead of ad hoc verb choice.
  • Cons: Expands the CLI surface during the transition period., Requires documentation and help text to teach the canonical form clearly.

ADR-0038: Keep ADR schema discussion-oriented and avoid broad migration

Status: accepted | Date: 2026-04-06

Tags: schema

References: ADR-0027, ADR-0036, ADR-0037

Context

We have two goals that now need to be balanced more carefully.

Problem Statement

  1. The canonical edit surface from ADR-0037 is valuable and should remain.
  2. The broader ADR schema redesign from ADR-0036 proved too heavy for the value it provides.
  3. In practice, ADR authoring works best when alternatives are written first, discussed, and then one option is marked as selected before the final decision prose is written.
  4. The selected_option plus structured-consequences redesign pushed the model toward a final-state representation and away from the natural discussion flow.
  5. The migration burden is not justified while this work is still on a PR branch and has not landed on the main branch.

Constraints

  • Preserve the canonical edit-surface work already captured in ADR-0037.
  • Preserve the discussion-oriented alternative model from ADR-0027.
  • Avoid a repository-wide ADR migration for a change that is not yet merged.
  • Keep the ADR schema simple enough that humans and agents can both use it reliably.

Options Considered

We considered keeping the full ADR-0036 redesign, keeping the current ADR schema and workflow, and adopting a smaller additive field for the selected option only.

Decision

We will keep the current ADR schema discussion-oriented and avoid the broad schema/migration redesign from ADR-0036 because:

  1. Authoring flow matters more than final-shape normalization. ADRs are written by exploring alternatives first and only then recording the final decision. The current alternatives-with-status model supports that flow directly.
  2. The migration cost is disproportionate. A schema and repository-wide migration is not justified for a redesign that has not landed on the main branch.
  3. The canonical edit surface already solves the more valuable problem. ADR-0037 gives us the regular mutation interface we wanted without requiring the ADR artifact itself to become deeply restructured.
  4. Future ADR refinement can still happen incrementally. If we later need a machine-readable chosen-option field or richer consequence structure, that should be justified by a narrower problem and designed without coupling it to a broad migration.

Implementation Notes

  • Keep content.consequences as prose markdown.
  • Keep content.alternatives[] with status = considered|rejected|accepted.
  • Continue to model the selected option by marking one alternative as accepted and then writing the final decision prose.
  • Do not introduce selected_option, structured consequences, or migration-specific ADR metadata in this line of work.

Consequences

Positive

  • Preserves the natural ADR writing flow: alternatives first, decision last.
  • Avoids a repository-wide ADR migration for a redesign that has not merged.
  • Keeps canonical edit-surface gains from ADR-0037 without tying them to a broader artifact rewrite.
  • Keeps ADR authoring understandable for humans and agents using today’s schema.

Negative

  • The chosen option remains represented partly by alternative status and partly by decision prose.
  • ADR tooling will have less machine-readable structure than ADR-0036 proposed.
  • Some future refinement pressure is deferred rather than eliminated. (mitigation: revisit only when a narrower, clearly justified problem emerges.)

Neutral

  • This decision supersedes the schema-and-migration redesign from ADR-0036 but does not change the canonical edit-surface direction from ADR-0037.
  • Existing ADR files remain valid without conversion.

Alternatives Considered

Keep ADR-0036 full redesign with selected_option, structured consequences, and migration metadata (rejected)

  • Pros: Makes the chosen option explicit, Provides more machine-readable structure
  • Cons: Encourages premature final-state authoring, Requires schema and repository migration
  • Rejected because: The migration and authoring costs are too high for a change that has not landed on the main branch.

Keep the current ADR schema and reinforce the alternatives-first workflow (accepted)

  • Pros: Matches the natural authoring flow of ADR discussion, Avoids repository-wide migration, Works with the canonical edit surface from ADR-0037
  • Cons: Keeps chosen-option state partly in alternative status and partly in decision prose

Add only a lightweight selected_option field and leave other ADR fields unchanged (rejected)

  • Pros: Gives tooling a direct chosen-option field
  • Cons: Still encourages agents to write the conclusion too early, Adds schema surface without solving the broader authoring-flow issue
  • Rejected because: It keeps the premature-conclusion problem while still introducing schema churn.

ADR-0039: Use SQLite FTS5 as read-only search index for governance artifacts

Status: accepted | Date: 2026-04-09

Tags: cli

References: RFC-0002, RFC-0004, ADR-0048

Context

govctl manages governance artifacts (RFCs, ADRs, clauses, work items, guards) as TOML files in gov/. As the corpus grows (currently 200+ artifacts, projected to reach 1000+ in active projects), finding artifacts by content becomes increasingly difficult.

Problem Statement

Users need to answer questions like “which ADR discussed caching?”, “which RFC clause mentions backward compatibility?”, or “which work items reference RFC-0002?”. Currently this requires:

  • grep over raw TOML files (poor UX, no ranking, no stemming)
  • govctl list + manual inspection (only searches titles)
  • Memorizing artifact IDs

None of these scale or provide relevance-ranked results.

Constraints

  • RFC-0002 establishes TOML files as the source of truth — any index must be derived, not authoritative
  • RFC-0004 governs concurrent write safety — the index must not interfere with the file locking protocol
  • The index must work offline with no external services
  • Rebuild must be fast enough to run transparently on every search query

Decision

Use SQLite FTS5 with lazy incremental sync as the search backend for govctl search, stored as derived local state under .govctl/index.db.

Design

  1. Index location: .govctl/index.db, with SQLite sidecars such as .govctl/index.db-wal and .govctl/index.db-shm when WAL mode is active. The database is disposable local state and is covered by the existing .govctl/ gitignore invariant.

  2. Catalog separation: The database may contain shared artifact catalog tables for ID-to-path lookup and freshness metadata per ADR-0048. Those catalog tables are shared lookup infrastructure. Search-specific FTS tables, ranking data, and snippets remain derived search data.

  3. Indexed content: RFCs, clauses, ADRs, work items, and guards. Each search document stores artifact ID, type, title, source path, stable status metadata where applicable, tags, refs, and a curated concatenation of searchable content fields. Work item descriptions, acceptance criteria, and notes are searchable; legacy inline journal entries remain render-only compatibility data and are not indexed. Raw TOML is not the search document.

  4. Sync strategy — lazy incremental: On every govctl search, compare current artifact path and freshness metadata against the local index manifest. New or changed files are parsed and upserted into the search projection. Deleted files are removed. Missing, corrupt, or incompatible index state is rebuilt.

  5. Freshness rule: govctl search must not return results from an index whose freshness cannot be established. If freshness cannot be established, it must rebuild, fall back to an uncached scan where possible, or return a diagnostic instead of silently returning stale results.

  6. No write-through optimization: Artifact write commands do not need to update the search FTS tables directly. Lazy sync remains correct for manual edits, branch switches, and govctl writes.

  7. Concurrency: SQLite WAL mode and transactions protect the local index from corruption during concurrent search invocations. The search index is not a governed artifact and does not participate in the RFC-0004 gov-root write lock.

  8. Explicit escape hatch: govctl search --reindex forces a full rebuild before querying.

Why This Design

  • .govctl/ is the existing local-state boundary for loop execution and other derived state.
  • Keeping the index out of gov/ avoids treating disposable search data as a governed artifact mutation.
  • Lazy sync avoids coupling between artifact write paths and search indexing.
  • SQLite FTS5 provides BM25 ranking and snippets without a daemon or external service.

Consequences

Positive

  • Users can find artifacts by content with relevance ranking instead of relying on raw grep, title-only lists, or memorized IDs.
  • The index is disposable and self-healing: deleting .govctl/index.db only removes local cache state, and the next search can rebuild it.
  • Lazy sync keeps search correct across manual edits, branch switches, and govctl writes without coupling every artifact mutation to the search backend.
  • Using .govctl/ keeps derived search data out of governed artifacts and rendered outputs.
  • Shared catalog metadata from ADR-0048 lets search avoid duplicating path and freshness discovery logic.

Negative

  • Adds rusqlite with bundled SQLite, increasing binary size and build complexity.
  • First search after a large branch switch or cache deletion may be slower while the local index rebuilds.
  • CJK text may require tokenizer improvements beyond the default English-oriented stemming setup.
  • Search must guard freshness carefully; returning stale results would be worse than a slower rebuild or diagnostic.

Neutral

  • The local SQLite database is a cache, not a new artifact storage format. TOML files remain the source of truth.

Alternatives Considered

SQLite FTS5 with lazy incremental sync: single-file read-only index using rusqlite (bundled), Porter stemming, BM25 ranking, and content-hash-based incremental updates on each search query. (accepted)

  • Pros: Battle-tested BM25 ranking out of the box, Single-file index, no daemon or external service, Porter stemming handles English morphology (cache/caching/cached), rusqlite is mature with bundled compilation — no system SQLite dependency, Lazy sync means no separate build step or cache invalidation protocol
  • Cons: Adds ~3MB to binary size from bundled SQLite, CJK segmentation requires additional tokenizer configuration

Tantivy (Rust-native full-text search): Use the tantivy crate, a Lucene-inspired search engine written in Rust. Supports BM25, tokenizers, and schema-defined fields natively. (rejected)

  • Pros: Pure Rust, no C dependency, More powerful query language (boolean, phrase, fuzzy), Purpose-built for search — better performance at scale
  • Cons: Much heavier dependency (~50 crates in dependency tree), Index is a directory of segment files, not a single file, Overkill for <1000 documents
  • Rejected because: Dependency weight and complexity are disproportionate to the scale of govctl’s artifact corpus. SQLite FTS5 covers the requirements with a single well-understood dependency.

In-memory inverted index with no persistence: Build a simple inverted index on every search invocation by scanning all TOML files, tokenizing content, and ranking by term frequency. No disk cache. (rejected)

  • Pros: Zero dependencies — no SQLite, no new crates, No cache invalidation problem — always fresh
  • Cons: Full rebuild on every query (~100ms at 200 files, grows linearly), No stemming or advanced tokenization without additional code, No BM25 — would need a custom ranking implementation
  • Rejected because: Lacks stemming and BM25 ranking out of the box. Rebuild cost scales linearly and becomes noticeable beyond 500 artifacts. The UX gap versus FTS5 is significant for the marginal dependency savings.

ADR-0040: Controlled-vocabulary tags for governance artifacts

Status: accepted | Date: 2026-04-09

Tags: schema

References: RFC-0002, ADR-0039

Context

As the govctl artifact corpus grows (currently 200+ artifacts), finding related artifacts by domain becomes difficult. Users resort to grep or memorizing IDs.

Problem Statement

There is no structured way to answer “show me everything related to caching” or “which ADRs touch the parser”. Artifact titles provide some signal, but titles are inconsistent and not designed for cross-cutting categorization.

Constraints

  • RFC-0002:C-RESOURCES defines the field surface for each artifact type — adding tags requires a schema amendment
  • RFC-0002:C-CRUD-VERBS governs how fields are mutated — tags must follow existing add/remove verb semantics
  • Tags must be diffable and reviewable in PRs (no hidden state)
  • The system should prevent tag sprawl — typos and near-duplicates degrade signal

Options Considered

Two tagging models: controlled vocabulary (registry-first) vs. free-form (tag-on-use). See alternatives for analysis.

Decision

We will use a controlled-vocabulary tag system where tags must be registered in a project-level allowed list before any artifact can reference them.

Why Controlled Vocabulary

The core trade-off is between friction and signal quality. Free-form tags have zero friction but degrade rapidly — typos, case variants, and synonyms fragment the taxonomy. In a governed workflow where artifacts are meant to be auditable and cross-referenced, unreliable metadata defeats the purpose.

A controlled vocabulary enforces consistency at the cost of a one-time registration step for each new tag. This cost is intentional: introducing a new domain category is a project-level decision that should be visible and reviewable.

Design Outline

  • Registry: a [tags] allowed list in gov/config.toml — flat, lowercase kebab-case strings
  • Artifact field: an optional tags array in the [govctl] section of RFCs, clauses, ADRs, work items, and guards (releases do not carry tags)
  • Management: registry-level new/delete/list commands; artifact-level tagging via existing add/remove verbs
  • Filtering: --tag flag on existing list commands for taggable resource types
  • Validation: govctl check rejects tags not in the allowed set; add rejects unregistered tags immediately

Detailed command syntax, schema changes, and validation rules will be specified in an RFC-0002 amendment.

Constraints

  • No maximum tag count per artifact — signal quality is maintained by the controlled vocabulary, not by limiting labels
  • The initial seed list of allowed tags is a separate operational decision from the mechanism itself
  • Tags complement but do not replace potential future full-text search (see ADR-0039)

Consequences

Positive

  • Cross-cutting discovery becomes a first-class operation — “show me everything about caching” is a single command
  • Controlled vocabulary prevents tag sprawl — consistency is enforced, not hoped for
  • Tags are part of the TOML source — diffable, reviewable in PRs, greppable
  • Agents can enumerate available tags and use them programmatically
  • Extends existing add/remove/list verb model — minimal new CLI grammar

Negative

  • Friction to introduce a new tag — requires a config edit before first use (mitigation: this friction is intentional and the operation is a one-liner)
  • Retroactive tagging of existing artifacts requires effort (mitigation: incremental adoption — untagged artifacts simply don’t appear in filtered queries)
  • Schema change across all five taggable artifact types (mitigation: tags is optional with empty-array default — existing artifacts remain valid without modification)

Neutral

  • govctl tag becomes a new top-level command namespace for registry management
  • The tag vocabulary will need periodic curation as the project evolves — orphaned or overly broad tags should be pruned
  • Tags complement but do not replace full-text search; ADR-0039 remains a viable future option if content-level discovery is needed
  • An RFC-0002 amendment is a prerequisite before implementation — this ADR authorizes the design direction but not the schema change

Alternatives Considered

Controlled vocabulary: tags registered in gov/config.toml before use, enforced by govctl check. Lowercase kebab-case, flat list. (accepted)

  • Pros: Prevents tag sprawl — typos and near-duplicates are caught at check time, Registry is diffable and reviewable in PRs, Tag list is enumerable — agents and CLI completion can offer suggestions, Removing a tag from the registry is an explicit, auditable decision
  • Cons: Friction to add a new tag — requires a config edit before first use

Free-form tags: any string can be used as a tag on any artifact. No registry. Tags are created implicitly on first use. (rejected)

  • Pros: Zero friction — tag immediately without config changes
  • Cons: Tag sprawl is inevitable — cache vs caching vs Cache are all different tags, No way to enforce consistency across contributors, Removing a stale tag requires finding and editing every artifact that uses it
  • Rejected because: In a governed workflow, uncontrolled metadata defeats the purpose of structured artifacts. Tag sprawl would quickly make filtering unreliable.

No tags — improve search and filtering instead: rely on title grep, rendered markdown search tools (rg, qmd), or future FTS (ADR-0039) to find artifacts by content rather than adding structured metadata. (rejected)

  • Pros: Zero schema changes — no new fields, no config section, no validation rules, No tagging discipline burden on authors
  • Cons: Finding all artifacts related to a topic requires remembering the right search terms, No enumerable taxonomy — agents cannot discover what categories exist, Cross-cutting queries remain ad hoc and fragile
  • Rejected because: Search finds text matches, not intentional categorization. Tags express author intent about which domain an artifact belongs to — a dimension that free-text search cannot reliably recover.

ADR-0041: Self-update and cargo-binstall binary distribution

Status: accepted | Date: 2026-04-13

Tags: release

References: RFC-0002, ADR-0018, ADR-0033

Context

govctl is distributed via cargo install govctl and as prebuilt binaries on GitHub Releases. The release CI (.github/workflows/release.yml) already produces binaries for five platform targets: x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-apple-darwin, aarch64-apple-darwin, and x86_64-pc-windows-msvc.

Problem Statement

Two gaps exist in the binary distribution story:

  1. No in-place update. Users must remember to re-run cargo install govctl or manually download from GitHub Releases to get a new version. There is no built-in way to check for or apply updates.

  2. No cargo binstall support. cargo-binstall can install prebuilt binaries from GitHub Releases without compiling from source, but requires [package.metadata.binstall] in Cargo.toml to locate the correct asset. Without this metadata, cargo binstall govctl falls back to a full source build.

Constraints

  • RFC-0002:C-GLOBAL-COMMANDS requires new global commands to meet at least one criterion: (1) multi-resource, (2) project-level init/cleanup, or (3) meta-information about the CLI itself. A self-update command qualifies under criterion 3.
  • ADR-0018 established “one canonical way” — the update mechanism should be singular.
  • Release assets use the naming convention govctl-v{version}-{target}.{ext} (tar.gz for Unix, zip for Windows).
  • The project already depends on reqwest for HTTP (via other crates), so adding network capability is not a new dependency class.

Decision

We will use the self_update crate for a built-in govctl self-update command and add [package.metadata.binstall] to Cargo.toml for cargo-binstall support, because:

  1. Existing infrastructure fits perfectly. The release CI already produces platform binaries with naming that self_update expects (govctl-v{version}-{target}.{ext}). No CI changes needed.

  2. Minimal effort, maximum coverage. The self_update crate handles the hard parts (API queries, platform detection, archive extraction, binary replacement) in ~20 lines. cargo-binstall metadata is a 4-line addition to Cargo.toml.

  3. Two complementary install paths, one asset layout. Users who installed via cargo binstall can update via cargo binstall govctl. Users who installed via direct download or govctl self-update can update in place. Both paths consume the same GitHub Release assets.

Consequences

Positive

  • Users can update govctl with a single command (govctl self-update) regardless of how it was originally installed
  • cargo binstall govctl installs prebuilt binaries in seconds instead of compiling from source (~2 min)
  • Both update paths share the same GitHub Release assets — no additional CI or hosting required
  • Version check (govctl self-update --check) enables scripted staleness detection in CI or hooks

Negative

  • New runtime dependency on self_update crate and its transitive dependencies (mitigation: the crate is well-maintained with 8M+ downloads; feature-flag to compile only the GitHub backend + rustls)
  • Binary replacement requires write permission to the install directory (mitigation: clear error message when permission is denied, suggesting sudo or ownership fix)
  • GitHub API rate limits apply to unauthenticated requests — 60 requests/hour per IP (mitigation: self-update is infrequent; document GITHUB_TOKEN env var for authenticated requests if needed)

Neutral

  • cargo install govctl continues to work unchanged — this adds paths, does not replace existing ones
  • Plugin users (ADR-0033) are unaffected — plugin updates are managed by Claude Code’s plugin system

Alternatives Considered

self_update crate with GitHub Releases backend: Use the self_update crate (v0.44, ~8M downloads, actively maintained) to query GitHub Releases API, download platform-appropriate binary, and replace the running executable. Pair with cargo-binstall metadata in Cargo.toml so both self-update and cargo-binstall share the same release asset layout. (accepted)

  • Pros: Minimal code (~20 lines) — the crate handles API queries, platform detection, archive extraction, and binary replacement, Actively maintained with broad adoption (8M+ downloads), Reuses existing release CI assets without changes — asset naming already matches, cargo-binstall support is additive metadata only, zero code, Both update paths share one asset layout, reducing maintenance
  • Cons: Adds a runtime dependency (~5 transitive crates for HTTP, archive, self-replace)

Manual implementation with reqwest: Implement GitHub Releases API querying, asset download, archive extraction, and binary replacement manually using reqwest and flate2/tar crates. (rejected)

  • Pros: Full control over behavior and error messages, No dependency on third-party update crate
  • Cons: Significant implementation effort (~200+ lines) for a solved problem, Must handle platform detection, archive formats, binary replacement, and edge cases manually, Ongoing maintenance burden for update logic
  • Rejected because: The self_update crate already solves this reliably. Reimplementing is unnecessary complexity for marginal control benefit.

Shell out to cargo install or cargo binstall: Instead of a built-in self-update, invoke cargo install govctl or cargo binstall govctl as a subprocess. (rejected)

  • Pros: Zero new code for the update mechanism itself, Leverages existing package manager infrastructure
  • Cons: Requires Rust toolchain (cargo install) or cargo-binstall installed separately, Slow for source builds — full compilation on every update, Poor UX — error messages come from external tools, not govctl, Cannot work in environments where govctl was installed via direct binary download
  • Rejected because: Depends on external toolchain being present. Users who installed from GitHub Releases would not have cargo available. Per ADR-0018, prefer one canonical path.

ADR-0042: Enforce ADR writing order with structural gates

Status: accepted | Date: 2026-04-14

Tags: validation

References: ADR-0027, RFC-0001

Context

The adr-writer skill prescribes a specific writing order — context, alternatives, mark alternatives as accepted/rejected, decision, consequences — but nothing in the CLI enforces it. Today, an agent or user can write decision on a fresh ADR with zero alternatives, or accept an ADR with empty context and no rejected options.

Problem Statement

Without structural enforcement, ADRs drift toward “conclusion-first” writing: a decision is stated without evidence that alternatives were considered. This undermines the purpose of ADRs as justificatory artifacts per ADR-0027.

The threshold of “at least 2 alternatives, with at least 1 accepted and 1 rejected” comes from the adr-writer skill’s core principle: “Let the alternatives show the discussion.” A decision that evaluated zero alternatives is not a decision — it is an assertion. A decision with only one option (the chosen one) has no visible trade-off. Two alternatives (one chosen, one rejected) is the minimum structure that demonstrates deliberation.

Current State

  • govctl adr set <ID> decision has no precondition checks
  • govctl adr accept <ID> only validates the status transition (proposed -> accepted) per RFC-0001:C-ADR-STATUS, not content completeness
  • govctl check validates schema and cross-references but has no ADR completeness rules
  • The adr-writer skill documents the order but cannot enforce it

Constraints

  • Historical backfills are a legitimate use case where alternatives may not be recoverable — enforcement must have an escape hatch
  • Write-time gates should not block exploratory drafting of other fields (context, alternatives, consequences) — only decision is order-sensitive
  • The force flag is the established override pattern in govctl (used by init, init-skills, delete); it applies to the lifecycle gate (adr accept --force) but not to the write-time gate

Decision

We will enforce ADR writing order at two points: when the decision field is written, and when the ADR is accepted, because:

  1. Write-time gates catch conclusion-first thinking at the source. Blocking decision before alternatives are evaluated forces the author to consider options before committing to a conclusion. This is the critical moment — once a decision is written, the mental model shifts from exploration to defense. This gate is strict and not bypassable.

  2. Lifecycle gates provide a completeness checkpoint. Acceptance requires evaluated alternatives per the adr-writer skill’s prescribed order and the minimum-deliberation threshold described in the context.

  3. The force flag on adr accept preserves historical backfill workflows. When alternatives cannot be reconstructed, the lifecycle gate can be bypassed explicitly via adr accept --force rather than silently.

The specific validation rules (minimum alternative count, required statuses) are implementation details guided by the adr-writer skill’s prescribed order and the minimum-deliberation threshold described in the context.

Consequences

Positive

  • ADRs become structurally complete before decisions are recorded — alternatives-first thinking is enforced, not just recommended
  • Agents cannot shortcut the process by writing decision before evaluating options
  • Acceptance gate catches incomplete ADRs even when write-time gate was bypassed
  • Historical backfills remain possible via the force flag with explicit intent

Negative

  • Authors who prefer to draft decision first and refine alternatives later face friction on every ADR (mitigation: this friction is intentional — the force flag exists for genuinely exceptional cases like historical backfills, not as a routine workflow bypass; the expected frequency of force usage should be low)
  • Validation logic spans two code paths (edit and lifecycle), which adds maintenance surface as the ADR schema evolves (mitigation: the checks are field-presence and count checks with clear error messages; both paths share the same validation function)

Neutral

  • Existing accepted ADRs are unaffected — the gates only apply to future write and accept operations
  • The adr-writer skill documentation remains the same; the CLI now enforces what the skill recommends

Alternatives Considered

Both write-time and lifecycle gates: Gate the decision field behind alternatives completeness, and gate acceptance behind overall ADR completeness. Both gates bypassable with the force flag for historical backfills. (accepted)

  • Pros: Enforces alternatives-first thinking at the moment it matters most, Lifecycle gate provides a second checkpoint at acceptance time, Consistent with the adr-writer skill prescribed order
  • Cons: Adds validation logic to two code paths (edit and lifecycle)

Lifecycle gate only: Enforce completeness only at adr accept time, no write-time restrictions on setting decision. (rejected)

  • Pros: No new edit-path complexity, Allows flexible drafting order
  • Cons: Decision can be written without evidence of alternatives-first thinking, Quality check only at acceptance, not at authoring time
  • Rejected because: Lifecycle-only enforcement misses the critical moment: when the decision is being written. By then, the conclusion-first pattern is already established.

No enforcement: Keep the current behavior where the adr-writer skill documents the order but the CLI does not enforce it. (rejected)

  • Pros: Zero implementation effort
  • Cons: No enforcement at all — relies entirely on skill guidance and human discipline, Agents can and do skip alternatives when not enforced
  • Rejected because: The adr-writer skill already documents the order. The problem is that documentation alone does not prevent conclusion-first writing.

ADR-0043: Redirect journal entries to local .govctl storage

Status: superseded | Date: 2026-05-31 Superseded by: ADR-0047

References: ADR-0032, ADR-0026, RFC-0000:C-WORK-DEF

Context

ADR-0026 added a journal field to WorkItemContent for execution tracking. It was designed as an in-file array of structured entries (date, scope, content) within the work item TOML under gov/work/.

The journal field serves two distinct purposes that are now in tension:

  1. Execution trace — round-by-round logs during iterative implementation loops (high frequency, high verbosity, ephemeral value after closure)
  2. Institutional memory — curated summaries of what was done and why (low frequency, concise, permanent value)

The next-generation /loop skill requires the work item to drive an iterative execution cycle where each round produces structured journal entries, detailed round logs, and guard output files. Storing all of this in the work item TOML creates unacceptable noise: diff pollution, commit hygiene degradation, mixed concerns between plan/outcome and execution log, and unbounded size growth.

The resolution is to separate execution state from governance artifacts. The .govctl/ directory (a local, gitignored directory for execution state that is not durable governance) becomes the home for loop execution state, while the work item returns to being a pure outcome artifact.

This is a breaking schema change: the journal field is removed from the work item TOML schema, and all existing journal entries (58 of 144 work items currently have them) must be extracted to the new location.

RFC conflict: RFC-0000:C-WORK-DEF currently mandates journal as part of the [content] section. This ADR proposes removing that field, which directly contradicts the normative clause. The RFC clause MUST be amended as part of implementation — the implementing work item will track both the code changes and the clause amendment together.

Decision

We will remove the journal field from WorkItemContent and redirect all journal operations to .govctl/loops/<WI-ID>/journal.toml.

Key invariants

  1. Single source of truth: Journal data lives exclusively in .govctl/loops/<WI-ID>/journal.toml. The work item TOML contains no journal entries.
  2. CLI surface unchanged: govctl work add WI journal, govctl work show WI, and govctl work remove WI journal continue to work identically from the user’s perspective. Internally they read/write the journal file directly.
  3. .govctl/ is local state: Created by govctl init, added to .gitignore, the loops/ subdirectory created on-demand.
  4. Automated migration: A schema v2 → v3 migration step extracts inline journals from existing work items into the new location.
  5. Backward compat: During the transition, v2 work items with inline journals render read-only with a warning. govctl check emits a diagnostic prompting migration.
  6. RFC amendment: RFC-0000:C-WORK-DEF will be amended to remove journal from the [content] section, reflecting that journal is no longer a work item field.

What this does NOT specify

The exact journal.toml schema, migration implementation steps, CLI command internals, and specific diagnostic codes are implementation details that belong in the implementing work item, not in this ADR.

Work item fields after this change

FieldLocationPurpose
descriptionwork item TOMLTask scope declaration
acceptance_criteriawork item TOMLCompletion criteria (scope contract)
noteswork item TOMLDurable constraints, lessons, retry rules
journal.govctl/loops/<WI-ID>/Execution process tracking (local, ephemeral)

Consequences

Positive

  • Work items become pure outcome artifacts — clean diffs, no execution noise, smaller files
  • Journal operations gain a dedicated, structured storage with room for round metadata without schema churn on the work item itself
  • .govctl/loops/ provides a natural home for future loop state (round logs, guard output files) without further breaking changes
  • Migration is automated via govctl migrate — same framework used for v1→v2

Negative

  • Breaking schema change: v2 work items with inline journal require govctl migrate. Mitigation: the migration step is automatic and idempotent; govctl check emits a warning for unmigrated items so users are prompted.
  • Journal data is not version-controlled: if .govctl/ is deleted (e.g., git clean -fdx), execution history is lost. Mitigation: govctl init adds .govctl/ to .gitignore automatically; the notes field captures durable learnings for cross-clone sharing; this ephemeral-by-design property is documented.
  • Remote clones don’t include journal history: new contributors see work items without execution context. Mitigation: notes field carries durable learnings that survive cloning; the journal is a local development aid, not an institutional record.
  • Large blast radius across the codebase: changes touch model, render, edit, migrate, init, check, and schema layers. This increases regression risk and requires coordinated testing across the journal read/write paths.

Neutral

  • The notes field remains in the work item TOML as the sole durable, freeform text field — its role sharpens to “things future work must remember”
  • CLI surface is unchanged — govctl work add WI journal works identically from the user’s perspective
  • The migration follows the existing versioned step framework from cmd/migrate.rs
  • JournalEntry struct is reused in the new location; only its storage path changes

Alternatives Considered

Chosen: Remove journal from work item schema, redirect to .govctl/loops/

See decision section for full rationale and key invariants. (accepted)

Rejected: Dual-write — keep journal in work item for institutional memory, add .govctl/loops/ for execution trace

Maintain journal in the work item TOML for curated, human-written summaries. Add .govctl/loops/<WI-ID>/ for detailed round logs and guard output. Two layers of journaling.

Rejected because:

  • Creates ambiguity: which journal is authoritative?
  • Requires agents to remember to write to both locations
  • The in-file journal still accumulates noise during active work
  • Duplicates the concept — “journal” means two different things depending on where it lives
  • Violates SSOT principle that the codebase already enforces elsewhere (rejected)

Rejected: Redirect journal to .govctl/, add a closure_summary field to work item

Move journal to .govctl/loops/. Add a new closure_summary field to the work item that the loop skill writes at closure — a curated, committed summary of what happened.

Rejected because:

  • notes already serves this purpose (“durable constraints, lessons, retry rules future steps must remember”)
  • Adding a new field for closure summaries creates yet another text field with unclear boundaries
  • The journal itself, in .govctl/loops/, is available locally for anyone who needs the detail
  • Keeps the work item schema minimal — only fields with clear, distinct purposes (rejected)

ADR-0044: Unified loop model for single and multi-WI execution

Status: accepted | Date: 2026-05-31

References: RFC-0006

Context

The /loop skill needs to drive work items to completion through iterative rounds. Two distinct use cases emerged:

  1. Single work item iteration: Agent works on one WI until acceptance criteria are satisfied
  2. Multi-WI batch execution: Agent creates multiple related WIs with dependencies, then iterates through them as a batch

The question: should these be handled by separate primitives (/loop for single WI, /batch for multiple WIs) or a unified primitive?

Key observations:

  • Work items naturally form DAGs (dependencies)
  • The execution mechanism is identical: resolve dependencies → iterate → verify → terminate
  • The state model is identical: .govctl/loops/<loop-id>/ works for both
  • Agents already use the pattern: “batch create WIs, then iterate through all of them”

Decision

We will use the unified model: a single /loop skill that accepts one or more work item IDs.

Key design points:

  1. /loop WI-001 drives a single work item
  2. /loop WI-001 WI-002 WI-003 drives multiple work items with dependency resolution
  3. Work items declare dependencies via depends_on field
  4. Execution state lives in .govctl/loops/<loop-id>/
  5. Downstream applications choose execution model (sequential/parallel)

This treats single-WI and multi-WI cases as the same primitive with different cardinality.

Consequences

Positive

  • One mental model to learn instead of two.
  • State management is consistent (.govctl/loops/ works for both single and multi-work-item loops).
  • Natural support for DAGs through work item dependencies.
  • Agents can use the same pattern for both use cases.
  • Future enhancements apply to both automatically.

Negative

  • Initial implementation is more complex because dependency resolution is present even for single-work-item loops. Mitigation: single-work-item loops use the same planner with an empty dependency graph.
  • Users who only need single-work-item iteration may see multi-work-item options as overhead. Mitigation: the command surface keeps the one-work-item invocation as the simple path.
  • Documentation must cover both use cases. Mitigation: docs introduce the single-work-item case first, then describe multi-work-item dependency behavior as an extension.

Neutral

  • Aligns with existing agent workflow patterns (batch create work items, then iterate).
  • No breaking changes to existing /gov or /quick skills.

Alternatives Considered

Separate primitives: distinct /loop (single WI) and /batch (multiple WIs) skills (rejected)

  • Pros: Simpler initial implementation
  • Cons: Two concepts with overlapping semantics, Forced choice for users, Duplicate state management
  • Rejected because: Underlying mechanism is identical; separate skills create artificial distinction

Unified model: single /loop skill accepts one or more WI IDs (accepted)

  • Pros: Simpler mental model, Consistent state model, Natural DAG support
  • Cons: Slightly more complex implementation

ADR-0045: Work item dependency declaration via depends_on field

Status: accepted | Date: 2026-05-31

References: RFC-0000:C-REFERENCE-HIERARCHY, RFC-0006

Context

Work items can depend on other work items, creating execution ordering constraints. The question: should dependencies be declared via a new depends_on field, or by reusing the existing refs field?

Key considerations:

  • refs is already used for cross-referencing RFCs and ADRs (informational)
  • Dependencies are blocking (“cannot proceed until this completes”)
  • Refs are informational (“I am aware of this artifact”)
  • The loop needs to distinguish between hard dependencies and soft references
  • Work items may reference RFCs/ADRs they implement while also depending on other work items

Decision

We will add a separate depends_on field to work items for declaring execution dependencies.

Key design points:

  1. depends_on contains work item IDs that must complete successfully before this work item can start
  2. refs remains for informational cross-references (RFCs, ADRs, related work items)
  3. A work item can have both refs (I implement RFC-0001) and depends_on (I need WI-001 to finish first)
  4. Work item schemas include depends_on as an optional [govctl] metadata field
  5. The loop uses depends_on to resolve a transitive dependency closure before execution
  6. The loop uses depends_on for dependency ordering and failure propagation
  7. Cyclic dependencies and missing dependency IDs are detected and rejected at loop start

This separates blocking dependencies from informational references, making intent explicit.

Consequences

Positive

  • Explicit semantics: dependencies are clearly marked as blocking.
  • Loop planning can reliably distinguish dependencies from references.
  • Work items can reference what they implement and what they depend on without ambiguity.
  • Dependency closure gives agents and humans a deterministic view of the executable set.

Negative

  • Schema change required: work item JSON Schema must accept optional govctl.depends_on. Mitigation: the field is additive and optional.
  • Slightly more metadata for users to understand. Mitigation: refs remains informational and depends_on is used only for blocking execution dependencies.
  • Existing work items that used refs to imply dependencies may need manual cleanup. Mitigation: loops only treat depends_on as blocking, so legacy refs remain safe informational links.

Neutral

  • Aligns with RFC-0000:C-REFERENCE-HIERARCHY because refs stays informational.
  • No breaking changes to existing refs usage.

Alternatives Considered

Reuse refs field for all cross-references (rejected)

  • Pros: No schema change, Fewer fields
  • Cons: Ambiguous semantics, Loop must guess dependency vs reference, Conflates informational and blocking relationships
  • Rejected because: Ambiguous semantics; loop cannot distinguish hard dependencies from soft references

Separate depends_on field for work item dependencies (accepted)

  • Pros: Explicit semantics, Clear intent, Allows both refs and depends_on
  • Cons: Schema change required

ADR-0046: Use loop-centric execution state storage

Status: accepted | Date: 2026-05-31

References: ADR-0043, RFC-0006, ADR-0047

Context

ADR-0043 chose a work-item-centric local execution-state layout under .govctl/loops/<WI-ID>/. ADR-0047 then removed execution history from the work item field surface while preserving render compatibility for legacy inline data.

RFC-0006 introduces a unified loop model where one loop can drive one or more work items. A per-work-item storage root cannot represent a multi-work-item loop because dependency graph, execution order, aggregate lifecycle, failure propagation, and resumption are loop-level concepts.

RFC-0006 now specifies .govctl/loops/<loop-id>/state.toml as the loop state anchor. That supersedes older storage-path wording that treated a per-loop execution-log file as the primary execution-tracking location. This ADR records the storage orientation for loop execution state so implementation does not inherit the older work-item-centric layout or legacy execution-history terminology.

Decision

We will store loop execution state by loop ID under .govctl/loops/<loop-id>/.

The required state anchor is .govctl/loops/<loop-id>/state.toml. Optional detailed per-round artifacts live below the same loop directory as loop-level round records, for example .govctl/loops/<loop-id>/rounds/round-NNN.toml. Round artifacts may mention relevant Work Item IDs in their payload, but the canonical storage path is loop-level rather than per-work-item.

Loop resumption supports two lookup paths: explicit lookup by loop ID, and root-set discovery when the caller provides the same explicit root work item set and exactly one matching non-terminal loop state exists. Ambiguous root-set matches require the caller to provide a loop ID.

Work item files remain outcome artifacts. Durable context belongs in notes; execution trace belongs in loop state and round artifacts. ADR-0047 remains authoritative for removing execution history from the work item field surface. This ADR replaces the older work-item-centric storage direction from ADR-0043 with loop-centric execution state storage and resolves stale future-storage wording in favor of state.toml.

Consequences

Positive

  • Enables unified multi-work-item loop execution with one shared state root.
  • Keeps dependency graph, execution order, lifecycle, failure propagation, and resumption state together.
  • Preserves the boundary that work item files are durable outcome artifacts, not execution traces.
  • Aligns local state layout with RFC-0006 and the ADR-0047 field-surface removal.
  • Gives resumption a deterministic fallback: exact loop ID first, root-set discovery only when unambiguous.

Negative

  • Existing experiments that wrote per-work-item local state need migration or removal. Mitigation: this work predates a stable loop implementation, so compatibility can be limited to explicit migration code or documented cleanup.
  • Loop ID generation becomes part of the storage contract. Mitigation: RFC-0006 constrains loop IDs to safe path segments and requires state to record the loop ID.
  • Root-set discovery requires scanning local loop state when no loop ID is provided. Mitigation: scanning is limited to non-terminal state.toml files under .govctl/loops/, and ambiguous matches are rejected.

Neutral

  • Detailed per-round artifacts are optional; state.toml is the required coordination point.
  • The .govctl/loops/ directory remains local execution state and is not a governed artifact.

Alternatives Considered

Keep work-item-centric execution state storage (rejected)

  • Pros: Smallest change to the older local-state direction
  • Cons: Multi-WI coordination becomes complex, Resumption requires scanning multiple directories, Cannot represent one loop-level lifecycle for several work items
  • Rejected because: A per-work-item state root cannot represent a multi-work-item loop lifecycle, dependency graph, failure propagation, or resumption state.

Use loop-centric execution state storage (accepted)

  • Pros: Natural multi-WI support, Shared loop state, Simpler resumption
  • Cons: Requires stable loop ID generation and lookup behavior

Use a per-loop execution-log file as the primary state anchor (rejected)

  • Pros: Retains the older execution-log naming convention
  • Cons: Cannot hold authoritative lifecycle and dependency graph state without becoming a mixed-purpose file, Conflicts with RFC-0006’s state.toml storage contract, Keeps future loop execution tied to legacy execution-history terminology
  • Rejected because: Loop execution needs an authoritative state file for lifecycle, dependency graph, work item statuses, and round counts; detailed logs may be separate optional artifacts, but state.toml is the coordination point.

ADR-0047: Remove journal from work item field surface for loop-centric execution state

Status: accepted | Date: 2026-05-31

References: ADR-0043, ADR-0026, RFC-0006, RFC-0000:C-WORK-DEF

Context

ADR-0026 added a journal field to work items for execution tracking. ADR-0043 proposed removing it entirely and redirecting execution tracking to a work-item-centric .govctl/loops/<WI-ID>/ layout. RFC-0006 then introduced a loop-centric model where .govctl/loops/<loop-id>/state.toml is the state anchor for loop execution.

Three problems with ADR-0043’s “remove and redirect” approach:

  1. Breaking change: Some work items may contain legacy inline execution-history entries. Removing the field entirely would force immediate migration.
  2. ADR-0043 is superseded by RFC-0006: Its target path (.govctl/loops/<WI-ID>/) conflicts with the loop-centric model (.govctl/loops/<loop-id>/).
  3. RFC-0000:C-WORK-DEF mandates journal: Removing it contradicted the normative clause without a proper amendment path at the time this decision was made.

The loop execution model (RFC-0006) makes inline execution-history data obsolete: loop execution state in .govctl/loops/<loop-id>/state.toml is the source of truth for active execution tracking. Any work item’s inline data is legacy compatibility data.

Rather than preserve journal as a separate read-only field, we remove it from the path-addressable work item field surface. Existing inline data may still be parsed so work show and render output can display historical entries without forcing an immediate migration.

Decision

Remove journal from the path-addressable work item field surface. journal MUST NOT be accepted by work get, work add, work edit, work remove, or work tick as a separate field.

For backward compatibility, implementations MAY continue to deserialize legacy inline content.journal entries and render them from work show / work item render output. This compatibility path MUST NOT make journal available as a normal editable or fetchable field.

Loop execution state is stored through the loop-centric state model in RFC-0006 and ADR-0046, not through a work item field.

Consequences

Positive:

  • Existing work items with legacy inline data continue to render correctly
  • Clear model boundary: journal is not a Work Item field even though legacy data can render
  • Historical execution data remains inspectable through work item show/render output when present
  • Establishes loop-centric state as the future path for active execution tracking
  • Supersedes the conflicting ADR-0043 with a more practical approach

Negative:

  • Legacy inline data may persist in external work item files, adding minor file size overhead
  • Compatibility parsing remains until the project intentionally removes legacy render support
  • No automated migration path for durable insights from legacy inline data to notes (manual process)

Neutral:

  • govctl check gains an informational diagnostic for work items with legacy inline data
  • JournalEntry struct and render code remain in the codebase for legacy render compatibility
  • New work items omit content.journal

Alternatives Considered

Remove journal from field surface while preserving render compatibility (accepted)

  • Pros: Clear field model: journal cannot be fetched or edited separately, Historical entries remain visible through show/render, No breaking changes for work items with legacy inline data
  • Cons: Legacy journal data persists indefinitely, Render compatibility keeps journal parsing code

Remove journal field entirely and force migration (rejected)

  • Pros: Clean break with no legacy compatibility path
  • Cons: Requires forced migration; destroys readable history, Breaking change for work items with legacy inline data
  • Rejected because: Immediate forced migration is unnecessary; ADR-0043 target path also conflicts with RFC-0006 loop-centric model

ADR-0048: Use local artifact catalog for direct lookup

Status: accepted | Date: 2026-06-04

References: RFC-0002, RFC-0004, ADR-0039

Context

Many govctl commands that operate on one artifact currently load an entire artifact collection and then search in memory for the requested ID. This is simple and correct at small scale, but it makes common commands such as work show, work edit, verify --work, and loop execution pay full-directory scan and parse costs even when the filesystem layout or a small local index could identify the target path directly.

The search feature planned by ADR-0039 needs similar file freshness metadata. If search owns the only cache, core CLI lookup would become accidentally coupled to full-text search. If every command continues to scan independently, search does not solve the broader performance problem.

The key constraint is authority: governed TOML artifacts remain the source of truth. Any cache used for lookup must be derived local state, and commands must still read and validate the target artifact before acting.

Decision

Use a project-local derived artifact catalog for direct artifact lookup.

The catalog records artifact kind, ID, source path, and file freshness metadata. It is stored under .govctl/ as local state and is not a governed artifact. Commands may use the catalog to find a candidate path for an ID, but the catalog never authorizes mutations by itself: the command must read the target file and verify that the artifact’s stored ID matches the requested ID before it acts.

The catalog is conceptually separate from full-text search. Search may reuse the catalog’s path and freshness metadata, but search ranking, snippets, and FTS tables remain search-specific derived data.

For artifact kinds with deterministic source paths, such as RFCs and clauses, commands should resolve paths directly and avoid the catalog when a simple path check is sufficient. For artifact kinds whose filenames are not fully determined by ID, such as work items and ADRs, commands should use the catalog first and fall back to a bounded collection rescan that repairs stale or missing catalog entries.

Consequences

Positive

  • Single-artifact commands can avoid full collection scans in the common case.
  • Search can reuse shared freshness metadata without owning core CLI lookup.
  • Stale cache entries are recoverable because authoritative artifact content is still read from TOML.
  • The .govctl/ local-state boundary keeps derived lookup state out of governed artifacts and rendered output.

Negative

  • Adds a local cache invalidation path that must be tested carefully.
  • Commands that use the catalog must verify ID/path agreement before mutation, or stale entries could become unsafe.
  • The first command after a branch switch or large artifact edit may still need a bounded rescan to repair catalog metadata.

Neutral

  • Full-project commands such as check, status, and bulk render still need broad loading. The catalog optimizes targeted lookup, not semantic validation.

Alternatives Considered

Derived local artifact catalog: Maintain a .govctl local-state catalog for ID-to-path lookup and freshness metadata, while still validating the target artifact before any read or mutation result is trusted. (accepted)

Keep full collection scans: Continue loading each whole artifact collection for single-ID commands and rely on search indexing only for search queries. (rejected)

  • Rejected because: This preserves correctness but leaves the common single-artifact command path slow and lets search solve only one symptom instead of the shared lookup problem.

ADR-0049: Adopt read-only cockpit model for TUI v2

Status: accepted | Date: 2026-06-06

Tags: tui

References: RFC-0007, RFC-0003, RFC-0006, RFC-0002

Context

TUI v2 needs to become more useful and more readable for humans working in a governed repository.

Problem Statement

The current TUI is primarily a dashboard plus RFC/ADR/work item browser. It does not expose newer governance concepts such as project-wide search, persisted loop state, dependency DAGs, or check diagnostics. At the same time, govctl already has a mature CLI mutation model for edits, lifecycle transitions, dry-run behavior, diagnostics, and write locking.

Constraints

  • RFC-0003 defines the existing TUI browsing baseline.
  • RFC-0007 defines TUI v2 behavior for a read-only cockpit.
  • RFC-0002 owns CLI resource and search semantics.
  • RFC-0006 owns loop state and loop execution semantics.
  • First-phase TUI v2 must serve humans, not agents or machine parsing.

Options Considered

We considered keeping the current TUI and adding isolated views, building a full CRUD TUI editor, and building a read-only human cockpit with loop DAG visualization.

Decision

We will build TUI v2 as a read-only human cockpit with loop DAG visualization.

The first phase of TUI v2 will focus on human understanding: project overview, artifact browsing, search, persisted loop state, dependency DAGs, and diagnostics. It will not implement artifact editing, lifecycle transitions, loop execution, migration, rendering, or other mutations.

Implementation Notes

  • TUI v2 may show suggested CLI commands for mutating workflows, but it must not execute those mutations.
  • Loop DAG rendering should use persisted loop state from RFC-0006 rather than recomputing a separate execution model.
  • Search behavior should reuse RFC-0002:C-SEARCH-COMMAND semantics instead of introducing TUI-only query behavior.
  • Responsive terminal layouts should degrade to readable simpler views rather than preserving broken multi-pane layouts.

Consequences

Positive

  • TUI v2 gets a coherent product shape instead of another set of isolated list/detail additions.
  • Humans can inspect project state, search context, loop progress, DAG dependencies, and diagnostics from one terminal surface.
  • The existing CLI remains the single mutation authority for artifact edits, lifecycle transitions, loop execution, rendering, dry-run, and locking.
  • The loop DAG view makes dependency readiness and blocked downstream work understandable without reading raw state files.

Negative

  • Users who want a full terminal editor must still switch to CLI commands for mutations. Mitigation: TUI v2 can display suggested commands without executing them.
  • Visual DAG layout adds complexity that simple lists do not have. Mitigation: keep the layout deterministic, test the data model separately from widget rendering, and provide readable fallbacks for large graphs or narrow terminals.
  • Search and diagnostics views may expose more information than fits comfortably on small terminals. Mitigation: prioritize stable summaries, selected-item inspectors, and responsive single-column fallbacks.

Neutral

  • This decision does not prevent future write-capable TUI workflows. It requires those workflows to be designed later against the existing edit model, dry-run behavior, diagnostics, and write-lock rules.
  • Disposable .govctl search/catalog index refresh remains acceptable when governed by the existing search freshness contract; persisted loop state remains read-only in the TUI.

Alternatives Considered

Keep current TUI and add isolated feature views (rejected)

  • Pros: Smallest incremental change, Low initial implementation risk
  • Cons: Leaves dashboard/list/detail as the organizing model, Makes search, loops, and diagnostics feel bolted on, Does not establish a coherent human cockpit information architecture
  • Rejected because: This would continue the existing pattern of isolated TUI additions rather than solving the product shape problem.

Build a full interactive CRUD TUI editor (rejected)

  • Pros: Provides one integrated terminal surface for browsing and editing, Could be attractive for humans who prefer TUI workflows
  • Cons: Duplicates CLI edit, lifecycle, dry-run, diagnostics, and lock semantics, Raises risk of a weaker parallel mutation model, Greatly expands first-phase scope before the cockpit model is proven
  • Rejected because: First-phase TUI v2 should not create a second mutation surface parallel to the governed CLI.

Build a read-only human cockpit with loop DAG visualization (accepted)

  • Pros: Creates one coherent product shape for overview, browsing, search, loops, and diagnostics, Preserves CLI ownership of mutations and lifecycle gates, Makes loop dependency state understandable to humans through a visual DAG, Can be implemented and tested incrementally without weakening artifact authority
  • Cons: Users still need to run CLI commands for edits and lifecycle transitions, DAG layout and responsive terminal rendering add UI complexity