Version: 1.0.0 Last Updated: 2026-02-05
feature.yaml is the machine-readable single source of truth for feature development state. It lives in each feature’s spec directory (e.g., specs/006-cli-settings-commands/feature.yaml) and tracks progress from research through completion.
Key Principles:
feature:
id: string # Feature ID (e.g., "006-cli-settings-commands")
name: string # Human-readable name
number: integer # Sequential feature number
branch: string # Git branch name
lifecycle: string # research | planning | implementation | review | complete
createdAt: string # ISO 8601 timestamp
status:
phase: string # Current phase within lifecycle
progress:
completed: integer # Number of completed tasks
total: integer # Total number of tasks (from tasks.md)
percentage: integer # Calculated: (completed/total)*100
currentTask: string | null # Current task ID (e.g., "task-8")
lastUpdated: string # ISO 8601 timestamp
lastUpdatedBy: string # Skill that made the update
validation:
lastRun: string | null # Last validation timestamp
gatesPassed: string[] # List of passed validation gates
autoFixesApplied: string[] # List of auto-fixes applied
tasks:
current: string | null # Current task ID
blocked: string[] # Task IDs that can't proceed
failed: string[] # Task IDs that failed
checkpoints:
- phase: string # Checkpoint name
completedAt: string # ISO 8601 timestamp
completedBy: string # Skill that created checkpoint
errors:
current: object | null # Current error (if any)
history: object[] # Past errors (for audit)
taskId: string # Task that failed
attempt: integer # Retry attempt number
error: string # Error description
details: string # Full error message/stack trace
timestamp: string # ISO 8601 timestamp
resolved: boolean # Whether error was resolved
resolvedAt: string # Resolution timestamp (if resolved)
new-feature → research → planning → implementation → review → complete
| Lifecycle | Valid Phases |
|---|---|
| research | research |
| planning | planning, ready-to-implement |
| implementation | implementation, ready-for-review, blocked |
| review | in-review, review-watching, review-fixing |
| complete | complete |
Always the first operation when working on a feature:
# Example pseudocode
feature_yaml_path="specs/$FEATURE_ID/feature.yaml"
if [[ -f "$feature_yaml_path" ]]; then
# Parse YAML
current_phase=$(yq '.status.phase' "$feature_yaml_path")
current_task=$(yq '.status.currentTask' "$feature_yaml_path")
progress=$(yq '.status.progress.completed' "$feature_yaml_path")
total=$(yq '.status.progress.total' "$feature_yaml_path")
echo "Feature $FEATURE_ID"
echo "Phase: $current_phase"
echo "Progress: $progress/$total tasks"
echo "Current: $current_task"
else
echo "ERROR: feature.yaml not found"
exit 1
fi
Check if current state is valid before continuing:
# Verify files exist for completed work
# Run tests for completed tasks
# Ensure build passes
# If validation fails, re-attempt current task
CRITICAL: Update feature.yaml after EVERY logical task group completion:
Example pattern:
Complete Phase 0 (6 tasks) → Update feature.yaml → Commit
Complete Phase 1 RED (6 tasks) → Update feature.yaml → Commit
Complete Phase 1 GREEN (X tasks) → Update feature.yaml → Commit
Complete Phase 1 REFACTOR (Y tasks) → Update feature.yaml → Commit
All updates should:
status.lastUpdated timestampstatus.lastUpdatedBy with skill namestatus.progress.percentage if tasks changedstatus.progress.completed by number of tasks just finishedstatus.currentTask to next task identifier# Before
status:
progress:
completed: 7
total: 12
percentage: 58
currentTask: "task-8"
lastUpdated: "2026-02-05T14:30:00Z"
# After (task-8 completed)
status:
progress:
completed: 8
total: 12
percentage: 67
currentTask: "task-9"
lastUpdated: "2026-02-05T15:45:00Z"
lastUpdatedBy: "shep-kit:implement"
checkpoints:
- phase: 'research'
completedAt: '2026-02-03T16:00:00Z'
completedBy: 'shep-kit:research'
- phase: 'plan'
completedAt: '2026-02-04T18:30:00Z'
completedBy: 'shep-kit:plan'
# NEW
- phase: 'implementation-started'
completedAt: '2026-02-05T09:00:00Z'
completedBy: 'shep-kit:implement'
errors:
current:
taskId: 'task-8'
attempt: 2
error: '3 unit tests failing in ShowCommand'
details: |
FAIL tests/unit/presentation/cli/commands/settings/show.command.test.ts
ShowCommand
✗ should format output as table
✗ should format output as JSON
✗ should format output as YAML
timestamp: '2026-02-05T15:30:00Z'
resolved: false
history: []
errors:
current: null
history:
- taskId: 'task-8'
attempt: 2
error: '3 unit tests failing in ShowCommand'
timestamp: '2026-02-05T15:30:00Z'
resolved: true
resolvedAt: '2026-02-05T15:45:00Z'
resolution: 'Fixed import paths in test file'
/shep-kit:new-featureWhen: Creating new feature spec
Updates:
feature.yaml from templatefeature.* metadatalifecycle: "research", phase: "research"Example:
feature:
id: '007-new-feature'
name: 'New Feature'
number: 7
branch: 'feat/007-new-feature'
lifecycle: 'research'
createdAt: '2026-02-05T16:00:00Z'
status:
phase: 'research'
progress: { completed: 0, total: 0, percentage: 0 }
currentTask: null
lastUpdated: '2026-02-05T16:00:00Z'
lastUpdatedBy: 'shep-kit:new-feature'
checkpoints:
- phase: 'feature-created'
completedAt: '2026-02-05T16:00:00Z'
completedBy: 'shep-kit:new-feature'
/shep-kit:researchWhen: Research phase completes
Updates:
lifecycle: "planning", phase: "planning"/shep-kit:planWhen: Plan and tasks.md written
Updates:
lifecycle: "implementation", phase: "ready-to-implement"tasks.md and set progress.totalTask Counting:
# Count tasks in tasks.md (assuming each task has "## Task N:" header)
total_tasks=$(grep -c "^## Task [0-9]" tasks.md)
/shep-kit:implementWhen: Starting implementation
Updates on start:
phase: "implementation"Updates during execution (after each task):
progress.completedprogress.percentagecurrentTask to next task IDlastUpdated timestampUpdates on completion:
phase: "ready-for-review"Updates on error:
errors.currentphase: "blocked"tasks.failed/shep-kit:commit-prWhen: PR created and review loop running
Updates on PR creation:
lifecycle: "review", phase: "in-review"prUrl: "https://github.com/..."Updates during review loop:
phase: "review-watching" when waiting for reviewsphase: "review-fixing" when applying fixesreviewLoop field to track iteration statereviewLoop field schema:
reviewLoop:
iteration: 0 # Current iteration number (0-based)
maxIterations: 5 # Configurable max review-fix cycles
commentsAddressed: [] # Comment IDs fixed so far
commentsRemaining: [] # Comment IDs still open
status: 'watching' # watching | fixing | approved | exhausted | failed
Review loop state transitions:
in-review → review-watching → review-fixing → review-watching (loop)
↓
review-watching → in-review (approved / no issues)
/shep-kit:mergedWhen: PR merged
Updates:
lifecycle: "complete", phase: "complete"mergedAt: "<timestamp>"All feature.yaml files MUST have:
feature.idfeature.namefeature.branchfeature.lifecyclestatus.phasestatus.lastUpdatedlifecycle must be valid state (research |
planning | implementation | review | complete) |
phase must be valid for current lifecycleprogress.percentage must equal (completed/total)*100 (rounded)currentTask must exist in tasks.md (if not null)errors.current is not null, phase should be “blocked”tasks.failed is not empty, review is required✅ Read feature.yaml first when resuming work
✅ Update immediately after state changes
✅ Use ISO 8601 timestamps consistently
✅ Record all errors (even resolved ones) in history
✅ Add descriptive checkpoint phases
✅ Keep error messages concise in error field, details in details field
❌ Manually edit feature.yaml (use skills)
❌ Duplicate task definitions (use tasks.md)
❌ Skip updating lastUpdated timestamp
❌ Leave errors.current populated after resolution
❌ Add checkpoints without timestamps
❌ Modify progress.total during implementation (only during planning)
Cause: Feature created before protocol was implemented
Solution: Create from template manually or re-run /shep-kit:new-feature
Cause: Manual edits or interrupted execution
Solution:
tasks.md to understand actual progressfeature.yaml to match realityCause: Manual update or floating-point error
Solution: Recalculate: Math.round((completed/total)*100)
Cause: Skill ran multiple times
Solution: Deduplicate by phase (keep most recent)
See .claude/skills/shep-kit-implement/examples/validation-report.md for complete examples of validation output and error handling.
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-02-05 | Initial protocol definition |
Reference: This protocol is used by all shep-kit skills. See skill-specific SKILL.md files for detailed implementation instructions.