Changelog

What’s new in Selah. Last shipped .

v0.39.5.1 → v0.39.5

Dragging a prayer in the Active column no longer jumps to the top-left.

Fixed

  • Dragging a prayer in the Active column no longer jumps to the top-left.

    The card now follows your cursor in every column, not just the others.

  • The prayer board drags cleanly on the first try.

    The first card you dragged could land misaligned while later drags were fine; the board now measures its columns continuously during a drag, so the first one behaves like the rest.

  • No more dead "Promote to prayer" button.

    The capture drawer had a permanently-disabled button that read as broken. It's hidden until the feature ships.

Added

  • Tables you can actually edit.

    Drop a table into a note and a small toolbar now appears while your cursor is in it — add or delete rows and columns, or remove the whole table. Before, an inserted table was stuck for good.

  • Terms and Privacy where you'd look for them.

    Sign-up and sign-in now carry a "By continuing, you agree to our Terms and Privacy Policy" line with links, and the landing-page footer links both pages.

Changed

  • A little more room on the free plan.

    The Companion's free allowance went from 5 to 7 messages a day, still shared across web and Telegram.

June 20, 2026

v0.39.2 → v0.39.4

The admin dashboard is now one room.

Added

  • The admin dashboard is now one room.

    It's a left-rail command center with a searchable, filterable Users directory. Each person shows their plan, billing status, email verification, last sign-in, and activity at a glance — no more bouncing between Stripe and Clerk to look someone up.

  • Grant a friend Plus from the admin.

    A Plan control on each user's page comps a free Plus plan in one click, and revokes it just as easily, for anyone without a paid Stripe subscription.

  • Google One Tap sign-in.

    Signed-out visitors now see Google's One Tap prompt automatically — one click to authenticate without navigating away or filling a form.

Changed

  • The per-user page consolidates the tools.

    It now carries read-only Billing and Identity panels (live subscription detail, a Stripe deep-link, Clerk sign-in and ban state) alongside the rename, admin, nudge, and delete actions, all in one place.

  • The "+ New" button and Search bar are now flag-gated.

    Both nav entry points are hidden by default while the features are still being designed. Enable PostHog flags nav_new_menu_enabled and nav_search_enabled (0% rollout) to show them per user.

  • The "selah" wordmark is now set in Geist sans-serif.

    Every surface that showed the brand name — nav, mobile drawer, onboarding header, sign-in, sign-up, and email footers — now uses Geist at weight 500, all lowercase. Cleaner, more minimal, and consistent with the rest of the type system.

  • The landing page wordmark matches.

    Both the header and footer on the public landing page use the same Geist treatment.

  • The trust row uses the real Link logo.

    The lock-and-link icons beneath the checkout button now show Link's actual brand mark instead of a hand-drawn chain — more recognizable at a glance.

  • Testimonials use the same type as the rest of the app.

    The quotes read in Inter (not a serif), consistent with the rest of onboarding.

  • The most important phrase in each testimonial is highlighted.

    A sage-tinted marker sweeps the full height of the text under "triggers my mind to think deeper" and "treated as a tool". It comes in slowly so scanners have time to read it, and the highlighted phrase is set slightly bolder.

  • Your billing plan shows in the settings sidebar.

    The Billing & plan row now says "Free" or "Plus" so you can see your plan at a glance without opening the page. On mobile the subtitle reads "Selah Plus" or "Free — upgrade anytime."

Fixed

  • Google One Tap now actually shows up.

    The One Tap prompt shipped last release but was silently blocked by the site's content-security policy, so signed-out visitors never saw it. Google's sign-in domains are now allowed and the prompt appears.

  • Companion replies on Telegram no longer push a big link card.

    When the Companion sent a reading-plan or Selah link, Telegram rendered a large preview image that crowded the chat. The Companion's replies now suppress that card. Sharing Selah elsewhere still shows the preview.

  • Lifecycle emails can't double-send.

    A retried Stripe webhook could send the trial-ending reminder or win-back email twice. Each now sends at most once.

  • Email links point at the right place by default.

    The fallback base URL was selah.app; it's now selah.so, so links never break if the environment variable is unset.

  • Onboarding survives a refresh.

    Reloading mid-signup no longer bounces you back to the first step.

  • Landing page headline and community link.

    The scatter section now reads "Your faith life, finally in one place." The Telegram community invite was expired; it's been replaced so clicking "Join the community" works again.

June 19, 2026

v0.37.0 → v0.39.1New

Sign-up is one continuous flow now.

Changed

  • The plan step shows social proof alongside the pricing.

    On desktop, testimonials from people who use Selah sit beside the plan card so you can read what others say while deciding. On mobile they stack above.

  • Real words from real people.

    Ever C. (a disciple) and Andrew B. (a church elder) share what they notice after using Selah — specific, unprompted, grounded.

  • The upgrade button is consistent everywhere in onboarding.

    Every primary call-to-action — from the welcome screen through the final demo — uses the same sage gradient button.

  • Selah's emails read tighter, and no longer use em dashes.
  • Sign-up is Clerk's polished screen now

    — the same look as sign-in, with social login available, instead of a hand-built form.

  • The whole app is easier to read and to navigate by keyboard.

    Links are darker and clearer, and a consistent focus ring follows you as you tab through the app.

  • Picking a reading plan is calmer.

    Instead of a wall of identical cards, there's one recommended plan to start with, the rest grouped by how much time they ask of you (a few weeks, a season, a year), and a quiet "build your own" at the end.

  • Selah Plus is live.

    $9/month or $90/year with a 14-day free trial. The free tier stays free, no card.

Added

  • Sign-up is one continuous flow now.

    Choosing your daily rhythm, building or picking a reading plan, and connecting Telegram all happen inside the onboarding wizard, with a Back button on every step. No more being dropped into a second setup screen after you thought you were finished.

  • A guided first look at Selah.

    On your first visit, a short walkthrough takes you through the Reader, your Journal, Prayer, the Companion, and Knowledge, one real page at a time.

  • Pick your plan when you sign up.

    The landing page sends you to pricing first. Choose Free and you go straight in. Choose Plus and you start a 14-day trial after onboarding, with a clear note that there's no charge today and a reminder before it ends.

  • A free Companion message every day, not just ten ever.

    The free tier now gives you 5 Companion messages a day instead of 10 for the lifetime of your account — enough to come back across several days and feel how Selah remembers your study. A quiet line appears only when you're down to your last one or two; nothing nags you before that.

  • Your reading on the web has its own pages.

    Browse the curated reading plans, see how Selah compares to other Bible tools, and read about what it's for — all without signing in.

  • A nudge before your trial ends and a way back if you leave.

    Plus trials now get a friendly reminder a few days before they convert, and if you cancel, a warm note that your study is still here whenever you want to return.

  • An invitation to the community.

    The welcome email now invites you into the private Selah group on Telegram, to share feedback and talk with the team.

  • Selah is open to the public.

    Anyone can sign up — no invite code. Every button on the landing page now starts an account, and sign-up is two steps instead of three.

  • Connect Telegram during onboarding.

    Right after you pick a reading plan, you can link Telegram in one tap and your daily reading arrives every morning. Skippable, and it skips itself if you're already connected.

  • The first run feels alive.

    A soft light drifts behind the onboarding screens, each step settles in at a calm pace, and the keepsake line draws its own underline. All of it goes still if you prefer reduced motion.

Fixed

  • The green buttons on the landing page now have readable white text.

    They were inheriting a dark color.

  • The "Kept" moment after your first note now waits for you to read it instead of vanishing on a timer.
  • The first-visit walkthrough no longer disappears when it reaches the Reader.
  • The landing animation no longer crashes.

    A rare crash (Sentry SELAH-SENTRY-2B) occurred when the ScrollTrigger fired after a chip element detached from the DOM on page load. The animation now checks whether the element is still attached before measuring it.

  • Opening a note no longer flashes a blank screen.

    Navigating from the notes list to a note editor briefly showed nothing before the editor loaded. There is now a loading skeleton so the transition is smooth.

  • The ⌘K folder picker no longer shows "No folders yet."

    It used to fetch your folders only when you opened the palette, so the first open always showed a brief empty state. Folders now load in the background on mount, so the list is ready when you open the palette.

  • Error messages across the app are now clean and consistent.

    In the stream, companion, reader, and notes, errors no longer leak raw browser messages. Every error surface says something like "Couldn't load your stream." or "Couldn't load notes." — nothing technical reaches you.

  • The Companion upgrade prompt appears when you've reached the free trial limit.

    Before, hitting the message limit surfaced a raw error instead of the option to upgrade.

  • Chat names no longer include intro phrases.

    A bug caused the AI to prefix titles with "Here's a short title:" or similar — those are stripped. Names like "David and Goliath" now appear instead of "Here's a title: David and Goliath".

  • The file import error says the right size.

    It previously said 2MB; the actual limit is 5MB.

  • Welcome and week-1 emails now open the right page.

    Both linked to a page that no longer exists, so the button did nothing useful; they now land you in your journal.

June 12, 2026

v0.33.2 → v0.36.3New

A new landing page.

Changed

  • A conversation's "⋯" menu and its note button stay pinned to the top-right

    of the chat as you scroll, instead of riding up out of view with the title. Picking "Rename" jumps you back to the top so the title field is in view.

  • Long conversation titles in the sidebar stay on one line and fade out

    at the edge instead of wrapping to two.

  • Every open conversation has a "⋯" menu in its top-right corner

    — rename, move to a folder, archive, or delete without going back to the sidebar.

  • Selah's replies dropped the green avatar dot

    for a cleaner, full-width message.

  • The floating companion bubble no longer appears on the companion screen itself

    , where it was redundant.

  • Removed the "Find a session" box

    from the sidebar; session search is moving to the global ⌘K.

  • You can set a conversation's status from its header

    — Open, Done, or Archived — and archive, restore, or delete a conversation from its menu. Archived conversations drop out of the default list.

  • The opening suggestions on a blank companion screen read as plain prompts ("Brainstorm a sermon", "Work through a passage", "Pray through something"), and the slash-command hints no longer repeat their own names.
  • A new landing page.

    The page a visitor sees before signing in is rebuilt from scratch. It opens on "A quiet place to study, pray, and teach." over a real, auto-cycling look at the app, then walks through the whole rhythm: your scattered study tools gathering into one place, a four-step "how it works", and three feature scenes that build themselves as you scroll — a verse picking up its Greek, a highlight, and an anchored thought; a prayer travelling from Active to Answered; an AI reading plan writing itself for your season. The companion section ("It will not write your sermon."), pricing with a clear free tier, a comparison table, the founder's note, and the FAQ round it out. The whole page scrolls smoothly.

  • Capture the page makes plain you can text Selah on Telegram

    , and the pricing is honest about what's free forever versus what the companion and knowledge graph cost.

  • Telegram is part of the free plan now.

    You can connect Telegram and talk with the Companion on it using your free messages — the same 10-message trial works on the web or in Telegram, whichever you prefer. Plus is for going unlimited and for proactive check-ins (Selah reaching out to you first). When you reach a limit, you get one calm note, not a wall.

