Skip to content

Stage-artifact publishing: rendered HTML per stage, shareable links on Claude Code - #23

Open
achuvyas-kv wants to merge 2 commits into
mainfrom
feat/stage-artifacts
Open

Stage-artifact publishing: rendered HTML per stage, shareable links on Claude Code#23
achuvyas-kv wants to merge 2 commits into
mainfrom
feat/stage-artifacts

Conversation

@achuvyas-kv

Copy link
Copy Markdown
Contributor

What

Each SDLC stage already writes a canonical .md (prd/hld/lld/review pack). This surfaces those as rendered pages the user can actually read after each stage — a shareable link on Claude Code, a local HTML file on Cursor/Codex.

How it fits maestro

  • engine/render_doc.py — stdlib-only, deterministic Markdown → self-contained, theme-aware HTML fragment. The fragment is both publish-ready (no <html>/<head>/<body> — the harness publisher wraps it) and locally openable (browsers render <style> + content fine). Covers the SDLC md subset: headings, tables, lists, code fences, blockquotes, bold/italic, links, hr.
  • engine/artifact_record.py — owns .maestro/runs/<slug>/artifacts.json, the step-id → {file,url} map, so a revised stage updates the SAME link instead of minting a new one on every gate cycle. A path-only harness never wipes a link a Claude Code run established.
  • skills/maestro — after complete on a step with a .md artifact: render, then publish harness-aware (Claude Code → Artifact link updated in place via the stored url; Cursor/Codex → the local .html path).

Design decisions

  • No workflow-graph edits. Publishing is a presentation add-on, not a workflow guarantee, so it's a skill-driven standing behavior rather than render nodes in the graph — zero back-edge/cascade risk, and it auto-covers every current and future doc stage.
  • Rules preserved. Never gates a step (the .md stays the proof). Never reads the doc into the lead agent's context — rendering/publishing read the file at the subprocess/tool layer only (hard rule 2 intact). Manifest writes are engine-owned and stay out of state.yaml.
  • Portable floor + Claude bonus. The rendered HTML file works everywhere; the hosted shareable link is a Claude-Code capability (Cursor/Codex have no equivalent), so it degrades to the file path there.

Tests

12 new tests (test_render_doc.py, test_artifact_record.py) covering the md subset, determinism, self-containment/publish-readiness, same-link-on-revision, and fail-closed manifest handling. Full suite green (181). No schema changes; UI anti-drift and workflow↔skill contract tests pass.

🤖 Generated with Claude Code

achuvyas-kv and others added 2 commits August 18, 2026 10:12
…ks on Claude Code

Each SDLC stage already writes a canonical .md (prd/hld/lld/review). This surfaces
those as rendered pages the user can read, not just paths — a shareable link on Claude
Code, a local HTML file on Cursor/Codex.

- engine/render_doc.py: stdlib-only, deterministic Markdown -> self-contained HTML
  fragment (publish-ready AND locally openable). Covers the SDLC md subset.
- engine/artifact_record.py: owns .maestro/runs/<slug>/artifacts.json, the
  step-id -> {file,url} map, so a revised stage updates the SAME link instead of
  minting a new one. Path-only harnesses never wipe a link a Claude Code run set.
- skills/maestro: after `complete` on a step with a .md artifact, render then publish
  harness-aware. Presentation only — never gates a step, never reads the doc into the
  lead agent's context (rule 2 preserved).

No workflow-graph edits (no back-edge/cascade risk); no schema changes. Rendering is a
skill-driven standing behavior, so it auto-covers every current and future doc stage.
12 new tests; full suite green (181).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An input-bearing gate option (e.g. LLD scope "Pick specific repos") collected a
free-text comma list even though the engine had already discovered the exact valid
values. Now an option may declare `choices` (a resolvable placeholder) and `multi`;
the follow-up ask_input action carries them so the harness renders a multi-select
instead of a text box. The recorded input is the selected label(s), the same
comma-separated shape free text produced — so downstream parsing is unchanged.

- resolver: _gate_input_action resolves the option's `choices` into the ask_input action
- schema + validate: allow choices/multi on a gate option; choices requires an input field
- skills/maestro: render a selector (AskUserQuestion multiSelect) when choices are present
- design.yaml: the LLD-scope "pick" option now feeds the discovered repo names
- ui/builder.html re-embedded; 2 resolver tests; full suite green (183)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant