From project-management-plugin
Renders fixed-width ASCII progress dashboards showing project phases, epics, tasks, completion bars, velocity metrics, and ETA from tasks.json. For terminal or markdown progress views.
npx claudepluginhub markus41/claude --plugin project-planner-pluginThis skill uses the workspace's default tool permissions.
The progress dashboard is rendered as a self-contained ASCII block using box-drawing characters. It is designed to be legible in any terminal, in markdown code blocks, and in plain-text environments where rich formatting is unavailable. The dashboard is regenerated on demand and after every phase completion; it is not stored to disk (the progress log captures events; the dashboard is a computed...
Displays Markdown Kanban board of tasks from openspec/changes/tasks.md and cm-tasks.json, summarizing agent mode (PLANNING/EXECUTION/VERIFICATION) and next step. Invoke via /cm-dashboard to track progress.
Displays TASKS.md progress in real time on Claude Code status bar Line 3, showing completed/total tasks, progress bar, phase, and next task. Use for live project tracking.
Renders markdown progress bars for StatsClaw workflows, showing pipeline stages (Credentials, Plan, Specs, Build/Test, etc.), active tasks, and elapsed time after status.md updates.
Share bugs, ideas, or general feedback.
The progress dashboard is rendered as a self-contained ASCII block using box-drawing characters. It is designed to be legible in any terminal, in markdown code blocks, and in plain-text environments where rich formatting is unavailable. The dashboard is regenerated on demand and after every phase completion; it is not stored to disk (the progress log captures events; the dashboard is a computed view over tasks.json).
The outermost container uses heavy box-drawing characters:
╔══════════════════════════════════════════════════════════════════╗
║ PROJECT: {project-name} v{version} ║
║ Goal: {goal-text truncated to 55 chars} ║
╠══════════════════════════════════════════════════════════════════╣
║ STATUS: {status} PHASE: {current-phase-name} ║
║ Started: {created_at date} Loop #: {loop_count} ║
╠══════════════════════════════════════════════════════════════════╣
║ OVERALL PROGRESS ║
║ [{progress-bar-50-chars}] {pct}% ({complete}/{total} tasks) ║
╠══════════════════════════════════════════════════════════════════╣
║ PHASES ║
║ ...phase rows... ║
╠══════════════════════════════════════════════════════════════════╣
║ VELOCITY & ETA ║
║ ...metrics rows... ║
╠══════════════════════════════════════════════════════════════════╣
║ PM SYNC ║
║ ...sync status row... ║
╚══════════════════════════════════════════════════════════════════╝
The total dashboard width is fixed at 68 characters (including the two border characters). All inner content is padded to exactly 66 characters. Lines that exceed 66 characters are truncated with an ellipsis at character 63 (...). Lines shorter than 66 characters are right-padded with spaces.
The overall progress percentage is computed exclusively from leaf tasks — tasks that have no entries in their subtasks array. This correctly handles the hierarchical task tree: a story with 4 subtasks contributes 0 to the numerator until its subtasks complete; each completed subtask contributes 1/4 of the story's weight to the overall count.
progress_pct = (count of leaf tasks with status == "COMPLETE") /
(count of all leaf tasks) * 100
Leaf tasks in BLOCKED status are counted in the denominator but not the numerator. They are displayed separately in the blocked task section rather than being excluded from the denominator (which would artificially inflate the percentage).
The progress bar itself is 50 characters wide. The number of filled characters is floor(progress_pct / 100 * 50). Filled characters are rendered as █; empty characters are rendered as ░. The bar always shows the boundary between filled and empty to make small progress visible even at low percentages.
Each phase is rendered as a row in the PHASES section. The row format is:
║ {phase-name padded to 20} [{bar-20-chars}] {pct}% {status-icon} ║
The 20-character phase progress bar uses the same █/░ fill formula as the overall bar but computed only over leaf tasks belonging to that phase. The status icon is a single character: ✓ for COMPLETE, ▶ for IN_PROGRESS, ○ for PENDING, ⊘ for SKIPPED. If phase-name exceeds 20 characters, it is truncated with no ellipsis (the bar is more important than the full name).
Phases are listed in their natural order from the phases array. The current active phase (the first phase with status IN_PROGRESS) is highlighted by replacing the outer ║ characters on its row with ▌ on the left and ▐ on the right, making it visually distinct without requiring color.
Below the phase overview, the dashboard renders a detailed breakdown for the current active phase only (rendering all phases would exceed practical terminal height for large projects). The breakdown uses a 2-space indent per level:
║ PHASE DETAIL: {current-phase-name} ║
║ ║
║ EPIC: {epic-title} [{bar-15}] {pct}% ║
║ Story: {story-title} [{bar-10}] {pct}% ║
║ ▶ Task: {task-title} {estimate}m {status} ║
║ · Subtask: {subtask-title} {status-icon} ║
║ ✓ Task: {completed-task-title} ({actual}m) ║
║ ⚠ Task: {blocked-task-title} BLOCKED ║
Epics are rendered with a 15-character bar and their own percentage. Stories are rendered with a 10-character bar. Individual tasks and subtasks are rendered as text-only rows with status indicators. A task row shows its estimate in minutes while PENDING/IN_PROGRESS, and shows its actual time in parentheses once COMPLETE.
If the current phase has more than 30 leaf tasks, the detail section is abbreviated: only epics with at least one non-COMPLETE task are shown, and stories within those epics are collapsed to a single summary line ("N tasks: X complete, Y in-progress, Z pending").
Blocked tasks are surfaced in a dedicated section placed between the PHASES section and the VELOCITY section. This placement ensures they cannot be missed — they interrupt the natural flow of the dashboard rather than appearing in a footer that might be scrolled past.
╠══════════════════════════════════════════════════════════════════╣
║ BLOCKED ({count}) ║
║ ⚠ {task-id}: {task-title truncated to 45} ║
║ └─ {blocked_reason truncated to 58} ║
Each blocked task gets two lines: the task identifier and title, then the blocked reason indented with a tree connector. If blocked_reason is null (which should not happen but may occur in corrupted state), the reason line reads "No reason recorded — review tasks.json." If there are no blocked tasks, the BLOCKED section is omitted entirely rather than showing a zero count.
Velocity is computed as the rolling average of actual_minutes over the last 10 completed leaf tasks. If fewer than 10 leaf tasks are complete, velocity is computed over all completed leaf tasks. If no leaf tasks are complete, velocity is displayed as "—" (not yet established).
║ VELOCITY & ETA ║
║ Velocity: {velocity}m/task (rolling 10) ║
║ Completed today: {count} tasks ({total-minutes}m) ║
║ Remaining: {remaining-leaf-count} tasks ║
║ ETA: {eta-date} ({hours}h at current velocity) ║
ETA is computed as: remaining_leaf_count * velocity_minutes / 60 hours from now, displayed as a wall-clock date. The ETA does not account for parallelism — it is a pessimistic single-threaded estimate. When velocity is not yet established, ETA is displayed as "Insufficient data (< 3 tasks complete)."
The "Completed today" row resets at midnight UTC. It uses the completed_at timestamps in tasks.json rather than the progress log, so it reflects only formally validated completions.
The final section of the dashboard shows the integration status with the connected PM platform (if any):
╠══════════════════════════════════════════════════════════════════╣
║ PM SYNC: {platform-name} ║
║ Last sync: {last_sync_at or "Never"} ║
║ Synced tasks: {count-with-external-id} / {total-tasks} ║
╚══════════════════════════════════════════════════════════════════╝
If pm_integration is null, the PM SYNC section is replaced with:
║ PM SYNC: Not configured (use /pm-init to connect a platform) ║
The sync section is always the last element before the bottom border, making it easy to find regardless of how long the phase detail section is.