Fixed

  • The companion's "New" button is a solid sage button again.

    It had been rendering as a cramped, dark-text blob; the previous fix didn't hold.

  • The "⋯" menu on a sidebar conversation opens in the right place.

    It was dropping to the bottom of the card; now it sits at the card's top-right corner, and the timestamp steps aside on hover.

  • The companion's text box now stays at the bottom of the screen

    in a brand-new chat and a short one, where you'd reach for it. It used to float up into the middle until the conversation grew long enough to fill the page.

  • The companion's buttons look like the rest of the app again.

    The "New" button and a few others had gone faint and flat; they're back to the app's normal solid styling.

  • Selah's "thinking" trail now settles below its reply

    once the answer arrives, instead of sitting above it.

  • The companion no longer scrolls as "one long page."

    The conversation, the session rail, and the living note each scroll on their own now, the message box stays put at the bottom, and opening a chat drops you at the latest message.

  • The new companion stopped responding for some people ("the connection dropped while I was thinking").

    If your conversation had been closed in the background — the 30-minute idle boundary, a "new conversation" tap, or opening a finished thread — the next message hit a dead end. It now quietly continues in a fresh conversation; finished conversations stay read-only, nothing is lost.

Added

  • A note from your first week.

    A few days after you start, if you saved something but haven't come back, Selah sends you one quiet email — your own first thought, with a gentle question to pick it back up. Reaches everyone, not just people on Telegram. One email, ever, and an unsubscribe link in the footer.

  • The companion screen is more complete and easier to live in.

    You can now organize past conversations into folders (a session can belong to several), filter the rail by folder, and close a conversation just by saying so — "close this session" — or with a Mark done action. When Selah keeps a living note beside the chat, a document icon reopens it after you've closed it. A short help note explains how the screen works.

June 11, 2026

v0.31.0 → v0.33.1New

Your beliefs, drawn as a map.

Changed

  • The app answers you now.

    Press a button or a tab and it deepens under your finger. Save a capture and the new entry settles into the feed instead of just appearing. Small moments that were missing — the difference between waiting and being answered.

  • An answered prayer finally feels like something.

    Move a prayer to Answered and the card glows warm gold, then settles — once, briefly, then it rests. The answered entry in your Stream echoes the same two breaths the next time you open it.

  • Your streak speaks in plain words.

    The prayer log marks the quiet milestones — "Seven days. A full week of showing up.", "A month of mornings." — and turns the number gold the day you reach seven, thirty, or a hundred. Still grace-based: a missed day doesn't punish you.

  • A warmer first line at home.

    The greeting now carries a second, quieter line that changes with the day.

  • The Companion, AI reading plans, and Telegram now follow your plan.

    Free includes a 10-message Companion trial and one AI-generated reading plan a quarter; Plus makes them unlimited and adds Telegram with proactive check-ins. When you reach a limit, Selah shows a calm upgrade card instead of an error.

  • Errors are now tied to a user (id only).

    When something breaks, the error report carries the user's id so you can tell who hit it and follow up — with their email, name, and IP still stripped, same as before. The companion's in-page cost estimate is now correct for Haiku calls (it was priced at the more expensive model).

Fixed

  • Full-height pages (settings, sign-up, admin) no longer jump as the mobile browser's address bar shows and hides.
  • You can delete and favourite a prayer on iPad now.

    Those actions used to live only on the prayer card's hover bar, which never appears on a touch screen — so on an iPad there was no way to reach them. They're now in the prayer's detail drawer (tap any prayer to open it): a star to favourite, a trash button with a confirm step to delete.

  • Your reading plan and your daily reading now agree on what day it is.

    If you fell behind on a plan, the daily reading (in the stream and on Telegram) used to freeze on your oldest unread day while the rest of the app showed today's calendar day — so the two disagreed (e.g. the card said Day 7 while your plan said Day 22). Both now show the same calendar day. Days you missed stay in the catch-up list on the web, ready when you want them.

Added

  • Your beliefs, drawn as a map.

    Knowledge now opens as a quiet constellation of everything you've studied — doctrines and themes as the largest names, the people and places that support them, connected by the notes and captures they share. Tap any belief to see it in your own words: the sentence you actually wrote, the verses it rests on, and a gentle sense of how rooted it is in your study so far. Nothing here grades whether a belief is right — only how much you've grown it. Switch to List anytime for the card view with merge and sync.

  • Selah Plus.

    Selah's core stays free. Plus opens the Companion without limits, the knowledge graph across every note you write, and Telegram — the parts that cost real money to run. $9/month or $90/year (two months free), with a 14-day trial and a card to start. Manage or cancel any time from Settings → Billing. If you were here before launch, Plus is on us — nothing to do.

  • A weekly nudge that brings your first capture back.

    If you saved one thing in your first week and didn't come back, the Companion now reaches out once over Telegram with a gentle question tied to what you wrote, so a single note doesn't go cold.

  • Per-user AI cost tracking, ready for launch.

    Every AI call the app makes — companion chat, devotionals, nightly memory and knowledge jobs, prayer matching, reading-plan generation — now records who it was for and what it cost, so you can see spend per person and per feature and tell who is driving the bill. Token counts and metadata only; no prayer or note content ever leaves for analytics.

  • A launch funnel.

    The app now records the moments that matter for activation — sign-up, onboarding finished, first session completed, Telegram linked — so the activation funnel, retention, and cost-per-user all live in one place.

Security

  • Public-launch hardening.

    Removed an internal debug endpoint from the app. Widened Telegram link codes so they can't be guessed inside their 15-minute window, and closed a race where two devices could claim the same code. The proactive check-in cron now claims each send atomically so a nudge can't fire twice.

June 10, 2026

v0.30.0 → v0.30.1New

The companion now reads your whole attachment.

Fixed

  • Groundwork fix for the new companion engine (still off by default).

    The experimental v2 companion engine couldn't reach the AI provider at all — every call failed — because of a base-path bug in the AI SDK's Anthropic adapter. Pinned the correct path; the engine's caching, step-by-step thinking, and tool use now all work end to end. No effect on the companion everyone currently uses.

  • The companion now reads your whole attachment.

    Attached notes used to be silently cut to the first paragraph or so; the companion answered as if the rest didn't exist. Notes now go in whole — a full sermon draft fits — and on the rare occasion something is still too large, the cut is marked so the companion knows it didn't see everything.

Added

  • A new dedicated companion screen, in early testing.

    Conversation on the left, a living note on the right: you watch the companion think and work — each step shown quietly as it goes — and when it starts a note, the note opens beside the chat. Stop a reply and keep what arrived, retry the last answer, edit a sent message and resend, find any session with ⌘K, and conversations name themselves after the first exchange. Off by default while it's validated; the classic chat is unchanged.

June 9, 2026

v0.29.0New

The landing page tour now shows Selah working, not screenshots of it.

Added

  • The landing page tour now shows Selah working, not screenshots of it.

    Three live demos play in "From a thought to Sunday morning": a capture types itself out and gets tagged to Romans 8:28, the same note resurfaces beside the verse three weeks later, and Sunday's outline assembles from the week's anchored thoughts. Each loops quietly while it's on screen and sits still when it isn't.

  • The "one tool" section crosses off the app pile in front of you.

    Logos, Notion, Obsidian, Telegram, and the rest get struck through one by one as the section scrolls in, instead of arriving pre-crossed.

Changed

  • The week-with-Selah timeline cascades in day by day

    instead of appearing all at once.

Fixed

  • No more blank gap under the hero preview on phones.

    The preview pane now sizes to the screenshot instead of holding a fixed height.

  • Reduced motion is honored across the whole landing page.

    The hero demo, the tour demos, and the strike-through all hold their finished state instead of looping. The "one tool" chips also keep their scattered layout for reduced-motion visitors — they used to pile up in the center.

  • Screen readers get a description of each tour demo.

    The old screenshots' alt text would have been lost in the swap; each demo now carries a spoken summary.

  • The tour demos survive a broken script.

    If JavaScript fails to load, every demo card still shows its complete final state — full sentence, tags, and confirmation — instead of an empty card.

June 5, 2026

v0.28.0 → v0.28.1New

Prayer reminders are opt-in.

Fixed

  • The companion no longer scatters loose captures across your stream during an interview or teaching-prep session.

    Those sessions are meant to gather everything into one place — the interview note or the teaching message — so saving stray captures along the way just made duplicates. It now waits for that single wrap-up. If you explicitly ask it to "save that as a capture," it still does.

  • No more invented "you haven't prayed for this in weeks."

    The "forgotten prayer" nudge now only fires for a prayer genuinely left untouched for 30+ days, measured from real engagement instead of guessed by the model. Fresh and recently-touched prayers are never described as neglected.

Added

  • Prayer reminders are opt-in.

    The companion no longer nudges you about a specific prayer unless you turn reminders on. There's a new toggle in Settings → Companion; it starts off, so a quiet prayer board stays quiet.

  • Your prayer streak counts everything you actually do.

    Creating a prayer, editing it, logging an update, or praying a session — even a short or discarded one — now counts toward your streak and activity heatmap. Before, only fully completed sessions counted, so most real prayer went uncredited.

Changed

  • The companion reaches out less often.

    The default time between proactive nudges went from one hour to two, so Selah feels present without crowding the day.

  • The companion stops repeating itself.

    It won't raise the same prayer or the same theme again within a cooldown window, and it caps general check-ins to once a week.

June 3, 2026

v0.25.0 → v0.27.1New

Pages load in one clean step.

Changed

  • The landing page shows the real app.

    The product tour in the hero now cycles through actual screenshots of Companion, the prayer board, and your knowledge graph instead of hand-drawn stand-ins. The philosophy section opens with a photo of Selah in use — an iPad and an open Bible — beside the words.

  • Returning to a page is instant.

    Move away from Library, Notes, Stream, or Reader and come back a moment later — it's already loaded, no spinner replay.

Fixed

  • The landing page no longer scrolls sideways on a phone.

    The prayer board preview was wider than the screen, dragging the whole page with it. It now stacks into one column on small screens.

  • The headline fits the phone screen.

    "A quiet place to study, pray, and teach" was oversized on mobile and broke awkwardly; it now sizes down and wraps cleanly.

  • Removed the dead Privacy and Terms links in the footer that went nowhere.
  • Pages load in one clean step.

    Library, Notes, and Stream used to flash a skeleton, then a second skeleton, then the content. Now there's a single loading state, then the page.

  • Unsaved note edits are protected.

    If a save fails, you'll see a retry prompt. Closing the tab with unsaved changes now asks before discarding them.

  • Highlighting on iPad works cleanly.

    The highlight sheet waits until you lift your finger before opening — no more popup mid-drag.

  • The Library looks like Notes.

    Same reading width, same top bar — consistent across both.

  • The Stream drawer stays open.

    Opening an entry in your Stream is reliable now; the panel no longer snaps shut.

  • Pages no longer flash white when you navigate.

    Moving between sections is smooth.

Added

  • A verse for your day.

    Your home screen now opens with one verse from Psalms or Proverbs — the same one for everyone each day. A quiet anchor before you start prep.

May 29, 2026

v0.24.0New

Your prayer board speaks the same status language as everything else.

Added

  • Your prayer board speaks the same status language as everything else.

    Prayers now use the one shared status system — the four columns (Active, Waiting, Ongoing, Answered) are those statuses, and the prayer panel gets the same status pill and picker you already see on notes. Marking a prayer answered from Telegram or the companion now lands it in your Stream the way doing it on the board always has.

Changed

  • Every page lines up.

    Notes, Library, Stream, Search, Settings, the companion, and onboarding now share one set of width rules, so the main column is the same comfortable reading width everywhere instead of cramped on some pages and sprawling on others. Loading screens match the real page padding, so content stops jumping when it arrives.

  • Status and folder sit on one row.

    On a note, the folder now sits beside the status instead of stacked below it. The list/grid view toggle is the same control across spaces, and your choice sticks.

