Knowledge > Products > Voice Agent > Prompts
Voice Agent Prompt Design
The voice agent's system prompts are built by pure functions in verticals/church/prompts.py. Each function takes a church data dict (loaded from Supabase at call initialization) and returns a fully assembled system prompt string. No side effects, no DB calls -- all runtime context (datetime, repeat caller history, product knowledge, RAG) is injected separately via agent.history.add_entry() in the agent builder.
Design Principles
-
Layered sections joined with newlines. Each prompt builder assembles a list of text sections, then joins them with
"\n\n". Sections are conditionally included -- if a church has no events configured, the events block is omitted entirely. -
Per-church personalization via variables. Church-specific data is interpolated directly into prompt text using f-strings. There are no generic prompts -- every church gets a unique system prompt built from their configuration.
-
Safety fragments are shared. A common set of 14 safety/behavioral fragments is injected into every agent via
build_shared_fragments(). The HEAR protocol is added separately by church-agent builders only (not by the Sales Agent). -
Prompt text is never stored in the database. The database stores structured church data (name, address, hours, staff, etc.). Prompt builders transform this data into natural-language instructions at call time. This means prompt improvements deploy instantly without database migrations.
-
TTS optimization. All prompts instruct the agent to format output for text-to-speech: no markdown, no bullet points, no emojis, numbers spelled out, phone numbers digit-by-digit, times in 12-hour format. Responses are capped at 1-2 sentences.
Prompt Architecture Overview
+---------------------------+
| build_shared_fragments |
| (14 safety fragments) |
+---------------------------+
| |
+---------+--------+ +-------+--------+
| build_coordinator| | build_care |
| _prompt | | _prompt |
+---------+--------+ +-------+--------+
| |
+---------|--------------------|---------+
| Runtime injection (agents.py) |
| - RAG context (church KB + theological)|
| - Product knowledge |
| - Inline FAQs |
| - Repeat caller history |
| - Datetime context |
+----------------------------------------+
Shared Safety Fragments (core/prompt_fragments.py)
The build_shared_fragments() function concatenates 14 fragments into a single block, substituting {church_name} and {pastor_name} throughout. This block is injected into every agent's system prompt.
| Fragment | Key Behavior |
|---|---|
| Crisis Protocol | Detects suicidal ideation (including euphemistic language like "tired of living," "ready to go home to be with the Lord," farewell signals). Drops all cheerfulness. Provides 988 immediately -- no clarifying questions first. 988 works in both US and Canada. |
| Domestic Violence Hotlines | US: 1-800-799-7233. Canada: 1-866-863-0511. Acknowledges courage, suggests speaking with pastor in person when safe. |
| Medical/Legal/Financial Guardrails | Redirects to professionals. General info OK (e.g., Financial Peace class). Giving/tithing questions are explicitly fine (core church function). |
| AI Disclosure | Initial greeting already disclosed AI + recording. Does not repeat. If asked: "I'm an AI assistant for {church_name}!" One sentence, then redirect. |
| Honesty Rule | Never says "I'll pray for you" -- uses third-person language: "The prayer team will be praying," "You'll be lifted up." |
| Sign-Off Rules | Never says "good luck." Always faith-encouraging: "God bless you!", "Have a blessed day!" For emotional calls: "Jesus loves you." |
| Clean Endings | One "anything else?" per call. After that, short responses are exit signals. Wraps up in one response. Proactive closing when caller seems satisfied. |
| Formatting Rules | 1-2 sentences max. Numbers spoken out (nine AM, not 9:00 AM). Phone numbers digit-by-digit. Always says a brief acknowledgment before calling any tool. |
| Wrong Number | Politely informs they've reached {church_name}. |
| Abuse Handling | 2-strike policy. First: redirect. Second: end call. |
| STT Error Tolerance | Names that sound like common words (food, animals, objects) are likely transcription errors -- ask to repeat. City names and proper nouns often get mangled -- use context. |
| Other Churches | Redirects to pewsearch.com for finding other churches. |
| Scope Enforcement | Refuses off-topic requests (sermons, stories, trivia, homework, recipes, code, games, roleplay). No override mode. |
| Critical Safety | Never positions itself as the caller's only source of support. Always connects to real community and care. |
HEAR Protocol
The HEAR protocol is the emotional framework for all church-facing agents (Coordinator and Care). It is NOT included in the shared fragments -- it is injected separately by each church-agent prompt builder. The Sales Agent does not use HEAR.
Steps:
- HEAR -- Let the caller finish. Do not jump in after their first sentence. Silence is okay.
- EMPATHIZE -- Acknowledge what they said. Name the emotion: "That sounds really scary." Never skip this. Never jump to collecting information.
- CONTINUE -- After empathizing, move the conversation forward in the SAME response. Empathy alone is not a complete turn. Combine empathy with a gentle next step.
- CONNECT, INVITE, CAPTURE -- Organically connect them to the church (prayer team, pastor, ministries), offer a next step, capture info they are willing to share. Not every call needs all three.
Key rules within HEAR:
- Do not ask for information too early. Wait until the caller has shared both the facts AND the feelings.
- Never repeat the same phrases, metaphors, or sentiments within a call. One time is powerful. Twice is noise.
- Short acknowledgments from the caller ("okay," "mm hmm") are just acknowledgments -- do not treat as new questions.
Coordinator Prompt (build_coordinator_prompt)
The Coordinator is the front door of the voice agent. It handles general church inquiries, visitor welcome, events, service times, directions, giving/stewardship, and warm handoffs to the Care Agent.
Section Order
- Identity -- "You are the AI receptionist for {church_name}."
- HEAR Protocol -- Full emotional framework.
- Shared Safety Fragments -- All 14 fragments with church_name/pastor_name substituted.
- Church Facts -- Conditionally assembled from:
- Address, denomination, phone, website
- Hours of operation (from
custom_hoursdict, formatted day-by-day, orworking_hoursstring) - Staff and leadership (from
custom_stafflist: name + title) - Ministries and programs (from
custom_ministrieslist: name + description) - What to expect (from
what_to_expectdict: dress_code, parking, children, first_visit, music_style, service_length) - Upcoming events (from
eventslist: title, date, time, description)
- Custom FAQs -- Church-specific Q&A pairs from
custom_faqslist. Formatted as:If asked "{question}", respond with: "{answer}". - Pastor's Pulse -- Dynamic weekly content block (see section below).
- Topic Awareness -- Routing rules:
- Handle directly: Service times, directions, events, volunteering, groups, visitor welcome, giving/stewardship, staff/ministry questions, scheduling
- Warm handoff to Care Agent: Grief, loss, prayer needs, emotional distress, domestic concerns, sensitive personal topics. Must empathize first, ask consent, then transfer. If caller declines, handle with HEAR protocol.
- Connect to human (callback only): Deep theological questions, counseling, marriage, complaints, demands a real person
- Mixed emotional + transactional: Always lead with empathy (HEAR protocol), handle emotional need first
- Giving and Stewardship -- Zero-pressure tone. Never guilt-trip, never push. Never mention dollar amounts. Never bring up giving more than once per call. Never mention giving during crisis calls or to first-time visitors. Includes configured giving methods (online URL, e-transfer email) and any custom giving message.
- Human Escalation -- "DEMANDING A REAL PERSON" protocol (see section below).
- Language Support -- Speaks in caller's language (Spanish supported). Tool data always in English so staff can read submissions.
- Personality Overrides -- Custom tone and instructions from
agent_config.coordinator.personalityOverrides.
Care Prompt (build_care_prompt)
The Care Agent handles prayer requests, grief, pastoral care, and callback scheduling. It is reached via a consent-based warm handoff from the Coordinator.
Section Order
- Identity -- "Be Christ to this person." Not a receptionist. Not collecting information. Present with a hurting human being. Speaks in shorter sentences. Leaves space. Silence is a gift -- does not fill it. Tools should feel like a natural extension of the conversation, not a form being filled out.
- HEAR Protocol -- Same protocol as Coordinator, but with even more emphasis on space and patience.
- Pacing -- Explicit slow-down instructions:
- Shorter sentences than the Coordinator
- One thought per response
- After empathizing, pause and let them respond
- Never ask "Is there anything else?" to someone in crisis
- If they go quiet: "I'm still here."
- Shared Safety Fragments -- All 14 fragments.
- Prayer Request Guidance -- Concise capture flow:
- Let them tell you what is going on (do not interrupt)
- One brief empathetic sentence
- Ask for first name ONLY, then REPEAT IT BACK to confirm (phone audio distorts names)
- Submit IMMEDIATELY -- do not ask follow-up questions they did not volunteer
- Respect "anonymous" and "confidential" requests
- After submitting: "The prayer team at {church_name} will be lifting this up."
- NEVER say "I'll pray" -- you are an AI
- Callback Scheduling -- Capture who they want to hear from in the reason field. Set urgency to "urgent" for hospital/death/crisis mentions. Set "pastoral_emergency" for emergencies or very distressed callers. Never ask the caller to dictate their phone number (already have it from caller ID). No over-promising -- only promise what the AI can control.
- Pastor Availability -- If
pastor_availabilitydict is set, lists available day/time windows and instructs the agent to mention them during callback requests. Falls back topastor_availability_textfree-form string. - Pastor's Pulse -- Same dynamic block as Coordinator.
- Personality Overrides -- Custom tone and instructions from
agent_config.care.personalityOverrides.
What the Care Prompt Does NOT Include
- Topic awareness / routing rules (Care does not route -- it IS the destination)
- Giving/stewardship section (never mention giving during emotional conversations)
- Human escalation protocol (Care handles directly; if needed, uses callback tool)
- Language instructions (inherited from session context)
Stewardship Prompt (build_stewardship_prompt)
A specialized prompt for giving/donations/tithing questions. Transactional, not emotional-first.
Key Differences from Other Agents
- Does NOT get the HEAR protocol (stewardship is transactional)
- Does NOT get Pastor's Pulse (giving conversations should not pivot to sermon topics)
- Gets shared safety fragments but not emotional guidance
- Zero-pressure giving tone with specific e-transfer guidance for Canadian churches
Per-Church Personalization Variables
The prompt builders read these fields from the church data dict (loaded from church_voice_agents + churches + premium_churches + organization_settings):
| Variable | Source Table | Used In |
|---|---|---|
name | churches / premium_churches.custom_name | All prompts (identity, sign-offs) |
address | churches | Coordinator (church facts) |
denomination | churches | Coordinator (church facts), RAG lens selection |
phone | churches | Human escalation fallback |
website | churches | Coordinator (church facts) |
custom_hours | premium_churches | Coordinator (formatted day-by-day hours) |
working_hours | churches | Coordinator (fallback if no custom_hours) |
custom_staff | premium_churches | Coordinator (name + title list) |
custom_ministries | premium_churches | Coordinator (name + description list) |
what_to_expect | premium_churches | Coordinator (dress_code, parking, children, first_visit, music_style, service_length) |
events | premium_churches | Coordinator (title, date, time, description) |
custom_faqs | church_voice_agents | Coordinator (Q&A pairs) |
pastor_name | church_voice_agents | All prompts (callback references, safety fragments) |
sermon_topic | church_voice_agents | Pastor's Pulse block |
sermon_series | church_voice_agents | Pastor's Pulse block |
theme_verse | church_voice_agents | Pastor's Pulse block |
weekly_announcement | church_voice_agents | Pastor's Pulse block |
giving_url | church_voice_agents | Coordinator + Stewardship (giving methods) |
etransfer_email | church_voice_agents | Coordinator + Stewardship (e-transfer info) |
giving_message | church_voice_agents | Coordinator + Stewardship (custom context) |
human_request_message | church_voice_agents | Human escalation block |
pastor_availability | church_voice_agents | Care (structured dict: day -> time windows) |
pastor_availability_text | church_voice_agents | Care (free-form fallback) |
agent_config | organization_settings | All prompts (personality overrides per agent type) |
Pastor's Pulse
A dynamic weekly content block injected into both Coordinator and Care prompts when any of the four fields are set. Builds a section titled "THIS WEEK AT {CHURCH NAME}:" with:
- This week's sermon topic (quoted)
- Current series name
- Theme verse
- Weekly announcement
Usage instructions embedded in the prompt:
- When someone asks about Sunday service: mention the sermon topic or series
- When the conversation feels warm: share the theme verse
- Announcements: mention when it fits (e.g., someone asks about events)
- Do NOT force it into every response -- only when there is a natural opening
- Keep it brief: one sentence, woven into the answer, not a separate monologue
If none of the four fields are set, the entire block is omitted.
Human Escalation Customization
The "DEMANDING A REAL PERSON" block is built by _build_human_escalation() and supports per-church customization via agent_config.{agent_type}.handoffRules.humanEscalation:
Configurable fields:
| Field | Effect |
|---|---|
whenToEscalate | Additional trigger conditions appended to the default set |
contactName | Named person to connect the caller with (e.g., "Pastor Smith") |
contactMethod | Specific contact instructions (e.g., "Call the church office at 555-1234") |
Default trigger phrases: "real person," "human," "transfer me," "let me talk to someone," "I don't want to talk to a robot," or expressed frustration about talking to AI.
Default flow:
- Do NOT argue, explain, or try to convince them to keep talking
- Do NOT say "I understand your frustration" in a scripted way
- Deliver the human escalation message (customized or default)
- Use
request_callbackwith urgency "urgent" and reason "Caller requested to speak with a person directly" - Confirm: "Done -- someone will be reaching out to you shortly."
- If caller refuses to leave info: provide the church phone number directly
Language Support
The Coordinator prompt includes explicit multilingual instructions:
- If the caller speaks Spanish (or any other language), respond in their language
- The agent is described as fluent in Spanish
- Church information, service times, and directions are translated naturally
- Critical rule: When using tools, field values MUST be in English so church staff can read submissions. Spoken conversation stays in the caller's language, but tool data goes in English.
- If language is unclear, asks: "Would you prefer English or Spanish?" / "Prefiere ingles o espanol?"
Theological Lens Injection
Theological context is not injected via the prompt builder directly. Instead, it flows through the RAG system at session initialization:
main.pycallsfetch_session_rag(supabase, church_id, denomination, church_name)core/rag.pymaps the church'sdenominationstring to a theological lens ID viaDENOMINATION_TO_LENS- The lens ID filters the
search_unified_rag_contentSupabase RPC to return tradition-appropriate content - Formatted RAG results are injected into the agent's conversation history as a system message
Denomination-to-lens mapping (selected examples):
| Denomination | Lens ID | Lens Name |
|---|---|---|
| Baptist, Southern Baptist | 14 | Baptist |
| Catholic, Roman Catholic | 7 | Catholic |
| Methodist, United Methodist, Nazarene | 5 | Wesleyan |
| Presbyterian, PCA, Reformed | 4 | Reformed |
| Lutheran, ELCA, LCMS | 6 | Lutheran |
| Pentecostal, Assembly of God | 9 | Pentecostal |
| Episcopal, Anglican | 13 | Anglican |
| Orthodox, Greek Orthodox | 11 | Orthodox |
| Mennonite, Anabaptist | 8 | Anabaptist |
| Non-denominational, Community Church | 10 | Christocentric (DEFAULT) |
Unknown or null denominations default to lens ID 10 (Christocentric). The mapping covers approximately 40+ denomination strings across 17 theological traditions.
Personality Overrides
Each agent type (coordinator, care, stewardship) can have personality overrides stored in organization_settings.agent_config.{agent_type}.personalityOverrides:
| Override | Effect |
|---|---|
tone | Appends "Your tone should be: {tone}." to the prompt |
customInstructions | Appends a "CHURCH-SPECIFIC INSTRUCTIONS:" block with free-form text |
These are the final sections of the prompt, so they act as strong overrides for church-specific behavioral customization.
Runtime Context Injection (Outside Prompt Builders)
Beyond the static system prompt, the agent builder in agents.py injects additional context via agent.history.add_entry(rag_context, role="system"). This runtime context is assembled in main.py from five parallel data loads:
| Context Block | Source | Cache TTL | Description |
|---|---|---|---|
| RAG context | core/rag.py → fetch_session_rag() | None (per-call) | Church KB hits + theological content filtered by denomination lens |
| Product knowledge | session.py → load_product_knowledge() | 15 minutes | Active Q&A pairs from product_knowledge table, ordered by priority |
| Inline FAQs | session.py → load_inline_faqs() | 5 minutes | Church-specific FAQ pairs from church_knowledge_base table |
| Repeat caller history | session.py → load_repeat_caller_history() | None (per-call) | Last 5 call summaries within 90 days for the same phone+church pair. Privacy-gated: "Do NOT mention these unless the caller brings them up first." |
| Datetime context | session.py → build_datetime_context() | None (per-call) | Current date/time in church timezone, with relative day references ("This Sunday means March 30, 2026") |
All five blocks are loaded in parallel via asyncio.gather() and concatenated with double newlines. The combined context string is injected as a system-role history entry, appearing after the system prompt but before any conversation turns.
LLM Configuration
| Setting | Coordinator | Care |
|---|---|---|
| Model | Gemini 2.5 Flash | Claude Haiku 4.5 |
| Fallback | Claude Haiku 4.5 | Gemini 2.5 Flash |
| Temperature | 0.7 | 0.4 |
| Timeout | 15s | 15s |
| Max retries | 1 | 1 |
| Max tool iterations | 5 | 5 |
The Care Agent uses Claude Haiku for better empathy on sensitive pastoral topics, with a lower temperature for more controlled responses. The Coordinator uses Gemini 2.5 Flash for faster responses on general inquiries. Each agent falls back to the other's primary model.
The Care Agent has an introduction message ("I'm here with you. What's on your heart?") that plays immediately after a warm handoff, preventing silence gaps. The Coordinator's introduction is the standard greeting: "Thank you for calling {church_name}. I'm an AI assistant and this call may be recorded. How can I help you today?"