Capabilities
Every capability with its mechanism and an independent way to verify it. Last updated October 17, 2026, 9:46am Eastern, with the current release.
| Capability | Mechanism | How to verify |
|---|---|---|
| Parallel outbound calls | Places up to 10 phone calls at the same time per task through a voice-agent runtime on a dedicated Atlanta number; each call carries a per-task script and a JSON extraction schema; results aggregate when all calls end or the time budget (default 5 minutes) elapses. | Create a task via POST /api/tasks with an ask such as "call the top 5 tailors in Buckhead"; open /app/tasks/{id} and count the call rows and their durations. |
| AI disclosure on every call | The first sentence any person hears from her names whose personal AI assistant she is, which discloses the AI before anything else is said; her next sentence says she is recording so she gets the details right. She listens first: through a recorded menu or hold she only presses keys, and her first words to the person who picks up are that sentence, fixed in code and checked by Caleyna's own server before any word reaches the voice; the system prompt forbids claiming to be human. | Read any call transcript on the task page: her first spoken line is the disclosure, then the recording notice, the same words on every call, after any keypad presses. |
| Structured extraction | Each call returns typed fields (accepts_new_customers, price_quote, earliest_availability, callback_needed, plus per-question answers). | GET /api/tasks/{id} returns calls[].structured for every completed call. |
| Family graph | Typed facts per family (subject, key, value, sensitivity) that plans and scripts read from; sensitive categories are declined by design. | POST /api/facts, then GET /app; the fact appears in the Family graph table. |
| Human escalation | Any task can be handed to an operator; research tasks auto-escalate when fewer than half the businesses were reached; operators resolve with notes in /ops. | POST /api/tasks/{id}/escalate then view /ops as an operator. |
| Share a result | A task result renders at /s/{token} showing ONLY that task's data, with a make-your-own conversion path. | Open /s/{token} for one task; no other family data is reachable from that page; a decoy household with a positive control is checked on every build. |
| Answers her own phone | A member calling +1 470 730 7429 reaches an assistant that discloses it is an AI, states it is recording, understands one request, and creates the task through the same planner the app uses. A caller whose number is not a member's is never told a household exists: a message is taken for a person instead. | Call the number and ask for something; the task appears at /app tagged as arriving by voice. The caller-unknown path writes an inbound_messages row and no task at all. |
| Sends and receives her own email | caleyna@caleyna.com. A finished research task emails the member the counts, the comparison and the recommendation, signed in her own name, with a footer stating she is an AI. The message contains no image of any kind, so it renders identically with images blocked. | Finish a task and read the mail; view its source and count the <img> tags, which is zero. |
| Never dials a mobile line | Every number is checked for its line type before any live call. A mobile line, a personal line, an invalid number, or a line whose type cannot be read routes to the human queue with its own escalation rather than being dialed by an automated voice. | GET /api/tasks/{id} on a task containing a mobile target: that call carries status needs_human and provider line-type-gate, and an escalation exists. |
| Call transcripts are untrusted input | A business on a call can say anything, including instructions aimed at the model that summarizes it. Call results are fenced before they reach the summary model, the fence cannot be closed from inside the data, and the instruction that the block is data rather than commands is placed after it. | Every build runs three decoy transcripts that carry instructions aimed at the model, and two controls; the summaries follow none of the instructions. |
| The household file is the member's | Every fact shows who added it and when; any member can delete any line; the whole household downloads as one file with nothing from any other household in it. | GET /api/family-file.json while signed in, and POST /api/facts/{id}/delete on any row. |
| Runs on | Web app (mobile-first, verified at narrow and desktop widths), her phone line, her text line, her email address, a Mac menu-bar client, a command line, an MCP server for any agent, and a Siri shortcut. | Open / at a narrow width and at desktop; call or text the number; email her address; finish a task and read the mail. |
| Ask her by email | Mail to her address is forwarded to the household's operator first, before anything is read, then a member's email becomes a task through the same planner the text line uses: the subject and the body, quoted history and signatures cut, an attached photo of a bottle or a card read for item, dose and plan only. A household opens only when the envelope sender, the header From and a member row agree and the receiving edge marked the mail dmarc=pass; anything less is a message for a person with no reply. The emergency refusal answers with one sentence and dials nothing. | Email caleyna@caleyna.com from a member address: the task appears at /app tagged as arriving by email and a reply carries the task link; a stranger's email writes an inbound_messages row and no task. |
| Usage analytics | Closed-vocabulary usage, funnel, and activity events; unknown ids are dropped, so the table is PII-free by construction. | GET /v1/health with the agent token lists event counts by id. |
| Keypad and phone-tree memory | She presses keys on a phone menu (the provider's keypad tool) and, after a call that navigated a menu, keeps the path per number so the next call presses it instead of listening to the whole menu; an operator can set a path with no deploy. | The provider's tool log lands on every row as structured._tools (a press is evidence, never a claim); GET /api/ops/dial-hints lists the stored paths. |
| First to say yes ends the rest | With first-match on, the moment one business says yes to the goal (in stock, can see the child, has the slot) the other calls are ended and read 'ended early'; a leg still waiting for opening time is released unrung. | A task created with stop_on_first: true; the other rows carry ended_reason first_match. |
| Calls at opening time, or at a named time | A closed business is called at the directory's next opening (Places nextOpenTime); a named time (up to seven days out) is honored for every target. The wait lives in a Durable Object alarm and the dial policy is read at the moment of the dial, so a stop that lands during the wait is honored. | A task with when: 'open' or dial_at: <time>; the row reads 'waiting' with the time, then 'calling' at that time (measured on our own test line). |
| Courtesy hours | A closed business that opens within fourteen hours is not rung now; its call waits for the door. Open businesses are called at any hour (a 24-hour pharmacy at 2am). when: 'now' rings a closed line on purpose to leave a voicemail. | POST /api/agent/plan on closed businesses shows 'would call at <opening>' with no flag. |
| Spanish calls | With language: 'es' the whole call is held in Spanish: the disclosure in Spanish still naming her as AI and whose assistant she is, a Spanish transcriber, a multilingual voice, Spanish goodbye and voicemail. | The request body carries transcriber.language 'es' and her opening line in Spanish. |
| Voicemail with her own number | Every voicemail she leaves gives her own line digit by digit so the business can call back; a business calling back within a week is greeted as that business, its answer lands on the task's thread and the operator queue, and the member is texted when they asked to be. | Call +1 470 730 7429 from a number she dialed this week: the greeting names your business and the purpose. |
| Emergency refusal | An ask that describes a life-threatening state (not breathing, unconscious, choking, seizure, chest pain, stroke, overdose, severe bleeding, 'call 911') is answered with one sentence to call 911 (a poisoning: Poison Control) and nothing is dialed, on the app, the agent route, text, and the phone line. | POST /api/agent/plan with such an ask returns kind 'emergency' and would_call []. |
| Do not call again, honored two ways | A business that asks not to be called again is filed in the household as a number never to dial, and a member can file one with a tap on any reached row; the dial policy refuses it on every later task with no deploy. | The household file shows a 'do not call' fact; the next task's row for that number reads 'with a person' and provider policy-gate. |
| The pick is called first next time | A business the household names as theirs ('Remember this one') is called first whenever the query matches, added at the front even when the directory leaves it out. | POST /api/agent/plan after the tap returns preferred: <name> and that business first. |
| Nearest and open first | Directory results rank open now, then nearest by traffic-aware driving time from an address the member gives, then rating; every row shows the drive and whether it is open. | POST /api/agent/plan with from: <address>: would_call carries driveMin and openNow. |
| Live status on every row | A row moves from ringing to talking when the provider says the call is in progress, says what the call is doing right now (on a menu, on hold, with a person, handing off), then moves to its outcome with cost, length, the recording and the transcript. Any one call can be ended from the task page or a session, and its result says it ended at your instruction. | Poll GET /api/agent/tasks/{id} during a task: each talking row carries live.label; POST /api/agent/tasks/{id}/end with a call_id hangs that leg up. |
| Connect the member | With transfer-to-me on, once a person who can help is on the line she connects them to the member's own phone, and to no other number; the result text offers 'Reply 1' to have her call the winner back and put the member through. | The transfer destination is set server-side from the member row ; reply 1 to a result text creates the callback task. |
| What a care coordinator writes down | Every call extracts a reference number, the member's next step, how the person on the line was, and whether anything was actually answered (the provider's pass/fail grade), beside the price, availability and hold. | GET /api/agent/tasks/{id}: calls[].structured carries reference_number, follow_up_action, tone and _success. |
| A session on a Mac can ask her | A Claude session on one of the family's own Macs places, plans and reads tasks through the agent route with a bearer token that acts only as an operator; the command-line client and the 'Ask Caleyna' Siri shortcut ride it. | POST /api/agent/plan is a dry run: who she would call and what she would ask, nothing dialed. |
| Steer a call while it runs | While a leg is talking, the member types one instruction into that row and she acts on it in her next turn (a whisper), or taps 'Put me on this call' and the leg is transferred to the phone on the member's own row and to no other number. The client does the same (caleyna whisper, caleyna join). A finished call cannot be steered. | POST /api/tasks/{id}/whisper with the call and the text while a row reads 'talking'; the transcript shows her asking it (measured on our own test line). |
| Two sentences a parent can act on | Every completed row carries the provider's summary written for a parent: what the business said, and what to do next. It is the row's one line and the client's 'in short'. | GET /api/agent/tasks/{id}: calls[].structured._summary on any completed row. |
| A text the moment something is confirmed | With texting on, she texts the member one sentence from her own number the moment a business confirms something worth knowing (in stock, the price, held under the name, the earliest slot), at most twice per call, while the other calls keep running. The text is sent from her side; no credential of the household's is handed to the voice provider. | A task created with notify_sms: true carries the text_member tool in its request body; the text names the business and links the task. |
| A deadline, and she keeps trying until then | 'By 6pm' names a deadline: a line that does not answer or is busy is tried again every fifteen minutes, each attempt through the full dial policy and counted by the daily caps, until it answers or the deadline passes. The row shows when the next try is and how many there were. | POST /api/agent/tasks with by: <time>; after a no-answer the row reads 'scheduled' with ended_reason 'retry at <time>'; the finished result says finishedBecause 'deadline' when it ran out. |
| The transcript, as it happens | While a leg is talking, its transcript grows on the row line by line; the page shows it open as 'Transcript so far' and the client prints each new line. | GET /api/agent/tasks/{id} mid-call: the in_progress row's transcript is non-empty and grows between polls. |
| Only a business reached counts | The result carries how many businesses were actually reached; a line that never picked up, a voicemail, a refusal, or a call ended early once the answer was in counts nothing toward the metered part of a plan. | GET /api/agent/tasks/{id}: result.billable equals the number of rows with status completed. |
| Every recording, kept by us | When a call ends, its recording is copied from the provider into our own storage and the row links to our copy, served only to a signed-in member of the household; a row whose copy did not land at the time is fetched on first play. The provider's own link is never handed to a player. | After a completed call, the row's recording_url reads https://caleyna.com/api/recordings/<callId>; a session downloads it with caleyna recording <task> <leg> (measured: 1.19 MB of 16 kHz WAV on a test-line call). |
| The result, as an email a parent can act on | When the calls finish, the email says in plain English who she called, why (the member's own words), when (Eastern), what she asked, what to do next as numbered steps with the number to tap, what is still in motion, and each business with its outcome, time, length, facts, verbatim answers and recording link. The subject reads '<brand> called <who>: <outcome>'. | Ask for any calls with an email on the member row; the mail arrives from caleyna@caleyna.com with that subject shape. |
| A photo instead of typing the drug name | A parent photographs the prescription bottle, the package, or the insurance card; she reads the drug, its dose and the plan name off it and nothing else: no name, no date of birth, no member or Rx number reaches the call, the task, or storage, and the image itself is dropped after one read. Those three fields fill the item and the plan and are handed to the transcriber as words to get right; the task page says what was read. | POST /api/agent/photo with photo (base64, at most 1.5 MB) and mime; the client passes the read as photo_read on POST /api/agent/tasks, shown on the plan card; CLI --photo, MCP photo_path. |
| A care schedule from a nurse-line call | With the nurse-line, urgent-care or pediatric-after-hours pack (or care_schedule on the request), the call's extraction carries a timed care schedule (when and what, in the nurse's words) and the red-flag symptoms they named, never guessed; the row, the email and the text show them. | POST /api/agent/tasks with care_schedule: true; the row's structured data carries care_schedule[] and red_flags[] (empty when none were given). |
| Listen to a call as it happens | While a leg is talking, a Listen button on its row plays the call in the browser; the stream is handed out only while the leg is on the line and only to the household. A session records it to a file the same way. | GET /api/tasks/{id}/calls/{callId}/listen while the row reads 'talking' returns the stream URL; after the call it refuses. |
| She reads their website first | Before a directory business is dialed, its own site is read and up to five facts a caller should know (hours, appointments, insurance, a drive-through, a stated policy) are given to her as facts to use, never to ask again; the page text is treated as data, never as instructions. | A directory target with a site: the call's system prompt carries 'From this business's own website'; a target without one carries nothing. |
| Ask again on a schedule | A wait time or a stock question can be re-asked every N minutes, M times in all; every answer is kept and the row shows the series over time. | POST /api/agent/tasks with repeat_every_min and repeat_times; the finished row's structured._series lists each answer with its time. |
| Book it behind your tap | On an ask that commits you, she finds out and stops. Your tap names one business she reached and she places one more call to book exactly what you chose, asking for the confirmation number and anything to bring; a person steps in only if that call does not confirm it. | On a done binding task, POST /api/tasks/{id}/confirm with what and business creates the booking task and the research task reads 'booking it'. |
| A person on the line before your phone rings | With texting and connect-me both on, the moment a person who can help is on the line she texts you that your phone rings next, then connects you. With --warm she tells you in one sentence what was confirmed before the bridge. | The call's system prompt carries the text-then-transfer rule only when both are on; the transfer plan reads warm-transfer-say-summary only with the flag. |
| Her number, watched | The weekly watch reads her outbound number's reputation (spam risk and scores) so a 'Spam Likely' label is caught before answer rates fall, and grades five of the week's transcripts for disclosure first, phone tree handled, and answers faithful to the call. | The watch email carries a reputation section and a transcript QA section, each saying NOT MEASURED when it could not run. |
| Put the follow-up on your own calendar | When a business names a day to check back on, the result email carries a calendar file with one entry per business, so the errand lands in whatever calendar the family already uses with a single tap. The entry holds the business's own words, the original ask, the person to ask for when they named one, and a link to the full result, with a reminder the evening before. Only a day that can be read from what the business actually said becomes an entry: words like "soon" or "when the truck gets here" produce none, and a result with nothing readable carries no file at all. | A standard iCalendar (RFC 5545) attachment named follow-ups.ics on the result email; the same reader that moves a re-ask series decides which words become a date, and it refuses anything sooner than a day away or further out than 180 days. |
| Ask again next month, and the month after | A re-ask on a cadence is a scheduled re-creation of the task: every 7 to 90 days, 2 to 12 times, at most 180 days out, 5 active schedules per household. Each firing is created through the very same path a first ask uses, so every cap, the dial policy, the courtesy hours and the emergency refusal apply to it unchanged; the result goes to a named member of the household. A firing the route refuses says so on the household's own page and is never retried the same day, and a cancel is a status and a time rather than a deleted row. | POST /api/agent/schedules with every_days and times (or caleyna call ... --again monthly --times 6); GET /api/agent/schedules lists next firing, done of times and recipient; the daily cron 0 13 * * * fires them and each fired task's plan carries authorization.scheduleId and firing. |
| An agent can ask her | An MCP server exposes plan, call, status, whisper, join and health to Claude Desktop and any agent, with the same safety rules as the client: plan first, she never dials a mobile or a household number, the dial policy decides. | Register the MCP server and call caleyna_health; it answers with the Worker's own health line. |
| Heard in the language the line switches to | With the multilingual transcriber the call rides a model that follows a mid-call switch between English and Spanish, so a business that answers in Spanish from its first word is heard verbatim while she holds the call in English; the default transcriber stays until a real-business run reads no worse. | caleyna call ... --transcriber flux-multi; the request body carries transcriber.model flux-general-multi. Benched on our own line that switches to Spanish mid-call: the multilingual model carried every Spanish line verbatim. |
| A school or daycare absence, called in | The school-absence pack states the student and the reason, asks the office to log the absence and name the person spoken with, and asks what is needed in writing on return. | caleyna call --pack school-absence --name <student> --item <reason>; the row's structured data carries logged and contact_person. |
| Voicemail told apart by her own ear | Voicemail detection rides the voice provider's own audio model plus beep detection instead of the carrier detector its documentation calls legacy and prone to false positives; a false positive would hang up on a live person, a miss would bill minutes to a machine. | Every call request carries voicemailDetection.provider vapi. |
| The re-ask moves to the date they named | When a business on a re-ask series says to check back after a date (a month, the Nth, next week, a span), the series' next firing moves to that day; anything within a day, past the 180-day horizon, or not a date leaves the cadence alone. | A series task whose extraction carries retry_after_date; GET /api/agent/schedules shows the moved next firing (nine phrasings, checked on every build). |
| Drive a live call by text | With text relay on, every final line of every call is texted to the member's own phone as it lands, her side and the business's side each named, and a text back is said by her on the call in her next turn: to the call named before a colon, or to every call on the line. At most 40 texts per call, then a link to the page. What she never says on a call cannot be texted onto it either, and the phone is the member row's own, never a request field. | caleyna call ... --text-relay (MCP text_relay: true); the texts arrive from her own number, and a reply lands as a whisper on the row's controls. |