Fixed

  • Changing a note's status sticks now.

    Setting a note to Exploring or Resolved used to quietly snap back to Active on reload; it saves for real.

  • Highlighting on iPad uses the bottom sheet

    — the touch-friendly highlight panel shows up on tablets, not just phones.

  • Reader polish on tablets

    — the sidebar footer stays pinned, the reading-plan catch-up box fits inside the dock, and the word-study badge is easier to tap.

  • Notes keep your chosen view on mobile

    — pick the list view and mobile stays a compact list instead of forcing the grid.

May 28, 2026

v0.23.0 → v0.23.1New

One status system across Selah.

Added

  • One status system across Selah.

    Notes, sessions, and prayers now share the same status: the same pill, the same dropdown, the same colors. The dropdown groups statuses by what they mean — Active, Done, Archived — so it reads the same everywhere.

  • Make your own statuses, per surface.

    Add a custom status (name, color, category) and it shows up only where it belongs — a note status won't clutter your prayer board, and vice versa.

Changed

  • Captures stop pretending to have a status.

    A capture is a quick thought on its way to becoming something. Instead of a status dot, a promoted capture now shows where it went — "→ Note", "→ Prayer", or "→ Session".

  • Deleting a custom status keeps your items where they are.

    If you delete a status you made, anything using it moves to the matching built-in status (a "done" item stays done) instead of silently reopening.

Fixed

  • Creating a status from a note no longer closes the menu.

    Clicking "New status" used to make the whole dropdown vanish; the form now opens in place.

  • Status pills are no longer clipped

    at the top of the note header.

  • The note editor no longer crashes on load

    in some cases (a rendering-timing fix shared with the scratchpad editor).

May 27, 2026

v0.22.6

Past weekly reflection cards now show the right companion session count.

Fixed

  • Past weekly reflection cards now show the right companion session count.

    Cards from weeks before the 0.22.5 update were showing "0 companion sessions" even when you had sessions that week. The count is now correct for all past weeks.

May 26, 2026

v0.22.5

You can turn the Saturday weekly reflection off.

Added

  • You can turn the Saturday weekly reflection off.

    Settings → Notifications has a new toggle for the Saturday-evening "Weekly reflection" digest. On by default for everyone. Flip it off and the digest stops landing in your stream; flip it back on whenever.

  • The weekly arc card now spells out the week.

    Under the headline, a single quiet line: "3 captures · 2 notes · 1 prayer · 4 companion sessions." Just the primitives that had activity this week — zeros hide. Replaces the broad "reflections" framing with the specific shape of what you actually did.

Changed

  • Disabling the digest takes effect across surfaces without a refresh.

    Same pattern as the daily-devotional toggle — flipping the setting broadcasts to every mounted surface so the stream, the menu, and any future digest affordances update in lockstep.

May 25, 2026

v0.22.3 → v0.22.4

Plan cards in the stream now update the second you mark a day read.

Fixed

  • Plan cards in the stream now update the second you mark a day read.

    Tap a plan day in the reader (or the drawer footer, or the day band), and the card in the stream switches to "✓ read" without a refresh. Before, the stream sat on stale state until you reloaded.

  • The "Today's reading" band hides itself when you mark the day read from anywhere else.

    Mark it in the reader, switch back to the stream — the band is gone. No more nag for a day you already finished.

  • Folder counts in the folder picker stay current.

    Move a note to a folder somewhere else in the app, then open the folder picker — the folder list reflects the move. Same for the prayer board (which also refreshes when you switch tabs back).

  • Telegram catches up on missed reading-plan days.

    If you skipped yesterday, this morning's message is for yesterday's day, not today's. The cron now walks the backlog before falling back to today. You stop silently losing days from Telegram.

  • Marking a plan day read from the daily devotional drawer updates the rest of the stream.

    Before, the devotional drawer's mark-read button worked but didn't tell any other surface, so cards stayed stale until reload.

  • "Send a daily message" delivers again when devotional is off.

    v0.22.2 decoupled the two settings on the page so toggling daily-scripture wouldn't silently re-enable devotional. But the morning cron still required both to be on, so the daily-scripture toggle wasn't actually delivering for anyone who had turned devotional off independently. The cron now respects the daily-scripture toggle on its own.

  • Enabling daily-scripture now also populates a default delivery hour.

    Before, you could toggle "Send a daily message" on without ever setting a delivery hour, and the cron would skip you silently. Now the toggle sets 7 AM local + auto-detects your timezone if either is unset, so the message actually arrives the next morning.

  • Re-anchor is no longer "Coming soon."

    The placeholder is gone. The pill is the action.

  • The homepage stopped 500ing after Brief 4 captures shipped (Sentry SELAH-SENTRY-1Y).

    A leftover prayers.tags column reference was throwing undefined_column on every page load because dev Neon had dropped the column out of band weeks earlier. The schema now matches reality, and the orphan prayer_tags table is gone too.

  • Prayer category writes stop racing each other.

    Two rapid taps on a prayer's status used to dispatch two opposite requests, and the loser would overwrite the winner. Mutations now go through one path with a stable cache key.

Added

  • Highlight a phrase in BSB, read it in WEB.

    Phrase highlights now follow you across translations. The matching tokens light up in the translation you switch to. When the auto-match isn't confident, you see the whole verse marked with a gold "adjusted" pill so you know the system isn't sure.

  • Multi-verse phrase highlights align verse by verse.

    A highlight that spans two verses gets aligned per-verse against the target translation. If verse 16 matches cleanly and verse 17 falls back, you see the precise phrase in 16 and the whole verse in 17 — not the whole highlight collapsing to fallback.

  • Re-anchor highlights when the auto-match is wrong.

    Click the gold "adjusted" pill on a phrase highlight, the active verse stays bright while siblings dim, you select the words you actually meant and hit Save. One click in, native text selection, no modal.

  • Universal status across notes, captures, and prayers.

    Four defaults everyone gets — Active, Exploring, On hold, Resolved — plus your own custom statuses through a single picker. Same color palette, same behavior, same place on every surface.

  • Notes and captures can live in more than one folder.

    A note about Romans 8 can sit in both Sermons and Romans without you picking one. Folder chips show in the note header with × to remove and + Folder to add another.

  • Note types became folders you can rename and merge.

    Threads, Insights, Teaching, Devotional — your old categories are now folders. A one-time banner explains the change; existing notes are auto-filed by their type.

  • Filter the Notes index by status, folder, or both.

    Two filter strips above the list: pick a status, pick folders, get the intersection.

  • Capture cards show status + folder chips in the Stream feed and reader dock.

    A glance at a capture card tells you its status and which folders it lives in.

May 23, 2026

v0.22.0 → v0.22.2New

Telegram prayer nudges stop inventing dates.

Fixed

  • Disabling "Daily devotional" actually hides devotional UI now.

    Toggling the setting off was only stopping the morning delivery; the stream still showed the "Sit with scripture" CTA, the "+ New" menu still listed Start devotional, the Devotionals filter chip stayed on the stream, and the settings page still showed this week's theme. All of those now disappear when you turn devotional off.

  • The toggle stops being silently flipped back on.

    Two unrelated flows were re-enabling devotional without telling you: toggling "Send a daily message" in settings, and revisiting the reading-plan picker. Both stop doing that. If you turn devotional off, it stays off until you turn it on yourself.

  • Re-enabling devotional updates the stream and menu instantly.

    No reload needed. Turn it back on in settings and the band, chip, and menu item all reappear.

  • Stuck on `?filter=devotionals` after disabling? Fixed.

    The URL now bounces back to All when the Devotionals chip disappears, so you can't get parked on an unreachable filter.

  • Settings page reads as intentionally quiet when disabled.

    When the toggle is off, the page shows the preview card plus a one-line "Re-enable to see your week's theme." instead of looking half-empty.

  • Telegram prayer nudges stop inventing dates.

    A prayer you added today no longer comes back as "this has been sitting since last month" or "you mentioned this a while ago." The AI now has the actual dates — added, last edited, last prayed — and only references them when the math is real.

  • The AI stops double-nudging prayers on a schedule.

    If you set daily, weekly, or monthly reminders on a prayer, only the scheduled digest sends them. The AI no longer picks the same prayer for a side nudge a few hours after the digest fires.

  • "Still carrying" nudges stop firing on fresh prayers.

    A prayer you added today isn't forgotten. That phrasing now requires either no prayer session in 7+ days, or a prayer added 7+ days ago that you've never opened.

Changed

  • The AI sees the body of your prayer, not just the title.

    Titles are usually three words; the actual context lives in the description. Nudges land with more specifics now — what the prayer is really about, not just a guess from the title.

  • Folder and favorite status reach the AI.

    A nudge about a Family prayer can sound different from a Career prayer. Starred prayers can be picked first.

  • Pray-through history reaches the AI.

    "When did I last pray this?" is now a real signal — not "when did I add it?" A prayer you wrestled with yesterday is not forgotten.

May 22, 2026

v0.21.0New

Organize prayers into folders.

Added

  • Organize prayers into folders.

    The prayer board now groups by folder as well as by status — a toggle above the board switches between them. Drag a prayer between folders, or make a new folder right from the board. Folders are shared with the Library, so a prayer you file shows up in both places.

  • Tell the companion to file prayers and set reminders.

    On Telegram you can now say "put these prayers in my Clients folder" or "remind me weekly about this one" and the companion does it.

Changed

  • Folders replace tags on the prayer board.

    Folders are the one way to organize a prayer now. Your existing tags carry over — each becomes a folder of the same name.

  • The activity heatmap moved to the Stats tab.

    Log is now just your session history. Stats holds the streak cards, the 52-week heatmap, and your rhythm — your prayer numbers in one place.

  • Each status column has a one-line explainer.

    Tap the question mark on Active, Waiting, Ongoing, or Answered to see what belongs there.

May 21, 2026

v0.19.0 → v0.20.0New

Privacy mode on the prayer board.

Added

  • Privacy mode on the prayer board.

    Tap the eye in the top bar and every prayer title, description, update, and session note blurs — so you can show the board on a shared screen without showing what you're carrying.

  • Edit and delete prayer updates.

    Fix a wording slip in an update, or remove one entirely, from the prayer's drawer.

  • A nudge to connect Telegram for reminders.

    Set a reminder on a prayer when Telegram isn't linked and the drawer now tells you reminders arrive on Telegram, with a link to connect it — so a reminder you set actually reaches you.

  • Prayer on Telegram.

    Start a prayer session from the Telegram bot — say "start prayer", pray, then "done" — and it lands in your web Prayer Timer log, stats, and streak, exactly like a session run on the site. Stop more than an hour after you started and the bot asks roughly how long you prayed instead of trusting a stale clock.

  • The bot understands prayer in plain language.

    Send "praying for the elders meeting" and it finds that prayer on your board and holds it with you. If it's something new, it adds it. No menus to tap through.

  • Per-prayer reminders.

    Every prayer on the board can carry a reminder — Off, Daily, Weekly, or Monthly — set from its drawer on the web. When reminders come due, the bot sends one message listing them; reply with a number, or just name the ones you want, and it starts a prayer session across them.

  • Mark a prayer answered from Telegram.

    Tap Mark answered, tell the bot how God met you in it, and the prayer moves to your answered prayers with the testimony saved.

  • A weekly prayer recap.

    Once a week the bot notes how many times you prayed, across how many prayers, and how many were answered.

