Skip to content

Render lenses

Flow-Next 2.0.0 adds an opt-in HTML artifact mode. When it is on, the lifecycle skills emit self-contained HTML pages, render lenses, alongside their markdown output. There are two: the spec lens for business and plan review, and the PR lens for diff review. Both are covered here.

For the zero-machinery counterpart, a one-screen markdown digest of a spec, task, or diff rendered straight into chat, see /flow-next:visual.

The spec lens for the feature that shipped it (fn-62) - masthead, at-a-glance dials, serif thesis. Generated by a fresh agent session from the disclosure reference alone. Click to zoom.

One config key, written by the /flow-next:setup ceremony or set directly:

Terminal window
flowctl config get artifacts.html.enabled --json # default: false
flowctl config set artifacts.html.enabled true
flowctl config set artifacts.html.enabled false # turn off again

With the mode off or unset, participating skills load no reference file, write no artifacts, open no Lavish sessions, and add no output - the single config read is the only addition. Setup asks once (only when the key is unset): enable or not, then - on yes - commit-vs-gitignore for .flow/artifacts/ and an optional lavish-axi install offer (never auto-installed).

Generation is agentic, not deterministic: when the mode is active, the skills load one shared disclosure reference carrying all generation rules and an explicit anti-slop design contract (own warm-black instrument-panel house style, local-only font stacks, no CDN fonts, no purple gradients), and the host agent writes the HTML. There is no Python renderer and no new slash command.

The spec artifact lives at a fixed, deterministic path - .flow/artifacts/<spec-id>/spec.html, never timestamped - and regenerates at its lifecycle touchpoints. What renders depends on what state exists, not on a config axis:

Lifecycle touchpointWhat renders
/flow-next:capture - fresh spec, no tasks yetSpec-only view: thesis, acceptance criteria with source-tag provenance chips, architecture panel, edge cases, boundaries, decision context - the business-review surface
/flow-next:plan - tasks now existSame file, same path, regenerated with the plan layer: task dependency DAG with critical path, R-ID → task coverage matrix

The plan layer makes the lens a plan-review aid too: a tech lead reads the task graph and coverage matrix as one page instead of walking task files. Generation runs only after plan’s refinement loop exits - the lens never renders a task graph you are still editing.

The post-plan layer: the task DAG laid out by dependency depth, edges measured from the DOM at load (never hand-typed coordinates), critical path in amber, live task-status chips. Click to zoom.

After writing, the skill updates a single artifact link line in the spec markdown (marked <!-- flow-next:artifact-link -->), replaced in place on every regeneration - repeated capture/plan runs never duplicate it. Every artifact footer carries a staleness stamp (spec updated_at + repo commit at render time) so a reader can tell when the lens lags the markdown. Generation failure is non-fatal everywhere: the markdown is already on disk and is the record.

With the mode on, /flow-next:make-pr emits a PR render lens at .flow/artifacts/<spec-id>/pr.html: a self-contained HTML page built for one job, getting a human reviewer through the diff fast with the spec’s acceptance criteria in hand.

It is a read-only review instrument: masthead + dials, a sticky review-progress bar, the 90-second read, a churn map grouped by review intent (canonical vs generated-mirror vs mechanical), the R-ID → evidence table, a where-to-look checklist, and a risk register.

The structured artifact, GitHub Markdown, and optional HTML lens share one versioned walkthrough: identity and currentness, grounded proof, ordered logical groups, exact file membership, separate change/attention dimensions, file-level R-ID/task links, deliberately unchanged behavior, and verification. These high-resolution references define the hierarchy and interaction - not a pixel-copy requirement.

Overview: thesis, proof, legend, and logical sequence. Click to zoom.
Progressive disclosure: step to file to bounded diff. Click to zoom.
Grouped files, deliberate non-changes, and verification. Click to zoom.

When a supported current v1 object exists, it is the HTML lens’s authoritative semantic input. Interaction may be richer, but the lens cannot reorder groups, move files, invent evidence, or mix stale and legacy fields.

The PR lens for the PR that shipped it - diff dials including the human-review-lines estimate (added lines minus generated and mechanical churn), the sticky review-progress bar, and the 90-second read. Click to zoom.

