`:
-```astro
-
-```
-
-- [ ] **Step 2: Wire search in `studio.ts`**
-
-Add the import:
-```ts
-import { fuzzyMatch } from './lib/filter';
-```
-Add the function and call it in `init()`:
-```ts
-function wireExplorerSearch() {
- document.querySelectorAll
('[data-explorer-search]').forEach((input) => {
- const scope = input.closest('[data-explorer-root]');
- if (!scope) return;
- const items = [...scope.querySelectorAll('[data-explorer-item]')];
- const apply = () => {
- const q = input.value;
- items.forEach((li) => {
- const name = li.dataset.explorerItem ?? '';
- li.hidden = fuzzyMatch(q, name) === null;
- });
- };
- input.addEventListener('input', apply);
- input.addEventListener('keydown', (e) => {
- if (e.key === 'Enter') {
- const first = items.find((li) => !li.hidden);
- const id = first?.dataset.explorerItem;
- if (id) { location.hash = `#${id}`; input.blur(); }
- }
- });
- });
-}
-```
-Call inside `init()`:
-```ts
- wireExplorerSearch();
-```
-
-- [ ] **Step 3: Build + browser verify**
-
-Run: `bunx astro build` → PASS.
-In dev (desktop), type `comp` in the Explorer search → only `compare` row remains visible; press `Enter` → navigates to `#compare`. Clearing the box restores all rows.
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add src/components/studio/Explorer.astro src/scripts/studio.ts
-git commit -m "feat: live-filter the explorer tree + Enter to jump"
-```
-
----
-
-### Task 13: Final QA pass
-
-**Files:** none (verification + fixes only).
-
-- [ ] **Step 1: Full build**
-
-Run: `bunx astro build`
-Expected: PASS (5 pages), no type errors.
-
-- [ ] **Step 2: Run all unit tests**
-
-Run: `bun test src/scripts/lib/`
-Expected: all PASS (console-copy, export, filter).
-
-- [ ] **Step 3: Browser smoke matrix (dev :4321)**
-
-Verify each row produces an action (no silent click), at 1440px and 390px:
-- Save / BEGIN / SANDBOX / EDIT / IMPORT / Format / Clear / Lines / Query / Monitoring / History / Saved / Charts / Autopilot / Pivot / Diff / Dashboard / newtab(+) / closetab(✕) → console toast appears.
-- RUN, ⌘+Enter → shimmer + `✓ rows` toast. Copy → clipboard + toast. Export → file downloads. Explain → panel toggles. AI / NL2SQL / ⌘K → palette. Docs / README → new tab. Explorer search → filters + Enter jumps.
-- Inert: version, status bar, result-meta, traffic dots → default cursor, no toast.
-
-- [ ] **Step 4: Accessibility + reduced-motion checks**
-
-- Tab to the palette trigger, open with Enter, confirm focus lands in the input, `Esc` restores focus.
-- Confirm toast container is `aria-live="polite"`; redirect controls are `` with text labels.
-- With OS "reduce motion" on, RUN does not animate (no fade).
-
-- [ ] **Step 5: Commit any fixes + final**
-
-```bash
-git add -A
-git commit -m "test: QA pass for interactive controls (build, units, a11y, reduced-motion)"
-```
-
----
-
-## Self-Review (completed by plan author)
-- **Spec coverage:** Every control in spec §9 maps to a task — redirects (Task 5), inert (Task 6), RUN (7), Copy (8), Export (9), Explain (10), palette + AI/NL2SQL (11), Docs/README (anchors in Task 5), search (12). Console mechanism (4), copy map (1), serializers (2), filter (3).
-- **Placeholder scan:** none — every code step has complete code; copy strings are verbatim.
-- **Type consistency:** `studioConsole`, `currentHash`, `sectionById`, `sections`, `serialize`, `Row`, `fuzzyMatch`, `filterItems`, `NOTICES`, `openPalette`, `copyLink`, `exportSection` used consistently across tasks; `data-action` values (`notice|run|copy-link|export|explain|palette`) match between markup (Task 5/7/9/10/11) and dispatch (Tasks 5,7,8,9,10,11).
diff --git a/docs/superpowers/plans/2026-06-23-multipage-studio.md b/docs/superpowers/plans/2026-06-23-multipage-studio.md
deleted file mode 100644
index b59b9b5..0000000
--- a/docs/superpowers/plans/2026-06-23-multipage-studio.md
+++ /dev/null
@@ -1,647 +0,0 @@
-# Multi-Page Studio Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Turn each Explorer "table" into its own real, indexable URL (incl. `/docker-compose-example` as a 9th table), navigated via Astro View Transitions, removing the in-page hash swap — while keeping the IDE shell and all interactions identical.
-
-**Architecture:** Builds on `StudioShell.astro` (single-section shell) from the deploy-unify branch. A single dynamic route `src/pages/[section].astro` generates every non-home section page from a slug manifest; `index.astro` is `/` (home). Explorer links become real URLs. `studio.ts` drops the swap/hash engine and re-wires per navigation via `astro:page-load`. ` ` + `transition:persist` give SPA-smooth navigation with persistent chrome.
-
-**Tech Stack:** Astro 6 (`astro:transitions` ClientRouter, `getStaticPaths`, `astro:components` `Code`), Tailwind v4, TypeScript, `bun:test`. Build: `bunx astro build` (NOT `bun run build`). Dev: `bun run dev` → :4321.
-
-## Global Constraints
-- Homepage model A: `/` = home/hero only; every other section is its own page. No single-scroll landing.
-- Explorer/MobileTopBar section links are REAL URLs (`/`, `/features`, `/deploy`, `/docker-compose-example`), never `/#id`.
-- In-page hash swap REMOVED: no `setActive` section-toggling, no `hashchange`/`popstate` engine in `studio.ts`.
-- `/deploy` and `/docker-compose-example` keep their EXACT current URLs + their structured data (deploy ItemList; docker-compose HowTo + SourceCode) for SEO continuity.
-- Single source: deploy content only in `DeploySection.astro`; docker-compose content only in `DockerComposeSection.astro`.
-- Design tokens only (no raw hex). `text-white` on `bg-primary` buttons is an accepted project-wide convention.
-- View Transitions: chrome (TopBar, Explorer, StatusBar, Console, CommandPalette) uses `transition:persist`; respect `prefers-reduced-motion`.
-- Out of scope (stay standalone, keep Header/Footer): `/privacy-policy`, `404`.
-- Slugs: home→`''`(`/`), features→`features`, databases→`databases`, compare→`compare`, tech_stack→`tech-stack`, get_started→`get-started`, faq→`faq`, deploy→`deploy`, docker_compose→`docker-compose-example`.
-- Verify each task with `bunx astro build` (must pass) + stated checks.
-
-## File Structure
-```
-src/data/sections.ts MOD + slug/pageTitle/pageDescription on 8; + docker_compose (9th) (Task 1)
-src/data/sections.test.ts NEW slug invariants (Task 1)
-src/data/section-seo.ts NEW id → JSON-LD[] (deploy, docker_compose) (Task 1)
-src/components/sections/DockerComposeSection.astro NEW single-source compose content (Task 2)
-src/pages/[section].astro NEW dynamic route for the 8 non-home sections (Task 3)
-src/pages/deploy.astro DEL (Task 3, with route)
-src/pages/docker-compose-example.astro DEL (Task 3, with route)
-src/pages/index.astro MOD home-only single section + home SEO (Task 4)
-src/components/studio/Explorer.astro MOD real-URL links (Task 5)
-src/components/studio/MobileTopBar.astro MOD forward URL link model (Task 5)
-src/scripts/studio.ts MOD drop swap/hash; URL nav; astro:page-load lifecycle; active sync (Task 6)
-src/styles/global.css MOD remove swap display rule; single-section always shown (Task 6)
-src/layouts/Layout.astro MOD add (Task 7)
-src/components/studio/{StudioShell,TopBar,StatusBar,Explorer,Console,CommandPalette}.astro MOD transition:persist (Task 7)
-src/components/Footer.astro, Header.astro MOD internal links → real URLs (Task 8)
-```
-
----
-
-### Task 1: Slug + SEO manifest, docker_compose table, section-seo
-
-**Files:**
-- Modify: `src/data/sections.ts`
-- Create: `src/data/section-seo.ts`
-- Test: `src/data/sections.test.ts`
-
-**Interfaces:**
-- Produces: `SectionMeta` gains `slug: string`, `pageTitle: string`, `pageDescription: string`. A 9th section `docker_compose` is added. `sectionSeo: Record` exports per-section JSON-LD arrays.
-
-- [ ] **Step 1: Write the failing test**
-
-```ts
-// src/data/sections.test.ts
-import { test, expect } from 'bun:test';
-import { sections, sectionById } from './sections';
-
-test('every section has a unique slug; home is empty', () => {
- const slugs = sections.map((s) => s.slug);
- expect(new Set(slugs).size).toBe(slugs.length);
- expect(sectionById['home'].slug).toBe('');
- expect(sectionById['tech_stack'].slug).toBe('tech-stack');
- expect(sectionById['get_started'].slug).toBe('get-started');
- expect(sectionById['docker_compose'].slug).toBe('docker-compose-example');
-});
-
-test('docker_compose table exists with page SEO', () => {
- const d = sectionById['docker_compose'];
- expect(d).toBeDefined();
- expect(d.pageTitle.length).toBeGreaterThan(0);
- expect(d.pageDescription.length).toBeGreaterThan(0);
-});
-
-test('every section has page SEO fields', () => {
- for (const s of sections) {
- expect(typeof s.slug).toBe('string');
- expect(s.pageTitle.length).toBeGreaterThan(0);
- expect(s.pageDescription.length).toBeGreaterThan(0);
- }
-});
-```
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: FAIL (slug/pageTitle undefined; docker_compose missing).
-
-- [ ] **Step 3: Extend `SectionMeta` and every section**
-
-In `src/data/sections.ts`, add to the `SectionMeta` interface:
-```ts
- slug: string; // URL slug ('' = home at '/')
- pageTitle: string; // when this section is its own page
- pageDescription: string;
-```
-Add these three fields to each existing section (verbatim values):
-```
-home: slug: '', pageTitle: 'LibreDB Studio - AI-Powered Open-Source SQL IDE',
- pageDescription: 'LibreDB Studio - The Modern, AI-Powered Open-Source SQL IDE for Cloud-Native Teams'
-features: slug: 'features', pageTitle: 'Features — LibreDB Studio SQL IDE',
- pageDescription: 'Everything you need to master your data: Monaco SQL editor, NL2SQL Copilot, AI query safety, 7+ databases, pro data grid, visual EXPLAIN, ER diagrams, data masking, SSO and more.'
-databases: slug: 'databases', pageTitle: 'Supported Databases — PostgreSQL, MySQL, Oracle, SQL Server, MongoDB, Redis',
- pageDescription: 'One tool, all your databases. Connect to PostgreSQL, MySQL, Oracle, SQL Server, SQLite, MongoDB and Redis through one unified browser-based SQL IDE.'
-compare: slug: 'compare', pageTitle: 'How LibreDB Studio Compares — vs DataGrip, DBeaver, pgAdmin, TablePlus',
- pageDescription: 'See why teams switch to LibreDB Studio: zero-install, mobile, AI-native, SSO and free — compared against DataGrip, DBeaver, pgAdmin and TablePlus.'
-tech_stack: slug: 'tech-stack', pageTitle: 'Tech Stack — LibreDB Studio',
- pageDescription: 'Built with a modern, production-ready stack: Next.js 16, React 19, TypeScript, Tailwind 4, Monaco, TanStack Table, ReactFlow, Gemini/OIDC, Docker and Bun.'
-get_started: slug: 'get-started', pageTitle: 'Get Started in Minutes — LibreDB Studio',
- pageDescription: 'Run LibreDB Studio locally in three steps — clone & install, configure, launch — or one-command Docker. Self-host the open-source AI SQL IDE.'
-faq: slug: 'faq', pageTitle: 'FAQ — LibreDB Studio',
- pageDescription: 'Frequently asked questions about LibreDB Studio: pricing, self-hosting, AI providers, security & SSO, supported databases, and how it compares to legacy tools.'
-deploy: slug: 'deploy', pageTitle: 'Deploy LibreDB Studio Anywhere — One-Click Apps, Helm, Docker & Cloud',
- pageDescription: 'Run the open-source LibreDB Studio SQL IDE anywhere: official Railway and CapRover one-click apps, Docker Hub & GHCR images, a Helm chart on Artifact Hub, npm, and every major open-source PaaS, managed PaaS, and cloud.'
-```
-Add the 9th section to the `sections` array (after `deploy`):
-```ts
- {
- id: 'docker_compose',
- table: 'docker_compose',
- slug: 'docker-compose-example',
- query: 'SELECT variable, default, description FROM env_vars;',
- rows: 21,
- cols: 3,
- execMs: 6,
- columns: [
- { name: 'variable', type: 'VARCHAR' },
- { name: 'default', type: 'VARCHAR' },
- { name: 'description', type: 'TEXT' },
- ],
- explain: 'A copy-paste docker-compose.yml: pulls the published ghcr.io image with every environment variable (auth, OIDC SSO, storage, AI/LLM, seed) — self-host in one command.',
- pageTitle: 'LibreDB Studio Docker Compose Example — Self-Host in Minutes',
- pageDescription: 'Copy-paste docker-compose.example.yml for LibreDB Studio. Run the open-source SQL IDE with one command using the ghcr.io/libredb/libredb-studio image. Includes every environment variable, SQLite/PostgreSQL storage, and OIDC SSO options.',
- },
-```
-
-- [ ] **Step 4: Run test to verify it passes**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: PASS (3 tests).
-
-- [ ] **Step 5: Create `section-seo.ts`**
-
-```ts
-// src/data/section-seo.ts
-// Per-section structured data injected into by the dynamic route.
-import { deployTargets } from './deploy-targets';
-
-const SITE = 'https://libredb.org';
-const REPO = 'https://github.com/libredb/libredb-studio';
-const rawFileURL = `${SITE}/docker-compose.example.yml`;
-
-export const sectionSeo: Record = {
- deploy: [
- {
- '@context': 'https://schema.org',
- '@type': 'ItemList',
- name: 'LibreDB Studio deployment targets',
- about: { '@id': 'https://libredb.org/#application' },
- itemListElement: deployTargets.map((t, i) => ({
- '@type': 'ListItem',
- position: i + 1,
- name: t.name,
- url: t.deployUrl ?? t.docsUrl ?? t.url,
- })),
- },
- ],
- docker_compose: [
- {
- '@context': 'https://schema.org',
- '@type': 'HowTo',
- name: 'Run LibreDB Studio with Docker Compose',
- description: 'Self-host the open-source LibreDB Studio SQL IDE using Docker Compose.',
- totalTime: 'PT5M',
- tool: [{ '@type': 'HowToTool', name: 'Docker' }, { '@type': 'HowToTool', name: 'Docker Compose' }],
- step: [
- { '@type': 'HowToStep', position: 1, name: 'Download the compose file', text: 'Download docker-compose.example.yml and rename it to docker-compose.yml.', url: `${SITE}/docker-compose-example/` },
- { '@type': 'HowToStep', position: 2, name: 'Configure environment', text: 'Set JWT_SECRET (min 32 chars), ADMIN_PASSWORD and USER_PASSWORD in your .env file.', url: `${SITE}/docker-compose-example/` },
- { '@type': 'HowToStep', position: 3, name: 'Start the container', text: 'Run "docker compose up -d" and open http://localhost:3000.', url: `${SITE}/docker-compose-example/` },
- ],
- },
- {
- '@context': 'https://schema.org',
- '@type': 'SoftwareSourceCode',
- name: 'docker-compose.example.yml',
- description: 'Ready-to-use Docker Compose configuration for LibreDB Studio.',
- programmingLanguage: 'YAML',
- codeRepository: REPO,
- url: rawFileURL,
- license: 'https://opensource.org/licenses/MIT',
- about: { '@id': 'https://libredb.org/#application' },
- },
- ],
-};
-```
-
-- [ ] **Step 6: Build + commit**
-
-Run: `bunx astro build` → PASS (5 pages). `bun test src/data/` → all pass.
-```bash
-git add src/data/sections.ts src/data/sections.test.ts src/data/section-seo.ts
-git commit -m "feat: section slugs + page SEO, docker_compose table, per-section JSON-LD"
-```
-
----
-
-### Task 2: `DockerComposeSection.astro` (single source)
-
-**Files:**
-- Create: `src/components/sections/DockerComposeSection.astro`
-
-**Interfaces:**
-- Produces: a self-contained section component rendering the docker-compose content (quick-start + copy, full yml via ``, 5 env-var tables, links row, copy `
-```
-
-- [ ] **Step 5: Rewrite `index.astro` to use `StudioShell`**
-
-Replace the entire body of `src/pages/index.astro` with:
-```astro
----
-import Layout from '../layouts/Layout.astro';
-import StudioShell from '../components/studio/StudioShell.astro';
-import SectionShell from '../components/studio/SectionShell.astro';
-import { sectionById } from '../data/sections';
-
-import HomeSection from '../components/sections/HomeSection.astro';
-import FeaturesSection from '../components/sections/FeaturesSection.astro';
-import DatabasesSection from '../components/sections/DatabasesSection.astro';
-import CompareSection from '../components/sections/CompareSection.astro';
-import TechStackSection from '../components/sections/TechStackSection.astro';
-import GetStartedSection from '../components/sections/GetStartedSection.astro';
-import FaqSection from '../components/sections/FaqSection.astro';
-import DeploySection from '../components/sections/DeploySection.astro';
-
-const s = sectionById;
----
-
-
-
-
-
-
-
-
-
-
-
-
-```
-(Note: the `` now lives in StudioShell, so it is removed from index.astro. The script path in StudioShell is `'../../scripts/studio.ts'` because StudioShell is one directory deeper.)
-
-- [ ] **Step 6: Build + browser verify (homepage unchanged)**
-
-Run: `bunx astro build` → PASS (5 pages).
-In dev (`bun run dev`, :4321), load `/`: the homepage is visually unchanged. Verify the studio still works:
-```js
-// in the browser console
-document.querySelector('[data-studio]').classList.contains('js') // true (script ran)
-document.querySelector('[data-section-link="compare"]').getAttribute('href') // "#compare" (NOT /#compare — homepage is not standalone)
-```
-Click an Explorer item → section swaps; press ⌘/Ctrl+K → palette opens. (No regression from the extraction.)
-
-- [ ] **Step 7: Commit**
-
-```bash
-git add src/components/studio/StudioShell.astro src/components/studio/StatusBar.astro src/components/studio/Explorer.astro src/components/studio/MobileTopBar.astro src/pages/index.astro
-git commit -m "refactor: extract StudioShell; index.astro renders through it"
-```
-
----
-
-### Task 3: `studio.ts` standalone awareness
-
-**Files:**
-- Modify: `src/scripts/studio.ts`
-
-**Interfaces:**
-- Consumes: `[data-studio]` dataset flags `data-initial-active`, `data-standalone` (from StudioShell, Task 2).
-- Behavior: on a standalone page (single section), the section activates on load even with no hash; `setActive` no-ops if the target section is absent; Explorer link clicks navigate (no in-page swap); palette "Jump" navigates to `/#id`.
-
-- [ ] **Step 1: Read the flags**
-
-Near the top of `src/scripts/studio.ts`, just after `const studio = document.querySelector('[data-studio]');`, add:
-```ts
-const standalone = !!studio && studio.hasAttribute('data-standalone');
-const initialActive = studio?.dataset.initialActive || 'home';
-```
-
-- [ ] **Step 2: `setActive` falls back to the page's initial active and bails if the section is absent**
-
-In `setActive`, replace the opening lines. Current:
-```ts
-function setActive(id: string, opts: { scroll?: boolean } = {}) {
- if (!ids.has(id)) id = 'home';
- const meta = sectionById[id];
-```
-Replace with:
-```ts
-function setActive(id: string, opts: { scroll?: boolean } = {}) {
- if (!ids.has(id)) id = initialActive;
- // Focused/standalone pages render a single section; if the requested one
- // isn't in the DOM, keep the current view instead of blanking it.
- if (!document.querySelector(`[data-section="${id}"]`)) return;
- const meta = sectionById[id];
-```
-
-- [ ] **Step 3: `currentHash` defaults to the page's initial active**
-
-Replace:
-```ts
-function currentHash(): string {
- return (location.hash || '#home').slice(1);
-}
-```
-with:
-```ts
-function currentHash(): string {
- return (location.hash || `#${initialActive}`).slice(1);
-}
-```
-
-- [ ] **Step 4: On standalone, let Explorer links navigate (no in-page swap)**
-
-In `onLinkClick`, add a standalone short-circuit at the top. Current:
-```ts
-function onLinkClick(e: Event, id: string) {
- if (isDesktop()) {
-```
-Replace with:
-```ts
-function onLinkClick(e: Event, id: string) {
- if (standalone) { closeDrawer(); return; } // links are /#id → let the browser navigate home
- if (isDesktop()) {
-```
-
-- [ ] **Step 5: Palette "Jump to section" navigates cross-page when standalone**
-
-In the palette `paletteItems()` jump mapping, the jump currently does `location.hash = \`#${s.id}\``. Replace that run body:
-```ts
- run: () => { location.hash = `#${s.id}`; },
-```
-with:
-```ts
- run: () => {
- if (standalone) location.href = `/#${s.id}`;
- else location.hash = `#${s.id}`;
- },
-```
-
-- [ ] **Step 6: Build + browser verify (homepage still fine)**
-
-Run: `bunx astro build` → PASS.
-In dev load `/` (NOT standalone): everything works as before — section swap, palette jump (sets `#section`, stays on page), search. The standalone branches don't fire on the homepage (no `data-standalone`). Confirm:
-```js
-document.querySelector('[data-studio]').hasAttribute('data-standalone') // false on homepage
-```
-
-- [ ] **Step 7: Commit**
-
-```bash
-git add src/scripts/studio.ts
-git commit -m "feat: studio.ts standalone awareness (initial-active, setActive bail, cross-page nav)"
-```
-
----
-
-### Task 4: `DeploySection.astro` becomes the single-source rich content
-
-**Files:**
-- Modify: `src/components/sections/DeploySection.astro`
-
-**Interfaces:**
-- Consumes: `deployTargets`, `starRepos` (`../../data/deploy-targets`), `deployCategories` (`../../data/deploy-categories`), `getStars`/`formatStars` (`../../lib/github-stars`), `PlatformCard` (`../deploy/PlatformCard.astro`), `SectionHeader` (`./SectionHeader.astro`).
-- Produces: the full deploy result content, rendered identically wherever ` ` appears. Includes the build-time `getStars` call and the client `[data-stars-repo]` refresh `
-```
-
-- [ ] **Step 2: Build + browser verify (homepage deploy is now rich)**
-
-Run: `bunx astro build` → PASS (5 pages). (GitHub API 403s during build are expected and fall back to baked-in star counts — not a failure.)
-In dev, open `/#deploy`: the deploy result pane now shows the summary strip, "Official one-click integrations" (Railway/CapRover), the category grids of `PlatformCard`s with star counts, the investor band, and the CTA — the same content `/deploy` used to have. Confirm:
-```js
-document.querySelectorAll('[data-section="deploy"] [data-stars-repo]').length > 0 // PlatformCards rendered
-```
-
-- [ ] **Step 3: Commit**
-
-```bash
-git add src/components/sections/DeploySection.astro
-git commit -m "feat: DeploySection is the single rich source for deploy content"
-```
-
----
-
-### Task 5: Rewrite `deploy.astro` thin (shell-wrapped, single section, SEO preserved)
-
-**Files:**
-- Modify: `src/pages/deploy.astro`
-
-**Interfaces:**
-- Consumes: `StudioShell` (Task 2), `SectionShell`, `DeploySection` (Task 4), `sectionById`, Layout `head` slot (Task 1), `deployTargets` (for ItemList JSON-LD).
-
-- [ ] **Step 1: Replace `deploy.astro` entirely**
-
-Replace the ENTIRE contents of `src/pages/deploy.astro` with:
-```astro
----
-import Layout from '../layouts/Layout.astro';
-import StudioShell from '../components/studio/StudioShell.astro';
-import SectionShell from '../components/studio/SectionShell.astro';
-import DeploySection from '../components/sections/DeploySection.astro';
-import { sectionById } from '../data/sections';
-import { deployTargets } from '../data/deploy-targets';
-
-const title = 'Deploy LibreDB Studio Anywhere — One-Click Apps, Helm, Docker & Cloud';
-const description =
- 'Run the open-source LibreDB Studio SQL IDE anywhere: official Railway and CapRover one-click apps, Docker Hub & GHCR images, a Helm chart on Artifact Hub, npm, and every major open-source PaaS, managed PaaS, and cloud.';
-
-const itemListSchema = {
- '@context': 'https://schema.org',
- '@type': 'ItemList',
- name: 'LibreDB Studio deployment targets',
- about: { '@id': 'https://libredb.org/#application' },
- itemListElement: deployTargets.map((t, i) => ({
- '@type': 'ListItem',
- position: i + 1,
- name: t.name,
- url: t.deployUrl ?? t.docsUrl ?? t.url,
- })),
-};
----
-
-
-
-
-
-
-```
-
-- [ ] **Step 2: Build + browser verify (/deploy in the shell, SEO intact)**
-
-Run: `bunx astro build` → PASS (5 pages, including `/deploy/index.html`).
-Verify the built page keeps its SEO and renders in the shell:
-```bash
-grep -c 'application/ld+json' dist/deploy/index.html # >= 4 (3 global + 1 ItemList)
-grep -o '[^<]* ' dist/deploy/index.html # the deploy title
-grep -c 'data-studio' dist/deploy/index.html # 1 (shell present)
-```
-In dev, open `/deploy`: it renders inside the IDE shell with deploy active (deploy.sql chrome, Explorer with deploy highlighted), showing the same rich `DeploySection`. Confirm standalone nav:
-```js
-document.querySelector('[data-studio]').hasAttribute('data-standalone') // true
-document.querySelector('[data-section-link="features"]').getAttribute('href') // "/#features"
-document.querySelector('.studio-section.is-active')?.id // "deploy"
-```
-Clicking Explorer "features" navigates to `/#features` (homepage, features active). No ``/`` on `/deploy`.
-
-- [ ] **Step 3: Commit**
-
-```bash
-git add src/pages/deploy.astro
-git commit -m "feat: /deploy renders in the IDE shell via DeploySection (single source), SEO preserved"
-```
-
----
-
-### Task 6: QA pass
-
-**Files:** none (verification + fixes only).
-
-- [ ] **Step 1: Full build + sitemap**
-
-Run: `bunx astro build`
-Expected: PASS, 5 pages (`/`, `/deploy`, `/docker-compose-example`, `/privacy-policy`, `404`). Confirm `/deploy` still emitted (not dropped).
-Run: `bun test src/` → still 21/21 pass (no test files changed; sanity that nothing broke imports).
-
-- [ ] **Step 2: Single-source check**
-
-Run: `grep -rl "Official one-click integrations" src/`
-Expected: ONLY `src/components/sections/DeploySection.astro` (the phrase exists in exactly one source file — proves no content duplication).
-
-- [ ] **Step 3: Browser matrix (dev :4321), desktop 1440 + mobile 390**
-
-- `/#deploy` (homepage): rich deploy content in the result pane; other sections still swap; ⌘K palette works; explorer links are `#section` (in-page).
-- `/deploy`: same rich content in the shell, deploy active on load; explorer links are `/#section`; clicking one navigates to the homepage; no Header/Footer.
-- Mobile `/deploy`: stacked, deploy query-card + content; hamburger drawer explorer links are `/#section`.
-- Stars: PlatformCards show counts; investor band shows total.
-- StatusBar on `/deploy` shows `deploy` / its row count (not `home`).
-
-- [ ] **Step 4: Revert any tracked compose mutation (safety)**
-
-Run: `git status --short` — if `src/data/docker-compose.example.yml` or `public/docker-compose.example.yml` show as modified (only happens if `bun run build` was used by mistake), revert them: `git checkout -- '**/docker-compose.example.yml'`. With `bunx astro build` they are untouched.
-
-- [ ] **Step 5: Commit any fixes**
-
-```bash
-git add -A
-git commit -m "test: QA pass for deploy unification (build, single-source, browser matrix)"
-```
-
----
-
-## Self-Review (completed by plan author)
-- **Spec coverage:** Layout head slot (Task 1) ✓; StudioShell + Explorer/MobileTopBar/StatusBar standalone/active props + index adoption (Task 2) ✓; studio.ts standalone awareness — initial-active, setActive bail, link navigate, palette jump (Task 3) ✓; DeploySection single-source rich content + stars + refresh script (Task 4) ✓; thin deploy.astro in shell with SEO + ItemList via head slot (Task 5) ✓; SEO/no-redirect + single-source verification (Tasks 5–6) ✓.
-- **Placeholder scan:** none — every code step is complete and verbatim; no TBD/TODO.
-- **Type/name consistency:** `StudioShell` props `active`/`standalone`; data attributes `data-initial-active`/`data-standalone` read by `studio.ts` as `initialActive`/`standalone`; `Explorer`/`MobileTopBar` `standalone`; `StatusBar` `active`; `DeploySection` exports nothing new (self-contained). Script path `'../../scripts/studio.ts'` correct from `src/components/studio/`. `linkBase` derives from `standalone`. All consistent across tasks.
diff --git a/docs/superpowers/plans/2026-06-27-product-positioning.md b/docs/superpowers/plans/2026-06-27-product-positioning.md
deleted file mode 100644
index 771884d..0000000
--- a/docs/superpowers/plans/2026-06-27-product-positioning.md
+++ /dev/null
@@ -1,1231 +0,0 @@
-# Product Positioning & Website IA Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Turn the single-product (Studio) website into a brand-house site for three products — Studio (hero), the open-source Database engine (`/database` credibility trio), and the commercial Platform (light open-core presence) — without diluting Studio's prominence.
-
-**Architecture:** The site is an Astro static "SQL IDE shell". `src/data/sections.ts` is the single source of truth; `[section].astro` generates a page per section, `Explorer.astro` renders the left tree, and section components under `src/components/sections/` render bodies inside `StudioShell` → `SectionShell`. We add a `schema` grouping layer (`schemas.ts` + a `schema` field on each section), rename `/databases`→`/providers`, add three `database` engine pages, three light Studio↔engine bridges, and a home open-core family block.
-
-**Tech Stack:** Astro 6, Tailwind CSS 4, TypeScript, `bun test` (bun:test runner), `@astrojs/sitemap`.
-
-## Global Constraints
-
-- **Studio stays the hero.** Homepage hero (`HomeSection.astro` headline/CTAs) and primary nav weight are unchanged; new content is secondary/lower.
-- **Database is pre-alpha, community-framed.** No production "Get Started" CTA on engine pages. CTAs are community only: GitHub star, npm, docs.
-- **Platform is light.** A lean internal `/platform` overview page (narrative) whose CTA opens the live app; no pricing page on-site. (Revised mid-execution from external-link-only — see the spec's Platform section.) External links use `target="_blank" rel="noopener noreferrer"`.
-- **Engine repo URLs (verbatim):** GitHub `https://github.com/libredb/libredb-database`; npm `https://www.npmjs.com/package/@libredb/libredb`; guides `https://github.com/libredb/libredb-database/tree/main/docs/guides`.
-- **Platform URL (verbatim):** `https://platform.libredb.org` (live, beta).
-- **Engine facts must stay honest** (sourced from the engine repo): pre-alpha `0.0.x`; one ordered key-value core + three lenses (kv/document/relational); zero runtime dependencies; ~712 lines of shipped code; `core.ts` under 600 lines; 2.83 kB bundled (min+brotli, 4 kB CI budget); 100% core line coverage; deterministic simulation testing; O(n) scans / no secondary indexes / single-process / RAM-bounded in v1.
-- **Preserve Explorer data hooks.** Keep `data-explorer-item`, `data-explorer-toggle`, `data-explorer-cols`, `data-section-link`, `data-explorer-search` attributes intact (wired by `src/scripts/studio.ts`).
-- **Per-task build check:** run `bunx astro build` (NOT `bun run build`) to verify compilation without triggering the docker-compose sync step that mutates tracked files. Tests: `bun test src/data/`.
-- **Responsive:** wide content (code blocks, tables) must scroll inside `overflow-x-auto`; never break the page's horizontal layout.
-
----
-
-### Task 1: Schema data model foundation
-
-**Files:**
-- Create: `src/data/schemas.ts`
-- Modify: `src/data/sections.ts` (interface + add `schema: 'studio'` to all 9 sections)
-- Test: `src/data/sections.test.ts`
-
-**Interfaces:**
-- Produces: `SchemaMeta` interface and `schemas: SchemaMeta[]` (ids `'studio' | 'database' | 'platform'`); `SectionMeta` gains required field `schema: 'studio' | 'database'`.
-- Consumes: nothing (first task).
-
-- [ ] **Step 1: Write the failing test**
-
-Add to `src/data/sections.test.ts`:
-
-```ts
-import { schemas } from './schemas';
-
-test('every section declares a schema of studio or database', () => {
- for (const s of sections) {
- expect(['studio', 'database']).toContain(s.schema);
- }
-});
-
-test('all existing (non-database) sections are schema "studio"', () => {
- const studioIds = ['home', 'features', 'compare', 'tech_stack', 'get_started', 'faq', 'deploy', 'docker_compose'];
- for (const id of studioIds) {
- expect(sectionById[id].schema).toBe('studio');
- }
-});
-
-test('schemas manifest has studio, database, platform in order', () => {
- expect(schemas.map((s) => s.id)).toEqual(['studio', 'database', 'platform']);
- const platform = schemas.find((s) => s.id === 'platform');
- expect(platform?.external?.href).toBe('https://platform.libredb.org');
-});
-```
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: FAIL — `Cannot find module './schemas'` (and `schema` undefined).
-
-- [ ] **Step 3: Create `src/data/schemas.ts`**
-
-```ts
-// src/data/schemas.ts
-// Schema grouping for the Explorer tree. One connection (libredb.org), three
-// schemas: studio (production hero), database (pre-alpha engine), platform
-// (commercial, external). Sections belong to studio or database; platform has
-// no internal sections — only an external link.
-
-export interface SchemaMeta {
- id: 'studio' | 'database' | 'platform';
- label: string; // tree heading
- badge?: string; // e.g. "pre-alpha", "beta · teams"
- badgeClass?: string; // styling hook (Tailwind classes)
- external?: { label: string; href: string }; // platform: link row, no section
-}
-
-export const schemas: SchemaMeta[] = [
- { id: 'studio', label: 'studio' },
- {
- id: 'database',
- label: 'database',
- badge: '🧪 pre-alpha',
- badgeClass: 'text-warn border border-warn/40',
- },
- {
- id: 'platform',
- label: 'platform',
- badge: 'beta · teams',
- badgeClass: 'text-ai border border-ai/40',
- external: { label: 'overview', href: 'https://platform.libredb.org' },
- },
-];
-```
-
-- [ ] **Step 4: Add `schema` to the `SectionMeta` interface**
-
-In `src/data/sections.ts`, add to the `SectionMeta` interface (after `pageDescription: string;`):
-
-```ts
- pageDescription: string;
- schema: 'studio' | 'database'; // Explorer grouping; platform has no sections
-```
-
-- [ ] **Step 5: Add `schema: 'studio'` to all 9 existing sections**
-
-In `src/data/sections.ts`, add the line `schema: 'studio',` to each of these section objects (one line per object): `home`, `features`, `databases`, `compare`, `tech_stack`, `get_started`, `faq`, `deploy`, `docker_compose`. Example for `home`:
-
-```ts
- slug: '',
- pageTitle: 'LibreDB Studio - AI-Powered Open-Source SQL IDE',
- pageDescription: 'LibreDB Studio - The Modern, AI-Powered Open-Source SQL IDE for Cloud-Native Teams',
- schema: 'studio',
- },
-```
-
-- [ ] **Step 6: Run tests to verify they pass**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: PASS (all tests, including the 3 new ones). The "every section declares a schema" test fails loudly if any of the 9 was missed.
-
-- [ ] **Step 7: Commit**
-
-```bash
-git add src/data/schemas.ts src/data/sections.ts src/data/sections.test.ts
-git commit -m "feat: add schema grouping data model (studio/database/platform)"
-```
-
----
-
-### Task 2: Rename `/databases` → `/providers`
-
-**Files:**
-- Modify: `src/data/sections.ts` (the `databases` section)
-- Rename: `src/components/sections/DatabasesSection.astro` → `src/components/sections/ProvidersSection.astro`
-- Modify: `src/pages/[section].astro` (import + COMPONENTS key)
-- Modify: `astro.config.mjs` (301 redirect)
-- Test: `src/data/sections.test.ts`
-
-**Interfaces:**
-- Consumes: `SectionMeta.schema` (Task 1).
-- Produces: section id `'providers'`, slug `'providers'`; route `/providers`; redirect `/databases → /providers`.
-
-- [ ] **Step 1: Write the failing test**
-
-Add to `src/data/sections.test.ts`:
-
-```ts
-test('providers section replaces databases (id, slug, table)', () => {
- expect(sectionById['databases']).toBeUndefined();
- const p = sectionById['providers'];
- expect(p).toBeDefined();
- expect(p.slug).toBe('providers');
- expect(p.table).toBe('providers');
- expect(p.schema).toBe('studio');
-});
-```
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: FAIL — `sectionById['providers']` is undefined; `databases` still defined.
-
-- [ ] **Step 3: Rename the section in `src/data/sections.ts`**
-
-Replace the entire `databases` section object with:
-
-```ts
- {
- id: 'providers',
- table: 'providers',
- query: 'SELECT name, type, driver FROM providers;',
- rows: 7,
- cols: 3,
- execMs: 2,
- columns: [
- { name: 'name', type: 'VARCHAR' },
- { name: 'type', type: 'VARCHAR' },
- { name: 'driver', type: 'VARCHAR' },
- ],
- explain: 'The database engines LibreDB Studio connects to — PostgreSQL, MySQL, Oracle, SQL Server, SQLite, MongoDB, Redis — behind one unified interface, plus LibreDB, our own embedded engine.',
- slug: 'providers',
- pageTitle: 'Supported Providers — PostgreSQL, MySQL, Oracle, SQL Server, MongoDB, Redis & LibreDB',
- pageDescription: 'One tool, all your databases. Connect LibreDB Studio to PostgreSQL, MySQL, Oracle, SQL Server, SQLite, MongoDB and Redis — plus LibreDB, our own open-source embedded engine — through one unified browser-based SQL IDE.',
- schema: 'studio',
- },
-```
-
-- [ ] **Step 4: Rename the component file**
-
-```bash
-git mv src/components/sections/DatabasesSection.astro src/components/sections/ProvidersSection.astro
-```
-
-- [ ] **Step 5: Update `src/pages/[section].astro`**
-
-Change the import line:
-
-```astro
-import ProvidersSection from '../components/sections/ProvidersSection.astro';
-```
-
-Change the `COMPONENTS` map key (remove `databases`, add `providers`):
-
-```ts
-const COMPONENTS: Record = {
- features: FeaturesSection,
- providers: ProvidersSection,
- compare: CompareSection,
- tech_stack: TechStackSection,
- get_started: GetStartedSection,
- faq: FaqSection,
- deploy: DeploySection,
- docker_compose: DockerComposeSection,
-};
-```
-
-- [ ] **Step 6: Add the 301 redirect in `astro.config.mjs`**
-
-Add a `redirects` key to the `defineConfig` object (after `site:`):
-
-```js
-export default defineConfig({
- site: 'https://libredb.org',
- redirects: {
- '/databases': '/providers',
- },
- integrations: [sitemap({
- lastmod: new Date(),
- })],
-```
-
-- [ ] **Step 7: Run tests and build**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: PASS.
-Run: `bunx astro build`
-Expected: build succeeds; `dist/providers/index.html` exists; `dist/databases/index.html` is a redirect page pointing to `/providers`.
-
-Verify the redirect file:
-Run: `grep -l "providers" dist/databases/index.html`
-Expected: matches (redirect target present).
-
-- [ ] **Step 8: Commit**
-
-```bash
-git add src/data/sections.ts src/components/sections/ProvidersSection.astro src/pages/[section].astro astro.config.mjs src/data/sections.test.ts
-git commit -m "feat: rename /databases to /providers with 301 redirect"
-```
-
----
-
-### Task 3: Add LibreDB as a native provider (Usage B bridge)
-
-**Files:**
-- Modify: `src/components/sections/ProvidersSection.astro` (add 8th provider card)
-- Modify: `src/data/sections.ts` (providers `rows` 7→8, explain unchanged from Task 2)
-
-**Interfaces:**
-- Consumes: `ProvidersSection.astro` (Task 2).
-- Produces: nothing downstream.
-
-- [ ] **Step 1: Add the LibreDB entry to the `databases` array in `ProvidersSection.astro`**
-
-Append this object as the last item of the `databases: DB[]` array (after Redis):
-
-```ts
- { name: 'LibreDB', type: 'embedded · our own', driver: '@libredb/libredb', color: 'text-ai', summary: 'Our own open-source embedded engine. Open a .libredb file directly — no server. Browse relational, document, and key-value lenses; query with a small get / put / prefix / range grammar (not SQL). Ships as a ready-to-use sample on first launch.' },
-```
-
-- [ ] **Step 2: Make the LibreDB card link to `/database`**
-
-In `ProvidersSection.astro`, the cards are rendered by `{databases.map((d) => (...))}`. Replace the `` block so the LibreDB card links to the engine page while others stay static. Change the map body to:
-
-```astro
- {databases.map((d) => (
-
-
-
- {d.name === 'LibreDB'
- ? {d.name} →
- : d.name}
-
-
{d.type} · {d.driver}
-
- {d.summary}
-
- ))}
-```
-
-- [ ] **Step 3: Bump the providers row count in `src/data/sections.ts`**
-
-In the `providers` section, change `rows: 7,` to `rows: 8,`.
-
-- [ ] **Step 4: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds. `dist/providers/index.html` contains "LibreDB" and the `/database` link.
-Run: `grep -c 'href="/database"' dist/providers/index.html`
-Expected: ≥ 1.
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add src/components/sections/ProvidersSection.astro src/data/sections.ts
-git commit -m "feat: list LibreDB as a native embedded provider on /providers"
-```
-
----
-
-### Task 4: Database engine sections data
-
-**Files:**
-- Modify: `src/data/sections.ts` (add 3 `database` sections)
-- Test: `src/data/sections.test.ts`
-
-**Interfaces:**
-- Consumes: `SectionMeta.schema` (Task 1).
-- Produces: section ids `'database'` (slug `database`), `'database_architecture'` (slug `database-architecture`), `'database_reliability'` (slug `database-reliability`), all `schema: 'database'`. These ids must have COMPONENTS entries (Tasks 5–7).
-
-- [ ] **Step 1: Write the failing test**
-
-Add to `src/data/sections.test.ts`:
-
-```ts
-test('three database-schema sections exist with correct slugs', () => {
- const dbSections = sections.filter((s) => s.schema === 'database');
- expect(dbSections.map((s) => s.id).sort()).toEqual(
- ['database', 'database_architecture', 'database_reliability'].sort(),
- );
- expect(sectionById['database'].slug).toBe('database');
- expect(sectionById['database_architecture'].slug).toBe('database-architecture');
- expect(sectionById['database_reliability'].slug).toBe('database-reliability');
-});
-```
-
-- [ ] **Step 2: Run test to verify it fails**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: FAIL — database sections undefined.
-
-- [ ] **Step 3: Append the 3 sections in `src/data/sections.ts`**
-
-Add these objects to the `sections` array, immediately after the `providers` section object (so the Explorer renders them in order):
-
-```ts
- {
- id: 'database',
- table: 'manifesto',
- query: 'SELECT principle, stance FROM manifesto;',
- rows: 6,
- cols: 2,
- execMs: 2,
- columns: [
- { name: 'principle', type: 'TEXT' },
- { name: 'stance', type: 'TEXT' },
- ],
- explain: 'The LibreDB engine manifesto: a small, readable, embeddable multi-model database you can read in one sitting — multi-model without the magic. Pre-alpha; community-driven.',
- slug: 'database',
- pageTitle: 'LibreDB — the embedded, multimodal database you can read in one sitting',
- pageDescription: 'LibreDB is a small, readable, embeddable, multi-model database in TypeScript. One ordered key-value core, three lenses (key-value, document, relational), zero dependencies, every line tested. Open source (MIT), pre-alpha.',
- schema: 'database',
- },
- {
- id: 'database_architecture',
- table: 'architecture',
- query: 'SELECT layer, role FROM architecture;',
- rows: 3,
- cols: 2,
- execMs: 3,
- columns: [
- { name: 'layer', type: 'TEXT' },
- { name: 'role', type: 'TEXT' },
- ],
- explain: 'How LibreDB works: one ordered byte key-value kernel with thin kv/document/relational lenses on top (FoundationDB pattern). The file boundary is the trust boundary, and the write-ahead log is the database.',
- slug: 'database-architecture',
- pageTitle: 'Architecture — LibreDB: one core, three lenses',
- pageDescription: 'Inside LibreDB: a single ordered key-value kernel with thin key-value, document, and relational lenses on top. The file boundary is the trust boundary; the write-ahead log is the only on-disk representation.',
- schema: 'database',
- },
- {
- id: 'database_reliability',
- table: 'reliability',
- query: 'SELECT guarantee, mechanism FROM reliability ORDER BY guarantee;',
- rows: 4,
- cols: 2,
- execMs: 4,
- columns: [
- { name: 'guarantee', type: 'TEXT' },
- { name: 'mechanism', type: 'TEXT' },
- ],
- explain: 'Why you can trust a pre-alpha engine: a CRC-32 checksummed, fsync-before-commit write-ahead log, crash recovery proven by deterministic simulation testing, 100% core line coverage — plus an honest list of what it deliberately is NOT yet.',
- slug: 'database-reliability',
- pageTitle: 'Reliability — LibreDB crash recovery & deterministic simulation testing',
- pageDescription: 'LibreDB durability: a length-framed, CRC-32 checksummed write-ahead log fsync-d before commit, crash recovery proven by deterministic simulation testing, and 100% core line coverage. Honest about its v1 limits.',
- schema: 'database',
- },
-```
-
-- [ ] **Step 4: Run test to verify it passes**
-
-Run: `bun test src/data/sections.test.ts`
-Expected: PASS for the new test. NOTE: `bunx astro build` will still FAIL until Tasks 5–7 add COMPONENTS entries — that is expected; do not build yet.
-
-- [ ] **Step 5: Commit**
-
-```bash
-git add src/data/sections.ts src/data/sections.test.ts
-git commit -m "feat: add database engine sections data (manifesto, architecture, reliability)"
-```
-
----
-
-### Task 5: Database manifesto page + shared CTA footer
-
-**Files:**
-- Create: `src/components/sections/DatabaseCtaFooter.astro` (shared by Tasks 5–7)
-- Create: `src/components/sections/DatabaseSection.astro`
-- Modify: `src/pages/[section].astro` (import + COMPONENTS key `database`)
-- Modify: `src/data/section-seo.ts` (JSON-LD for `database`)
-
-**Interfaces:**
-- Consumes: section id `'database'` (Task 4); `SectionHeader.astro` (existing).
-- Produces: `DatabaseCtaFooter.astro` (no props) reused by architecture & reliability pages; COMPONENTS entry `database`.
-
-- [ ] **Step 1: Create the shared CTA footer `src/components/sections/DatabaseCtaFooter.astro`**
-
-```astro
----
-// Shared honest status box + community CTAs for all three /database pages.
-// Community framing ONLY — no production "Get Started".
-const GH = 'https://github.com/libredb/libredb-database';
-const NPM = 'https://www.npmjs.com/package/@libredb/libredb';
-const DOCS = 'https://github.com/libredb/libredb-database/tree/main/docs/guides';
----
-
-
- 🧪 Pre-alpha — not production ready
-
-
- LibreDB is early (0.0.x). The architecture is in place and every line
- of the core is tested, but the API may still change and it is not yet meant for production data.
- Star it, follow along, and help shape it.
-
-
-
-```
-
-- [ ] **Step 2: Create `src/components/sections/DatabaseSection.astro`**
-
-```astro
----
-import SectionHeader from './SectionHeader.astro';
-import DatabaseCtaFooter from './DatabaseCtaFooter.astro';
-
-const principles = [
- { name: 'Simple', stance: 'Against the database experience that forces you into a giant ORM, an admin panel, and a vendor ecosystem just to manage your own data. Not at war with ORMs — at war with being forced into one.' },
- { name: 'No magic', stance: 'The query is visible. The schema is visible. Errors are not hidden. Plans are explained. No unnecessary veil between data and developer.' },
- { name: 'Readable', stance: 'Small enough to read in one sitting. The kernel is under 600 lines. Readability is not marketing — it is a design constraint.' },
- { name: 'Embeddable', stance: 'bun add @libredb/libredb and go. Zero runtime dependencies, in-process, nothing else to install or run.' },
- { name: 'Multi-model', stance: 'One ordered key-value core; key-value, document, and relational are thin lenses over it — not three engines bolted together.' },
- { name: 'Reliable', stance: 'Readable does not mean toy. Every line of the core is tested; crash recovery is proven by deterministic simulation testing.' },
-];
----
-
-
-
- 🧪 Pre-alpha · open source (MIT)
-
-
-
-
-
- Multi-model without the magic.
- One core, three lenses, every line tested. A small, readable, embeddable database in TypeScript —
- built on one idea: a database can be powerful and still be understood by opening its source.
-
-
-
-
-
- Competes with the database textbook and the “I’ll just use a Map for now” hack —
- not with Postgres.
-
-
The database you read, learn from, hack on, and embed fast.
-
-
-
-
-
-
- {principles.map((p) => (
-
- {p.name}
- {p.stance}
-
- ))}
-
-
-
-
-
-
-
-
{`bun add @libredb/libredb
-
-import { open, kv, doc, table } from "@libredb/libredb";
-
-// In-memory for tests, or open({ path: "data.libredb" }) for a durable file.
-const db = open();
-
-// 1. Key-value — a durable, ordered, string-keyed map.
-kv(db).set("user:1", "Ada");
-
-// 2. Document — a collection of JSON documents.
-doc(db, "logs").put("l1", { level: "info", at: 1 });
-
-// 3. Relational — a schema-validated, typed table.
-const users = table(db, "users", {
- primaryKey: "id",
- columns: { id: "string", name: "string", age: "number" },
-});
-users.insert({ id: "1", name: "Ada", age: 36 });
-users.where({ name: "Ada" }).select("id", "age").toArray();`}
-
-
-
-
-
-
One core, three faces
-
- LibreDB Database is the plain core of data.
- LibreDB Studio is the understandable face of data.
- LibreDB Platform is the manageable form of data for teams.
- All three speak the same spine.
-
-
- Want to see it live? LibreDB Studio opens with a
- ready-to-use LibreDB sample — all three lenses, zero setup.
-
-
-
-
-
-```
-
-- [ ] **Step 3: Wire the component into `src/pages/[section].astro`**
-
-Add the import:
-
-```astro
-import DatabaseSection from '../components/sections/DatabaseSection.astro';
-```
-
-Add to the `COMPONENTS` map:
-
-```ts
- database: DatabaseSection,
-```
-
-- [ ] **Step 4: Add JSON-LD for the manifesto page in `src/data/section-seo.ts`**
-
-Add a `database` key to the `sectionSeo` object (alongside `deploy` and `docker_compose`):
-
-```ts
- database: [
- {
- '@context': 'https://schema.org',
- '@type': 'SoftwareSourceCode',
- name: 'LibreDB',
- description: 'A small, readable, embeddable, multi-model database in TypeScript. One ordered key-value core, three lenses, zero dependencies, every line tested.',
- programmingLanguage: 'TypeScript',
- codeRepository: 'https://github.com/libredb/libredb-database',
- license: 'https://opensource.org/licenses/MIT',
- },
- {
- '@context': 'https://schema.org',
- '@type': 'SoftwareApplication',
- name: 'LibreDB',
- applicationCategory: 'DeveloperApplication',
- operatingSystem: 'Cross-platform (Bun, Node 22+)',
- offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
- softwareVersion: 'pre-alpha (0.0.x)',
- },
- ],
-```
-
-- [ ] **Step 5: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/database/index.html` exists and contains "Multi-model without the magic" and the JSON-LD `SoftwareSourceCode`.
-Run: `grep -c 'SoftwareSourceCode' dist/database/index.html`
-Expected: ≥ 1.
-
-- [ ] **Step 6: Commit**
-
-```bash
-git add src/components/sections/DatabaseCtaFooter.astro src/components/sections/DatabaseSection.astro src/pages/[section].astro src/data/section-seo.ts
-git commit -m "feat: add /database manifesto page with embed snippet and community CTAs"
-```
-
----
-
-### Task 6: Database architecture page
-
-**Files:**
-- Create: `src/components/sections/DatabaseArchitectureSection.astro`
-- Modify: `src/pages/[section].astro` (import + COMPONENTS key `database_architecture`)
-
-**Interfaces:**
-- Consumes: section id `'database_architecture'` (Task 4); `DatabaseCtaFooter.astro` (Task 5); `SectionHeader.astro`.
-
-- [ ] **Step 1: Create `src/components/sections/DatabaseArchitectureSection.astro`**
-
-```astro
----
-import SectionHeader from './SectionHeader.astro';
-import DatabaseCtaFooter from './DatabaseCtaFooter.astro';
-
-const lenses = [
- { name: 'kv', tag: 'the proof', desc: 'The ordered key-value core, usable directly. A durable, ordered, string-keyed map — the thinnest possible lens.' },
- { name: 'document', tag: 'the differentiator', desc: 'Collections of JSON documents under string ids, with by-id CRUD and an in-engine find() predicate.' },
- { name: 'relational', tag: 'the reach', desc: 'Schema-validated typed tables with where / select / join — a relational view, deliberately not a SQL engine.' },
-];
----
-
-
-
-
-
- {lenses.map((l) => (
-
-
-
{l.name}
- {l.tag}
-
- {l.desc}
-
- ))}
-
-
-
-
-
{` kv document relational ← lenses (open edge)
- \\ | /
- \\ | /
- +--------+----------+
- | one narrow transact() port
- ============|===================== TRUST BOUNDARY
- |
- core.ts ← the kernel (guarded)
- ordered KV · txns · WAL · recovery
- |
- FileSystem seam (node:fs, or SimFS for crash tests)`}
-
-
-
-
-
-
-
- Below the line — guarded
-
- core.ts is where data can be corrupted, so every line passes heavy review
- and deterministic crash tests. It stays small because it is genuinely minimal.
-
-
-
- Above the line — open
-
- Lenses, query surface, and catalog are open and fast to contribute to — the worst a bug can do is present
- a bad view; it reaches the store only through one narrow port.
-
-
-
-
-
-
-
-
The WAL is the database
-
- Most databases keep a write-ahead log separate from data files. LibreDB does not: the file you open
- is the sequence of every committed transaction, replayed into an in-memory sorted array on open.
- No separate data file, no buffer pool — the same lineage as Redis AOF mode. Two boxes instead of three,
- which is how the kernel stays small enough to understand.
-
-
-
-
-
-```
-
-- [ ] **Step 2: Wire into `src/pages/[section].astro`**
-
-Add the import:
-
-```astro
-import DatabaseArchitectureSection from '../components/sections/DatabaseArchitectureSection.astro';
-```
-
-Add to the `COMPONENTS` map:
-
-```ts
- database_architecture: DatabaseArchitectureSection,
-```
-
-- [ ] **Step 3: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/database-architecture/index.html` exists and contains "One core, three lenses".
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add src/components/sections/DatabaseArchitectureSection.astro src/pages/[section].astro
-git commit -m "feat: add /database-architecture page (one core, three lenses)"
-```
-
----
-
-### Task 7: Database reliability page
-
-**Files:**
-- Create: `src/components/sections/DatabaseReliabilitySection.astro`
-- Modify: `src/pages/[section].astro` (import + COMPONENTS key `database_reliability`)
-
-**Interfaces:**
-- Consumes: section id `'database_reliability'` (Task 4); `DatabaseCtaFooter.astro` (Task 5); `SectionHeader.astro`.
-
-- [ ] **Step 1: Create `src/components/sections/DatabaseReliabilitySection.astro`**
-
-```astro
----
-import SectionHeader from './SectionHeader.astro';
-import DatabaseCtaFooter from './DatabaseCtaFooter.astro';
-
-const numbers = [
- { n: '~712', l: 'lines of shipped code', cls: 'text-primary' },
- { n: '0', l: 'runtime dependencies', cls: 'text-ok' },
- { n: '2.83 kB', l: 'bundled (min+brotli)', cls: 'text-ai' },
- { n: '100%', l: 'core line coverage', cls: 'text-warn' },
-];
-
-const notForYet = [
- { area: 'Production at scale', why: 'It is pre-alpha; today’s beachhead is test/dev.' },
- { area: 'Secondary indexes / planner', why: 'Queries are O(n) scans by design in v1 (on the roadmap).' },
- { area: 'Concurrent / networked access', why: 'It is embedded and single-process — no replication or client/server.' },
- { area: 'SQL wire compatibility', why: 'No SQL text, no existing-driver ecosystem — a relational view, not a SQL engine.' },
-];
----
-
-
-
-
-
- {numbers.map((s, i) => (
-
- ))}
-
-
-
-
-
- A write-ahead log, fsync-d before commit
-
- A transaction that returns has been written to a length-framed, CRC-32 checksummed log and fsync-d
- before the commit becomes visible. A crash can only ever damage the last, un-fsync-d record —
- which recovery detects and truncates, leaving a valid committed prefix.
-
-
-
- Deterministic simulation testing
-
- The crash/recovery path is proven by running the real engine against a seeded in-memory filesystem that
- tears, corrupts, and crashes the log on command — then checking that recovery is always a valid committed
- prefix. The FoundationDB-style approach that keeps the durability claims honest.
-
-
-
-
-
-
-
-
-
-
-
- You need…
- Why not yet
-
-
-
- {notForYet.map((r) => (
-
- {r.area}
- {r.why}
-
- ))}
-
-
-
-
-
-
-
-```
-
-- [ ] **Step 2: Wire into `src/pages/[section].astro`**
-
-Add the import:
-
-```astro
-import DatabaseReliabilitySection from '../components/sections/DatabaseReliabilitySection.astro';
-```
-
-Add to the `COMPONENTS` map:
-
-```ts
- database_reliability: DatabaseReliabilitySection,
-```
-
-- [ ] **Step 3: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/database-reliability/index.html` exists and contains "Crash recovery you can trust". All four database/provider routes now build.
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add src/components/sections/DatabaseReliabilitySection.astro src/pages/[section].astro
-git commit -m "feat: add /database-reliability page (DST, durability, honest limits)"
-```
-
----
-
-### Task 8: Explorer schema grouping
-
-**Files:**
-- Modify: `src/components/studio/Explorer.astro`
-
-**Interfaces:**
-- Consumes: `schemas` (Task 1), `sections` with `schema` field (Task 1/4).
-- Produces: a three-schema grouped tree. Preserves all `data-*` hooks.
-
-- [ ] **Step 1: Update the imports in `Explorer.astro` frontmatter**
-
-Replace the frontmatter import block with:
-
-```astro
----
-import { sections } from '../../data/sections';
-import { schemas } from '../../data/schemas';
-
-interface Props {
- active?: string;
- idPrefix?: string; // to keep ids unique between desktop sidebar & mobile drawer
- showConnectionsLabel?: boolean;
-}
-const { active = 'home', idPrefix = 'exp', showConnectionsLabel = true } = Astro.props;
-const internalCount = sections.length; // total internal sections across schemas
----
-```
-
-- [ ] **Step 2: Replace the `` tree block**
-
-Replace the entire `... ` element with the following (this preserves every `data-*` hook and the column sub-lists, and adds per-schema headings + badges + the platform external row):
-
-```astro
-
-
- {schemas.map((schema) => (
-
-
- ▾ ▦
- {schema.label}
- {schema.badge && (
-
- {schema.badge}
-
- )}
-
-
- {schema.external ? (
-
- ) : (
-
- {sections.filter((s) => s.schema === schema.id).map((s) => (
-
-
-
- {s.columns.map((c) => (
-
-
- ◆ {c.name}
-
- {c.type}
-
- ))}
-
-
- ))}
-
- )}
-
- ))}
-
-```
-
-- [ ] **Step 3: Update the Explorer header count badge**
-
-The header badge currently reads `{sections.length}`. Leave it as `{internalCount}` (defined in Step 1, same value — total internal sections). Replace `{sections.length}` with `{internalCount}` in the "Explorer header" block.
-
-- [ ] **Step 4: Verify build and that search hooks survive**
-
-Run: `bunx astro build`
-Expected: build succeeds.
-Run: `grep -c 'data-explorer-item' dist/index.html`
-Expected: ≥ 11 (9 studio + 3 database = 12 items appear twice — desktop + mobile drawer — so expect ≥ 22; any value ≥ 11 confirms the hooks render).
-Run: `grep -c 'platform.libredb.org' dist/index.html`
-Expected: ≥ 1 (external row present).
-
-- [ ] **Step 5: Manual smoke check (dev server)**
-
-Run: `bunx astro dev` and open `http://localhost:4321/`. Confirm: three schema headings (studio, database 🧪 pre-alpha, platform beta · teams); database group lists manifesto/architecture/reliability; platform row opens `platform.libredb.org` in a new tab; the explorer search box still filters items; caret toggles still expand column lists. Stop the server when done.
-
-- [ ] **Step 6: Commit**
-
-```bash
-git add src/components/studio/Explorer.astro
-git commit -m "feat: group Explorer tree by schema (studio/database/platform)"
-```
-
----
-
-### Task 9: Home open-core family block + sample teaser
-
-**Files:**
-- Modify: `src/components/sections/HomeSection.astro`
-
-**Interfaces:**
-- Consumes: nothing new. Adds a secondary block below the existing hero (hero unchanged — Global Constraint).
-
-- [ ] **Step 1: Add the family block to `HomeSection.astro`**
-
-In `HomeSection.astro`, insert this block immediately BEFORE the closing ` ` of the outer `
` wrapper (i.e. after the "Hint" `
` and before the final `
`). Do NOT modify the headline, subtitle, CTAs, or stats above it.
-
-```astro
-
-
-
The LibreDB family — one spine, three faces
-
-
- -- open core: Studio is free & open; Platform funds the open-source work.
- -- Studio opens live with a ready-to-use LibreDB sample across all three lenses, zero setup.
-
-
-```
-
-- [ ] **Step 2: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/index.html` contains "The LibreDB family" and links to `/database` and `platform.libredb.org`.
-
-- [ ] **Step 3: Commit**
-
-```bash
-git add src/components/sections/HomeSection.astro
-git commit -m "feat: add open-core family block + sample teaser to home"
-```
-
----
-
-### Task 10: Features zero-setup sample card
-
-**Files:**
-- Modify: `src/components/sections/FeaturesSection.astro` (add 18th card)
-- Modify: `src/data/sections.ts` (`features` rows 17→18, explain text)
-
-**Interfaces:**
-- Consumes: nothing new.
-
-- [ ] **Step 1: Add the sample card to the `features` array in `FeaturesSection.astro`**
-
-Append this object as the last item of the `features: Feature[]` array (after 'DBA Toolkit'):
-
-```ts
- { name: 'Opens Ready-to-Use', category: 'CORE', summary: 'No empty screen on first launch — Studio ships with a live Sample (LibreDB) connection powered by our open-source embedded engine. Explore relational, document, and key-value side by side, no server required. Editable, deletable, off by one env flag.' },
-```
-
-- [ ] **Step 2: Update the `features` row count and explain in `src/data/sections.ts`**
-
-In the `features` section: change `rows: 17,` to `rows: 18,`, and change the `explain` to:
-
-```ts
- explain: 'Lists 18 capabilities grouped by area — from the Monaco SQL editor and NL2SQL Copilot to data masking, the DBA toolkit, and a zero-setup embedded LibreDB sample on first launch.',
-```
-
-- [ ] **Step 3: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/features/index.html` contains "Opens Ready-to-Use".
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add src/components/sections/FeaturesSection.astro src/data/sections.ts
-git commit -m "feat: add zero-setup LibreDB sample feature card"
-```
-
----
-
-### Task 11: Header & Footer navigation
-
-**Files:**
-- Modify: `src/components/Header.astro`
-- Modify: `src/components/Footer.astro`
-
-**Interfaces:**
-- Consumes: routes `/providers`, `/database` (Tasks 2, 5).
-
-- [ ] **Step 1: Update Header nav links in `src/components/Header.astro`**
-
-Replace the desktop navigation block (the `
` group) with:
-
-```astro
-
-```
-
-(Tech Stack and Get Started are dropped from the top nav to make room; they remain reachable via the Explorer and their routes are unchanged.)
-
-- [ ] **Step 2: Update Footer "Product" link group in `src/components/Footer.astro`**
-
-In the `sections` array, replace the `product` group's `links` with (rename Databases→Providers; add Database + Platform):
-
-```ts
- links: [
- { label: "Features", href: "/features" },
- { label: "Providers", href: "/providers" },
- { label: "Database (pre-alpha)", href: "/database" },
- { label: "Platform (beta)", href: "https://platform.libredb.org", external: true },
- { label: "Tech Stack", href: "/tech-stack" },
- { label: "Deploy", href: "/deploy" },
- { label: "Live Demo", href: "https://app.libredb.org", external: true },
- ],
-```
-
-- [ ] **Step 3: Verify build**
-
-Run: `bunx astro build`
-Expected: build succeeds; `dist/index.html` header contains `href="/providers"`, `href="/database"`, and `platform.libredb.org`; no `href="/databases"` remains in nav.
-Run: `grep -c 'href="/databases"' dist/index.html`
-Expected: `0`.
-
-- [ ] **Step 4: Commit**
-
-```bash
-git add src/components/Header.astro src/components/Footer.astro
-git commit -m "feat: update header & footer nav for providers, database, platform"
-```
-
----
-
-### Task 12: Full verification & cleanup
-
-**Files:**
-- No source changes — integration verification only.
-
-**Interfaces:**
-- Consumes: all prior tasks.
-
-- [ ] **Step 1: Run the full test suite**
-
-Run: `bun test src/data/`
-Expected: PASS (all tests green, including the new schema/providers/database assertions).
-
-- [ ] **Step 2: Run the real production build**
-
-Run: `bun run build`
-Expected: build succeeds (this runs `scripts/sync-docker-compose.mjs` then `astro build`). Note: this step mutates the tracked `docker-compose.example.yml` file(s) by design.
-
-- [ ] **Step 3: Verify all new routes and the redirect exist in `dist/`**
-
-Run:
-```bash
-ls dist/providers/index.html dist/database/index.html dist/database-architecture/index.html dist/database-reliability/index.html dist/databases/index.html
-```
-Expected: all five exist (`dist/databases/index.html` is the redirect page → `/providers`).
-
-- [ ] **Step 4: Confirm Studio is still the hero (no regressions)**
-
-Run: `grep -c 'The Modern' dist/index.html`
-Expected: ≥ 1 (the Studio hero headline is intact on home).
-
-- [ ] **Step 5: Revert build-mutated compose files**
-
-Run:
-```bash
-git checkout -- $(git diff --name-only | grep 'docker-compose.example.yml')
-```
-Expected: working tree clean except intended source changes (verify with `git status`).
-
-- [ ] **Step 6: Final commit (if any non-compose changes remain) and branch summary**
-
-```bash
-git status
-# If nothing remains to commit, the feature is complete on this branch.
-```
-
----
-
-## Self-Review
-
-**Spec coverage:**
-- Namespace collision `/databases`→`/providers` + 301 → Task 2. ✅
-- Engine home `/database` (3-table credibility trio: manifesto/architecture/reliability) → Tasks 4–7. ✅
-- Schema grouping (`schemas.ts`, `SectionMeta.schema`, Explorer by schema, platform external) → Tasks 1, 8. ✅
-- Bridge 1 (Studio→engine): features sample card → Task 10; home family block + teaser → Task 9. ✅
-- Bridge 2 (engine→Studio reverse link) → in DatabaseSection (Task 5). ✅
-- Bridge 3 (`/providers` LibreDB native entry, Usage B) → Task 3. ✅
-- Usage A embed snippet on `/database` → Task 5. ✅
-- Platform: open-core family block (Task 9) + nav (Task 11); lean internal `/platform` page with CTA→app + Explorer `↗ open app` row (added post-plan, Task 13). No on-site pricing. ✅
-- SEO: 301 redirect (Task 2), `database` JSON-LD (Task 5). ✅
-- Header/Footer updates → Task 11. ✅
-- Tests updated → Tasks 1, 2, 4; full run Task 12. ✅
-- Studio stays hero (hero/home untouched; checked) → Global Constraint + Task 12 Step 4. ✅
-
-**Placeholder scan:** No TBD/TODO; every code step contains full content. ✅
-
-**Type consistency:** `SchemaMeta` / `schemas` (Task 1) consumed by Explorer (Task 8) and the platform test (Task 1). `SectionMeta.schema` added in Task 1, set on all sections in Tasks 1/2/4, read in Task 8. Section ids `providers`, `database`, `database_architecture`, `database_reliability` defined in Tasks 2/4 and mapped in COMPONENTS in Tasks 2/5/6/7 — names match exactly. `DatabaseCtaFooter` (Task 5) imported by Tasks 5/6/7 with the same path. ✅
diff --git a/docs/superpowers/plans/2026-06-30-playground-opfs-editor.md b/docs/superpowers/plans/2026-06-30-playground-opfs-editor.md
deleted file mode 100644
index e4e13dc..0000000
--- a/docs/superpowers/plans/2026-06-30-playground-opfs-editor.md
+++ /dev/null
@@ -1,1066 +0,0 @@
-# /playground OPFS Editor Implementation Plan
-
-> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
-
-**Goal:** Add a public `/playground` route that runs a real OPFS-backed LibreDB entirely in the browser — preloaded sample data, a clickable command cheatsheet, reset, and graceful in-memory fallback — with no backend and no login.
-
-**Architecture:** A SSR-safe Astro page reuses the site's `StudioShell` chrome and mounts a client-only island. The engine runs in a Web Worker (OPFS sync-access handles are Worker-only); the UI talks to it over `postMessage`. Pure, testable modules (`protocol`, `engine`) hold the command grammar and lens dispatch; the worker and client are thin shells around them.
-
-**Tech Stack:** Astro 7 (static, no React), TypeScript (strict), Tailwind 4, `@libredb/libredb@0.1.3` (`/browser` entry), `bun:test`, Playwright (MCP) for browser verification.
-
-## Global Constraints
-
-- Import the engine **only** from `@libredb/libredb/browser` (its import graph reaches no `node:` module). Never import the bare `@libredb/libredb`.
-- **No engine/DOM/Worker code may run during SSR.** All engine code lives in the Worker or in client `
-```
-
-- [ ] **Step 3: Create `src/pages/playground.astro`**
-
-```astro
----
-import Layout from "../layouts/Layout.astro";
-import StudioShell from "../components/studio/StudioShell.astro";
-import Playground from "../components/studio/Playground.astro";
----
-
-
-
-
-
-
-```
-
-- [ ] **Step 4: Add the nav link in `src/components/studio/TopBar.astro`**
-
-Read the file first. Find the existing top-bar link/menu markup and add, following the surrounding pattern, a link whose `href="/playground"` labeled `Playground`. Do **not** modify `src/data/sections.ts` (that drives the schema explorer rows and homepage nav). Keep the change to a single anchor consistent with the existing nav items.
-
-- [ ] **Step 5: Verify it builds and renders**
-
-Run: `bun run build 2>&1 | tail -25`
-Expected: build succeeds; `dist/playground/index.html` exists.
-Then revert the build-mutated compose files:
-Run: `git checkout -- src/data/docker-compose.example.yml public/docker-compose.example.yml 2>/dev/null; git status --short`
-Expected: only the new/intended files show as changes.
-
-- [ ] **Step 6: Commit**
-
-```bash
-git add src/components/studio/Cheatsheet.astro src/components/studio/Playground.astro src/pages/playground.astro src/components/studio/TopBar.astro
-git commit -m "feat(playground): editor pane, cheatsheet, route, nav link (#19)"
-```
-
----
-
-## Task 6: Gate + browser verification (Playwright)
-
-**Files:** none created — verification only.
-
-- [ ] **Step 1: Run the full gate**
-
-Run: `bun run gate 2>&1 | tail -30`
-Expected: typecheck, format, lint, knip, and all `bun:test` pass. Fix any failures (likely knip on unused exports — ensure every new export is consumed; prettier — run `bun run format:fix`).
-
-- [ ] **Step 2: Serve the production build with caching disabled**
-
-Run (background): `bunx http-server dist -p 8081 -c-1`
-(Use a cache-disabled static server per the repo's VT runtime-testing note.)
-
-- [ ] **Step 3: Playwright — load and assert seed renders**
-
-Navigate to `http://localhost:8081/playground`. Take a snapshot. Assert:
-- The result grid shows the 3 seeded users (Ada, Linus, Grace).
-- The persistence badge reads `OPFS · persistent` (Chromium on localhost is a secure context with OPFS).
-
-- [ ] **Step 4: Playwright — click-to-run, persist, reset**
-
-- Click the cheatsheet button `insert into users {"id":"4","name":"Lin","age":29,"active":true}`, then `select * from users` → assert a 4th row `Lin` appears.
-- Reload the page → assert `Lin` is still present (OPFS persistence across reload).
-- Click `↺ Reset sandbox` → assert the grid returns to exactly the 3 seed rows.
-- Click `prefix config:` → assert key/value rows for `config:*` render.
-
-- [ ] **Step 5: Confirm no `node:` in the client bundle**
-
-Run: `grep -rl "node:fs\|require(\"fs\")\|node_fs" dist/assets/*.js | head` (or scan the playground chunk).
-Expected: no matches — the browser entry pulled no `node:` module into the client bundle.
-
-- [ ] **Step 6: Final commit (if any verification fixes were needed)**
-
-```bash
-git add -A && git commit -m "test(playground): gate fixes + browser-verified OPFS demo (#19)"
-```
-
----
-
-## Self-Review
-
-- **Spec coverage:** Public no-login route (Task 5) ✓ · client-side OPFS Worker, no backend (Tasks 3,6) ✓ · 3-lens seed (Task 2) ✓ · clickable palette (Tasks 4,5) ✓ · persist + isolate + reset (Tasks 3,6) ✓ · no `node:fs`, marketing build unaffected (Task 6, TopBar-only nav change) ✓ · in-memory fallback + notice (Tasks 3,4,5) ✓ · `db.close()` teardown (Tasks 3,4) ✓ · no SSR engine code (Task 5 client-only `