Changed

  • The prayer card is just the title now.

    Folder, tags, and the stage buttons came off the card. At rest you see the prayer; hover and Pray, Favourite, and Delete appear along the bottom.

  • Folder and tags moved into the prayer's drawer.

    Open a prayer to set its folder or tags. The card stays clean, and the drawer now has a folder control beside its tags.

  • New tags all share one color

    instead of getting a random one. The five built-in tags keep their own colors.

  • The Answered column sits at the far right

    of the board, after Ongoing.

  • The prayer board uses the full width

    of the page.

  • Scripture references in the Telegram daily message are tappable.

    The day's passage and every cross-reference open straight to that passage in the Selah reader, and read as "Proverbs 21" rather than a code.

  • Prayer nudges are actionable.

    The bot's prayer reminders now carry Pray now and Mark answered buttons — one tap instead of a message you can't do anything with.

  • The Telegram prayer board

    is a numbered list you answer by typing: open one prayer, or start praying for several at once.

  • A prayer session started on Telegram shows up on the web.

    The prayer pill sees it, tells you it's running on Telegram, and lets you continue it on the web or end it from there.

Fixed

  • A malformed link into the reader

    — a bad note or passage id in the URL — now returns a clean not-found instead of an error page.

  • Choosing a translation Selah doesn't carry no longer breaks your daily reading.

    If you picked ESV or NASB at sign-up, the devotional errored out instead of showing anything. It now falls back to a translation that's available, and still remembers the one you'd prefer.

  • The Prayer Timer's Log and Stats tabs no longer overlap.
  • "Proverbs, Story & Gospel" now reads Proverbs by the calendar date.

    On the 21st of the month you read Proverbs 21, whatever day of the plan you're on. It used to start at Proverbs 1 and count up regardless of the date. The Old Testament story and New Testament readings still move in order.

  • The daily Telegram message no longer dumps a whole chapter into the chat.

    When the day's reading is long, the message carries just the reference; a short passage of a verse or two still comes through in full.

May 20, 2026

v0.16.0 → v0.18.2New

The Prayer Timer.

Changed

  • The "building your plan" screen is honest now.

    While a custom reading plan is generating, the wait screen used to show a sample list of days that looked like your finished plan but was the same every time. It now shows just the build steps; your real plan appears on the next screen.

  • The Companion shows its work.

    While it thinks through a question, a calm line tells you where it is — checking cross-references, looking up a word, drafting the reply — instead of a silent thirty-second spinner. The answer still arrives the same way; the wait just stopped being a black box.

  • The home and notes pages now use the same wider layout as the prayer page, so the surfaces line up.

Fixed

  • Building a custom reading plan no longer times out.

    Longer plans — a full year, say — used to fail with an error before they finished generating. They now build reliably, however many days you ask for.

  • Some people weren't getting their daily devotional.

    If you had no active reading plan and your week had no theme set, devotional generation errored out and skipped you — every day. It now passes over that day quietly and resumes the moment there's something to read.

  • The reading-plan picker now shows the full set of curated plans.

    They were missing immediately after the 0.16.0 launch.

Added

  • The Prayer Timer.

    Start a timer and pray. The clock holds when you pause; you can give blocks of time to specific prayers on your board, and jot a thought or a verse mid-session without losing focus. A focus mode clears the screen down to just the timer. Finished sessions are saved with a note (very short ones are discarded), and a Log and Stats view show where your prayer time has gone.

  • A reworked prayer board.

    The board is now a kanban with a filter row and custom tags you create yourself — organize prayers however fits.

  • A new curated reading plan — "Proverbs, the Story & the Gospel."

    A year in three short readings a day: a chapter of Proverbs keyed to the date, the Old Testament story of God's people in order, and a New Testament passage. At thirty turning points the Old Testament shadow and its New Testament fulfilment are set on the same day — Isaac bound on Moriah alongside the crucifixion, the bronze serpent alongside John 3, Jonah's three days alongside the sign of Jonah. Curated by Patrick B.

  • Two whole-Bible reading plans.

    "Bible in a Year" reads straight through, Genesis to Revelation. "Old & New Testament Daily" pairs an Old Testament reading with a New Testament reading every day. They join the curated set — seven plans to choose from.

  • The Reader — a dedicated Scripture study workspace.

    A new /reader surface for deep study. Read two passages side by side in a multi-pane layout. Tap any word for Word Study: its Strong's number, lexicon definition, morphology, how often it occurs, and how the KJV renders it. Tag multi-word phrases as single study targets. Cross-references show inline with hover previews. Visualizations bring the text to life — a family tree you can zoom, pan, and click through person to person; a places map; a timeline. A Gospel harmony lines up parallel accounts. A Resources tab surfaces Old-Testament-in-New quotations and the Names of God. Keep a scratchpad open beside the passage to write as you study, or summon the Companion into the reader to talk a passage through. Per-pane full-text search, a ⌘K command palette, KJV by default. The lexical, morphology, and cross-reference data comes from STEPBible — the open scholarly Bible dataset curated by Tyndale House, Cambridge.

  • Reading Plans — read through Scripture with a plan.

    Pick a curated plan (the New Testament in 90 days, Psalms + Proverbs monthly, the Sermon on the Mount, the Gospel of John, the Pauline epistles, or a year-long Wisdom-Story-Gospel rotation) — or describe a goal and have a custom plan built for you. Each day's reading lands as a card. The plan is calendar-aligned: "today" is the day you're actually on, and days you miss collect in a catch-up list you can read in order or skip. Mark days read, pause and resume without losing your place, and switch plans anytime — picking a plan back up resumes where you left off. A reading-plan tab lives in the Reader, your daily devotional is built from the plan's passage, the home dashboard tracks your progress, and Telegram delivers each day's reading.

  • Public profile pages.

    Your activity now has a shareable /@username page with a contribution-style heatmap, shown only when you turn on the activity-visible toggle.

May 1, 2026

v0.15.11

Sign-up rollback no longer leaves users in a half-deleted state.

Fixed

  • Sign-up rollback no longer leaves users in a half-deleted state.

    When a sign-up needs to be rolled back (bad invite code, transient Clerk outage), both the local account and the Clerk identity now come down together, or neither does. The previous path could quietly leave a "ghost" account that looked signed up but had no invite consumed. Two affected users on 2026-05-01 had their email verification restored manually.

  • Unauthenticated API requests return 401 instead of 500.

    Hitting prayer or concept endpoints without a session now returns a clean "Unauthorized" response. Previously the unauth case escaped as a server error and showed up as a spike in error tracking, drowning out real bugs.

  • Already-signed-in visitors no longer hit an error on the sign-up page.

    If you landed on the sign-up page while already signed in — for example, after an admin verified your email — you'd see a confusing error instead of getting into the app. You now go straight to onboarding instead.

April 30, 2026

v0.15.8 → v0.15.9

No more "you started a companion session about an hour ago" message after using Telegram.

Fixed

  • No more "you started a companion session about an hour ago" message after using Telegram.

    The bot was sending it after an hour of silence following any Telegram chat. Telegram chat doesn't have a session you "start" or "wrap up" — the message read as nonsense. Devotional sessions still get the same idle check, where it actually maps to something the user is doing.

  • Sign-up works again for invite-coded accounts.

    Some sign-ups in the last day created a Clerk account, then had it deleted seconds later, bouncing the user back to the sign-in page. Two affected users can retry their original invite codes and finish creating their accounts.

April 29, 2026

v0.15.7

Stream is a complete redesign.

Added

  • Stream is a complete redesign.

    The Stream page now shows every entry type in one unified feed — captures, notes, prayers, devotionals, companion sessions, weekly arcs — instead of a flat capture list. Each card opens into a drawer for inline detail. Date grouping, filter tabs (All / Captures / Notes / Prayers / Devotionals / Companion), live-session banner, a capture input pinned to the bottom, and a "+ New" menu for jumping into anything from one place.

  • Folders + Library.

    A new sidebar folder tree and a Library page give you one place to organize notes, captures, and prayers across every surface. Star a folder to pin it to the top. Drag items between folders. Open a folder to see breadcrumbs and sub-folders. Reorganizing never leaves items half-filed. The folder chip on each card lets you re-file in one click.

  • Weekly arc — your week, summarized in Telegram.

    A Saturday-evening Telegram message lands with a one-paragraph lede, this-week stats (captures, sessions, notes, primary book studied), prayer summaries from your active board, and the scripture refs that came up most. Quiet weeks get gentler copy ("a quieter week — sometimes that's the point") instead of a stat dump.

  • Cross-surface notifications.

    Things you do on the web — raise a prayer, save a note, end a session, confirm a theme, mark a prayer answered — now ping your Telegram chat with a short observational note. Events that started on Telegram don't echo back. If you do the same thing five times in two minutes, you get one ping, not five.

  • Telegram `/stream` command.

    Browse the same unified feed from inside the bot, paginated. Now you have parity between web and chat for what you've been up to.

  • Smarter heartbeat scheduling.

    Long active sessions get a single check-in ("still in 1 Cor 13?" after an hour). Prayer reminders and forgotten-prayer nudges look different from each other so you can tell at a glance which is which. Prayers and notes don't get nudged twice for the same thing under different wording.

  • Daily devotional card leads with scripture.

    The Stream's daily devotional card shows the scripture ref + opening line first so you can decide whether to dive in without expanding.

Fixed

  • Stream no longer errors out when you're signed out.

    Hitting /stream without a session used to throw a server error; it now redirects you to sign-in like every other authed page.

  • Untitled placeholder shows up on a fresh note.

    New notes were saving with the literal title "Untitled" instead of leaving the title blank, so typing in the title field appended to it. Now the field is empty by default and the placeholder reads "Untitled" until you write something.

  • Devotional settings card no longer logs a stray error when you navigate away mid-load.

    Switching surfaces while the card was fetching could leave a half-finished request that the page later complained about. It now cancels cleanly.

  • Filing an item into a brand-new folder is now all-or-nothing.

    Creating a folder and dropping an item into it in one gesture used to leave the item half-filed if the second step failed. The flow either succeeds completely or leaves the item where it was.

  • Telegram welcome message now mentions everything you can do.

    The /start linking flow undersold what was wired up; it now lists Stream browsing, prayer raising, note-saving from chat, and the Saturday weekly arc.

Changed

  • Public note URLs use a stable namespace.

    The user-facing share URL stays /@username/[slug] — that hasn't changed and your existing share links still work. Internally the route is now namespaced so adding new top-level pages won't collide with usernames in the future.

  • Prompts tightened across devotional, prep, heartbeat, learning, summary, and knowledge graph.

    Less restating things you already know, fewer hedge words, more direct observational voice. Quality re-checked against the eval suite for each surface.

  • Saturday-evening double-pinging fixed.

    When the weekly arc Telegram lands at 6pm, the regular Saturday devotional now drops the parts that overlap so you don't read the same three sentences twice in five minutes.

  • Marking a prayer answered uses 🕊 (peace dove) instead of 🌅 (sunrise).

    The dove reads tonally neutral whether the answer was joyful or somber — a sick parent who passed shouldn't get a sunrise emoji.

  • Help icons and loading states now consistent across pages.

    The ? help button sits in the same spot on every authed page; loading skeletons match the layouts they stand in for; keyboard shortcuts no longer fire from inside form inputs.

April 28, 2026

v0.15.6

Pages now show instant skeletons while loading.

