← HOME

PROJECT

Understory Labs

ACTIVE

Next.jsTypeScriptTailwindSupabaseVercel

ABOUT

Public presentation layer — project showcase, infrastructure dashboard, curated changelog, and internal wiki.

FEATURES

SHIPPED

  • Field Station intelligence dashboard
    MAY 2026

CHANGELOG

UNDERSTORY-LABS-SITEfeatureaiinfrastructure

Field Notes pipeline complete — all 5 steps, end-to-end live

Features

  • Field Notes pipeline end-to-end operational — GitHub Trending scan → enrichment → Field Station review → implementation
  • Enrichment trigger live (trig_01S3L3aKyThqy4aKPTyMVgUq) — Monday 10am EDT, reads unprocessed items, runs three-lens analysis, writes to fn_enrichments
  • Implementation trigger live (trig_01CZNzNJAwgZQynAhUu7EL4s) — daily 8am EDT, reads approved items, generates implementation artifacts in action_details JSONB
  • Field Station intelligence dashboard shipped — see ship entry for full detail

Infrastructure

  • CCR trigger prompts include explicit CRON_SECRET header and Supabase URL — remote agents have zero local env access, all context must be in the prompt
  • Implementation trigger v1 stores note content in action_details JSONB rather than committed files — CCR can clone the repo but cannot push without a GitHub PAT configured in the trigger prompt

Lessons

  • CCR agents run in a fully isolated cloud environment — they can read the cloned repo but git push fails without a PAT explicitly embedded in the trigger prompt; design around this constraint rather than assuming git write access
UNDERSTORY-LABS-SITESHIPPEDfeatureailaunch

Field Station shipped — intelligence dashboard at /intel

Features

  • Field Station intelligence dashboard shipped at /intel — surfaces AI-enriched items from the field-notes pipeline for weekly review
  • Two-panel layout: 220px sticky source sidebar with amber active state + scrollable content area; source tabs collapse to a horizontal strip on mobile
  • Three-lens scoring per item — Signal (amber), Learning (teal), Relevance (green), each on a 1–10 bar with fill transition and glow
  • ItemCard expands three sections on demand — Why Trending, Insights, Relevance — each collapsed by default to keep the digest scannable
  • Approve / Reject review flow per item — confirm step with optional note field, optimistic state update, reverts on server error
  • Sort and filter bar sticks below the briefing header — sort by any score axis, filter by enrichment status (all / pending / approved / rejected)
  • Own visual identity distinct from the Cybernetic Nature main site — --intel-bg-deep #0f1117, Instrument Serif (editorial display), Geist Sans/Mono (UI + data labels), amber bridges to site accent

Infrastructure

  • /api/intel/review POST route writes to fn_enrichments via SUPABASE_SERVICE_ROLE_KEY — anon key correctly excluded from write path
  • --intel-* CSS variables scoped in globals.css — no color collisions with main site palette
  • Instrument Serif, Geist Sans, and Geist Mono added to root layout via next/font/google

Lessons

  • Tailwind v4 CSS variable tokens don't participate in opacity modifiers (bg-intel-bg/80 outputs solid color) — inline style props with raw CSS variables are the correct pattern for scoped design systems that aren't in the Tailwind config
  • Service role key must be a non-NEXT_PUBLIC_ env var in Vercel; the public key won't pass RLS write policies regardless of how the client is constructed

TODO

  • Peer Sync source card design exists but source is not live — awaiting the peer /api/peer endpoint from Naptown Labs
  • ProjectIcon images still pending at public/icons/
  • insert-release-note.ts schema mismatch — script uses body/released_at but table has content/published_at; fix when release notes are next used
UNDERSTORY-LABS-SITEfeaturetoolinginfrastructure

Wiki user guide system — six projects documented with drift detection

Features

  • HOW TO USE page type added to the wiki — renders first on every project page, above architecture, always expanded
  • Staleness indicator wired to drift data — "last updated X ago — N feature commits since" shown when a guide has fallen behind feature work
  • Commit-specific drift classification: feat:, ui:, design:, ship: prefixes trigger staleness; fix:, refactor:, chore: do not
  • Six project user guides written: life-automation (full Kitchen Module + companion + Home Projects coverage), kitchen-module, save-state, bud, codec, bark
  • /ship extended with guide update/create prompt after vault check — fires whenever a feature is marked shipped
  • /wrap extended with ship check — scans for shippable commits before drafting the session entry, closing the /wrap/ship → guide update chain

