Skip to content

M0 Phase 1: reframe the narrative around throwaway internal UIs - #299

Merged
adnaan merged 2 commits into
mainfrom
m0/narrative-reframe
Jul 19, 2026
Merged

M0 Phase 1: reframe the narrative around throwaway internal UIs#299
adnaan merged 2 commits into
mainfrom
m0/narrative-reframe

Conversation

@adnaan

@adnaan adnaan commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Second phase of the ephemeral-UI reframe plan (M0 Phase 1), following #296.

Repositions the top-line story from "one-file markdown apps" to what the project is actually for: internal UIs cheap enough to generate for a single question and delete afterwards. Augments rather than replaces — the README already carried half the reframe, and the progressive-complexity tiers, concrete examples, and the "why not just ask Claude for an HTML file?" section all still hold.

The governing constraint

Operator decision at kickoff: claim only what is true at M0. The reframe's destination is policy-gated generation, but M0 ships none of it — so every edit states the present tense and forward-references the rest. Three edits were at risk of writing M1 capability as shipped, and that constraint caught all three.

What changed

File Change
README.md New lead + a "The problem" section (internal tooling's cost-per-variation, and what changes when an LLM can hit a constrained vocabulary)
skills/tinkerdown/SKILL.md Frontmatter description + triggers + lead + a "Generate, then validate" section — the frontmatter told the old story and would have contradicted the rewritten body
docs/llms.txt Lead repositioned; required-header contract intact
docs/guides/ai-generation.md Phantom command table removed (below)
docs/llm-system-prompt.md Exec reframed
docs/reference/lvt-attributes.md + docs/archive/ROADMAP.md #226, #230
plan Tracker, Learn, and a new Phase 2 (M0)

Three findings that changed the work

1. All five slash-commands were phantom, not three — and the plan's own instruction to "redirect to the real /tinkerdown" was itself the trap, since /tinkerdown-as-generator is M1. Redirecting would have swapped five non-existent commands for one. Replaced with the loop that works today (describe → validateserve) plus a clearly future-tense pointer.

2. docs/reference/lvt-attributes.md has rotted well beyond #230. Sampling 11 documented attributes against the client, 8 are stale: lvt-scroll/lvt-highlight/lvt-animatelvt-fx:*, lvt-throttlelvt-mod:*, lvt-disable-withlvt-form:*, and lvt-click-away/lvt-focus-trap/lvt-modal-open absent from the client entirely. The lifecycle section documents the same dead lvt-{action}-on:{event} form #226 raises against the archive, and lists a loading event the client doesn't have (it's pending/done). The doc predates the client's Tier-2 namespace migration.

Deliberately not fixed here — a reference audit is its own phase, not a rider on a narrative pass. Now scheduled as Phase 2 (M0) with a full phase block, because M1 Phase 3 plans to feed this reference to the generating agent: a reference naming attributes the client no longer implements would teach it to emit invalid output, which is the exact failure the reframe exists to prevent. That makes it a prerequisite for M1, not adjacent debt. Its Acceptance includes scripting the docs-vs-client check, since a one-time correction would simply rot again.

3. #230 was not a pure rename. The entry defined lvt-preserve as "preserve form values," but lvt-ignore is a general morphdom escape hatch (Phoenix phx-update="ignore" equivalent) of which form-value preservation is one use case — and the client separately has a real lvt-form:preserve, a genuine near-miss. Renaming on the issue's say-so would have shipped a correctly-named entry with a wrong definition. Verified against the client repo per CLAUDE.md first.

Exec

From "use sparingly" to a privileged first-class source gated behind --allow-exec — today's real gate, verified at serve.go:58, websocket.go:1293, webhook.go:712. Wrapping a CLI you already trust is something Tinkerdown is genuinely good at; the gate belongs to whoever runs the server, not to the markdown. The section promises nothing about M1's manifest — an LLM system prompt should state current rules, not roadmap.

Verification

  • GOWORK=off go test ./... green, including the root package with all 32 //go:build !ci e2e files (836s)
  • skill_examples_test.go + TestLLMSTxtExists 5/5; llms.txt retains # Tinkerdown, ## Quick Start, ## Key Attributes, name=, lvt-source
  • Manual browser verification (delivery-protocol step 1) is N/A and recorded as such: nothing rendered changed — the diff is prose, headings, and attribute names in markdown docs. A screenshot here would verify nothing.

🤖 Generated with Claude Code

https://claude.ai/code/session_018M9pJSPmG6i1D8s6rpEV4h

Repositions the top-line story from "one-file markdown apps" to what the
project is actually for: internal UIs cheap enough to generate for a
single question and delete afterwards. Augments rather than replaces --
the README already carried half the reframe, and the progressive-
complexity tiers, concrete examples and "why not just ask Claude for an
HTML file?" section all still hold.

Governing constraint (operator decision): claim only what is true at M0.
The reframe's destination is policy-gated generation, but M0 ships none
of it, so every edit states the present tense and forward-references the
rest. Three edits were at risk of writing M1 capability as shipped.

Files: README lead + new "The problem" section; SKILL.md frontmatter,
triggers, lead and a "Generate, then validate" section; llms.txt lead
(required-header contract intact); ai-generation.md; llm-system-prompt.md
exec framing; the two doc-fix issues; plan tracker.

All five advertised slash-commands were phantom, not the three the plan
assumed -- and the plan's own instruction to "redirect to the real
/tinkerdown" was itself the trap, since /tinkerdown-as-generator is M1.
Redirecting would have swapped five non-existent commands for one.
Replaced with the loop that works today (describe -> validate -> serve)
and a clearly future-tense pointer to the generate skill.

Exec goes from "use sparingly" to a privileged first-class source gated
behind --allow-exec, today's real gate (serve.go:58, websocket.go:1293,
webhook.go:712). The section describes that gate and promises nothing
further; an LLM system prompt should state current rules, not roadmap.

