A working kanban for the site. Every card has an explicit status, owner context, and next action; move work by changing the card status in the source of truth.
46 open45 done6 waiting on you
In flight, or blocked and urgent
Rewrite guides and posts: longer, concrete, one worked example each
Blocked on Paul: SANITY_API_KEY is rejected by Sanity ("Session not found") so nothing can be written. Needs an Editor token from sanity.io/manage > API > Tokens, pasted into Vars. Diagnosis: every guide is ~300 words (1.8-2.3k chars); the body restates the answer field almost word for word; no worked example, no real numbers, no named situation. Posts are personal essays and need Paul's own material, not generated text.
Paste STRIPE_WEBHOOK_SECRET into Vercel production
The new endpoint's signing secret (in the Stripe dashboard, never in this file). Vercel holds the dead endpoint's secret, so every delivery fails signature verification. Prove it with scripts/verify_webhook.py.
Delete the old Stripe endpoint we_1TsOtp
Points at the apex domain, which 307-redirects. Stripe does not follow redirects, so it could never deliver.
Rotate the live Stripe keys and the Google OAuth secret
Secret key, publishable key and webhook signing secret have all been pasted into chat transcripts.
Add a card to the Vercel team so AI Gateway serves the advisor
Needs Paul. Gateway returns customer_verification_required until a card is on file (Vercel dashboard > AI > add card). Advisor code is live and waiting on this.
Agreed, not started
Two registers: editorial for public pages, application for the library
Cards, rails, HUDs and tables are library patterns. They are wrong on the home page and right on /browse. Write it into DESIGN-SYSTEM.md and show both at /design-system. The largest type on the site is 32px and everything sits within one step of everything else. A publication needs 40-56px doing work against 16px body.
Podcast schema and first episode
No podcastEpisode type exists. Needs title, number, date, description, audio or embed, Apple and Spotify links. Sanity write — Paul or a Studio session.
Social links in siteSettings
siteSettings holds four membership fields and nothing else. Needs YouTube, X, TikTok, Threads and the podcast feeds.
Unpublish "This is a course"
Live at /courses, $1, body "hi", published: true. Two clicks in the Studio.
Podcast index and episode pages
Depends on the schema.
Match YouTube videos to posts automatically
Today the URL is pasted by hand. The YouTube Data API v3 can list a channel's uploads (search.list or playlistItems on the uploads playlist); match a video to a post by title similarity and date proximity, propose the pairing, never write it silently. Needs a YOUTUBE_API_KEY. Free quota is 10k units/day, a list is 1 unit.
Backfill videoUrl on existing posts
Depends on yt-auto. Run the matcher over every published post, print the proposed pairs with confidence, and let Paul approve in one pass rather than pasting one URL at a time.
Art for every post, not just four
web/scripts/art.py <slug> "<scene>" makes one. Four posts have one. Every other published post needs a scene written and an image made. 8 credits each. See docs/ART.md for how to write the scene.
An accessibility gate, not an accessibility opinion
check_contrast.js covers colour only. Add axe-core to the live run over the same page list: landmark order, form labels, heading sequence, focus order, aria on the custom listbox and segmented controls. Every custom control here replaced a native one and inherited none of its behaviour for free.
Fold the sixteen remaining double-declared classes into one each
globals.css has two stacked generations. Seven first declarations were entirely dead and are deleted; sixteen remain where some properties still reach the page, so each needs merging by hand rather than deleting. scripts/check_css_dupes.py holds the list as a ratchet.
Adopt the ruthless visual audit rubric
Every route is judged 0–5 on hierarchy, layout, spacing, typography, contrast, interaction clarity, responsive behavior, accessibility, and content integrity. A page does not pass because it renders; it passes when the screenshot is calm, legible, and intentional at desktop and 390px.
Replace the shell with one coherent product frame
The current header/nav, topbar, theme control, focus treatment, and page margins still feel like pieces from different sites. Establish one Vercel-like monochrome shell with a clear active state, predictable mobile behavior, and no competing navigation systems. CRITIQUE: this is not one navigation system; it is a rail, a breadcrumb, a topbar, and a mobile strip all negotiating for attention. The result looks like a theme assembled from incompatible kits. Active state is too quiet, the search affordance is a browser-looking control, and the mobile row has no clear overflow strategy. Score: coherence 1/5, wayfinding 2/5, focus 2/5, responsive behavior 2/5. Replace the shell wholesale, not by nudging its borders. Paul: small, understated type — not large headlines.
Make Library, Browse, Search, and reference pages feel like one system
Audit /browse, /library, /concepts, /figures, /traditions, /math, /guides, and /frameworks together. Remove accidental differences in rails, filters, row density, empty states, and result hierarchy; the current family reads as related templates, not a product. CRITIQUE: /browse, /library, /concepts, /figures, /traditions, /math, /guides, and /frameworks look like pages that share a codebase but not a product decision. Rows, filters, headings, and empty states change tone without earning the difference. The user cannot tell whether they are browsing a corpus, searching a database, or opening an article. Score: system consistency 1/5, scanability 3/5, information scent 2/5. Define one reference grammar and apply it to every member of the family.
Writing and the article page: editorial, not assembled
Audit /blog, domain indexes, article pages, reading lists, and the reader. Fix weak headline-to-dek contrast, inconsistent metadata, orphaned actions, contents behavior, and the lack of a confident end-of-article next step. CRITIQUE: /blog and article pages borrow editorial signals—large type, dates, cover art—without the editorial pacing that makes them useful. Metadata is ornamental, article actions arrive late, and related reading is not a confident next move. The contents rail feels like an implementation detail. Score: reading rhythm 2/5, content hierarchy 3/5, next-step clarity 1/5, accessibility 2/5. Design the reading experience around attention, not around component placement. Headline, standfirst, date on open background. No cards. It already has a contents rail and a standfirst. Needs the editorial type scale and a proper end-of-article block: subscribe, next piece, related.
Unify Store, product pages, checkout, join, and account states
Audit /store, /store/[slug], /store/[slug]/read, /courses, /join, /account, /checkout/return, and auth screens. Buttons, prices, access states, errors, and forms must share one conversion grammar instead of changing tone route by route. CRITIQUE: /store, products, courses, join, account, and checkout do not share a conversion grammar. Price, access, membership, errors, and primary actions change visual language route by route. That is not personality; it is trust leakage. Score: conversion clarity 2/5, state communication 1/5, form quality 2/5, mobile safety 2/5. Establish one purchase state model before touching cosmetics.
Turn Tools into a clear application surface
Audit /tools and every calculator/scorecard. The tools should explain the job, state, inputs, result, and next action with application-grade feedback; no ambiguous controls, ornamental panels, or result screens that look like dead ends. CRITIQUE: the calculators make the user infer the job, the input contract, and what to do with the result. Controls look like decorative panels, feedback is too quiet, and the result does not become a useful next action. Score: onboarding 1/5, control clarity 2/5, feedback 2/5, usefulness after result 1/5. Rebuild each tool as a transparent application flow: purpose, inputs, calculation state, result, recommendation.
Fix content integrity before polishing pixels
The screenshot audit must flag placeholder copy, empty sections, missing images, duplicate labels, broken links, weak metadata, and pages that technically render but have no credible reason to exist. Delete or finish the dead weight. Includes removing AI-sounding filler and anything untrue about Paul, site-wide, in Paul’s voice.
Make 390px a first-class layout, not a shrink test
Capture every route at 390px and reject horizontal overflow, clipped controls, overlong nav, tiny type, stacked whitespace, and actions pushed below the fold. Mobile needs deliberate composition, not desktop CSS with fewer columns.
Give figures dates and places
Sanity schema: born and died (year, with circa and BCE), birthplace and places worked (name plus lat/long), tradition, era. Backfill from Wikidata by QID, then Paul reviews. Works get publication year; concepts get first attested date and figure. This is what the timeline and map read from.
Hold tens of thousands of resources: audio, video, text
One resource model with a media type (essay, episode, video, lecture, book, primary text, tool). Faceted search on type, figure, concept, era, length and access level. Audio and video get a persistent mini-player that survives navigation, with chapters and transcripts that are searchable and highlightable.
Tools as a product line, gated by plan
Each tool declares free, member or paid-add-on access. A tool page shows what the free version does and what membership unlocks. Usage is metered per account in Supabase so AI tools have a monthly allowance. Paul can ask for a new tool and it drops into the same frame.
Search and filters that work at tens of thousands of items
Faceted filters (type, domain, era, place, format, access), instant results, keyboard-first, URL-shareable state. The ⌘K search covers every collection and media type.
One icon language across the site
Every collection, content type and state has one icon, used the same way in nav, filters, rows and badges — the site reads as an intuitive state machine.
Member goals: time-bound goals per domain of life with progress check-ins
Supabase tables goal + goal_checkin (RLS by user). Domains: relationships, money, business, career, mind, meaning. Private to the member.
Real, not scheduled
The editorial worklist: 85 pages
Entirely academic. Deprioritised repeatedly.
Wire check_weight.js into CI
The budget exists and currently fails on all eight pages it checks. Wire it once the JS number comes down.
Deep links to a passage, and "cite this"
Headings are addressable now; an arbitrary span is the same anchor problem as a highlight.
A lesson schema for real courses
Only a scaffold course exists.
Keep the art scene on the post in Sanity
The scene that produced a post's image lives only in docs/ART.md. It belongs on the document, so the image can be regenerated or restyled later without archaeology. Add artScene (text) to post.
The art in light mode
These are dark paintings on a light page. They look deliberate in dark mode and like a hole in light mode. Decide: a border, a slightly inset surface behind them, or accept it. Look before choosing.
Create a component inventory and delete visual impostors
Inventory buttons, inputs, badges, cards, rows, tables, rails, filters, dialogs, forms, and empty states. Consolidate duplicates, name variants by intent, and ban one-off styles that make the site look like a scrapbook of prior redesigns.
Guided timelines: the history of a field
A curated path through the timeline, e.g. the history of metaphysics: each figure in order, what they moved, which concept changed and how. Built from the same data, with Paul writing the connective sentence at each step.
Counsel: ask the philosophers about your situation (paid)
The paid centre of membership. A private workspace where a member describes a situation and gets answers grounded in Paul’s library, never the open web. Every answer cites the entries, passages and highlights it drew on, and links to them. Built on the AI SDK through the Vercel AI Gateway, with retrieval over the library (embeddings per section) so answers stay inside what Paul has written and curated.
Counsel: answer in a chosen voice
“What would Aristotle say?” The member picks a figure; the answer is written from that figure’s actual positions as the library states them, with the relevant concepts named (e.g. phronesis, the mean) and a short note on how to apply it this week. Clear labelling that this is an interpretation, with the source passages one click away. Compare mode: two figures on the same question.
Counsel: what should I be reading?
From a member’s situation, journal and highlights, rank the figures, concepts and works in the library most relevant to them, with one sentence on why for each, and build a reading path. Refreshes as they write.
Critique studio: your work through a named lens
Paste a URL, upload a draft or an image. Get a design critique in the manner of Dieter Rams or Josef Müller-Brockmann, a writing critique from Orwell’s rules or Strunk, an argument critique by taking the load-bearing premise apart. Returns specific, located comments, not a score, plus an optional revision. Website critiques screenshot the page and read the copy. Metered: a set number per month in membership, packs above that.
Journal: a private place to think, and a practice to keep
Members write dated entries, tag them with situations and concepts, and link them to passages and highlights. Prompts drawn from the library (a Stoic evening review, a Socratic question). Counsel can read the journal only when the member allows it per entry. Encrypted at rest, exportable, deletable; Paul cannot read it.
Workspace: manage your own reading, notes and projects
Saved items, highlights, journal and Counsel threads in one place with the same table, timeline and board views as the library. Collections a member can share by link.
Counsel guardrails
Not therapy, not legal or medical advice: stated plainly, and crisis language routes to real resources. Answers cite or say they cannot. Per-member rate limits, an eval set of 50 real questions Paul signs off on before launch, and a feedback button on every answer.
Embed library entries for advisor retrieval
pgvector in Supabase, re-embedded on Sanity publish webhook. Lets the advisor cite the exact passage.
Suggested thinkers and methods from your goals
Rank figures/concepts by fit to active goals; show on the account page and in the advisor empty state.
Shipped and verified
Listing pages: calmer filter bar and readable rows
2026-09-27. Shared Collection, so Guides, Writing, Concepts and the rest all change. Sort no longer renders as a solid black button (filters only mark as changed when they differ from the default, with an outline). Search box outlined like its neighbours. The stray count chip only appears when filtering ("4 of 13"). Rows show the summary's first sentence at a 68ch measure instead of two sentences cut off by an ellipsis across the full screen.
Absorb leftover UI into one system: one pill, one cover, one title size
2026-09-27. Seven pill recipes (listing tag, post pill, rail chip, board/admin/member tags) now share one rule: 24px, hairline, fg-2, 12px. Store covers lose the colour gradient, dark scrim and watermark letter: flat bg-3 with a faint motif. Concept web loses its accent glow. Article titles drop to the entry/work size (26/23); only the home intro stays large.
Design system, part two: figure tag column, one subscribe form per page, themed Stripe embed
Shipped 2026-09-27. List tags sit in a fixed 18rem column with the date right-aligned. The footer signup hides on any page that already has one. Stripe checkout uses branding_settings (Inter, site accent, rounded, 'Paul Maxwell').
About: the true story, from LinkedIn
PhD and teaching, the move into revenue operations, Meta and Apple, founder of RevOps HQ. Harvard and Dartmouth certificates as credentials, not the headline. Replace the indented facts list with a clean two-column record.
Entry pages: FAQ as an accordion, a better rail
Questions become a bordered expand/collapse list. The rail gets group icons, the current section marked in Contents, and entry facts in a grid. On a phone the rail is a compact block above the content, not a long stack at the bottom.
Home page: a publication front page that makes the point fast
Masthead, the latest piece at editorial scale, recent writing, the podcast, social, subscribe, work with me, and the library as one line at the bottom. See PLAN.md. The homepage is visually improved but still asks the reader to infer what matters first. Give it one unmistakable thesis, one primary action, disciplined supporting content, and a finish that does not collapse into a generic personal-site footer. CRITIQUE: the page has a respectable thesis but still spends the first viewport proving it is a website instead of making one decision easy. The oversized line break is theatrical, the index rail is underpowered, and the first article begins below a dead ocean of whitespace. Score: hierarchy 3/5, layout 2/5, density 2/5, action clarity 1/5, mobile composition 2/5. Rebuild the opening as a product-grade reference surface: one promise, one featured object, one obvious path into the library. DONE 2026-09-26: subscribe in the masthead, lead + recent, tools and store as ruled rows, Work with Paul as one line (RevOps HQ since 2025, PE-backed), library as one line. No boxes. Podcast and social wait on their own cards.
Icon navigation with mega-menus and a Subscribe dropdown
One menu open at a time (a small state machine). Hover intent, click and keyboard all work. Library opens into types and views, Subscribe opens into newsletter, podcast, RSS and membership. On phones the scrolling strip is replaced by a full menu sheet.
A real subscribe block, not only a popup
Shipped: subscribe block at the end of every post and at the bottom of the home page.
A consulting page
Shipped: /consulting, linked from the home Work with Paul block.
Reader highlights, saved and shared
Members select any passage in writing, library entries or the Reading Room and it saves to their account. Painted with the CSS Highlight API so links keep working. Passages three or more readers highlighted show as a quiet underline, with your own in yellow. Panel bottom-right on desktop, a sheet on phones. Margin notes are the next step.
Design-system adoption to 100%
Was 14 of 28 page files importing nothing from components/ui. Five exemptions remain, each with a reason, and the list is a ratchet.
/blog uses the same card as everywhere else
Was a bare h2, an italic date and a paragraph at 1,400px under a lede wrapped at 52 characters.
A real motion scale: four curves, duration by distance
Card lifts and presses, picker opens from above, preview crossfades, theme transitions.
Page transitions with the rail held still
Only the main column transitions. Verified by instrumenting document.startViewTransition.
The rail rebuilt without lines, four groups, Math demoted
Was a hairline above the first group, a left border down each list and a second left border for state.
The phone rail is one swipeable line
Was 430px of navigation above the content on every page. Six stacked links took the whole first screen on a 390px phone before the page's own heading. Now a horizontal scrolling row. No hamburger: a menu you must open is a menu you must guess at, and it is six short words.
Products and access are filterable
One HUD in three places. Collection moved onto it in the same commit.
One type scale, eight roles, enforced
Root font size was declared twice so the whole scale rendered 27% large; 23 hardcoded sizes and a second --t-* scale underneath them.
The login page has visible input fields
Twenty borders were invalid and silently dropped: --border was a width and became a colour.
A custom 404 on both paths
Root and in-segment.
A tools index, and both scorecards on a segmented control
/tools was a 404; twenty filled white buttons per scorecard, invisible in light mode.
The store is a table, and readable on a phone
Price was off the right edge at 390px inside a scroller.
A working Stripe webhook endpoint
The old one pointed at the apex domain and could never deliver.
The library does not need the auth provider to be up
An unconfigured Supabase used to 500 every page, including 500 public reference pages.
Six gates, on every commit and in CI
Palette, type scale, CSS variables, design-system adoption, rendered pages, contrast, overflow. Each verified against the commit before its fix.
A video on a post, embedded
post.videoUrl already exists in the Studio (YouTube or Vimeo) and components/ui/video.tsx renders it by parsed ID via youtube-nocookie, lazily. Paste the URL on the post and it appears. /blog marks the row 'Video'.
Contents floats and follows the reader
Sticky beside the piece, scroll-margin on the headings so an anchor jump clears the top bar, and an IntersectionObserver marking where the reader is. Not :target, which only fires on a click.
Remove reading time
A guess presented as a fact, near-identical on every piece, and nobody decides to read something because a robot estimated four minutes.
Finished art is committed and compressed
public/art/ holds one JPEG per post and is in the repo; public/art-samples/ is gitignored scratch. art.py resizes to 1600px at quality 82 — 1.2MB PNG becomes about 80KB.
Share cards: every page needs an og:image
Shipped: /og ImageResponse card (Geist) is the site default; posts use their art, then cover, then a titled card.
Know whether anybody reads it
Shipped: Vercel Analytics + GA4 already mount in production from app/layout.tsx. No consent dialog.
Real alt text on the art
Shipped: ArtHead alt comes from lib/art-scenes (the scene sentence); thumbnails are decorative.
Inline links stay in the sentence
The link-preview wrapper shared a class with the floating tooltip, so every link in a library entry was pulled out of the text and stacked on the paragraph. Split the classes. Verdict headings got their spacing back.
Membership is $100 a month, billed monthly
Stripe checkout for membership is now a recurring subscription, not a one-off payment; access is revoked when the subscription ends. Price, name and pitch are editable at /account/admin (paulcmaxwell@gmail.com is admin).
Monthly webinars with guests, managed from the account
Webinars table in Supabase, visible only to members. Paul adds title, guest, time, join link, then the recording link afterwards. Members see upcoming and past sessions on /account with Join or Watch.
Table, timeline and map views on every collection
Shipped: List, Table and Timeline on /figures, switched client-side from ?view= (no server round-trip). Collection keeps other query params. Map moves to "Give figures dates and places" — nothing carries a location yet.
Every template screenshotted and de-stubbed
Screenshotted all 30 templates. Fixed: reading lists (author, note, real titles), Reading Room chapter rows (one lock icon instead of a pill per row), guides/frameworks no longer repeat the answer, summaries lose the rule, quotes use a mark not a line, Contents rail loses its track line, Courses loses the public Studio note, 404 spacing, Search loses the duplicate nav, auth buttons styled, bullets gone from chip lists, Yes/No control compact.
Template audit follow-ups
Done: login card single box; Private Session labelled Session; Tools index aligned; pre-order page shows its contents (lib/product-kind.ts PENDING_CONTENTS) and drops "(pre-order)" from the title; Art bench styled (chips, working grid, segmented Keep/No, expired images hidden). Reading-list titles still overridden in sanity/lib/library.ts LIST_TITLES until the Studio copies are edited.
Highlight colours, and a preview when signed out
Yellow is the real highlight; four other colours. Signed-out readers see their mark and a Sign in to keep it note. Works in dark mode.
Figures table: same filters, grouping and sort as the list
One control bar drives list and table; sortable column headers; grouped rows.
About: RevOps HQ since 2025, private equity work, Neuros
Neuros = north San Diego marketing and software agency: performance campaigns, software diligence, CRM rip-and-replace for M&A.
Coaching topics: leaving religion, life transitions, goals
Added to /consulting topics and a Coaching route on /contact.
Concept web on entries + /concepts/web atlas
Entry web drawn at real pixel size in the main column with cross-links; atlas of all 262 concepts with search, domain filters, pan/zoom and ?focus=.
Component catalogue + local MCP server for agents
docs/DESIGN.md §9 and .mcp.json -> web/scripts/mcp-server.mjs (tokens, components, roadmap, static gate).
Advisor chat: ask a thinker or a method about your goal
Shipped at /account/advisor. AI SDK + AI Gateway (anthropic/claude-sonnet-4.6), Supabase goal / goal_checkin / advisor_thread with RLS. Pick a domain and a thinker; cites library entries; logs check-ins.