Gate 1 prototype · Digital Receptionist · interface only, no new backend · October 5, 2026

An interface change. No new backend.

This is a re-layout of what the Digital Receptionist already does, and it adds no backend. Seth reviewed the first version and was right: it had grown into new features and leaned on a phone system we do not have. Every rebuild since was checked against the receptionist worker on main, and four rounds by independent reviewers who had seen none of the earlier notes. Whatever the worker cannot back was removed or relabeled, and what is left for the build to handle is listed below. Open it. These pages are unlisted: search engines skip them, but anyone with a link can open them.

What Seth flagged, and what this does about it

Seth: "You realize the digital receptionist changes are pretty large in scope? I was expecting an interface change but these are pretty serious... our system isn't a calling-out platform and you are creating functionality that we don't have. The call back stuff isn't there. How did you plan on making calls?"

He is right on every point. The first version turned "please call me back" into a Call back button, a done-tracker and a work queue, as if the platform dialed out. Seth confirmed we are not a calling-out platform, so all of it is gone. The one phone action left is Take over on a call that is happening right now, which is the existing warm transfer of a live inbound call to your transfer number. It does not dial a customer.

The product, honestly

Rippler answers your inbound phone. Two tabs, because there are two jobs: read what it handled, and configure it.

What it does (all live today)

  • The log of inbound calls, with the shipped filters (Status, Urgency, On or after, Include spam) and paging, each call with the caller's first words, how it was handled, and what Rippler captured, on the calls where it captured something
  • A call record: transcript, recording, its Outcome, and the caller looked up in the CRM by phone
  • Answer a question Rippler could not, which publishes it so Rippler answers it next time
  • Approve or reject what the AI proposes, from the shipped Agent activity approval list
  • Take over a call that is live right now (a warm transfer to your transfer number)
  • Settings: your number, who answers when and business hours, voice and special instructions and what Rippler does on a call, what Rippler knows (with New article), how Rippler handles calls (with New skill), and health checks