Infrastructure

  • sync-wiki-state.ts extended with isFeatureCommit(), getGuideLastUpdated(), and syncGuideDrift() — runs on every push via the existing pre-push hook
  • guide_last_updated (timestamptz) and guide_drift_count (int, -1 = no guide) added to project_state table in the save-state Supabase project
  • WIKI_DIR_OVERRIDE map added to handle project ID → wiki directory mismatches (current-oslife-automation)
  • Codec added to PROJECT_PATHS — drift tracking now covers 10 projects

Lessons

  • project_state lives in the save-state Supabase project, not the nrisacher-lang project — the dashboard defaults to the wrong one
  • Reading git log before writing a project's guide surfaces shipped work you've forgotten — codec had Layer 2 Steps 1–2 live; the guide would have listed them as planned
  • replace_all: true on Edit only catches the first match when a formatter has changed indentation on a second occurrence — target the second block directly
UNDERSTORY-LABS-SITEfeatureinfrastructuretooling

Peer API — outbound endpoint live, field-notes sync architecture

Features

  • /api/peer live at understorylabs.co/api/peer — read-only outbound JSON endpoint returning project states, recent activity, and releases; consumed by Nathan's Claude Code setup
  • Bearer token auth via Authorization: Bearer header — 401 on missing or invalid token, validated against PEER_API_KEY env var before any Supabase queries run
  • Stack field derived from connections JSONB — service values deduplicated into an array; no schema change required
  • Peer sync architecture finalized — outbound lives here, inbound (weekly fetch, snapshot storage, diff logic, briefings) belongs in field-notes as a source module; brief at ~/.claude/plans/field-notes-peer-sync-brief.md

Infrastructure

  • PEER_API_KEY added to Vercel production and .env.local
  • Vercel deploy confirmed — /api/peer registers as a dynamic route (ƒ) in build output, aliased to understorylabs.co

Lessons

  • A new file showing "nothing to commit" in git status usually means a parallel session already committed it — check git show HEAD --stat before assuming a gitignore issue
  • A peer API doesn't need to match a pre-agreed schema when the source is richer — Nathan's API returns full markdown session logs with features, bug fixes, and lessons; consuming it directly outperforms translating to a flattened contract

TODO

  • field-notes: implement peer-naptown source module — scan handler, intel_sources row, diff logic against previous snapshot
  • Exchange PEER_API_KEY with Nathan so he can call understorylabs.co/api/peer
UNDERSTORY-LABS-SITEinfrastructuretoolingfeature

Wiki maintenance layer — automated status sync, Supabase infra map, JSON tech radar

Features

  • projects.status now auto-inferred by sync-wiki-state.ts — active (≤30 days), paused (>30 days), planned (no state row); complete is protected from overwrite and must be set manually
  • kitchen-module inherits status from current-os via STATUS_INHERITS_FROM map — child projects track parent activity instead of syncing independently
  • Infra map migrated from hardcoded arrays to Supabase — infra_nodes table with type/parent_id hierarchy replaces three static constants; grid column count adapts dynamically to container count
  • Tech radar extracted from hardcoded page to src/data/tech-radar.json — edit the file to update, commit to version-track ring movements; moved field added per ThoughtWorks standard
  • claude-code project added to sync pipeline — ~/.claude is a git repo, now tracked alongside the other 9 projects

Infrastructure

  • infra_nodes table created in Supabase with RLS enabled — SELECT policy grants anon key read access; all 4 node types (compute, service, monitoring, external) seeded from prior hardcoded data
  • projects_status_check constraint updated to include complete — original constraint only allowed active/paused/planned
  • wiki/tech/page.tsx drops force-dynamic — JSON import makes the page statically generated at build time
  • backfill-wiki-activity.ts and seed-wiki-life-automation.ts committed to save-state repo — claude-code missing from backfill PROJECT_PATHS, add before running

Lessons

  • Supabase check constraints don't inherit from TypeScript types — a ProjectStatus type with complete doesn't mean the DB constraint allows it; the constraint must be explicitly updated to match
  • Static generation is appropriate for config-file-backed pages — force-dynamic adds server overhead with no benefit when the data source is a committed JSON file
UNDERSTORY-LABS-SITEfeatureinfrastructure

Wiki enrichment — MDX content, guest access, responsive layout redesign

