Skip to content

feat(v2.4.0): HTML SDD foundation — templates, theming, plugin integration (PR 1/5)#10

Merged
DanielPodolsky merged 13 commits into
mainfrom
feat/v240-html-foundation
May 28, 2026
Merged

feat(v2.4.0): HTML SDD foundation — templates, theming, plugin integration (PR 1/5)#10
DanielPodolsky merged 13 commits into
mainfrom
feat/v240-html-foundation

Conversation

@DanielPodolsky
Copy link
Copy Markdown
Owner

@DanielPodolsky DanielPodolsky commented May 28, 2026

Summary

First of five sequential PRs delivering the v2.4.0 migration of the Spec-Driven Development workflow from Markdown to canonical HTML, per the architecture decisions locked in #9.

This PR is the foundation — it ships the entire HTML template bundle, the new /own:theme command, the /own:init plugin-check phase, and the install-script plumbing that propagates templates into user projects. The remaining four PRs activate this foundation in /own:init, /own:feature, /own:done+/own:status, and /own:migrate.

What ships in PR 1

Area Changes
HTML templates 6 .html.template files (mission, stack, roadmap, spec, design, tasks) in core/templates/html/
Theme defaults theme-prompt.md.template (Apple Documentation aesthetic) + theme-fallback.css (production CSS covering all semantic classes)
New command /own:theme — 4 user actions (change/preset/regenerate/view) + --revert flow with timestamped history backups
/own:init hook New Phase 0.5: detect frontend-design plugin, offer auto-install, seed .theme/ directory, generate theme.css
Install plumbing STEP 7.5 in both project-install.sh and project-install.ps1 copies the template bundle into user projects at ownyourcode/templates/html/

Architecture highlights

  • Option D mutation strategy: Every task block uses data-task-id + data-status attributes, allowing /own:done to mutate state via Claude's existing Edit tool with exact-string find-and-replace. No external HTML parser needed — Claude IS the HTML mutator.
  • Theme as single CSS file: All 6 HTML templates reference one theme.css, so changing themes is instant and lossless. No HTML regeneration needed when the theme prompt changes.
  • Soft plugin dependency: frontend-design is auto-offered during /own:init but never required. Users who decline still get an acceptable themed output via the bundled fallback CSS.
  • Backup-before-write: Every /own:theme mutation backs up to ownyourcode/.theme/.history/[timestamp]/ before overwriting, enabling /own:theme --revert.
  • No SDD semantic changes: Hard constraint — HTML migration is pure visualization. Every file's purpose stays identical to its MD counterpart. The theme command rejects prompts that try to alter workflow.

Why no behavior change yet

This PR is intentionally non-activating. /own:init's Phase 6 still writes Markdown product files (PR 2 will flip this). /own:feature still writes Markdown spec files (PR 3 will flip this). Existing users see no change to their projects.

PR 1 ships the infrastructure — templates exist, the theme command works, the plugin check runs. PRs 2–5 will activate the migration.

Roadmap to v2.4.0

  • PR 1 (this PR) — Foundation: templates + /own:theme + plugin integration
  • PR 2 — Activate HTML output in /own:init (mission.html, stack.html, roadmap.html)
  • PR 3 — Activate HTML output in /own:feature (spec.html, design.html, tasks.html) + roadmap.html phase detection
  • PR 4 — DOM mutation in /own:done + parsing in /own:status using the Option D data-attribute contract
  • PR 5/own:migrate opt-in command for existing Markdown projects with backup + --revert

Test plan

  • Run bash scripts/project-install.sh against a fresh test directory; confirm ownyourcode/templates/html/ is populated with the 8 expected files
  • Run pwsh scripts/project-install.ps1 against a fresh test directory on Windows (or via PowerShell on macOS); confirm same outcome
  • Run /own:theme in a fresh project with .theme/ already present; confirm it offers the 4-action menu
  • Run /own:theme in a fresh project without .theme/; confirm it tells the user to run /own:migrate first and stops
  • Run /own:theme --revert with no backups present; confirm it reports "No theme backups found"
  • Run /own:init in a fresh directory; confirm Phase 0.5 executes (plugin check + install prompt + theme.css generation)
  • Run /own:init with .theme/ already present; confirm Phase 0.5 is skipped (idempotency)
  • Manually validate that theme-fallback.css renders all 6 template types with light + dark mode parity
  • Inspect every *.html.template for valid semantic structure and correct data-* attribute contracts

Refs

🤖 Generated with Claude Code

DanielPodolsky and others added 4 commits May 28, 2026 14:45
…D migration

Lay the semantic foundation for the spec-driven development workflow's
migration from Markdown to canonical HTML. Each template establishes the
data-attribute-based mutation strategy that lets Claude's Edit tool act
as the HTML mutator without introducing any external parser dependency.

Templates added (core/templates/html/):
- tasks.html.template — canonical Option D exemplar. Establishes the
  data-task-id + data-status contract that /own:done mutates and
  /own:status counts via pure text operations.
- roadmap.html.template — phase-detection contract using
  data-phase-number + data-phase-name + data-status, consumed by
  /own:feature for next-incomplete-phase auto-detection.
- mission.html.template — project vision template with distinct
  data-dod-id namespace to prevent /own:done cross-file mutations.
- stack.html.template — technology table with data-stack-layer rows
  and source attribution via data-source-type.
- spec.html.template — user stories, acceptance criteria, edge cases,
  and out-of-scope sections with referenceable data-* IDs.
- design.html.template — technical software architecture (NOT UI
  mockups). Trade-off articles with chosen/rejected/reasoning blocks.
- theme-prompt.md.template — default Apple Documentation aesthetic
  prompt consumed by frontend-design to generate theme.css.
- theme-fallback.css — hand-authored production CSS mirroring the
  default aesthetic. Used when frontend-design plugin is unavailable.
  Covers every semantic class and data-* selector across all 6
  templates with light/dark mode via prefers-color-scheme.

Inline HTML comments document mutation contracts in every template
for self-discoverability across future Claude sessions.

Refs #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…integration

Add the v2.4.0 /own:theme slash command that lets developers manage the
visual styling of their generated HTML SDD files independently of the
workflow itself. The theme is a single CSS file referenced by all six
HTML templates, so changing themes is instant and lossless — no HTML
files need regenerating.