The lens is built from the flowctl spec export-cognitive-aid payload plus the real diff - commit subjects and bodies are not lens input. What a reviewer reads reflects what actually changed, not what the commits claim changed.

The churn map groups the diff by review intent: canonical changes to actually review, generated mirrors to verify-not-line-review (gray bars), docs, and mechanical lockstep. Click to zoom.

Before publishing, the lens is verified against the spec’s R-ID export. Mismatches - claimed evidence outside the diff range, uncovered R-IDs, evidence touching no diff files - render as visibly flagged rows (red R-ID cell, mismatch chip, reason). A mismatch never blocks PR creation and is never silently dropped: the discrepancy is the finding.

Flagged rows in action - two R-IDs whose evidence lives in a separate repo render with red flags and a one-line reason - above the where-to-look checklist, whose checkmarks persist locally and feed the sticky progress bar. Click to zoom.
  • Current v1 stays local-only. The lens embeds a lossless HTML-safe carrier of the exact head-bound cognitive-aid object. Committing it would advance the reviewed head and immediately stale its own input, so the body gives local-open guidance and the branch head stays unchanged. Only a visibly labeled legacy fallback may use the narrow chore(flow): pr artifact <spec-id> commit.
  • The GitHub limitation. GitHub renders committed fallback HTML as raw source. Current v1 lenses are opened locally (open .flow/artifacts/<spec-id>/pr.html).
  • --dry-run writes nothing. No artifact, no commit, no body line.
  • Failure is non-fatal. Artifact generation or staging failure degrades to no-body-line plus one stderr note; the PR is still created.

The spec lens opens a Lavish annotation session when available; the PR lens never does - interactive and autonomous alike. A PR artifact derives from an immutable diff, and GitHub already owns review conversation - duplicating that surface would create a sync problem. PR feedback belongs in review threads, where /flow-next:resolve-pr picks it up.

Pilot, Land, and Ralph generate artifacts at the same touchpoints but never open a Lavish session and never poll - a loop never blocks on a human. Ralph’s PR_URL= stdout contract is untouched: all artifact messaging routes to stderr. See the safety model.

Every lens is a single HTML file - inline CSS/JS, zero external requests, fonts included, print-friendly. It opens identically from file://, inside Lavish, in a CI archive, and on paper.

GitHub renders committed .html as raw source and rejects .html PR attachments, so the markdown links carry local-open guidance:

Terminal window
open .flow/artifacts/<spec-id>/spec.html # macOS; xdg-open on Linux

Spec and legacy-fallback artifacts are committed by default; the setup ceremony offers gitignoring .flow/artifacts/ instead for clean history. A current v1 PR lens is deliberately local-only so it cannot advance and stale its own head-bound input. The skills probe ignore status and never emit a link that 404s.

Annotate in the browser (Lavish, optional)

Section titled “Annotate in the browser (Lavish, optional)”

lavish-axi (npm) is an optional companion: it serves the spec artifact in a browser session where humans annotate, and annotations flow back to the agent as edits of the markdown source of truth, followed by lens regeneration. Detected on PATH, never required - absent means a plain static artifact, never an error, never an auto-install.

Terminal window
npm i -g lavish-axi # or zero-setup per run: npx lavish-axi <artifact.html>
lavish-axi .flow/artifacts/<spec-id>/spec.html

The feedback loop is pull-only and session-spanning: annotations queue in the global ~/.lavish-axi/state.json and survive agent death - annotate tonight, and any later agent session drains the queue via lavish-axi poll, mapping each annotation to a spec edit and regenerating the lens. The local server idle-stops after ~30 minutes; the artifact still renders as a plain static page, and re-running lavish-axi <file> resumes the session.

The annotate loop applies to spec artifacts only - the PR lens never enters it, and autonomous loops never poll (see Going Autonomous).

There is no regeneration command. Auto-regen rides the lifecycle touchpoints (capture, plan, make-pr); everything else is conversational - after hand edits, an interview pass, or drained annotations, just ask the agent:

“regenerate the artifact for fn-12”

It reloads the disclosure reference, re-reads the spec + flowctl state, and regenerates at the same fixed path.