Features

  • Architecture and Decision Log MDX content written for all 7 remaining projects — save-state, bark, bud, taproot, lore, understory-labs-site, claude-code; every wiki project page now renders populated Architecture and Decision Log sections
  • Guest password support added to wiki login — WIKI_GUEST_PASSWORD env var checked alongside WIKI_PASSWORD; both produce the same HMAC auth cookie
  • Wiki project page layout redesigned — asymmetric two-column replaced with horizontal metadata card row (Operational, Connections, Related Projects) above full-width content sections capped at 700px for readable line length
  • Wiki sidebar now sticky — position: sticky; top: 0; height: 100vh keeps navigation visible while content scrolls
  • Content area centered on wide screens — layout wrapper handles centering via flexbox with 1100px max-width

Bug Fixes

  • Heredoc (<<<) appends trailing newline to Vercel env var values — guest password stored with \n suffix, silently failing login; fixed with printf '%s' 'value' | vercel env add

Infrastructure

  • Responsive CSS classes (wiki-project-stats, wiki-card-row, wiki-landing-body) replace inline grid styles — stats grid collapses to 2-col at 900px, 1-col at 500px; card row uses auto-fill for fluid adaptation
  • Landing page layout (/wiki) uses dedicated wiki-landing-body two-column grid — Active Projects + Recent Activity have balanced content that suits side-by-side display, unlike the project detail page

Lessons

  • <<< (bash here-string) appends \n to piped values — invisible in shell output, breaks exact-match password comparisons; printf '%s' strips the newline
  • Different page types need different layouts — the wiki landing page has balanced columns (projects + activity), but the project detail page has asymmetric content (2000px of MDX vs one small card); forcing one grid pattern on both creates dead space or buried content
  • overflowY: auto on a container creates its own scroll context — position: sticky children inside it stick relative to that container, not the viewport; removing it restores expected sticky behavior
UNDERSTORY-LABS-SITEfeatureinfrastructuretooling

Wiki complete — project pages, cross-project views, release notes, and auto-sync

Features

  • Per-project wiki pages live at /wiki/[project-id] — header with clickable vault link, at-a-glance stats grid, checklist with progress bar, activity feed, MDX slots for architecture and decision log, release notes preview
  • Three cross-project views: Activity timeline (events grouped by recency), Infra Map (Taproot LXC container hierarchy + external services tier), Tech Radar (adopt/trial/assess/hold rings across 6 categories with project tags)
  • Release notes system — full timeline at /wiki/[project-id]/releases, insert-release-note.ts script, /ship Step A3.5 wired to prompt on every feature shipped
  • Connections panel on each project page — service name, type badge, usage note, and ⬡ vault_path linking to vault.rootstack.dev; seeded for all 7 projects with service URLs and Vaultwarden paths
  • update-connection.ts script — patches a single connection entry (add, update, or remove) by substring match without touching raw JSON; /ship Step A3.6 now prompts for vault path whenever new credentials are created

Infrastructure

  • sync-wiki-state.ts — reads git log -1 from all 7 local repos, upserts project_state (branch, commit, timestamp), inserts commit activity events only when hash changes; --dry-run and --project-id flags supported
  • wiki-sync.js PostToolUse hook — fires after git commit in Claude Code, spawns sync non-blocking and unref'd; registered in settings.json on Bash(git commit:*)
  • /start skill updated to surface the sync command when wiki state may be stale after recent commits
  • connections JSONB column added to projects table; SQL seed covers all 7 projects; wiki.ts SELECT queries updated in both getAllWikiProjects and getWikiProject

Bug Fixes

  • 2>/dev/null in execSync git commands silently fails on Windows cmd — replaced with stdio: ['pipe', 'pipe', 'pipe'] to suppress stderr cross-platform
  • Top-level await in tsx script fails with "cjs output format" error — wrapped in async function main() + main().catch() to match the existing script pattern across the repo
  • SQL apostrophe in Nathan's broke the connections seed — escaped to Nathan''s

Lessons

  • 2>/dev/null does not suppress stderr from execSync on Windows cmd — stdio: ['pipe', 'pipe', 'pipe'] is the cross-platform fix
  • Top-level await in a tsx script throws "cjs output format" unless the package has "type": "module" — the async function main() + main().catch() pattern is required, not stylistic
  • Supabase's "UPDATE without WHERE" safety warning fires on any query containing UPDATE, even when every statement has a WHERE clause — blanket check, not a smart one
  • next-mdx-remote/rsc is the correct App Router import path — next-mdx-remote directly does not work in server components