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-references —
refsand[[...]]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 passed1— 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"]
include is the positive scan domain and uses Git gitignore path-pattern
semantics. Project .gitignore files provide the baseline exclusions.
Governance-specific exclusions and re-inclusions belong in .govignore files:
# Skip generated source evidence
generated/
# Restore one governed subtree excluded by .gitignore
!fixtures/
!fixtures/governed/
.govignore uses normal gitignore ordering and ! re-inclusion, and its rules
take precedence over .gitignore. Re-including a descendant requires
re-including each excluded parent directory. govctl prunes excluded directories
before reading their contents.
An optional source_scan.pattern override must be a valid regular expression
whose capture group 1 returns the complete artifact ID for every match. Unknown
and outdated reference diagnostics report the normalized source path followed
by a one-based line and byte column.
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"]
Each guard is a TOML file in gov/guard/:
#:schema ../schema/guard.schema.json
[govctl]
id = "GUARD-LIFECYCLE-TESTS"
title = "lifecycle tests pass"
refs = ["RFC-0000"]
[check]
command = "cargo test --test lifecycle_tests"
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 command --set "npm run lint"
govctl guard edit GUARD-MY-LINT 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
| Field | Required | Description |
|---|---|---|
id | Yes | Unique guard identifier (e.g., GUARD-LINT) |
title | Yes | Human-readable description |
refs | No | Related RFCs/ADRs |
command | Yes | Shell command to execute from project root |
timeout_secs | No | Max execution time (default: 300s) |
pattern | No | Regex pattern that must match stdout+stderr |
Guard Behavior
- A guard passes when its command exits with code 0 (and matches
patternif 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> donesucceeds
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
govctl work move <WI-ID> done runs the same effective required guards. Do not
run govctl verify --work <WI-ID> immediately before that move; doing so
executes the guards twice. Use independent verification for early feedback,
diagnosis, or workflows that leave the Work Item active.
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_guardswhen verification is enabled - plus the work item’s
verification.required_guards - minus any explicitly waived guards
Choosing Guard Granularity
Treat default_guards as the intersection of checks required by every Work
Item, not as a catalog of everything the project can verify. A default guard
should be necessary even for documentation-only work, fast enough for every
completion gate, stable, and independent of optional services.
Keep reusable checks narrow and name them for the risk domain they cover, such as lifecycle tests, schema tests, or CLI parsing tests. Add those guards to affected Work Items:
govctl work edit WI-2026-01-17-001 verification.required_guards --add GUARD-LIFECYCLE-TESTS
Full test suites, full lint suites, integration tests, and other expensive aggregate checks should remain available as guards, but normally be required only by Work Items that change shared infrastructure or cross multiple risk domains. One-off diagnostic commands do not need Guard artifacts.
Repeated waivers are not a substitute for correct scope. If many unrelated Work
Items waive the same default guard, remove it from default_guards and require
it only where its risk applies.
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.
Search
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 # Adds counts and non-terminal project state
The output includes a schema version and derives its command tree from the
running CLI. Context mode omits terminal artifact details and offers only
read-only discovery commands; use resource show commands or installed skills
for deeper guidance.
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 Integration
Install or update govctl’s user-scoped integration through the agent runtime’s native plugin mechanism:
govctl agent doctor all
govctl agent install claude
govctl agent install codex
govctl agent update all
doctor is read-only. install preserves existing Codex reviewer-role files;
update refreshes govctl’s installed role files. Start a new agent session
after installation or update so the runtime reloads its integration. Both
runtimes load bundled skills and hooks from their native plugin. Claude also
loads Markdown reviewer agents from that plugin; Codex reviewer agents are
standalone TOML roles managed by the same command.
Claude and Codex load separate hook manifests so each client receives fields and output in its native protocol. At session start, govctl uses normal upward project discovery and injects compact active-work and loop context only when the working directory belongs to a governed project. It stays silent in unmanaged directories and reports damaged governance state as non-blocking recovery context.
Before a direct edit to lifecycle-managed artifacts, the hook advises using the
resource-specific CLI when it can express the change. The edit is never blocked:
direct editing remains the recovery path for unsupported operations, followed by
govctl check. The plugin does not run project-wide validation at the end of
every turn.
Use init-skills only when a project-local or custom-directory copy is needed:
govctl init-skills --format claude
govctl init-skills --format codex
govctl init-skills --dir /path/to/agent-config
This direct projection does not register a native user plugin. It writes bundled workflow skills, writer/helper skills, and reviewer agents to the resolved destination.
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 | |
|---|---|---|
| What | Upgrade existing govctl artifacts to current format | Adopt govctl in an existing project |
| When | After updating govctl version | When starting governance in a brownfield repo |
| Effect | Syncs TOML artifacts, schemas, ignore configuration, and local support files | Discovers decisions, backfills ADRs, annotates source |
| Risk | Low — transactional, reversible | Medium — 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/. Schema versions below 3 require
migration with a compatible earlier govctl version before upgrading. Legacy RFC
or clause JSON storage is rejected explicitly. Use the /migrate skill when
bringing an existing project under governance for the first time.