Public presentation layer — project showcase, infrastructure dashboard, curated changelog, and internal wiki.
ABOUT
FEATURES
SHIPPED
- ✓Field Station intelligence dashboardMAY 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 tofn_enrichments - Implementation trigger live (
trig_01CZNzNJAwgZQynAhUu7EL4s) — daily 8am EDT, reads approved items, generates implementation artifacts inaction_detailsJSONB - Field Station intelligence dashboard shipped — see ship entry for full detail
Infrastructure
- CCR trigger prompts include explicit
CRON_SECRETheader 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_detailsJSONB 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 pushfails 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/reviewPOST route writes tofn_enrichmentsviaSUPABASE_SERVICE_ROLE_KEY— anon key correctly excluded from write path--intel-*CSS variables scoped inglobals.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/80outputs solid color) — inlinestyleprops 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/peerendpoint from Naptown Labs ProjectIconimages still pending atpublic/icons/insert-release-note.tsschema mismatch — script usesbody/released_atbut table hascontent/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
/shipextended with guide update/create prompt after vault check — fires whenever a feature is marked shipped/wrapextended with ship check — scans for shippable commits before drafting the session entry, closing the/wrap→/ship→ guide update chain
Infrastructure
sync-wiki-state.tsextended withisFeatureCommit(),getGuideLastUpdated(), andsyncGuideDrift()— runs on every push via the existing pre-push hookguide_last_updated(timestamptz) andguide_drift_count(int, -1 = no guide) added toproject_statetable in the save-state Supabase projectWIKI_DIR_OVERRIDEmap added to handle project ID → wiki directory mismatches (current-os→life-automation)- Codec added to
PROJECT_PATHS— drift tracking now covers 10 projects
Lessons
project_statelives in the save-state Supabase project, not the nrisacher-lang project — the dashboard defaults to the wrong one- Reading
git logbefore 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: trueon 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/peerlive atunderstorylabs.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: Bearerheader — 401 on missing or invalid token, validated againstPEER_API_KEYenv var before any Supabase queries run - Stack field derived from
connectionsJSONB —servicevalues 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_KEYadded to Vercel production and.env.local- Vercel deploy confirmed —
/api/peerregisters as a dynamic route (ƒ) in build output, aliased tounderstorylabs.co
Lessons
- A new file showing "nothing to commit" in
git statususually means a parallel session already committed it — checkgit show HEAD --statbefore 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-naptownsource module — scan handler,intel_sourcesrow, diff logic against previous snapshot - Exchange
PEER_API_KEYwith Nathan so he can callunderstorylabs.co/api/peer
UNDERSTORY-LABS-SITEinfrastructuretoolingfeature
Wiki maintenance layer — automated status sync, Supabase infra map, JSON tech radar
Features
projects.statusnow auto-inferred bysync-wiki-state.ts— active (≤30 days), paused (>30 days), planned (no state row);completeis protected from overwrite and must be set manuallykitchen-moduleinherits status fromcurrent-osviaSTATUS_INHERITS_FROMmap — child projects track parent activity instead of syncing independently- Infra map migrated from hardcoded arrays to Supabase —
infra_nodestable withtype/parent_idhierarchy 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;movedfield added per ThoughtWorks standard claude-codeproject added to sync pipeline —~/.claudeis a git repo, now tracked alongside the other 9 projects
Infrastructure
infra_nodestable created in Supabase with RLS enabled —SELECTpolicy grants anon key read access; all 4 node types (compute, service, monitoring, external) seeded from prior hardcoded dataprojects_status_checkconstraint updated to includecomplete— original constraint only allowed active/paused/plannedwiki/tech/page.tsxdropsforce-dynamic— JSON import makes the page statically generated at build timebackfill-wiki-activity.tsandseed-wiki-life-automation.tscommitted to save-state repo —claude-codemissing frombackfillPROJECT_PATHS, add before running
Lessons
- Supabase check constraints don't inherit from TypeScript types — a
ProjectStatustype withcompletedoesn'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-dynamicadds 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_PASSWORDenv var checked alongsideWIKI_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: 100vhkeeps 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\nsuffix, silently failing login; fixed withprintf '%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 usesauto-fillfor fluid adaptation - Landing page layout (
/wiki) uses dedicatedwiki-landing-bodytwo-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\nto 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: autoon a container creates its own scroll context —position: stickychildren 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.tsscript,/shipStep A3.5 wired to prompt on every feature shipped - Connections panel on each project page — service name, type badge, usage note, and
⬡ vault_pathlinking tovault.rootstack.dev; seeded for all 7 projects with service URLs and Vaultwarden paths update-connection.tsscript — patches a single connection entry (add, update, or remove) by substring match without touching raw JSON;/shipStep A3.6 now prompts for vault path whenever new credentials are created
Infrastructure
sync-wiki-state.ts— readsgit log -1from all 7 local repos, upsertsproject_state(branch, commit, timestamp), inserts commit activity events only when hash changes;--dry-runand--project-idflags supportedwiki-sync.jsPostToolUse hook — fires aftergit commitin Claude Code, spawns sync non-blocking and unref'd; registered insettings.jsononBash(git commit:*)/startskill updated to surface the sync command when wiki state may be stale after recent commitsconnectionsJSONB column added toprojectstable; SQL seed covers all 7 projects;wiki.tsSELECT queries updated in bothgetAllWikiProjectsandgetWikiProject
Bug Fixes
2>/dev/nullinexecSyncgit commands silently fails on Windows cmd — replaced withstdio: ['pipe', 'pipe', 'pipe']to suppress stderr cross-platform- Top-level
awaitin tsx script fails with "cjs output format" error — wrapped inasync function main()+main().catch()to match the existing script pattern across the repo - SQL apostrophe in
Nathan'sbroke the connections seed — escaped toNathan''s
Lessons
2>/dev/nulldoes not suppress stderr fromexecSyncon Windows cmd —stdio: ['pipe', 'pipe', 'pipe']is the cross-platform fix- Top-level
awaitin a tsx script throws "cjs output format" unless the package has"type": "module"— theasync 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/rscis the correct App Router import path —next-mdx-remotedirectly does not work in server components