What it does not do

  • Dial a caller back or keep a callback list. The worker's only outbound calls are Test a call (it rings the number typed into its dialog, or your profile phone if blank) and the setup call (your profile phone), and nothing redrawn here places a call
  • Track callbacks as a to-do queue with a "Done" state
  • Book appointments, text callers, or change a contact from a call. The four capability rows for those are shown locked, as the shipped page shows them
  • Create a CRM lead, contact or activity from a call. A call marked Lead is a flag on the call plus a New Lead notification to the owner; the only link to the CRM runs one way, when the worker looks the caller up by phone
  • Write a summary of a call (the worker stores the caller's first words)
  • Anything from the Full Agent program (it ships dark). The Ghost Agent phone tree is left as it is

Open it

Same seeded day. The Live today switch in the review bar tags each control with the route behind it.

These pages are unlisted, not private: search engines skip them, but anyone with a link can open them.

Backend check against main

Read from the receptionist worker at origin/main (5ffd380aa, October 5) and the shipped v3 receptionist pages (27b73d55), read-only, and again on October 6 (worker b7cb8fa55, web app 6091be41) and against the production tag v2026.10.05-1; where the release and main differ, the row says so. Every row is a route or column that already exists. There is no "small backend" or "backend" column, because the point of the rebuild is that it adds none.

In the prototypeVerdictThe route or column on main
The log, a call record, the recordingFrontend onlyGET /calls (limit up to 200, offset, status, urgency, afterDate, excludeSpam), GET /calls/:id, GET /calls/:id/recording. A row's summary is exactly what is stored: the caller's first turn, cut at 120 characters, written when the call ends (for a transferred call, when it is transferred). A name is the CRM name or what Rippler captured; for anyone else the worker stores whatever Twilio sends (a caller-ID name where the number has lookup, otherwise the city) or nothing, and the number is shown when there is no name or only the city. The list has no total and no search, so search, Today and the counts are done in the browser over the rows loaded.
Call filters, paging and OutcomeFrontend onlyGET /calls?status=&urgency=&afterDate=&excludeSpam=0&limit=51&offset=N, all filtered by the worker: status and urgency match the exact text sent, afterDate is compared as text so a day starts at 00:00 UTC, only excludeSpam=0 includes spam, and the projection carries no spam marker. A page is 50 rows: the page asks for 51 and Next is enabled only when the 51st comes back, because there is no total. Outcome is the stored status in words (in progress, completed, voicemail, failed). The shipped Status list also offers Forwarded, which never matches: no code stores that status, because a forwarded call is stored completed with handled_by forwarded.
To approve: Approve, Reject, DetailsFrontend onlyGET /dashboard/pending-actions?status=pending for the waiting rows (receptionist view) and GET /dashboard/activity for the decided ones, the feed the shipped Agent activity tab reads, with its Details dialog. POST /dashboard/pending-actions/:id/approve and .../reject (receptionist edit; Reject sends the reason "Rejected from dashboard."). Approve runs the action inside the request: the row becomes Executed, or Failed, or Needs User Input for a meeting action. Rows come from the Ripple chat agent, a signed-in tool or a Meeting Studio proposal, queued while an Autonomy gate is set to Approval (the SMS, contact and tag gates default to Auto and the skill gates to Approval; the reason names the gate, which lives on the Autonomy page that is not redrawn). The phone call itself queues none, and a row is not linked to a call.
A call's facts (service, worth, lead, preferred time)Frontend onlyColumns save_lead writes: service_type, estimated_value, is_qualified_lead, preferred_callback. A call has them only if Rippler ran its lead tool, and worth and preferred time only if it passed them. Lead reads Yes when is_qualified_lead is 1, which save_lead sets while Lead qualification is on. A voicemail left on the voicemail route runs no AI, so it has none; a call Rippler transferred that nobody answered goes to voicemail and keeps what it captured.
Take over a live callFrontend onlyGET /calls/active, POST /calls/:id/transfer: a warm transfer of the live call to your transfer number. During hours that is the forward-to number; after hours it is the after-hours transfer number, else the after-hours forward-to, else the during-hours one; the profile phone if none is set. Needs live-call-control, which owners and admins have by default.
Questions to answerFrontend onlysave_question already writes an unanswered knowledge row with its call id and context. GET /knowledge-base?surface=receptionist&includeDraft=1 lists it (needs receptionist edit); the browser joins each question to its call by source_call_id.
Answer it, and Delete this questionFrontend onlyPUT /knowledge-base/:id then POST /knowledge-base/:id/publish; delete is DELETE /knowledge-base/:id. The shipped Company Knowledge page already runs that save-then-publish sequence. The shipped receptionist FAQ editor only re-publishes an article that was already published, so for a question from a call this is a route the receptionist screen would newly call, not a new route. The answer box starts empty because nothing drafts answers.
The caller windowFrontend onlycalls.contact_id is never written on main, so no CRM match is stored. The window looks the caller up by phone with GET /api/pm/people/lookup/:phone (needs CRM view, exact match on the stored number), which the web app does not call today. Name, email and address come from the person. Open in CRM goes to the existing CRM page; Add to the CRM opens the existing new-person form (needs CRM edit), which the build would prefill from the call.
Settings: your numberFrontend onlyGET /phone/mine, GET /phone/verify, DELETE /phone/mine. Active since is numberChangedAt from GET /auth/me. No last-check time is stored, so none is shown.
Settings: who answers whenFrontend onlyPUT /phone/settings (receptionist edit): during and after-hours mode, forward-to (blank after hours means the same as during hours), after-hours transfer-to, rings. Rings are only offered with Ring my phone first, because any ring count above 0 rings the forward number first in every mode but voicemail. Business hours are PUT /contractors/profile businessHours (settings admin): a list of start and end times per day in 24-hour HH:MM; the prototype edits one per day.
Settings: voice and instructionsFrontend onlyPUT /contractors/profile (settings admin): the greeting field is special instructions the AI follows on every call, not the spoken opening line; aiLanguage (auto, en, es); aiAnswersAfter (used only when your phone rings first); aiEnabled; the voice and the six capability rows inside aiCapabilities. Two have a phone tool behind them. On main, Lead qualification off means a basic message, calls not marked as leads and no new-lead alert, and Answer from knowledge base off drops published answers from the prompt and turns website searches into saved questions; in the October 5 release, Off for either only adds a "do not" line to the prompt. The other four (Book appointments, Send SMS follow-up, Update contact records, Create project notes) have no phone tool: main locks them with a Deferred or Not live tag, as here, and in the October 5 release they toggle but turning one On changes nothing. GET /voices (ten voices); POST /voices/preview plays a fixed sample sentence.
Settings: what Rippler knows, with New articleFrontend only/knowledge-base routes. In the October 5 release, POST /knowledge-base {category, title, content, status} creates an answered or draft article and a plain PUT edits it. On main, POST needs an Idempotency-Key header and the receptionist audience (an internal draft cannot be published to the receptionist, and an editor without memory admin is refused) and can create a draft or a published article; a draft is published with POST /knowledge-base/:id/publish {audience: receptionist, revision}, and a published article is edited by retract, PUT, publish. DELETE /knowledge-base/:id is a soft delete. A manual draft and a question from a call both have status unanswered, so the browser tells them apart by source and source_call_id. Category is free text, suggested from the ones in use; on main a title over 160 or a category over 80 characters is cut.
Settings: how Rippler handles calls, with New skillFrontend only/customer-skills routes. POST /customer-skills: the skill key must match [a-z0-9_.]+ and be unique among the tenant's live skills (409 otherwise; a deleted key is restored, and a key that exists only as a platform template is accepted as an override, which the prototype refuses), name and prompt are required, the skill is created Active, and a dotted key fills in its parent from the prefix. PUT /customer-skills/:key edits name, description, condition, category and prompt on the tenant's own skills; DELETE is a soft delete that leaves child skills. A platform template is layered in and copied with POST /from-template when changed. Category (four) and condition (ten) are stored unchecked, and all ten conditions are evaluated on a call. Known caller means the call arrived with a stored name, which for most callers includes Twilio's city. The set shown is a typical one.
Settings: is Rippler working?Frontend onlyGET /phone/diagnostics: the worker's own check ids, labels and details, and its own summary line for the heading (numbers in local format, a plain hyphen for the dash). The within-hours check appears once hours are set, as the worker does it. The prototype recomputes only the hours checks; the worker would also change the routing checks when a mode or forward-to number changes.
Permissions, not new backend. A plain receptionist viewer would see a thinner page and an empty To answer list, not an error. Questions to answer, releasing the number and editing skills need receptionist edit. Hours, voice, instructions, language and the switches save through the profile route, which needs settings admin (owners and admins). Routing needs receptionist edit. The caller window needs CRM view, and Add to the CRM needs CRM edit. Take over needs live-call-control, which owners and admins have by default.
Things the build has to handle, none of them a backend change.
  • The call list pages at up to 200 rows with no total and no search. Today, To answer, search and the caller window cover the pages loaded, and a question whose call is not loaded needs one GET /calls/:id.
  • The call list pages by asking for 51 rows and showing 50, so Next only exists once more than 50 calls match. The shipped Status filter offers Forwarded, which never matches a row (no code stores that status); the build should filter on Routed to (handled_by) or drop the option. The prototype keeps it as shipped so you can see the empty state.
  • The Calls tab count adds the proposals waiting for approval to the questions to answer, both counted in the browser. An approval row names no call: nothing links a pending action to a call.
  • New article follows the worker on main: POST /knowledge-base needs an Idempotency-Key header and the receptionist audience, and its PUT ignores status and sort order. Read from the code, not run, the shipped editor does not send that key yet and still sends a Status, so its Save article would fail on main until it is brought in line; in the October 5 release a plain POST works. The prototype asks for the body before Publish; the shipped editor lets an empty article be published.
  • Count the questions to answer from the knowledge list (GET /knowledge-base?surface=receptionist&includeDraft=1, questions from calls only). Main's /knowledge-base/unanswered/count also counts manual drafts, so it is the wrong source for that number.
  • The older voicemail calls in the log assume the number was set to Voicemail only on those days: the voicemail route runs no AI, so there is no summary or transcript, and the call's duration stays 0. Show the recording's own length, which GET /calls/:id returns as recording_duration.
  • In the October 5 release a skill made from the dashboard has an empty load command, and the AI loads skills from a tree that leaves the Intent category out, so a new skill may never be loaded. Main puts every active skill that passes its condition straight into the prompt.
  • Questions from calls show read-only on the receptionist Agent activity tab today. No receptionist screen can answer, publish or delete them; that is possible only in Settings, Company Knowledge. The To answer view is new front-end wiring. The live voice agent must also have the save-question tool registered with the provider; the worker's own provider check says provider tools still need verification.
  • Hours: send businessHours: null when every day is blank, because an object of empty days counts as configured. Send 24-hour HH:MM. One range per day drops any extra ranges. Hours use the workspace time zone (Settings, Regional and format defaults); with none stored, routing assumes America/Chicago and Rippler's prompt assumes America/New_York.
  • Voice and switch saves must resend the whole aiCapabilities object, including agent_id and ghost_agent_full, because the route replaces it.
  • The schema default ring count is 3 and new tenants start with Rippler switched off. A tenant that never saved routing rings the forward number first, so saving the routing page should set rings to 0 in AI mode, as the shipped page does.
  • The prototype's routing mode keys are its own, not the stored values. The shipped Routing page sends a different AI value for each window: AI Receptionist during hours and ai_only after hours (receptionist-logic.ts). The build must send what that page sends.
  • A caller outside the CRM whom Rippler did not capture has no stored name of their own: the worker stores whatever Twilio sends (a caller-ID name, the city, or nothing). Show the number when the name is empty or only the city.
  • Take over: ring-first calls look exactly like a live Rippler call. A call Rippler already transferred already has its transcript and duration, so the page can hide Take over for it. The worker rejects Take over (500) unless Rippler is on the call, so show that error. It returns success before the dial, and if no usable transfer number exists the caller is hung up on.
  • Stored durations are not the whole call: a live call shows 0 until it ends, a transferred call stores only Rippler's part, and calls on the voicemail route stay at 0.

What the shipped tabs have that this prototype still leaves out

A box-by-box read of the nine shipped tabs (the web app on main, 6091be41; production, the October 5 release, has these nine) against this prototype after the restore. Counting every heading, field, switch, button, column and message an owner sees, that is 246 boxes: 125 are here, 28 are here in a simpler form, 26 are left out on purpose and 67 are missing. Another 38 are super-admin tools in Phone & SMS (Repair webhooks, 10DLC registration), 34 of them missing. This count is finer than the first one (it counts each field in the dialogs), so the totals are not comparable. Nothing below needs new backend, and the shipped pages stay as they are until the build decides what to bring over.

Shipped tabHere / simpler / on purpose / missingNot in this prototype
Shared3 / 0 / 2 / 1The tab strip is now Calls and Settings. On purpose: Test call (a header button on four tabs) and its Call this number field. Missing: the "Digital Receptionist is not available for this workspace." card.
Call history & logs35 / 3 / 4 / 4Missing: the load-error banner with Retry, the call's own Address row, the call page's load error. On purpose: Create follow-up with its Follow-up time dialog (main only), End call and Delete call. This prototype never links to the shipped call page, so the build has to keep it reachable for those three.
Agent activity12 / 1 / 0 / 5Missing: the Calls this week, Open voicemails and Qualified leads tiles, "Current proposal unavailable.", and Load more. The approval list is now To approve, calls and questions are in Calls, and the Pending actions tile is the To approve count.
Routing9 / 8 / 0 / 8Missing: the AI-off banner and the "Routing wasn't saved" error (both main only), the load error, both Reset buttons, inline checks, removing a time block, and + Add block (so one time range a day). Simpler: fields save as you leave them instead of three Save buttons, free text instead of day checkboxes and time pickers, no AI transfer number label.
Knowledge base14 / 6 / 0 / 7Missing: category counts, drag to reorder, "No articles in this category yet", two load errors, the AI usage rules card, and Preview answer. Simpler: Publish and Save draft instead of a Status select (so a published article cannot be unpublished), and required-field messages as toasts.
Customer skills16 / 5 / 0 / 8Missing: Search skills, the category group headers, the platform-template banner (Clone template happens silently), Parent key, Sort order, Load command, the B, I, List and H3 buttons, and the load error. Delete is only on skills made here.
Phone & SMS (an owner sees 30 boxes)12 / 1 / 4 / 13Missing: Buy number with its area-code search dialog and Buy & assign confirm, the SMS status row, the lookup error banner with Retry, and the page error line. On purpose: Test inbound call and its dialog. The Release dialog still says "until you buy a new number", though Buy number is not here. Super-admin only (38 more, 34 missing): the mismatch rows, Repair webhooks, Repair outbound voice, and 10DLC compliance with its sub-account, brand and campaign registration dialogs.
Autonomy4 / 0 / 16 / 1On purpose: the whole page (the eight Allowed actions switches, the Daily SMS budget, Review changes and Save policy). It is the owner's approval policy for actions the AI queues, and Meeting Studio's actions share it; nothing on the live phone path reads it, and its text switch implies texting. Its Owner review queue is now To approve. Missing: "Owner review queue unavailable."
Config16 / 3 / 0 / 13Missing: Reset, the page error line, the Business identity card (Business, Trade, Owner, Hours, Location, Edit business profile), the ElevenLabs agent picker, the Current setup card with Account phone, and the Special instructions preview. In the October 5 release the four extra capability rows toggle; main locks them, as here.
Diagnostics4 / 1 / 0 / 7Missing: Run again, the number heading, the overall badge (Answering calls, Issues found, Not answering), the "worker is running" and "No checks available" messages, and Recent issues. Fix links show only on the failing check.
Permissions are not drawn. Every control is shown as an owner sees it. Receptionist edit gates article and skill changes, Approve and Reject, routing and Test call; settings admin gates saving hours and the voice settings; live-call control gates Take over and End call; call delete rights gate Delete call.
Also on main, not in production yet. Handled and Full Agent rules (behind a flag that is off), Phone tree, Connections, Actions, Training and Pilot. None are redrawn.
What the prototype adds, all on routes that exist. Active since (numberChangedAt from GET /auth/me, which the web app does not read today), Check again and a Phone connection row for every user (GET /phone/verify), the To answer list with Answer it, the caller window, the chips and search, a warning line at the top of Calls, and red counts on menu items.

What the reviews removed

After Seth's note, and again after four rounds of independent review, everything the worker could not back came out or was relabeled. The first column is what an earlier version showed.

Was in an earlier versionWhat the worker actually has
The callback workflow: Call back button, done-state, "needs a callback" queue, a "message taken" blockSeth confirmed we are not a calling-out platform. A caller's preferred time is a stored field, so it shows as a plain fact, only where Rippler ran its lead tool and passed one.
Text-messaging setup and working Book / Text / Keep-contacts switchesRippler has no general tool to text, book or edit a contact on a call. The narrow Full Agent tools ship dark. The four capability rows are back as main shows them: locked, tagged Deferred or Not live.
"What she can do without asking" section, with text switches and a daily text limitIt is the owner's approval policy for actions the AI queues (text a caller, edit skills or knowledge, update contacts), and Meeting Studio's actions share it. Nothing on the live phone path reads it, and its text switch implies texting. The existing page is untouched; it is just not redrawn here.
Written call summaries ("Asked whether we do Saturday appointments")The caller's first turn, cut at 120 characters. A written summary would need a summarizing job that does not exist, so rows show exactly what is stored.
Invented caller names and a stored "In the CRM" link on each callA name is the CRM name or what Rippler captured; otherwise the worker stores whatever Twilio sends or nothing, and the number is shown when there is no name or only the city. Nothing writes calls.contact_id, so the caller is looked up by phone when you open the window.
Lead facts nobody earned: a worth or preferred time the caller never said, and any lead facts on a call where Rippler ran no lead toolOnly its lead tool writes them, and only what Rippler passed it. Lead reads Yes when the lead flag is 1, which the lead tool sets while Lead qualification is on.
Rippler lines that promised too much: "I've passed that to the team", "I see your bath remodel", a transfer marker the worker never writes, a transfer after the caller said it could wait, and a 5:22 callIts prompt forbids promising a callback time or claiming staff were notified unless a tool confirms it, it cannot see projects, the worker writes the marker with the owner's name, its transfer skill says to transfer for a real emergency, a frustrated caller it cannot help, or a caller who still insists on a person after it has tried to help (not on a first request), and its part of a call is cut at 5:00. Those lines were changed to match, and every transcript opens with the platform's first message: the worker's default line unless a platform-wide setting replaces it (a June snapshot of production data in the repo shows one set, so real transcripts may open differently).
Take over "to your phone"The transfer rings your transfer number: the forward-to number during hours, the after-hours transfer number first after hours. It is not a person you choose.
Switch descriptions that overclaimed ("Ask new callers what they need", "Only published answers reach a call")On the live phone path the two switches change its prompt and what is saved, not which tools exist. Labels now match the shipped page and say what off does.
A "Greeting" box that read like the spoken opening lineThe profile's greeting field is special instructions for the AI; the spoken opening line is platform-wide. Relabeled Special instructions, as the shipped page does.
"Rippler is answering" heading and a "Checked today" timeThe worker's own summary says a live call is still needed to verify the provider, and it stores no last-check time. The heading is now the worker's summary line.
"Used N times" on every answer, and "Published by"No usage counter is stored, and the row holds a user id rather than a name. Rows show the stored updated date.
A pre-filled draft answer on each questionNothing drafts answers. Only the question and its context are stored, so the box starts empty.
"Said to the caller" with its source articleThe worker does not record which article a sentence came from. The transcript shows what Rippler said.
"Documents on file" in the caller windowNo route gathers a caller's contracts and invoices.
A Block list: Manage control, and blocked calls always on the listNo route lists or removes blocked numbers. The call list leaves blocked and spam calls out by default; Include spam brings them back, as on the shipped page, and the list carries no spam marker.
"Emergencies only" Saturday hours and an "On call this week" rotationA day's hours are start and end times. There is no emergencies-only flag and no rotation, only a forward-to number and an after-hours transfer number.
A "Her name" field, and a short voice listThe profile has no receptionist-name setting. AI language, which is real, is back, and the voice list is all ten.
An "Everything" countThe call list returns no total, so the chip carries no number.
A question Rippler could not answer about Lowell, while the service area said all of Kent CountyLowell is in Kent County, so Rippler would have answered it. The service area now lists towns and leaves Lowell out.
The seeded problem, wrong twice: texting not registered, then a blank after-hours numberA blank after-hours number falls back to the during-hours one. The problem is now the worker's own "business hours are not configured" check, which is real and has a real fix.

The earlier versions, kept

Nothing already looked at moves. These are untouched snapshots.

The version Seth reviewed (two tabs, with the callback workflow that was removed) · the three-tab first redo · the September 13 version.

Sample data, illustrative only, seeded with one real problem (business hours are not configured). Built to the RippleCore prototype standard, on the live v3 chrome, the decided Rippler bar, Ubuntu, and the June 2026 DataRipple tokens. Routes read from origin/main read-only on October 5, 2026. Run locally with node mockups/receptionist-refresh/_serve.mjs then http://127.0.0.1:4650/; add ?clean=1 to hide the review bar. The prototype and these links are private until MJ shares them.