render-loop
A self-checking loop for developing this repo's exporter. It lets you see what the HTML actually renders (via a headless-Chrome screenshot you can open with the Read tool), fix the renderer, and re-validate — without leaving the session.
This skill is repo-local (.claude/skills/render-loop/) and not shareable: it
hard-codes this repo's layout (skills/session-export/) and assumes Google
Chrome + Node 18+.
The loop
When the user points at a rendering concern and a session (e.g. "the rendering of TaskGet looks like raw JSON, see session 2e875f45…"):
Locate & classify the session. A session id is a UUID. Claude sessions live under
~/.claude/projects/**/<uuid>.jsonl; Codex rollouts under~/.codex/sessions/**/rollout-*<uuid>*.jsonl. If it's a Codex rollout, use--codex. You can pass a full path instead of an id.Inspect the raw record first. Find the relevant
tool_use/ message in the jsonl to learn the exact input/result shape before changing code:grep -n '"name":"TaskGet"' <session.jsonl> # or node one-liner to dump the blockExport + screenshot the card. From the repo root:
.claude/skills/render-loop/render.sh <uuid-or-path> [--codex] --find "<text near the card>"--findtext should be something visible in that card (a tool name, an arg, a phrase). It printsHTML:andPNG:paths. Read the PNG to view the current rendering. (Omit--findfor a full-page capture, height-capped.)Diagnose. Compare what you see against what the user wants. The renderer is
skills/session-export/template.js(shared client renderer — tool cards live in therenderToolCallswitch; entry/role logic inrenderEntry/renderRun). Parsing/normalization isexport.js(Claude) andcodex-export.js(Codex); shared redaction inredact.js.Fix the JS (usually a
casein therenderToolCallswitch, or a helper).Re-render & validate. Re-run the same
render.sh …command, Read the new PNG, and confirm it matches the requested outcome. Iterate steps 4–6 until it's right. Also run the cheap sanity check after edits:node -e 'const h=require("./skills/session-export/template.js")();const m=h.match(/<script>([\s\S]*?)<\/script>\s*<\/body>/);new Function(m[1]);console.log("ok")'Report the change and offer to commit (template work currently lives on the
codex-exportbranch).
Tools in this skill
render.sh <session> [--codex] [--find "text"] [--index N]— export then screenshot in one step (most common entry point).shoot.js <file.html> [--find "text" | --selector css] [--index N] [--full] [--out png]— screenshot any already-exported HTML. Drives Chrome over the DevTools Protocol with Node's built-in WebSocket (no npm deps); expands all collapsible cards, then crops to the matched element (or full page, capped at 4000px). Override the browser withCHROME_BIN.
Notes
- Exported HTML lands in the repo root (
claude-session-*/codex-session-*, both gitignored); the PNG goes to$TMPDIR/render-loop.png. Both are scratch. --findmatches the first card (.tool,.askq,.subagent,.context,.command,.entry) containing the text; use--index Nto disambiguate.- Self-improving: if the loop exposes a gap —
shoot.jscan't target what you need, a new card type isn't matchable, the diagnosis was slow — improveshoot.js/ thisSKILL.mdas part of the task so the next loop is sharper.