Stacks v0.5 — interactive stack builder, GitHub App write path, full registry browse
Ship the Stacks feature end-to-end: a public catalog of who's using what, OAuth-gated edit at /people/{handle}/stack/edit, a Svelte StackBuilder that buffers drafts in localStorage and publishes via direct commit through a GitHub App bot, and a registry-wide browse at /stacks/see-all-tools so members can read the catalog without having to add tools to their own stack first. Plus the home page reflows: the Dojo cards explainer moves to a new /about placeholder, leaving the home column uniform with the hero.
Changelog — 2026-04-28 (02)
Stacks v0.5
This entry consolidates the full Stacks feature, which landed across several commits over the last 36 hours without its own changelog: b2789eb (initial read path), b42ef4f (write path + Svelte + GitHub App bot), af9d30e (tool registry seed + roster), a9da596 (header popdown + AlertDisplay), and the polish landing in this commit.
Why Care?
The Agentic VC Dojo's launch webinar is in <2 days. The whole point of the dojo is to make it easy for venture professionals to share what they're actually using — and to learn from each other's setups. Until this feature, the site was read-only marketing copy. Now it's a working community surface: members log in with GitHub, build their stack interactively, and a bot publishes a commit to lossless-group/fullstack-vc:main on submit. Vercel rebuilds in ~30 seconds and the public /people/{handle} profile updates. No database, no Auth0, no Notion sync — markdown files in a git repo all the way down, in line with the firm thesis that AI tools work best on markdown and JSON.
What Got Built
Read path (public, static)
/people/[handle]— per-participant profile rendering current / aspirational / abandoned stacks viaParticipantStackView. Headshot priority: explicitheadshot:field →github_avatar./people— directory of members with public profiles./stacks— community-aggregate front door. Shows the most-adopted tools in current use (top 8) and members with public stacks./stacks/see-all-tools(new this commit) — flat alphabetical listing of every entry in the registry, with adoption-count annotations on tools that show up in someone'scurrent_stack. Front-door surfaces only the most-adopted handful; this page makes the whole registry browseable without having to add tools to your own stack first.ToolCard,ParticipantCard,ParticipantStackView— display components, mode-aware semantic tokens, no JS. All cataloged in/design-system.
Tool registry seed
~14 entries seeded so far, copy-pasted from the Lossless Obsidian
Tooling/*vault (Astro, Svelte, Claude Code, Cursor, Windsurf, Ghostty, n8n, CrewAI, Hermes, Pi-Dev, Bolt, Ideogram, Obsidian, Jina, ImageKit, Fallow Tools).Schema is a strict superset of the Obsidian Tooling frontmatter (Jina + OpenGraph fetch pipeline) so files paste in unchanged.
Tool schema fix (this commit)
The schema declared OG-prefixed names (og_image, og_favicon, url_aliases) but Obsidian source files use the bare names (image, favicon, aliases). .passthrough() masked the issue (files validated), but typed renderers querying data.og_image silently missed data stored under image, so e.g. Ghostty's favicon never rendered. Fixed by:
Adding bare-name fields to the Zod schema as first-class typed properties (
image,favicon,aliases,hero_image_url), plus typed entries for the fields that were passing through unannotated (docs_url,github_profile_url,github_repo_url,product_of,publish).Renderer fallback in
ToolCard.astro:og_screenshot_url ?? og_image ?? image ?? hero_image_url;og_favicon ?? favicon.Same fallback in
/api/tools.json.tsso the StackBuilder picker typeahead inherits favicons.
The schema is now an actual strict superset of the Obsidian Tooling frontmatter, as the spec promised.
Auth (Phase 1: GitHub OAuth, hand-rolled)
/api/auth/github/{login,callback}+/api/auth/logout— three endpoints, ~100 LOC, no Auth0 / Clerk / Lucia. Session is ajose-signed JWT in an HttpOnly cookie.Roster match is by GitHub handle first, with email fallback for registrants not yet roster'd by handle (most webinar attendees are roster'd by email only).
LinkedIn OIDC scaffolded but not yet wired into the public flow.
Write path (the no-DB challenge, solved)
StackBuilder.svelte— the only interactive island on the site. Editscurrent_stack(v1 scope); aspirational + abandoned tiers are hand-edited in the participant.mdfor now. Buffers every keystroke tolocalStorage["stack-draft:{handle}"]so refresh / navigate / close-tab doesn't lose work. 5-min idle threshold + visibility-loss event both trigger best-effort auto-save.POST /api/stack/save— Zod validation, frontmatter merge that preserves UI-untouched fields (so editing the current stack doesn't blow away your aspirational stack), retry-on-409 for SHA conflicts.GitHub App bot auth — App ID + Installation ID + Private Key (PKCS#1 or PKCS#8, both handled via Node
crypto.createPrivateKey()+joseSignJWT). Lazy env reads so HMR picks up.envchanges without restart.Direct commit to
mainwith prefixdata(stack):for filterable git history (git log --invert-grep "^data"filters the noise so feature commits stay readable). PR + auto-merge was the spec's original Phase 1; direct-commit was chosen for v0.5 to ship inside the 36hr launch window. PR-with-auto-merge becomes a v0.6 hardening pass.scripts/smoke-test-github-app.ts— direct READ + WRITE auth check, no dev-server needed. Saved hours when debugging the App ↔ Installation handshake.
Header surfaces (prev commit a9da596)
JumboPopdown__More— third sibling popdown alongside Groups and Projects. Static items (Stacks, People) under a "More" trigger.AlertDisplay— inline announcement bar with primary→secondary gradient and an×dismiss button. Per-id session-scoped dismissals viasessionStorage. The home page now opens with one clarifying that "FullStack VC is NOT a VC."Top utility strip with an
Aboutlink (above the main nav row, hidden on mobile).Mobile drawer — gained Stacks, People, About entries.
Home / About page split (this commit)
The new Section__HowItWorks plus the home hero conflicted on column width — the section's three-card explainer wanted ~1100px, the hero wanted max-w-4xl. Resolution: extract the cards into Section__DojoComponents (kept at 72rem) and ship it on a new /about placeholder page. The home page now reads as a single uniform column hero → Dojo intro + hierarchy diagram → "Learn more about the Dojo →" → footer. Section__HowItWorks accepts an optional hideMore prop so the about page can suppress the self-referencing link.
Design System catalog
Per the design-system maintenance motion, every component introduced lands in /design-system in the same change. Added in this batch: JumboPopdown__More, AlertDisplay, both with their own demo subpages.
Behavior
All read paths are fully static at build time. The only server endpoints are
/api/auth/*and/api/stack/save.Submit → commit → Vercel rebuild → live ≈ 30 seconds.
StackBuilder draft survives a tab close until the user explicitly clears
localStorage.Roster mismatch (logged-in GitHub user not on the Kauffman list) lands on a friendly
/login/not-on-rosterpage rather than the edit screen.The bot writes only ever start with
data(...)so feature-commit history stays scannable.
Decisions Encoded That Revise the Original Spec
URL structure: canonical per-person path is
/people/[handle](not/stack/people/[handle]); aggregate front door is/stacks(plural)./stack/meis preserved as a backward-compat redirector.Direct-commit chosen over PR + auto-merge for v0.5 launch velocity. Audit-trail concerns become a v0.6 hardening pass.
/stacks/see-all-toolsadded because the front-door page caps at the top 8, which made registry browsing impossible without first adding a tool to your own stack.
Open Work for v0.6
Aspirational + abandoned tier editing in StackBuilder (current_stack only today).
Free-text "add a tool not in registry" → save creates
tools/{slug}.mdplaceholder + participant file in the same submit.Per-tool detail page (
/stacks/tools/[slug]) that renders the tool's body markdown.Full
/stacksaggregate: heatmap (categories × tools, intensity = adoption count), leaderboards, sparklines fromadded:dates.PR-with-auto-merge write path for audit-trail value.
Cohort views (
/stack/cohorts/kauffman-[year]).AI-assisted tool metadata enrichment (Browserless + LLM agent for tool YAML autogen from a URL).
Verification
pnpm build— clean across all routes, including/stacks/see-all-tools,/about,/design-system/components/alert-display,/design-system/components/jumbo-popdown-more.Tool schema fix verified by inspecting Ghostty's card on
/stacks/see-all-tools— favicon now renders (was previously blank because the file usesfavicon:notog_favicon:).StackBuilder smoke-tested end-to-end: log in via GitHub OAuth → /people/mpstaton/stack/edit → drag a tool → wait 5 minutes → idle auto-save fires → page refresh → draft restored from localStorage → submit → commit lands on main with
data(stack):prefix → Vercel rebuilds → public/people/mpstatonreflects the change.scripts/smoke-test-github-app.tsconfirms App credentials independently of the dev server.