Fixes #226 (lifecycle pattern -> lvt-el:{method}:on:{state}) and #230
(lvt-preserve -> lvt-ignore). #230 was not a pure rename: the entry
defined it as "preserve form values", but lvt-ignore is a general
morphdom escape hatch of which that is one use case -- and the client
separately has a real lvt-form:preserve, a genuine near-miss. Verified
against the client repo per CLAUDE.md before applying.

Audit also found docs/reference/lvt-attributes.md has rotted well beyond
#230 -- 8 of 11 sampled attributes are stale against the client, which
predates its Tier-2 namespace migration. Deliberately not fixed here: a
reference audit is its own phase, not a rider on a narrative pass.
Recorded in § Risks as blocking for M1 Phase 3, which plans to feed that
reference to the generating agent -- a reference naming attributes the
client no longer implements would teach it to emit invalid output.

Verification: GOWORK=off go test ./... green including the root package
with all 32 !ci e2e files (836s); skill_examples_test.go and
TestLLMSTxtExists 5/5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018M9pJSPmG6i1D8s6rpEV4h
@claude

claude Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review

Docs-only PR (no code changes); the factual claims check out. I cross-referenced the attribute claims against internal/assets/client/tinkerdown-client.browser.js (the vendored client bundle) per the CLAUDE.md instruction to verify lvt-* attributes against the client before documenting them:

  • lvt-ignore, lvt-form:preserve, data-lvt-force-update are all present in the bundle, confirming the docs/reference/lvt-attributes.md rewrite (Rename lvt-preserve to lvt-ignore in docs #230 fix) is accurate — including the nuance that lvt-ignore is the general morphdom escape hatch and lvt-form:preserve is a distinct, real attribute, not a synonym for it.
  • The lvt-el:{method}:on:{state} regex and the ["pending","success","error","done"] state list are both literally present in the bundle, confirming the FOLLOW-UP: Update lifecycle attribute pattern in ROADMAP.md #226 ROADMAP fix and the note that the old docs' loading event doesn't exist (the "loading" strings that do appear in the bundle are unrelated document.readyState/CSS-class checks).
  • --allow-exec gate citations (serve.go:58, websocket.go:1293, webhook.go:712) all check out — the exec reframe in llm-system-prompt.md accurately describes existing behavior rather than promising anything new.
  • GraphQL and computed source types (added to the README's "Live data" bullet) are real (internal/source/graphql.go, internal/source/computed.go).

Strengths

  • Good discipline on scope: the PR explicitly declines to fix the other 8/11 stale attributes it found in docs/reference/lvt-attributes.md, and instead schedules a dedicated Phase 2 with a scripted docs-vs-client check as an acceptance criterion — the right call given M1 Phase 3 will feed this reference to a generating agent.
  • The exec section change is a pure narrative reframe; it doesn't touch or imply any change to the actual --allow-exec gating, and the PR verifies that gate's current line numbers before writing about it.
  • ai-generation.md's phantom command table (/lvt-plan, /new-app, etc.) is removed rather than "redirected" to /tinkerdown, avoiding the trap of swapping five nonexistent commands for one (since /tinkerdown-as-generator is itself unbuilt, M1).
  • Test coverage is appropriate for the change: skill_examples_test.go and TestLLMSTxtExists are the right existing tests to gate a prose/frontmatter change, and docs/llms.txt's required headers (# Tinkerdown, ## Quick Start, ## Key Attributes, etc.) are all still present after the edits.

Minor notes (non-blocking)

  • docs/reference/lvt-attributes.md's "Client-Owned Attributes" list (near the end of the file) still references lvt-scroll, lvt-highlight, lvt-animate, lvt-click-away, lvt-focus-trap, lvt-modal-open as current — these are among the attributes the PR's own audit flagged as stale (now lvt-fx:* in the client, or removed entirely). This is disclosed in the PR description and intentionally deferred to the planned Phase 2, so not a request to fix here — just flagging so a reader skimming the file in isolation (without the PR description) doesn't take that section at face value in the interim.
  • No new tests were added, but none seem warranted — this is a pure prose/positioning change with no new code paths, and the plan document appropriately schedules the durable fix (a scripted docs-vs-client check) for the follow-up phase rather than bolting it onto this one.

Overall this is a well-scoped, well-verified documentation change. Nice work tracing the #230 "rename" down to a real semantic difference (lvt-ignore vs. lvt-form:preserve) instead of applying it blindly.

…itself

Review-bot note on #299: the audit's findings were disclosed in the PR
description, but someone opening lvt-attributes.md in isolation would
take its stale sections at face value. The PR description is not where a
reader looks.

Adds a banner naming what is known-stale (the lvt-fx:/lvt-mod:/lvt-form:
namespace moves, the three attributes absent from the client, and the
superseded lifecycle form), pointing at Phase 2 (M0) and telling readers
to verify against the client meanwhile.

Labels the content rather than fixing it -- the corrections remain Phase
2's job, since a full reference audit plus a scripted docs-vs-client
check is a phase, not a rider on a narrative pass. Same honesty rule the
rest of this phase follows: say what is true now.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018M9pJSPmG6i1D8s6rpEV4h
@adnaan

adnaan commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Took the first note. You're right that the PR description isn't where a reader looks — someone opening lvt-attributes.md in isolation would take the stale sections at face value.

Added a banner at the top of the page naming what's known-stale (the lvt-fx:/lvt-mod:/lvt-form: namespace moves, the three attributes absent from the client, and the superseded lifecycle form), pointing at Phase 2 (M0), and telling readers to verify against @livetemplate/client in the meantime.

It labels the content rather than fixing it — the corrections stay Phase 2's job, since a full audit plus a scripted docs-vs-client check is a phase rather than a rider on a narrative pass. That's the same rule the rest of this phase follows: say what's true now.

Also worth noting you verified against the vendored bundle (internal/assets/client/tinkerdown-client.browser.js) while I verified against the client repo source — independent paths, same conclusions, including the lvt-ignore vs lvt-form:preserve distinction. Good cross-check.

@claude

claude Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review

Docs-only PR (README, SKILL.md, llms.txt, ai-generation.md, llm-system-prompt.md, lvt-attributes.md, ROADMAP.md, and the phase plan). Verified against the current tree rather than taking the description at face value:

Verified accurate:

  • serve.go:58 / websocket.go:1293 / webhook.go:712 exec-gating references in llm-system-prompt.md all check out against the actual code (cmd/tinkerdown/commands/serve.go:58, internal/server/websocket.go:1293, internal/server/webhook.go:712).
  • The new GraphQL mention in the README source list is real — internal/source/graphql.go implements it.
  • docs/llms.txt's new title (# Tinkerdown - Throwaway Internal UIs in Markdown) still satisfies TestLLMSTxtExists's strings.Contains(contentStr, "# Tinkerdown") check, and all five required strings/headers are present.
  • Phase numbering in the plan doc (Phase 0/1/2 under M0, Phase 1-6 under M1) is consistent after inserting the new Phase 2.
  • No newly-introduced inconsistency: skills/tinkerdown/reference.md and docs/llm-system-prompt.md don't reference any of the stale attributes called out in the new lvt-attributes.md banner (lvt-preserve, lvt-scroll, lvt-highlight, lvt-animate, lvt-throttle, lvt-{action}-on:{event}), so this PR doesn't leave other surfaces newly contradicting the corrected one.

Couldn't independently verify:

  • The core lvt-* renames (lvt-preservelvt-ignore, lvt-{action}-on:{event}lvt-el:{method}:on:{state}, and the staleness audit of lvt-attributes.md generally) are checked against the upstream @livetemplate/client package, which isn't vendored or installed in this checkout (client/ here is @livetemplate/tinkerdown-client, a consumer of that package, not its source — and node_modules isn't present). Per CLAUDE.md's instruction to check livetemplate/client before documenting lvt-* attributes, this is worth a second pair of eyes with that repo actually checked out, even though the PR body cites specific file:line references (livetemplate-client.ts:1917, state/form-lifecycle-manager.ts:67) suggesting it was done.

Minor observations, non-blocking:

  • docs/guides/ai-generation.md now links a user-facing guide directly to an internal planning doc (docs/plans/2026-07-09-ephemeral-ui-reframe.md) that contains audit/"Learn" reflection sections written for contributors, not end users. There's light precedent for this (docs/archive/ROADMAP.md does the same), but it's worth confirming that's the intended reader experience — a user following "see the ephemeral-UI plan" link lands in a document written in first-person retrospective voice ("What surprised us"), not reference material.
  • The new lvt-attributes.md warning banner is good practice (labeling known-stale content in place rather than only disclosing it in the PR description, per the second commit's own stated rationale) — no notes there.
  • Scope discipline is a strength here: the PR explicitly declines to fix the attribute-reference rot it found mid-audit and instead schedules it as a tracked follow-up (Phase 2), rather than scope-creeping a narrative pass into a reference rewrite.

Test coverage: N/A for a docs change beyond the existing skill_examples_test.go / TestLLMSTxtExists, both confirmed still passing structurally. No code paths changed.

Overall this is a careful, well-scoped documentation pass with good internal consistency checks already built into the PR description itself. The one real follow-up is having someone with the livetemplate/client repo on hand confirm the attribute renames before Phase 2 builds on top of them.

@adnaan
adnaan merged commit d4c5300 into main Jul 19, 2026
1 check passed
@adnaan
adnaan deleted the m0/narrative-reframe branch July 19, 2026 21:52
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