Changed

  • Pages now show instant skeletons while loading.

    Notes, Companion, Prayer Board, Knowledge, and Search all display page-matched placeholder layouts the moment you navigate to them — no blank screens or layout jumps while data fetches.

  • Button and Badge styles compose cleanly.

    Tailwind class overrides passed via className now reliably win over defaults. Stacking multiple variants no longer produces unexpected merged styles.

  • New `Page` component for consistent 5-state layout.

    Any page that fetches data can now use <Page loading error empty emptyState> to get loading skeletons, auto-dismissing error banners, and empty states without writing that logic from scratch each time.

April 26, 2026

v0.15.5

Companion chat works across web and Telegram again.

Fixed

  • Companion chat works across web and Telegram again.

    Switching between the web companion and your Telegram bot could trigger a crash. Both surfaces now stay in sync without errors.

  • Notes load reliably again.

    Some users saw an error when opening their notes list. That's resolved.

April 25, 2026

v0.15.3 → v0.15.4

Companion now remembers things about you across sessions.

Added

  • Companion now remembers things about you across sessions.

    The memory system extracts atomic facts from session summaries (study style, theology, life context, preferences, observations) and stores them persistently. Facts are reinforced when they reappear, superseded when they change, and expired when they have a deadline. The companion and devotional engine pull the top active facts into context so each session builds on what came before.

  • Concept summaries now include personal context.

    When the cron resynthesizes a concept summary, it includes memory facts that mention that concept by name — prefixed [memory] in the snippet context passed to the LLM. "Grace" as a concept will now surface that you view it as empowerment rather than permission.

  • Concept cards show "Updated X ago".

    Every concept detail view now shows a relative timestamp ("Updated 3 hours ago") regardless of whether the concept has a summary yet. Previously the timestamp was only visible when a summary existed.

  • Notes track how many times they've been edited.

    A new edit_count column on notes increments on every content save. The companion's activity digest now reflects the real edit depth rather than a hardcoded floor of 1.

  • Cleaner public changelog page.

    The /changelog page now groups releases by date instead of stacking version sections vertically. When several versions ship the same day, they collapse into one accordion bullet per release with the version number tagged inline. Less scroll, easier to find what shipped this week.

Fixed

  • Prompt injection in memory facts is now caught and flagged.

    Fact text is screened against known injection patterns before storage. Suspicious facts are stored with flagged_injection=true and excluded from all LLM context rather than dropped — so "I want to disregard my doubts about grace" doesn't disappear, it just waits for review. Reinforcement updates also propagate the flag if a later extraction catches it.

  • Concept staleness matching is more accurate.

    The stale-concept flagging logic (which marks concepts for re-summarization after a session produces related facts) now uses a shared token-based matcher instead of a substring check. Short concept names (≤ 3 chars) no longer produce false positives. Same matcher used in both the pipeline and the cron so they can't diverge.

  • Profile regeneration is now concurrent-safe.

    factsVersion was set to facts.length on every update, so two simultaneous regenerations could both read 5 facts and write factsVersion: 5 — making the second write look like a no-op when it wasn't. Now incremented atomically with COALESCE(current, 0) + 1 in SQL on both the INSERT and UPDATE branches.

  • Database errors in Sentry now actually tell us what went wrong.

    Postgres errors from the Neon serverless driver were arriving as "NeonDbError: null" with no SQLSTATE, no severity, no way to triage. The redactor strips message text for privacy (users write prayers); the categorical Postgres metadata never made it through Sentry's normalization. Two new tags now ride along on every NeonDbError event: dbErrorCode (the 5-char SQLSTATE — 42P01, 23505, etc) and dbErrorSeverity (ERROR / FATAL / PANIC / etc). When a database query fails in production, we'll know in seconds whether it's a missing table (migration drift), a duplicate key, a connection failure, or a timeout. Closes [SELAH-SENTRY-D](https://selah-sr.sentry.io/issues/7440039530/), unblocks triage on SELAH-SENTRY-C and SELAH-SENTRY-3 (same throw site, different captures via errorDigest matching).

  • Telegram companion back online after silent migration failure took down the sessions table.

    relation "sessions" does not exist was killing every /api/telegram/webhook call since the stream v2 deploy. Root cause: the migration runner's regex splitter (/;\s*(?:\n|$)/) shredded DO $$ PL/pgSQL blocks into invalid fragments. Neon's HTTP driver accepted them silently (returned 200, executed nothing), the runner marked all three migrations (0026, 0027, 0028) as applied, and the companion_sessions → sessions rename never happened. Recovery migration 0032_fix_sessions_schema.sql applies all the skipped DDL idempotently — rename, new columns, index, stream_entries table, session_id foreign keys on stream_captures and notes.

  • Companion warnings stop arriving as "<unlabeled>" events.

    Sentry's captureMessage calls (the orphan-intent breadcrumb, the tool-loop hop budget exhaustion log, the final-response fallback warning) hand a static string to event.message, which the redactor strips for privacy. Without a tag, every site looked identical on the dashboard. New messageOrigin tag derives from a fixed prefix allowlist of literal strings our code emits — companion.orphan_intent, companion.hop_budget_exhausted, companion.final_response_fallback, ai.stop_reason, ai.schema.json_parse_failed, ai.schema.validation_failed, ai.job. Each captureMessage site now sorts to its own dashboard bucket. Closes [SELAH-SENTRY-8](https://selah-sr.sentry.io/issues/7436346156/).

April 24, 2026

v0.15.0 → v0.15.2New

Your Telegram companion now walks alongside you, not just organizes your desk.

Added

  • Sentry events you can actually triage.

    Every Sentry event now ships with three new tags the redactor keeps alongside the existing privacy allowlist: errorType (TypeError, Error, ...), errorMechanism (onerror, onunhandledrejection, generic), and errorOrigin (a tag like stream.load when the stripped error message starts with one of our own static throws). Before this, window.onerror-caught errors landed as "Error: null" with no way to tell a TypeError apart from a generic Error or a boundary throw apart from a global-handler capture. Now a single glance at the tags narrows the universe: errorType=Error + errorMechanism=onerror + no errorOrigin + no boundary = "thrown outside React and outside any throw site we recognized" — probably third-party or an async callback we forgot to wrap. Actionable in seconds. Privacy unchanged: exception messages still stripped; errorOrigin only ever holds one of the fixed literal prefix labels, never any user content.

  • Your Telegram companion now walks alongside you, not just organizes your desk.

    Most of the time it notices what you've been carrying (a recent devotional, a pattern of anxiety in your captures, a prayer you've been sitting with) and invites a heart-level response instead of reminding you about stale notes. A smaller slice still handles the file clerk work. The mix target baked into the prompt: ~60% formation (application, gratitude, lament, practice rhythms, shepherd questions, sometimes just "sitting with you"), ~25% study/notes organization, ~15% trivia.

  • New nudge types to match.

    [application], [meditation_invite], [gratitude_surface], [lament_invite], [practice_rhythm], [shepherd_question], [silence_invite] alongside the existing [note_stale], [prayer_forgotten], [connection], [did_you_know], [check_in], [offer]. All enum-locked at the parser — if Haiku invents a new tag like [heart_check], the nudge gets dropped (with a summary.skippedUnknownType counter for observability) rather than saved to the DB as a freeform string.

  • Post-devotional cooldown.

    If you just finished a devotional (saved it, opened it on web, or received it on Telegram), the heartbeat stays quiet for 4 hours. No more "you have stale notes" nudges 35 minutes after a morning reading. Cooldown anchors on the strongest completion signal available.

  • Weekly reflection nudge.

    On your reflection weekday (default Saturday), if you haven't written this week's reflection, you get one gentle "looking back at the week, where did you see grace?" nudge. It bypasses the post-devotional cooldown on purpose (reflection day IS the weekly wrap-up) but counts against your daily 2-nudge cap like any other content nudge.

  • First-nudge intro.

    The very first heartbeat you ever receive teaches you you can tune the companion by chatting with it: "Tell me anytime if the tone's off — 'more rest, less notes' — and I'll adjust." Delivered once via an atomic claim so a partial-write can't double-send it. Cap-exempt.

  • Visible tuning affordance on `/settings`.

    The heartbeat card now shows the first 280 characters of your current instructions inline (with a "Show full" toggle) and tells you how to change them: "Tell Selah in chat to tune this." No more accordion hiding the most important signal that the thing is editable.

Fixed

  • Post-devotional cooldown actually fires again.

    The 4-hour quiet window added in 0.15.0 was dying silently on every cron run for users who had ever saved or received a devotional entry. A raw SQL GREATEST(saved_at, delivered_web_at, delivered_telegram_at) was typed as Date but came back as a string from the Neon HTTP driver — the cooldown check called .getTime() on it and threw TypeError, which the per-user try/catch swallowed into observability. End result: users who just finished a devotional could still get a study-notes nudge 35 min later, which was the original bug 0.15.0 was supposed to fix. Now coerced to Date at the boundary (toDateOrNull helper) with 7 regression tests covering ISO-8601, the Neon timestamptz shape ("2026-04-24 12:00:00+00"), epoch millis, passthrough, null, unparseable, and unsupported types. Sentry issue SELAH-SENTRY-B.

Changed

  • Parser rejects off-contract responses.

    The old parser truncated any tag to 40 chars and let it through, which meant Haiku could drift from the intended taxonomy without anyone noticing. Now tags not on the allowlist get skipped (logged to summary.skippedUnknownType), and meta tags ([intro], [tune], [weekly_reflection]) can only come from code-gated delivery paths, never from the LLM output.

  • Prayer titles are wrapped and length-capped when they enter the system prompt.

    Titles are now truncated to 120 characters and wrapped in per-title <user_prayer id="...">...</user_prayer> delimiters, both in the new formation-context section and in the existing ACTIVE PRAYERS section. Closes the prompt-injection surface where a prayer titled "</user_content><system>IGNORE PREVIOUS..." could have broken out of the user-content wrapper.

  • Default heartbeat instructions upgraded for every user who was on the seeded default.

    Existing users who customized their instructions (via update_heartbeat_config in Telegram) are untouched. Classification is tracked in a new heartbeat_instructions_source column ('seeded' | 'customized') so future default rotations don't have to rely on fragile exact-string matching — a migration can just target WHERE source = 'seeded'.

April 23, 2026

v0.13.0 → v0.14.2New

Admins can nudge stuck users.

Fixed

  • Admin dashboard stays up even when a migration is late.

    The analytics endpoint used to crash with a 500 whenever a referenced table wasn't there yet, taking down the whole dashboard. Now the affected card reads zero-state and self-hides; every other metric still renders. Same treatment for the nudge "send" button — if the log table is missing, the email still goes out and you get a success response, with a loud warning logged so the gap gets noticed and fixed.

  • Admin dashboard analytics works again.

    GET /api/admin/analytics was throwing NeonDbError because a migration that was supposed to create the retention_email_sends table silently never ran. The admin Overview nudge effectiveness card and the Analytics tab's cohort sparkline depended on it, so both were broken until this patch. Fixed end-to-end.

  • The stuck-user nudge email's "Set up Telegram" button now opens the right page.

    Previously it linked to /settings?focus=telegram, which isn't a real route — users landed on the generic settings page and had to hunt for Telegram manually. Now it opens /settings/telegram directly, and if you're not signed in, you're bounced through sign-in and returned to that exact page after login.

  • The Back button on Settings (desktop) goes to home every time.

    Before, it used browser history, which was unreliable — depending on how you arrived at Settings, it could drop you on the sign-in page (which immediately redirects back into Settings), leaving you stuck in a loop. Now "Back" just means "leave Settings," which is what the button label says.

  • Invite codes actually show as claimed now.

    Before, every user who signed up and hit /stream fast enough left their invite code looking unclaimed in the admin dashboard, even though signup worked fine. A race between our user-row fallback and the Clerk webhook meant invite consumption was silently skipped. Fixed, and backfilled the orphaned history so the admin view is accurate end to end.

  • Admins can see who claimed each invite code.

    The Invite Codes tab shows a → Name link next to each claimed row, so you can tell at a glance which code belongs to which user without drilling in.

  • Notes stop losing your last 800ms of typing on fast nav.

    If you typed something and hit N to create a new note before the debounced save fired, the debounced PATCH is now flushed with keepalive: true on unmount. Nothing drops.

  • The "Pull in note" picker doesn't re-fetch every time anymore, and won't cross-populate between notes.

    Per-mount cache plus AbortController on rapid nav.

