Skip to main content
These are the complete prompts the engine assembles, one per situation, with each snippet inlined in production order. They are published so you can see exactly what the model is told. Each situation also lists the framework tools offered on that call. Prompt text and tool availability are kept in step, so a prompt never advertises a tool the model was not given. Your own skill tools are additional and are gated by their own requires: conditions. Read System Prompt first for the assembly order and which agent.yml keys override which section.
{{ ... }} and {% ... %} are Jinja2, resolved from live conversation state or your agent.yml.One engine-side gate is not shown as a condition because it is already resolved in each template below: the acknowledgement section (resolved prompts.ack_enabled — on by default on voice turns, off on text when unset) is rendered on the first LLM iteration of a turn, and omitted on later iterations of the same turn. Out-of-scope handling needs two conditions — the scope handler is not the active skill, and the cannot_help tool is offered on that call. With a knowledge base configured that tool is withheld until search_knowledge has run this turn, and the section is withheld with it. Each situation lists the other gates it has resolved, so what you see is what is present at that point in the conversation.When a collect step is skipped because the value is already filled, the engine surfaces ### Already collected (do not re-ask) in two places for the rest of that user turn: inside the active-skill section of the main system prompt, and again as a trailing system message after history / in-turn tool results (same idea as the ack reminder, different insertion point). See Already collected notice.After a non-filler canned response is delivered, the next main LLM request in the same user turn receives a canned-response reminder as its final system message.

Values in the templates

The same handful of values fill every template. Everything else is literal prompt text.

Main turn

Each of these five is a complete system prompt. A pending tool confirmation can appear on top of any of them. Bracketed sections are conditional.
When. No skill is on the stack.Sections. Header, skill glossary, channel rules, [acknowledgement], lifecycle tools, [out-of-scope handling], current date and time, [project], routing catalogue, [pending confirmation].Already resolved. has_active_skill is false, so there is no skill-completion, cancel, or referenced-skills guidance.Framework tools offered (what each one does)
  • activate, when at least one skill is startable. A skill is startable when it is not disabled, not engine-managed, and not hidden
  • search_knowledge, when a references index is packaged
  • cannot_help, immediately when no knowledge base exists; with one, only after a search has run
  • listen, on main LLM calls except guided collect, post-search answer calls, and pending tool confirmation
  • resolve_tool_confirmation, when a tool is paused on requires_confirmation:
The list stops there. complete_skill, cancel_skill, set_fields, and correct all act on an active skill, and there is none.
01_routing_no_skill_active.jinja2
When. A prose skill is on top of the stack.Sections. Header, skill glossary, channel rules, [acknowledgement], lifecycle tools, [out-of-scope handling], current date and time, [project], active skill, [pending confirmation].Already resolved. has_active_skill is true.Framework tools offered (what each one does)
  • activate, when at least one target is startable. That means another skill, or one of this skill’s own blocks reached with @block.<id>. The skill on top is never offered
  • search_knowledge, when a references index is packaged
  • cannot_help, immediately when no knowledge base exists; with one, only after a search has run
  • listen, on main LLM calls except guided collect, post-search answer calls, and pending tool confirmation
  • resolve_tool_confirmation, when a tool is paused on requires_confirmation:
  • complete_skill and cancel_skill
  • set_fields, when the skill still has settable entries this turn
  • correct, when an earlier user-provided value is correctable
Plus the skill’s own tools whose requires: gate currently holds.
02_skill_active_prose.jinja2
When. An ordered block is on top of the stack. Its activate target id is {skill_id}__{block_id}.Sections. Same as a prose skill: header, skill glossary, channel rules, [acknowledgement], lifecycle tools, [out-of-scope handling], current date and time, [project], active skill, [pending confirmation].Already resolved. has_active_skill is true, and the skill-level Instructions section is omitted because the block supplies the steps.Framework tools offered (what each one does)
  • activate, when at least one target is startable. That means another skill, or another block of this skill. The block on top is never offered
  • search_knowledge, when a references index is packaged
  • cannot_help, immediately when no knowledge base exists; with one, only after a search has run
  • listen, on main LLM calls except guided collect, post-search answer calls, and pending tool confirmation
  • resolve_tool_confirmation, when a tool is paused on requires_confirmation:
  • cancel_skill (complete_skill is withheld; the block finishes at END)
  • set_fields, when the skill still has settable entries this turn
  • correct, when an earlier user-provided value is correctable
