ADR-0018: Global Command Shortcuts vs Strict Resource-First Syntax
Status: accepted | Date: 2026-01-19
References: RFC-0002, ADR-0017
Context
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:
- Keep
listandnewas convenient global shortcuts that delegate to resource-first implementations? - Remove them entirely and enforce strict resource-first syntax per RFC-0002?
- 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
-
RFC Compliance: RFC-0002:C-GLOBAL-COMMANDS deliberately defines the exhaustive list of global commands.
listandneware not on that list, indicating they should be resource-scoped. -
Design Clarity: The resource-first pattern (
govctl <resource> <verb>) provides a clear, predictable structure:govctl rfc list- list RFCsgovctl work new- create work itemgovctl adr accept- accept ADR
Having two ways (
govctl list rfcvsgovctl rfc list) violates the “one obvious way” principle. -
Reduced Complexity: Maintaining both patterns adds ~40 lines of delegation code and increases cognitive load for users (“which way should I use?”).
-
Pre-1.0 Window: We’re at version 0.2.0, which traditionally allows breaking changes before stabilizing at 1.0.
-
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.
-
Consistency: If we keep
listandnewas globals, why notmove,tick,accept,reject? The line becomes arbitrary. Resource-first is consistent across all operations.
Migration Plan
Since this is a breaking change:
- Update all documentation to use resource-first syntax ✅ (done)
- Update internal workflows (gov.md, .claude/CLAUDE.md) ✅ (done)
- Remove from Commands enum in main.rs
- Remove delegation logic from command_router.rs
- Update CHANGELOG.md noting the breaking change
- 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
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 listorgovctl newwill break- Mitigation: We’re pre-1.0, document in CHANGELOG
- More Keystrokes:
govctl rfc listis longer thangovctl 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