| name | agile:epic:progress |
| description | Track and update epic progress by scanning artifacts, running compilation to detect error counts, auto-updating tasks.md markers based on build progress AND team inbox state (state.json + TaskList drift detection — same narrow auto-fix as /agile:epic:assign), syncing tasks.md↔spec.md↔epic.md status mismatches, and pushing all updates to Azure DevOps. This skill DISPLAYS a dashboard BUT ALSO automatically UPDATES all artifact files (tasks.md, spec.md, epic.md) and DevOps work items. Use --no-sync only when you want a completely read-only dashboard with NO file writes. Use this skill whenever the user asks about epic progress, status, how far along an epic is, what's left to do, wants a progress report, asks to "update" or "sync" or "refresh" epic status, asks to "fix tasks.md markers" or "fix marker drift", or mentions any combination of "tasks.md", "spec.md", "epic.md" with progress or status. Triggers on: "epic progress", "show progress", "what's blocking", "sync epic status", "update progress", "refresh epic", "fix status mismatch", "fix tasks.md drift", "marker drift", "tasks.md", "spec.md", "epic.md status".
|
| user-invocable | true |
| disable-model-invocation | false |
| allowed-tools | Read, Edit, Glob, Grep, Bash, Skill, TaskList, TaskGet, AskUserQuestion |
Epic Progress Dashboard
Track and report the progress of an epic by scanning all its artifacts — epic.md, checklist.md, and per-feature
spec.md and tasks.md files. Produces a progress dashboard with completion percentages, health indicators, and
actionable recommendations.
By default, also cross-checks artifact synchronization at all 3 levels (Epic, Feature, User Story),
fixes mismatches, and pushes state to Azure DevOps. Use --no-sync if you only want a read-only
dashboard without any writes.
Invocation
/agile:epic:progress 125 — Target by epic number (dashboard + sync)
/agile:epic:progress agile/epics/125-lombok-removal — Target by path (dashboard + sync)
/agile:epic:progress — Auto-detect from current branch (dashboard + sync)
/agile:epic:progress --dry-run 125 — Show what would change without writing
/agile:epic:progress --no-sync 125 — Read-only dashboard, no writes or DevOps sync
Flags
| Flag | Purpose | Default |
|---|
--no-sync | Disable sync: read-only dashboard, no writes or DevOps push | false |
--dry-run | Show planned corrections without writing (ignored with --no-sync) | false |
Dynamic Context
- Current branch: !
git branch --show-current
- Existing epics: !
ls agile/epics/ 2>/dev/null | sort | tail -5
Phase 1: Resolve Epic Context
Parse $ARGUMENTS to find the epic directory:
| Pattern | Resolution |
|---|
3-digit number (e.g., 125) | Find directory matching agile/epics/125-* |
Full path (contains /) | Use directly |
| Empty | Extract epic number from current branch name (first 3 digits) |
If multiple directories match or none found, ask the user to clarify.
Set EPIC_DIR to the resolved path.
Phase 2: Validate Prerequisites
Verify EPIC_DIR contains:
epic.md — hard prerequisite, exit with error if missing
- At least one feature directory with
tasks.md
If checklist.md exists, include it in the scan. If absent, skip checklist reporting (it's optional for older epics).
Phase 3: Run Progress Scan
Execute the scan script to collect structured data:
bash .claude/skills/agile-epic-progress/scripts/scan-progress.sh "$EPIC_DIR"
The script outputs JSON with:
epic_id, epic_status — from epic.md metadata
checklist — checked/unchecked counts from checklist.md (null if absent)
features[] — per-feature task counts by marker type
totals — aggregated counts and overall progress percentage
Task Marker Reference
| Marker | State | Counts as Terminal |
|---|
[ ] | Pending | No |
[W] | In Progress | No |
[X] | Completed | Yes |
[-] | Partial | No |
[B] | Blocked | No |
[S] | Skipped | Yes |
Progress % = completed / (total - skipped) × 100
Skipped tasks are excluded from both numerator and denominator (aligned with agile:epic:implement
status-tracker and agile:epic:priority T-factor). If effective total (total - skipped) = 0, progress = 0.
Phase 3b: Compilation Progress Detection (Optional Auto-Sync)
This phase runs automatically when the epic targets a compilable module, to keep tasks.md in sync
with actual build progress. Skip this phase if the epic does not target a compilable module (e.g.,
documentation-only, agile framework, or infrastructure epics).
This phase detects when tasks.md markers don't reflect actual build progress and auto-updates them.
It runs compilation, analyzes error counts per feature, and updates tasks.md markers accordingly.
3b.1 Detect Service Module
From the epic context, determine which service module this epic targets:
- Read
epic.md for module references in the Architecture Context or Feature Breakdown
- Check feature directory names for service module hints (e.g.,
legals, loans, core)
- If a compilable module is identified, set
SERVICE_MODULE (e.g., services/legals)
- If no compilable module is detected, skip Phase 3b entirely
3b.2 Run Compilation
Execute Maven compilation to get current error counts:
cd "$PROJECT_ROOT"
mvn compile -pl "$SERVICE_MODULE" -DskipTests 2>&1 | tee /tmp/compile-output.txt
3b.3 Analyze Errors
Count errors from compilation output. The error pattern matching is determined by the epic's
feature names — each feature's name typically describes the error category it addresses:
TOTAL_ERRORS=$(grep -c "error:" /tmp/compile-output.txt || echo "0")
For each feature, extract the error category from its directory name and search the compilation
output for matching error patterns.
3b.4 Calculate Progress
For each feature, calculate progress based on error reduction:
- Read baseline error counts from feature tasks.md (if available)
- Calculate current error count for that feature's patterns
- Determine marker status:
| Error Reduction | Marker |
|---|
| 100% (0 errors) | [X] Completed |
| >50% reduction | [W] In Progress |
| <50% reduction | [ ] Pending |
| 0% reduction + no baseline | [ ] Pending |
3b.5 Auto-Update tasks.md
For each feature where progress differs from tasks.md markers:
- Read the feature's tasks.md file
- Update task markers based on calculated progress (using 6-state markers)
- Write updated tasks.md back to file
3b.6 Progress Report
Report the compilation-based sync:
## Compilation Progress Detected
| Feature | Errors | Status | Marker |
|---------|--------|--------|--------|
| NNN-01-feature-name | 0 | resolved | [ ] → [X] |
| NNN-02-feature-name | 42 | 90% fixed | [ ] → [W] |
**Auto-updated**: N features had tasks.md markers updated based on compilation
This phase ensures tasks.md always reflects real compilation progress, eliminating
the gap between markers and actual progress.
Phase 3c: Team Inbox Drift Auto-Fix (Optional)
This phase runs automatically when the current session can read the team inbox AND the epic has
a state.json written by /agile:epic:implement. It catches the case where a teammate's task
got marked completed in the team inbox but the corresponding tasks.md line never got rewritten
to [X] — typically because a previous run of /agile:epic:implement or /agile:epic:assign
died mid-cycle. This is the same narrow auto-fix implemented in
.claude/skills/agile-epic-assign/modules/inbox-inspector.md Step 5; we port the rule here so a
single /agile:epic:progress run can heal that drift without the user having to re-enter the
team-lead session.
Skip this phase silently if any of the following is true (no warning, no error):
{EPIC_DIR}/state.json does not exist (epic was never run through /agile:epic:implement)
state.json.taskInboxMapping is empty
TaskList() is not callable in the current session (not a team-lead session)
- The
--no-sync flag was passed (the skill is in read-only mode)
3c.1 Read state.json + Build Reverse Mapping
state = read_json("{EPIC_DIR}/state.json")
inboxToTaskId = { inboxId: taskId for taskId, inboxId in state.taskInboxMapping.items() }
If state.taskInboxMapping is empty, exit Phase 3c.
3c.2 Snapshot the Inbox
Call TaskList(). Categorize each task by its status. For drift detection only the completed
bucket matters; everything else is reported in the dashboard but not auto-fixed.
For each task with status == "completed":
- Look up
inboxToTaskId[task.id]. If missing → tag the task as stale (not in mapping); skip.
- Locate its
tasks.md line: {EPIC_DIR}/features/{featureId}/tasks.md, line matching
- [marker] {taskId} (where taskId = NNN-XX-Tnn).
- Read the marker character.
3c.3 Apply the Narrow Auto-Fix
Use the same drift table as agile-epic-assign:
| Inbox status | tasks.md marker | Action |
|---|
completed | [ ] or [W] | Auto-fix: rewrite to [X] |
completed | [X] | No action — markers agree |
completed | [B]/[S]/[-] | Warn (ambiguous); leave as-is |
The auto-fix is intentionally narrow. [B], [S], and [-] could represent legitimate human
edits (a teammate flagged a blocker, the user skipped a task post-completion, work was partial) —
silently overwriting them would destroy intent. Warn instead and let the user resolve it.
Implementation: use Edit with old_string = "- [{currentMarker}] {taskId}" and
new_string = "- [X] {taskId}". If the line is non-unique (would only happen with duplicate task
IDs in the same file — a planning bug), skip and warn.
3c.4 Drift Report
Surface the result in the dashboard alongside Phase 3b's compilation report:
## Team Inbox Drift Detected
| Feature | Task | Inbox | tasks.md | Action |
|---------|------|-------|----------|--------|
| 136-03 | T05 | completed | [ ] → [X] | auto-fixed |
| 136-03 | T08 | completed | [W] → [X] | auto-fixed |
| 136-04 | T02 | completed | [B] | warned (ambiguous) |
**Auto-fixed**: N markers re-aligned with team inbox state.
**Warnings**: M ambiguous cases require manual review.
If no drift was detected, omit this section entirely — clean state needs no callout.
3c.5 Why This Matters
The compilation-based check in Phase 3b says "the build is green for these tasks". The inbox-based
check here says "the teammate reported their task done and a different teammate validated it".
Both are independent positive signals. They never disagree in the direction of "fix to [X]" —
the worst that can happen is one fires when the other doesn't (a docs-only feature has no compile
signal; a feature with no team-lead history has no inbox signal). Running both keeps tasks.md
in sync with whichever signal is currently authoritative.
Phase 4: Render Dashboard
Using the scan JSON, render a markdown dashboard. Follow this exact structure:
4.1 Header
# Epic Progress: {epic_id}
**Status**: {epic_status}
**Overall Progress**: {progress_pct}% ({terminal}/{total} tasks)
**Features**: {features_done}/{features} complete
4.2 Feature Progress Table
## Feature Progress
| Feature | Name | Status | Done | Total | Progress | Blocked |
|---------|------|--------|------|-------|----------|---------|
| 125-01 | common-shared-cleanup | DRAFT | 0 | 12 | 0% | 0 |
| 125-02 | common-mysql-cleanup | DRAFT | 0 | 18 | 0% | 0 |
| ... | | | | | | |
Rules for the table:
- Feature: Extract the
NNN-XX prefix from the directory name
- Name: The rest of the directory name after the prefix
- Done:
completed count (skipped tasks are excluded, not counted as done)
- Progress:
completed / (total - skipped) × 100, rounded to nearest integer. If total - skipped = 0, progress = 0.
- Blocked: Count of
[B] markers — highlight with bold if > 0
- Sort by feature ID (natural order)
4.3 Status Breakdown
## Task Status Breakdown
| Status | Count | Pct |
|--------|-------|-----|
| Completed | N | X% |
| In Progress | N | X% |
| Pending | N | X% |
| Blocked | N | X% |
| Partial | N | X% |
| Skipped | N | X% |
Only include rows with count > 0.
4.4 Checklist Status (if checklist.md exists)
## Cross-Cutting Checklist
**Progress**: {done}/{total} items checked ({pct}%)
If the checklist has sections (like "Constitution Compliance", "Build & Compilation", etc.), scan checklist.md
directly and report per-section completion:
| Section | Done | Total |
|---------|------|-------|
| Constitution Compliance - Master | 0 | 7 |
| Constitution Compliance - Common | 0 | 3 |
| Build & Compilation | 0 | 4 |
| ... | | |
4.5 Health Indicators
Analyze the scan data and report health signals:
| Condition | Indicator | Recommendation |
|---|
Any [B] tasks | BLOCKED | List blocked features and suggest investigation |
Any [W] tasks with no [X] in same feature | STALLED | Feature has started work but nothing completed yet |
Feature has all tasks [X]/[S] but status != IMPLEMENTED | SYNC NEEDED | Feature status doesn't match task completion |
| Epic status is PLANNING but tasks are in progress | STATUS LAG | Epic status should be updated to IMPLEMENTING |
> 20% tasks [-] (partial) | FRAGMENTED | Many partial tasks suggest scope issues |
| 0 tasks completed across all features | NOT STARTED | Epic has no completed work yet |
| Some features IMPLEMENTED + some BLOCKED/SKIPPED (epic not yet PARTIAL) | PARTIAL | Epic has mixed terminal states — update to PARTIAL |
Only show indicators that actually apply. If everything is healthy, show:
## Health: OK
No issues detected.
4.6 Dependency Status (if applicable)
Read epic.md's **Dependencies**: field. If not "None":
- For each dependency, find the dependent epic directory and check its status
- Render:
## Epic Dependencies
| Dep Epic | Name | Status | Met |
|----------|------|--------|-----|
| 122 | common-postgres-tests | PLANNING | NO |
**Dependency Gate**: BLOCKED (0 of 1 dependencies met)
A dependency is "met" if its epic status is COMPLETED or IMPLEMENTED.
If all deps met: **Dependency Gate**: CLEAR
If no deps: omit this section.
Phase 5: Recommendations
Based on health indicators and current state, provide 1-3 actionable next steps. Examples:
- "Next action: Begin feature 125-01 (no dependencies, lowest risk)"
- "Resolve 3 blocked tasks in feature 125-09 before proceeding"
- "Update epic status from PLANNING to IMPLEMENTING (4 features have in-progress tasks)"
- "Feature 125-01 has all tasks completed — update spec.md status to DONE"
Keep recommendations specific and actionable. Reference feature IDs and task counts.
Phase 6: Synchronization (skipped when --no-sync is passed)
This phase cross-checks artifact consistency and fixes mismatches. It runs by default.
With --no-sync, this phase is skipped entirely and the skill remains read-only.
Before other sync checks, this phase includes two parallel auto-fix passes:
- Phase 3b — Compilation Progress Detection: runs Maven compile, counts errors per feature, and
rewrites tasks.md markers based on the build state.
- Phase 3c — Team Inbox Drift Auto-Fix: reads
state.json and the team inbox; for any task
marked completed in the inbox but still [ ]/[W] in tasks.md, rewrites the marker to [X]
(same narrow rule as /agile:epic:assign).
Both passes are best-effort and skip silently when their preconditions aren't met (no compilable
module for 3b; no state.json or no team-lead session for 3c). Together they keep tasks.md
aligned with whichever signal is authoritative for the current epic — compilation health, team
process, or both.
6.1 Cross-Check: tasks.md ↔ spec.md (Feature Status)
For each feature, compare the derived status from tasks.md markers against the **Status**: field
in spec.md. Derive the expected status using the implement skill's bottom-up derivation rules:
| Task State | Expected spec.md Status |
|---|
All [ ] (no work started) | PENDING |
Any [W] or mix of [X] and [ ] | IMPLEMENTING |
All [X]/[S] (all terminal) | IMPLEMENTED |
Any [B] present | BLOCKED |
Any [-] with no [W] | IMPLEMENTING |
| Feature explicitly skipped | SKIPPED |
Terminology alignment: These statuses match the agile:epic:implement status-tracker module:
PENDING (not DRAFT) — plan skill generates features with initial status PENDING
IMPLEMENTED (not DONE) — implement skill uses IMPLEMENTED for features with all stories completed
SKIPPED — implement skill supports feature-level skipping
Legacy epics may use DRAFT or DONE; accept these as equivalent to PENDING and IMPLEMENTED
when reading, but write the canonical form when correcting.
If the current spec.md Status does not match the expected status, record the mismatch:
MISMATCH: 125-01 spec.md says "PENDING" but tasks.md shows all completed → expected "IMPLEMENTED"
6.1b Cross-Check: tasks.md ↔ spec.md (User Story Status)
For each feature's spec.md, scan for user story sections (headers matching ### User Story N or
### NNN-XX-Un). Each user story may have its own **Status**: and **DevOps ID**: fields.
Derive the expected user story status from the tasks.md markers that fall under that story's scope.
If tasks.md groups tasks by user story headings (U0, U1, U2, ...), use those groups. The implement
skill enforces User Story sequential gates — all tasks in U{n} must complete before U{n+1} starts.
| User Story Task State | Expected User Story Status |
|---|
All [ ] (no work started) | PENDING |
Any [W] or mix of [X] and [ ] | IMPLEMENTING |
All [X]/[S] (all terminal) | COMPLETED |
Any [B] present | BLOCKED |
Terminology alignment: These match the implement skill's status-tracker derivation rules:
PENDING (not DRAFT) for no-work-started
COMPLETED (not DONE) for all-terminal user stories
If the user story's current **Status**: does not match the expected status, record the mismatch:
MISMATCH: 125-01-U1 story says "PENDING" but tasks show implementing → expected "IMPLEMENTING"
6.2 Cross-Check: features ↔ epic.md
Derive the expected epic status from the aggregate feature states, using the implement skill's
bottom-up derivation rules:
| Feature Aggregate | Expected epic.md Status |
|---|
| All features IMPLEMENTED or SKIPPED | DONE |
| Any feature IMPLEMENTING | IMPLEMENTING |
| All features PENDING (no work started) | PLANNING |
| All remaining features BLOCKED | BLOCKED |
| Some features IMPLEMENTED, some BLOCKED/SKIPPED | PARTIAL |
Terminology alignment: The implement skill uses DONE at epic level (all features
implemented/skipped). The priority skill normalizes DONE → COMPLETED for cross-epic comparison.
This skill writes DONE to epic.md (matching implement) since progress operates on a single epic.
Compare against the current **Status**: field in epic.md and record any mismatch.
6.3 Cross-Check: features ↔ epic.md Stage column
For each feature in the epic.md breakdown table, compare the Stage column against the derived
status from tasks.md. If a feature's tasks are all terminal but the Stage column still says
PENDING, record a mismatch.
6.4 Apply Corrections
If --dry-run is set, display all detected mismatches and stop:
## Sync Dry Run — Corrections Needed
| Type | Artifact | Field | Current | Expected | Action |
|------|----------|-------|---------|----------|--------|
| Epic | epic.md | Status | PLANNING | IMPLEMENTING | Would update |
| Feature | 125-01/spec.md | Status | DRAFT | DONE | Would update |
| Feature | 125-02/spec.md | Status | DRAFT | IMPLEMENTING | Would update |
| Feature | epic.md | 125-01 Stage | PENDING | DONE | Would update |
| User Story | 125-01/spec.md | U1 Status | DRAFT | DONE | Would update |
| User Story | 125-02/spec.md | U2 Status | DRAFT | IMPLEMENTING | Would update |
If --dry-run is NOT set, apply corrections:
- Update each mismatched spec.md Feature Status — replace the
**Status**: line with the correct value
- Update each mismatched User Story Status — within spec.md, find the user story section and update its
**Status**: line
- Update epic.md Status — replace the
**Status**: line with the correct value
- Update epic.md Stage columns — update feature Stage values in the breakdown table
Use targeted sed replacements or the Edit tool for each correction. Report each change made:
## Sync Applied
| Type | Artifact | Field | Was | Now |
|------|----------|-------|-----|-----|
| Epic | epic.md | Status | PLANNING | IMPLEMENTING |
| Feature | 125-01/spec.md | Status | DRAFT | DONE |
| Feature | epic.md | 125-01 Stage | PENDING | DONE |
| User Story | 125-01/spec.md | U1 Status | DRAFT | DONE |
4 corrections applied.
6.5 Trigger DevOps Sync (All 3 Work Item Types)
After applying corrections (or if no corrections needed and sync is active), push the
current state to Azure DevOps by invoking the devops-workitem skill:
Skill(skill: "devops-workitem", args: "sync {EPIC_NUMBER}")
Where {EPIC_NUMBER} is the 3-digit epic number (e.g., 125). This pushes the updated status
of all 3 work item types — Epic, Feature, and User Story — to their corresponding Azure
DevOps work items. The devops-workitem sync command uses collect-state-pairs.sh which
collects DevOps IDs and statuses across all hierarchy levels.
Report the sync result with a per-type breakdown:
## DevOps Sync
Pushed work item status to Azure DevOps via `devops-workitem sync {EPIC_NUMBER}`:
| Type | Synced | Skipped (no DevOps ID) |
|------|--------|------------------------|
| Epic | 1 | 0 |
| Feature | 5 | 1 |
| User Story | 12 | 3 |
If the DevOps sync fails (MCP server unavailable, auth error, etc.), report the error as a
warning — the local corrections are already applied and the DevOps sync can be retried later
with /devops-workitem sync {EPIC_NUMBER}.
Error Handling
| Scenario | Behavior |
|---|
| Epic directory not found | Report error, list available epics |
| epic.md missing | Report error, suggest running /agile:epic:plan first |
| No feature directories | Report error, suggest running /agile:epic:plan |
| No tasks.md in any feature | Warning: "No task lists found — run /agile:epic:plan to generate" |
| Script fails | Fall back to inline scanning (read files directly, count markers manually) |
| DevOps sync fails | Warning only — local corrections are preserved |
--dry-run with --no-sync | Ignore --dry-run (it has no effect with --no-sync) |
Guardrails
- Sync by default: The skill cross-checks all 3 levels (Epic, Feature, User Story), fixes mismatches, and pushes to DevOps unless
--no-sync is passed.
--no-sync for read-only: With --no-sync, the skill only reads and reports. It does not modify any files.
--dry-run safety net: Users can preview corrections before applying them.
- Graceful degradation: Missing optional artifacts (checklist.md, spec.md) produce warnings, not errors.
- DevOps sync is best-effort: If the DevOps MCP server is unavailable, local corrections still apply. The sync can be retried
independently.
Status Terminology Reference
This skill uses status values aligned with the agile:epic:implement status-tracker module.
Legacy epics may use older terminology; accept these as equivalent when reading.
| Level | Canonical Statuses | Legacy Equivalents |
|---|
| Task | [ ] [W] [X] [-] [B] [S] | (6-state, no legacy) |
| User Story | PENDING, IMPLEMENTING, COMPLETED, BLOCKED | DRAFT→PENDING, DONE→COMPLETED |
| Feature | PENDING, IMPLEMENTING, IMPLEMENTED, BLOCKED, SKIPPED | DRAFT→PENDING, DONE→IMPLEMENTED |
| Epic | PLANNING, IMPLEMENTING, DONE, PARTIAL, BLOCKED | COMPLETED→DONE (at epic level) |
Pipeline Alignment
This skill integrates with the agile epic pipeline:
| Pipeline Stage | Skill | Progress Connection |
|---|
| Brainstorm | agile:epic:brainstorm | design.md archived after planning — not tracked by progress |
| Plan | agile:epic:plan | Generates artifacts (plan.md, checklist.md, spec.md, tasks.md) that progress scans |
| Implement | agile:epic:implement | Status-tracker writes markers; progress reads and cross-checks them |
| Priority | agile:epic:priority | Uses same progress % formula: completed / (total - skipped) |
| Progress | agile:epic:progress | This skill — reads markers, derives status bottom-up, syncs to DevOps |