Added

  • Admins can nudge stuck users.

    In the admin Users tab there's a new mail-icon button per user. Clicking it sends a warm, manually-triggered email that pitches the Telegram companion + daily devotional with one CTA and leaves a reply loop open so you learn what's in their way. Guarded so it won't send to anyone who already has Telegram linked.

  • Double-send guard on nudges.

    If you've already nudged someone in the last 14 days, the admin tells you up front ("Last nudge sent 3 days ago") and requires an explicit override to send again. No more accidental double-taps.

  • Nudge effectiveness at a glance.

    The Overview tab now shows "X% linked Telegram after nudge" with the raw numbers as soon as you've sent at least one. Tells you whether the email actually moves the needle.

  • Telegram activation trendline.

    The Analytics tab has a new 8-week sparkline showing the share of each signup cohort that's linked Telegram. Latest cohort highlighted, with an up/down arrow vs the prior cohort so you can read the trend in a glance.

  • Faster page loads.

    Inter and Lora fonts are now self-hosted via next/font/google instead of fetched from Google on every cold load. LCP drops by roughly 100-300ms depending on network.

  • Cleaner landing page.

    The "Join the waitlist" button is now the primary filled CTA on hero and footer, and "I have an invite code" drops to outlined secondary, matching the roughly 95/5 split of who actually has a code. A one-line clarifier ("We'll email you when a spot opens. One email.") kills the implicit newsletter objection.

  • The "How it works" section on the homepage now has images.

    Each step — Capture, Study, and Share — shows a visual so you can see what Selah looks like before you sign up.

April 22, 2026

v0.12.0 → v0.12.1New

A changelog page.

