Summary
Add a MarkdownProgressRenderer that produces human-readable Markdown progress reports from the framework's progress data model, providing a dashboard-like view without requiring a web UI.
Motivation
The framework has IssueProgressWriter and FleetProgressWriter that produce JSON progress files. These are great for machine consumption but aren't human-readable. When operators are monitoring a long-running agent pipeline (especially via SSH, CI logs, or file watchers), a well-formatted Markdown file is immediately useful:
- Can be viewed in any terminal with
cat or less
- Renders natively in GitHub, VS Code, and most editors
- Can be committed to a repository for persistent status tracking
- Works as a lightweight alternative to building a monitoring web UI
AAMF implements a ProgressWriter that generates a rich progress.md with phase status tables, task completion progress bars, event timelines, retry history, wave lifecycle tracking, and terminal exhaustion summaries — all atomically updated after each state change.
Proposed API
MarkdownProgressRenderer
interface MarkdownProgressConfig {
/** Project/run name displayed in the header. */
projectName: string;
/** Path to write the progress.md file. */
outputPath: string;
/** Whether to include the event timeline section (default: true). */
showEvents?: boolean;
/** Maximum number of events to show (default: 50, most recent). */
maxEvents?: number;
/** Whether to include token usage breakdown (default: true). */
showTokenUsage?: boolean;
/** Custom sections appended after the standard sections. */
customSections?: Array<{ title: string; render: () => string }>;
}
class MarkdownProgressRenderer {
constructor(config: MarkdownProgressConfig, logger: LoggerLike);
/** Set the phase definitions for rendering the phase table. */
setPhases(phases: PhaseDefinition[]): void;
/** Update a phase's status. */
updatePhase(phaseId: number, status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped', notes?: string): void;
/** Set the total task count (for progress percentage). */
setTaskCount(total: number): void;
/** Update a task's status. */
updateTask(taskId: string, status: 'pending' | 'running' | 'completed' | 'failed' | 'blocked', details?: Record<string, unknown>): void;
/** Append a timestamped event to the timeline. */
appendEvent(message: string): void;
/** Update token usage stats. */
updateTokenUsage(usage: { total: number; byPhase?: Record<number, number>; byAgent?: Record<string, number> }): void;
/** Update cumulative wall-clock duration. */
updateDuration(durationMs: number): void;
/** Write the progress.md file atomically. */
flush(): Promise<void>;
}
Generated Markdown Structure
# Migration Progress — {projectName}
**Started:** 2026-03-09T14:30:00Z | **Duration:** 2h 34m | **Tokens:** 1,234,567
## Phases
| # | Phase | Status | Notes |
|---|-------|--------|-------|
| 0 | KB Indexing | :white_check_mark: Completed | 6,336 symbols indexed |
| 1 | Task Graph | :white_check_mark: Completed | 142 tasks, 8 SCCs |
| 2 | Impact Assessment | :white_check_mark: Completed | |
| 3 | Migration Strategy | :arrow_forward: Running | |
| 4 | Iterative Migration | :hourglass: Pending | |
## Tasks — 47/142 completed (33%)
`████████████░░░░░░░░░░░░░░░░░░░░` 33%
| Status | Count |
|--------|-------|
| Completed | 47 |
| Running | 3 |
| Failed | 1 |
| Blocked | 2 |
| Pending | 89 |
## Token Usage
| Agent | Tokens | Est. Cost |
|-------|--------|-----------|
| code-migrator | 890,000 | $2.67 |
| parity-verifier | 234,000 | $0.70 |
| test-writer | 110,567 | $0.33 |
## Recent Events
- `14:32:05` Phase 0 completed — KB indexed 6,336 symbols
- `14:33:12` Phase 1 completed — 142 tasks, 12 waves
- `14:45:00` Phase 2 completed — impact-assessor succeeded
- `15:01:33` Wave 1 started — 8 tasks
- `15:12:44` Wave 1 barrier entered — build passed, 2 test failures
- `15:14:02` Wave 1 convergence iteration 1 — 1 failure remaining
FleetEventBus Integration
The renderer can subscribe to framework events for automatic updates:
/** Create middleware that auto-updates the renderer from framework events. */
function createProgressMiddleware(renderer: MarkdownProgressRenderer): EventBusMiddleware;
Events mapped:
phase-started → updatePhase(id, 'running')
phase-completed → updatePhase(id, 'completed')
issue-started / work-step-started → updateTask(id, 'running')
work-step-completed → updateTask(id, 'completed')
- All events →
appendEvent(formatted message) + flush()
Implementation Notes
flush() uses atomic write (write to temp file + rename) so readers never see partial content
- The renderer debounces
flush() calls — if multiple updates arrive within 100ms, only one write occurs
- Progress bar is built from Unicode block characters for terminal compatibility
- Emoji status markers (
:white_check_mark:, :arrow_forward:) render in GitHub/VS Code; plain text fallbacks for terminals
customSections allows consumers to append domain-specific sections (e.g., AAMF adds wave lifecycle and retry target tables)
- The renderer is independent of
IssueProgressWriter — they can run in parallel (JSON for machines, Markdown for humans)
Summary
Add a
MarkdownProgressRendererthat produces human-readable Markdown progress reports from the framework's progress data model, providing a dashboard-like view without requiring a web UI.Motivation
The framework has
IssueProgressWriterandFleetProgressWriterthat produce JSON progress files. These are great for machine consumption but aren't human-readable. When operators are monitoring a long-running agent pipeline (especially via SSH, CI logs, or file watchers), a well-formatted Markdown file is immediately useful:catorlessAAMF implements a
ProgressWriterthat generates a richprogress.mdwith phase status tables, task completion progress bars, event timelines, retry history, wave lifecycle tracking, and terminal exhaustion summaries — all atomically updated after each state change.Proposed API
MarkdownProgressRenderer
Generated Markdown Structure
FleetEventBus Integration
The renderer can subscribe to framework events for automatic updates:
Events mapped:
phase-started→updatePhase(id, 'running')phase-completed→updatePhase(id, 'completed')issue-started/work-step-started→updateTask(id, 'running')work-step-completed→updateTask(id, 'completed')appendEvent(formatted message)+flush()Implementation Notes
flush()uses atomic write (write to temp file + rename) so readers never see partial contentflush()calls — if multiple updates arrive within 100ms, only one write occurs:white_check_mark:,:arrow_forward:) render in GitHub/VS Code; plain text fallbacks for terminalscustomSectionsallows consumers to append domain-specific sections (e.g., AAMF adds wave lifecycle and retry target tables)IssueProgressWriter— they can run in parallel (JSON for machines, Markdown for humans)