The command exposes four actions through AskUserQuestion:
- Change theme prompt — free-text custom prompt for frontend-design
- Pick a preset — bundled aesthetic presets (apple-light/dark, etc.)
- Regenerate current — re-roll CSS using the existing prompt
- View full prompt — read-only inspection of theme-prompt.md

Every write is backup-first: the prior prompt and CSS are copied to
ownyourcode/.theme/.history/[ISO-timestamp]/ before overwrite, enabling
non-destructive iteration. The accompanying /own:theme --revert flow
restores from any timestamped backup.

frontend-design is treated as a soft dependency: when the plugin is
unavailable, the command falls back to the bundled theme-fallback.css
and writes theme.fallback_mode = true to the manifest. Users without
the plugin still get an acceptable themed output instead of an error.

Hard constraint enforced in the command's instructions: theme prompts
that attempt to alter SDD workflow semantics (e.g., "hide the
checkboxes") must be rejected with a warning. The theme is visual
styling only — never workflow.

Refs #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ependency

Insert a new Phase 0.5 between the existing MCP check (Phase 0) and the
project detection step (Phase 1) so that every fresh OwnYourCode
project starts with a working visual theme for its eventual HTML SDD
files. The phase is idempotent — it detects an existing .theme/
directory and skips entirely, so re-running /own:init never overwrites
a user's customized theme.

The new flow:
1. Skip if ownyourcode/.theme/ already exists.
2. Detect the frontend-design plugin via the marketplace cache.
3. If missing, surface a single AskUserQuestion with an explicit
   permission request to install it — Daniel does not want users
   discovering plugin dependencies via cryptic failures later.
4. Honor the user's choice: install on yes, set fallback_mode on skip.
5. Create ownyourcode/.theme/ with history directory pre-seeded.
6. Copy the default theme prompt from ownyourcode/templates/html/.
7. Generate theme.css via frontend-design (or copy fallback CSS).
8. Record theme metadata in .claude/ownyourcode-manifest.json.

This phase ships in PR 1 ahead of the HTML output activation (planned
for PR 2 in /own:feature). Until then, theme.css sits ready and is
harmlessly inactive — no existing functionality breaks. When PR 2
flips /own:init's Phase 6 to write HTML, the theme is already in place.

Refs #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend both the POSIX (bash) and Windows (PowerShell) install scripts
with a STEP 7.5 that propagates the v2.4.0 HTML template bundle from
the OwnYourCode source repo into each user's installed project. The
new step runs between the existing guides copy (STEP 7) and the
product-templates heredoc generation (STEP 8), preserving the
established ordering convention.

Templates land at ownyourcode/templates/html/ inside the user's
project so commands like /own:init Phase 0.5, /own:feature, and
/own:theme can resolve them via relative project-root paths instead
of needing a separately-discovered install location.

Both glob copies are made safe on older source repos: missing files
or directories are silently skipped (POSIX uses 2>/dev/null || true;
PowerShell uses Test-Path guards). Existing installations that
upgrade by re-running the installer get the new templates added
without overwriting anything they already have.

Refs #9

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude finished @DanielPodolsky's task in 4m 34s —— View job


Claude Code Review — PR #10 (v2.4.0 HTML Foundation)

  • Read repo CLAUDE.md + reviewer standards
  • Pull full diff (gh pr diff 10)
  • Inspect /own:theme command (frontmatter, plan-mode warning, Socratic flow)
  • Inspect /own:init Phase 0.5 additions
  • Inspect 6 HTML templates + theme assets for data-* contract consistency
  • Verify .sh / .ps1 install script parity (T1)
  • Check README/CHANGELOG sync (D1/D2)
  • Check cross-references to /own:migrate (S4)
  • Post inline findings + verdict

Summary

This PR delivers an unusually well-architected foundation. The Option D data-attribute contract in the HTML templates is the load-bearing decision — exact-string mutation via Edit, text-count parsing for /own:status, and a clean separation of data-task-id / data-dod-id / data-roadmap-item that prevents cross-file accidents. The fallback CSS is comprehensive (light + dark, every semantic class covered, custom-property tokens), the backup-before-write discipline in /own:theme is belt-and-suspenders, and the "theme = visual only, never workflow" hard constraint preserves Gate 1 cleanly. Frontmatter, plan-mode warnings, and allowed-tools minimalism are all clean on theme.md.

That said, there's one MAJOR finding that needs to be addressed before merge, plus a handful of minor follow-ups. None of them touch the architecture — they're consistency and rollout-discipline issues.

Findings

Severity Rule Finding
MAJOR P3 / S4 init.md line 781 uses claude plugin install … as a shell command — but plugin installs in Claude Code are the /plugin install slash command (as correctly documented in theme.md line 202). The two files contradict each other; Phase 0.5 Step 3's "Yes, install it" branch will silently fail and downgrade every opt-in user to fallback CSS. See inline comment on init.md:781.
MINOR S4 theme.md:55 points users to /own:migrate, which doesn't exist until PR 5. Either hold the merge until PR 5, or soften the message to acknowledge it's not ready yet. See inline.
MINOR D2 No CHANGELOG.md entry for this PR. A new command (/own:theme), a new init phase (Phase 0.5), and an install-script behavior change collectively warrant a MINOR semver bump and an [Unreleased] block. Currently [Unreleased] only mentions the reviewer + tag responder.
MINOR D1 README Commands table (lines 104–119) does not list /own:theme. Discoverability gap — D1 says user-facing commands must appear in the table.
MINOR T1 Subtle .sh / .ps1 parity asymmetry on the new STEP 7.5: .sh is non-recursive, .ps1 uses -Recurse. Benign today, breaks the moment presets/ lands. See inline on project-install.ps1:301.
MINOR T1 theme.md:239 uses macOS-only open for the preview action with a comment about cross-platform but no actual branching. Linux/Windows users get a silent no-op. See inline.
MINOR D4/T2 theme-prompt.md.template:27 ships a TODO(daniel) note into every user's .theme/theme-prompt.md. Inside an HTML comment so invisible in render, but visible in the file users edit. See inline.
PRAISE The Option D data-* contract in tasks.html.template (and the mirrored discipline in roadmap.html.template + mission.html.template) is exactly the kind of decision that pays off later. See inline on tasks.html.template:11-28.
PRAISE theme-fallback.css is real engineering taste — token-driven, full light/dark parity, covers every semantic class across all 6 templates, and degrades gracefully on mobile. Users who skip the plugin still get a premium-feeling default.
PRAISE The hard constraint at theme.md:34 ("Theme = visual styling ONLY... If the user's custom prompt suggests workflow changes, reject those modifications") is a clean P2 guardrail. Prevents the failure mode where someone prompts frontend-design into mutating SDD semantics.

Philosophy check

  • P1 (Socratic): /own:theme uses AskUserQuestion for the 4-action menu and for revert selection, and intentionally uses free-text chat for the custom-prompt input where multiple-choice would be wrong. Good. ✅
  • P2 (Ownership / Gate 1): No bypass. The user owns their theme prompt, sees backups before every overwrite, and can revert. The "reject prompts that alter semantics" constraint guards Gate 1 directly. ✅
  • P3 (Evidence-Based): The plugin-install invocation is the one place this slips — see MAJOR finding. ⚠️
  • P4 (Universal Audience): Fallback CSS means Junior profile users without the plugin still get a usable themed output. No profile is regressed. ✅

Verdict

The architecture is sound and the engineering instincts on display (data-attribute contract, fallback parity, backup-before-write) are top-tier. But the claude plugin install invocation is a real correctness bug in the headline feature of Phase 0.5, and the CHANGELOG + README sync gaps mean the PR isn't fully shipped against OwnYourCode's own documentation discipline. Address the MAJOR, decide on the /own:migrate reference strategy, sync README + CHANGELOG, then this lands cleanly.

VERDICT: REQUEST_CHANGES
· branch feat/v240-html-foundation

Comment thread .claude/commands/own/init.md Outdated
Comment thread .claude/commands/own/theme.md Outdated
Comment thread .claude/commands/own/theme.md
Comment thread core/templates/html/theme-prompt.md.template Outdated
Comment thread scripts/project-install.ps1
Comment thread core/templates/html/tasks.html.template
DanielPodolsky and others added 5 commits May 28, 2026 14:52
…d table

Pre-emptively address the documentation sync gap before the reviewer
finds it. Document the v2.4.0 PR 1 scope explicitly so future readers
of the changelog understand the foundation-only nature of this PR and
the four subsequent PRs that will activate HTML output, mutation
contracts, and the migration command.

CHANGELOG additions land in [Unreleased] under a dedicated v2.4.0
sub-heading rather than under Repository Infrastructure, because this
is a product-surface change (templates, command, init phase) rather
than internal tooling.

README's slash-command table now lists /own:theme between /own:profile
and /own:test, tagged with the v2.4.0+ availability marker so users
who land on the README without context can see at a glance that this
command requires a later release.

Refs #9, #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lash command

PR #10 review caught a real correctness bug in Phase 0.5 Step 3: the
"Yes, install it" branch invoked `claude plugin install ...` as a
shell command, but Claude Code's plugin marketplace install is a
slash command (`/plugin install`). The shell form silently fails and
downgrades every opt-in user to the bundled fallback CSS, defeating
the purpose of the install prompt.

Slash commands cannot directly invoke other slash commands from
within their flow, so the corrected behavior is to instruct the user
to run `/plugin install frontend-design@claude-plugins-official`
themselves, then re-run `/own:init`. The re-run hits Step 2's plugin
detection, finds the now-installed plugin, and skips the install
prompt entirely — clean idempotent handoff.

Surfacing the slash-command invocation also gives the user explicit
visibility into what's being installed, which fits OwnYourCode's
evidence-based-engineering principle better than a hidden shell exec.

Addresses MAJOR finding (P3/S4) on PR #10.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m preview

Two minor review findings addressed in a single touch on theme.md:

1. The Phase 1 pre-flight error message that fires when ownyourcode/.theme/
   is missing previously told the user to "run /own:migrate first" — but
   /own:migrate ships in PR 5 and does not exist when PR 1 lands alone. The
   message now explains both paths honestly: new v2.4.0+ projects should
   run /own:init; existing Markdown projects acknowledge that /own:migrate
   is forthcoming and offer a manual workaround in the meantime. Users
   reading the message during the PR-1-only window get accurate guidance
   instead of a dead-end command name.

2. The Phase 7 preview action previously hardcoded macOS's `open` with a
   comment promising cross-platform support but no actual branching. Linux
   and Windows users hit a silent no-op. The corrected flow detects the
   platform via `uname -s` and dispatches to `open` on macOS, `xdg-open`
   on Linux, and `start` on Cygwin/MSYS/MinGW. A PowerShell-equivalent
   `Start-Process` snippet is documented for PowerShell sessions where
   `uname` is absent. If no opener is available, the file path is surfaced
   so the user can open it manually rather than nothing happening.

Addresses MINOR findings S4 and T1 on PR #10.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l parity

The PowerShell variant of STEP 7.5 was already using -Recurse to copy
the HTML template bundle, so it would automatically pick up any
subdirectory that lands later (e.g., a planned presets/ folder for
bundled theme presets). The bash variant only globbed *.template and
*.css at the top level, which would silently skip future
subdirectories — a real parity gap waiting to bite the moment
presets/ ships.

The fixed bash version uses `cp -R "$SRC/." "$DEST/"` to recursively
copy the entire html/ directory contents, mirroring the PowerShell
semantics exactly. The trailing `/.` ensures contents are copied (not
the directory itself), keeping the destination flat the way the
PowerShell version produces it. A guard checks for the source
directory's existence first so older OwnYourCode source repos (where
the templates don't yet exist) still install cleanly.

Addresses MINOR finding T1 on PR #10.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ompt

The default theme prompt previously embedded a TODO(daniel) note as
a Markdown comment immediately after the H1 heading. The note was
intended as an editor-time reminder for the project author but was
inside the file content itself, so it would ship into every user's
ownyourcode/.theme/theme-prompt.md on install — visible whenever
they opened the file to edit their theme, even though the personal
addressing applies only to the upstream repo.

Removing the lines entirely. The HTML comment block at the top of
the file (explaining how the prompt is consumed) is unchanged — that
guidance is genuinely useful for users editing their own theme.

Addresses MINOR finding D4/T2 on PR #10.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude finished @DanielPodolsky's task in 2m 35s —— View job


Claude Code Review — PR #10 (re-review after sync)

  • Pull latest diff & confirm commits (5 new commits, 1:1 with prior findings)
  • Verify MAJOR fix: claude plugin install/plugin install slash-command handoff in init.md (2dc45f2)
  • Verify MINOR S4: softened /own:migrate forward reference in theme.md (960dec3)
  • Verify MINOR T1: .sh recursive parity with .ps1 install copy (08cc6be)
  • Verify MINOR T1: cross-platform preview opener with Darwin/Linux/Windows branch (960dec3)
  • Verify MINOR D4/T2: TODO(daniel) stripped from theme-prompt.md.template (ab01c75)
  • Verify MINOR D1+D2: /own:theme row in README Commands table + complete CHANGELOG [Unreleased] block (8835af7)

Re-review summary

Every finding from the prior REQUEST_CHANGES review is cleanly addressed. Specifically:

MAJOR — P3/S4 (init.md Phase 0.5 Step 3): Resolved. The bash invocation is replaced with an explicit slash-command handoff — the user is told to run /plugin install frontend-design@claude-plugins-official themselves and re-run /own:init. The rationale at init.md:790 ("a slash command cannot invoke another slash command directly") is correct, and the form now matches theme.md:205. The contradiction between the two files is gone. Soft-dependency promise is now actually deliverable.

MINOR — S4 (/own:migrate forward reference): Resolved. theme.md:58 now says "/own:migrate will land in a future v2.4.0 PR — until then, you can manually create ownyourcode/.theme/ by running /own:init in a clean copy." No dead-end reference; honest about the rollout state and offers a concrete fallback path.

MINOR — T1 (install script parity): Resolved. project-install.sh:267 switched to cp -R "$BASE_DIR/core/templates/html/." "$PROJECT_DIR/ownyourcode/templates/html/" with an inline comment noting the parity intent. Both platforms now copy recursively. Forward-looking nit (not blocking): the .ps1 block at project-install.ps1:300-303 iterates Get-ChildItem -Recurse and copies each file to $destHtml flat — which will flatten any future presets/ subdirectory on Windows while .sh's cp -R preserves it. Worth fixing in the PR that lands presets/, but no behavior difference today.

MINOR — T1 (cross-platform preview): Resolved. theme.md:243-249 now branches on uname -s for Darwin/Linux/CYGWIN+MINGW+MSYS, has a default arm that surfaces the path instead of silently failing, and includes a PowerShell Start-Process fallback for sessions where uname is absent.

MINOR — D4/T2 (TODO leak): Resolved. theme-prompt.md.template is clean — no TODO(daniel) artifact. Users get production-ready scaffolding.

MINOR — D1+D2 (docs sync): Resolved. README Commands table has /own:theme | Manage HTML theme styling (v2.4.0+) at line 118. CHANGELOG [Unreleased] block documents the HTML template bundle, theme assets, /own:theme, Phase 0.5, and install-script updates — appropriately scoped as a MINOR addition. ✅

Philosophy re-check

  • P1 (Socratic): Still preserved — AskUserQuestion flows intact, custom-prompt input remains free-text (correct choice).
  • P2 (Ownership / Gate 1): Still preserved — the slash-command handoff in Step 3 actually strengthens P2: the user explicitly invokes plugin install, gaining visibility and consent rather than having it happen autonomously.
  • P3 (Evidence-Based): Now clean — the previously-fabricated claude plugin install invocation is replaced with the verifiable /plugin install slash command.
  • P4 (Universal Audience): Still preserved — fallback CSS path remains intact.

Verdict

The architecture was sound on the first pass and the engineering instincts (Option D data-attribute contract, fallback CSS parity, backup-before-write, cross-platform branch discipline) carried through cleanly. Daniel addressed every finding precisely — no scope creep, no incidental edits, just the targeted fixes — which is exactly the iteration discipline this project preaches. The remaining .ps1 flattening observation is a worthwhile note for the PR that introduces presets/, but not a present-day defect.

Ship it.

VERDICT: APPROVE
· branch feat/v240-html-foundation ·

@DanielPodolsky
Copy link
Copy Markdown
Owner Author

🛠️ Review findings addressed

Thanks for the thorough review. All 7 findings (1 MAJOR + 6 MINOR) addressed in 5 fix-up commits on this branch:

Finding Severity Commit Status
init.md claude plugin install (shell) → /plugin install (slash) 🔴 MAJOR 2dc45f2 ✅ Fixed
theme.md /own:migrate forward reference softened 🟡 MINOR 960dec3 ✅ Fixed
CHANGELOG.md missing v2.4.0 entry 🟡 MINOR 8835af7 ✅ Fixed (pre-emptive)
README missing /own:theme row 🟡 MINOR 8835af7 ✅ Fixed (pre-emptive)
.sh vs .ps1 parity (sh non-recursive) 🟡 MINOR 08cc6be ✅ Fixed
Cross-platform preview action (macOS-only open) 🟡 MINOR 960dec3 ✅ Fixed
theme-prompt.md.template leaked TODO(daniel) to users 🟡 MINOR ab01c75 ✅ Fixed

Notes on specific fixes

  • MAJOR plugin install: The corrected flow now instructs the user to run /plugin install themselves (slash commands can't invoke other slash commands), then re-run /own:init. The re-run hits Phase 0.5 Step 2's plugin detection, finds the plugin, and skips the install prompt — clean idempotent handoff. Also gives explicit user consent visibility, which fits the evidence-based-engineering principle better than a hidden shell exec.

  • /own:migrate reference: Rather than removing the reference (which would create an orphan-knowledge problem for users when PRs 2–5 land), the message now explains both paths honestly. Users get accurate guidance during the PR-1-only window without losing the forward-pointer when /own:migrate ships.

  • Cross-platform preview: Now dispatches via uname -s to open / xdg-open / start. A PowerShell Start-Process snippet is documented for sessions where uname is absent. Fallback to surfacing the file path so users can open it manually — never a silent no-op.

  • Install script parity: Bash now uses cp -R "$SRC/." "$DEST/" to mirror PowerShell's -Recurse semantics exactly. Future subdirectories (e.g., presets/) propagate cleanly across both platforms.

Praise notes saved to my career memory — particularly the Option D contract and fallback CSS callouts. 🙏

Ready for re-review. The CI gate should kick off automatically on this push.

…g Phase 0.5

The previous fix correctly switched the plugin install invocation from
a shell command to the /plugin install slash command, but it forced
every opt-in user to STOP /own:init and re-run from Phase -1, throwing
away their already-completed profile selection, MCP check, and any
other in-flight progress. Real correctness, real UX regression.

The corrected design uses two AskUserQuestion calls to hold the slash
command's flow in place while the user runs /plugin install in a
separate message. The first AskUserQuestion asks whether to install
at all; the second is the actual pause — it stays open while the user
types the install command elsewhere in the conversation, and resumes
Phase 0.5 from exactly the point it paused when they pick "Done."

After the user reports "Done," Phase 0.5 re-runs the plugin detection
silently. On success, it continues to Step 4 (.theme/ creation) with
plugin_available = true. On failure (install didn't register, command
mistyped, plugin cache not refreshed), it loops up to two retries
before forcing the skip path so no user ever ends up stuck.

The "Cancel — use fallback" branch at every prompt level preserves
the soft-dependency contract: every user keeps all their progress and
ends up with a working theme regardless of whether the plugin lands.

Why this works: AskUserQuestion in Claude Code holds the conversation
turn open until the user answers. Other slash commands invoked in
between (like /plugin install) don't destroy the parent command's
context — when the user picks an option, the original /own:init flow
resumes where it paused.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude finished @DanielPodolsky's task in 4m 20s —— View job


Claude Code Review — PR #10 (3rd pass, post-2417cc3)

  • Identify what changed since prior APPROVE (8835af7)
  • Read the new init.md Phase 0.5 pause-and-resume flow
  • Verify the slash-command handoff still respects P2 (consent/ownership) and P3 (verifiable invocation)
  • Check that idempotency claim from prior re-review still holds
  • Post inline findings + verdict

Summary

Single new commit since the prior APPROVE (2417cc3pause-and-resume plugin install flow). It addresses a real UX regression my last pass missed: the previous fix correctly switched claude plugin install/plugin install (slash command), but forced opt-in users to restart /own:init from Phase -1, throwing away their already-completed profile selection, MCP check, and detection work. That's a P4 (Universal Audience) cost — Junior profile users in particular, who walk through that flow carefully, would lose the most.

The fix uses two AskUserQuestion calls to hold the parent slash-command's flow in place while the user runs /plugin install in a separate conversation turn, then resumes from the pause when they answer. The design degrades gracefully: every branch (skip / install-failed / 3 detection-failure retries) lands the user on fallback CSS without losing prior work.

Findings

Severity Rule Finding
MINOR P3 The Rationale at init.md:833 makes a confident claim about Claude Code's runtime behavior (AskUserQuestion holds the parent flow while another slash command runs in between) that isn't cited or empirically verified. Same category of issue as the prior MAJOR (claude plugin install was assumed to exist) — but saved from blocking merge by the graceful-degradation property: if the assumption is wrong, the worst case is the user picks "Install failed" and lands on fallback CSS. See inline.
PRAISE The bounded retry loop at init.md:827 (3 attempts total, then forced graceful exit to fallback) is exactly the discipline this kind of flow needs — explicit cap, lossless exit, user controls every iteration. See inline.
PRAISE Recovering from the prior fix's UX regression with zero work lost across every branch is genuine engineering taste. The soft-dependency contract you set at the top of this PR holds at the third level of nested branching (SkipTry again × 3Force-skip) — that's not accidental, it's deliberate graceful-degradation architecture, and it shows in every state transition.

Philosophy re-check

  • P1 (Socratic): AskUserQuestion flows multiplied, never collapsed to a hardcoded path. ✅
  • P2 (Ownership / Gate 1): Strengthened, actually — the user explicitly invokes /plugin install themselves (consent + visibility) instead of having it happen autonomously. The pause-and-resume preserves the visible chain of decisions. ✅
  • P3 (Evidence-Based): One small slip — the Rationale's claim about AskUserQuestion runtime behavior is unverified. See inline finding. ⚠️ (non-blocking)
  • P4 (Universal Audience): Materially improved — Junior-profile users no longer pay a "lose all your work" tax for opting into the plugin. ✅

Standards re-check

  • S1/S2 (frontmatter, tool minimalism): No change. Still clean.
  • S4 (cross-references): No new cross-references introduced. Existing /own:migrate softened reference (from prior pass) still resolves to honest fallback guidance.
  • T1 (.sh/.ps1 parity): No change to install scripts in this commit. Prior parity fix (08cc6be) still holds.
  • T2 (template migration): No template changes. theme-prompt.md.template still clean post-ab01c75.
  • D2 (CHANGELOG): The [Unreleased] block already documents Phase 0.5 in full — this commit is a fix-up to that same Unreleased feature, no new entry needed. ✅
  • D3 (commit pitch): fix(own:init): pause-and-resume plugin install flow without restarting Phase 0.5 — passes the recruiter-skim test. Body explains the why (UX regression, lost progress) and the how (two AskUserQuestion calls). Strong commit discipline. ✅

Verdict

Daniel caught and fixed a real regression I should have flagged in the prior pass — that's the kind of self-review that makes external review work. The new flow is materially better than what merged in my "APPROVE" review: it preserves user progress, degrades gracefully under every failure mode I can construct, and reads cleanly. The one P3 nit on the unverified runtime assumption is real but bounded by the graceful-degradation design, so it's a follow-up not a blocker.

Ship it.

VERDICT: APPROVE
· branch feat/v240-html-foundation

@DanielPodolsky
Copy link
Copy Markdown
Owner Author

Follow-up: pause-and-resume UX fix (2417cc3)

Even though the prior review was APPROVE, one UX wart remained on the
soft-dependency contract: when a user opted to install the plugin, the
flow told them to "re-run /own:init" — losing their already-completed
profile selection and any other in-flight progress. Real correctness fix,
real UX regression.

The corrected design uses two AskUserQuestion calls to hold the
slash-command flow in place
while the user runs /plugin install
in a separate message. After the user reports the install is done,
/own:init re-checks plugin detection silently and continues Phase 0.5
from exactly where it paused. No restart, no work lost.

Retry logic loops up to 2 times if the post-install detection fails
(common if the user hits a permission dialog or mistypes), then forces
the skip path so nobody ends up stuck. Every prompt branch has a "Cancel
— use fallback" escape so the soft-dependency promise holds end-to-end.

Deferred from prior review

The re-review surfaced one non-blocking observation worth noting on the
record:

The .ps1 block at project-install.ps1:300-303 iterates Get-ChildItem -Recurse and copies each file to $destHtml flat — which will flatten any future presets/ subdirectory on Windows while .sh's cp -R preserves it. Worth fixing in the PR that lands presets/, but no behavior difference today.

Not addressed in this PR per the reviewer's "no scope creep" guidance.
Will be picked up in whichever future PR introduces core/templates/html/presets/.

Ready for the third review pass.

Comment thread .claude/commands/own/init.md Outdated
Comment thread .claude/commands/own/init.md Outdated
DanielPodolsky and others added 2 commits May 28, 2026 16:34
Manual /own:init runtime testing in /tmp/owntest-pr1 surfaced a real
correctness bug that no static review caught. When the user uninstalled
the frontend-design plugin to exercise the install prompt, Phase 0.5
silently bypassed Step 3 entirely and went straight to creating the
.theme/ directory with fallback CSS — while telling the user
"plugin is available so I'll use it for premium styling." The user-
facing claim and the manifest's fallback_mode: true value disagreed
about the same runtime fact, and the install prompt the user actually
wanted to test never appeared.

Root cause was instruction ambiguity in our own prompt: "Run silently:"
above the plugin detection bash command was interpreted as "skip
running the command" rather than "do not narrate the command." Without
the actual bash output, the implementing agent fell back to assuming
the plugin existed (which happened to be the most common case), then
correctly used fallback CSS in Step 5 once it discovered there was no
real signal — but never reconciled the contradictory message it had
already shown the user.

Fixed by adding an EXECUTION CONTRACT block at the top of Phase 0.5
that establishes two non-negotiable rules: (1) every bash command in
the phase MUST be executed via the Bash tool, with branching decisions
driven by the literal stdout, and (2) any user-facing message about
plugin availability MUST match the manifest's fallback_mode value —
the two cannot disagree. Step 1 and Step 2 are rewritten with
imperative "Execute this bash command via the Bash tool" headers and
explicit "do NOT assume" guidance. Step 2's bash command now produces
an unambiguous "plugin:found" / "plugin:missing" marker via
`&& echo / || echo` so the decision input is text-deterministic
rather than empty-string-versus-something.

This is the same category of bug as the prior MAJOR finding on the
shell-vs-slash plugin install — a P3 (Evidence-Based Engineering)
slip where the spec made a confident claim that wasn't backed by an
executed verification. Found by Daniel's own runtime test rather than
the static reviewer, which is exactly what runtime tests exist for.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s seed fallback

Two consecutive rounds of runtime testing in /tmp/owntest-pr1 demonstrated
that the original Phase 0.5 design — programmatically detect the
frontend-design plugin, optionally pause-and-resume for an install
handoff, then invoke the plugin as a Skill mid-flow to generate
theme.css — is not reliably deliverable inside a Claude Code slash
command. Three failure modes converged:

  1. Stale cache directories from prior /plugin uninstall left the
     check command returning "directory exists" even when the plugin
     was effectively gone. Tightening the bash check to use && echo
     "plugin:found" markers didn't help because the cache dir genuinely
     existed.
  2. The implementing agent repeatedly skipped the plugin-detection
     bash command despite explicit EXECUTION CONTRACT instructions to
     run it, defaulting to "plugin probably available" assumptions.
     Even the second round of hardening (Step 2 explicitly imperative,
     "do NOT assume" warnings, deterministic markers) did not produce
     the desired execution behavior.
  3. The agent's own narration in the test runs reported the plugin
     could not be invoked as a Skill mid-flow at all, which makes
     Step 5's "Invoke the frontend-design skill" instruction
     architecturally undeliverable from inside this slash command —
     regardless of whether the plugin is installed.

Rather than continue layering reliability fixes on a fundamentally
fragile mid-flow integration, this commit removes the entire plugin
detection / install / skill-invocation path and replaces it with a
deterministic "always seed the bundled fallback CSS" design. The
fallback CSS was already independently praised by the PR reviewer as
"real engineering taste — token-driven, full light/dark parity, covers
every semantic class," so making it the universal default rather than
a degradation path is honest about what we can actually ship.

Phase 0.5 went from 7 steps and ~190 lines to 4 steps and ~80 lines.
The user-facing summary now ends with a prominent, opt-in upgrade hint
that explains how to install the plugin manually and how /own:theme
regenerates theme.css. This shifts the plugin from "automatic mid-flow
dependency we try to install for you" to "optional polish the user
opts into when they want it" — and stops the slash-command flow from
making confident claims it cannot back up.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude finished @DanielPodolsky's task in 4m 28s —— View job


Claude Code Review — PR #10 (4th pass, post-8da392d)

  • Identify what changed since prior APPROVE (commit 2417cc3)
  • Read the new commits (827c199, 8da392d) and understand the architectural shift
  • Re-evaluate Phase 0.5 against P1/P2/P3/P4 + S/T/D rules
  • Check CHANGELOG / README consistency with the new simplification
  • Post findings and verdict

Re-review summary

Two new commits since the prior APPROVE, and they're connected:

  • 827c199fix(own:init): force Phase 0.5 to actually run bash detection commands — Added an EXECUTION CONTRACT block requiring bash commands to be executed and reconciling claims with manifest state. Found by Daniel's runtime testing in /tmp/owntest-pr1 (a real correctness bug no static review — including mine — had caught).
  • 8da392drefactor(own:init): simplify Phase 0.5 — drop plugin detection, always seed fallback — When the tightened contract also failed runtime testing, the response was the right one: stop building on an unreliable foundation. Phase 0.5 went from 7 steps (~190 lines) to 4 steps (~80 lines). Plugin detection, install handoff, pause-and-resume, retry loop, and mid-flow Skill invocation all removed. Phase 0.5 now seeds the bundled fallback CSS deterministically and surfaces an explicit opt-in upgrade hint pointing at /plugin install … + /own:theme.

The arc from 2417cc3827c1998da392d is textbook P3 (Evidence-Based Engineering) — runtime evidence beat spec confidence, and the spec got reshaped to match what the runtime can actually deliver. See inline praise on init.md:737-750 for the full breakdown.

Findings

Severity Rule Finding
MINOR D2 The CHANGELOG [Unreleased] block still describes the pre-refactor Phase 0.5 ("detects the frontend-design plugin, offers auto-install with explicit user permission, ... generates the project's initial theme.css"). None of that ships after 8da392d. See inline on CHANGELOG.md:15. The PR description's "/own:init hook" table row drifted the same way and is worth refreshing alongside.
PRAISE P3 The whole simplification arc is the cleanest P3 demonstration in this PR. The previous design's load-bearing assumptions (plugin detection reliability, AskUserQuestion pause-and-resume across user-invoked slash commands, mid-flow Skill invocation) were all unverified — and runtime testing in /tmp/owntest-pr1 proved each one wrong. The new design has zero such load-bearing claims. See inline on init.md:737-750.
PRAISE The fact that theme-fallback.css was already engineered to production-quality is what made this retreat honest. Users opting out of the plugin path don't pay a quality penalty — they get the same default they would have gotten via the plugin's "happy path" output, just deterministically. That's compounding engineering investment paying off exactly where it should.
PRAISE D3 Commit body on 8da392d is the right shape: three numbered failure modes, each tied to an empirical observation, with the anti-pattern named explicitly ("rather than continue layering reliability fixes on a fundamentally fragile mid-flow integration"). A junior reading this commit body in six months internalizes runtime testing > spec confidence.

Philosophy re-check

  • P1 (Socratic): Questions removed from Phase 0.5 only because they rested on broken runtime behavior. The teaching flows that worked (Phase -1 profile selection, MCP check) are intact. No regression. ✅
  • P2 (Ownership / Gate 1): Strengthened. The user owns their theme.css (it's the bundled fallback they can edit) and the upgrade path is explicit and consent-gated. ✅
  • P3 (Evidence-Based): Materially improved. All unverified runtime claims removed; remaining bash commands are deterministic and observable. ✅
  • P4 (Universal Audience): Materially improved. All five profiles get production-grade default; power users opt into the plugin via the documented upgrade hint. No profile loses. ✅

Standards re-check

  • S1/S2 (frontmatter, tool minimalism): unchanged, still clean. Phase 0.5 now uses fewer tools, which is a win.
  • S3 (plan-mode warning): unchanged at top of init.md.
  • S4 (cross-references): /own:theme and /plugin install … references both resolve. Soft /own:migrate forward-reference in theme.md still phrased honestly per pass-2 fix.
  • S5 (file paths): ownyourcode/.theme/ and ownyourcode/templates/html/ conventions preserved.
  • T1 (script parity): no changes to install scripts; prior parity holds.
  • T2 (template migration awareness): no template changes; clean.
  • T3 (manifest schema): theme.fallback_mode default flipped to true, which is honest about the post-refactor reality. Additive — no schema break.
  • X1/X2 (security): no new shell-execution surface; deterministic bash with proper quoting.
  • D1 (README sync): /own:theme row at line 118 still correct.
  • D2 (CHANGELOG): stale — see MINOR finding above.
  • D3 (commit pitch): both new commits pass the recruiter-skim test with strong bodies.
  • D4 (learning registry): no learning entries touched.

Verdict

The architectural decision in 8da392d is the right call, and the way Daniel got there — runtime testing surfacing a P3 violation, tightening the contract, watching that fail too, then stepping back to simplify rather than escalating complexity — is exactly the senior judgment this project is supposed to teach. The previous reviews (mine included) approved a design that the runtime didn't actually honor; runtime testing caught what static review missed. That's the entire point of P3.

The CHANGELOG drift is real but a 30-second fix and doesn't block merge — it's a doc sync issue caused by an architectural change, not a correctness problem in the code. Touch up the [Unreleased] block (and ideally the PR body's table row) before merging, and this lands cleanly.

Ship it.

VERDICT: APPROVE
· branch feat/v240-html-foundation

@DanielPodolsky
Copy link
Copy Markdown
Owner Author

🛠️ Phase 0.5 simplification — driven by manual runtime testing

After the prior APPROVE, I ran the full PR test plan locally on macOS + Windows. Test #1 (install) passed cleanly on both platforms. The /own:theme tests all passed. Manual visual validation of theme-fallback.css across all 6 templates in light + dark mode passed.

But the runtime test of /own:init Phase 0.5 surfaced two genuine architectural problems that no static review could have caught:

What runtime testing actually found

  1. Stale plugin cache directories survive /plugin uninstall. After running /plugin uninstall frontend-design, the cache directory ~/.claude/plugins/cache/claude-plugins-official/frontend-design/ still existed (containing only a stub unknown file). Phase 0.5's ls-based detection happily reported "plugin found" while the plugin was effectively gone. Tightening the bash check to && echo "plugin:found" || echo "plugin:missing" didn't help — the directory genuinely existed.

  2. The implementing agent skipped the plugin-detection bash command despite explicit "MUST execute" instructions in a hardening pass (commit 827c199). When pushed even harder with an EXECUTION CONTRACT block at the top of Phase 0.5, the agent still defaulted to "plugin probably available" assumptions on the second test run.

  3. The agent's own narration revealed that frontend-design cannot be invoked as a Skill mid-slash-command flow at all — meaning Step 5's "Invoke the frontend-design skill" instruction was architecturally undeliverable from inside /own:init, regardless of whether the plugin was installed.

The decision

Rather than layer more reliability hardening on a fundamentally fragile design, commit 8da392d drops the entire plugin detection / install / skill-invocation path. Phase 0.5 now deterministically seeds the bundled fallback CSS (which this review independently praised as "real engineering taste — token-driven, full light/dark parity, covers every semantic class") and surfaces a prominent opt-in upgrade hint at the end:

✨ Make it even better (optional, recommended for portfolio work)

For fully custom styling generated from your theme prompt — with Anthropic's official design framework — install the frontend-design plugin yourself in a separate message:

/plugin install frontend-design@claude-plugins-official

Then run /own:theme to regenerate theme.css based on your prompt.

Phase 0.5 went from 7 steps and ~190 lines to 4 steps and ~80 lines. The plugin is now opt-in polish, not an automatic mid-flow dependency.

Commits since the prior APPROVE

Commit What Why
2417cc3 Pause-and-resume plugin install (avoid /own:init restart) UX regression in prior MAJOR fix — already approved
827c199 EXECUTION CONTRACT to force bash detection Runtime test 1 showed agent skipped Step 2
8da392d Drop plugin detection entirely Runtime test 2 showed even hardened detection was unreliable; mid-flow Skill invocation impossible

What I verified locally before this push

Test Result
bash project-install.sh writes templates to a fresh project
pwsh project-install.ps1 writes templates on Windows (via irm | iex from branch URL)
/own:theme 4-action menu with .theme/ present
/own:theme graceful softened message when .theme/ missing
/own:theme --revert graceful "no backups" message
/own:init Phase 0.5 (simplified) — no plugin check, fallback seeded, manifest's fallback_mode: true matches user-facing message
Visual CSS rendering across all 6 templates in light + dark mode ✅ (preview HTML, both modes inspected)

Ready for re-review.

Comment thread CHANGELOG.md Outdated
Comment thread .claude/commands/own/init.md
…d in 8da392d

The [Unreleased] CHANGELOG entry for /own:init Phase 0.5 still described
the original design — programmatic plugin detection, autonomous install
prompt, and theme.css generation via the frontend-design plugin — none
of which actually ship after the 8da392d simplification. Replace that
paragraph with an accurate description of the deterministic
fallback-first design: Phase 0.5 seeds ownyourcode/.theme/ with the
bundled theme prompt and theme-fallback.css unconditionally, then
surfaces an opt-in upgrade hint pointing users to /plugin install
frontend-design@claude-plugins-official followed by /own:theme.

This addresses the D2 finding from the latest CI review pass.

Refs #10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude encountered an error after 1m 21s —— View job


Claude Code Review — PR #10 (5th pass, post-cb4c55b)

  • Identify what changed since prior APPROVE (commit 8da392d)
  • Verify the CHANGELOG drift fix from the prior MINOR finding
  • Confirm no other behavioral changes slipped in
  • Post findings + verdict
· branch `feat/v240-html-foundation`

@claude
Copy link
Copy Markdown

claude Bot commented May 28, 2026

Claude finished @DanielPodolsky's task in 2m 50s —— View job


Claude Code Review — PR #10 (5th pass, post-cb4c55b)

  • Identify what changed since prior APPROVE (commit 8da392d)
  • Verify the CHANGELOG drift fix from the prior MINOR finding
  • Confirm no other behavioral changes slipped in
  • Post findings + verdict

Re-review summary

Single commit since the prior APPROVE: cb4c55b — docs(changelog): sync Phase 0.5 entry to the simplified design shipped in 8da392d. The diff is exactly what the prior pass asked for — a one-line [Unreleased] rewrite of CHANGELOG.md:15, scoped to the D2 finding, with no incidental edits to anything else (git diff 8da392d..HEAD --stat confirms: 1 file, 1 line). Zero scope creep.

The rewritten entry now matches the shipped behavior at .claude/commands/own/init.md:737-820:

CHANGELOG claim init.md reality Match
"inserted between the MCP Check and Detection phases" Phase 0 → Phase 0.5 → Phase 1
"idempotent" Step 1 detects existing .theme/ and skips
"seeds ownyourcode/.theme/ with the bundled theme prompt and theme-fallback.css as the project's initial theme.css" Step 2 cp block does exactly this
"opt-in upgrade hint pointing users to /plugin install frontend-design@… followed by /own:theme" Step 4 message body is verbatim this hint
"deliberately does not attempt programmatic plugin detection or auto-install" Design note at init.md:741-750 confirms
"stale plugin cache directories, no in-flow Skill invocation" Design note cites both failure modes
"plugin-generated styling is a user-driven upgrade, not an automatic mid-flow dependency" Step 4 framing matches exactly

The bonus "runtime testing during PR 1 showed those paths are unreliable" sentence in the CHANGELOG is a nice transparency touch — users (and future contributors) reading release notes can see why the plugin auto-install was dropped, not just that it was. That's the same documentation discipline that made the 8da392d commit body strong.

Standards re-check (delta only)

  • D1 (README sync): /own:theme row at line 118 still correct (verified). ✅
  • D2 (CHANGELOG): Previously stale, now accurate. Closes the prior MINOR finding cleanly. ✅
  • D3 (commit pitch): docs(changelog): sync Phase 0.5 entry to the simplified design shipped in 8da392d — passes the recruiter-skim test: <type>(<scope>): <imperative summary> form, names the referenced commit so a future reader can trace the why. Body explains the drift and what was fixed. ✅
  • All other rules (P1–P4, S1–S5, T1–T3, X1–X2, D4): No changes since the prior APPROVE that affect these. No regression.

Philosophy re-check

No code, command, or behavior changed. All four protocols remain in the state they were in at 8da392d's APPROVE:

  • P1 (Socratic): ✅ unchanged
  • P2 (Ownership / Gate 1): ✅ unchanged
  • P3 (Evidence-Based): ✅ unchanged — and this very PR pass demonstrates P3 working as intended (runtime testing → simplification → CHANGELOG correction → re-review). Every step is anchored to verifiable artifact state.
  • P4 (Universal Audience): ✅ unchanged

Verdict

Daniel responded to the prior pass's one remaining MINOR with a minimal, targeted, accurate doc-sync commit. No drift, no incidental changes, no new findings. The PR train has reached a clean state across all of architecture, code, install scripts, and documentation. Ready to ship.

VERDICT: APPROVE
· branch feat/v240-html-foundation

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