Context and Problem Statement
Spec-kitty is a Specification-Driven Development tool where "specification" means explicit, visible, and unambiguous. However, feature metadata was relying on implicit defaults:
Before (0.13.7 and earlier):
{
"feature_number": "001",
"slug": "001-my-feature",
"created_at": "2026-01-29T00:00:00Z"
// target_branch: missing → implicit default "main"
// vcs: missing → implicit default "git"
}
Problems discovered during ~/tmp testing:
- Cannot debug by reading meta.json (configuration invisible)
- Cannot grep for 2.x features:
grep -r '"target_branch": "2.x"'finds nothing - Violates SDD principle: "Specification should be explicit, not implicit"
- When get_feature_target_branch() defaults to "main", users don't know if it's explicit or fallback
- VCS fallback logic is invisible
Question: Should configuration fields ALWAYS be set explicitly in meta.json, even if they match defaults?
Decision Drivers
- SDD Principles - Specification-Driven Development requires explicit configuration
- Debugging - Should be able to see config by reading meta.json
- Transparency - No hidden defaults or magic behavior
- Dual-branch routing - Need to distinguish "explicitly main" vs "defaulted to main"
- VCS locking - Need to know if VCS choice was explicit or auto-detected
- User expectations - Developers expect config files to show configuration
Considered Options
- Option 1: Always set target_branch and vcs explicitly in meta.json
- Option 2: Keep implicit defaults, add --show-config command to display them
- Option 3: Hybrid: Set only if non-default (target_branch if not "main")
- Option 4: Status quo (implicit defaults, documentation in code)
Decision Outcome
Chosen option: "Option 1: Always set explicitly", because:
- Aligns with SDD principles (specification is visible)
- Debugging-friendly (cat meta.json shows config)
- Self-documenting (no hidden defaults)
- Prevents ambiguity (explicit "main" vs missing field)
- Enables grepping for features by config
Consequences
Positive
- Debugging -
cat meta.jsonshows complete configuration - Clarity - No hidden defaults or magic behavior
- Dual-branch -
grep -r '"target_branch": "2.x"'finds SaaS features - SDD compliance - Specification is explicit and visible
- VCS transparency - Can see the VCS choice explicitly
- Audit trail - Git history shows when fields were added/changed
Negative
- Verbosity - meta.json slightly larger (two extra fields)
- Migration required - Must add fields to existing features
- Template complexity - Agents must set fields during /spec-kitty.specify
- Redundancy - Default values ("main", "git") appear in every meta.json
Neutral
- Defaults still exist - get_feature_target_branch() returns "main" if field missing (backward compat)
- Validation not enforced - Missing fields don't cause errors (safe fallback)
- Schema expansion - Meta.json schema now has 8 fields instead of 6
Confirmation
We validated this decision by:
- ✅ 13 integration tests proving explicit fields work
- ✅ ~/tmp Feature 001 fixed with explicit fields
- ✅ All future features created with /spec-kitty.specify have fields
- ✅ Template updated in all 12 agent directories (source of truth)
- ✅ No performance impact (fields are lightweight)
Pros and Cons of the Options
Option 1: Always set explicitly (CHOSEN)
meta.json always includes target_branch and vcs, even if they match defaults.
Pros:
- Visible: cat meta.json shows configuration
- Debuggable: No guessing about defaults
- SDD-compliant: Specification is explicit
- Greppable: Can find features by config
- Self-documenting: New developers see config immediately
Cons:
- Verbose: Two extra lines per meta.json
- Migration: Must update existing features
- Template: Agents must set fields
Option 2: --show-config command
Keep implicit defaults, add command to display them.
Pros:
- No migration needed
- Smaller meta.json files
- No template changes
Cons:
- Requires running command to see config
- Not visible in git history
- Cannot grep for features by config
- Violates SDD (config not in specification)
- Debugging requires extra step
Option 3: Hybrid (set only if non-default)
Set target_branch only if not "main", vcs only if not "git".
Pros:
- Smaller meta.json for most features
- Explicit when overriding defaults
Cons:
- Ambiguous: Is "main" explicit or implicit?
- Cannot distinguish explicit from fallback
- Debugging still requires checking code
- Partial SDD compliance only
Option 4: Status quo (implicit)
Keep current behavior, document defaults in code comments.
Pros:
- No changes needed
- Minimal meta.json
- No migration
Cons:
- Violates SDD principles
- Not debuggable from meta.json
- Cannot grep for features by config
- Hidden behavior (magic defaults)
- User confusion: "Why did it use main?"
More Information
Implementation:
src/specify_cli/missions/software-dev/command-templates/specify.md(template updated)- Deployed to all 12 agent directories (
.claude/,.codex/, etc.) src/specify_cli/core/feature_detection.py::get_feature_target_branch()(safe default fallback)
Tests:
tests/integration/test_specify_metadata_explicit.py(13 tests)- All tests validate explicit fields are set, never null, and readable
Migration:
m_0_13_8_target_branch.pyadds target_branch to existing features- Auto-detects Feature 025 as 2.x (from spec.md content)
- Defaults to "main" for all others
Related ADRs:
- ADR-12: Two-Branch Strategy (establishes need for target_branch)
- ADR-13: Target Branch Routing (uses target_branch for status commits)
Version: 0.13.8 improvement (template fix)
SDD Principle: "Specification should be explicit, visible, and unambiguous"