FaceSign

Conversation Rules

The 11 rules that make or break avatar behavior in verification flows.

These rules are load bearing. Violating them causes the avatar to hallucinate, loop, double speak, or fail silently. Every rule is the result of real debugging time across real integrations. Treat them as gospel until you understand them deeply enough to bend them.

1. Always author prompts in English; choose Say: vs descriptive by verbatim-control needs

Author every prompt and outcome condition in English — regardless of which languages your deployment supports. The FaceSign runtime translates avatar speech into the resolved session language at runtime; mixing authoring languages across nodes (some in English, some in the target language) causes the avatar to flip languages mid-flow.

Within that constraint, the prompt style is a separate choice driven by whether you need verbatim control:

Descriptive prompts — the default. The LLM paraphrases at runtime and translates cleanly into any session language. Use for multilingual flows and whenever exact wording doesn't matter.

Descriptive — paraphrased at runtime, translatable
prompt: "Warmly greet the user and tell them you need to verify their identity. Ask if they're ready."

Say: <exact text> — a verbatim-wording directive. The avatar stays close to the source sentence; the runtime still translates the text into the resolved session language, but the result tends to be stiffer than a fresh paraphrase. Use when wording is non-negotiable (legal disclaimers, brand copy).

Say: — verbatim wording
prompt: "Say: Hi! I just need to quickly verify your identity. Ready?"

For multilingual flows, prefer descriptive prompts — they produce more natural target-language output.

2. Never put conditional logic in a single prompt

This is the single most common cause of broken demos. Do not write "If recognized, do X. If not, do Y." The avatar will ignore the condition, hallucinate, or pick the wrong branch.

Instead, use the flow's structural branching:

Wrong: one node, conditional prompt
{ id: 'post_id', prompt: "If recognized, greet by name. If not, ask for their name." }
Right: separate nodes per path
recognition.outcomes = {
  recognized: 'greet_known',   // "Hey [name], great to see you!"
  newUser: 'ask_name',         // "Welcome! What's your name?"
  noFace: 'ask_name'
}

3. Outcome conditions: "" for unconditional, natural language for branching

Every conversation-node outcome takes one of two forms:

  • Single outcome (unconditional)condition: "". No evaluation happens; the flow moves to the target regardless of what the user says. Use for informational turns that don't branch — greetings, explanations, closings, and every node with doesNotRequireReply: true.
  • Multi-outcome (conditional) — each branch gets a natural-language condition describing its trigger. Always include an explicit stall or refusal branch so the conversation can't get stuck.
Single-outcome unconditional
{
  id: 'doc_prep',
  type: 'conversation',
  prompt: "Say: Please have your ID ready. The scanner will appear in a moment.",
  outcomes: [{ id: 'next', targetNodeId: 'doc_scan', condition: '' }]
}
Multi-outcome with explicit fallback
outcomes: [
  { id: 'ready',   condition: 'User said yes or confirmed they are ready',      targetNodeId: 'next' },
  { id: 'refused', condition: 'User declined or refused to continue',           targetNodeId: 'end'  },
  { id: 'stall',   condition: 'Dialog reached 3 exchanges with no clear answer', targetNodeId: 'end' }
]

4. doesNotRequireReply: true only on the last node before end

The flag marks a final monologue — the avatar delivers a closing message and the session ends without waiting for a reply. The node must have a single outcome that targets an end node with condition: "".

It has no meaning on mid-flow nodes. If you want a mid-flow node that speaks and continues without waiting for a reply, use a single unconditional outcome (condition: "") and leave doesNotRequireReply unset — see Rule 3.

5. One question per node

Do not ask multiple questions in a single conversation node. Outcome conditions will match prematurely after the first answer. Split into separate nodes.

Wrong
prompt: "Say: What's your date of birth? And what's your zip code?"
Right
{ id: 'ask_dob', prompt: "Say: Can you confirm your date of birth?" }
{ id: 'ask_zip', prompt: "Say: And what's the zip code on file?" }

6. The greeting must be long enough for video accumulation

Video-analysis nodes (liveness_detection, face_scan, face_compare, recognition) need at least 5 seconds of camera feed before they can run. A conversation node with actual avatar speech must precede the first video-analysis node in the flow to establish that buffer. Once buffered, subsequent video-analysis nodes can run back-to-back without another conversation in between.

Short greetings cause the first video-analysis node to fail — for recognition this typically surfaces as newUser even for returning users.

Too short, first video-analysis node may fail
"Say: Ready?"
Good, gives the camera time to accumulate video
"Say: Hi! I just need to quickly verify your identity to keep your account secure.
It only takes a few seconds. Ready to get started?"

7. Do not reference invisible steps

liveness_detection, recognition, face_scan, and face_compare run silently in the background. Do not have the avatar say "That's done!" or "Looking good!" after one of these — the user saw nothing happen, so the acknowledgment breaks the illusion. Skip straight to the next meaningful interaction.

8. Use the full name for recognized users

When greeting recognized users, instruct the avatar to use the full name: "Hey Ada Lovelace" not "Hey Ada". Add "Use their full name, not just first name." to the prompt.

9. The avatar does not need to introduce herself

Do not waste time with "I'm your verification assistant." Go straight into the purpose.

10. Combine the greeting with the first question for recognized users

This removes an awkward extra conversational turn.

Good: one node
prompt: "Say: Hey [full name], great to see you! Can you quickly confirm your date of birth?"

11. No self-loops in conversation node outcomes

The flow validator rejects any outcome whose targetNodeId equals its own node's id. If you need retry-on-unclear-input behavior, fold it into the prompt text rather than using a self-looping outcome:

Rejected by the validator
outcomes: [
  { id: 'retry', condition: 'Response is blank', targetNodeId: 'ask_name' },
  { id: 'done',  condition: 'User gave name',    targetNodeId: 'next' }
]
Accepted
prompt: "Ask for their full name. If they respond unclearly, ask once more gently.",
outcomes: [
  { id: 'done', condition: 'User responded, or the conversation has exceeded two exchanges', targetNodeId: 'next' }
]

Next Steps

On this page