From 3f09fe472e5f63aa96346040661ea983131c344f Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Tue, 14 Jul 2026 10:42:06 +0300 Subject: [PATCH 01/13] docs: add Blume public docs site plan and research passes Consolidated implementation plan plus GLM, GPT, and Opus research findings for standing up a Blume documentation site in the monorepo. --- docs/plans/blume-docs-site.md | 443 +++++++++++++++++++++++++++++++ docs/research/blume-docs-glm.md | 271 +++++++++++++++++++ docs/research/blume-docs-gpt.md | 281 ++++++++++++++++++++ docs/research/blume-docs-opus.md | 294 ++++++++++++++++++++ 4 files changed, 1289 insertions(+) create mode 100644 docs/plans/blume-docs-site.md create mode 100644 docs/research/blume-docs-glm.md create mode 100644 docs/research/blume-docs-gpt.md create mode 100644 docs/research/blume-docs-opus.md diff --git a/docs/plans/blume-docs-site.md b/docs/plans/blume-docs-site.md new file mode 100644 index 0000000..7a947dc --- /dev/null +++ b/docs/plans/blume-docs-site.md @@ -0,0 +1,443 @@ +# Plan: public documentation site (Blume) + +Consolidated from three research passes against this monorepo and [Blume](https://useblume.dev/) ([llms.txt](https://useblume.dev/llms.txt), [llms-full.txt](https://useblume.dev/llms-full.txt)). + +**Full subagent findings (debate context, rejected alternatives, model-specific nuance):** + +- [GLM 5.2 — `docs/research/blume-docs-glm.md`](../research/blume-docs-glm.md) (`docs-site/` placement, Core tab IA, `/guides/inference`) +- [GPT 5.6 — `docs/research/blume-docs-gpt.md`](../research/blume-docs-gpt.md) (contract+delta adapter pattern, positioning narrative, `site/` placement) +- [Opus 4.8 — `docs/research/blume-docs-opus.md`](../research/blume-docs-opus.md) (`apps/docs/` insulation, mermaid architecture, contributor workflow, oxfmt patch alternative) + +## Executive summary + +- Stand up **Blume in a dedicated workspace at `apps/docs/`**, insulated from library quality gates (`sherif`, `size-limit`, zero-dep guard, `oxfmt`, `lychee`). Do **not** point Blume at root `docs/` — that folder is governance-owned maintainer substrate (`plans/`, `audits/`, `research/`) and must stay unpublished. +- Mirror the library seam in information architecture: **Guides** (task recipes) · **Concepts** (engine model) · **Adapters** (per-framework deltas) · **Reference** (glossary + curated API) · **Changelog** (GitHub Releases). Use Blume **header tabs** so each tab scopes the sidebar — the primary lever for a 7-framework library without 7 duplicate guide trees. +- **One concept, one canonical home.** Lift consumer-facing prose from `docs/architecture.md` into Blume Concepts pages; shrink package READMEs to npm landings (install + taste + link); keep maintainer-only material in-repo per [`docs-governance`](../.agents/skills/docs-governance/SKILL.md). +- **AI-readiness is near-free on static deploy:** `llms.txt`, `llms-full.txt`, raw `.md` URLs, Copy as Markdown, `agent-readability.json`. MCP + Ask AI need `deployment.output: "server"` — defer to Phase 4. +- **Tracer bullet first:** landing + install + one React getting-started page, `blume build` green in CI, preview deploy — then expand adapters, concepts, changelog. + +--- + +## Why Blume + +| Need | Blume feature | +| ------------------------------------------ | ------------------------------------------------------------ | +| Markdown-first, zero app boilerplate | Folder of `.mdx` → production site; `npx blume init` | +| Multi-framework IA | Header tabs scope sidebar per section | +| Install snippets per adapter | `package-install` directive → npm/pnpm/yarn/bun tabs | +| Side-by-side framework examples | Built-in ``, ``, callouts, Mermaid | +| Agent consumers (this repo is agent-first) | `llms.txt`, per-page `.md`, optional MCP server | +| Changelog without double-writing | `github-releases` content source | +| Monorepo edit links | `github.dir` points at project root inside repo | +| Experimental API | Banner + stability page; no generated API pages until stable | + +Blume builds on Astro/Vite, static by default — fits a library docs site with no server cost in Phase 1. + +--- + +## Site placement + +### Decision: `apps/docs/` + +| Option | Verdict | +| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`apps/docs/`** | **Chosen.** App workspace, fenced from `packages/*` publish gates. Matches monorepo convention for non-published apps. | +| `docs-site/` or `site/` at root | Acceptable alternative; less explicit about insulation from library tooling. | +| Root `docs/` as Blume content | **Rejected.** Leaks `plans/`, `audits/`, `research/`; mixes generated TypeDoc (`docs/api`) with authored content; violates `docs-governance` lifecycle. | +| `packages/docs` | **Rejected.** `packages/*` implies publishable library; trips `sherif`, `size-limit`, `check:pack`, zero-dep guard. | +| Separate repo | **Rejected.** Loses monorepo edit links, colocated changelog, agent-first story. | + +### Proposed layout + +```text +layers/ +├── packages/ # unchanged — core + 6 adapters +├── docs/ # unchanged — maintainer governance (architecture, glossary, roadmap, plans/, research/) +├── apps/ +│ └── docs/ # NEW — Blume site +│ ├── package.json # "@stainless-code/layers-docs", private +│ ├── blume.config.ts +│ ├── tsconfig.json +│ ├── content/ # authored public docs +│ └── public/ # logo, favicon; later: generated TypeDoc +└── package.json # add "apps/*" to workspaces; docs:* scripts +``` + +### Monorepo wiring + +```jsonc +// root package.json (additions) +"workspaces": ["packages/*", "apps/*"], +"scripts": { + "docs:dev": "bun run --filter '@stainless-code/layers-docs' dev", + "docs:build": "bun run --filter '@stainless-code/layers-docs' build", + "docs:preview": "bun run --filter '@stainless-code/layers-docs' preview", + "docs:check": "bun run --filter '@stainless-code/layers-docs' check" +} +``` + +```jsonc +// apps/docs/package.json (sketch) +{ + "name": "@stainless-code/layers-docs", + "private": true, + "type": "module", + "scripts": { + "dev": "blume dev", + "build": "blume build", + "preview": "blume preview", + "check": "blume check", + }, + "dependencies": { "blume": "^1.0.3" }, +} +``` + +### Insulation from library gates + +| Gate | Action | +| -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `sherif` (`check:deps`) | Ignore `apps/docs` — Astro/React deps won't match library pins | +| Root `build` / `test` / `test:dom` | Already scoped to `@stainless-code/*-layers`; docs not swept | +| `size-limit`, `knip`, `check:pack`, zero-dep guard | Do not extend to `apps/docs` | +| `oxfmt` (`format` / pre-commit) | **Exclude `apps/docs/content/**`** — pinned `oxfmt@0.58.0` collapses Blume `:::note` callouts (Blume documents a patch for this exact version) | +| `lychee` (`check:links`) | **Exclude `apps/docs/**`** in `lychee.toml` — site-absolute links (`/concepts/...`) false-flag; use `blume validate` for docs | +| `.gitignore` | `apps/docs/.blume/`, `.blume-verify/`, `dist/` | + +Node ≥ 22.12 required by Blume; root `engines` already allows `>=22.12.0` — confirm docs CI job uses Node 22+. + +--- + +## Information architecture + +Use Blume tabs + `sidebar.display: "group"` for collapsible adapter sections. + +```text +Header tabs: Guides · Concepts · Adapters · Reference +Featured: Changelog · GitHub + +/ Landing — pitch, use-case matrix, framework picker +/concepts/stability Experimental status, semver, pinning (banner target) + +── Guides (task-oriented; framework code via ) ── +/guides/getting-started Install → declare → mount → open+await +/guides/awaiting-results await open, DataTag inference, fire-and-forget +/guides/singletons upsert + update (toasts, progress) +/guides/serial-queues scope: serial, getQueuedSnapshot +/guides/nested-overlays layer groups +/guides/animations transition axis, delays, call.settle() +/guides/dismissal-blockers blockers, dismissing, dismissAll modes +/guides/payload-validation Standard Schema, PayloadValidationError +/guides/error-handling Promise rejections, narrowing +/guides/headless-rendering useStackHandles, StackSubscribe, when to skip StackOutlet +/guides/ssr per-adapter SSR posture + +── Concepts (canonical engine model — lifted from architecture.md) ── +/concepts/when-to-use Use-case matrix (from root README) +/concepts/overview Core + adapter boundary +/concepts/lifecycle phase / transition / actionStatus (diagram-first) +/concepts/stacks-scope-gc named stacks, serial/parallel, gcTime, upsert +/concepts/identity-and-types key vs instance id, DataTag, Register +/concepts/blockers engine-level blocker model (links to guide) +/concepts/notifications notifyManager batching +/concepts/glossary Ubiquitous language (from docs/glossary.md) + +── Adapters (tab-scoped sidebar — one framework at a time) ── +/adapters Parity matrix (architecture.md § Adapter ergonomics) +/adapters/core UI-agnostic engine (packages/core README) +/adapters/react packages/react README → thin delta +/adapters/preact +/adapters/vue +/adapters/solid +/adapters/angular renderStack(vcr) divergence called out +/adapters/svelte/runes entry `.` (5.7+) +/adapters/svelte/store entry `./store` (3+) + +── Reference ── +/reference/overview How to read reference; TypeDoc link +/reference/core-api Curated LayerClient, LayerStack, layerOptions… +/reference/adapter-hooks Hook signatures matrix +/reference/roadmap Lifted from docs/roadmap.md +/reference/migration Breaking-change notes when they ship + +── Changelog (github-releases source) ── +/changelog Timeline + RSS from GitHub Releases +``` + +**Pedagogy:** navigation teaches the architecture. Concepts = engine (framework-free). Adapters = per-stack binding. Guides = cross-cutting tasks with `` for syntax — **never fork a guide per framework.** + +--- + +## Single source of truth + +| Content | Canonical home | Other surfaces | +| ------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| Engine model (lifecycle, stacks, blockers, transitions) | Blume `/concepts/*` | `docs/architecture.md` slimmed to maintainer slice (invariants, test matrix, isolation) + links to site | +| Glossary | `docs/glossary.md` (governance-owned) | Imported or copied into `/concepts/glossary`; fix internal links to site-absolute URLs | +| Per-adapter getting-started | Blume `/adapters/` | Package READMEs → install + ~20-line taste + "Full guide →" | +| When-to-use matrix | Blume `/concepts/when-to-use` | Root README keeps teaser + link | +| Adapter parity matrix | Blume `/adapters` (one home only) | Do not duplicate in architecture.md long-term | +| Exhaustive symbol list | TypeDoc → `apps/docs/public/api/**` (CI-generated) | Curated `/reference/*` deep-links; keep `docs:api` in CI as validation | +| Changelog | GitHub Releases | `github-releases` source; no hand-maintained changelog | +| Plans / audits / research | In-repo `docs/` | Never published | +| Agent skills (`packages/*/skills`) | In-repo | Link to site concepts; don't restate APIs | + +**README drift policy (needs ratification):** make the Blume site canonical for users; shrink npm READMEs until they're too thin to drift. Alternative: keep READMEs canonical and accept drift — worse for a 7-package monorepo. + +**Do not auto-import `packages/*/README.md` as Blume filesystem sources.** GitHub-relative links and npm-standalone requirements break clean import. + +--- + +## Content map (migration) + +| Source | Destination | Treatment | +| ----------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------ | +| `README.md` | `/`, `/guides/getting-started`, `/concepts/when-to-use` | Split: matrix → landing; React taste → getting-started | +| `docs/architecture.md` | `/concepts/*`, `/guides/*`, `/adapters`, `/guides/ssr` | Decompose; demote file to maintainer slice | +| `docs/glossary.md` | `/concepts/glossary` | Near-verbatim; fix cross-links | +| `docs/roadmap.md` | `/reference/roadmap` | Near-verbatim | +| `packages/core/README.md` | `/adapters/core`, `/reference/core-api` | Lift | +| `packages/{react,preact,vue,solid,angular}/README.md` | `/adapters/` | Thin delta only | +| `packages/svelte/README.md` | `/adapters/svelte/runes` + `/adapters/svelte/store` | Two pages — two package entries | +| GitHub Releases | `/changelog` | `github-releases` source | +| `docs/plans/*`, `docs/research/*`, `docs/audits/*` | — | Excluded | +| `docs/api/` (TypeDoc HTML today) | `apps/docs/public/api/` (Phase 4) | CI-generated; stop committing HTML | + +--- + +## `blume.config.ts` (draft) + +```ts +import { defineConfig } from "blume"; + +export default defineConfig({ + title: "Layers", + description: + "Headless modal/dialog/drawer/popover/toast manager — open any layer from anywhere. Zero-dep core + React, Preact, Vue, Solid, Svelte, and Angular adapters.", + + logo: { image: "/logo.svg", text: "Layers" }, + + banner: { + content: + "Experimental — the API may change between minors. Pin your version.", + link: { text: "Stability & versioning", href: "/concepts/stability" }, + dismissible: true, + id: "experimental-2026", + }, + + github: { + owner: "stainless-code", + repo: "layers", + branch: "main", + dir: "apps/docs", // monorepo: correct Edit-on-GitHub links + }, + + lastModified: true, // CI: fetch-depth: 0 + + content: { + sources: [ + { type: "filesystem", root: "content" }, + { + type: "github-releases", + prefix: "changelog", + owner: "stainless-code", + repo: "layers", + limit: 100, + }, + ], + }, + + navigation: { + tabs: [ + { label: "Guides", path: "/guides", icon: "book-open" }, + { label: "Concepts", path: "/concepts", icon: "layers" }, + { label: "Adapters", path: "/adapters", icon: "plug" }, + { label: "Reference", path: "/reference", icon: "code" }, + ], + featured: [ + { label: "Changelog", href: "/changelog", icon: "sparkles" }, + { + label: "GitHub", + href: "https://github.com/stainless-code/layers", + icon: "github", + }, + ], + sidebar: { display: "group" }, + }, + + theme: { accent: "teal", radius: "md", mode: "system" }, + search: { provider: "orama" }, + + markdown: { + code: { icons: true }, + codeBlocks: { theme: { light: "github-light", dark: "github-dark" } }, + }, + + toc: { minHeadingLevel: 2, maxHeadingLevel: 3 }, + + ai: { + llmsTxt: true, + // Phase 4 — requires output: "server" + deploy adapter + API key + // mcp: { enabled: true, route: "/mcp" }, + // ask: { enabled: true, provider: "gateway", model: "…" }, + }, + + seo: { + og: { enabled: true }, + rss: { enabled: true, types: ["changelog"] }, + sitemap: true, + robots: true, + structuredData: true, + agentReadability: true, + }, + + deployment: { + output: "static", + site: "https://layers.stainless-code.dev", // decide domain before launch + }, + + redirects: [ + { from: "/architecture", to: "/concepts/overview", status: 301 }, + { from: "/glossary", to: "/concepts/glossary", status: 301 }, + ], +}); +``` + +### Authoring patterns + +- **Install:** ` ```package-install ` fences (MDX-only) per adapter page. +- **Framework parity:** one guide page, `` for React / Preact / Vue / Solid / Angular / Svelte runes / Svelte store. +- **Lifecycle:** Mermaid state diagram on `/concepts/lifecycle` — the `phase × transition` truth table is the #1 confusion point. +- **Type inference:** dedicated content showing `await client.open(...)` inferring `R` via `DataTag` — the library's signature feature; consider Twoslash blocks later. +- **Angular / Svelte:** document imperative/primitive rendering as intentional compiler-free design, not a parity gap. + +--- + +## CI / deploy + +### CI (`.github/workflows/ci.yml`) + +Add a separate **`docs`** job (do not block `CI complete` on docs churn initially): + +1. Checkout with `fetch-depth: 0` (for `lastModified`). +2. Node 22+ (Blume requirement). +3. `bun install` +4. `bun run docs:check` (or `docs:build` + `blume validate`) +5. Optionally assert `dist/llms.txt` and `dist/llms-full.txt` exist post-build. + +Keep existing **`docs-api`** TypeDoc job — it validates exports independently of narrative docs. + +### Deploy + +- **Phase 1:** static host (Vercel / Netlify / Cloudflare Pages / GitHub Pages). Build `apps/docs`, publish `dist/`. +- **Trigger:** deploy on `main` push (docs-only or any); **not** tied to npm release workflow. +- **Phase 4:** if MCP or Ask AI enabled → `deployment.output: "server"` + adapter; `AI_GATEWAY_API_KEY` or provider key; rate limits on `/api/ask`. + +### Changelog pipeline + +Adopt **changesets linked (or fixed) versioning** so all `@stainless-code/*-layers` packages bump together → **one GitHub Release per version** feeding `/changelog`. Per-package releases create a noisy timeline. + +Requirements: + +- `GITHUB_TOKEN` in docs build/deploy env for `github-releases` source. +- Redeploy docs on `release` published (webhook or workflow dispatch). + +--- + +## Phased rollout + +Aligned with [`tracer-bullets`](../../.agents/rules/tracer-bullets.md): one vertical slice, validate, expand. + +### Phase 0 — Ratify (this plan) + +- Confirm `apps/docs` placement, README canonical policy, domain/host. +- Architecture-priming: new workspace is structurally significant — this plan satisfies exploration; amend if needed. + +**Acceptance:** plan merged or amended; open questions below resolved. + +### Phase 1 — Tracer bullet + +- `blume init` → `apps/docs` with minimal config above. +- Fence `oxfmt` + `lychee` excludes. +- Pages: landing (`index.mdx`), `/guides/getting-started` (React only), `/guides/install` or install section. +- Root `docs:*` scripts + `docs` CI job. +- Preview deploy. + +**Acceptance:** `blume build` green; `blume validate` clean; library `CI complete` unaffected; `llms.txt` emitted with correct `deployment.site` URLs. + +### Phase 2 — Concepts + stability + +- Author `/concepts/*` from `architecture.md`. +- `/concepts/glossary` from `docs/glossary.md`. +- `/concepts/stability` + experimental banner. +- Slim `docs/architecture.md` to maintainer slice. + +**Acceptance:** one canonical page per engine concept; no consumer prose duplicated in `docs/architecture.md`. + +### Phase 3 — Guides + adapters + +- All `/guides/*` with ``. +- All `/adapters/` pages; Svelte split (runes + store). +- `/adapters` parity matrix (single home). +- Shrink 7 package READMEs + root README links. + +**Acceptance:** no framework-forked guide duplicates; READMEs ≤ ~30 lines prose each. + +### Phase 4 — Reference + changelog + AI + +- TypeDoc output → `apps/docs/public/api/**` (CI-generated; stop committing `docs/api/**`). +- Curated `/reference/*` with links into TypeDoc. +- Enable `github-releases` changelog; linked versioning in changesets. +- `llms.txt` / `llms-full.txt` quality pass. +- Optional: `output: "server"`, MCP, Ask AI. + +**Acceptance:** `/changelog` populated; TypeDoc regenerated in CI; MCP answers a sample agent query (if enabled). + +### Phase 5 — Polish + +- Custom landing, OG images, redirects for old anchors. +- `blume-update-docs` automation (Blume ships an agent skill for drift audits). +- Close this plan per `docs-governance` lifecycle. + +--- + +## Risks and open questions + +| # | Question | Recommendation | +| --- | ---------------------------------------- | ---------------------------------------------------------------------------- | +| 1 | README vs site canonical? | Site canonical; READMEs thin npm landings | +| 2 | API reference during experimental phase? | Curated guides + glossary; defer full TypeDoc surfacing until API stabilizes | +| 3 | Docs hostname? | Decide before setting `deployment.site` | +| 4 | GitHub Pages subpath? | Requires `deployment.base`; root domain preferred | +| 5 | Linked changesets versioning? | Adopt before relying on `/changelog` | +| 6 | `layer-handles` plan in flight? | Badge/callout APIs in flux; don't document unshipped renames as current | +| 7 | Ask AI cost/abuse? | Unauthenticated endpoint — rate limits + spend caps if enabled | + +### Anti-patterns (consensus) + +- Letting `oxfmt` format MDX content. +- Running `lychee` over Blume-authored links. +- Putting the site under `packages/`. +- Publishing `docs/plans/` or `docs/research/`. +- Auto-importing 7 READMEs verbatim. +- Forking guides per framework (6× "serial queues" pages). +- Hand-maintaining 130+ TypeDoc HTML pages in git. +- Per-package GitHub Releases → noisy changelog. +- Blocking library CI on docs failures (keep jobs separate initially). + +--- + +## Cross-agent insights worth keeping + +1. **Blume tabs solve the 7-framework IA problem** — scoped sidebar per adapter tab; don't flatten into one tree. +2. **AI features are asymmetric value** for a headless library users ask agents about ("open confirm from route guard, await in React"). Prioritize `llms-full.txt` prose quality; MCP in Phase 4. +3. **The three-axis model deserves diagram-first treatment** — `phase` / `transition` / `actionStatus` on `/concepts/lifecycle`. +4. **Navigation is pedagogy** — Concepts / Adapters / Guides mirrors core/adapter seam. +5. **Experimental is an asset if framed with design rigor** — link stability page to adversarial design process (e.g. layer-handles plan). +6. **Svelte two-entry case** (`./` vs `./store`) is an early IA proof — two sibling pages under `/adapters/svelte/`, not two packages. +7. **Changelog via `github-releases`** is high-ROI for a changesets repo — zero double-writing once linked versioning is adopted. + +--- + +## Next action + +Run Phase 1 tracer bullet: `npx blume init` in `apps/docs`, one React getting-started page, CI job, preview deploy. Resolve open question #3 (domain) in parallel. diff --git a/docs/research/blume-docs-glm.md b/docs/research/blume-docs-glm.md new file mode 100644 index 0000000..dea8f2e --- /dev/null +++ b/docs/research/blume-docs-glm.md @@ -0,0 +1,271 @@ +# Blume docs research — GLM 5.2 + +Research pass for public documentation of `@stainless-code/layers` using [Blume](https://useblume.dev/). Consolidated into [`docs/plans/blume-docs-site.md`](../plans/blume-docs-site.md); this file preserves full findings and model-specific rationale. + +**Date:** 2026-07-14 · **Model:** GLM 5.2 High + +--- + +## Executive summary + +- **Co-locate the site as a bun workspace at `docs-site/`** (not under `docs/`). The existing `docs/` is a maintainer-facing governance substrate (architecture, glossary, roadmap, plans, research) governed by the `docs-governance` skill — repurposing it would collide with that lifecycle and with Blume's `content.root` scanning. A dedicated `docs-site/` workspace keeps Blume's `.blume/`/`dist/` build artifacts, `blume.config.ts`, and Astro runtime out of the source tree and lets `blume` resolve via the workspace. +- **Information architecture mirrors the library's package boundary**: a _Core_ tab (UI-agnostic engine), an _Adapters_ tab (one section per framework, scoped sidebar via Blume tabs), a _Guides_ tab (cross-cutting concepts that aren't framework-specific), and a _Reference_ tab (API + glossary). This maps 1:1 to how the library is actually consumed and to the `@stainless-code/layers` + 6 adapter package split. +- **Content is lifted, not copied**: the public user-facing prose already exists — root `README.md` (use-case matrix, React taste), `docs/architecture.md`, `docs/glossary.md`, `docs/roadmap.md`, and each `packages/*/README.md`. The plan moves user-facing pages into `docs-site/src/content/` and _leaves_ `docs/plans/`, `docs/research/`, `docs/audits/` in place (internal lifecycle, not user docs — `docs/README.md` says so explicitly). +- **AI-readiness is Blume's killer feature for this library** and is nearly free: `llms.txt` + `llms-full.txt` + raw `.md` URLs are on by default. The MCP server and Ask AI need `deployment.output: "server"` — gate those behind Phase 3, keep Phase 1 static. +- **Tracer bullet first**: one install page + one React quickstart + the config file, built and deployed, _before_ migrating the other 6 adapters or the architecture deep-dive. Matches the repo's `tracer-bullets` rule. + +> **Note:** Consolidated plan chose `apps/docs/` over `docs-site/` for stronger insulation from library gates. Rationale for `docs-site/` at root remains valid as an alternative; see Opus research for the `apps/docs` argument. + +--- + +## Recommended site location in monorepo + +``` +layers/ +├─ packages/ # unchanged — core + 6 adapters +├─ docs/ # unchanged — maintainer governance substrate +├─ docs-site/ # NEW bun workspace +│ ├─ package.json # name: "@stainless-code/layers-docs", private, dep on "blume" +│ ├─ blume.config.ts +│ ├─ tsconfig.json # extends astro/tsconfigs/strict, includes .blume types +│ ├─ public/ # logo.svg, favicon, og images +│ └─ src/content/ # the actual user-facing docs tree +└─ package.json # add "docs-site" to workspaces, add root scripts +``` + +**Why `docs-site/` and not `docs/`:** + +- `docs/` is explicitly a _maintainer-facing reference + lifecycle substrate_ (`docs/README.md`), governed by `docs-governance`. Blume's `content.root` would scan `plans/`, `research/`, `audits/` — internal work artifacts that must not ship as user docs. +- Blume writes a generated `.blume/` runtime + `dist/` next to its config; you don't want that churn inside `docs/` (which `check:links` via lychee and `docs-governance` lifecycle sweeps operate on). +- A workspace gets `blume` resolved through `bun install` like every other package, and the root `--filter` script fan-out pattern extends naturally: `bun run --filter '@stainless-code/layers-docs' build`. + +**Root `package.json` additions** (sketch): + +```jsonc +"workspaces": ["packages/*", "docs-site"], +"scripts": { + "docs:dev": "bun run --filter '@stainless-code/layers-docs' dev", + "docs:build": "bun run --filter '@stainless-code/layers-docs' build", + "docs:preview": "bun run --filter '@stainless-code/layers-docs' preview", + "docs:check": "bun run --filter '@stainless-code/layers-docs' check" +} +``` + +The repo already has a `docs:api` script running `typedoc` → `docs/api`. That output is generated and should _not_ live inside Blume's content root. + +--- + +## Proposed IA / sidebar + +Use Blume **header tabs** (each tab scopes the sidebar to its `path`) plus generated sidebar with `meta.ts` per folder. `display: "group"` so adapter sections collapse. + +``` +Tabs: Guides · Core · Adapters · Reference · Changelog +``` + +**`/` (no tab)** — landing page: hero, use-case matrix from README "When to use it", framework picker cards linking into each adapter quickstart. + +**Guides** (`/guides/*`) — cross-framework concepts: + +- Getting started (install, the 3-step declare→mount→await model) +- Layer lifecycle (`pending → active → dismissed → exiting → removed → cached`) +- Transitions (`phase` / `transition` / `actionStatus` — three orthogonal axes) +- Blockers & dismissal (`addBlocker`, `dismissAll` modes, `dismissing`) +- Stacks, scope, gcTime (named stacks, serial queue, `getQueuedSnapshot`, caching) +- Layer groups (nested/child stacks, `childStackId`, event-driven drain) +- Payload validation (Standard Schema, `PayloadValidationError`) +- Error handling (`Promise`, why rejections aren't typed, `isPayloadValidationError`) +- Headless rendering (`useStackHandles`, `StackSubscribe`, when to skip `StackOutlet`) + +**Core** (`/core/*`) — `@stainless-code/layers` (zero-dep engine), from `packages/core/README.md`: + +- Overview / when to use core directly +- `LayerClient` API +- `layerOptions` / `layerKey` / `DataTag` inference +- `createCallContext` / call handle +- `notifyManager` batching +- `Register` / `DefaultLayerError` + +**Adapters** (`/adapters/*`) — one section per framework, tab-scoped sidebar: + +- `react/`, `preact/`, `vue/`, `solid/`, `angular/`, `svelte/` (two sub-pages: `runes` and `store`) +- Cross-adapter **comparison** page — capability matrix from `docs/architecture.md` § Adapter ergonomics at `/adapters` index + +**Reference** (`/reference/*`): + +- Glossary — from `docs/glossary.md` +- API reference — link out to TypeDoc `docs/api` for Phase 1; evaluate Markdown mount later +- Roadmap — from `docs/roadmap.md` +- SSR posture — per-adapter table from `docs/architecture.md` + +**Changelog** (`/changelog/*`) — `github-releases` source pointed at `stainless-code/layers`. + +--- + +## Content map (source → target page) + +| Source file | Target | Treatment | +| -------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `README.md` (root) | `/` landing + `/guides/getting-started` | Lift use-case matrix → landing cards; React taste → React quickstart; Concepts bullets → Guides intros | +| `docs/architecture.md` | `/guides/*` (split) + `/adapters` comparison + `/reference/ssr` | **Split**, don't copy whole. Package-boundary + ergonomics matrix → `/adapters` index; SSR → `/reference/ssr`. Keep file as maintainer doc. | +| `docs/glossary.md` | `/reference/glossary` | Near-verbatim lift | +| `docs/roadmap.md` | `/reference/roadmap` | Near-verbatim lift | +| `packages/core/README.md` | `/core/*` | Lift + restructure | +| `packages/*/README.md` | `/adapters//*` | Lift; `package-install` blocks for install | +| `packages/svelte/README.md` | `/adapters/svelte/runes` + `/adapters/svelte/store` | **Split into two pages** | +| `.changeset/` + GitHub Releases | `/changelog/*` | `github-releases` source | +| `docs/plans/*`, `docs/research/*`, `docs/audits/*` | **Not migrated** | Internal lifecycle | +| `docs/api/` (TypeDoc) | `/reference/api` (external link) | Phase 1 link out | + +--- + +## Blume config sketch + +```ts +// docs-site/blume.config.ts +import { defineConfig } from "blume"; + +export default defineConfig({ + title: "@stainless-code/layers", + description: + "Headless manager for modal/dialog/drawer/popover/toast UI — open any layer from anywhere, manage it as an ordered, named stack. Zero-dep core + React, Preact, Vue, Solid, Angular, Svelte adapters.", + + logo: { image: "/logo.svg", text: "layers" }, + github: { + owner: "stainless-code", + repo: "layers", + branch: "main", + dir: "docs-site", // monorepo: path from repo root to project root + }, + lastModified: true, + + content: { + root: "src/content", + sources: [ + { type: "filesystem", root: "src/content" }, + { + type: "github-releases", + prefix: "changelog", + owner: "stainless-code", + repo: "layers", + }, + ], + }, + + navigation: { + sidebar: { display: "group" }, + tabs: [ + { label: "Guides", path: "/guides", icon: "book-open" }, + { label: "Core", path: "/core", icon: "boxes" }, + { label: "Adapters", path: "/adapters", icon: "plug" }, + { label: "Reference", path: "/reference", icon: "dictionary" }, + { label: "Changelog", path: "/changelog", icon: "history" }, + ], + featured: [ + { + label: "GitHub", + href: "https://github.com/stainless-code/layers", + icon: "github", + }, + ], + }, + + theme: { accent: "teal", radius: "md", mode: "system" }, + search: { provider: "orama" }, + + markdown: { + code: { icons: true }, + codeBlocks: { theme: { light: "github-light", dark: "github-dark" } }, + }, + + toc: { minHeadingLevel: 2, maxHeadingLevel: 3 }, + + deployment: { + output: "static", + site: "https://layers.stainless-code.dev", + }, + + ai: { + llmsTxt: { enabled: true }, + // mcp: { enabled: true, route: "/mcp" }, // Phase 3 — needs server output + // ask: { enabled: true, provider: "gateway", model: "openai/gpt-5.5", + // suggestions: [ + // { label: "How do I await a modal's result?", icon: "help-circle" }, + // { label: "How do I open a layer from a route guard?", icon: "route" }, + // { label: "How do I animate enter/exit?", icon: "sparkles" }, + // ] }, + }, + + seo: { + og: { enabled: true }, + rss: { enabled: true, types: ["changelog"] }, + sitemap: true, + robots: true, + structuredData: true, + agentReadability: true, + }, + + redirects: [{ from: "/architecture", to: "/guides/lifecycle", status: 301 }], +}); +``` + +**Multi-package install tabs** — every adapter page uses `package-install` (MDX-only). Svelte: same install block on both pages; divergence is in import path. + +**Framework-specific sections** — use `` on cross-framework Guides pages for the same concept in each adapter's syntax. + +--- + +## Monorepo-specific concerns & solutions + +| Concern | Solution | +| --------------------------------------- | -------------------------------------------------------------- | +| **`blume` resolution** | `docs-site` workspace; `blume` in `dependencies`; Node ≥ 22.12 | +| **Edit-on-GitHub links** | `github.dir: "docs-site"` | +| **`lastModified` git dating** | Non-shallow checkout in CI (`fetch-depth: 0`) | +| **Content root collision with `docs/`** | `docs-site/src/content`, not `docs/` | +| **`sherif`** | `docs-site` declares `blume` as real dependency | +| **Root `lint-staged`/pre-commit** | Confirm `oxfmt` won't break `.mdx`; exclude if needed | +| **TypeDoc `docs/api`** | Don't put in Blume content root; link out Phase 1 | +| **`blume dev` vs `blume build`** | `blume build --isolated` in CI; gitignore `.blume/`, `dist/` | +| **Two Svelte entries** | Two pages under `/adapters/svelte/`, not two packages | +| **Search across 7 frameworks** | `search.tags: []` on adapter pages | + +--- + +## Phase 1 tracer bullet + +1. Create `docs-site/` workspace + `package.json` + minimal `blume.config.ts`. +2. Add to root `workspaces` + `docs:*` scripts. +3. Landing (`index.mdx`) — hero + use-case matrix. +4. `/guides/install` with `package-install`. +5. `/adapters/react/quickstart` — React taste example. +6. `meta.ts` for `/guides` and `/adapters/react` only. +7. `blume build` → verify `llms.txt` + raw `.md` URLs. +8. Preview deploy; `sherif`/`knip` green. + +**Then:** Phase 2 (other adapters + Guides from architecture), Phase 3 (server + MCP + Ask AI), Phase 4 (API reference reconciliation). + +--- + +## Risks & open questions + +1. **README ↔ docs-site duplication** — recommend site canonical + README pointer; needs maintainer decision. +2. **API reference strategy** — link out Phase 1; hand-written type tables may read better than TypeDoc during experimental phase. +3. **Server output for AI** — MCP + Ask AI need host + API key; GitHub Pages = static only. +4. **Changelog via `github-releases`** — confirm releases are published, not just tags. +5. **`blume` version / Node** — CI must use Node 22+. +6. **Mermaid for lifecycle** — must be in `.mdx`, not `.md`. +7. **`agents-first-convention`** — if docs authoring skill/rule added, follow symlink convention. +8. **Ask AI cost abuse** — rate limiting if enabled. + +--- + +## Unique insights (GLM) + +1. **7-framework split = Blume tab-scoped sidebar.** Don't flatten into one bloated sidebar. +2. **AI-readability is asymmetric value** for a headless library — MCP is the biggest leverage point for "open any layer from anywhere." +3. **`DataTag`/inference is the signature feature** — dedicated `/guides/inference` page showing `await client.open(...)` inferring `boolean`. +4. **`phase`/`transition`/`actionStatus` is novel and confusing** — Mermaid + `` with/without delays across frameworks. +5. **Don't generate API reference until stable** — experimental API + TypeDoc = liability. +6. **Svelte two-entry case** — two sibling pages under `/adapters/svelte/`, not two packages. +7. **Changelog via `github-releases`** — high-ROI for changesets repo; scoped-tag pagination handled automatically. diff --git a/docs/research/blume-docs-gpt.md b/docs/research/blume-docs-gpt.md new file mode 100644 index 0000000..7842e32 --- /dev/null +++ b/docs/research/blume-docs-gpt.md @@ -0,0 +1,281 @@ +# Blume docs research — GPT 5.6 + +Research pass for public documentation of `@stainless-code/layers` using [Blume](https://useblume.dev/). Consolidated into [`docs/plans/blume-docs-site.md`](../plans/blume-docs-site.md); this file preserves full findings and model-specific rationale. + +**Date:** 2026-07-14 · **Model:** GPT 5.6 Terra Medium + +--- + +## Executive summary + +Create a dedicated top-level Blume app at `site/`, with source content in `site/content/`. Keep repository docs as contributor/architecture sources; make Blume the canonical public-consumer documentation. + +Use shared conceptual guides plus thin framework adapter pages. Do not mirror seven README files verbatim. Phase 1 should deploy static docs; `llms.txt`, raw Markdown, and Copy as Markdown work without a server. Add MCP only after choosing a server-capable host. + +> **Note:** Consolidated plan chose `apps/docs/` over `site/`. Placement tradeoffs below remain useful for review. + +--- + +## Site placement decision + +| Option | Decision | Tradeoffs | +| ------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------- | +| `site/` top-level Blume app | Recommended (this pass) | Clear deploy boundary, own dependencies/config/content, avoids mixing site MDX with repo governance docs. | +| Reuse `docs/` as Blume root | No | `docs/` contains architecture, plans, audits, research, and generated TypeDoc output—not all public or stable. | +| Add a `packages/docs` workspace | No initially | Makes deploy/versioning more coupled to packages without a present need. | + +Proposed layout: + +```text +site/ + blume.config.ts + package.json + content/ + index.mdx + getting-started/ + guides/ + concepts/ + adapters/ + react/ + preact/ + vue/ + solid/ + angular/ + svelte/ + reference/ + public/ +``` + +Keep `docs/architecture.md`, `docs/glossary.md`, and package READMEs as source material initially. Do not mount the entire existing `docs/` folder as a Blume filesystem source: plans such as `docs/plans/layer-handles.md` are explicitly unimplemented and must not become public API documentation. + +--- + +## Navigation design + +Use top-level tabs so framework material does not bury core concepts. + +```text +Home / +Getting started /getting-started + Choose your adapter /getting-started/choose-an-adapter + Installation /getting-started/installation + First confirm dialog /getting-started/first-layer + +Guides /guides + Define a layer /guides/define-a-layer + Mount and render a stack /guides/render-a-stack + Open and await a result /guides/open-and-resolve + Fire-and-forget notices /guides/fire-and-forget + Singleton / live updates /guides/upsert-and-update + Serial flows /guides/serial-stacks + Nested layers /guides/layer-groups + Transitions /guides/transitions + Guard dismissal /guides/blockers + Validate payloads /guides/payload-validation + +Concepts /concepts + Architecture /concepts/architecture + Layer lifecycle /concepts/lifecycle + Stacks and scopes /concepts/stacks + Type inference /concepts/type-inference + SSR posture /concepts/ssr + Glossary /concepts/glossary + +Adapters /adapters + Overview / comparison /adapters + React /adapters/react + Preact /adapters/preact + Vue /adapters/vue + Solid /adapters/solid + Angular /adapters/angular + Svelte /adapters/svelte + Svelte stores /adapters/svelte/stores + +Reference /reference + Core API /reference/core + Adapter API matrix /reference/adapters + Package compatibility /reference/compatibility + Migration / breaking changes /reference/migration + +Changelog /changelog +GitHub external featured link +``` + +Configure Blume header tabs for `/guides`, `/concepts`, `/adapters`, and `/reference`. Route-scoped sidebar means the adapter tab only shows adapter material. + +--- + +## Content migration strategy + +| Existing source | Destination | Treatment | +| ----------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| Root `README.md` | Home, installation, adapter picker, first-layer guide | Split rather than copy. Preserve use-case matrix and React taste example. | +| `packages/core/README.md` | Core API + headless renderer guide | Lift `LayerClient`, `LayerStack`, `layerOptions`, `layerKey`, validation, direct-core use. | +| `docs/architecture.md` | Architecture, lifecycle, transitions, SSR, adapter comparison | Primary source, decomposed into reader-sized pages. | +| `docs/glossary.md` | Concepts glossary | Preserve exact terminology; link terms to primary guide. | +| `packages/*/README.md` | Adapter overview + seven adapter pages | Extract only installation, provider/client acquisition, rendering, adapter-specific wrappers. | +| `typedoc.json` / generated `docs/api` | Reference validation input, not initial public source | Keep in CI; later decide link/deploy vs curated pages. | +| `docs/plans/**`, `docs/research/**`, `docs/audits/**` | Excluded | Internal, historical, or unimplemented material. | + +Each guide should begin with a decision-oriented summary: when to use it, APIs involved, minimal example, framework differences, edge cases. + +--- + +## Blume config sketch + +```ts +import { defineConfig } from "blume"; + +export default defineConfig({ + title: "@stainless-code/layers", + description: + "Headless typed layer stacks for modals, dialogs, drawers, popovers, and toasts.", + github: { + owner: "stainless-code", + repo: "layers", + }, + + content: { + root: "content", + }, + + navigation: { + tabs: [ + { label: "Guides", path: "/guides", icon: "book-open" }, + { label: "Concepts", path: "/concepts", icon: "layers" }, + { label: "Adapters", path: "/adapters", icon: "plug" }, + { label: "Reference", path: "/reference", icon: "braces" }, + ], + featured: [ + { + label: "GitHub", + href: "https://github.com/stainless-code/layers", + icon: "github", + }, + ], + }, + + search: { provider: "orama" }, + + ai: { + llmsTxt: true, + mcp: { + enabled: false, // Enable only after server-host decision. + route: "/mcp", + name: "@stainless-code/layers docs", + instructions: + "Use framework-specific pages for rendering APIs; core guides apply to every adapter.", + }, + }, + + seo: { + og: { enabled: true }, + sitemap: true, + robots: true, + structuredData: true, + agentReadability: true, + }, + + deployment: { + output: "static", + site: "https://layers.stainless-code.dev", // decide actual domain first + }, +}); +``` + +Use MDX for pages requiring `package-install`, callouts, framework tabs, Mermaid lifecycle diagrams, or components. Plain Markdown for prose-heavy reference. + +--- + +## Framework adapter doc pattern + +Use a shared **contract + delta** structure: + +1. One canonical guide explains `LayerClient`, `layerOptions`, `open`, phases, transitions, blockers, scopes, and validation. +2. Every adapter page contains only: + - `package-install` block, + - supported framework/peer range, + - how the client is provided/read, + - idiomatic stack rendering, + - adapter-only ergonomic APIs, + - links back to shared guides. +3. Use one "same confirm dialog" example across all adapters, changing only framework syntax. + +The stable common contract: adapters re-export core, expose a client acquisition mechanism, and bind stack snapshots to framework reactivity. Rendering surface deliberately varies: + +- **React/Preact/Vue/Solid:** `StackProvider`, `useLayerClient`, `useStack`, `StackOutlet`. +- **Angular:** `provideLayerClient`, `LAYER_CLIENT`, signal-style `useStack`, imperative `renderStack(vcr)`. +- **Svelte runes:** `setLayerClient`, `useStack().current`, `stack.callFor`. +- **Svelte stores:** `/store`, `Readable`, `$stack`, standalone `callFor`. + +This prevents falsely documenting `StackOutlet` as universal while avoiding seven copies of the core lifecycle explanation. + +Use Blume `package-install` blocks per adapter. Use framework `` only when code is genuinely parallel; prefer individual adapter pages for larger differences. + +--- + +## CI/CD plan + +1. Add `blume` as a dev dependency in `site/package.json` or root workspace tooling. +2. Add root scripts: `docs:dev`, `docs:build`, `docs:preview`. +3. Add CI `Docs site` job to `.github/workflows/ci.yml`: + - checkout; + - existing Bun setup; + - `bun run docs:build`; + - optionally validate `site/dist/llms.txt`, `llms-full.txt`, `agent-readability.json`. +4. Keep existing `docs-api` TypeDoc job — validates exports independently. +5. Add deployment only on `main`, after CI succeeds: + - Static hosting enough for Phase 1. + - Vercel/Netlify/Cloudflare Pages build `site/` and publish `site/dist/`. + - GitHub Pages viable but needs `deployment.base` for project subpath. +6. Do not attach docs deployment to npm Release workflow initially. Documentation deploys when `main` changes, independent of package version publication. + +--- + +## Phase 1 / Phase 2 / Phase 3 rollout + +### Phase 1 — tracer bullet + +- `site/` with Blume config and static deployment. +- Home, installation/adapter chooser, React first-layer tutorial. +- One shared guide: "Define, mount, open, resolve." +- Generated `llms.txt`, raw `.md` pages, Copy as Markdown verified on preview. +- CI build gate and production deploy. + +Proves source → build → deploy → machine-readable reader path before migrating everything. + +### Phase 2 — shared model and adapters + +- Migrate architecture into concepts pages. +- Add React, Svelte runes, and Svelte stores first (conventional outlet + two Svelte render paths). +- Add Preact, Vue, Solid, Angular as thin deltas. +- Publish adapter comparison matrix and compatibility page. +- Add lifecycle diagrams, serial queue, layer groups, transitions, blockers, validation, SSR guides. +- Redirect README/package README links to canonical site routes once stable. + +### Phase 3 — reference and agent integration + +- Curate core/reference API pages from TypeDoc-validated exports. +- Add release changelog source from GitHub Releases if release notes are consistently useful. +- Enable hosted MCP only after `output: "server"` with selected adapter and rate-limit policy. +- Optionally add Blume Ask AI after content coverage is sufficient. + +--- + +## Risks + +- **API drift:** library is experimental; layer-handles plan documents future breaking API. Public pages must distinguish shipped APIs from plans. +- **Duplicate truth:** package READMEs, root README, architecture docs, and site can diverge. Declare Blume site canonical for users; reduce package READMEs to install/short-start/link surfaces. +- **Server cost/security:** MCP and Ask AI require server output; Ask AI needs key management and abuse controls. Static Phase 1 avoids both. +- **Seven-way duplication:** writing complete framework guides independently will introduce factual drift. Use canonical guides plus explicit deltas. +- **Domain uncertainty:** no current docs hostname/deployment provider configured. Avoid baking `deployment.site` until chosen. +- **Generated TypeDoc:** `docs/api` is generated beneath general docs tree. Do not ingest as Blume content until navigation/design meets public reference standard. + +--- + +## Unique insights (GPT) + +1. **Strongest public narrative is not "a modal library."** It is **typed, imperative layer orchestration**: declare once with `layerOptions`, invoke from anywhere through `LayerClient`, optionally await a typed result. +2. **"Await" should be shown as optional.** `void client.open(...)` is first-class; docs that lead only with confirmation dialogs understate toast, progress, and notification use cases. +3. **Svelte and Angular differences are architectural, not parity gaps.** Document primitive/imperative rendering as intentional compiler-free design. +4. **Blume's agent-facing output fits immediately on static deploy:** `/llms.txt`, `/llms-full.txt`, per-page `.md`, Copy as Markdown, `agent-readability.json`. MCP is valuable but not required for AI-ready docs. diff --git a/docs/research/blume-docs-opus.md b/docs/research/blume-docs-opus.md new file mode 100644 index 0000000..54adb01 --- /dev/null +++ b/docs/research/blume-docs-opus.md @@ -0,0 +1,294 @@ +# Blume docs research — Opus 4.8 + +Research pass for public documentation of `@stainless-code/layers` using [Blume](https://useblume.dev/). Consolidated into [`docs/plans/blume-docs-site.md`](../plans/blume-docs-site.md); this file preserves full findings and model-specific rationale. **This pass drove the consolidated placement decision (`apps/docs/`).** + +**Date:** 2026-07-14 · **Model:** Claude Opus 4.8 Thinking High + +--- + +## Executive summary + +`layers` is unusually hard to document: a **zero-dep headless core + 6 published framework adapters (7 entry points, counting Svelte runes/store)**, an engine with three orthogonal axes (`phase` / `transition` / `actionStatus`), and an _experimental, breaking-major-accepted_ API (see [`docs/plans/layer-handles.md`](../plans/layer-handles.md), which is about to rename half the adapter surface). The documentation problem is therefore **not "write pages" — it is "manage N-way duplication across 7 READMEs, 7 agent skills, `architecture.md`, `glossary.md`, JSDoc, and a soon-to-exist site without drift."** + +Recommendation: stand up **Blume in an insulated `apps/docs` workspace**, fenced off from the library's strict quality gates (sherif, size-limit, oxfmt, lychee, the zero-dep guard). Establish **one canonical home per concept** — lift the engine model out of `docs/architecture.md`/`glossary.md` into canonical Blume "Concepts" pages, shrink the 7 package READMEs to thin npm landings that _link into_ the site, and keep the maintainer-only lifecycle folders (`plans/`, `audits/`, `research/`) in-repo and unpublished per the `docs-governance` skill. Feed the changelog from **GitHub Releases** (after adopting changesets _linked_ versioning so a version = one coherent release, not 7). Ship `llms.txt` + MCP so coding agents consume the docs natively. + +**Day-one gotchas:** + +1. Repo pins **`oxfmt@0.58.0`**, the exact version whose Markdown formatter **collapses Blume's `:::note` directives** (Blume ships a patch for that exact build). +2. **`check:links` (lychee)** runs on `**/*.md` and will **false-flag Blume's site-absolute links** (`/concepts/...`). Both must be fenced off from the library gates. + +--- + +## Strategic positioning + +### Who reads what + +| Reader | Enters via | Wants | Primary surface | +| ------------------------ | --------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------- | +| **Evaluator** | Google / npm / GitHub | 60-second pitch, when-to-use / when-to-skip matrix, one taste example | Landing + `/concepts/when-to-use` | +| **Newcomer adopter** | Landing → their framework | Copy-paste getting-started in _their_ adapter | `/adapters//getting-started` | +| **Working developer** | Search (⌘K) / sidebar | Task recipes: serial queues, blockers, animation, validation | `/guides/*` (adapter-parameterized) | +| **Deep integrator** | Concepts / Reference | Engine model, three axes, SSR posture, type surface | `/concepts/*` + `/reference/*` | +| **Contributor / porter** | GitHub | Test matrix, adapter-ergonomics parity table, isolation invariant | **In-repo** `CONTRIBUTING.md` + `docs/architecture.md` (maintainer slice) | +| **Coding agent** | `llms.txt`, MCP, `.md` URLs | Machine-readable corpus, per-page raw markdown | Blume AI features | + +Rows 1–4 and 6 = public Blume site. Contributor row + agent config = in-repo. Maps onto `docs-governance` split. + +### Experimental-status messaging + +Library is pre-1.0 and accepts breaking majors (layer-handles renames `useLayer`→`useLayerState`, reshapes `useStack`, flips `LayerStack.find`). Three-layer approach: + +1. **Persistent `banner`** — `"Experimental — the API may change between minors. Pin your version."` (dismissible, stable `id`). +2. **Dedicated `/concepts/stability` page** — semver posture, pinning, how breaking changes are announced (→ changelog), parity promise ("all adapters move together"). +3. **Per-page callouts** on APIs in flight — `:::warning[Changing in vNext]` (e.g. handles work). + +**Opinionated stance:** lead with design maturity, not version number. The grilled decision logs (layer-handles.md is 423 lines of adversarial design review) are evidence this is _carefully_ experimental, not _unfinished_. Message: "small, sharp, and honest about churn." + +--- + +## Recommended architecture + +**Decision: `apps/docs/` as a workspace member, insulated from library quality gates.** + +Rejected alternatives: + +- **`packages/docs`** — ❌ `packages/*` is the _published-library_ namespace; zero-dep guard, `sherif`, `size-limit`, `check:pack` all assume publishable libraries. +- **Root `docs/` (Blume reads it directly)** — ❌ `docs/` is governance-owned lifecycle substrate; would leak `plans/`/`audits/`/`research/` to the public site. +- **Separate repo** — ❌ loses edit-links, monorepo colocation, `github-releases` wiring, agent-first story. + +```mermaid +flowchart TB + subgraph repo["stainless-code/layers (monorepo)"] + direction TB + subgraph pkgs["packages/* — PUBLISHED, zero-dep gated"] + core["core README\n(thin npm landing)"] + adapters["6 adapter READMEs\n(thin npm landings)"] + skills["packages/*/skills/*/SKILL.md\n(agent surface)"] + end + subgraph gov["docs/ — MAINTAINER, governance-owned (UNPUBLISHED)"] + plans["plans/ audits/ research/"] + arch["architecture.md — maintainer slice\n(invariants, test matrix)"] + gloss["glossary.md — SSOT (imported)"] + roadmap["roadmap.md"] + end + subgraph docsapp["apps/docs — Blume site (INSULATED workspace)"] + content["content/\n landing · guides · concepts · adapters · reference"] + cfg["blume.config.ts"] + pub["public/api/** ← generated TypeDoc"] + end + end + + gh["GitHub Releases\n(changesets, linked versioning)"] -->|github-releases source| content + gloss -->|filesystem include source| content + arch -.canonical concept text lifted into.-> content + content --> build["blume build"] + cfg --> build + pub --> build + build --> site["dist/ → static host\n(search · llms.txt · MCP · OG · sitemap)"] + skills -.link to.-> site + core -.link to.-> site + adapters -.link to.-> site +``` + +### Insulation checklist + +- Add `apps/*` to `workspaces` (dedup + `blume check` as docs typecheck), **but**: + - `sherif` → ignore `apps/docs` (Astro/React island deps won't match library pins). + - Root `build` already scoped (`build:core && --filter '@stainless-code/*-layers'`) — docs not swept. ✅ + - Root `test`/`test:dom`/`typecheck` use `--filter '*'`; give `apps/docs` **no** `test`/`test:dom` (skipped) and optional `typecheck: "blume check"`. + - `size-limit`, `knip`, zero-dep guard, `check:pack` — do not extend to `apps/docs`. + - **`oxfmt`:** exclude `apps/docs/content/**` **OR** apply Blume's `patches/oxfmt@0.58.0.patch` via `patchedDependencies`. + - **`lychee`:** exclude `apps/docs/**` in `lychee.toml`; use `blume validate` for docs. + - `.gitignore`: `apps/docs/.blume/`, `.blume-verify/`, `dist/`. + +--- + +## Detailed information architecture + +Use Blume **tabs** (scope sidebar). Root shows loose pages + featured links. + +``` +/ Landing (pitch, taste, when-to-use, framework picker) +/concepts/stability Experimental status, semver, pinning, parity promise + +── Tab: Guides (task-oriented, framework-parameterized via ) ── +/guides/getting-started Install → declare → mount outlet → open+await +/guides/awaiting-results await open, DataTag response inference, fire-and-forget +/guides/singletons upsert + update (toasts, progress) +/guides/serial-queues scope: serial, getQueuedSnapshot, onboarding flows +/guides/nested-overlays layer groups (useLayerGroup / createLayerGroup) +/guides/animations transition axis, enteringDelay/exitingDelay, call.settle() +/guides/dismissal-blockers blockers, dismissing flag, dismissAll modes, force +/guides/payload-validation validate (Standard Schema / fn), PayloadValidationError +/guides/error-handling Promise rejections, narrowing, isPayloadValidationError +/guides/ssr per-adapter SSR posture, client-only-today caveat + +── Tab: Concepts (canonical engine model — lifted from architecture.md) ── +/concepts/overview Core + adapter model, the package boundary +/concepts/lifecycle phase / transition / actionStatus (the three axes) +/concepts/stacks-scope-gc named stacks, serial/parallel, gcTime, upsert +/concepts/identity-and-types key vs instance id, DataTag inference, Register +/concepts/notifications notifyManager batching +/concepts/glossary Ubiquitous language (imported from docs/glossary.md — SSOT) + +── Tab: Adapters (one folder per adapter → tab-scoped sidebar) ── +/adapters/overview The parity matrix (from architecture.md § Adapter ergonomics) +/adapters/core UI-agnostic engine surface +/adapters/react Provider, useStack/useLayer, StackOutlet, createStackHook… +/adapters/preact (delta from React) +/adapters/vue provideLayerClient, StackOutlet, … +/adapters/solid LayerClientContext, create* aliases, … +/adapters/svelte runes (.) + store (./store) — two entries +/adapters/angular provideLayerClient, renderStack(vcr), inject* — divergences + +── Tab: Reference ── +/reference/overview How to read the reference; link to generated symbols +/reference/core-api Curated: LayerClient, LayerStack, layerOptions, … via +/reference/adapter-hooks Curated hook signatures (parameterized) +/reference/api/** Generated TypeDoc (served from public/, "generated" labeled) + +── Featured (always visible) ── +/changelog Auto-generated timeline from GitHub Releases +GitHub External link +``` + +**Why this shape:** Guides are _task-first_ with `` inside each page — single biggest anti-duplication lever. Adapters is _reference-per-framework_. Concepts is the _engine_. IA teaches the architecture by existing. + +--- + +## Single-source-of-truth strategy + +**Governing rule:** one concept has exactly one canonical home; every other mention is a link, never a copy. + +| Content | Canonical home | Consumed by / mechanism | Drift control | +| ----------------------------------- | ------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------- | +| Engine model | **Blume `/concepts/*`** (lifted from `architecture.md`) | Guides link; `docs/architecture.md` slimmed to maintainer slice | Content lives once | +| Glossary | **`docs/glossary.md`** | Blume filesystem include → `/concepts/glossary` | One file, two surfaces; fix links to site-absolute URLs | +| Per-adapter getting-started | **Blume `/adapters/`** | READMEs → install + taste + link | READMEs too thin to drift | +| When-to-use matrix | **Blume `/concepts/when-to-use`** | Root README teaser + link | Single authoritative matrix | +| Adapter parity matrix | **Blume `/adapters/overview`** | Everything else links | High-drift table — ONE home | +| Exhaustive symbol reference | **Generated TypeDoc** → `apps/docs/public/api/**` | Curated `/reference/*` deep-links | Regenerated in CI | +| Changelog | **GitHub Releases** | `github-releases` source | Written once | +| Agent skills | **In-repo** | Link to site concept pages | Skills reference, don't restate | +| Plans / audits / research / roadmap | **In-repo `docs/`** | `docs-governance` lifecycle | Never published | + +**Two hard calls:** + +1. **Lift `architecture.md` consumer content into Blume; demote file to maintainer slice.** `docs-governance` supports lifting when docs become public policy. +2. **Do not auto-import the 7 READMEs into Blume.** Invert: Blume adapter pages canonical; starve READMEs to install + taste + link. + +**Glossary include-source caveat:** filesystem source pointing at `../../docs` with `include: ["glossary.md"]` nests routes under a prefix and renders raw links as-is. Glossary internal links (`architecture.md#anchor`) must become site-absolute (`/concepts/lifecycle#...`) or full URLs. + +--- + +## Blume implementation spec — `apps/docs/blume.config.ts` + +See consolidated plan for the canonical draft. Opus-specific additions: + +- `github.dir: "apps/docs"` — monorepo edit-link fix. +- `search: orama` — keyless; generated TypeDoc HTML under `public/api` not in Orama index (acceptable). +- `ai.mcp` off initially; enable phase 4 with `output: "server"`. +- `lastModified: true` requires `fetch-depth: 0` in CI. + +--- + +## Content authoring workflow for contributors + +1. **Local:** `bun run docs:dev` → `blume dev` in `apps/docs`. +2. **Write** `.mdx` under `apps/docs/content/`. Use ``, ``, `:::note`, ``, `mermaid`. Frontmatter: `title`, `description`, optional `sidebar`/`search.tags`. +3. **Framework parity:** one guide, `` per adapter. Reviewers reject React-only guides that duplicate recipes. +4. **Verify (agent-safe):** `blume build --isolated` / `blume check --isolated` (`BLUME_RUNTIME_DIR=.blume-verify`). Then `blume validate`. +5. **Governance:** `authoring-discipline` + `docs-governance`. New public concept → Blume, not `docs/`. +6. **Formatter fence:** exclude `apps/docs/content/**` from `oxfmt` — do not run `bun run format` over MDX. +7. **CI job `docs`:** `blume check` + `blume build` + `blume validate`, **separate** from library `CI complete`. + +**Self-updating docs:** wire Blume's `blume-update-docs` agent skill into weekly automation — audits merged PRs/changelogs against docs, opens `docs/*` PR only on drift. + +--- + +## Release / changelog pipeline + +Current: changesets → Version PR → OIDC publish, per-package `CHANGELOG.md`. + +**Problem:** default changesets cuts **one GitHub Release per package per bump** → 7 releases/version → noisy `github-releases` timeline. + +**Recommendation — changesets linked (or fixed) versioning:** all `@stainless-code/*-layers` bump together → **one GitHub Release per version**. + +```mermaid +flowchart LR + pr["PR + changeset (.md)"] --> ver["Version Packages PR\n(changesets)"] + ver -->|merge| pub["OIDC publish to npm"] + pub --> rel["ONE GitHub Release per version\n(aggregated notes, tag vX.Y.Z)"] + rel -->|github-releases source| tl["/changelog timeline + RSS\n(rebuilt each docs deploy)"] +``` + +Requirements: + +- `GITHUB_TOKEN` in docs build/deploy env. +- Redeploy docs on `release` published. +- If per-package releases kept: timeline noisier but still works. + +--- + +## Phase plan (tracer-bullet aligned) + +### Phase 0 — Seam decision (architecture-priming) + +Adding workspace app is structurally significant. This research + consolidated plan satisfies exploration; ratify or amend. + +**Acceptance:** decision on `apps/docs` insulation + architecture.md lift documented. + +### Phase 1 — Tracer bullet + +`blume init` → `apps/docs`, minimal config, one page (`/guides/getting-started` React only), landing stub. Fence oxfmt + lychee. Root `docs:*` scripts + `docs` CI job. + +**Acceptance:** `blume build` green; `blume validate` clean; library gates unaffected; preview URL. + +### Phase 2 — Concepts (SSOT lift) + +`/concepts/*` from `architecture.md`; glossary import; `/concepts/stability` + banner; slim `docs/architecture.md`. + +**Acceptance:** one canonical page per engine concept; glossary on GitHub + site. + +### Phase 3 — Guides + Adapters + +`/guides/*` with ``; `/adapters/`; shrink 7 READMEs; update package skills to link. + +**Acceptance:** no framework-forked guide duplicates; READMEs ≤ ~30 lines prose. + +### Phase 4 — Reference + Changelog + AI + +TypeDoc → `apps/docs/public/api/**`; curated `/reference/*`; linked versioning + `github-releases`; `llms.txt` quality pass; optional MCP. + +**Acceptance:** `/changelog` populated; TypeDoc CI-generated; MCP answers sample query (if enabled). + +### Phase 5 — Polish & governance close + +OG images, landing, redirects; `blume-update-docs` automation; close plan per lifecycle. + +--- + +## Anti-patterns to avoid + +- ❌ Letting library formatter touch MDX (`oxfmt@0.58.0` collapses `:::note`). +- ❌ Running `lychee` over docs MDX (site-absolute links false-flag). +- ❌ Putting docs in `packages/` (trips zero-dep guard, sherif, size-limit, check:pack). +- ❌ Pointing Blume at root `docs/` (publishes plans/research). +- ❌ Auto-importing 7 READMEs as-is. +- ❌ Forking guides per framework. +- ❌ Hand-maintaining 130+ API pages. +- ❌ Committing generated `docs/api/**`. +- ❌ Per-package GitHub Releases → noisy changelog. +- ❌ Shallow CI checkout with `lastModified: true`. +- ❌ Blocking library CI on docs (keep jobs separate initially). + +--- + +## Unique insights (Opus) + +1. **Docs should mirror the seam — that's pedagogy.** Concepts + Adapters + Guides teaches core/adapter model through navigation. +2. **Three-axis model is the docs' hardest job** — dedicated `/concepts/lifecycle` with mermaid + `phase×transition` truth table from `architecture.md`. +3. **Agent-first repo → AI features are native distribution.** Prioritize `llms-full.txt` quality; ship MCP in phase 4. Users are coding agents. +4. **"Experimental" is a positioning asset** if framed with design rigor — stability page shows adversarial design process. +5. **Parity matrix is the biggest drift risk** — three current homes (architecture.md, 7 READMEs, site). Pick `/adapters/overview` only. +6. **`` + Twoslash for live-typed reference** — proves `DataTag` inference works in docs, not just claims it. Uniquely on-brand for this library. From 2313f1485a815035e5473913caa8fe0f8c6db657 Mon Sep 17 00:00:00 2001 From: Sutu Sebastian Date: Thu, 16 Jul 2026 12:43:58 +0300 Subject: [PATCH 02/13] docs: ship Blume public docs site at apps/docs --- .agents/README.md | 1 + .agents/lessons.md | 6 + .agents/skills/docs-governance/LIFECYCLE.md | 6 + .agents/skills/docs-governance/SKILL.md | 2 +- .agents/skills/docs-voice/SKILL.md | 69 + .agents/skills/product-tenets/SKILL.md | 46 + .agents/skills/update-docs/SKILL.md | 36 + .cursor/skills/docs-voice | 1 + .cursor/skills/product-tenets | 1 + .cursor/skills/update-docs | 1 + .github/workflows/ci.yml | 24 +- .github/workflows/deploy-docs.yml | 61 + .gitignore | 1 - .oxlintrc.json | 3 +- .sherifrc.json | 1 + AGENTS.md | 2 +- README.md | 104 +- apps/docs/.gitignore | 10 + apps/docs/.oxfmtrc.json | 9 + apps/docs/blume.config.ts | 118 ++ apps/docs/components.ts | 19 + apps/docs/components/RecipeCodeBlock.astro | 26 + apps/docs/components/blume/Footer.astro | 160 ++ apps/docs/components/blume/Pagination.astro | 63 + apps/docs/content/adapters/angular.mdx | 139 ++ apps/docs/content/adapters/core.mdx | 87 + apps/docs/content/adapters/index.mdx | 90 + apps/docs/content/adapters/meta.ts | 7 + apps/docs/content/adapters/preact.mdx | 96 + apps/docs/content/adapters/react.mdx | 110 ++ apps/docs/content/adapters/solid.mdx | 127 ++ apps/docs/content/adapters/svelte/meta.ts | 7 + apps/docs/content/adapters/svelte/runes.mdx | 128 ++ apps/docs/content/adapters/svelte/store.mdx | 133 ++ apps/docs/content/adapters/vue.mdx | 117 ++ apps/docs/content/concepts/blockers.mdx | 61 + apps/docs/content/concepts/comparison.mdx | 172 ++ apps/docs/content/concepts/glossary.mdx | 53 + .../content/concepts/identity-and-types.mdx | 81 + apps/docs/content/concepts/index.mdx | 18 + apps/docs/content/concepts/lifecycle.mdx | 81 + apps/docs/content/concepts/meta.ts | 18 + apps/docs/content/concepts/notifications.mdx | 38 + apps/docs/content/concepts/overview.mdx | 57 + apps/docs/content/concepts/stability.mdx | 26 + .../docs/content/concepts/stacks-scope-gc.mdx | 63 + apps/docs/content/concepts/when-to-use.mdx | 30 + .../content/examples/animated-enter-exit.mdx | 63 + apps/docs/content/examples/async-loadfn.mdx | 55 + apps/docs/content/examples/blockers-force.mdx | 56 + apps/docs/content/examples/confirm-dialog.mdx | 64 + apps/docs/content/examples/drawer.mdx | 63 + apps/docs/content/examples/index.mdx | 85 + apps/docs/content/examples/meta.ts | 18 + apps/docs/content/examples/nested-confirm.mdx | 65 + apps/docs/content/examples/progress.mdx | 55 + .../content/examples/route-guard-open.mdx | 56 + .../content/examples/serial-onboarding.mdx | 56 + apps/docs/content/examples/toast.mdx | 63 + apps/docs/content/guides/animations.mdx | 88 + apps/docs/content/guides/awaiting-results.mdx | 178 ++ .../content/guides/dismissal-blockers.mdx | 89 + apps/docs/content/guides/error-handling.mdx | 88 + apps/docs/content/guides/getting-started.mdx | 106 + .../content/guides/headless-rendering.mdx | 319 +++ apps/docs/content/guides/index.mdx | 41 + apps/docs/content/guides/install.mdx | 69 + apps/docs/content/guides/meta.ts | 20 + apps/docs/content/guides/nested-overlays.mdx | 189 ++ .../content/guides/payload-validation.mdx | 78 + apps/docs/content/guides/serial-queues.mdx | 85 + apps/docs/content/guides/singletons.mdx | 69 + apps/docs/content/guides/ssr.mdx | 44 + .../base-ui/animated-enter-exit.mdx | 25 + .../integrations/base-ui/confirm-dialog.mdx | 26 + .../content/integrations/base-ui/drawer.mdx | 25 + .../content/integrations/base-ui/index.mdx | 52 + .../docs/content/integrations/base-ui/meta.ts | 7 + .../integrations/base-ui/nested-confirm.mdx | 25 + .../content/integrations/base-ui/toast.mdx | 26 + apps/docs/content/integrations/index.mdx | 29 + apps/docs/content/integrations/meta.ts | 7 + .../react-aria/animated-enter-exit.mdx | 25 + .../react-aria/confirm-dialog.mdx | 26 + .../integrations/react-aria/drawer.mdx | 26 + .../content/integrations/react-aria/index.mdx | 52 + .../content/integrations/react-aria/meta.ts | 7 + .../react-aria/nested-confirm.mdx | 26 + .../content/integrations/react-aria/toast.mdx | 27 + apps/docs/content/reference/adapter-hooks.mdx | 149 ++ apps/docs/content/reference/api/index.mdx | 48 + apps/docs/content/reference/api/meta.ts | 17 + apps/docs/content/reference/core-api.mdx | 210 ++ apps/docs/content/reference/index.mdx | 24 + apps/docs/content/reference/meta.ts | 7 + apps/docs/content/reference/migration.mdx | 31 + apps/docs/content/reference/roadmap.mdx | 30 + .../docs/islands/AnimatedEnterExitExample.tsx | 144 ++ apps/docs/islands/AsyncLoadFnExample.tsx | 239 +++ apps/docs/islands/BlockersForceExample.tsx | 265 +++ apps/docs/islands/ConfirmDialogExample.tsx | 171 ++ apps/docs/islands/DrawerExample.tsx | 154 ++ apps/docs/islands/HeroDemo.tsx | 1376 +++++++++++++ apps/docs/islands/NestedConfirmExample.tsx | 218 ++ apps/docs/islands/ProgressExample.tsx | 230 +++ apps/docs/islands/RouteGuardExample.tsx | 173 ++ apps/docs/islands/SerialOnboardingExample.tsx | 222 +++ apps/docs/islands/ToastExample.tsx | 120 ++ apps/docs/islands/_overlayPortal.ts | 13 + apps/docs/package.json | 50 + apps/docs/pages/404.astro | 80 + apps/docs/pages/_home/Batteries.astro | 105 + apps/docs/pages/_home/FinalCta.astro | 42 + apps/docs/pages/_home/FrameworkTabs.astro | 170 ++ apps/docs/pages/_home/Hero.astro | 194 ++ apps/docs/pages/_home/InstallBox.astro | 27 + apps/docs/pages/_home/Stability.astro | 27 + apps/docs/pages/_home/UseCases.astro | 176 ++ apps/docs/pages/_home/adapter-snippets.ts | 305 +++ apps/docs/pages/index.astro | 52 + apps/docs/public/.htaccess | 47 + apps/docs/public/android-chrome-192x192.png | Bin 0 -> 1689 bytes apps/docs/public/android-chrome-512x512.png | Bin 0 -> 6872 bytes apps/docs/public/apple-icon.png | Bin 0 -> 1703 bytes apps/docs/public/favicon-16x16.png | Bin 0 -> 237 bytes apps/docs/public/favicon-32x32.png | Bin 0 -> 353 bytes apps/docs/public/icon.svg | 12 + apps/docs/public/icons/alpine.svg | 1 + apps/docs/public/icons/angular.svg | 1 + apps/docs/public/icons/base-ui.svg | 4 + apps/docs/public/icons/ember.svg | 1 + apps/docs/public/icons/lit.svg | 1 + apps/docs/public/icons/marko.svg | 1 + apps/docs/public/icons/preact.svg | 1 + apps/docs/public/icons/qwik.svg | 1 + apps/docs/public/icons/react-aria.svg | 1 + apps/docs/public/icons/react.svg | 1 + apps/docs/public/icons/solid.svg | 1 + apps/docs/public/icons/standard-schema.svg | 1 + apps/docs/public/icons/svelte.svg | 1 + apps/docs/public/icons/vanilla.svg | 1 + apps/docs/public/icons/vue.svg | 1 + apps/docs/public/logo.svg | 6 + apps/docs/public/site.webmanifest | 20 + .../recipes/animated-enter-exit/angular.ts | 94 + .../recipes/animated-enter-exit/preact.tsx | 84 + .../animated-enter-exit/react.baseui.tsx | 92 + .../recipes/animated-enter-exit/react.rac.tsx | 109 + .../recipes/animated-enter-exit/react.tsx | 84 + .../animated-enter-exit/react.wiring.tsx | 53 + .../recipes/animated-enter-exit/solid.tsx | 84 + .../animated-enter-exit/svelte-runes.svelte | 74 + .../animated-enter-exit/svelte-store.svelte | 80 + .../recipes/animated-enter-exit/vue-host.vue | 86 + apps/docs/recipes/animated-enter-exit/vue.vue | 135 ++ apps/docs/recipes/async-loadfn/angular.ts | 101 + apps/docs/recipes/async-loadfn/preact.tsx | 89 + apps/docs/recipes/async-loadfn/react.tsx | 89 + .../recipes/async-loadfn/react.wiring.tsx | 55 + apps/docs/recipes/async-loadfn/solid.tsx | 87 + .../recipes/async-loadfn/svelte-runes.svelte | 74 + .../recipes/async-loadfn/svelte-store.svelte | 75 + apps/docs/recipes/async-loadfn/vue-host.vue | 54 + apps/docs/recipes/async-loadfn/vue.vue | 33 + apps/docs/recipes/blockers-force/angular.ts | 159 ++ apps/docs/recipes/blockers-force/preact.tsx | 125 ++ apps/docs/recipes/blockers-force/react.tsx | 125 ++ .../recipes/blockers-force/react.wiring.tsx | 94 + apps/docs/recipes/blockers-force/solid.tsx | 131 ++ .../blockers-force/svelte-runes.svelte | 96 + .../blockers-force/svelte-store.svelte | 100 + .../recipes/blockers-force/vue-discard.vue | 20 + apps/docs/recipes/blockers-force/vue-host.vue | 40 + apps/docs/recipes/blockers-force/vue.vue | 64 + apps/docs/recipes/confirm-dialog/angular.ts | 65 + apps/docs/recipes/confirm-dialog/preact.tsx | 66 + .../recipes/confirm-dialog/react.baseui.tsx | 98 + .../docs/recipes/confirm-dialog/react.rac.tsx | 83 + apps/docs/recipes/confirm-dialog/react.tsx | 66 + .../recipes/confirm-dialog/react.wiring.tsx | 41 + apps/docs/recipes/confirm-dialog/solid.tsx | 66 + .../confirm-dialog/svelte-runes.svelte | 55 + .../confirm-dialog/svelte-store.svelte | 56 + apps/docs/recipes/confirm-dialog/vue-host.vue | 38 + apps/docs/recipes/confirm-dialog/vue.vue | 16 + apps/docs/recipes/drawer/angular.ts | 67 + apps/docs/recipes/drawer/preact.tsx | 70 + apps/docs/recipes/drawer/react.baseui.tsx | 105 + apps/docs/recipes/drawer/react.rac.tsx | 83 + apps/docs/recipes/drawer/react.tsx | 70 + apps/docs/recipes/drawer/react.wiring.tsx | 42 + apps/docs/recipes/drawer/solid.tsx | 70 + apps/docs/recipes/drawer/svelte-runes.svelte | 57 + apps/docs/recipes/drawer/svelte-store.svelte | 58 + apps/docs/recipes/drawer/vue-host.vue | 40 + apps/docs/recipes/drawer/vue.vue | 45 + apps/docs/recipes/nested-confirm/angular.ts | 125 ++ apps/docs/recipes/nested-confirm/preact.tsx | 101 + .../recipes/nested-confirm/react.baseui.tsx | 147 ++ .../docs/recipes/nested-confirm/react.rac.tsx | 125 ++ apps/docs/recipes/nested-confirm/react.tsx | 101 + .../recipes/nested-confirm/react.wiring.tsx | 73 + apps/docs/recipes/nested-confirm/solid.tsx | 100 + .../nested-confirm/svelte-runes.svelte | 70 + .../nested-confirm/svelte-store.svelte | 75 + .../docs/recipes/nested-confirm/vue-child.vue | 19 + apps/docs/recipes/nested-confirm/vue-host.vue | 33 + apps/docs/recipes/nested-confirm/vue.vue | 50 + apps/docs/recipes/progress/angular.ts | 88 + apps/docs/recipes/progress/preact.tsx | 79 + apps/docs/recipes/progress/react.tsx | 79 + apps/docs/recipes/progress/react.wiring.tsx | 75 + apps/docs/recipes/progress/solid.tsx | 84 + .../docs/recipes/progress/svelte-runes.svelte | 73 + .../docs/recipes/progress/svelte-store.svelte | 74 + apps/docs/recipes/progress/vue-host.vue | 61 + apps/docs/recipes/progress/vue.vue | 15 + apps/docs/recipes/route-guard-open/angular.ts | 75 + apps/docs/recipes/route-guard-open/preact.tsx | 76 + apps/docs/recipes/route-guard-open/react.tsx | 76 + .../recipes/route-guard-open/react.wiring.tsx | 60 + apps/docs/recipes/route-guard-open/solid.tsx | 75 + .../route-guard-open/svelte-runes.svelte | 63 + .../route-guard-open/svelte-store.svelte | 64 + .../recipes/route-guard-open/vue-host.vue | 46 + apps/docs/recipes/route-guard-open/vue.vue | 24 + .../docs/recipes/serial-onboarding/angular.ts | 113 ++ .../docs/recipes/serial-onboarding/preact.tsx | 108 + apps/docs/recipes/serial-onboarding/react.tsx | 108 + .../serial-onboarding/react.wiring.tsx | 78 + apps/docs/recipes/serial-onboarding/solid.tsx | 107 + .../serial-onboarding/svelte-runes.svelte | 92 + .../serial-onboarding/svelte-store.svelte | 93 + .../recipes/serial-onboarding/vue-host.vue | 82 + apps/docs/recipes/serial-onboarding/vue.vue | 17 + apps/docs/recipes/toast/angular.ts | 80 + apps/docs/recipes/toast/preact.tsx | 65 + apps/docs/recipes/toast/react.baseui.tsx | 92 + apps/docs/recipes/toast/react.rac.tsx | 96 + apps/docs/recipes/toast/react.tsx | 65 + apps/docs/recipes/toast/react.wiring.tsx | 43 + apps/docs/recipes/toast/solid.tsx | 69 + apps/docs/recipes/toast/svelte-runes.svelte | 70 + apps/docs/recipes/toast/svelte-store.svelte | 71 + apps/docs/recipes/toast/vue-host.vue | 36 + apps/docs/recipes/toast/vue.vue | 28 + apps/docs/scripts/rewrite-api-links.ts | 606 ++++++ apps/docs/theme.css | 47 + apps/docs/tsconfig.json | 4 + apps/docs/tsconfig.recipes-angular.json | 8 + apps/docs/tsconfig.recipes-preact.json | 16 + apps/docs/tsconfig.recipes-react.json | 13 + apps/docs/tsconfig.recipes-solid.json | 16 + apps/docs/tsconfig.recipes-svelte.json | 7 + apps/docs/tsconfig.recipes-vue.json | 8 + bun.lock | 1753 ++++++++++++++++- docs/README.md | 4 +- docs/architecture.md | 4 +- docs/glossary.md | 6 +- docs/plans/blume-docs-site.md | 443 ----- docs/research/blume-docs-glm.md | 271 --- docs/research/blume-docs-gpt.md | 281 --- docs/research/blume-docs-opus.md | 294 --- docs/roadmap.md | 6 +- lychee.toml | 11 +- package.json | 12 +- packages/angular/README.md | 231 +-- packages/angular/package.json | 2 +- .../angular/skills/angular-layers/SKILL.md | 4 +- packages/core/README.md | 192 +- packages/core/package.json | 2 +- packages/core/skills/layers/SKILL.md | 4 +- packages/core/src/dataTag.ts | 5 +- packages/preact/README.md | 176 +- packages/preact/package.json | 2 +- packages/preact/skills/preact-layers/SKILL.md | 4 +- packages/react/README.md | 168 +- packages/react/package.json | 2 +- packages/react/skills/react-layers/SKILL.md | 4 +- packages/solid/README.md | 183 +- packages/solid/package.json | 2 +- packages/solid/skills/solid-layers/SKILL.md | 4 +- packages/svelte/README.md | 387 +--- packages/svelte/package.json | 2 +- packages/svelte/skills/svelte-layers/SKILL.md | 4 +- packages/vue/README.md | 201 +- packages/vue/package.json | 2 +- packages/vue/skills/vue-layers/SKILL.md | 4 +- typedoc.json | 48 +- 289 files changed, 20558 insertions(+), 2801 deletions(-) create mode 100644 .agents/skills/docs-voice/SKILL.md create mode 100644 .agents/skills/product-tenets/SKILL.md create mode 100644 .agents/skills/update-docs/SKILL.md create mode 120000 .cursor/skills/docs-voice create mode 120000 .cursor/skills/product-tenets create mode 120000 .cursor/skills/update-docs create mode 100644 .github/workflows/deploy-docs.yml create mode 100644 .sherifrc.json create mode 100644 apps/docs/.gitignore create mode 100644 apps/docs/.oxfmtrc.json create mode 100644 apps/docs/blume.config.ts create mode 100644 apps/docs/components.ts create mode 100644 apps/docs/components/RecipeCodeBlock.astro create mode 100644 apps/docs/components/blume/Footer.astro create mode 100644 apps/docs/components/blume/Pagination.astro create mode 100644 apps/docs/content/adapters/angular.mdx create mode 100644 apps/docs/content/adapters/core.mdx create mode 100644 apps/docs/content/adapters/index.mdx create mode 100644 apps/docs/content/adapters/meta.ts create mode 100644 apps/docs/content/adapters/preact.mdx create mode 100644 apps/docs/content/adapters/react.mdx create mode 100644 apps/docs/content/adapters/solid.mdx create mode 100644 apps/docs/content/adapters/svelte/meta.ts create mode 100644 apps/docs/content/adapters/svelte/runes.mdx create mode 100644 apps/docs/content/adapters/svelte/store.mdx create mode 100644 apps/docs/content/adapters/vue.mdx create mode 100644 apps/docs/content/concepts/blockers.mdx create mode 100644 apps/docs/content/concepts/comparison.mdx create mode 100644 apps/docs/content/concepts/glossary.mdx create mode 100644 apps/docs/content/concepts/identity-and-types.mdx create mode 100644 apps/docs/content/concepts/index.mdx create mode 100644 apps/docs/content/concepts/lifecycle.mdx create mode 100644 apps/docs/content/concepts/meta.ts create mode 100644 apps/docs/content/concepts/notifications.mdx create mode 100644 apps/docs/content/concepts/overview.mdx create mode 100644 apps/docs/content/concepts/stability.mdx create mode 100644 apps/docs/content/concepts/stacks-scope-gc.mdx create mode 100644 apps/docs/content/concepts/when-to-use.mdx create mode 100644 apps/docs/content/examples/animated-enter-exit.mdx create mode 100644 apps/docs/content/examples/async-loadfn.mdx create mode 100644 apps/docs/content/examples/blockers-force.mdx create mode 100644 apps/docs/content/examples/confirm-dialog.mdx create mode 100644 apps/docs/content/examples/drawer.mdx create mode 100644 apps/docs/content/examples/index.mdx create mode 100644 apps/docs/content/examples/meta.ts create mode 100644 apps/docs/content/examples/nested-confirm.mdx create mode 100644 apps/docs/content/examples/progress.mdx create mode 100644 apps/docs/content/examples/route-guard-open.mdx create mode 100644 apps/docs/content/examples/serial-onboarding.mdx create mode 100644 apps/docs/content/examples/toast.mdx create mode 100644 apps/docs/content/guides/animations.mdx create mode 100644 apps/docs/content/guides/awaiting-results.mdx create mode 100644 apps/docs/content/guides/dismissal-blockers.mdx create mode 100644 apps/docs/content/guides/error-handling.mdx create mode 100644 apps/docs/content/guides/getting-started.mdx create mode 100644 apps/docs/content/guides/headless-rendering.mdx create mode 100644 apps/docs/content/guides/index.mdx create mode 100644 apps/docs/content/guides/install.mdx create mode 100644 apps/docs/content/guides/meta.ts create mode 100644 apps/docs/content/guides/nested-overlays.mdx create mode 100644 apps/docs/content/guides/payload-validation.mdx create mode 100644 apps/docs/content/guides/serial-queues.mdx create mode 100644 apps/docs/content/guides/singletons.mdx create mode 100644 apps/docs/content/guides/ssr.mdx create mode 100644 apps/docs/content/integrations/base-ui/animated-enter-exit.mdx create mode 100644 apps/docs/content/integrations/base-ui/confirm-dialog.mdx create mode 100644 apps/docs/content/integrations/base-ui/drawer.mdx create mode 100644 apps/docs/content/integrations/base-ui/index.mdx create mode 100644 apps/docs/content/integrations/base-ui/meta.ts create mode 100644 apps/docs/content/integrations/base-ui/nested-confirm.mdx create mode 100644 apps/docs/content/integrations/base-ui/toast.mdx create mode 100644 apps/docs/content/integrations/index.mdx create mode 100644 apps/docs/content/integrations/meta.ts create mode 100644 apps/docs/content/integrations/react-aria/animated-enter-exit.mdx create mode 100644 apps/docs/content/integrations/react-aria/confirm-dialog.mdx create mode 100644 apps/docs/content/integrations/react-aria/drawer.mdx create mode 100644 apps/docs/content/integrations/react-aria/index.mdx create mode 100644 apps/docs/content/integrations/react-aria/meta.ts create mode 100644 apps/docs/content/integrations/react-aria/nested-confirm.mdx create mode 100644 apps/docs/content/integrations/react-aria/toast.mdx create mode 100644 apps/docs/content/reference/adapter-hooks.mdx create mode 100644 apps/docs/content/reference/api/index.mdx create mode 100644 apps/docs/content/reference/api/meta.ts create mode 100644 apps/docs/content/reference/core-api.mdx create mode 100644 apps/docs/content/reference/index.mdx create mode 100644 apps/docs/content/reference/meta.ts create mode 100644 apps/docs/content/reference/migration.mdx create mode 100644 apps/docs/content/reference/roadmap.mdx create mode 100644 apps/docs/islands/AnimatedEnterExitExample.tsx create mode 100644 apps/docs/islands/AsyncLoadFnExample.tsx create mode 100644 apps/docs/islands/BlockersForceExample.tsx create mode 100644 apps/docs/islands/ConfirmDialogExample.tsx create mode 100644 apps/docs/islands/DrawerExample.tsx create mode 100644 apps/docs/islands/HeroDemo.tsx create mode 100644 apps/docs/islands/NestedConfirmExample.tsx create mode 100644 apps/docs/islands/ProgressExample.tsx create mode 100644 apps/docs/islands/RouteGuardExample.tsx create mode 100644 apps/docs/islands/SerialOnboardingExample.tsx create mode 100644 apps/docs/islands/ToastExample.tsx create mode 100644 apps/docs/islands/_overlayPortal.ts create mode 100644 apps/docs/package.json create mode 100644 apps/docs/pages/404.astro create mode 100644 apps/docs/pages/_home/Batteries.astro create mode 100644 apps/docs/pages/_home/FinalCta.astro create mode 100644 apps/docs/pages/_home/FrameworkTabs.astro create mode 100644 apps/docs/pages/_home/Hero.astro create mode 100644 apps/docs/pages/_home/InstallBox.astro create mode 100644 apps/docs/pages/_home/Stability.astro create mode 100644 apps/docs/pages/_home/UseCases.astro create mode 100644 apps/docs/pages/_home/adapter-snippets.ts create mode 100644 apps/docs/pages/index.astro create mode 100644 apps/docs/public/.htaccess create mode 100644 apps/docs/public/android-chrome-192x192.png create mode 100644 apps/docs/public/android-chrome-512x512.png create mode 100644 apps/docs/public/apple-icon.png create mode 100644 apps/docs/public/favicon-16x16.png create mode 100644 apps/docs/public/favicon-32x32.png create mode 100644 apps/docs/public/icon.svg create mode 100644 apps/docs/public/icons/alpine.svg create mode 100644 apps/docs/public/icons/angular.svg create mode 100644 apps/docs/public/icons/base-ui.svg create mode 100644 apps/docs/public/icons/ember.svg create mode 100644 apps/docs/public/icons/lit.svg create mode 100644 apps/docs/public/icons/marko.svg create mode 100644 apps/docs/public/icons/preact.svg create mode 100644 apps/docs/public/icons/qwik.svg create mode 100644 apps/docs/public/icons/react-aria.svg create mode 100644 apps/docs/public/icons/react.svg create mode 100644 apps/docs/public/icons/solid.svg create mode 100644 apps/docs/public/icons/standard-schema.svg create mode 100644 apps/docs/public/icons/svelte.svg create mode 100644 apps/docs/public/icons/vanilla.svg create mode 100644 apps/docs/public/icons/vue.svg create mode 100644 apps/docs/public/logo.svg create mode 100644 apps/docs/public/site.webmanifest create mode 100644 apps/docs/recipes/animated-enter-exit/angular.ts create mode 100644 apps/docs/recipes/animated-enter-exit/preact.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/react.baseui.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/react.rac.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/react.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/react.wiring.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/solid.tsx create mode 100644 apps/docs/recipes/animated-enter-exit/svelte-runes.svelte create mode 100644 apps/docs/recipes/animated-enter-exit/svelte-store.svelte create mode 100644 apps/docs/recipes/animated-enter-exit/vue-host.vue create mode 100644 apps/docs/recipes/animated-enter-exit/vue.vue create mode 100644 apps/docs/recipes/async-loadfn/angular.ts create mode 100644 apps/docs/recipes/async-loadfn/preact.tsx create mode 100644 apps/docs/recipes/async-loadfn/react.tsx create mode 100644 apps/docs/recipes/async-loadfn/react.wiring.tsx create mode 100644 apps/docs/recipes/async-loadfn/solid.tsx create mode 100644 apps/docs/recipes/async-loadfn/svelte-runes.svelte create mode 100644 apps/docs/recipes/async-loadfn/svelte-store.svelte create mode 100644 apps/docs/recipes/async-loadfn/vue-host.vue create mode 100644 apps/docs/recipes/async-loadfn/vue.vue create mode 100644 apps/docs/recipes/blockers-force/angular.ts create mode 100644 apps/docs/recipes/blockers-force/preact.tsx create mode 100644 apps/docs/recipes/blockers-force/react.tsx create mode 100644 apps/docs/recipes/blockers-force/react.wiring.tsx create mode 100644 apps/docs/recipes/blockers-force/solid.tsx create mode 100644 apps/docs/recipes/blockers-force/svelte-runes.svelte create mode 100644 apps/docs/recipes/blockers-force/svelte-store.svelte create mode 100644 apps/docs/recipes/blockers-force/vue-discard.vue create mode 100644 apps/docs/recipes/blockers-force/vue-host.vue create mode 100644 apps/docs/recipes/blockers-force/vue.vue create mode 100644 apps/docs/recipes/confirm-dialog/angular.ts create mode 100644 apps/docs/recipes/confirm-dialog/preact.tsx create mode 100644 apps/docs/recipes/confirm-dialog/react.baseui.tsx create mode 100644 apps/docs/recipes/confirm-dialog/react.rac.tsx create mode 100644 apps/docs/recipes/confirm-dialog/react.tsx create mode 100644 apps/docs/recipes/confirm-dialog/react.wiring.tsx create mode 100644 apps/docs/recipes/confirm-dialog/solid.tsx create mode 100644 apps/docs/recipes/confirm-dialog/svelte-runes.svelte create mode 100644 apps/docs/recipes/confirm-dialog/svelte-store.svelte create mode 100644 apps/docs/recipes/confirm-dialog/vue-host.vue create mode 100644 apps/docs/recipes/confirm-dialog/vue.vue create mode 100644 apps/docs/recipes/drawer/angular.ts create mode 100644 apps/docs/recipes/drawer/preact.tsx create mode 100644 apps/docs/recipes/drawer/react.baseui.tsx create mode 100644 apps/docs/recipes/drawer/react.rac.tsx create mode 100644 apps/docs/recipes/drawer/react.tsx create mode 100644 apps/docs/recipes/drawer/react.wiring.tsx create mode 100644 apps/docs/recipes/drawer/solid.tsx create mode 100644 apps/docs/recipes/drawer/svelte-runes.svelte create mode 100644 apps/docs/recipes/drawer/svelte-store.svelte create mode 100644 apps/docs/recipes/drawer/vue-host.vue create mode 100644 apps/docs/recipes/drawer/vue.vue create mode 100644 apps/docs/recipes/nested-confirm/angular.ts create mode 100644 apps/docs/recipes/nested-confirm/preact.tsx create mode 100644 apps/docs/recipes/nested-confirm/react.baseui.tsx create mode 100644 apps/docs/recipes/nested-confirm/react.rac.tsx create mode 100644 apps/docs/recipes/nested-confirm/react.tsx create mode 100644 apps/docs/recipes/nested-confirm/react.wiring.tsx create mode 100644 apps/docs/recipes/nested-confirm/solid.tsx create mode 100644 apps/docs/recipes/nested-confirm/svelte-runes.svelte create mode 100644 apps/docs/recipes/nested-confirm/svelte-store.svelte create mode 100644 apps/docs/recipes/nested-confirm/vue-child.vue create mode 100644 apps/docs/recipes/nested-confirm/vue-host.vue create mode 100644 apps/docs/recipes/nested-confirm/vue.vue create mode 100644 apps/docs/recipes/progress/angular.ts create mode 100644 apps/docs/recipes/progress/preact.tsx create mode 100644 apps/docs/recipes/progress/react.tsx create mode 100644 apps/docs/recipes/progress/react.wiring.tsx create mode 100644 apps/docs/recipes/progress/solid.tsx create mode 100644 apps/docs/recipes/progress/svelte-runes.svelte create mode 100644 apps/docs/recipes/progress/svelte-store.svelte create mode 100644 apps/docs/recipes/progress/vue-host.vue create mode 100644 apps/docs/recipes/progress/vue.vue create mode 100644 apps/docs/recipes/route-guard-open/angular.ts create mode 100644 apps/docs/recipes/route-guard-open/preact.tsx create mode 100644 apps/docs/recipes/route-guard-open/react.tsx create mode 100644 apps/docs/recipes/route-guard-open/react.wiring.tsx create mode 100644 apps/docs/recipes/route-guard-open/solid.tsx create mode 100644 apps/docs/recipes/route-guard-open/svelte-runes.svelte create mode 100644 apps/docs/recipes/route-guard-open/svelte-store.svelte create mode 100644 apps/docs/recipes/route-guard-open/vue-host.vue create mode 100644 apps/docs/recipes/route-guard-open/vue.vue create mode 100644 apps/docs/recipes/serial-onboarding/angular.ts create mode 100644 apps/docs/recipes/serial-onboarding/preact.tsx create mode 100644 apps/docs/recipes/serial-onboarding/react.tsx create mode 100644 apps/docs/recipes/serial-onboarding/react.wiring.tsx create mode 100644 apps/docs/recipes/serial-onboarding/solid.tsx create mode 100644 apps/docs/recipes/serial-onboarding/svelte-runes.svelte create mode 100644 apps/docs/recipes/serial-onboarding/svelte-store.svelte create mode 100644 apps/docs/recipes/serial-onboarding/vue-host.vue create mode 100644 apps/docs/recipes/serial-onboarding/vue.vue create mode 100644 apps/docs/recipes/toast/angular.ts create mode 100644 apps/docs/recipes/toast/preact.tsx create mode 100644 apps/docs/recipes/toast/react.baseui.tsx create mode 100644 apps/docs/recipes/toast/react.rac.tsx create mode 100644 apps/docs/recipes/toast/react.tsx create mode 100644 apps/docs/recipes/toast/react.wiring.tsx create mode 100644 apps/docs/recipes/toast/solid.tsx create mode 100644 apps/docs/recipes/toast/svelte-runes.svelte create mode 100644 apps/docs/recipes/toast/svelte-store.svelte create mode 100644 apps/docs/recipes/toast/vue-host.vue create mode 100644 apps/docs/recipes/toast/vue.vue create mode 100644 apps/docs/scripts/rewrite-api-links.ts create mode 100644 apps/docs/theme.css create mode 100644 apps/docs/tsconfig.json create mode 100644 apps/docs/tsconfig.recipes-angular.json create mode 100644 apps/docs/tsconfig.recipes-preact.json create mode 100644 apps/docs/tsconfig.recipes-react.json create mode 100644 apps/docs/tsconfig.recipes-solid.json create mode 100644 apps/docs/tsconfig.recipes-svelte.json create mode 100644 apps/docs/tsconfig.recipes-vue.json delete mode 100644 docs/plans/blume-docs-site.md delete mode 100644 docs/research/blume-docs-glm.md delete mode 100644 docs/research/blume-docs-gpt.md delete mode 100644 docs/research/blume-docs-opus.md diff --git a/.agents/README.md b/.agents/README.md index 64895b2..1610959 100644 --- a/.agents/README.md +++ b/.agents/README.md @@ -11,6 +11,7 @@ Source of truth for AI agent configuration. Cursor consumes via symlinks in `.cu | Tier 1 / 2 / 3 attachment modes | [rules/agents-tier-system.md](rules/agents-tier-system.md) | | Layers tier/pairing deltas | [skills/writing-agents-config](skills/writing-agents-config/SKILL.md) | | Authoring new rules/skills (meta) | [`writing-great-skills`](skills/writing-great-skills/SKILL.md) | +| Product north-star (tenets) | [`product-tenets`](skills/product-tenets/SKILL.md) | | Past corrections | [`lessons.md`](lessons.md) | | What exists on disk right now | `ls .agents/rules` · `ls .agents/skills` | diff --git a/.agents/lessons.md b/.agents/lessons.md index 8938868..70eae2c 100644 --- a/.agents/lessons.md +++ b/.agents/lessons.md @@ -20,3 +20,9 @@ alwaysApply: true - npm trusted publishing (OIDC) needs npm ≥ 11.5.1 + Node ≥ 22.14; oven-sh/setup-bun leaves npm 10.x in PATH, so a release job running `changeset publish`/`npm publish` must also run actions/setup-node (Node 24 → npm 11) or OIDC isn't detected → ENEEDAUTH. - Don't pin a GitHub action to a moving major tag's commit SHA (e.g. setup-node@) — the tag moves and orphans/GCs the commit → "unable to find version"; pin to an immutable release-tag commit or use the moving @vN tag. - Subagent model choice: use `composer-2.5-fast` for fast implementation, `glm-5.2-high` for deeper exploration/design/debate; mix or run both for hard findings. +- Format `apps/docs` non-content files at `printWidth: 80` — oxfmt uses **nearest-config-wins per file**, so the nested `apps/docs/.oxfmtrc.json` (ignore-only → default printWidth 100) shadows root `.oxfmtrc.json` (80) for every `apps/docs/*` file regardless of CLI scope; fix by adding `"printWidth": 80` to `apps/docs/.oxfmtrc.json` (or `-c .oxfmtrc.json --disable-nested-config`). `content/**` stays excluded by the nested ignore so writes won't collapse `:::note` callouts. +- The layers repo has tracked `.oxlintrc.json` + root `.oxfmtrc.json` (since the initial commit) with real plugins/rules/ignorePatterns (`.oxlintrc.json` ignores `**/*.svelte` and `**/*.vue`); merge additions into them — never overwrite/replace. Verify tracked lint/format configs via `git ls-files '*.oxlintrc*' '*oxfmt*'` before touching (3 tracked today: `.oxlintrc.json`, `.oxfmtrc.json`, `apps/docs/.oxfmtrc.json`); the "no oxlint config" explore report was wrong. +- A blume version bump needs `rm -rf .blume .blume-verify` (or a dev-server restart) before trusting build/preview output — `blume build --isolated` always regenerates the runtime, but incremental `writeIfChanged` skips, `ensureDepsLink` no-ops, `blume preview` serving an existing build, and `.blume/.astro` caches can persist stale output and silently mask new markdown/transformer features (e.g. 1.0.4 `blume:table-wrap`), reading as a false upstream regression. +- Blume ``/islands **hard-cap** live-render at React/Vue/Svelte (+Astro static) — pilot-confirmed in Blume 1.0.4 (`FRAMEWORK_BY_EXT` maps jsx/tsx→react, no solid/preact; generated `astro.config.mjs` only wires react/vue/svelte; no integration hook). Installing `@astrojs/solid-js`/`preact` is inert; `.tsx` always routes to the React renderer (Preact hooks crash, Solid renders broken via React). Non-React recipes are permanently code-only; Vue preview needs `@astrojs/vue` + the `vue.vue` SFC compile fix. (Astro officially also supports Preact/SolidJS/Alpine/Lit; Angular/Qwik community — Blume exposes a strict subset.) [components](https://useblume.dev/docs/content/components), [astro frameworks](https://docs.astro.build/en/guides/framework-components/#official-front-end-framework-integrations). +- Recipes are `?raw`-imported, so `blume build` never typechecks them — gate with `bun run typecheck:recipes` in `apps/docs` (per-framework `tsconfig.recipes-*.json` + `tsconfig.solid.json`/`tsconfig.preact.json` via `vue-tsc`/`svelte-check`/`tsc`; wired into CI as root `typecheck`). (Supersedes the old solid/preact-no-`export default` + `vue.vue` SFC-compile bullet — both fixed; gate is live and green.) +- Recipe files keep their framework-native extension (`vue.vue`, `svelte-runes.svelte`, `angular.ts`) — renaming a Vue SFC to `vue.ts` makes oxlint parse `