Added

  • You can ask for today's devotional anytime, on any surface.

    On Telegram, the companion pushes it straight into the chat. On web, it surfaces a preview with a link to the full reading. No more "head to the app" dead-ends.

  • Migrations apply automatically on production deploys.

    New database changes run as part of the Vercel build — no more copy-pasting SQL into Neon by hand, no more forgetting.

  • A changelog page.

    Visit [selah.so/changelog](https://selah.so/changelog) anytime to see what's shipped, in plain English. Bookmark it to follow along.

  • Sliding settings sidebar

    with a dedicated page for devotional settings. The menu now slides between groups instead of jumping between pages, and your devotional timing, timezone, and theme all live together in one place.

  • The companion knows your week's devotional theme.

    Ask "what's this week's theme?" and it answers directly instead of saying it can't see that.

  • Instant Telegram delivery after a theme switch.

    Say "now" when changing themes and the fresh devotional lands in your Telegram chat right away — no waiting until tomorrow's scheduled time.

Fixed

  • Switching themes mid-week now actually works end-to-end.

    Before, if a cron-written entry existed under the old theme, the companion would keep serving it even after a pivot. Now the old entry is cleared on confirm and a fresh one is written under the new theme on next fetch.

  • The companion no longer describes two devotional themes as "running alongside."

    It used to rationalize stale chat history by inventing a parallel arc. Now it treats the DB as the single source of truth and the current week has exactly one theme, period.

  • Note reformat retries instead of giving up.

    If Claude returns an empty response (rare, but it happens), the reformat tries once more with an explicit nudge before surfacing a "try again" message. No more blank modals.

  • Switching themes mid-week now gives you the right content.

    If today's entry was already written under your old theme, changing themes replaces it with a fresh entry for the new one. Before, you could end up reading a devotional about the old topic even after a successful switch.

  • The changelog page shows cleaner dates.

    Timestamps at [selah.so/changelog](https://selah.so/changelog) now read "today", "yesterday", or "3 days ago" instead of "17 hours ago" — more honest since entries are dated by day, not by hour.

  • Finishing a prep interview is more reliable.

    Saying "done", "wrap up", or "finish the prep" now saves your note every time, and the Enrich/Format card shows up when you expect it.

  • The companion is more honest about what it did.

    It won't claim to finish a task it didn't actually complete.

  • Error tracking is working correctly again.

    A setting was blocking our internal tools from seeing what's happening in the app, which meant we were slower to spot bugs. Fixed.

April 21, 2026

v0.10.0New

If a theme isn't working, switch it.

Change your week's theme anytime

  • If a theme isn't working, switch it.

    Ask the companion to pivot and it'll suggest a new direction. Say yes, and it writes fresh entries for the rest of the week around the new theme. Nothing you've already written disappears.

  • The companion asks before it changes anything.

    It proposes the new theme first and waits for your "yes" before applying it.

  • Works on web and Telegram

    through the same flow.

Fixed

  • No more blank crash screens.

    If something goes wrong, you'll see a helpful message with a way back, not a white page.

  • Signing in takes you to where you were going.

    Before, it dropped you on the home page every time.

  • Our bug-tracking tools are working again.

    That means we can catch and fix problems faster.

April 20, 2026

v0.9.0New

If you email us for support, we can now see where things went wrong

Faster help when something breaks

  • If you email us for support, we can now see where things went wrong

    — did your devotional deliver, did Telegram connect, did your notes save. We see status signals, not your content. This lets us fix problems faster without having to ask you a bunch of questions first.

  • Better view of signup health.

    Helps us spot when something's broken for new users before they have to tell us.

Fixed

  • Daily devotionals arrive on time again.

    A bug was stopping delivery for some users. They're coming through now.

  • Analytics and error tracking are working.

    A setting was blocking our tools from seeing what's happening in the app. Fixed.

April 19, 2026

v0.8.1

The companion thinks longer before it answers.

Smarter companion

  • The companion thinks longer before it answers.

    Especially during prep interviews. Its answers are more thoughtful and less likely to be wrong.

  • It remembers you better.

    The companion learns about you quietly in the background. It's better at picking up what matters and skipping what doesn't.

  • Reminders sound more natural.

    The companion's nudge messages used to always sound like questions. Now they can be statements when that fits better — and they don't repeat as often.

April 18, 2026

v0.8.0New

The companion lives on every page on tablets.

Tablet companion

  • The companion lives on every page on tablets.

    Before, you had to go to a specific screen. Now it follows you around the app.

  • See changes live.

    When the companion edits a note while you're looking at it, the changes appear right away. No refresh.

  • Clean change cards.

    When the companion edits something from your chat, you see a tidy "View changes" card instead of a wall of text.

Settings redesigned

  • Settings are organized now.

    Eleven sections with a side menu. Finding what you're looking for takes one click instead of scrolling through everything.

  • Cleaner look.

    No more double borders or awkward spacing.

Fixed

  • The `/` menu shows up in the right place

    when you're typing in a long, scrolled note. Before, it jumped to the top of the page.

  • Telegram devotionals and reminders

    work again for users on Telegram only. A bug was blocking them.

April 17, 2026

v0.6.0 → v0.7.0New

Edit your notes by talking to the companion.

Conversational note editing

  • Edit your notes by talking to the companion.

    Ask it to "add a point about Romans 8 to my sermon prep note" or "tighten up the intro" and it actually does it. Works from the web companion and from Telegram.

  • List your notes from Telegram.

    Send /notes in the bot and you get a browsable list. Tap one to open a thread where every message you send gets appended to that note. Great for capturing thoughts on the go without opening the app.

  • Undo any AI edit.

    When the companion or Telegram modifies a note, an Undo button appears at the top of the note page with a diff summary ("Added 2 paragraphs to Introduction · from Companion"). One tap reverts the change. Nothing is permanent unless you want it to be.

  • Stale-version banner.

    If you have a note open in the web editor and Telegram edits it underneath you, we show a banner with a Refresh button so you don't accidentally overwrite each other's work.

  • New `note_edits` ledger.

    Every AI edit gets logged with before/after content, source surface (web or Telegram), and a plain-English diff summary. Foundation for the fuller history panel we're planning.

Fixed

  • Onboarding + notes no longer 500 for users with stale email rows.

    If a Clerk user's email matched a pre-existing user row with a different id (legacy Neon-auth leftover), the fallback insert silently no-op'd and every downstream foreign-key insert (user_onboarding, notes) blew up. Now we detect the collision explicitly and throw a clear error pointing at the migration script.

  • `src/app/api/telegram/webhook/route.

    ts` — voice path no longer sends the 👀 reaction twice (one Telegram API call saved per voice message)

  • 18 new tests for the transcription helper + 1 for the file-download guard (40 added across both files)

Added

  • `src/lib/note-edit-helpers.

    ts` — diff summary generation, section-level updates, append/replace helpers shared by companion + Telegram

  • `src/lib/db/schema.

    ts — new note_edits` table: userId, noteId, sourceSurface, contentBefore, contentAfter, diffSummary, revertedAt

  • `src/lib/companion-tools.

    tsappend_to_note, update_note_section, revert_last_edit` tools for the companion pipeline

  • `src/app/notes/[id]/page.

    tsx` — undo button, stale-version banner, polling for concurrent edits

  • `src/app/api/notes/[id]/undo/route.

    ts` — GET latest un-reverted edit, POST to revert

  • `src/app/api/telegram/webhook/route.

    ts/notes` command, inline-keyboard note picker, append-mode callback routing, undo callback

  • `src/app/api/debug/whoami/route.

    ts` — temporary auth diagnostic endpoint (to be removed after dev stabilizes)

  • `src/lib/transcription.

    ts — Whisper API wrapper, raw-fetch (no openai SDK), discriminated TranscribeResult`, exhaustive failure-reason mapping

  • `src/lib/telegram.

    tsdownloadTelegramFile(fileId) for two-step getFile` → file fetch

  • `src/app/api/telegram/webhook/route.

    ts — voice/audio dispatch in handleMessage, transcribeIncomingVoice helper, 🎙️` transcript confirmation message

Changed

  • `src/lib/auth-session.

    tsensureUserInDb now detects email collisions against stale user rows and surfaces a descriptive error instead of silently no-opping via .onConflictDoNothing()`

  • `src/proxy.

    ts/api/debug/* added to public route patterns (Next 16 private-folder _debug` convention forced the rename)

Voice notes on Telegram

  • Send voice messages to your companion on Telegram.

    Tap-and-hold the mic in Telegram, talk, release. The companion downloads the voice note, transcribes it via OpenAI Whisper, echoes the transcript back so you can verify (🎙️ "your words"), then routes it through the same companion pipeline as a typed message. Captures, prayers, slash commands — everything works.

  • Audio uploads work too.

    Forward an audio file from another chat and it gets transcribed the same way.

  • Friendly failure modes.

    Voice notes that are empty, too long (>10 min), or fail transcription get a clear message ("I had trouble transcribing that — try again or send text") instead of silent dropping.

  • No new env vars.

    Reuses the existing OPENAI_API_KEY (already used for embeddings).

April 16, 2026

v0.5.0New

The companion now reaches out to you.

Heartbeat Companion Nudges + Nightly Learning Loop

  • The companion now reaches out to you.

    Every 15 minutes, a Vercel Cron evaluates your recent notes, prayers, and captures with Claude Haiku. If there's something worth surfacing — a stale note, a forgotten prayer, a connection to the week's devotional theme — it sends you a Telegram message. Feels like a thoughtful friend, not a notification bot.

  • Smart nudge timing.

    You control active hours (default 8am–10pm) in Settings. Nudges respect a daily cap of 2 so they stay meaningful. Overnight windows work correctly — set 10pm–6am if you want late-night prompts.

  • Nudges that don't repeat.

    The system reads the last 7 days of nudges before asking the LLM to generate a new one. If you've already been reminded about Romans 8 three times this week, it won't ask again.

  • Heartbeat settings in the web app.

    The Settings page now has a Proactive Check-ins card. Toggle nudges on/off, set your active hours, and write custom instructions for the companion (e.g., "Only nudge me about Study-stage notes" or "Focus on prayer when I haven't prayed in 3 days").

  • Nightly companion learning loop.

    Every night at 2am, the companion reviews the past 24 hours of your activity — notes edited, captures saved, prayers engaged — and updates its understanding of you. Five facts about your patterns and interests stay current. Your companion profile is regenerated from those facts so every conversation starts with fresh context.

  • Activity-aware learning.

    The learning loop uses Haiku to reason over your recent activity digest. It can add new facts, update existing ones, and remove stale ones — so the companion's knowledge of you actually evolves rather than accumulating noise.

  • Telegram formatting fixed.

    Companion responses now render bold, italic, inline code, and links correctly in Telegram (HTML mode). This was a regression introduced in the prior release and is now fully restored.

Added

  • `src/lib/heartbeat.

    ts — context assembly, LLM evaluation, parseHeartbeatResponse, buildHeartbeatSystemPrompt`

  • `src/app/api/cron/heartbeat/route.

    ts — 15-minute Vercel Cron (GET), isWithinActiveHours, isNudgeCapReached`

  • `src/app/api/cron/companion-learn/route.

    ts` — nightly learning cron (GET), activity digest, fact maintenance

  • `src/app/api/heartbeat-preferences/route.

    ts` — GET/PUT/PATCH heartbeat preferences

  • `src/app/settings/heartbeat-card.

    tsx` — Proactive Check-ins settings card

  • `src/lib/companion-learning.

    tsbuildActivityDigest, runLearningLoop`, fact CRUD helpers

  • `src/lib/telegram.

    tssendHeartbeatNudge, markdownToTelegramHtml` (restored)

  • `drizzle/0015_heartbeat.

    sqlheartbeat_nudges table + companion_preferences` heartbeat columns

  • `drizzle/0016_companion_learning.

    sqltopFacts column on companion_preferences`

  • 5 new test files: 432 tests total (up from ~370)

April 15, 2026

v0.3.0 → v0.4.0New

Interview notes now save as full, editable study documents.

Full Interview Notes + Cross-Surface Session Navigation

  • Interview notes now save as full, editable study documents.

    When you say "save this" on Telegram or in the web companion at the end of an interview, the companion captures everything: the theological arc of the conversation (as a pull quote), all your significant insights (no 3-6 limit, no truncation), scripture references with context, your most powerful verbatim quotes, and any open questions to explore later. The saved note opens as a rich, editable TipTap document — not a read-only summary. Old notes keep working through a backward-compat read path.

  • Tap "View Note" from Telegram.

    After saving an interview, prep, or general note from Telegram, the companion now includes an inline "View Note" button that deep-links straight to the editable note in the web app. No more "I can't edit notes" confusion.

  • `/sessions` on Telegram.

    See your recent conversations across both web and Telegram with one command. Tap any session to jump to it on the web. Same agent, multiple surfaces — the session is unified.

  • "History" button on the web companion.

    The clock icon now has a visible "History" label so you can actually find the session drawer. The drawer itself already listed topics + dates; now new users know it exists.

  • Deep-link into any past session.

    Navigate to /companion?sessionId=X and the companion loads that conversation directly. If the session doesn't exist (typo, deleted, stale Telegram link), you get a clear error banner — "Couldn't find that conversation. Started a new chat." — not a silent empty chat.

  • Notes link back to their source conversation.

    The "View companion interview" button on an interview note now routes through the unified session URL, so you can jump from the saved note back to the conversation that produced it, continue thinking, and save again.

  • Telegram companion loop crash fixed.

    markdownToTiptap(undefined) no longer throws — empty input returns a valid empty-paragraph doc. parseLLMJson now recovers when the LLM wraps JSON output in prose. Both fixed the "Something went wrong" errors that were locking users out of their own conversations.

  • System prompt truth-up.

    The companion no longer believes falsehoods about its own capabilities. It knows notes are editable at /notes/[id], it knows it can save verbatim quoted content, and it knows to capture all insights without truncating for a 3-6 bullet limit.

  • Data integrity: `openQuestions` field drop fixed.

    Interview notes stored questions under the wrong field name, which caused every open-question section to render blank. Fixed with a dual-field read in the notes editor and the embeddings backfill cron — old notes now display their questions correctly, and re-embeddings don't silently lose questions text.

Prayer-Aware Companion

  • `/prayers` — your prayer board in one tap.

    Send /prayers in Telegram to see all your active, ongoing, and waiting prayers grouped by status. Each prayer gets inline [Answered] / [Waiting] / [Ongoing] buttons. Tapping a button updates the status in-place — the message edits itself and the buttons disappear so you can't accidentally retap.

  • `/note [text]` — save a note directly from Telegram.

    Send /note Romans 5:3 — suffering produces perseverance and it goes straight to your notes library with an auto-title and a deep link back to the note in the app.

  • Companion knows your prayer board.

    Every conversation now includes your most recent non-answered prayers as context. When you say "God answered my prayer about the job offer," the companion understands what you mean and can call update_prayer_status to mark it answered. It won't guess UUIDs — if it's unsure which prayer you mean, it asks by title.

  • Three new companion tools:

    read_prayers (filtered board lookup), update_prayer_status (mark answered/waiting/ongoing with an optional note), create_note (save a theological insight or study reflection directly from conversation).

  • Bug fix:

    /start, /help, /recent, /profile, /prayers, and /note no longer send a redundant 👀 acknowledgment reaction — the reaction from the message handler is sufficient.

April 14, 2026

v0.2.0New

End-to-end devotional pipeline.

Adaptive Daily Devotional System

  • End-to-end devotional pipeline.

    Users receive a fresh scripture-based devotional every day at their chosen local hour, delivered via Telegram and/or surfaced in the companion chat. The system is week-aware: Monday opens a theme, Friday closes with reflection, mid-week entries develop it.

  • `devotional_weeks` + `devotional_entries` tables

    (migration 0011) — week records track theme, proposedNextTheme, and week-end reflection; entry records carry all rendered fields (dayRole, scriptureRef, scriptureText, opening, reflection, prayerPrompt, question) plus Telegram delivery metadata.

  • `src/lib/devotional.ts`

    ensureTodaysDevotional is the core coordinator: claim a pending slot, call the role-specific LLM tool (theme_open / reflection_close / middle), write the result. Idempotent — concurrent callers compete for a pending row; only the first writer wins. LLM output truncated via v100()/txt() helpers before every DB write. tool_choice: { type: "tool", name } forces the correct role-specific tool to fire.

  • `POST /api/cron/devotional`

    — hourly Vercel cron that sweeps stale pending entries (> 10 min old), finds users at their delivery hour, generates entries, and sends to Telegram. Midnight hour normalized (% 24) for V8 Intl.DateTimeFormat quirk. Query capped at 500 users per run with a log warning when the limit is hit.

  • `POST /api/cron/devotional-extract`

    — nightly cron that extracts week-level reflection from completed entries and proposes next week's theme.

  • `GET /api/devotional`

    — returns today's devotional for the authenticated user (generating on first request).

  • `PATCH /api/devotional-preferences`

    — saves timezone, delivery hour, and devotional_enabled flag. IANA timezone validated via Intl.DateTimeFormat; isValidIanaZone exported for testability.

  • DevotionalMessage UI

    (src/components/companion/DevotionalMessage.tsx) — inline companion card rendering scripture reference, opening, reflection, prayer prompt, and reflection question with gold-tinted scripture styling per DESIGN.md.

  • DevotionalCard settings

    (src/components/settings/DevotionalCard.tsx) — timezone picker (20 common zones), hourly delivery selector, enable toggle, "Send now" preview button.

  • Daily Rhythm onboarding step

    — new step 4 in the onboarding flow introducing the devotional, with a scripted companion demo that walks through the companion philosophy using pre-scripted message pairs.

  • Notes page badge

    devotional note type now renders a gold "Devotional" badge in the notes list.

  • `isDevotionalStructured` type guard

    — replaces a blind cast in the companion page; validates dayRole shape before rendering the devotional card inline.

  • Telegram delivery

    sendDevotional renders devotionals as clean Markdown messages; atomic update sets deliveredTelegramAt only when IS NULL to prevent double-sends.

  • 15 new pure-function tests

    (269 total) — chunkMessage, verifyWebhookSecret, isValidIanaZone with full branch coverage.

  • Four adversarial-review fixes:

    midnight normalization, scale cap log warning, reflection_close idempotency guard, handleConnect single body parse.

New user discovers the bot → signup → back to Telegram.

Telegram Signup (Phase 1)

  • New user discovers the bot → signup → back to Telegram.

    Previously, a Telegram user with no Selah account hit a dead end: the bot sent them to /settings/telegram (7 steps to actually get connected). Now the bot creates a one-time signup invite, sends a single "Sign up to Selah" button, the website binds the chat on signup, and the user lands back in Telegram with the bot already greeting them.

  • `telegram_signup_invites` table

    (migration 0010) — 32-byte url-safe random token, 24h TTL, single-use, tracks chatId + Telegram username/first name. Inverse direction of the existing telegram_link_codes flow (website → bot).

  • `src/lib/telegram-signup.ts`

    createSignupInvite, findOpenInviteForChat, findSignupInvite, claimSignupInvite, pushTelegramWelcomeIfEligible, buildWelcomeMessage. The claim function handles happy path, invalid/expired/consumed tokens, and cross-user guard with idempotent self-reclaim.

  • `POST /api/telegram/claim`

    — auth-required. Body { token }. Binds the chat to the authenticated user and returns botDeepLink from TELEGRAM_BOT_USERNAME. Maps claim errors to 400 (invalid/expired/consumed) and 409 (chat_linked_to_another_user).

  • Webhook unlinked-user branch

    (src/app/api/telegram/webhook/route.ts) — replaced the dead-end "go to settings" message with a personalized welcome + "Sign up to Selah" button. Reuses an existing open invite if the user re-messages instead of creating a fresh row each time.

  • Sign-up + sign-in pages

    (src/app/sign-up/page.tsx, src/app/sign-in/page.tsx) — read ?via=telegram&t=TOKEN on mount, stash the token in sessionStorage, show a "Signing up from Telegram" banner. After successful auth, call /api/telegram/claim immediately. Sign-up routes to /onboarding?via=telegram; sign-in (already-onboarded users) redirects straight to the bot via window.location. Wrapped in Suspense for useSearchParams() per Next.js 16.

  • Onboarding flow

    (src/app/onboarding/onboarding-flow.tsx) — detects via=telegram from the URL, hides the "How did you find Selah?" question, forces signup_source = "telegram" in the PATCH (including on Skip), and swaps the step 3 CTA from "Enter Selah" to "Open Telegram." On completion, reads telegramBotDeepLink from the response and redirects via window.location.

  • `/api/onboarding` PATCH

    now returns telegramBotDeepLink when signup_source === "telegram" and TELEGRAM_BOT_USERNAME is set. Also triggers pushTelegramWelcomeIfEligible on the first completion transition (gated behind !before.completed). Non-fatal if the push fails.

  • Welcome push

    — 3-tier context-aware greeting: anchors on first capture content if saved, else on current focus, else falls back to a generic "share a thought" prompt. All under 2 sentences per DESIGN.md's Telegram response rules. No emoji in message text (DESIGN.md rule).

  • Memory fact seeding

    remains unchanged: signup_source = "telegram" is analytics, not memory, so it isn't written to memory_facts.

  • Claim-immediately-after-signup architecture

    — the chat → user link is established before onboarding begins. If the user abandons mid-onboarding, they can return to Telegram and keep using the bot; onboarding resumes on their next web visit.

  • Tests (38 new, 218 total):

    20 helper tests (telegram-signup.test.ts), 11 claim-route tests (telegram-claim-route.test.ts), plus updates to the onboarding-route suite covering the welcome-push gate and the bot deep link response shape.

Onboarding — Companion Context

  • Step 1 redesigned as a single dense screen

    — role (required-ish) plus four optional companion-context questions: Bible translation, what they're studying right now, theological tradition, and how they found Selah. All optional fields can be skipped with one button.

  • Translation preference

    — 9-option pill row (ESV, NIV, NLT, KJV, NASB, CSB, NRSV, MSG, Other), defaulted to ESV. Stored on user_onboarding.translation.

  • Tradition

    — 11-option pill row (Reformed, Wesleyan, Pentecostal, Baptist, Anglican, Lutheran, Catholic, Orthodox, Non-denominational, Still exploring, Other). Framed sensitively: "so we don't push contradictory stuff." Stored on user_onboarding.tradition.

  • Current focus

    — single-line text input. "What are you studying right now?" → free text up to 500 chars. The single biggest unlock for first-session value.

  • Signup attribution

    — "How did you find Selah?" pill row (Friend, Social, Search, Blog/podcast, Other). Stored on user_onboarding.signup_source. Analytics-only, NOT memory.

  • Memory fact seeding on completion

    — when a user finishes onboarding, role/translation/tradition/currentFocus are written into memory_facts (category: life_context / preference / theology, confidence 0.95, sourceType manual). The companion sees these from message #1 instead of cold-starting from zero. Gated so re-entry doesn't double-seed; non-fatal if seeding fails.

  • `PillRow` reusable component

    inside the onboarding flow with proper radiogroup/radio ARIA roles, 44px min touch targets, sage active state.

  • Migration `0009_user_onboarding_context.sql`

    — additive ALTER TABLE for the four new columns. Idempotent.

  • 30 new tests added (180 total passing)

    — helper coverage for the new fields, EAV mapping in seedMemoryFactsFromOnboarding, route validation for every new field's enum + bounds, the seeding gate (fires once, no re-fire on re-entry), and the non-fatal error path.

Signup + Onboarding

  • Dedicated `/sign-up` page

    — New optimized signup form replaces the inline toggle on /sign-in. Name is optional. Password has a show/hide toggle. Clear value prop, trust microcopy ("Free. No credit card. Takes 30 seconds."), and friendly error states.

  • Sign-in focused

    /sign-in is now sign-in only with a clear link to /sign-up for new users. Matches signup-flow-cro best practices: one page, one job.

  • New user onboarding flow

    /onboarding is a 3-step guided experience new users hit immediately after signup:

    1. Welcome + role — Pick how you use scripture (pastor, small group leader, student, personal). Skippable. Feeds companion personalization later.
    2. First capture (aha moment) — Guided textarea with an example placeholder. Saves a real stream capture so the user sees their Home populated immediately. Supports Cmd/Ctrl+Enter to submit.
    3. You're ready — Warm recap of what Selah can do (capture, companion, notes, prayer). Single CTA: "Enter Selah."
  • Onboarding state in DB

    — New user_onboarding table tracks role, first capture, and completed_at. Home page redirects any user with completed_at IS NULL to /onboarding, so returning users who bailed mid-flow resume where they left off.

  • `/api/onboarding` route

    GET reads status (creates row lazily), PATCH updates role, saves first capture, or marks complete. All fields optional so the client can update progressively.

  • Proxy matcher update

    /sign-up is now excluded from Neon Auth proxy alongside /sign-in so unauthenticated visitors can reach it.

April 13, 2026

v0.2.3

Upload a profile photo

Profile

  • Upload a profile photo

    — New photo section at the top of Settings → Public profile. Pick an image and it's resized, cropped to a square, and saved automatically. Change or remove anytime. JPG, PNG, and WebP welcome.

  • Branded default avatar

    — Accounts without a photo now show a warm soft-gold mark with a sage circle in the middle, matching the design system. Same mark on shared notes, the settings page, and anywhere the avatar appears.

  • Avatar on the settings page

    — Your avatar now sits beside your name and email in the Account card, and beside the Public profile link so it's obvious where to change it.

  • Consistent across surfaces

    — Shared note pages, settings, and the profile editor all use the same Avatar component, so the default and uploaded states look identical everywhere.

April 11, 2026

v0.2.0 → v0.2.2New

Tables in the editor

Knowledge Graph

  • Editable concept summaries

    — Click any summary on a concept's detail page to edit it inline. Click outside to auto-save. Write your own or hit the sparkle button to generate one with AI instantly (no waiting for background jobs).

  • "Generate Summary" button

    — One click to create a summary from your linked notes, captures, and teachings using AI. Available on concepts with no summary and inside the editor. 300 character limit keeps summaries tight.

  • Fixed stuck "updating" concepts

    — Concepts showing "updating" forever are now fixed. The background summarizer was being starved by the extraction pipeline. Summaries now process first, with a time budget that drains the full queue.

  • Smarter stale detection

    — The companion no longer mass-flags short-named concepts like "God" or "Sin" for summary refresh. Stale matching uses in-memory lookup instead of per-fact database queries.

  • Scripture parsing fix

    — "1 John 4:8", "2 John", and "3 John" references now parse correctly (trailing space in the regex key was eating the chapter separator).

Prayer Board

  • Inline-editable titles

    — Click any prayer title to edit it in place. Auto-sizing textarea preserves line wrapping. Enter saves, Escape cancels, blur saves. Optimistic updates with rollback.

  • Cleaner card layout

    — "Move to" buttons and delete icon collapse behind hover on desktop, always visible on mobile. Trash icon moved to top-right corner. Cards at rest show just the title and timestamp.

  • Loading skeleton

    — Card-shaped placeholders while prayers load instead of a blank board.

  • Keyboard shortcut hint

    N badge next to "Add Prayer" button on desktop.

  • Serif page heading

    — "Prayer Board" now uses Cormorant Garamond per the design system.

  • API: title updates

    — PATCH endpoint now supports updating prayer titles alongside status changes.

Design System

  • Added **Keyboard Shortcut Hints** pattern to DESIGN.

    md (styling, placement, rules).

  • Added **Loading Skeletons** pattern to DESIGN.

    md (card skeletons, anti-spinner rule).

  • New decisions logged: hover-only card actions, shortcut hints, skeleton convention.

Notes

  • Tables in the editor

    — Type /table to insert a 3x3 table with a header row. Columns are resizable by dragging. Tables styled to match the warm journal aesthetic (sage selection highlights, warm-white headers).

  • Paste markdown, get formatted content

    — Paste a markdown table, heading, or list into the editor and it auto-converts to rich text. No more raw | pipes or asterisks.

  • Selection-based cleanup

    — Select text in a note and click the sparkle (✦) in the floating toolbar to format just that section with AI. No selection = format the whole document (as before). Long notes no longer lose content during cleanup.

  • Slash commands fixed

    — The / menu now appears reliably when you type / at the start of a line.

Companion

  • Formatted interview transcripts

    — AI and user messages in companion interviews now render bold, italic, lists, headings, blockquotes, and tables instead of showing raw markdown like this.

Fixes

  • Reformat no longer truncates notes over 8K characters (raised to 25K with clear error for very long notes).
  • Reformat errors now show in the UI instead of silently failing.
  • Table CSS aligned to design system (4px grid spacing, `tabular-nums`, accessible `scope="col"` headers).
  • Defensive HTML escaping in companion transcript rendering.

April 10, 2026

v0.1.0New

`/prep` command

Companion

  • `/prep` command

    — Type /prep [topic] to start a Socratic interview for sermon, Bible study, or devotional prep. The AI interviews you (8+ exchanges before it lets you build), then formats your words into a structured teaching note with inline enrichment tags ([Historical], [Greek/Hebrew], [Cross-ref], [Cultural], [Illustration]). Your voice stays central. Saved as a note you can edit in the Tiptap editor.

  • Backend-driven session mode

    — The companion tracks what mode you're in (prep, interview, pray) server-side. No more frontend guessing.

  • Structural tool gating

    — The AI can't skip the interview. The save_prep tool is withheld until you've had enough exchanges. When you say "done," the AI is forced to call the tool instead of just saying "Building now."

  • Reading level matching

    — Prep output matches your vocabulary and tone. If you write simply, the note reads simply.

  • Full-page build animation

    — When the AI builds your prep note, a loading overlay shows progressive status messages instead of a generic spinner.

  • Socratic interview mode

    — Deep-dive conversations with pull-quote transcript UI.

  • Capture and note attachments

    — Attach your stream captures and notes to companion messages as context.

  • Session persistence

    — Leave and come back. Your conversation picks up where you left off.

  • `/pray`, `/interview`, `/help` commands

    — Quick-access slash commands for common actions.

Stream

  • Scripture auto-detection with expandable pills.
  • Chronological feed with timestamps.
  • Promote stream entries to notes (new or append to existing).

Notes

  • Tiptap rich text editor with slash commands (`/` menu: headings, lists, quote, divider).
  • Selection toolbar (floating: bold, italic, highlight, headings, list, quote).
  • Soft-gold text highlighting.
  • Properties drawer with stage stepper (Capture → Study → Finished) and type tags.
  • Auto-save with 800ms debounce.
  • Filter tabs: All, Capture, Studying, Finished, Threads, Teaching, Prep.
  • Scripture block extension (insertable via `/` menu).

Prayer Board

  • Kanban columns: Active, Waiting, Answered, Ongoing.
  • Drag-and-drop between columns.

Knowledge Graph

  • Auto-extraction pipeline: concepts, edges, and relationships from your notes and captures.
  • Knowledge dashboard (`/knowledge`) with type filters and manual sync.
  • Concept detail pages with delete and merge UI.
  • Auto-generated concept summaries.

Search

  • Postgres full-text search with GIN indexes.
  • Global search bar in sidebar.

Import

  • Import from Markdown, TXT, CSV, DOCX, and PDF files.
  • Proper markdown-to-Tiptap conversion (headings, lists, bold, etc.

    ).

Auth

  • Neon Auth (managed Better Auth) with middleware route protection.
  • Sign in/sign up page.