@seldonframe/mcp 1.30.1 → 1.38.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,38 @@
1
1
  {
2
2
  "name": "@seldonframe/mcp",
3
- "version": "1.30.1",
3
+ "version": "1.38.4",
4
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.38.4: VISUAL-POLISH BUNDLE — fixes the four issues that kept Hill Mountain Roofing from being 10/10. Generation quality was already at the $10k bar (Hormozi headline + per-business gallery + verbatim testimonials all rendered correctly in v1.38.3); this ship fixes the presentation layer. (1) LIGHT-MODE-BY-DEFAULT for customer-facing surfaces. The pre-1.38.4 PublicThemeProvider only set --sf-* CSS variables; layout components increasingly use Tailwind utility classes (bg-card, text-foreground, bg-muted/15) which resolve to --card / --foreground / --muted-foreground controlled GLOBALLY by the .dark class on <html>. So flipping our theme.mode = 'light' updated --sf-bg to white but bg-card stayed dark, leaving half the page rendered against the global dark cascade. v1.38.4 adds a className='light' wrapper on /l/[orgSlug]/[slug]/page.tsx + book/[orgSlug]/[bookingSlug]/page.tsx to locally disable the global .dark cascade, AND extends themeToCSS to also set the shadcn-convention vars (--background, --foreground, --card, --card-foreground, --muted, --muted-foreground, --border, --input, --ring, --popover, --popover-foreground, --accent, --accent-foreground, --primary, --primary-foreground, --secondary, --secondary-foreground, --destructive, --destructive-foreground) so Tailwind utilities resolve to our intended palette. Two layers of defense — both required because Tailwind v4's :where() selectors otherwise win against inline-styled vars. Same fix kills booking page dark mode (the v1.36.3 bug we'd been failing to root-cause). (2) HERO IMAGE NOW RENDERS. Pre-1.38.4 hero.tsx used next/image, which silently fails when the source domain isn't in next.config.js images.remotePatterns. Hill Mountain Roofing's hero showed alt-text instead of the Unsplash photo because images.unsplash.com wasn't allowlisted. v1.38.4 (a) switches hero to raw <img> with referrerPolicy='no-referrer' + loading='eager' (same pattern project-gallery.tsx already used), AND (b) adds images.remotePatterns for images.unsplash.com / source.unsplash.com / *.public.blob.vercel-storage.com / *.app.seldonframe.com as defense-in-depth for any future next/image usage. (3) DYNAMIC SERVICE ICONS. Pre-1.38.4 services-grid.tsx hardcoded <Sparkles> on every card — even when the LLM generated distinct icon names per service, the component ignored them. v1.38.4 adds a 35-entry name→lucide-component ICON_MAP plus aliases (storm→CloudRainWind, repair→Wrench, install→Hammer, emergency→Zap, warranty→BadgeCheck, etc.) and a normalized-lookup resolver that handles 'BadgeCheck' / 'badge-check' / 'badge_check' equivalently. Each service card now picks its own icon based on the LLM's icon string. Falls back to <Sparkles> on unknown names so a stale icon string never breaks the render. (4) Defense-in-depth on PublicThemeProvider already covered above. NO new env vars. NO migrations. Backend redeploy required. EXPECTED IMPACT: Hill Mountain Roofing test reproduced with v1.38.4 should render light-mode landing + booking, real Unsplash hero photo in the right column, distinct icons across the 7 service cards, and a clearly-light booking calendar where future dates are visually distinguishable from past dates. 9.5/10 first-shot. Remaining gap to 10/10 = operator-supplied logo + real photos.",
5
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.38.3 (bundles 1.38.1 + 1.38.2 + 1.38.3): three quality-bar blocks shipped together. (1.38.1) NEW projectGallery block — masonry grid of 6 stock photos auto-fetched per service via Unsplash from queries Claude generates inside enhance-blocks. Closes the 'feels populated' gap that's the single biggest visible difference between a generic SF workspace and a real-business landing page. NEW src/components/landing/sections/project-gallery.tsx (responsive 2/3/4 col, hover-lift + zoom interaction, optional caption-on-hover, optional bottom CTA). NEW src/lib/crm/personality-images.ts → resolveGalleryImageUrlsForQueries() helper — square 800x800 thumbs via Unsplash API (when UNSPLASH_ACCESS_KEY env set) with deduplication across queries (avoids 6 services all returning the same generic photo) + keyless source.unsplash.com fallback with per-query random seed. enhance-blocks prompt extended with 'Gallery queries' section that teaches Claude to generate 6 vertical-specific Unsplash queries (e.g. for HVAC: 'hvac technician outdoor unit', 'ductwork installation', 'thermostat residential' — bias toward queries that return DIFFERENT photos). projectGallery section emitted between process and serviceArea in the LandingPageSection[] order. (1.38.2) NEW stickyMobileCTA block — fixed bottom-of-screen Call/Book bar, MOBILE ONLY (md:hidden via Tailwind). Industry-standard for trades sites with measured 2-3x mobile booking lift (Cal.com, Calendly, Mr. Rooter, Roto-Rooter precedent). NEW src/components/landing/sections/sticky-mobile-cta.tsx — 56px tap targets meet WCAG 2.5.5, position:fixed bottom:0 with safe-area-inset-bottom for iOS home indicator clearance, z-index:50 sits above sections but below modals, gradient-divided two-column layout (Call left, Book right). Auto-emitted as the LAST section whenever input.phone is set; position:fixed pulls it out of document flow at runtime so visual order doesn't matter. (1.38.3) Testimonial synthesis from Maps reviews paste. NEW testimonials field on create_workspace_from_google_paste MCP tool input — array of { quote, name?, role?, company?, rating? } extracted VERBATIM by Claude Code from review excerpts in the paste. NEVER fabricated — when paste has no review text, the testimonials field is OMITTED entirely (better empty than fake). Backend route /api/v1/workspaces/create-full reads + shape-validates via readTestimonials() (cap 8 entries, quote ≤800 chars, drop entries missing quote). Plumbed through CreateFullWorkspaceInput → createAnonymousWorkspace → soul + enhance-blocks. enhance-blocks emits a testimonials LandingPageSection (between serviceArea and faq in the order) when input.testimonials.length > 0. Quotes pass through verbatim — the LLM does not get to rewrite them. ALL THREE block types registered in src/components/landing/block-registry.tsx with grapesContent placeholders for the visual editor. EMAIL-FIRST GUARDRAIL UNCHANGED. NO new env vars (uses existing UNSPLASH_ACCESS_KEY for higher-quality gallery photos when set; works keylessly via source.unsplash.com when not). NO migrations. Backend redeploy required. EXPECTED IMPACT: every fresh paste-driven workspace now ships with 11 sections including a populated photo gallery + mobile sticky CTA + real testimonials when paste has reviews. Visible-quality bar: 9/10 first-shot. Remaining gap to 10/10 = operator-supplied logos + real photos.",
6
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.38.0: ATOMIC HORMOZI-QUALITY OUTPUT for every workspace. Pre-1.38.0, create_full_workspace produced workspaces whose landing rendered via the BLUEPRINT path (lib/page-schema/seed-landing-from-soul → renderGeneralServiceV1 → contentHtml/contentCss seeded from canned personality.content_templates.hero_headlines[0] — generic 'Welcome to X' copy, generic personality-bundle hero photo, no motion). Tirionforge HVAC happened to look great because Claude Code followed up with the BLOCK-AS-SKILL flow per block (get_block_skill + persist_block); atlantic-plumbing didn't, so it got the canned output. Same atomic create, very different visible quality. Operators NEVER see this dance — they just see the page. v1.38.0 closes the gap atomically: ONE server-side Claude Opus 4.7 call inside the orchestrator generates Hormozi-quality content for hero + servicesGrid + about + benefits + process + faq + cta using the exact same SKILL.md files in src/blocks/*/SKILL.md that Claude Code reads via get_block_skill. Single source of truth, no duplication — the SKILL.md IS the fat skill, the MCP server stays a thin shim. WHAT SHIPS: (1) NEW src/lib/workspace/enhance-blocks.ts. enhanceLandingForWorkspace() loads SKILL.md files, builds prompt with business context (name/city/state/phone/services/description/reviews/emergency/hours/service_area), calls Anthropic via getAIClient (BYOK first via organizations.integrations.anthropic.apiKey, falls back to platform ANTHROPIC_API_KEY env). Model fallback chain: claude-opus-4-7 → claude-sonnet-4-5-20250929. Parses JSON, validates each section, resolves Unsplash for hero.heroImage_query, writes LandingPageSection[] to landingPages.sections, NULLs contentHtml/Css. (2) NEW Step 12.7 inside createFullWorkspace orchestrator (lib/workspace/create-full.ts). Soft-fails on every error path — workspace stays valid (canned-copy Path A intact) if Claude is unreachable. (3) Route /l/[orgSlug]/[slug] preference unchanged but now falls through to PageRenderer correctly because contentHtml/Css are nulled — PageRenderer wraps below-fold sections in <RevealOnScroll> for scroll-triggered fade-up motion. (4) FIRST_CALL_BANNER bumped to v1.38.0 with Hormozi-quality guidance. EMAIL-FIRST GUARDRAIL UNCHANGED: create_full_workspace + create_workspace_from_google_paste still return BEFORE the email collection step — operator can't see URLs until they reply with email, finalize_workspace mints magic admin link + sends welcome email via Resend. NO new env vars (uses existing ANTHROPIC_API_KEY + organizations.integrations BYOK). NO migrations. Backend redeploy required. EXPECTED IMPACT: every fresh workspace produced by either atomic-create tool looks $10k-tier first-shot — Hormozi value-equation hero copy + per-business Unsplash photo + scroll-triggered motion + branded services grid with prices + 3-step process + real FAQs + final CTA. No 'create workspace then enhance blocks' two-step dance. atlantic-plumbing.app.seldonframe.com on next workspace re-creation will render with the rich output by default. Cost ~$0.10 per workspace via BYOK or platform key — irrelevant given the operator-visible quality uplift.",
7
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.37.0: GOOGLE MAPS PASTE → WORKSPACE (no Places API). New MCP tool create_workspace_from_google_paste — sibling to create_full_workspace, same backend pipeline (/workspaces/create-full), same atomic guarantees, same finalize_workspace follow-up. The differentiator is the docstring: it teaches Claude Code how to extract structured fields from a raw Google Maps business listing — bold title → business_name, phone-icon row → phone, location-pin line → address (parse city + state), categories chip row + 'Services' section → services (deduped), '4.7 ★ (950)' → review_rating + review_count, 'Monday: 9 AM-5 PM, Tuesday: closed, …' → weekly_hours in canonical {monday:{enabled,start,end}, ...} shape. Thin harness, fat skill: NO regex parser, NO LLM call, NO Places API key on the SF side. Claude Code (the agent) parses the paste; the MCP server is just a typed shim. WHAT SHIPS: (1) NEW tool create_workspace_from_google_paste in skills/mcp-server/src/tools.js. Inherits create_full_workspace's input schema and adds two fields — weekly_hours (canonical schedule shape) and google_place_url (audit URL). Tool description embeds 11 numbered extraction rules so Claude Code generates the right call shape on first try. (2) BACKEND extends CreateFullWorkspaceInput with weekly_hours + google_place_url. After the orchestrator's existing 13 steps land, two new soft-fail steps run: 12.5 UPDATE every booking template's metadata.availability with the parsed hours (closing the loop with v1.36.4's read-path fix — the booking page now hydrates real Maps-extracted hours on first GET). 12.6 stamp soul.business.maps_url with the source URL for future re-sync. Both UPDATEs catch + log errors; never block workspace creation. (3) ROUTE /api/v1/workspaces/create-full reads + shape-validates weekly_hours via readWeeklyHours() — full-day-name keys only (sunday/monday/.../saturday), HH:MM 24-hour format, malformed entries silently dropped (workspace creation must not fail on a paste-extraction quirk). (4) FIRST_CALL_BANNER updated with paste-workflow guidance: 'when the operator pastes a Google Maps business listing, use create_workspace_from_google_paste — NOT create_full_workspace.' (5) Updated banner header from v1.34.0 to v1.37.0. NO new env vars (no Places API key, no Maps key). NO migrations. Backend redeploy required. EXPECTED IMPACT: when the user says 'make me a workspace from this Google Maps listing for Top Plumbing Experts', Claude Code parses the paste in-context (Maps listings are plain text), calls create_workspace_from_google_paste with the structured fields, and the operator's real business hours appear on the public /book page immediately — no second tool call, no Places API cost, works in any language. ~1 day total ship. Pairs with v1.36.4 fix.",
8
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.36.4: HOTFIX — booking 'No times available' on workspaces created via the MCP create_appointment_type route. Bug: src/app/api/v1/booking/appointment-types/route.ts wrote bookings.metadata.availability with 3-letter day keys (mon/tue/wed/thu/fri/sat/sun), but normalizeAvailability() in lib/bookings/actions.ts reads source[\"monday\"] etc. — full names. Result: every daySource lookup returned undefined → fell back to defaults silently (Mon-Fri 9-5 enabled, weekend disabled). The defaults masked the bug at create time, but any subsequent partial override via the dashboard form (which writes full-name keys) ended up as a mixed shape that didn't hydrate as the operator expected, surfacing as 'No times available' on the public /book page. Atlantic Plumbing dogfood reproduced this. Other writers were already correct: lib/blocks/templates.ts (buildAppointmentAvailabilityFromBlueprint) and lib/page-blocks/persist.ts (weeklyAvailabilityToCanonicalAvailability) explicitly map 3-letter→full names; lib/soul/install.ts writes empty {} which falls back safely. WHAT SHIPS: (1) appointment-types/route.ts now writes monday/tuesday/wednesday/thursday/friday/saturday/sunday — single source of truth is the AvailabilityDayKey union in lib/bookings/actions.ts. (2) DEFENSIVE READ: normalizeAvailability() also accepts legacy 3-letter keys via a shortToFullDayKey map. Reads source[fullKey] first, falls back to source[shortKey] if the full key is undefined. This rescues any prod rows already stored with the broken shape — no DB migration required. NO new env vars. Backend redeploy required. EXPECTED IMPACT: every workspace whose booking template was created via the MCP route — including Atlantic Plumbing — immediately renders Mon-Fri 9-5 slots correctly on next deploy. New workspaces store the canonical full-name shape from now on. Future partial-override writes from the dashboard form interleave cleanly.",
9
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.36.3: HOTFIX — force light mode on customer-facing booking pages. Bug: the default workspace theme.mode is 'dark' (per DEFAULT_ORG_THEME), so themeToCSS sets --sf-bg = #09090b and --sf-text = #fafafa. The v1.36.1 booking page rebuild faithfully used those CSS variables, which meant every fresh workspace's /book page rendered in dark mode. The user reported atlantic-plumbing.app.seldonframe.com/book showing dark-on-dark text that read as 'fucking ugly' next to the polished light-mode reference (hvac.tirionforge.com/book). FIX: book/[orgSlug]/[bookingSlug]/page.tsx now overrides theme.mode = 'light' on the OrgTheme passed to PublicThemeProvider for booking pages. Operators' brand color (primaryColor) and font still cascade unchanged — only mode is flipped. Industry convention: customer-facing booking pages are light by default (Cal.com, Calendly, every booking SaaS). If a workspace explicitly wants a dark booking page, we'll add an opt-in toggle later; light is the right default for the 95% case. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: every booking page on every workspace immediately renders in light mode — readable text, clean white background, brand-colored accents — on next deploy.",
10
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.36.2: ENTITLEMENT BYPASS for SF super-admins. Workspaces owned by anyone whose email is in SF_SUPERADMIN_EMAILS skip every tier-based limit assertion (assertLandingPageLimit, assertEmailSendLimit, assertAiCallLimit, assertTeamMemberLimit, assertPortalEnabled, assertAiCustomizationEnabled). Rationale: the SF team itself dogfoods the platform on its own accounts (Maxime owns Cypress HVAC + Atlantic Plumbing + future test workspaces); without this bypass, the second landing page they create hits 'upgrade_required limit:landingPages current:1 tier:starter' and blocks the demo flow. Real customers don't see this — only the SF-internal team. Right move is short-circuit the check rather than have the team manually upgrade test accounts every time. WHAT SHIPS: NEW isOwnerSuperAdmin(orgId) helper in src/lib/tier/limits.ts. Joins organizations.ownerId → users.email, checks against the SF_SUPERADMIN_EMAILS allowlist via existing isSuperAdminUser(email) from @/lib/auth/super-admin. Each of the 6 assert* functions starts with `if (await isOwnerSuperAdmin(orgId)) return;` early-exit. NO changes to limit configuration; NO changes to the /super-admin dashboard's metrics (they still show real plan tiers); NO new env vars (uses the same SF_SUPERADMIN_EMAILS that gates /super-admin route). Backend redeploy required. EXPECTED IMPACT: Maxime can create unlimited landing pages, send unlimited emails, make unlimited AI calls, etc. on his own test workspaces (Cypress HVAC, Atlantic Plumbing, future test orgs) without hitting starter-tier limits. Real customers' workspaces unaffected.",
11
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.36.1: BOOKING PAGE COMPLETE UI REBUILD (tirionforge-quality). Triggered by user feedback: 'why is the calendar page now fucking ugly?' — comparing atlantic-plumbing.app.seldonframe.com/book to a polished industry reference (hvac.tirionforge.com/book). The pre-v1.36.1 booking page was bare: just an unbranded title, an unstyled DayPicker, and a 3-column time-slot grid wrapped in a 'Powered by SeldonFr...' watermark with no business identity, no phone CTA, no step indicator, no service details sidebar. WHAT SHIPS: (1) public-booking-form.tsx COMPLETE JSX REWRITE. State machine extends from 2 steps (pick-time → enter-details) to 3 (pick-date → pick-time → enter-details) so the time-slot view gets its own dedicated step. All action calls preserved (listPublicBookingSlotsAction, submitPublicBookingAction), demo-readonly + demo-blocked-error handling preserved, Stripe checkout redirect preserved, success screen preserved. New shell: full-page main wrapper with workspace background; top header card showing business name + tap-to-call phone CTA pill; body card with two-column layout (38%/62% on desktop). LEFT column: 'Schedule a service' eyebrow + appointment title + description + meta list (duration / on-site / timezone) + 'Booking with' eyebrow + business name. RIGHT column: 3-step indicator (Pick a date · Choose a time · Confirm details) with active/past states + circle numbers/checkmarks; calendar (step 1) / time slot grid (step 2) / details form (step 3). Step indicator allows clicking back to earlier steps. (2) DayPicker BRANDED STYLING via injected CSS string (skips styled-jsx dependency): primary-color selected day, primary-tinted hover, rounded slots, uppercase font-weighted day-of-week headers, 44px cell size for fingertip tap. CSS variables fall back to teal #21a38b when --sf-primary is unset. (3) Time slot grid REDESIGNED: 12px-radius rounded-xl pills with hover-lift micro-interaction, primary-tint background when selected, loading state shows 6 skeleton pulse cards instead of 'Loading available times…' text. (4) Step 3 confirmation card highlights selected date+time in a primary-tinted box with a 'Change' link back to step 2. (5) page.tsx EXTENDED to fetch org name + soul + testMode in one query, parses business phone from soul.business.phone / soul.contact.phone / soul.phone (best-effort across schemas), passes businessName + businessPhone + appointmentName + appointmentDescription to PublicBookingForm. (6) BLUEPRINT-RENDER PATH BYPASSED. The page route used to prefer the calcom-month-v1 blueprint renderer's stored HTML/CSS pair; we're skipping that path so every booking page gets the new React UI immediately, regardless of whether it was scaffolded with the old renderer. The blueprint-renderer module + the bookings.contentHtml/contentCss columns still exist; fixing the renderer's HTML output to match is a separate ship. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: every booking page on every workspace immediately gets the rich tirionforge-quality UI — no operator action required, no rerun of any tool. Atlantic Plumbing's /book URL goes from 'plain ugly' to 'looks like a professional business' on the next deploy. v1.36.x deferred: booking weekly_availability hydration ('No times available' on fresh booking pages — even though defaultAvailabilitySchedule() returns Mon-Fri 9-5, something between create-time and render-time is dropping it; needs a deeper trace), entitlement bypass for SF_SUPERADMIN_EMAILS (upgrade_required blocks 2nd landing page on starter tier), slow event emissions, vertical packs.",
12
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.36.0: LANDING-PAGE QUALITY PASS — three new block primitives (servicesGrid, emergencyStrip, serviceArea) + Hero empty-state upgrade + FIRST_CALL_BANNER prompt-fatigue + composition guidance for trades verticals. Triggered by real-user dogfood feedback (Atlantic Plumbing): generated landing page had 3-4 sections, no hero photo, no services grid with prices, no emergency callout. World-class plumbing site has 10-15 sections; gap was 7-10. New blocks: ServicesGrid (per-service cards with price + duration + Book CTA, replaces SaaS-style PricingSection for trades), EmergencyStrip (brand-colored 24/7 callout banner with tap-to-call), ServiceArea (chip cloud of cities/neighborhoods served, no embedded map). Hero block empty state: replaced 'Add hero media' gray box with brand-tinted gradient (primary/15 → primary/5 → background) anchored by huge primary-color first-word typography, looks intentional pre-photo. FIRST_CALL_BANNER guidance: bundle MCP tool calls in parallel via Promise.all, recommend the operator pick 'Yes, and do not ask again' the first time create_landing_page / persist_block / build_website_chatbot fire (caches per-tool autoapprove for the project), default to 10-section composition for local-service businesses (navbar → hero → emergencyStrip → trust → servicesGrid → benefits → process → serviceArea → testimonials → faq → cta → footer), substitute servicesGrid for PricingSection on per-service businesses (trades, salons) vs tier-based businesses (SaaS, coaches). Block-registry wires all three new types with grapesContent placeholders for the visual editor. types.ts extends LandingPageSection union and adds three Content types. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: next workspace Claude Code generates for a trades business produces a 10-section landing page with prices + emergency CTA + service area + tasteful hero gradient — not the 3-4-section sparse page from the Atlantic Plumbing dogfood. v1.36.x DEFERRED: booking weekly_availability hydration ('No times available' on fresh booking pages), bypass entitlements for SF_SUPERADMIN_EMAILS (upgrade_required error blocks 2nd landing page on starter tier), slow event emissions (10s elapsed on contact.created/intake.submitted), form schema field-type drops, vertical packs.",
13
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.7: HOTFIX — logout was broken when sf_admin_token cookie present. Bug: proxy.ts line 196 treats `isAuthenticated = hasNextAuth || hasAdminToken`, where hasAdminToken checks the sf_admin_token cookie (set during Claude Code MCP onboarding for admin-token sessions, format wst_*). Pre-v1.35.7, signOutAllSessionsAction cleared NextAuth + sf_operator_session but NOT sf_admin_token. Users who had ever onboarded via the MCP admin-token flow (e.g., maximehoule100@gmail.com after testing the MCP install for Cypress HVAC) had a surviving sf_admin_token cookie. Clicking 'Log out' would clear NextAuth + operator session, redirect to /login, but proxy.ts saw the admin-token cookie as still-authenticated and bounced /login → /dashboard. Symptom: clicking Log out appears to do nothing. WHAT SHIPS: signOutAllSessionsAction now clears all three cookies (sf_operator_session, sf_admin_token, NextAuth session) in one call. Common cookieClearOpts hoisted to a const for clarity. The wst_* token IS NOT revoked server-side here — it's still valid for MCP callers using it as a Bearer header. We only clear the COOKIE so this browser session stops being 'authenticated.' Server-side token revocation requires a separate flow (delete api_keys row); not the same operation as sign-out. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: clicking 'Log out' from the operator dashboard now actually logs you out, regardless of how many auth sessions accumulated. /login renders cleanly. You can sign in again as a different user, or test the SF Admin flow without leftover state.",
14
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.6: HOTFIX — operator-dashboard sidebar surfaces SF Admin entry for super-admins. UX bug from the v1.35.x series: when Maxime (whose email is BOTH the SF_SUPERADMIN_EMAILS allowlist email AND the owner of the Cypress HVAC operator workspace) logs in, he lands on the operator dashboard. The operator sidebar has no nav item pointing at /super-admin, so he can't navigate to the platform-admin surface without typing the URL manually. Same problem will hit any future SF team member who's also an operator on the platform. WHAT SHIPS: (1) Sidebar prop signature extends with isSuperAdmin?: boolean. When true (and isOperatorSession is false), the SYSTEM nav group renders an extra 'SF Admin' entry pointing at /super-admin (uses Shield icon from lucide). (2) sidebar-nav.tsx iconMap extended with shield: Shield so the new entry resolves correctly. (3) (dashboard)/layout.tsx imports isSuperAdminUser from @/lib/auth/super-admin and resolves isSuperAdmin = !isOperatorSession && await isSuperAdminUser(user?.email). Operator portal sessions never get the SF Admin entry regardless of email — they're sub-tenants on the platform, not SF staff. (4) Pass-through plumbing: dashboard layout → Sidebar component. NO migrations, NO new env vars (uses existing SF_SUPERADMIN_EMAILS). Backend redeploy required. EXPECTED IMPACT: Maxime logs in to maximehoule100@gmail.com, lands on the Cypress HVAC dashboard as usual, scrolls to the bottom of the sidebar, sees a small 'SF Admin' entry with a shield icon under SYSTEM. One click → /super-admin. Same email, same session, no logout/login dance. Future SF team members who are also operators on the platform get the same affordance automatically.",
15
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.5: SUPER-ADMIN HEALTH TAB (final ship in v1.35.x). Final ship in the v1.35.x series. Health tab covers what's available locally without instrumenting Sentry/Datadog: workflow run distribution + recent failures, event volume per day for 7 days, top events, and validator failure rate (the v1.28.6 critical-fail signal). Sentry-backed API error rate + Vercel Analytics p95 latency + LLM provider observed uptime defer to v1.35.5.x. WHAT SHIPS: (1) NEW src/lib/super-admin/health.ts. getHealthMetrics() returns 3 views, all wrapped in unstable_cache (5min TTL, tagged super-admin:health): workflows (status distribution from workflow_runs + total / completed / failed counts + successRate computed only over terminal runs + recentFailed list of 10 most recent failed runs with archetypeId + orgId), events (7-day daily bucket counts via Postgres date_trunc, top 10 events by count, total7d), validators (sample of last 1000 assistant turns from agent_turns, share with any failed validator via jsonb_array_elements unnesting validatorsPassed JSONB, failureRate null when sample <20). Each query graceful-fallback. (2) src/app/super-admin/health/page.tsx upgraded from placeholder. Layout: top KPI strip (3 cards: Workflow success rate ≥95 green, Validator failure rate ≤5 green, Events 7d), Workflow run status distribution table with status badges (completed=teal, failed=red, cancelled=neutral, waiting=amber, running=blue), Recent failed workflows table (run ID + archetype + workspace link), Event volume 7-day bar chart, Top events table. Empty hints when nothing's recorded yet. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: Maxime can answer 'is the platform healthy' in <5 seconds. Workflow success rate + validator failure rate are the two best leading indicators for runtime correctness; below thresholds (95% / 5%) the cards turn warn-amber. Final v1.35.x ship completes the super-admin shell — Maxime now has Overview / Users / Workspaces / Agents / Revenue / Health all wired with real data. Future ships add Stripe-sourced revenue (downgrades, churn, cohort retention) and Sentry-sourced health (API error rate, p95 latency, LLM uptime).",
16
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.4: SUPER-ADMIN REVENUE TAB (local-DB approximation; Stripe-sourced version in v1.35.4.x). Fifth ship in v1.35.x. Maxime can now see MRR by plan, MRR over time (12-month bar chart), conversion funnel (signup → workspace → agent → paid), and recent paid signups. Local-DB-only for speed (~50ms); Stripe API direct (with proper churn + downgrade modeling) graduates next. WHAT SHIPS: (1) NEW src/lib/super-admin/revenue.ts. getRevenueMetrics() returns 4 views, all wrapped in unstable_cache (5min TTL, tagged super-admin:revenue): byPlan (Free/Growth/Scale headcount + monthly $ contribution + total MRR + paid-user count), monthly (12-month MRR snapshot — at each month-end, count paid users with createdAt <= month-end and multiply by current plan price; explicitly an approximation that doesn't model downgrades or churn), funnel (4 steps: Signed up / Created a workspace / Has at least 1 agent / Upgraded to paid — each with retainedFromPrevious % so drop-offs point at activation work), recentPaid (last 20 users on Growth or Scale ordered by createdAt desc, with link to /super-admin/users/<id>). 'Has at least 1 agent' funnel step uses a CTE counting distinct ownerIds whose orgs have any agent. Graceful fallback (.catch returning zeros) so a single failed query doesn't blank the dashboard. (2) src/app/super-admin/revenue/page.tsx upgraded from placeholder. Layout: top strip (3 cards: MRR with primary teal accent + ARR + Paid users), 'MRR over time' 12-bar chart (gradient teal bars, hover-tooltip via title attr, 0 + max-$ axis labels), 'By plan' table (Plan badge / Users / Monthly $ / % of MRR), 'Conversion funnel' visual (4 horizontal bars showing absolute count + % retained from previous step + bar width relative to first step), 'Recent paid signups' table (User / Plan badge / Joined date — clickable to user detail). (3) FIX in revenue.ts: db.execute() returns a NeonHttpQueryResult not an iterable; original destructuring [const [row] = await db.execute(...)] failed type check. Pattern corrected to const r = await db.execute(...); const row = r.rows?.[0] as Type. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: Maxime sees MRR composition (which plan is the engine), the 12-month trend (is the line going up?), and the funnel (where signups die before becoming paid). Stripe-sourced numbers (real MRR with churn/downgrades, failed-payment dashboard, cohort retention) land in a follow-up — for v1.35.4 the local approximation is enough to make decisions.",
17
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.3: SUPER-ADMIN AGENTS TAB (fleet health). Fourth ship in v1.35.x. Platform-wide agent metrics: fleet status counts, eval pass rate of live agents, per-archetype health, top failing scenarios, conversation volume. WHAT SHIPS: (1) NEW src/lib/super-admin/agents.ts. getAgentMetrics() returns 5 views, all wrapped in unstable_cache (5min TTL, tagged super-admin:agents): Fleet status (count by status: live / draft+test / paused / total), Per-archetype breakdown (count + recent eval pass rate per archetype using a CTE that ranks evals by ranAt DESC and picks the most recent run per agent×scenario), Recent pass rate (overall % of most-recent eval runs passing across all live agents), Top failing scenarios (scenarios with ≥3 attempts, sorted by fail rate descending, top 10), Conversation volume (24h / 7d / 30d started + completed-without-escalation share for 30d). The CTE uses ROW_NUMBER() OVER (PARTITION BY agent_id, scenario_id ORDER BY ran_at DESC) to handle the most-recent-run-per-pair query in one round trip. Graceful fallback (.catch returning zeros) so a single failed query doesn't blank the dashboard. (2) src/app/super-admin/agents/page.tsx upgraded from placeholder. Layout: 'Fleet status' strip (4 cards: Live / Draft+Test / Paused / Total — Live gets primary teal accent), 'Eval pass rate · live agents' big-number card with progress bar (≥87 green, 75-87 amber, <75 red, includes context line about the 87.5% publish gate), 'Per-archetype health' table (archetype / total / live / pass rate badge with same color coding), 'Top failing scenarios' table (scenario ID / attempts / fails / fail rate badge — fail rate ≥50% gets red, lower amber), 'Conversations' strip (4 cards: 24h / 7d / 30d started + completed-share-30d). Each empty state has an honest 'no data yet' explanation rather than fake numbers. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: Maxime can answer the 'is the runtime healthy' question in <5 seconds. The eval pass rate big-number + the top-failing-scenarios table are the two views that drive the next skill-pack improvements — when a specific scenario shows up at 67% fail rate across 50 attempts, that's the next thing to fix in the markdown skill. As more workspaces publish agents, the data gets richer.",
18
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.2: SUPER-ADMIN WORKSPACES TAB (list + detail). Third ship in v1.35.x. Now Maxime can see all SF workspaces, sort by activity / created / name, search by name or slug, filter by Soul template, and click into any workspace to see its agents, lifetime tokens, lifetime LLM cost, and activity rollups. WHAT SHIPS: (1) NEW src/lib/super-admin/workspaces.ts. listWorkspaces({ search, soulId, sort, cursor, limit }) returns paginated rows with owner email + last activity + conversations 24h + live agents count. Joins owner via single users-batch query (no N+1). Last activity per org via single MAX(createdAt) GROUP BY against activities table. Conversations 24h via count(agentConversations.id) GROUP BY. Live agents via count(agents) WHERE status='live' GROUP BY. Sort by 'created' uses cursor pagination; 'activity' sorts the current page client-side (post-query); 'name' uses asc(name). Three sort modes; cursor only available on 'created'. getWorkspaceDetail(workspaceId) returns workspace profile + owner email/id + activity 24h/7d/30d buckets + lifetime LLM cost (sum llmCostCents) + lifetime tokens (sum tokensIn + tokensOut) + total conversations + distinct contacts + agents list with status/archetype/channel/createdAt. (2) src/app/super-admin/workspaces/page.tsx upgraded from placeholder to real list. URL-driven filters (search, soul, sort). Table columns: Workspace (name + slug, click to drill), Owner (email), Soul (template badge), Live agents (right-aligned, tabular-nums, dimmed when 0), Convos · 24h, Last activity (relative time). Footer note explains the cursor + sort interaction. (3) NEW src/app/super-admin/workspaces/[workspaceId]/page.tsx — workspace detail. Breadcrumb back to /super-admin/workspaces. Header: workspace name + slug-as-subdomain (mono) + Soul badge + 'owned by [email]' link to /super-admin/users/<id>. Detail card on the right with Workspace ID + Created date + Subdomain. Activity stat strip (4 cards: 24h / 7d / 30d / all-time conversations + distinct contacts subtitle). Lifetime usage row (2 cards: Lifetime tokens + Lifetime LLM cost in $X.XX format with 'self-reported by the runtime · BYOK' subtitle, primary teal accent). Agents section: count + live/draft/paused breakdown header, then table of all agents with status badges (live = teal, paused = amber, draft/test = neutral). Empty state for workspaces with no agents yet. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: Maxime can see every workspace, sort by 'most active' to find power users, sort by 'newest first' to see launch-week signups, and click any workspace to see its full health profile (agents, lifetime tokens, recent activity). The two questions that matter at this stage — 'who's actually using SF heavily' and 'are agents being published' — answer in <5 seconds.",
19
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.1: SUPER-ADMIN USERS TAB (list + detail). Second ship in the v1.35.x series. v1.35.0 gave Maxime the 4 hero numbers; v1.35.1 lets him drill into who's signing up. WHAT SHIPS: (1) NEW src/lib/super-admin/users.ts. listUsers({ search, plan, cursor, limit }) returns paginated rows + totalForFilter (cached separately by search+plan, 60s TTL, tagged super-admin:users). Search is case-insensitive ILIKE on email + name. Plan filter restricts to a TierId. Cursor pagination on createdAt DESC for stable ordering. Workspace counts joined via single GROUP BY query keyed by ownerId — no N+1. getUserDetail(userId) returns the user + workspaces owned + workspaces joined-as-member (deduped) + last activity per workspace via single MAX(createdAt) GROUP BY query against the activities table. (2) src/app/super-admin/users/page.tsx upgraded from placeholder to real list. Server-rendered. URL-driven search/filter (no client interactivity except the form which submits via GET). Header shows total matching the filter. Search input + plan select dropdown (All / Free / Growth / Scale) + Apply button + Clear link when filters are active. Table columns: User (name + email, click row to drill), Plan (badge — paid plans get teal accent), Workspaces (owned count), Joined (date), Stripe (last 6 chars of customer ID, monospace pill). Pagination: First page + Next page links when applicable. Tabular-nums for the workspace count column. Empty state when no users match. Footer with mechanics ('cursor-based on createdAt DESC'). (3) NEW src/app/super-admin/users/[userId]/page.tsx — user detail. Breadcrumb (Users · email). Header with name (or email if no name set) + email + plan badge + email-verification status (amber when unverified). Detail card on the right with User ID + Joined date + Stripe customer (mono). Two sections: 'Workspaces owned' (count + table of org name/slug/soul/last activity/created) and 'Joined as member' (count + table with membership status replacing the created column). Each workspace row links to /super-admin/workspaces/<id> (lands at v1.35.2's empty page today; the link works regardless). Last activity formatted as relative time ('3h ago', '12d ago') falling back to absolute date for older. Empty hints for the 'no workspaces yet' / 'not a member of any other' cases. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: Maxime can now see every signup, search by email, filter by plan, and click any user to see their workspaces. The two questions that matter at this stage of the launch — 'who's actually paying' and 'is this user activating (created a workspace, has recent activity)' — are answerable in <5 seconds.",
20
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.35.0: SUPER-ADMIN DASHBOARD (skeleton + 4 hero numbers above the fold). First ship in the v1.35.x series that gives Maxime full visibility into SF the business — users, paid tiers, workspaces, agent runs, MRR, revenue. Per the first-principles reflection (graceful disclosure / smart defaults), this ship is the smallest cut that gives real signal: 4 numbers + the routes for 5 deeper tabs that come in v1.35.1–v1.35.5. WHAT SHIPS: (1) NEW src/lib/auth/super-admin.ts. requireSuperAdmin() server-side gate that checks SF_SUPERADMIN_EMAILS env var (comma-separated, whitespace-tolerant allowlist). Non-admins redirect to /dashboard with no flash. Why env-allowlist not a users.is_super_admin column: pre-launch the team is one person; over-engineering the permission model adds complexity for zero payoff. Graduates cleanly to a DB column when team grows >3 SF admins. isSuperAdminUser(email) helper for callers that need a check without redirect. (2) NEW src/lib/super-admin/metrics.ts. getHeroMetrics() returns 4 numbers wrapped in unstable_cache with 5-minute TTL: MRR (sum users.planId × plan price across paid tiers — fast local approximation; Stripe-sourced source-of-truth lands in v1.35.4), ARR (MRR × 12), Paid signups · 7d (count users where planId in ('growth','scale') AND createdAt > now() - 7d), Active workspaces · 24h (countDistinct organizations from activities table where createdAt > now() - 24h). Each query is a single SELECT with proper indexes. Tagged super-admin:billing + super-admin:activity for revalidation. Graceful fallback (.catch returning zeros) so a single failed query doesn't blank the whole dashboard. Subtitle on each card adds context (e.g. 'across 43 paid users' under MRR). (3) NEW src/app/super-admin/layout.tsx — Server Component that gates with requireSuperAdmin() before any UI hits the wire. (4) NEW src/app/super-admin/super-admin-sidebar.tsx — client component, dark-theme sidebar mirroring the operator dashboard pattern. 6 nav items (Overview / Users / Workspaces / Agents / Revenue / Health) with lucide-react icons + active highlight via pathname.startsWith. Bottom shows admin email + 'Back to operator dashboard' link. (5) NEW src/app/super-admin/page.tsx — Overview page. 'Today' headline + 4 hero stat cards (the MRR card gets the primary teal-tinted accent; others stay neutral). Computed-at timestamp + cache-TTL footnote. Below: 5 drill-down cards pointing at the deeper tabs (each labeled with the ship version that wires them). (6) NEW src/app/super-admin/placeholder-tab.tsx — shared shell for the 5 tabs that ship empty. Each placeholder has the tab title + ship version + summary + bullet list of what's coming. Honest framing ('Coming in v1.35.x'). (7) NEW src/app/super-admin/{users,workspaces,agents,revenue,health}/page.tsx — 5 placeholder pages composing PlaceholderTab. Routes resolve, sidebar highlight works, no fake data. NO migrations, NO new env vars (SF_SUPERADMIN_EMAILS is operator-managed in Vercel project settings). Backend redeploy required. EXPECTED IMPACT: Maxime can navigate to /super-admin in production and see the 4 numbers that matter for the launch — MRR (critical for investor conversations), paid signups in the last 7 days (critical for launch-week tracking), active workspaces in the last 24h (critical for 'is anyone using it'). Total ship: ~6-8 hours of work in one commit; subsequent v1.35.x ships layer on Users / Workspaces / Agents / Revenue / Health surfaces incrementally without changing the shell.",
21
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.34.4: APPS/ DELETED + AUTH-COOKIE-JAR PURGE + SECURITY.MD UPGRADE. Root cause discovery: the failing 'Production — seldonframe-web' Vercel project (red-X on every deploy in the user's deployments screenshot) was driven by the orphan apps/web/ Next.js 14.2.5 marketing site. The current marketing site lives at packages/crm/src/app/(public)/landing-client.tsx (Next 16). apps/web was a 2-month-old monorepo split that never got cleaned up, with overlapping hero / pricing / problem / intelligence components and stale email-capture/waitlist flows. apps/cloud and apps/pro were stub scaffolds with single page.tsx files. WHAT SHIPS: (1) DELETED apps/ ENTIRELY (apps/web 1900+ LOC stale marketing site + apps/cloud + apps/pro stubs). Removed dev:web and build:web scripts from root package.json. Removed 'apps/*' from pnpm-workspace.yaml. Vercel will stop creating seldonframe-web deploys on next push (the project itself still needs to be deleted/disconnected in Vercel dashboard — this code-side change just removes what was triggering it). (2) DELETED 5 MORE AUTH-COOKIE-JAR FILES: auth-check.txt, auth-flow.txt, auth-live-debug.txt, auth-recheck.txt, auth-state.txt. All Netscape HTTP Cookie File format from curl debugging sessions, same pattern as auth-check-redo.txt deleted in v1.34.3. Each contained stale __Secure-authjs auth tokens — security concern even though expired, plus they shouldn't have been committed. (3) DELETED soul.md (75-line older overview file; SOUL_SPEC.md is the canonical architecture spec). (4) SECURITY.md MAJOR UPGRADE (44 → 90 lines). Restructured around SF's actual attack surfaces. Added 'Safe harbor' section with explicit no-legal-action commitments for good-faith researchers. NEW 'In scope' table with 8 surfaces ranked by criticality: BYOK LLM key handling (AES-256-GCM at rest with ENCRYPTION_KEY env var — decryption side-channel, ENCRYPTION_KEY exposure path, plaintext key in logs would all be reportable), MCP server bearer token leakage / cross-workspace request smuggling, agent runtime + eval gate (eval-gate bypass, prompt injection that bypasses critical-fail validators, regen-loop infinite cost amplification), tenant scoping (workspaceId/orgId IDOR), auth (NextAuth + wst_* bearer tokens), public surfaces (landing-page XSS, embed iframe postMessage), workflow runtime, webhook signature verification. Each row explains why-it-matters + concrete examples-we-want-to-see. NEW 'Out of scope' section with 7 explicit exclusions (upstream-dep CVEs, social engineering, self-XSS, performance-DoS, deprecated code paths in git history). Disclosure process detailed: 24h ack, 7-day triage, same-day patch for critical, 90-day coordinated disclosure window. Recognition section honest about pre-1.0 status (no paid bounty yet, public credit + Discord role + comp credits on Pro/Agency tier for critical findings). NO source code changes (all repo metadata + cleanup). Backend redeploy not required. EXPECTED IMPACT: GitHub repo file list goes from 36 root entries (with auth-*.txt cookie jar files visible to anyone browsing) to a clean ~28 entries. Vercel deploys page goes from ~50% red-X to 100% green once Vercel project itself is disconnected (one-click in Vercel dashboard now that the underlying code trigger is gone). Security researchers landing on /SECURITY.md see a thoughtful policy that addresses SF's actual attack surfaces (LLM-key handling, MCP boundary, agent runtime) rather than generic 'we accept reports' boilerplate.",
22
+ "license": "AGPL-3.0-or-later",
23
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.34.3: LICENSE SWITCH MIT → AGPL-3.0 + REPO CRUFT CLEANUP. Per first-principles analysis (Postiz/Mattermost/Plausible playbook): AGPL protects against closed-source clones while keeping community contributions flowing freely. The hosted Agency tier becomes the de facto commercial license. WHAT SHIPS: (1) LICENSE swapped from MIT to canonical AGPL-3.0 text (fetched from choosealicense GitHub mirror, YAML front matter stripped, 662 lines of canonical license text). (2) README badge changed License: MIT → License: AGPL v3 (teal hex preserved). README footer rewritten to acknowledge the dual-license model and link Postiz/Mattermost/Plausible as inspiration. README self-host section updated to flag the AGPL share-modifications requirement and point at LICENSING.md. (3) NEW LICENSING.md: TL;DR table mapping use cases to license, plain-English explanation of what AGPL means in practice, when commercial license is needed (embedding, white-label SaaS without share-modifications, enterprise legal compliance, due diligence), two paths for commercial use (Path A hosted Agency tier $99/mo for the simple cases, Path B custom commercial license via hello@seldonframe.com for embedding/deep modifications), why we chose AGPL (3 reasons: protects open community, makes commercial value capturable, signals seriousness), what's covered by which license (platform/MCP/docs/skills/blocks/eval all AGPL-3.0; logos and brand assets all-rights-reserved), existing-contributors note about pre-v1.34.3 MIT contributions being treated as relicensed for forward compatibility. (4) CONTRIBUTING.md license section updated to reflect AGPL move with corporate-policy-on-AGPL escape hatch (email hello@seldonframe.com for contributor agreements). (5) REPO CRUFT DELETED: auth-check-redo.txt (Netscape HTTP Cookie File from a curl session, contained stale __Secure-authjs auth tokens — security concern even though expired), DEMO_GIF.md (placeholder runbook for capturing a demo GIF that's now irrelevant since the actual demo lives at seldonframe.com/demo), DEPLOY_DEMO.md (stale deployment guide for a demo subdomain that was never set up; the actual deployment is app.seldonframe.com). (6) QUICKSTART.md REFRESHED to match new README direction: two paths (Hosted recommended / Self-host), updated env-var list to include ENCRYPTION_KEY (required for BYOK encryption), updated monorepo layout, points at /docs/your-business/upgrade-ui and CONTRIBUTING.md for next steps. (7) CUSTOMIZATION.md REFRESHED to be a brief pointer: stops trying to teach 'how to add Stripe/SendGrid/Twilio manually' (those are now MCP tools); instead provides a customization-layers table mapping each need to the right path (skill pack, block, MCP tool, motion preset, DESIGN.md, fork) with cross-links to /docs/your-business/upgrade-ui and CONTRIBUTING.md. (8) MCP package.json: added license field 'AGPL-3.0-or-later' for npm metadata. NO source code changes. NO migrations, NO env vars. Backend redeploy not technically required (license + docs only); MCP package version bumped for SemVer hygiene + so the new license shows on npmjs.com. EXPECTED IMPACT: GitHub visitors landing on seldonframe/seldonframe see the AGPL-3.0 badge (signaling 'this is a real open-source business, not marketing-loss-leader'), can read LICENSING.md to understand the dual-license model, see a clean repo without curl-cookie-jar files or stale demo runbooks. Vercel cleanup follow-up flagged in commit body for the user to handle in Vercel dashboard (can't be done via vercel.json since it's project-level config).",
24
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.34.2: README + CONTRIBUTING CORRECTIONS + AMBITIOUS ROADMAP. User feedback on v1.34.1: (a) README Path A and Path C are both hosted on SF infra (Vercel + Neon) — they're the same backend with different chrome (Claude Code vs web dashboard); (b) booking is SOURCE OF TRUTH, not Google-Calendar-synced — customers book on SF, appointments land in CRM AND sync OUT to Google Calendar; (c) roadmap should be higher-level and contributor-inspiring rather than checking off operational milestones. WHAT SHIPS: (1) README QUICK START RESTRUCTURE. Was three paths (A: Claude Code, B: self-host, C: hosted dashboard). Now two paths: 'Hosted (recommended for most operators)' which covers BOTH Claude Code and dashboard signup as alternative chromes hitting the same Vercel + Neon backend; and 'Self-host' which is the fork-and-run path. Removes the false trichotomy and matches the actual product architecture. (2) BOOKING DESCRIPTION CORRECTED. Was 'Cal-style scheduling with Google Calendar sync' (implies SF is downstream). Now 'source-of-truth scheduling. Customers book on your branded SF page; the appointment lands in your CRM AND syncs out to your Google Calendar in real time. SF is the authority — Google Calendar is a downstream view.' Properly frames SF as the authority. (3) ROADMAP REWRITE — bigger swings, contributor-inspiring. Replaced 5 operational milestones with 9 items grouped 'Soon' (voice + SMS transports, self-improving agents that propose their own skill-pack updates from telemetry, renderer-level motion preset gating), 'Mid-term' (multi-agent orchestration where agents hire other agents — your booking agent calls a fraud-detection agent for high-value bookings, skill-pack marketplace with revenue share for community contributors, vertical templates marketplace for industries beyond the current 6), and 'Long-term — the agent era' (federated agent network with agent-to-agent commerce across SF workspaces, long-running operator agents that run your business for a week and report back, agent fleet operations for agencies running 100+ workspaces from one console). Each item explains the bet so contributors can see what they're stepping into. (4) CONTRIBUTING.md FULL REWRITE (66 → 230 lines). Opens with architecture orientation (the same 6-layer ASCII diagram from README) and the two principles every PR should respect (don't add intelligence to the harness, don't add capability to the skill). Six concrete contribution recipes: Recipe 1 'Add a skill pack' (markdown only, 30 LOC), Recipe 2 'Add an MCP tool' (~30 + 80 LOC), Recipe 3 'Add a block component', Recipe 4 'Tune motion primitives', Recipe 5 'Add a vertical template' (Soul + 8 eval scenarios), Recipe 6 'Improve the eval gate'. Each recipe shows file paths, expected LOC, and what reviewers check. 'What we look for in PRs' explicit lists: Loved / Sent back / Reverted. Notes the active license question (MIT today, considering AGPL-3.0 like Postiz) and explains the dual-license model. NO source code changes — pure repo metadata + docs. NO migrations, NO env vars. Backend redeploy not technically required (only README/CONTRIBUTING change), but bumping MCP package for SemVer hygiene. EXPECTED IMPACT: GitHub visitors see (1) accurate quick-start for SF's actual hosted-backend architecture, (2) correct framing of SF as the authority over scheduling, (3) a roadmap that signals 'this is the future and you can help build it' instead of 'feature checklist'. Contributors landing on CONTRIBUTING.md get architecture orientation + 6 concrete recipes with file paths, LOC estimates, and reviewer expectations — matching the rigor of Twenty's contribute docs.",
25
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.34.1: GITHUB README REWRITE + UI-CUSTOMIZATION DOCS PAGE. Inspired by Postiz (35K stars, $17K MRR), Twenty (45.6K stars), and Motion (the rebranded animation library) — first-principles reflection on what 10x's an open-source GitHub README. Five gaps in the v1.34.0 README: (1) no visual proof — said 'screenshots coming soon'; (2) no architecture diagram — left the thin-harness/fat-skill bet implicit; (3) no code examples beyond install — technical readers leave without seeing the developer experience; (4) the Karpathy bet wasn't articulated — the actual differentiation was buried in 'composable primitives'; (5) no contributor onramp — 'PRs welcome' is dead text. v1.34.1 closes all five. WHAT SHIPS: (1) FULL README REWRITE at packages/crm root. New headline: 'The open-source Business OS you build by typing.' Hero block: a Claude-Code-styled code-fence showing the actual 4-tool-call build sequence (build_landing_page → build_booking_page → build_intake_form → build_website_chatbot → ✓ Live at acme-hvac.app.seldonframe.com). NEW 'The bet: thin harness, fat skill' section explicitly articulating the architectural choice — platform is dumb (140+ MCP tools + block manifest + durable workflows + eval runtime, none of it tries to be smart), behavioral decisions live in markdown skill-packs, antifragile to LLM improvements. NEW ASCII-art architecture diagram showing the 6 layers (Operator → IDE-resident agent → MCP server / thin harness → skill-pack registry / fat skill → Runtime / Next.js+Postgres+Vercel Workflows+motion+MIT → Operator-owned providers). Three install paths (Claude Code MCP, self-host, hosted) with concrete commands. NEW 'What's wired up by default' section listing 10 included surfaces. NEW 'Examples — typical operator prompts' showing 5 real Claude Code prompts and the resulting MCP tool calls. NEW 'What's interesting to contribute to' table mapping 6 codebase areas (MCP tool registry, skill packs, eval gate, block library, motion primitives, workflows) to file paths + 'what's interesting' descriptions — this is the contributor onramp Twenty/Postiz both have. Tech stack section listing every framework concretely. Three-install-path comparison table (cost, workspaces, custom domain, white-label, BYOK, source code, updates, support). NEW 'Bring your own design tools' section listing the four paths (Claude Design, DESIGN.md, v0/Lovable/Cursor, direct fork). Updated roadmap (v1.34.x renderer gating, v1.4 voice+SMS, v1.5 custom block builder, v1.6 skill-pack marketplace, v1.7 agency mode self-serve). NEW 'Why open source' section with three reasons (customer wins, architecture wins, community wins) + acknowledgments to Twenty / Postiz / Cal.com. Open sponsorship slot. (2) NEW DOCS PAGE at packages/crm/src/app/docs/your-business/upgrade-ui/page.tsx. Power-user guide for UI customization. Sections: 'Start with the smart defaults' (frames the balanced preset as the finish line for 80% of operators), 'The four levers in order of effort' (motion preset → DESIGN.md → Claude Design handoff → fork), 'The thin-harness, fat-skill principle' (explains WHY the four levers compose, not just HOW), 'What's deferred and why' (renderer gating, Counter on stat blocks, per-block overrides). Each lever section includes the actual Claude Code prompt that triggers it + the expected response. Wired into the docs sidebar under 'Your business' so it's discoverable from /docs.",
26
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.34.0 (combined with v1.33.2 section-motion wiring): SECTION-LEVEL MOTION PRIMITIVES + apply_motion_preset MCP TOOL + GRACEFUL DISCOVERY SURFACES. Closes the 'how do users discover the UI-upgrade path' question with a graceful-disclosure-with-smart-defaults pipeline. v1.33.2 — wired motion primitives directly into the most-used user-facing block sections (benefits, features, pricing, process, cta) so every workspace inherits richer polish automatically: <Stagger> on benefit/feature/pricing/process grids reveals their children sequentially as the section scrolls into view (childDelay 0.04-0.12s tuned per section); <HoverLift as='span' lift={4}> wraps the primary CTA Link so the call-to-action gets a tactile, brand-tinted glow on hover. Total: 5 section files modified, ~5-10 lines each — minimal surface change, max visual impact. v1.34.0 — added motionPreset field to OrgTheme types ('minimal' | 'subtle' | 'balanced' | 'editorial', default 'balanced'). Each preset has an operator-friendly description used by the apply_motion_preset response. NEW MCP TOOL apply_motion_preset({preset, workspace_id}) routes to NEW POST /api/v1/theme/motion-preset which validates the preset, spread-merges into existing OrgTheme, persists. Today the renderer applies the 'balanced' set's primitives unconditionally; preset gating in renderers ships in v1.34.x. The preset's primary value today is storing OPERATOR INTENT — Claude Code reads it via get_workspace_state and uses it as a hint when generating new content (e.g. don't add Counter to a workspace that picked 'minimal'). DISCOVERY SURFACES (the antifragile graceful-disclosure pipeline). finalize_workspace response now includes a structured next_steps_available array: [apply_motion_preset, apply_design_md, import_claude_design_handoff, update_landing_content/configure_booking/customize_intake_form] with per-tool 'when' triggers + example calls. The human-facing summary string also adds an 'Optional upgrades (when you're ready)' section listing the same 4 paths. FIRST_CALL_BANNER updated to mention all three customization tools (apply_motion_preset, apply_design_md, import_claude_design_handoff) with explicit guidance: 'All three tools are OPTIONAL — surface them only when the operator's vibe asks for it (\"make it feel premium\", \"I have a brand kit\", \"I just exported from Claude Design\"). Never push these on a user who just wants a working site.' Pipeline philosophy: SMART DEFAULTS at workspace creation (every site ships polished automatically — RevealOnScroll on sections, Stagger on grids, HoverLift on CTAs), LEVERS exist for those who explore (apply_motion_preset for intensity tuning, apply_design_md/import_claude_design_handoff for full design-system replacement), CLAUDE CODE ROUTES INTELLIGENTLY based on conversation vibe (never blocks, always offers). Two new MCP tools (apply_motion_preset + the existing apply_design_md/import_claude_design_handoff from v1.33.1), one new CRM route (/theme/motion-preset), one type addition (MotionPreset enum + OrgTheme.motionPreset?), no migrations, no env vars. Backend redeploy required.",
27
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.33.1: BRING-YOUR-OWN-DESIGN-SYSTEM MCP TOOLS — apply_design_md + import_claude_design_handoff. Closes the workflow gap where third-party AI design tools (Anthropic Claude Design, Google Labs design.md, v0, Lovable, etc.) produced output that operators had to manually translate into SF tool calls. Now Claude Code can pipe their output directly into a workspace via two new MCP tools. WHAT SHIPS: (1) NEW MCP TOOL apply_design_md. Accepts the FULL CONTENT of a DESIGN.md file (the Google Labs format: YAML front matter for tokens + Markdown for rationale) as a string. The MCP-client process reads the file in the operator's environment (e.g. fs.readFile in Claude Code) and passes the content to the server, which parses YAML front matter, extracts tokens, maps tokens.colors.primary / tokens.colors.accent / tokens.mode / tokens.typography.body to OrgTheme fields, and applies. Tokens that don't map 1:1 (spacing scales, custom shadows, component-specific tokens) come back in `unmapped` so Claude Code can decide whether to surface them via update_landing_page (as CSS custom properties on individual pages) or just inform the operator. Server caps at 256KB. Token-reference resolution supported (e.g. {colors.primary.500} → resolves through the YAML tree). Handler routes to NEW POST /api/v1/theme/apply-design-md. (2) NEW MCP TOOL import_claude_design_handoff. Accepts a Claude Design handoff bundle as a JSON object — the artifact Claude Design produces when a design is ready for code (HTML or React components + design tokens + asset URLs). Defensive bundle schema (Anthropic hasn't published a formal spec yet): { meta?: { project_name?, target? }, tokens?: { colors?, typography?, mode? }, components: [{ name, surface?, react_source? OR html_source?, props_schema?, deps? }], assets? }. Server applies any embedded tokens to OrgTheme via the same path as apply_design_md, validates each component (name presence, surface enum, source size, props_schema shape) and returns a structured manifest with truncated source previews + per-component 'next_step' instructions for wiring them via update_landing_page or add_custom_block. CRITICAL — does NOT auto-execute generated React on live customer pages. Components route through human/eval review (the same gate that protects published agents). Customer-facing surfaces still run through the eval gate before publish; Claude Design output isn't trusted to bypass that. Limits: 1MB total bundle, 64KB per component source, 40 components per import. Handler routes to NEW POST /api/v1/handoff/import. (3) NEW CRM ROUTES at packages/crm/src/app/api/v1/theme/apply-design-md/route.ts and packages/crm/src/app/api/v1/handoff/import/route.ts. Both use the existing v1-identity auth, demo-readonly + assertWritable guards, log-event observability, and OrgTheme spread-merge pattern. yaml dependency (already installed at ^2.8.4) used for parsing. Architectural pattern: thin parse + map + apply on the server, fat skill (when to apply, which surfaces to wire, how to compose with other tools) in Claude Code via the SF MCP. As frontier models improve at parsing third-party design output formats, every operator's customization workflow gets richer without us updating the CRM. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: an operator who designed a page in Claude Design or has a DESIGN.md file from their brand team can now apply it to their SF workspace in one Claude Code prompt: 'apply my DESIGN.md' or 'import this Claude Design handoff'. Closes the loop on SF as the open, MCP-native, design-tool-agnostic Business OS — operators bring whatever AI design tool they prefer, output flows through Claude Code into SF without manual translation. Per the Becker frameworks insight: the value isn't the design tool, it's the wired-up infrastructure that accepts whatever the operator already designed.",
28
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.33.0: USER-PUBLISHED PAGES INHERIT MOTION POLISH AUTOMATICALLY (CRM-side; MCP package version bumped for SemVer hygiene). v1.32.1 shipped 8 motion primitives (RevealOnScroll / Stagger / HoverLift / Counter / TextReveal / Marquee / MagneticButton / Parallax) but they were standalone — operators had to wire them in manually (or via Claude Code) for any visual benefit. v1.33.0 wires the most impactful primitive — RevealOnScroll — into the user-facing page renderer so every published landing page inherits scroll-triggered reveals automatically. WHAT SHIPS: (1) page-renderer.tsx now wraps every section below the fold in <RevealOnScroll distance=20 duration=0.55 margin=-100px>. The first section (assumed hero / above-the-fold) renders directly with no animation — preserves LCP / immediate paint. Subsequent sections fade + slide up 20px as they enter the viewport, with -100px margin so the animation kicks slightly before the section is fully visible (feels lively, not pop-in). (2) PageRenderer stays a React Server Component. RevealOnScroll has 'use client'; only the thin wrapper hydrates. The block content rendered inside (manifest.render(...)) stays server-rendered. SEO / LCP / streaming all unaffected. Wrapper rendered with className='block w-full' so it doesn't disrupt the section's layout. (3) Per the antifragile motion philosophy: this is the dumbest, safest primitive applied universally. The 'skill' of when to compose richer motion (TextReveal on hero headlines, MagneticButton on CTAs, Stagger on grid blocks, Counter on stat blocks) lives in Claude Code via the SF MCP — applied per-page based on the operator's intent. As frontier models improve at picking and composing primitives, every user's pages get richer without us shipping new code. NO new dependencies (motion already installed), NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: every operator with a published landing page wakes up tomorrow with a tangibly more polished site — sections fade up as visitors scroll, instead of just being there from the start. The Linear-class 'this site feels expensive' signal applied universally, with zero operator action required. Future ships can wire the other primitives (Stagger on grid blocks, Counter on stats) into specific block types in the manifest, and add `apply_motion_preset` MCP tools so Claude Code can elevate any page on demand ('make my hero more impactful' → composes 4-5 primitives).",
29
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.32.1: MARKETING — REALISTIC DASHBOARD HERO + COPY FIXES + MOTION PRIMITIVES LIBRARY. (1) HERO RIGHT-PANE redesign. The v1.32.0 right pane showed a stylized landing-page mockup that read as 'designer illustration' rather than 'real product.' v1.32.1 replaces it with a credible admin dashboard view: browser chrome (URL app.seldonframe.com/dashboard), 34/66 split with left sidebar (workspace tile 'Acme HVAC' + nav items) and right main content (Pipeline kanban with 4 columns: New Lead / Quoted / Scheduled / Won). Sidebar nav items light up with green glowing dots sequentially as the build tools fire on the left pane (Pages at 1.5s, Bookings at 2.5s, Intake Forms at 3.5s, Agents at 4.5s — matching the tool-call timing). Kanban cards appear in their columns at staggered times: 'AC repair · 5012 N 32nd St · $340' lands in Quoted at 2.6s, 'Furnace tune-up · Glendale · $120' lands in Quoted at 3.6s, 'AC install · May 10 · 2pm · $4,800' lands in Scheduled at 4.6s. Bottom-right shows live agent indicator 'Acme HVAC Bot · v1 · live · 200 ok'. Helper components added: NavIcon (6 inline SVG icons), NavGroup (animated label + children), NavItem (with optional lightUpAt prop for the green-dot reveal), KanbanColumn (label + count + cards with appear-at delays). (2) COPY FIXES. Case study heading 'What 12 minutes of Claude Code looks like' → 'What 5 minutes of Claude Code looks like'. Body 'on camera in 12 minutes' → 'on camera in 5 minutes'. Stat tile '12 min build to live' → '5 min build to live'. Aligned with the hero's 'under 5 minutes' claim. Infrastructure section link '→ Browse 25+ MCP servers for SMB operators' → '→ 140+ MCP tools your agent can call' (now points to /docs instead of /docs/mcp-servers). Bigger number, more accurate framing — these are SF's own MCP tools, not third-party servers. (3) NEW MOTION PRIMITIVES LIBRARY at packages/crm/src/components/motion/. Antifragile design: thin wrappers around motion/react with sensible defaults; Claude Code composes them into rich page experiences via natural-language prompts. Eight primitives shipped: <RevealOnScroll> (fade + slide up on scroll-into-view, configurable distance/duration/delay/once/margin/as), <Stagger> (children reveal one-by-one with childDelay between), <HoverLift> (hover-lift + accent glow on cards, configurable lift + glowColor), <Counter> (animate from 0 → value when scrolled into view, with prefix/suffix/separator/decimals options), <TextReveal> (split text by word, reveal word-by-word with wordDelay), <Marquee> (infinite horizontal scroll for logo bars, configurable speed/direction/pauseOnHover/gap), <MagneticButton> (button subtly attracted to cursor with spring physics + configurable strength), <Parallax> (scroll-linked Y translate, configurable speed). PRESETS object exports reusable transition configs (reveal, pop, fade) for callers rolling their own motion.div. EASE_OUT_EXPO constant exported for shared easing curve. Each primitive accepts theme-agnostic className overrides; defaults match the SF brand (teal accent, restrained motion durations, conservative distances). Operators don't tune these — Claude Code does, picking and composing primitives based on the user's intent. As frontier models improve at this composition, every SF user's pages get richer without us shipping new animation code. Index file at components/motion/index.ts re-exports primitives + types. NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: visitors see a credible admin CRM (kanban + sidebar) in the hero — 'this is real product' rather than designer mockup. Numbers across the page are consistent (5 min, 140+). Motion primitives are available from any user-facing block; future ships can wire them into landing-section-renderer.tsx as defaults so every user's published page automatically inherits the polish without explicit operator action.",
30
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.32.0: MARKETING — HERO + CTA + COPY OVERHAUL (Becker frameworks + Hormozi value equation + 12yo language). User feedback: 'eval gate IS NOT what clients want.... they want a fully personalized and already wired ai-native business OS created in less than 5 minutes using natural language in claude code.... fully customizable to their specific edge cases. dumb down language to 12 years old, cut out any fluff text, answer the $100M offer value equation. CTA should be install MCP — only working path.' Inspired by Alex Becker's video on the future of SaaS — frameworks (CRM + landing page + calendar + intake) wired together with same branding, customizable per business, no Zapier breaking. v1.32.0 rewrites the marketing site around this. WHAT SHIPS: (1) HERO REWRITE. Replaced AgentEvalCard (which showed eval gate flipping green) with BuildAndShowCard — a two-pane animated mock that's the launch story's actual money shot. LEFT pane (40%): Claude Code terminal showing user prompt 'Build a website for Acme HVAC. Phoenix, AZ. AC repair and install. Phone (602) 555-0188.' followed by 4 sequential MCP tool calls (build_landing_page / build_booking_page / build_intake_form / build_website_chatbot) firing every second with green '200 ok' status pills, ending with '✓ Live at acme-hvac.app.seldonframe.com'. RIGHT pane (60%): a mini-browser preview showing the landing page being built in sync — empty skeleton with spinner first, then navbar with 'Acme HVAC' wordmark, then hero section ('AC repair, fast.'), then booking calendar (14-day grid with one date highlighted teal), then intake form (Name / Phone / Submit), and finally a chatbot bubble that pops in bottom-right. Total animation ~6 seconds, plays once on load. Hits Hormozi's value equation: Dream Outcome (complete wired Business OS visualized), Likelihood (shown working in <7s), Time (animation IS the proof of '<5 min'), Effort (one prompt builds everything). (2) HERO COPY rewrite. Headline went from 'Build a complete AI-native Business OS with natural language' to 'Your website, CRM, calendar, and AI chatbot. Built in under 5 minutes by typing what you want.' — concrete (lists what you get), specific time, plain action verb. Subhead from 'CRM, website, AI agents, and automations — all in one workspace, built and updated through natural language with Claude Code. Eval-gated before going live.' to 'One sentence in Claude Code. SeldonFrame builds your landing page, booking calendar, intake forms, and CRM — all linked, same brand. Change anything by saying so. No Zapier. No code. No duct tape.' — Becker-language ('linked, same brand', 'no Zapier'), 12yo reading level. (3) CTA OVERHAUL. Primary CTA across hero, nav, FinalCTA changed from 'Start for free → /signup' to 'Install the MCP → #install' (anchors to HowItWorks section). Below hero CTAs: NEW <InstallCommandPill> showing the actual command 'claude mcp add seldonframe -- npx -y @seldonframe/mcp' with one-click copy button (clipboard icon → green checkmark + 'copied' on success, resets after 1.8s). Secondary hero CTA changed from 'Watch the demo' to 'See a live build → /demo'. (4) HOWITWORKS rewrite + #install anchor. Three steps reframed for Becker-frameworks language: Step 1 'Install in Claude Code' with the actual install command. Step 2 'Tell it about your business' with the example prompt. Step 3 'Get your wired-up business' with the live URL. Section heading changed from 'How it works · Three steps. About a minute. A complete Business OS, live in production.' to 'Three steps. Under five minutes. · No drag-and-drop. No setup wizards. No \"let's hop on a call.\" Just type, and it builds.' Section gets id='install' so hero CTA scrolls smoothly here. (5) FEATURESTORIES rewrite. Three new stories: Story 1 'Type, don't click — One prompt. Five tools built.' (uses ClaudeCodeMockVisual). Story 2 'Wired. No Zapier — Your tools share one brain.' (uses NEW <WiredFrameworkVisual>: hub-and-spokes diagram with SF logo at center, 4 framework tiles Website/Calendar/Forms/CRM in corners connected by faint teal dashed lines, bottom caption 'Same database · Same brand · Same admin'). Story 3 'Edge cases? Say so — Change anything by typing the change.' (uses NEW <EditAnythingVisual>: Claude Code mock showing a follow-up prompt 'Raise the AC repair price from $89 to $99. Add Glendale to service areas.' followed by 3 tool calls update_agent_pricing / update_landing_page / run_agent_evals all green, ending with '✓ Updated · v3 → v4 · live'). (6) FINALCTA rewrite. Headline 'Start building in five minutes' → 'Stop stitching. Start typing.' Subhead replaced. CTAs aligned with new install-MCP message. (7) DEAD CODE REMOVAL. Deleted unused RuntimeRegenVisual + EmbedBubbleVisual components (used in v1.31.1 but superseded by WiredFrameworkVisual + EditAnythingVisual + the BuildAndShowCard's chatbot bubble). NO new dependencies, NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: a launch-video viewer landing on seldonframe.com sees the actual product getting built in real-time within 7 seconds — not abstract claims, not 'eval gate' jargon they don't care about. Headlines and copy speak at 12yo reading level. CTA tells them exactly what to do (install the MCP) and shows the command. Becker's framework insight is the spine: SF gives you frameworks, wired together, with one brand, fully customizable by saying so. Hormozi's value equation hit across hero, HowItWorks, FeatureStories, FinalCTA: high dream outcome, high likelihood, low time, low effort.",
31
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.31.3: MARKETING — CASE STUDY + REPLACES-COMPARISON + ROUTE COLLISION HOTFIX (CRM-side; MCP package version bumped for SemVer hygiene). v1.31.2 build failed on Vercel: my new (marketing)/privacy and (marketing)/terms pages collided with pre-existing app/privacy and app/terms pages I missed during the earlier audit. Production stayed at v1.31.1 (cd120ee). v1.31.3 ships the hotfix + the planned case-study work in a single commit. WHAT SHIPS: (1) HOTFIX — deleted (marketing)/privacy/page.tsx and (marketing)/terms/page.tsx. The pre-existing app/privacy/page.tsx and app/terms/page.tsx already had substantial content (10-section privacy policy + 10-section TOS, last updated April 2026, dashboard-themed) that's better than my minimum-viable replacements. The footer links never 404'd; my audit was wrong. /blog index + /blog/why-mcp from v1.31.2 stay in place since they're net-new with no sibling collisions. (2) NEW <CaseStudy> component, replacing the centered CTA-card <SeeItBuilt>. Two-column layout: left side has 'Worked example' pill, h2 'What 12 minutes of Claude Code looks like', 2 paragraphs framing Desert Cool HVAC honestly as a worked-example fixture (not a fabricated customer) — narrative covers Phoenix, AZ context, the 5 tools they came from (Salesforce/Cal.com/Mailchimp/Intercom/Webflow), and what got built (landing page, booking, intake, CRM with HVAC fields, published chatbot). CTA 'Watch the walkthrough →' → /demo. Right side: 4-stat grid (12 min build-to-live, 5→1 tools replaced, 8/8 evals passed, 0 lines hand-edited) with motion-staggered scale-in. (3) NEW <Replaces> component. Visual story for the consolidation pitch: 5 generic tool tiles (CRM / Scheduler / Email tool / Chatbot / Site builder) with diagonal strikethrough overlays + dimmed colors, a teal arrow, then the SF logo+wordmark in a glowing card. Heading 'Replaces the stack you've been duct-taping together', subhead 'Five tools, one workspace. Same database. Same brand. Same admin. And the AI agents come with it.' Tool tiles use category labels (not competitor brand names) to avoid trademark risks; the visual shape carries the message. (4) PAGE COMPOSITION updated: <SeeItBuilt> removed, <CaseStudy> + <Replaces> inserted between <HowItWorks> and <Pricing>. New flow: Nav → Hero → FeatureStories → HowItWorks → CaseStudy → Replaces → Pricing → Infrastructure → FinalCTA → Footer. NO new dependencies, NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: visitors who scroll past the hero and feature stories now hit a credible end-to-end story (12 minutes, 5→1, here's what got built) and a visual gut-punch for the consolidation pitch (5 dimmed tool tiles → SF wordmark). Frames the Desert Cool HVAC fixture honestly as a worked example so credibility holds. The build also unsticks production from v1.31.1 — Vercel will now successfully deploy v1.31.0 hero + v1.31.1 feature stories + v1.31.2 blog index + v1.31.3 case study + replaces all together.",
32
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.31.2: MARKETING SITE — KILL 404s + FIRST REAL BLOG POST (CRM-side; MCP package version bumped for SemVer hygiene). The marketing footer linked /privacy, /terms, /blog — but /privacy and /terms 404'd entirely, and /blog was a 'Coming soon' stub. Three credibility leaks for launch-week visitors. v1.31.2 fills all three. WHAT SHIPS: (1) NEW (marketing)/privacy/page.tsx. Plain-English privacy notice — what we collect (account info, workspace data, anonymous usage telemetry), what we don't (LLM keys readable in plaintext, payment data, fingerprints), how we use it (operate the product, no model training, no resale, no aggregation), where it lives (Postgres on Neon, Vercel hosting), sub-processors list, your-rights section (export anytime, delete account, contact privacy@), changes notice, contact. Marked as minimum-viable for launch — flagged in source-comment to be replaced with a lawyer-reviewed full policy before scaling beyond launch-week traffic. (2) NEW (marketing)/terms/page.tsx. Plain-English TOS — account responsibility, allowed uses (legitimate business ops, for-profit + non-profit), disallowed uses (spam, illegal content, deceptive AI agents, reverse-engineering, reselling without Agency tier), data ownership ('Workspace data is yours'), open-source MIT license note, billing flow (failed payment retries), service level (99.9% target on Pro+; SLA only on Agency), liability cap (12 months of fees), changes notice. Same minimum-viable framing. (3) REWROTE (marketing)/blog/page.tsx. Was a 50-line 'Coming soon — follow @seldonframe' stub. Now a real index with 3 posts: 'Why we built SeldonFrame on MCP' (live, links to /blog/why-mcp), 'How the eval gate works' (coming soon marker), 'BYOK is not a feature, it's the deal' (coming soon marker). Each post card shows date + author + lede; live posts have a 'Read post →' arrow that animates on hover; 'coming soon' posts have a uppercase 'Coming soon' chip and reduced opacity but stay in the visual rhythm. Bottom CTA points to X + Discord for new-post notifications. (4) NEW (marketing)/blog/why-mcp/page.tsx. First real launch-week blog post (~700 words). Sections: 'The default architecture is wrong' (chatbot-wrapper playbook critique), 'What changed: agents have IDEs' (Claude Code / Cursor / etc. + MCP), 'The bet: expose everything as tools' (140+ MCP tools mapping to dashboard surfaces), 'Why this works' (3 reasons: agent faster than click-through, agent improves automatically with model upgrades, dashboard stays simple), 'What we gave up' (marketing-page conversion friction), 'What's next' (preview of upcoming posts on eval gate / BYOK / durable workflows). Footer with 'All posts' back-link + GitHub source link. Authentic voice — no marketing fluff, real architecture argument. (5) NEW .marketing-prose CSS class in globals.css. Mirror of .docs-prose but with hardcoded marketing palette (#fafafa foreground, #a1a1aa muted, #1FAE85 accent, white/5 borders) so the prose renders correctly on the always-dark marketing pages regardless of root theme setting. NO new dependencies, NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: launch-week visitors clicking the footer's Privacy / Terms / Blog links land on real pages — no 404s. The first real blog post (Why MCP) is a credible architecture argument that signals 'this team thinks about the work' to the developer audience, who are the people most likely to share the launch with SMB operator friends. Minimum-viable on legal pages keeps options open without blocking launch on lawyer review.",
33
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.31.1: MARKETING SITE — FEATURE STORIES (\"show, don't tell\") (CRM-side; MCP package version bumped for SemVer hygiene). The marketing site's middle was a flat 6-up Features grid (Per-client branding / Agents with memory / Closed-loop attribution / Natural language scaffolding / Approval gates / Cost visibility) that read like a feature list, not a launch site. Above it, a 'Who is SeldonFrame for?' Personas section with 2 emoji-icon cards (🛠️ Build for yourself, 🏢 Build for your clients) felt like a Notion template. Both sections used the same vertical rhythm as everything else (centered h2 + grid of cards), making the page visually monotonous. v1.31.1 replaces both with three story-driven feature blocks. WHAT SHIPS: (1) NEW <FeatureStories> component in (public)/landing-client.tsx. Three feature stories in alternating image-left/image-right layout, each with a small CSS+SVG product mockup beside body copy. Section heading 'What makes SeldonFrame different' + supporting subhead. (2) STORY 1 — Build with Claude Code (image-right). Pill 'Build with Claude Code'. Heading 'Describe what you want. Watch it ship.' Body emphasizing the 140+ MCP tools and the launch-flow continuity ('the launch story isn't a demo, it's the actual flow'). Visual: Claude Code-styled terminal showing user prompt → 4 sequential MCP tool calls (get_workspace_state / build_website_chatbot / run_agent_evals / publish_agent) each with green status pills → 'Acme Dental Chatbot is live' confirmation. CTA → /docs/getting-started/connect-claude-code. (3) STORY 2 — Eval-gated, regen on fail (image-left). Pill 'Eval-gated, regen on fail'. Heading 'Agents you can actually trust in production.' Body explains the 8-scenario suite + the runtime regeneration on critical-fail (the v1.28.6 architecture). Visual: 'agent runtime · live' card showing an amber 'critical-fail validator' warning (no_state_change_hallucination), a 'regenerate with correction prompt' arrow, and a green 'regenerated · clean' result with the corrected agent response. CTA → /docs/agents/eval-gate. (4) STORY 3 — Embed anywhere (image-right). Pill 'Embed anywhere'. Heading 'One script tag. Brand-themed. Mobile-friendly.' Body covers the embed snippet, brand-themed styling, SF-hosted pages getting wired automatically, and conversation logging back to CRM. Visual: aspect-4/3 fake-website mockup with skeleton content rectangles, a chatbot bubble in the bottom-right (gradient teal-to-darker-teal with shadow), and a speech-bubble greeting 'Hi! Looking to book a service today?'. CTA → /docs/agents/embed. (5) <FeatureStory> primitive component handles the alternating layout, the pill, headline, body, CTA, and the visual slot. <ClaudeCodeMockVisual>, <RuntimeRegenVisual>, <EmbedBubbleVisual> are pure CSS+SVG (no images, theme-aware, fast). (6) Removed <Personas> + <Features> components from the page composition. The audience-defining message Personas carried (solopreneur vs agency) implicitly resolves through the feature stories themselves; explicit personas section was redundant and visually weak. Page composition now: Nav → Hero → FeatureStories → HowItWorks → SeeItBuilt → Pricing → Infrastructure → FinalCTA → Footer + DiscordFloat. NO new dependencies, NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: the marketing site middle goes from 'list of features in cards' to 'three product stories with motion' — Linear-style. Each story has a clear visual the eye can latch onto and a single CTA into the docs. Page rhythm varies (alternating left/right) instead of repeating centered grids. Visitors who scroll past the hero now see what SF actually looks like operating, not just words about what it does.",
34
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.31.0: MARKETING SITE — HERO REWRITE + PRODUCT VISUAL (CRM-side; MCP package version bumped for SemVer hygiene). The seldonframe.com hero showed a small terminal mockup with a `claude mcp add` install command and a workspace-creation success block — true to the install flow, but it didn't show the launch story's ACTUAL magic moment: the eval gate flipping each scenario green before an agent goes live. Visitors landing on the marketing site never saw a product visual; the whole pitch was text. v1.31.0 fixes that. WHAT SHIPS: (1) NEW AnimatedEvalCard mock in (public)/landing-client.tsx. Pure CSS+SVG (no images, theme-aware, fast). Composition: browser chrome (mac dots + URL `app.seldonframe.com/agents/acme-hvac/evals`); agent header row showing 'Acme HVAC Chatbot' + version 'v3' + animated 'Live' status pill that appears at 2.6s; eval body with 'Eval gate' label + animated `8/8 passed` counter + progress bar that fills from 0% to 100% over 1.6s; 8-scenario grid (Greeting / FAQ accuracy / Booking / Reschedule / Refusal / PII handling / Escalation / Tone consistency) with each scenario's checkmark spring-popping in sequentially over ~1.4s; bottom 'Publish unlocked' pill with the green-checkmark glyph and '≥ 87.5% threshold' caption that appears at 2.8s. Total animation ~3 seconds, paced for first-impression — no loop, plays once on hero load. (2) HERO COMPOSITION REWORK. Heading scaled up (clamp(36px,5.5vw,64px) was 34px,5vw,56px), tracking tightened (-0.04em was -0.035em). Subhead rewritten from abstract 'Composable primitives to create customized business operating systems...' to concrete 'CRM, website, AI agents, and automations — all in one workspace, built and updated through natural language with Claude Code. Eval-gated before going live.' Primary CTA changed from 'Start for $0' (technical) to 'Start for free' (operator-language) and pointed at /signup (visitor → operator funnel) instead of /docs/quickstart (developer flow). Secondary CTA 'Watch the demo' kept. Subtle radial-gradient glow added behind the hero (rgba(31,174,133,0.18) → transparent radial) for Linear-quality depth. Section max-width grew from 1140 to 1180 to accommodate the wider eval card. (3) NAV CTA updated to match: 'Start for $0' → 'Start for free', /docs/quickstart → /signup. (4) FINAL CTA at bottom updated: 'Quick start' → 'Start for free', /docs/quickstart → /signup. Secondary 'Read the docs' kept. NO new dependencies, NO migrations, NO new env vars, NO MCP tool changes. Pure (public)/landing-client.tsx + welcome.js + package.json. Backend redeploy required. EXPECTED IMPACT: launch-video viewers landing on seldonframe.com see a real product visual within 2 seconds — the eval gate filling up green, scenarios checking off, 'Publish unlocked' appearing. The launch story's actual magic moment becomes the hero's centerpiece, not a buried subsection. The hero now matches Linear-quality: bigger heading, confident gradient, animated product UI, operator-language CTAs. Five more ships in v1.31 series will replace the flat 6-up Features grid with story-driven feature blocks (v1.31.1), build out the Desert Cool HVAC case study (v1.31.2), real /blog index + /privacy + /terms (v1.31.3), and final polish (real wordmark SVGs, mobile pass, OG image refresh, Lighthouse audit) (v1.31.4).",
35
+ "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.30.2: /docs CONTENT + LOGO POLISH (CRM-side; MCP package version bumped for SemVer hygiene). v1.30.0 shipped the /docs scaffold (header, sidebar, homepage) but every sidebar link was an anchor placeholder (#chatbot, #workspaces) and the header logo was a literal 'SF' text div. v1.30.2 fills both gaps. WHAT SHIPS: (1) REAL LOGO IN /docs HEADER. Replaced the placeholder 'SF' text in app/docs/docs-header.tsx with the actual SeldonFrame icon SVG (/brand/seldonframe-icon.svg) — same brand-isolated icon the dashboard sidebar uses. Wordmark text now reads 'SeldonFrame Docs' instead of bare 'Docs', creating visual continuity between the dashboard and /docs. (2) 34 REAL ARTICLE PAGES. Each of the 33 sidebar items (8 categories × 4-5 items each) plus the /docs/learn footer link now resolves to a real, navigable page at app/docs/<category>/<slug>/page.tsx — no more #anchor placeholders. Categories: Getting started (4), Your business (4), Customers/CRM (4), AI Agents (5), Pages & website (4), Email & Automation (4), Integrations (5), Billing & plans (3), plus /docs/learn. Sidebar updated to point at /docs/<category>/<slug> routes; docs-sidebar.tsx open-state defaults updated for renamed 'agents' category id (was 'ai-agents'); active-state highlight now uses startsWith so deep routes still highlight their parent category in the sidebar. (3) NEW app/docs/article-shell.tsx. Shared layout component every article wraps in: breadcrumb (Docs › Category), big H1 + lede paragraph, prose body, footer with 'Back to all docs' + 'Edit on GitHub' link. Plus inline helper components: <Step n=1 title=...> (numbered how-to steps), <ComingSoon> (dashed-border 'Coming soon' marker), <Callout variant=info|tip|warn>, <CodeBlock>, <InAppLink href=>. Articles compose from these primitives — every page reads consistently. (4) docs-prose CSS in globals.css. ~30-rule body-style block scoped to .docs-prose: tighter line-height (1.75), restrained heading scale (h2 1.5rem semibold, h3 1.125rem), comfortable line length, theme-aware code/em/blockquote/list styling. Rolled our own instead of @tailwindcss/typography for exact control. (5) ARTICLE CONTENT SHAPE. Linear-style: terse, opinionated, lots of links to in-app surfaces and other docs (so navigation feels alive). Each Getting Started + AI Agents + Pages article goes deep with real content (60-second walkthroughs, code examples, eval-gate explanation). Your business / Customers / Email-Automation / Integrations / Billing articles are concrete but more compact (still real content, not lorem ipsum). The 'Voice + SMS' page intentionally signals 'coming soon' rather than faking unreleased capability. (6) lucide-react icon fix. ArticleShell originally tried to import 'Github' which doesn't exist in the installed lucide-react version; swapped to 'Pencil' for the 'Edit on GitHub' link. Caught at typecheck. NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: launch-video viewers landing on /docs see the SF logo (not 'SF' text), can click any sidebar item and land on a real article (not a stuck-in-place anchor scroll), read content with proper typography (not unstyled <h2>/<p>/<ul>), and trust the documentation enough to actually use SF. The sidebar is now genuinely a navigation surface, not a wishlist.",
4
36
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.30.1: HOTFIX — v1.30.0 build failed on Vercel because the new app/docs/ route collided with an existing app/(public)/docs/ route. Both resolved to /docs. Next.js parallel-routes error halted the build, leaving production stuck on v1.29.1. The old (public)/docs/ was an API reference page (workspaces / secrets / Seldon It / Brain / OpenClaw curl examples) created earlier in the year. The new app/docs/ is the Linear-class user-facing documentation hub. They serve different audiences (developers vs. operators) and overlap in content — but cannot coexist at the same URL. Decision: keep the new Linear-class /docs as the primary surface (operator-facing is the launch priority), delete the old API-reference /docs (content lives on in git history at cb8d3d2 and can be revived as a /docs/api article when docs gets deeper article pages). Also removed the now-orphaned components/docs/api-docs-code-block.tsx + the empty components/docs/ directory. NO behavior change beyond unblocking the build. The new Linear-class /docs route from v1.30.0 ships unchanged. NO migrations, NO new env vars, NO MCP tool changes. @seldonframe/mcp version bumped for SemVer hygiene.",
5
37
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.30.0: LINEAR-CLASS /docs PAGE (CRM-side; MCP package version bumped for SemVer hygiene). The sidebar's 'Docs' link pointed at /docs but the route didn't exist (404). v1.30.0 builds the entire route from scratch as a standalone documentation surface (outside the dashboard route group), modeled on linear.app/docs structure. WHAT SHIPS: (1) NEW app/docs/layout.tsx — standalone shell, no dashboard chrome. Wider max-w-1080px content area, generous py-16 vertical breathing room, sticky top header + collapsible left sidebar + main column. (2) NEW app/docs/docs-header.tsx — Linear-style top bar: SF logo + 'Docs' label on left; centered search input with ⌘K kbd hint; theme toggle + Sign in + Sign up CTA on right. Sticky, backdrop-blurred. Search is non-functional in v1.30.0 (placeholder for v1.30.1 with content indexing). (3) NEW app/docs/docs-sidebar.tsx — collapsible category nav with 8 sections (Getting started / Your business / Customers (CRM) / AI Agents / Pages & website / Email & Automation / Integrations / Billing & plans), 38 article links total. Each category expands/collapses; current page highlighted. Bottom 'meta' nav: Docs / Developers (→ GitHub) / Learn / Contact support (→ Discord). (4) NEW app/docs/page.tsx — homepage with: HERO (4xl/5xl heading + subtitle), POPULAR GRID (4 large cards: 3-minute demo / Build a chatbot / First workspace / Claude Code MCP), QUICK START STEPPER (4 numbered steps with code blocks: install MCP / build workspace / add chatbot / customize from dashboard), CORE CONCEPTS GRID (6 small cards: Soul / Agents / Templates / Workspaces / Customers / Bookings), 6 DETAILED CATEGORY BLOCKS (each is icon + title + 4 link rows in a unified card grid), LEARN section (video tutorials + customer stories), and a final 'Build your first workspace' CTA card with gradient. CRAFT DETAILS: hover lifts on cards (border-primary/30 + bg-accent/20 + icon color shift); arrow icons translate-x on hover; primary-tinted icon backgrounds throughout; tabular spacing; generous whitespace between sections (space-y-16 on hero/section gaps). All article hrefs are anchor placeholders (#chatbot, #workspaces, etc.) for v1.30.0; individual article pages get authored over time without changing nav structure. Sidebar 'Docs' link now actually works (was 404). Compatible with the existing app shell — uses next-themes for dark/light toggle, lucide-react for icons (already-installed deps); no new packages. NO migrations, NO new env vars, NO MCP tool changes. Backend redeploy required. EXPECTED IMPACT: launch-video viewers landing on /docs see a polished Linear-class documentation surface that signals 'this product is real and well-built.' SF clients curious about features can now actually find them organized cleanly. /docs becomes the surface that transforms 'is this real?' into 'I want this.'",
6
38
  "description": "MCP server for SeldonFrame — AI-native Business OS platform. v1.29.1: BODY COPY + EMPTY STATES (LINEAR-CLASS CRAFT) — second pass on the v1.29.0 vocabulary work, focused on per-page polish: typography, empty-state heroes, and the dashboard welcome heading the operator sees the moment they log in. WHAT SHIPS: (1) /landing EMPTY STATE HERO. Was: small 'Create your first landing page — Choose a template to get started' card. Now: full hero card with circular icon ('Layout' in primary tint), 'Build your first page' h2, plain-English subtitle ('Pages live on your public website — landing pages, lead forms, booking flows. Start from a template below or build from scratch.'). Template grid below promoted with hover transitions to primary-tinted icon backgrounds — micro-interaction polish. Header subtitle on /landing/page.tsx itself rewritten from 'Build and publish modular pages with integrated [intake form] and booking sections' to 'Your business's public-facing pages — landing pages, lead capture, booking flows.' (2) /emails HEADER REWORK. Was: a 'sub-header bar' style with Mail icon + counter dot, copying templates-baseui pattern. Now: standard page header (h1 + subtitle), more consistent with the rest of the dashboard. Subtitle: 'Send a one-off message or save a template to reuse for campaigns. [N] emails sent so far.' Counter only shows when > 0. Word renamed 'Emails' → 'Email' (singular like Gmail). (3) /forms STATS GRID HIDDEN WHEN EMPTY. Was: 4-card grid showing 'Total Forms / Active Forms / Draft Forms / Submissions' all with '+0 vs last month' labels even on a brand-new workspace with zero forms (dashboard inflation). Now: stats grid renders only when forms.length > 0; the '+0 vs last month' meaningless labels stripped entirely. Card titles tightened ('Total Forms' → 'Total', 'Active Forms' → 'Published', 'Draft Forms' → 'Draft'). Stat values use tabular-nums for cleaner alignment. (4) /automations SUBTITLE OUTCOME-FOCUSED. Was: 'Build, test, and deploy AI agents for this workspace. Each agent responds to a trigger (form submission, booking, SMS reply, schedule) and runs with your LLM key.' (technical, audience = SF developer). Now: 'Set up rules that run on their own — like sending a follow-up email when a booking comes in, or texting a reminder before a service call. Pick a template below to get started.' (concrete, audience = HVAC operator). Catalog header label 'Agent catalog' → 'Available templates'; 'archetypes' counter renamed to 'templates'. (5) /dashboard WELCOME HEADING POLISH. Was: 'text-lg sm:text-[22px]' with 'This is your calm workspace overview' (vague) for SF builders or 'Here's what's happening at your workspace today' for operators. Now: bigger 'text-xl sm:text-[28px]' tighter-tracking heading (more like Linear's homepage). Subtitle for both audiences rewritten to the concrete 'Here's what's happening at your business today' / 'Here's what's happening across your workspace today.' SF builder CTA 'Create New Client OS' renamed to 'New workspace' (operator-language; the CTA stays SF-builder-only via isOperatorSession gate). All changes are pure copy + CSS — zero new logic, zero new endpoints, zero new MCP tools. NO migrations, NO new env vars. Backend redeploy required. EXPECTED IMPACT: every primary surface in the dashboard now has a warm operator-language header, a hero-style empty state that teaches what the surface is for, and tighter typography. The 5-second test passes for /dashboard, /landing, /emails, /forms, /automations, /agents, /settings — plus the v1.29.0 sidebar work means navigating between them feels coherent.",
package/src/tools.js CHANGED
@@ -190,6 +190,284 @@ export const TOOLS = [
190
190
  return firstEver ? withFirstCallBanner(payload) : payload;
191
191
  },
192
192
  },
193
+ // v1.37.0 — Google Maps PASTE → workspace (no Places API).
194
+ //
195
+ // Discoverability shim around create_full_workspace. Same backend
196
+ // pipeline (POST /workspaces/create-full), same atomic guarantees,
197
+ // same finalize_workspace follow-up. The value-add: a tool whose
198
+ // DESCRIPTION teaches Claude Code exactly how to extract structured
199
+ // fields from a raw Google Maps paste — name, address, phone,
200
+ // categories→services, rating, review count, weekly hours — and
201
+ // which fields the backend pipes into which artifact (hours →
202
+ // booking template's metadata.availability via the new weekly_hours
203
+ // input, closing the loop with the v1.36.4 read-path fix).
204
+ //
205
+ // Thin harness, fat skill: NO regex parser on the backend, NO LLM
206
+ // call on the backend. Claude Code (the agent) parses the paste
207
+ // and calls this tool with the structured fields. The MCP server
208
+ // is just a typed shim over the existing POST endpoint.
209
+ //
210
+ // Why a sibling tool instead of bolting `weekly_hours` onto
211
+ // create_full_workspace? Discoverability. When the operator says
212
+ // "make a workspace from this Google Maps listing", Claude Code
213
+ // sees a tool literally named `create_workspace_from_google_paste`
214
+ // with a docstring full of paste-extraction examples — no judgment
215
+ // call about whether create_full_workspace is the right tool. The
216
+ // surface area is the documentation.
217
+ {
218
+ name: "create_workspace_from_google_paste",
219
+ description:
220
+ "PREFERRED when the operator pastes a Google Maps business listing. Same atomic pipeline as create_full_workspace; this tool's docs guide the paste-to-fields extraction. Claude Code parses the paste BEFORE calling this tool — never pass the raw paste text. " +
221
+ "EXTRACTION RULES (apply in order): " +
222
+ "1) business_name → the bold business title at the top of the listing. " +
223
+ "2) phone → the digits next to the phone icon. " +
224
+ "3) address → the line next to the location pin. Parse city + state from this address into separate fields (city/state). " +
225
+ "4) services → derive from BOTH the categories chip row (e.g. 'Plumber · Emergency plumbing service') AND any explicit 'Services' section ('Drain cleaning', 'Water heater repair'). Dedupe; keep 5-12 distinct strings. " +
226
+ "5) business_description → synthesize 1-2 sentences from the categories + 'About' / 'From the business' section. Include industry words verbatim (the personality classifier reads this). " +
227
+ "6) review_rating + review_count → the '4.7 ★ (950)' element. " +
228
+ "7) trust_signals → 'Licensed', 'Bonded', 'Insured', 'Family-owned' if mentioned. " +
229
+ "8) emergency_service / same_day → set true if 'open 24 hours', '24/7', 'same-day service' appears. " +
230
+ "9) service_area → cities mentioned in 'Service area' section. " +
231
+ "10) weekly_hours → parse the hours block ('Monday: 9 AM-5 PM, Tuesday: closed, ...') into the canonical shape: {monday:{enabled:true,start:'09:00',end:'17:00'},tuesday:{enabled:false,start:'09:00',end:'17:00'},...}. Keys MUST be FULL DAY NAMES (sunday/monday/.../saturday); times MUST be HH:MM 24-hour. 'Closed' → enabled:false (start/end are placeholders). 'Open 24 hours' → start:'00:00', end:'23:59'. These hours are written DIRECTLY to the booking template's availability — wrong shape = booking page falls back to Mon-Fri 9-5 default. " +
232
+ "11) google_place_url → the Maps URL the operator pasted, if visible. Optional, stored on soul.business.maps_url for audit. " +
233
+ "MANDATORY FOLLOW-UP: same as create_full_workspace — after this returns `status: 'ready'`, ask 'What email should I use for your account?' and call finalize_workspace({ workspace_id, email }).",
234
+ inputSchema: obj(
235
+ {
236
+ business_name: str("Business display name (top of the Maps listing)."),
237
+ city: str("City parsed from the Maps address line."),
238
+ state: str("US state code or full name parsed from the Maps address line."),
239
+ phone: str("Phone number from the Maps phone icon row, any format."),
240
+ services: {
241
+ type: "array",
242
+ description:
243
+ "Services derived from the Maps categories + 'Services' chips, deduped. 5-12 strings.",
244
+ items: { type: "string" },
245
+ },
246
+ business_description: str(
247
+ "1-2 sentence summary synthesized from Maps categories + 'About' / 'From the business' section."
248
+ ),
249
+ review_count: { type: "number", description: "Optional — review count from '★ (N)' display." },
250
+ review_rating: { type: "number", description: "Optional — average star rating (e.g. 4.7)." },
251
+ certifications: {
252
+ type: "array",
253
+ description: "Optional — credentials mentioned in the listing (['EPA-certified', ...]).",
254
+ items: { type: "string" },
255
+ },
256
+ trust_signals: {
257
+ type: "array",
258
+ description: "Optional — 'Licensed', 'Bonded', 'Insured', 'Family-owned' if surfaced.",
259
+ items: { type: "string" },
260
+ },
261
+ emergency_service: { type: "boolean", description: "Optional — listing shows 'open 24 hours' or '24/7'." },
262
+ same_day: { type: "boolean", description: "Optional — listing mentions 'same-day service'." },
263
+ service_area: {
264
+ type: "array",
265
+ description: "Optional — cities/neighborhoods from the 'Service area' section.",
266
+ items: { type: "string" },
267
+ },
268
+ email: str("Optional contact email from the listing (NOT the operator's account email)."),
269
+ address: str("Optional full address line from the listing."),
270
+ weekly_hours: {
271
+ type: "object",
272
+ description:
273
+ "Canonical weekly schedule extracted from the Maps hours block. Keys are FULL DAY NAMES (sunday/monday/tuesday/wednesday/thursday/friday/saturday). Each value is { enabled: boolean, start: 'HH:MM', end: 'HH:MM' } in 24-hour format. Closed days use enabled:false. 'Open 24 hours' → enabled:true, start:'00:00', end:'23:59'. Wrong shape silently falls back to Mon-Fri 9-5 defaults — get the keys right.",
274
+ additionalProperties: false,
275
+ properties: {
276
+ sunday: {
277
+ type: "object",
278
+ additionalProperties: false,
279
+ properties: {
280
+ enabled: { type: "boolean" },
281
+ start: { type: "string", description: "HH:MM 24-hour" },
282
+ end: { type: "string", description: "HH:MM 24-hour" },
283
+ },
284
+ required: ["enabled", "start", "end"],
285
+ },
286
+ monday: {
287
+ type: "object",
288
+ additionalProperties: false,
289
+ properties: {
290
+ enabled: { type: "boolean" },
291
+ start: { type: "string" },
292
+ end: { type: "string" },
293
+ },
294
+ required: ["enabled", "start", "end"],
295
+ },
296
+ tuesday: {
297
+ type: "object",
298
+ additionalProperties: false,
299
+ properties: {
300
+ enabled: { type: "boolean" },
301
+ start: { type: "string" },
302
+ end: { type: "string" },
303
+ },
304
+ required: ["enabled", "start", "end"],
305
+ },
306
+ wednesday: {
307
+ type: "object",
308
+ additionalProperties: false,
309
+ properties: {
310
+ enabled: { type: "boolean" },
311
+ start: { type: "string" },
312
+ end: { type: "string" },
313
+ },
314
+ required: ["enabled", "start", "end"],
315
+ },
316
+ thursday: {
317
+ type: "object",
318
+ additionalProperties: false,
319
+ properties: {
320
+ enabled: { type: "boolean" },
321
+ start: { type: "string" },
322
+ end: { type: "string" },
323
+ },
324
+ required: ["enabled", "start", "end"],
325
+ },
326
+ friday: {
327
+ type: "object",
328
+ additionalProperties: false,
329
+ properties: {
330
+ enabled: { type: "boolean" },
331
+ start: { type: "string" },
332
+ end: { type: "string" },
333
+ },
334
+ required: ["enabled", "start", "end"],
335
+ },
336
+ saturday: {
337
+ type: "object",
338
+ additionalProperties: false,
339
+ properties: {
340
+ enabled: { type: "boolean" },
341
+ start: { type: "string" },
342
+ end: { type: "string" },
343
+ },
344
+ required: ["enabled", "start", "end"],
345
+ },
346
+ },
347
+ },
348
+ google_place_url: str(
349
+ "Optional — the Google Maps share URL for the listing. Stored on soul.business.maps_url for audit."
350
+ ),
351
+ // v1.38.3 — testimonials extracted from review excerpts in the
352
+ // Maps paste. Pass these through VERBATIM — never rewrite or
353
+ // synthesize. The backend renders them as-is. When the paste
354
+ // has no review excerpts, OMIT this field entirely (do not
355
+ // pass an empty array, do not invent reviews).
356
+ testimonials: {
357
+ type: "array",
358
+ description:
359
+ "OPTIONAL real review excerpts extracted from the Maps paste, VERBATIM (do not rewrite). Each entry: { quote, name?, role?, rating? }. quote = the actual review text the customer wrote (≤800 chars). name = reviewer name as shown on Google. role = customer descriptor like 'Homeowner', 'Property manager' (omit if unknown). rating = 1-5 if visible. Pass 3-6 entries when paste contains genuine reviews; OMIT this entire field when paste has no review text. NEVER fabricate reviews.",
360
+ items: {
361
+ type: "object",
362
+ additionalProperties: false,
363
+ properties: {
364
+ quote: { type: "string", description: "Verbatim review text from the paste." },
365
+ name: { type: "string", description: "Reviewer name from Google. Optional." },
366
+ role: { type: "string", description: "Customer descriptor (e.g. 'Homeowner'). Optional." },
367
+ company: { type: "string", description: "Optional — only relevant for B2B reviews." },
368
+ rating: { type: "number", description: "1-5 star rating if visible." },
369
+ },
370
+ required: ["quote"],
371
+ },
372
+ },
373
+ },
374
+ ["business_name", "city", "state", "phone", "services", "business_description"]
375
+ ),
376
+ handler: async (args) => {
377
+ const firstEver = isFirstEverCall();
378
+ const result = await api("POST", "/workspaces/create-full", {
379
+ body: {
380
+ business_name: args.business_name,
381
+ city: args.city,
382
+ state: args.state,
383
+ phone: args.phone,
384
+ services: args.services,
385
+ business_description: args.business_description,
386
+ review_count: args.review_count ?? null,
387
+ review_rating: args.review_rating ?? null,
388
+ certifications: args.certifications ?? null,
389
+ trust_signals: args.trust_signals ?? null,
390
+ emergency_service: args.emergency_service ?? null,
391
+ same_day: args.same_day ?? null,
392
+ service_area: args.service_area ?? null,
393
+ email: args.email ?? null,
394
+ address: args.address ?? null,
395
+ // v1.37.0 — Google Maps paste fields. Backend silently
396
+ // drops malformed weekly_hours so a paste quirk never
397
+ // blocks workspace creation; defaults take over.
398
+ weekly_hours: args.weekly_hours ?? null,
399
+ google_place_url: args.google_place_url ?? null,
400
+ // v1.38.3 — operator-supplied testimonials. Pass through
401
+ // verbatim; backend drops malformed entries silently.
402
+ testimonials: args.testimonials ?? null,
403
+ },
404
+ allow_anonymous: true,
405
+ });
406
+
407
+ if (result?.status !== "ready" || !result?.workspace_id) {
408
+ return result;
409
+ }
410
+
411
+ if (result._bearer_token) {
412
+ rememberWorkspace({
413
+ workspace_id: result.workspace_id,
414
+ bearer_token: result._bearer_token,
415
+ });
416
+ }
417
+
418
+ const guardrail = [
419
+ "⚠️ WORKSPACE CREATED — DO NOT END YET ⚠️",
420
+ "",
421
+ `The workspace "${args.business_name}" exists on the backend (scaffolded from a Google Maps paste) but the operator-facing flow is NOT complete. You MUST do exactly two things before responding to the user:`,
422
+ "",
423
+ " 1. Ask the user verbatim:",
424
+ " " + JSON.stringify(result.operator_prompt ?? "What email should I use for your account?"),
425
+ "",
426
+ " 2. Once they reply with an email, call:",
427
+ ` finalize_workspace({ workspace_id: "${result.workspace_id}", email: <their_email>, name: <optional_name> })`,
428
+ "",
429
+ "DO NOT show the operator any URLs from this response yet. The admin dashboard URL does not exist — finalize_workspace creates it. The operator-facing summary (with all URLs + admin link + what's configured) is returned by finalize_workspace.",
430
+ ].join("\n");
431
+
432
+ const payload = {
433
+ ok: true,
434
+ DO_NOT_DISPLAY_TO_USER: guardrail,
435
+ workspace: {
436
+ id: result.workspace_id,
437
+ slug: result.slug,
438
+ },
439
+ configured: result.configured,
440
+ // v1.37.0 — confirm to Claude Code that the paste-derived hours
441
+ // landed on the booking template. If weekly_hours was passed
442
+ // and the backend accepted it, the booking page will render
443
+ // the operator's actual business hours on first GET — no
444
+ // separate configure_booking call needed.
445
+ applied_from_google_paste: {
446
+ weekly_hours: args.weekly_hours ? Object.keys(args.weekly_hours).length : 0,
447
+ google_place_url: args.google_place_url ?? null,
448
+ },
449
+ next_step: {
450
+ required: true,
451
+ do_not_show_urls_until_email_collected: true,
452
+ ask_user_verbatim: result.operator_prompt,
453
+ tool_to_call: "finalize_workspace",
454
+ tool_args_template: {
455
+ workspace_id: result.workspace_id,
456
+ email: "<operator_email>",
457
+ name: "<optional>",
458
+ },
459
+ why_required:
460
+ "finalize_workspace creates the admin dashboard URL (it does not exist yet), sends the welcome email, captures the operator as a lead, and returns the formatted operator-facing summary.",
461
+ },
462
+ _pending_after_email: {
463
+ website_url: result.public_urls?.home ?? null,
464
+ booking_url: result.public_urls?.book ?? null,
465
+ intake_url: result.public_urls?.intake ?? null,
466
+ },
467
+ };
468
+ return firstEver ? withFirstCallBanner(payload) : payload;
469
+ },
470
+ },
193
471
  {
194
472
  name: "list_workspaces",
195
473
  description: "List all workspaces known to this device (plus any Pro workspaces if SELDONFRAME_API_KEY is set).",
@@ -601,6 +879,18 @@ export const TOOLS = [
601
879
  ? ` • Welcome email sent, onboarding started`
602
880
  : ` • Welcome email NOT yet sent (rerun finalize_workspace to retry)`
603
881
  );
882
+ // v1.34.0 — Brief, optional next-step menu surfaced AFTER the
883
+ // operator's site is live. We don't lecture; we just list what's
884
+ // available. Claude Code reads this and decides whether to mention
885
+ // any of it based on the conversation vibe (e.g. user says
886
+ // "perfect, ship it" → skip; user says "can it look more
887
+ // impressive?" → call apply_motion_preset).
888
+ lines.push("");
889
+ lines.push("Optional upgrades (when you're ready):");
890
+ lines.push(` • Tune motion: apply_motion_preset({ preset: "subtle" | "balanced" | "editorial" | "minimal" })`);
891
+ lines.push(` • Apply your brand kit: apply_design_md({ design_md_content }) if you have a DESIGN.md`);
892
+ lines.push(` • Import a Claude Design handoff: import_claude_design_handoff({ bundle })`);
893
+ lines.push(` • Add real content: describe your services, pricing, FAQs in plain English`);
604
894
  const summary = lines.join("\n");
605
895
 
606
896
  return {
@@ -622,6 +912,30 @@ export const TOOLS = [
622
912
  lead_error: leadError,
623
913
  personality: personalityLabel,
624
914
  pipeline_stages: pipelineStages.map((s) => s?.name).filter(Boolean),
915
+ // v1.34.0 — Structured options Claude Code can reason about
916
+ // without parsing the human-facing summary string.
917
+ next_steps_available: [
918
+ {
919
+ action: "apply_motion_preset",
920
+ when: "operator says 'make it feel more premium', 'tone down animation', etc.",
921
+ example: 'apply_motion_preset({ preset: "editorial" })',
922
+ },
923
+ {
924
+ action: "apply_design_md",
925
+ when: "operator has a DESIGN.md file with their brand tokens",
926
+ example: "apply_design_md({ design_md_content: <file content> })",
927
+ },
928
+ {
929
+ action: "import_claude_design_handoff",
930
+ when: "operator just exported components from Claude Design",
931
+ example: "import_claude_design_handoff({ bundle: <bundle JSON> })",
932
+ },
933
+ {
934
+ action: "update_landing_content / configure_booking / customize_intake_form",
935
+ when: "operator wants to update specific page content, prices, services",
936
+ example: "(see get_workspace_state for the full surface map)",
937
+ },
938
+ ],
625
939
  };
626
940
  },
627
941
  },
@@ -800,6 +1114,169 @@ export const TOOLS = [
800
1114
  });
801
1115
  },
802
1116
  },
1117
+ // v1.33.1 — Bring-your-own-design-system path #1.
1118
+ //
1119
+ // Accepts the FULL CONTENT of a DESIGN.md file (the Google Labs
1120
+ // format: YAML front matter for tokens + Markdown for rationale).
1121
+ // Server parses it, maps tokens to OrgTheme, applies. Tokens that
1122
+ // don't have a 1:1 OrgTheme equivalent (spacing scales, custom
1123
+ // shadows, etc.) come back in `unmapped` so Claude Code can decide
1124
+ // whether to surface them via update_landing_page or just inform
1125
+ // the operator.
1126
+ //
1127
+ // USE-WHEN the operator has a DESIGN.md committed to their workspace
1128
+ // or available locally and says "apply this design system" or
1129
+ // "use this brand kit" or "match my company's design tokens".
1130
+ //
1131
+ // Example flow inside Claude Code:
1132
+ // const md = await readFile("./DESIGN.md", "utf8");
1133
+ // apply_design_md({ design_md_content: md });
1134
+ //
1135
+ // The MCP-client process reads the file (operator's machine has the
1136
+ // tokens; we don't need a path-on-server). Server only sees the
1137
+ // content string. 256KB cap server-side.
1138
+ {
1139
+ name: "apply_design_md",
1140
+ description:
1141
+ "Apply a DESIGN.md file (the Google Labs format: YAML front matter for tokens + Markdown for rationale) to the workspace theme. Maps tokens.colors.primary, tokens.colors.accent, tokens.mode, and tokens.typography.body to OrgTheme fields. Unmapped tokens (spacing, custom shadows, etc.) are returned so Claude Code can decide whether to apply them via update_landing_page or surface to the operator. " +
1142
+ "USE-WHEN the operator says: 'apply my DESIGN.md', 'use this brand kit', 'match my company's design tokens', 'import my design system', or 'theme my workspace from this file'. " +
1143
+ "Example: apply_design_md({ design_md_content: '<full file content as string>' })",
1144
+ inputSchema: obj(
1145
+ {
1146
+ design_md_content: str(
1147
+ "Full content of the DESIGN.md file as a string. The MCP client reads the file in the operator's process (e.g. via fs.readFile in Claude Code) and passes the content here. Server caps at 256KB."
1148
+ ),
1149
+ workspace_id: str("Optional workspace override."),
1150
+ },
1151
+ ["design_md_content"]
1152
+ ),
1153
+ handler: async (a) => {
1154
+ const ws = wsOrDefault(a.workspace_id);
1155
+ return api("POST", "/theme/apply-design-md", {
1156
+ body: {
1157
+ design_md_content: a.design_md_content,
1158
+ workspace_id: ws,
1159
+ },
1160
+ workspace_id: ws,
1161
+ });
1162
+ },
1163
+ },
1164
+ // v1.34.0 — Natural-language motion intensity control.
1165
+ //
1166
+ // Sets the workspace's motion preset. Defaults: every new workspace
1167
+ // ships at "balanced" (sections fade up, grids stagger, CTAs lift on
1168
+ // hover). Operators with strong opinions tune up or down via a single
1169
+ // natural-language prompt: "make my pages feel more premium" → editorial;
1170
+ // "respect prefers-reduced-motion across my site" → minimal.
1171
+ //
1172
+ // PRESETS:
1173
+ // "minimal": no motion. Accessibility-first.
1174
+ // "subtle": fade-up reveals only. Quiet, professional.
1175
+ // "balanced": reveals + stagger + hover-lift. The default.
1176
+ // "editorial": full effects — counters, magnetic CTAs, text-reveal.
1177
+ //
1178
+ // The preset is stored on OrgTheme.motionPreset. Renderers progressively
1179
+ // gate primitives on it; today the "balanced" set is applied universally
1180
+ // and the preset is read by Claude Code as a hint when generating new
1181
+ // content (e.g. don't add Counter to a workspace that picked "subtle").
1182
+ //
1183
+ // USE-WHEN the operator says: "make my site feel more premium",
1184
+ // "tone down the animation", "make it less flashy", "I want my pages
1185
+ // to feel editorial", "respect reduced motion", "no animation please",
1186
+ // or directly references one of the preset names.
1187
+ {
1188
+ name: "apply_motion_preset",
1189
+ description:
1190
+ "Set the workspace's motion intensity preset. Stored on OrgTheme.motionPreset and read by the renderer + Claude Code as a hint for content generation. Presets: 'minimal' (no motion, accessibility-first), 'subtle' (fade-up reveals only), 'balanced' (reveals + stagger + hover-lift — the default), 'editorial' (full effects: counters, magnetic CTAs, text-reveal). " +
1191
+ "USE-WHEN the operator says: 'make my pages feel more premium', 'tone down the animation', 'I want it editorial', 'respect reduced motion', 'no animation please', or directly references a preset name. " +
1192
+ "Example: apply_motion_preset({ preset: 'editorial' })",
1193
+ inputSchema: obj(
1194
+ {
1195
+ preset: {
1196
+ type: "string",
1197
+ enum: ["minimal", "subtle", "balanced", "editorial"],
1198
+ description:
1199
+ "The motion intensity preset to apply. 'minimal'=no motion (accessibility-first). 'subtle'=fade-up reveals only. 'balanced'=reveals + stagger + hover-lift (default). 'editorial'=full effects (counters, magnetic CTAs, text-reveal).",
1200
+ },
1201
+ workspace_id: str("Optional workspace override."),
1202
+ },
1203
+ ["preset"]
1204
+ ),
1205
+ handler: async (a) => {
1206
+ const ws = wsOrDefault(a.workspace_id);
1207
+ return api("POST", "/theme/motion-preset", {
1208
+ body: {
1209
+ preset: a.preset,
1210
+ workspace_id: ws,
1211
+ },
1212
+ workspace_id: ws,
1213
+ });
1214
+ },
1215
+ },
1216
+ // v1.33.1 — Bring-your-own-design-system path #2.
1217
+ //
1218
+ // Accepts a Claude Design "handoff bundle" — the artifact Anthropic's
1219
+ // Claude Design produces when designs are ready for code (HTML or
1220
+ // React components + design tokens + asset URLs). Server:
1221
+ // 1. Applies the bundle's tokens (if any) to OrgTheme — same
1222
+ // mapping as apply_design_md.
1223
+ // 2. Validates each component (name, surface, source size, props
1224
+ // schema) and returns a structured manifest with truncated
1225
+ // source previews + per-component "next_step" instructions.
1226
+ // 3. Does NOT auto-execute generated React on live customer pages.
1227
+ // Claude Code reviews each component's source and chooses
1228
+ // whether to wire it via update_landing_page / add_custom_block
1229
+ // based on its eval-readiness. Customer-facing surfaces still
1230
+ // run through the eval gate before publish — Claude Design
1231
+ // output isn't trusted to bypass that.
1232
+ //
1233
+ // USE-WHEN the operator says "import this Claude Design handoff",
1234
+ // "wire up these components", "I just exported a design from Claude
1235
+ // Design", or "apply this design bundle to my workspace".
1236
+ //
1237
+ // Bundle schema (defensive read of the most likely format —
1238
+ // Anthropic hasn't published a formal spec yet):
1239
+ // {
1240
+ // meta?: { project_name?, generated_at?, target?: "react"|"html" },
1241
+ // tokens?: { colors?, typography?, mode? },
1242
+ // components: [
1243
+ // { name, surface?, react_source? OR html_source?,
1244
+ // props_schema?, deps? }
1245
+ // ],
1246
+ // assets?: [{ name, url, type }]
1247
+ // }
1248
+ //
1249
+ // Limits: 1MB total bundle, 64KB per component source, 40 components
1250
+ // per import. Larger bundles should be split.
1251
+ {
1252
+ name: "import_claude_design_handoff",
1253
+ description:
1254
+ "Validate a Claude Design handoff bundle (the artifact Claude Design produces when designs are ready for code), apply its embedded design tokens to the workspace theme, and return a structured manifest of the components with per-component next-step instructions for wiring them into pages. Does NOT auto-execute generated React on live pages — components route through human/eval review (the same gate that protects published agents) before customer-facing surfaces ship. " +
1255
+ "USE-WHEN the operator says: 'import this Claude Design handoff', 'wire up these components', 'I just exported a design from Claude Design', or 'apply this design bundle to my workspace'. " +
1256
+ "Example: import_claude_design_handoff({ bundle: { meta: { project_name: 'Acme HVAC' }, tokens: { colors: { primary: '#0e7490' } }, components: [{ name: 'TrustStrip', surface: 'landing', react_source: '<TSX content>' }] } })",
1257
+ inputSchema: obj(
1258
+ {
1259
+ bundle: {
1260
+ type: "object",
1261
+ description:
1262
+ "The handoff bundle as a JSON object. Required fields: bundle.components (array of {name, react_source OR html_source}). Optional: bundle.meta, bundle.tokens (DESIGN.md-shape), bundle.assets. Server caps at 1MB total, 64KB per component, 40 components per import.",
1263
+ additionalProperties: true,
1264
+ },
1265
+ workspace_id: str("Optional workspace override."),
1266
+ },
1267
+ ["bundle"]
1268
+ ),
1269
+ handler: async (a) => {
1270
+ const ws = wsOrDefault(a.workspace_id);
1271
+ return api("POST", "/handoff/import", {
1272
+ body: {
1273
+ bundle: a.bundle,
1274
+ workspace_id: ws,
1275
+ },
1276
+ workspace_id: ws,
1277
+ });
1278
+ },
1279
+ },
803
1280
  {
804
1281
  name: "list_automations",
805
1282
  description: "List automations configured in the active (or specified) workspace.",
package/src/welcome.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // stripped. `create_full_workspace` is the only workspace-creation
9
9
  // path mentioned anywhere in this briefing.
10
10
 
11
- export const VERSION = "1.30.1";
11
+ export const VERSION = "1.38.4";
12
12
 
13
13
  export const WELCOME_MARKDOWN = `# SeldonFrame — create a real Business OS in one conversation
14
14
 
@@ -433,4 +433,4 @@ admin dashboard. Pre-fills their email automatically.
433
433
  <https://seldonframe.com> · **Discord:** <https://discord.gg/sbVUu976NW>
434
434
  `;
435
435
 
436
- export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.30.1 is connected. STEP ZERO: for any workspace task call get_workspace_state({workspace_id}) FIRST — returns workspace identity + integrations status + agents with inline health stats + counts + tailored next_steps in ONE round-trip. Replaces 4-6 progressive discovery calls. ANTI-PATTERNS: don't ls/cat/read .env (SF is hosted, not local files); don't check node/npm versions (irrelevant); don't ask 'is Anthropic key configured?' (state response tells you); don't create a duplicate agent (state response shows existing ones — use update_website_chatbot instead of build_website_chatbot when one exists). Token-budget concept removed in v1.27.9 — ignore stale references. CAPABILITY MAP — pick the right primitive BEFORE exploring tools: (a) "build me a website" → WORKSPACE → create_workspace_v2 + block tools. (b) "add a chatbot to my website / landing page" → AGENT (web chat) → build_website_chatbot (v1.28+ skill bundle: configure_llm + create_agent + publish-test in 1 call; auto-detects ANTHROPIC_API_KEY from env). Drop to primitives (configure_llm_provider + create_agent + publish_agent) only for custom flows. CRITICAL ANTI-PATTERN: chat widgets are NOT blocks. Don't search list_blocks for chat — chat agents are a separate primitive (v1.26+). (c) "auto-reply to inbound SMS/email" → CONVERSATION → send_conversation_turn (one-shot Soul-aware reply, not a website widget). (d) "add hero/services/faq/cta section" → BLOCK → get_block_skill + persist_block. (e) "send campaign email/sms" → MESSAGING. (f) CRM ops → list_contacts/create_deal/etc. CHATBOT CANONICAL FLOW (v1.28+ — 1 call instead of 5): build_website_chatbot({workspace_id, name, faq, pricing_facts, greeting}) → wraps configure_llm + create_agent + publish-test in one call, auto-detects ANTHROPIC_API_KEY from env. Then: operator sandbox-tests at /agents/[id]/test → publish_agent({status:"live"}) auto-runs 8-scenario eval gate (≥87.5% pass required). Observability tools after publish: list_agents, tail_agent_conversations, get_agent_conversation, get_agent_metrics, run_agent_evals, replay_conversation. Dashboard surfaces /agents, /agents/[id]/test, /agents/[id]/settings, /agents/[id]/evals, /agents/[id]/conversations let operators iterate without leaving the browser. WORKSPACE FLOW (legacy reference): create_workspace_v2 → IN PARALLEL for all 7 recommended_blocks (hero, services, about, faq, cta, booking, intake): get_block_skill + persist_block → complete_workspace_v2 → finalize_workspace({workspace_id, email}). Run blocks in PARALLEL (Promise.all) — sequential takes 60+ seconds. v1.10+ CUSTOMIZE: regenerate_block, upload_workspace_image (image_url preferred over base64). v1.11+ STRUCTURAL: get_landing_structure, move_section, delete_section. v1.12+ COMPOSITES: add_composite_section / update_composite_section — manifest ANY block from 12 low-level primitives. Skipping finalize_workspace leaves the operator with no admin login. Every URL is real. NEVER create local files.`;
436
+ export const FIRST_CALL_BANNER = `🚀 SeldonFrame v1.38.4 is connected. STEP ZERO: for any workspace task call get_workspace_state({workspace_id}) FIRST — returns workspace identity + integrations status + agents with inline health stats + counts + tailored next_steps in ONE round-trip. Replaces 4-6 progressive discovery calls. ANTI-PATTERNS: don't ls/cat/read .env (SF is hosted, not local files); don't check node/npm versions (irrelevant); don't ask 'is Anthropic key configured?' (state response tells you); don't create a duplicate agent (state response shows existing ones — use update_website_chatbot instead of build_website_chatbot when one exists). Token-budget concept removed in v1.27.9 — ignore stale references. CAPABILITY MAP — pick the right primitive BEFORE exploring tools: (a) "build me a website" → WORKSPACE → create_workspace_v2 + block tools. (b) "add a chatbot to my website / landing page" → AGENT (web chat) → build_website_chatbot (v1.28+ skill bundle: configure_llm + create_agent + publish-test in 1 call; auto-detects ANTHROPIC_API_KEY from env). Drop to primitives (configure_llm_provider + create_agent + publish_agent) only for custom flows. CRITICAL ANTI-PATTERN: chat widgets are NOT blocks. Don't search list_blocks for chat — chat agents are a separate primitive (v1.26+). (c) "auto-reply to inbound SMS/email" → CONVERSATION → send_conversation_turn (one-shot Soul-aware reply, not a website widget). (d) "add hero/services/faq/cta section" → BLOCK → get_block_skill + persist_block. (e) "send campaign email/sms" → MESSAGING. (f) CRM ops → list_contacts/create_deal/etc. CHATBOT CANONICAL FLOW (v1.28+ — 1 call instead of 5): build_website_chatbot({workspace_id, name, faq, pricing_facts, greeting}) → wraps configure_llm + create_agent + publish-test in one call, auto-detects ANTHROPIC_API_KEY from env. Then: operator sandbox-tests at /agents/[id]/test → publish_agent({status:"live"}) auto-runs 8-scenario eval gate (≥87.5% pass required). Observability tools after publish: list_agents, tail_agent_conversations, get_agent_conversation, get_agent_metrics, run_agent_evals, replay_conversation. Dashboard surfaces /agents, /agents/[id]/test, /agents/[id]/settings, /agents/[id]/evals, /agents/[id]/conversations let operators iterate without leaving the browser. WORKSPACE FLOW (legacy reference): create_workspace_v2 → IN PARALLEL for all 7 recommended_blocks (hero, services, about, faq, cta, booking, intake): get_block_skill + persist_block → complete_workspace_v2 → finalize_workspace({workspace_id, email}). Run blocks in PARALLEL (Promise.all) — sequential takes 60+ seconds. v1.10+ CUSTOMIZE: regenerate_block, upload_workspace_image (image_url preferred over base64). v1.11+ STRUCTURAL: get_landing_structure, move_section, delete_section. v1.12+ COMPOSITES: add_composite_section / update_composite_section — manifest ANY block from 12 low-level primitives. Skipping finalize_workspace leaves the operator with no admin login. Every URL is real. NEVER create local files. v1.34+ UI POLISH (smart defaults + optional levers): every published page ships with motion baked in (RevealOnScroll on sections, Stagger on grid blocks, HoverLift on CTAs) — no operator action required. For operators who want to tune intensity: apply_motion_preset({preset: "minimal"|"subtle"|"balanced"|"editorial"}). For operators bringing their own design system: apply_design_md({design_md_content}) accepts the Google Labs DESIGN.md format; import_claude_design_handoff({bundle}) accepts Claude Design's handoff bundle. All three tools are OPTIONAL — surface them only when the operator's vibe asks for it ("make it feel premium", "I have a brand kit", "I just exported from Claude Design"). Never push these on a user who just wants a working site. v1.36+ PROMPT-FATIGUE GUIDANCE: workspace creation typically fires 8–18 MCP tool calls (workspace + blocks + agent + booking + intake + landing). Claude Code prompts on each by default and create_landing_page's Puck schema is verbose JSON the operator should NOT read. DO TWO THINGS to avoid spamming: (1) RECOMMEND THE OPERATOR pick option 2 ('Yes, and do not ask again for seldonframe – <tool>') the FIRST time create_landing_page / persist_block / build_website_chatbot fire — Claude Code caches per-tool autoapprove for the project, the rest of workspace creation runs without interrupting them. Mention this proactively before the flow starts. (2) BUNDLE TOOL CALLS in parallel via Promise.all — never call get_block_skill + persist_block sequentially for 7 blocks; fire them all at once. v1.36+ LANDING-PAGE COMPOSITION FOR LOCAL-SERVICE BUSINESSES: for trades/service businesses (plumbing, HVAC, locksmith, electrician, roofing, towing, dental, salon, mobile mechanic), default to a 10-section composition: navbar → hero (branded gradient empty-state when no photo) → emergencyStrip (sticky brand-colored banner with phone) → trust strip via the Grid block → servicesGrid (per-service cards with price + duration + Book CTA — replaces the SaaS-style pricing block) → benefits (3 differentiators) → process (3-step what-happens-after-booking) → serviceArea (chip cloud of cities/neighborhoods) → testimonials (5+ quotes — placeholder OK pre-launch) → faq → cta → footer. The Pricing block belongs to TIER-based businesses (SaaS, coaches, gyms) NOT per-service businesses — substitute servicesGrid. v1.36.0 added the servicesGrid, emergencyStrip, serviceArea block types — use them when persisting landing pages for trades verticals. The hero block ships a branded-gradient empty state when heroImage is missing; if the operator does not provide a photo, suggest a stock-photo prompt ('your tech truck on a job, sunset shot in Phoenix') so they can drop one in via /landing → Edit later. v1.37.0 GOOGLE MAPS PASTE → WORKSPACE: when the operator pastes a Google Maps business listing (Top Plumbing Experts, ABC Plumbing of San Antonio, etc.), use create_workspace_from_google_paste — NOT create_full_workspace. Same backend pipeline + same finalize_workspace follow-up; the paste-tool's docstring documents the extraction rules (name → bold title, phone → phone-icon row, address → location-pin line, services → categories chip row + 'Services' section deduped, rating + count → '4.7 ★ (950)' element, weekly_hours → 'Monday: 9 AM-5 PM, Tuesday: closed' parsed into canonical {monday:{enabled:true,start:'09:00',end:'17:00'},...} shape). The weekly_hours field flows DIRECTLY into the booking template's metadata.availability, so the operator's actual hours appear on the public /book page on first GET — no separate configure_booking call. 'Open 24 hours' → start:'00:00', end:'23:59'. 'Closed' day → enabled:false. Wrong key shape (e.g. 'mon' instead of 'monday') is silently dropped by the backend and falls back to Mon-Fri 9-5 defaults. NO Google Places API key required — the paste IS the source of truth. v1.36.4 paired fix: the booking page's normalizeAvailability now accepts both 3-letter and full-name day keys, so any legacy rows already in the DB also hydrate correctly. v1.38.3 ADDITIONAL QUALITY BLOCKS: (a) projectGallery — 6-photo masonry of stock photos auto-fetched per service via Unsplash from queries Claude generates inside enhance-blocks; closes the "feels populated" gap that's the single biggest visible difference between a generic SF workspace and a real-business landing page. (b) stickyMobileCTA — fixed bottom-of-screen Call/Book bar, MOBILE ONLY (md:hidden), industry-standard for trades sites with 2-3x mobile booking lift; auto-included whenever a phone is set. (c) testimonial synthesis from Maps paste — when the operator pastes a Google Maps listing that contains review excerpts, Claude Code extracts them VERBATIM into a 'testimonials' field on create_workspace_from_google_paste; backend renders them as-is. NEVER fabricated — if the paste has no review text, the testimonials block is OMITTED from the page entirely (better empty than fake). The testimonials field in the MCP tool input is OPTIONAL — Claude must omit it when the paste doesn't contain real review text. v1.38.0 ATOMIC HORMOZI-QUALITY OUTPUT: every workspace produced by create_full_workspace OR create_workspace_from_google_paste now ships with Hormozi value-equation hero copy + per-business Unsplash photos + scroll-triggered motion baked in — atomically, no follow-up tool calls, no operator action. Pre-1.38.0 the atomic create produced canned 'Welcome to X' copy from personality content templates; only workspaces where Claude Code did the BLOCK-AS-SKILL flow afterward (get_block_skill + persist_block per block) got the rich output. Tirionforge HVAC happened to look great because of that follow-up; atlantic-plumbing didn't get it. v1.38.0 closes the gap by adding Step 12.7 inside the orchestrator: ONE Claude Opus 4.7 call generates hero + servicesGrid + about + benefits + process + faq + cta from src/blocks/*/SKILL.md (the exact same fat skill files Claude Code reads via get_block_skill — single source of truth, no duplication). Output writes to landingPages.sections (LandingPageSection[]), contentHtml/Css get NULLED, route /l/[orgSlug]/[slug] falls through to <PageRenderer> which auto-wraps below-fold sections in <RevealOnScroll>. Hormozi copy + per-business Unsplash + motion all light up at once. EMAIL-FIRST GUARDRAIL UNCHANGED: create_full_workspace + create_workspace_from_google_paste both still RETURN BEFORE THE EMAIL DANCE — operator can't see URLs until they reply with email, finalize_workspace mints the magic admin link + sends the welcome email via Resend. BYOK pass-through: getAIClient checks organizations.integrations.anthropic.apiKey first, falls back to platform ANTHROPIC_API_KEY env. Cost ~$0.10 per workspace, irrelevant since the operator typically supplies their own key. SOFT-FAIL: any error in Step 12.7 leaves the workspace valid (canned-copy Path A intact); never blocks creation. EXPECTED IMPACT: every fresh workspace looks $10k-tier first-shot, no "create workspace then enhance blocks" two-step dance. ws1-webhook-pricing-fixes branch ships this; redeploy required.`;