Plus the skill’s own tools whose requires: gate currently holds.
03_skill_active_ordered_block.jinja2
When. A skill is on the stack and search_knowledge has already run this turn.Sections. Header, skill glossary, channel rules, [acknowledgement], lifecycle tools, [out-of-scope handling], current date and time, [project], knowledge answering, [pending confirmation].Already resolved. has_active_skill is false for the lifecycle section, matching the trimmed tool list, so skill-completion and cancel guidance is dropped. listen_available is false, so the listen() bullet in the lifecycle snippet below does not render.Framework tools offered (what each one does)
  • activate, when at least one target is startable
  • search_knowledge, to re-query with a refined search
  • cannot_help
  • resolve_tool_confirmation, when a tool is paused on requires_confirmation:
This is the shortest list of any situation. Once a search has run, the schema builder returns activate, search_knowledge, and cannot_help (plus resolve_tool_confirmation when a confirmation is pending) and stops, so the skill’s lifecycle tools, its own tools, and listen are withheld for the rest of the turn and return on the next one. A post-search call must present the retrieved information rather than wait silently. search_knowledge and cannot_help are unconditional here: a knowledge base exists by definition, and a search has run.
04_after_knowledge_search.jinja2
When. The bundled unsupported-request handler is the active skill.Sections. Header, skill glossary, channel rules, [acknowledgement], lifecycle tools, current date and time, [project], active skill, [pending confirmation].Already resolved. The out-of-scope handling section is omitted, since the decline is already underway.Framework tools offered (what each one does)
  • activate, when at least one target is startable. The handler itself is engine-managed, so it is never in its own list
  • search_knowledge, when a references index is packaged
  • cannot_help, immediately when no knowledge base exists; with one, only after a search has run
  • listen, on main LLM calls except guided collect, post-search answer calls, and pending tool confirmation
  • resolve_tool_confirmation, when a tool is paused on requires_confirmation:
  • cancel_skill (complete_skill is withheld; the handler is an ordered block)
  • set_fields, when the skill still has settable entries this turn
  • correct, when an earlier user-provided value is correctable
The model therefore cannot re-enter the decline it is delivering.
05_scope_handler_active.jinja2

Separate calls

These use their own, much smaller prompts rather than the main one.
When. A response opted into metadata.rephrase: true.Sections. A system message of header, rephrase task, channel rules, and the current date and time, then the history and user turn, then a trailing system message carrying the text to rephrase.Already resolved. No glossary, lifecycle, out-of-scope, routing, or active-skill sections.Framework tools offered (what each one does)None. The call is made with no tool schemas at all, so the model can only return text. That is what makes it safe for wording you declared verbatim.System message:
06_rephrase_only.jinja2
Trailing system message, sent after the history and the user turn:
06_rephrase_only.jinja2 (trailing)
When. A collect: step confirms a value that is already filled.Sections. The same shell as the rephrase call, with a trailing message that names the field and its captured value.Already resolved. No glossary, lifecycle, out-of-scope, routing, or active-skill sections.Framework tools offered (what each one does)None, the same as the rephrase call.System message:
07_confirm_rephrase.jinja2
Trailing system message, sent after the history and the user turn:
07_confirm_rephrase.jinja2 (trailing)
When. One or more collect steps were skipped this user turn because the value was already filled (ask_before_filling off).Sections. The notice is rendered twice from the same template:
  1. Inside the active-skill section of the main system prompt (next to ### Memory:)
  2. As its own trailing system message after conversation history and in-turn tool results (recency after tool output), similar to how the ack reminder is an extra system message — but appended at the end, not after the last user message
Already resolved. Not shown when nothing was skipped this turn. Cleared on the next user message.Framework tools offered (what each one does)Whatever the turn it is attached to offers. This is prompt text on an existing call, not a call of its own.
skipped_collect_notice.jinja2
When. A non-filler response template was delivered since the latest user message and the engine is making another main LLM request in that same turn.Sections. Inserted as its own trailing system message after conversation history and in-turn tool results, so it remains salient after the canned text.Already resolved. Not shown for filler responses. Not injected after the next user message.Framework tools offered (what each one does)Whatever the turn it is attached to offers. This is prompt text on an existing call, not a call of its own.
canned_utter_notice.jinja2
When. The first LLM iteration of a turn, when resolved ack_enabled is true and no collect step is active.Sections. Inserted as its own system message directly after the last user message.Already resolved. Not part of the main system prompt. Uses prompts.ack_reminder when set, otherwise the default below.Framework tools offered (what each one does)Whatever the turn it is injected into offers. This is a message added to an existing call, not a call of its own.
08_ack_reminder_injected.jinja2
When. Once the agent’s reply has been sent, on turns that changed which skill is active. It runs off the customer’s latency path and is best-effort: a failure is logged and the turn still succeeds.Sections. This task text alone, appended after the conversation so far. None of the main-turn sections are included.Already resolved. Not part of the main system prompt, and not part of the turn’s response loop.Framework tools offered (what each one does)One purpose-built tool, record_discovered_facts, and nothing else. It is not one of the nine framework tools offered during a turn.
discover_facts_task.jinja2

See also