Problem
Long Codev specs/plans/reviews carry useful at-a-glance metadata that's not currently surfaced in the preview:
- Where am I in the doc? (scroll position relative to length)
- How done is it? (acceptance-criteria checkbox completion)
- What's its approval state? (
approved: / validated: YAML frontmatter)
- How long will reading take? (word count → minutes)
All four are derivable from the doc content with zero new state. None require interaction. Today the architect either ignores them or hand-tallies — both bad. This issue surfaces all four as pure display chrome at the top of the preview.
Proposal — four document-state surfaces, one bundle
Bundled because they share infrastructure: a single sticky header bar at the top of the preview rendered via previewScripts + previewStyles, with no interaction (purely informational).
1. Reading progress bar
A thin colored bar fixed at the very top of the preview, tracking scroll position 0–100%.
- Renders: 2–3px tall, full-width, accent color from VS Code theme (
--vscode-progressBar-background)
- Behavior: updates on scroll; smooth animation; fades to subtle background on hover so it doesn't fight other UI
- Rationale: answers "how much more is there?" without scrolling to find out
2. Acceptance-criteria progress badge
A compact badge in the sticky header showing checkbox completion across the entire doc.
- Format:
AC 12 / 18 ✓ (or similar; 67% green when 80%+ complete, yellow otherwise)
- Source: scan rendered DOM for
<input type="checkbox"> elements (markdown-it renders - [ ] / - [x] as inputs); count checked vs total
- Behavior: click → reserved for future (could jump to first unchecked); v1 no-op (display only)
- Empty state: badge hidden when the doc has zero checkboxes
3. Frontmatter status badges
Parse YAML frontmatter at the top of the doc; render specific fields as colored chips.
Known Codev frontmatter fields (per codev/CLAUDE.md):
-
approved: 2026-01-29 → green chip ✓ approved · Jan 29
-
validated: [gemini, codex, claude] → blue chip validated by 3 (tooltip shows list)
-
(future: other fields render as gray "info" chips by default)
-
Source: simple YAML parse of the doc's first --- ... --- block (use js-yaml if not already bundled, or hand-roll for the small subset needed)
-
Behavior: static display; click → reserved for future; v1 no-op
-
Empty state: no chips when no frontmatter (today most committed files have it; pre-approval drafts don't)
4. Reading time estimate
Word-count derived estimate, shown in the sticky header.
- Format:
~5 min read (using 225 wpm — standard for technical prose)
- Source: count word-like tokens in rendered preview text (strip code blocks, headings, lists; count remaining)
- Behavior: static; updates on save
- Empty state: hidden if estimate <1 minute
Visual layout
Single sticky header bar at top of preview, below the reading progress strip:
████████████████░░░░░░░░░░░░░░░░░ ← progress bar (top edge)
0042-feature-x.md ✓ approved validated by 3 AC 12/18 ✓ ~5 min read
─────────────────────────────────────────────────────────────────────────
# Spec: Feature X
...
Path eligibility
Same as #859, #860, #861: only applies to .md files in codev/(plans|specs|reviews)/. Other markdown files get the standard preview unchanged.
Implementation sketch
Files
- New:
packages/vscode/src/markdown-preview/doc-state.js — previewScripts entry; DOM-scanning + sticky-header rendering
- New:
packages/vscode/src/markdown-preview/doc-state.css — previewStyles; layout + chip styling + progress bar positioning
- Optionally new: a
markdownItPlugin that emits the parsed frontmatter as a <meta> tag in the rendered HTML so the script doesn't have to re-parse the YAML in the browser. Cleaner separation of concerns; small additional code
Updates rendered on
load event (initial render)
- Scroll (for the progress bar — throttled via
requestAnimationFrame)
- Webview-side
message event when extension host signals doc change (markdown preview already has the plumbing for "doc rebuilt"; piggyback on it)
No interactivity in v1
All four surfaces are display-only. Click-handlers are reserved for future expansion (jump-to-first-unchecked-AC, etc.) but not wired in this PR.
Acceptance criteria
Reading progress bar
Acceptance-criteria progress badge
Frontmatter status badges
Reading time estimate
General
Out of scope (v1)
- Interactive behaviors (click AC badge to jump to first unchecked; click frontmatter chip to filter; etc.) — pure display in v1, future expansion
- Per-section AC counts — whole-doc only in v1
- Custom frontmatter rendering rules (per-field display configuration) — fixed visual; the four known fields are special-cased; everything else is generic
- Toggle to hide individual surfaces — all-on or all-off via standard markdown-preview extension disable
- Status bar item variants (showing AC count in VS Code's status bar instead of in-preview) — separate filing if desired; this issue is preview-only
- Settings to customize wpm / colors — fixed defaults; configuration adds complexity not warranted for v1
Composability
Why this is worth shipping together
Splitting into four issues would create four PRs that all touch package.json contributes.markdown.previewScripts, all reuse the same sticky-header positioning CSS, all need the same eligibility-regex gating. Bundling lands the entire status chrome in one PR — and as a set, the four surfaces tell a complete "what's the state of this doc?" story. Individually they're each useful but smaller wins.
Problem
Long Codev specs/plans/reviews carry useful at-a-glance metadata that's not currently surfaced in the preview:
approved:/validated:YAML frontmatter)All four are derivable from the doc content with zero new state. None require interaction. Today the architect either ignores them or hand-tallies — both bad. This issue surfaces all four as pure display chrome at the top of the preview.
Proposal — four document-state surfaces, one bundle
Bundled because they share infrastructure: a single sticky header bar at the top of the preview rendered via
previewScripts+previewStyles, with no interaction (purely informational).1. Reading progress bar
A thin colored bar fixed at the very top of the preview, tracking scroll position 0–100%.
--vscode-progressBar-background)2. Acceptance-criteria progress badge
A compact badge in the sticky header showing checkbox completion across the entire doc.
AC 12 / 18 ✓(or similar; 67% green when 80%+ complete, yellow otherwise)<input type="checkbox">elements (markdown-it renders- [ ]/- [x]as inputs); count checked vs total3. Frontmatter status badges
Parse YAML frontmatter at the top of the doc; render specific fields as colored chips.
Known Codev frontmatter fields (per
codev/CLAUDE.md):approved: 2026-01-29→ green chip✓ approved · Jan 29validated: [gemini, codex, claude]→ blue chipvalidated by 3(tooltip shows list)(future: other fields render as gray "info" chips by default)
Source: simple YAML parse of the doc's first
--- ... ---block (usejs-yamlif not already bundled, or hand-roll for the small subset needed)Behavior: static display; click → reserved for future; v1 no-op
Empty state: no chips when no frontmatter (today most committed files have it; pre-approval drafts don't)
4. Reading time estimate
Word-count derived estimate, shown in the sticky header.
~5 min read(using 225 wpm — standard for technical prose)Visual layout
Single sticky header bar at top of preview, below the reading progress strip:
position: sticky; top: 0; stays visible as the user scrolls+add-comment affordance (different hover targets)Path eligibility
Same as #859, #860, #861: only applies to
.mdfiles incodev/(plans|specs|reviews)/. Other markdown files get the standard preview unchanged.Implementation sketch
Files
packages/vscode/src/markdown-preview/doc-state.js—previewScriptsentry; DOM-scanning + sticky-header renderingpackages/vscode/src/markdown-preview/doc-state.css—previewStyles; layout + chip styling + progress bar positioningmarkdownItPluginthat emits the parsed frontmatter as a<meta>tag in the rendered HTML so the script doesn't have to re-parse the YAML in the browser. Cleaner separation of concerns; small additional codeUpdates rendered on
loadevent (initial render)requestAnimationFrame)messageevent when extension host signals doc change (markdown preview already has the plumbing for "doc rebuilt"; piggyback on it)No interactivity in v1
All four surfaces are display-only. Click-handlers are reserved for future expansion (jump-to-first-unchecked-AC, etc.) but not wired in this PR.
Acceptance criteria
Reading progress bar
--vscode-progressBar-backgroundor similar)requestAnimationFrameAcceptance-criteria progress badge
<checked> / <total>count of all<input type="checkbox">in rendered previewFrontmatter status badges
--- ... ---YAML blockapproved: <date>→ green chip with datevalidated: [...]→ blue chip with count (tooltip shows full list on hover)Reading time estimate
~N min read(singular1 min readwhen applicable)General
codev/(plans|specs|reviews)/*.mdpaths+— no visual collisionOut of scope (v1)
Composability
Why this is worth shipping together
Splitting into four issues would create four PRs that all touch
package.jsoncontributes.markdown.previewScripts, all reuse the same sticky-header positioning CSS, all need the same eligibility-regex gating. Bundling lands the entire status chrome in one PR — and as a set, the four surfaces tell a complete "what's the state of this doc?" story. Individually they're each useful but smaller wins.