> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usefini.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How Fini works

> The lifecycle of one customer conversation in Fini, from the surface it arrives on to the reply, the escalation, the AI Steps trace, and the review loop that improves the agent.

export const StepExplorer = ({title, steps = [], hint = "Click a step, or use Next."}) => {
  const FV = {
    lime: "#C3EE5E",
    ink: "#131415",
    line: "rgba(127,127,127,0.28)",
    soft: "rgba(127,127,127,0.07)",
    softer: "rgba(127,127,127,0.04)",
    muted: "rgba(127,127,127,0.95)",
    pass: "#C3EE5E",
    warn: "#FFB020",
    fail: "#FF4D4D",
    radius: 14
  };
  const fvCard = {
    border: `1px solid ${FV.line}`,
    borderRadius: FV.radius,
    padding: 18,
    margin: "20px 0",
    background: FV.softer
  };
  const fvChip = active => ({
    border: `1px solid ${active ? FV.lime : FV.line}`,
    background: active ? FV.lime : "transparent",
    color: active ? FV.ink : "inherit",
    borderRadius: 999,
    padding: "6px 12px",
    fontSize: 13,
    fontWeight: 600,
    cursor: "pointer",
    lineHeight: 1.2
  });
  const fvBtn = primary => ({
    border: `1px solid ${primary ? FV.lime : FV.line}`,
    background: primary ? FV.lime : "transparent",
    color: primary ? FV.ink : "inherit",
    borderRadius: 10,
    padding: "7px 14px",
    fontSize: 13,
    fontWeight: 600,
    cursor: "pointer"
  });
  const fvLabel = {
    fontSize: 11,
    fontWeight: 700,
    letterSpacing: "0.08em",
    textTransform: "uppercase",
    opacity: 0.6,
    marginBottom: 8
  };
  const [i, setI] = useState(0);
  const s = steps[i] || ({});
  return <div style={fvCard}>
      {title && <div style={fvLabel}>{title}</div>}
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: 0,
    overflowX: "auto",
    paddingBottom: 6
  }}>
        {steps.map((st, k) => <div key={k} style={{
    display: "flex",
    alignItems: "center",
    flex: k === steps.length - 1 ? "0 0 auto" : "1 0 auto"
  }}>
            <button onClick={() => setI(k)} title={st.title} style={{
    width: 34,
    height: 34,
    borderRadius: 999,
    flex: "0 0 auto",
    cursor: "pointer",
    fontWeight: 700,
    fontSize: 13,
    border: `2px solid ${k <= i ? FV.lime : FV.line}`,
    background: k === i ? FV.lime : k < i ? "rgba(195,238,94,0.25)" : "transparent",
    color: k === i ? FV.ink : "inherit"
  }}>{k + 1}</button>
            {k < steps.length - 1 && <div style={{
    height: 2,
    minWidth: 18,
    flex: 1,
    background: k < i ? FV.lime : FV.line,
    margin: "0 4px"
  }} />}
          </div>)}
      </div>
      <div style={{
    display: "flex",
    gap: 6,
    flexWrap: "wrap",
    margin: "6px 0 14px"
  }}>
        {steps.map((st, k) => <span key={k} onClick={() => setI(k)} style={{
    fontSize: 12,
    cursor: "pointer",
    opacity: k === i ? 1 : 0.55,
    fontWeight: k === i ? 700 : 500,
    marginRight: 8
  }}>{st.label}</span>)}
      </div>
      <div style={{
    border: `1px solid ${FV.line}`,
    borderRadius: 12,
    padding: 16,
    background: FV.soft,
    minHeight: 120
  }}>
        {s.meta && <div style={{
    ...fvLabel,
    opacity: 0.75
  }}>{s.meta}</div>}
        <div style={{
    fontSize: 17,
    fontWeight: 700,
    marginBottom: 6
  }}>{s.title}</div>
        {s.body && <div style={{
    fontSize: 14.5,
    lineHeight: 1.6,
    opacity: 0.9
  }}>{s.body}</div>}
        {s.points && <ul style={{
    margin: "10px 0 0",
    paddingLeft: 18,
    fontSize: 14,
    lineHeight: 1.6
  }}>
            {s.points.map((p, k) => <li key={k}>{p}</li>)}
          </ul>}
      </div>
      <div style={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    marginTop: 12,
    gap: 8
  }}>
        <span style={{
    fontSize: 12,
    opacity: 0.6
  }}>{hint}</span>
        <div style={{
    display: "flex",
    gap: 8
  }}>
          <button style={fvBtn(false)} disabled={i === 0} onClick={() => setI(v => Math.max(0, v - 1))}>Back</button>
          <button style={fvBtn(true)} onClick={() => setI(v => (v + 1) % Math.max(1, steps.length))}>{i === steps.length - 1 ? "Start over" : "Next"}</button>
        </div>
      </div>
    </div>;
};

Fini (usefini.com) handles every customer message with the same pipeline, whether it arrives by chat, email, voice or a helpdesk ticket: decide whether to engage, plan, load customer context, run a deterministic Rulebook workflow or answer from approved knowledge, check the reply with Guardrails, then deliver it or escalate to a human with the full trace. Every step is recorded in the AI Steps trace, and the conversations themselves feed a review loop that improves the agent's knowledge over time.

This page walks one conversation through that pipeline and links to the page that owns each step. For the higher-level picture of what Fini is, read [What is Fini](/en/what-is-fini).

## The lifecycle at a glance

```mermaid theme={null}
---
title: One customer message through Fini
---
flowchart TD
    IN(["Customer message<br/>chat · email · voice · helpdesk"]) --> RR{"Reply Rules<br/>No Reply · Internal Comment · Direct Reply"}
    RR -->|"No Reply"| SILENT(["Agent stays silent"])
    RR -->|"Direct Reply or<br/>Internal Comment"| PLAN["Planning<br/>what to do with this turn"]
    PLAN -->|"escalation trigger"| ESC(["Escalate to your team<br/>with trace attached"])
    PLAN --> ATTR["User Attributes<br/>customer context"]
    ATTR --> PICK{"Intent Rule<br/>selected?"}
    PICK -->|"Yes"| TREE["Rulebook tree runs<br/>Check · Read · Tool · Form · Reply"]
    PICK -->|"No"| KB["Answer from approved<br/>Articles"]
    TREE --> COMPOSE["Reply composition"]
    KB --> COMPOSE
    COMPOSE --> GR{"Guardrails"}
    GR -->|"Passed, Rewritten or<br/>check error"| OUT(["Reply delivered<br/>or internal note posted"])
    GR -->|"Unsafe after rewrite"| ESC
    OUT --> TAGS["Output Tag Selection<br/>Conversation Status · Sentiment · ..."]
    ESC --> TAGS
    TAGS --> LOOP["Inbox · Review · Test Suite<br/>improvement loop"]

    classDef io fill:#F7F7F7,color:#131415,stroke:#E8E8E8
    classDef step fill:#FFFFFF,color:#131415,stroke:#131415
    classDef core fill:#131415,color:#FFFFFF,stroke:#131415,stroke-width:3px
    classDef human fill:#C3EE5E,color:#131415,stroke:#131415,stroke-width:2px

    class IN,SILENT,OUT io
    class RR,ATTR,PICK,KB,COMPOSE,GR,TAGS,LOOP step
    class PLAN,TREE core
    class ESC human
```

The sections below follow the diagram top to bottom. To click through the same journey one stage at a time, use the explorer.

<StepExplorer
  title="Walk one conversation through Fini"
  steps={[
{ label: "Arrives", meta: "Step 1", title: "The message arrives on a surface", body: "Widget, Email, Voice, a helpdesk such as Zendesk or Intercom, Slack, or the API. The surface does not change how the agent reasons.", points: ["Channel Prompts add per-channel instructions for Email and Chat", "Integration Provider and Channel are available as conditions", "Every conversation lands in Inbox"] },
{ label: "Reply Rules", meta: "Step 2", title: "Reply Rules decide whether the agent engages", body: "No Reply keeps the agent silent, Internal Comment posts a note only your team sees, Direct Reply responds to the customer.", points: ["The stricter behavior wins when several cards match", "No Reply beats Internal Comment, which beats Direct Reply"] },
{ label: "Planning", meta: "Step 3", title: "Planning decides what to do with this turn", body: "The LLM reads the message and the conversation so far, on every customer turn.", points: ["Routes to the Intent Rule whose Description matches", "Applies your escalation triggers from the Planning Prompt", "Input Tag Selection classifies the message"] },
{ label: "Attributes", meta: "Step 4", title: "Attributes load the customer's context", body: "User Attributes fetch plan, account status, billing date or orders from your systems, and each one reports Success or Failed in the trace.", points: ["Use in Rulebooks makes an attribute available to Rulebook Checks", "Attribute filters gate which Articles this customer can get"] },
{ label: "Rulebook or knowledge", meta: "Step 5", title: "A Rulebook tree runs, or the agent answers from Articles", body: "If Planning selected an Intent Rule, the tree walker runs it deterministically: Check, Read, Tool, Form and Reply nodes. Otherwise the agent answers from approved Articles, using LLMs to reason over the knowledge graph.", points: ["A failed Check short-circuits a Steps sequence", "Tool nodes call your Actions", "Retrieved article titles are pinned under the reply in Inbox"] },
{ label: "Compose", meta: "Step 6", title: "The reply is composed", body: "Reply node instructions, retrieved knowledge, customer attributes, Main Guidelines, Predefined Replies and the matching Channel Prompt come together.", points: ["Generate Answer shows Interaction Reasoning, Prompt Reasoning and Final Answering Strategy"] },
{ label: "Guardrails", meta: "Step 7", title: "Guardrails check the reply before delivery", body: "Built-in checks plus up to 10 Custom rule checks per agent. The outcome is Passed, Rewritten, Escalated to a human, or Check failed, sent as generated.", points: ["Guardrails are not a fail-closed security boundary"] },
{ label: "Deliver or escalate", meta: "Step 8", title: "The reply is delivered, or the conversation is handed off", body: "Escalation happens when a Planning trigger matches, a Rulebook branch ends in a handoff Reply, an article marked for escalation is hit, a Guardrail cannot produce a safe reply, or the customer asks for a person.", points: ["On a helpdesk, your team picks up the ticket in the tool they already use", "On the widget, Business Rules run On Escalation to create the ticket", "Every escalation gets a reason from a fixed taxonomy"] },
{ label: "Tags and trace", meta: "Steps 9 and 10", title: "Tags record the outcome, AI Steps records every step", body: "Output Tag Selection applies your tag groups, including the mandatory Conversation Status group. Open any reply in Inbox and click the light bulb icon to see the AI Steps trace.", points: ["Analytics statuses are Resolved by AI, Escalated to Human Team and Waiting for Customer"] },
{ label: "Improve", meta: "Step 11", title: "The conversation improves the agent", body: "Feedback and Refine with AI, Generate Knowledge and Magic Articles, background gap and conflict detection, and Test Suite all run off Inbox.", points: ["Refine with AI drafts changes but never applies them automatically", "Background drafts always land in the In Review tab of Review"] }
]}
/>

## 1. The message arrives on a surface

A conversation starts on whichever surface you've connected: the [Widget](/en/deploy/widget), native [Email](/en/deploy/email), [Voice](/en/deploy/voice), a helpdesk such as [Zendesk](/en/deploy/zendesk) or [Intercom](/en/deploy/intercom), [Slack](/en/deploy/slack), or your own product over the API. See the [Channel overview](/en/deploy/overview) for the full list.

The surface doesn't change how the agent reasons. The same knowledge, prompts and rules apply everywhere, which is why a cancellation policy question gets the same answer by email in Zendesk as it does in the widget. Two things are surface-aware:

* **Channel Prompts** append per-channel instructions (currently **Email** and **Chat**) to the agent's Main Guidelines, for example shorter replies on chat. See [Prompts](/en/configuration/prompts#channel-prompts).
* **System fields** such as **Integration Provider** and **Channel** are available as conditions in Reply Rules and Rulebook Checks.

Every conversation, from every surface, lands in [Inbox](/en/testing/inbox). Helpdesk conversations are mirrored read-only (your team replies in the helpdesk); widget, UI and native email conversations are editable.

## 2. Reply Rules decide whether the agent engages

Before anything else, [Reply Rules](/en/automations/reply-behavior) (under **Rulebook → Reply Rules**) decide what kind of response the agent may give on this conversation:

| Reply type | What happens |
| - | - |
| **No Reply** | The agent stays silent. No Rulebook tree runs. |
| **Internal Comment** | The agent works the conversation but posts an internal note visible only to your team. This is shadow mode. |
| **Direct Reply** | The agent responds to the customer. |

When more than one card matches, the stricter behavior wins: No Reply over Internal Comment over Direct Reply. This is how teams keep the agent off conversations a human already owns, or internal-only on sensitive intents such as chargebacks or account closure.

## 3. Planning decides what to do with this turn

The agent re-evaluates from the root on every customer turn. The first step is **Planning**: the LLM reads the message and the conversation so far and decides what to do, for example *"this is a how-to question, knowledge search applies"* or *"this is a request to transfer to a human"*.

Planning does two consequential things:

* **Routes to an Intent Rule.** It compares the message against each assigned rule's **Description** and selects the rule whose intent matches. See [How rules get selected](/en/automations/rulebook#how-rules-get-selected).
* **Applies your escalation triggers.** Escalation topics live in the **Knowledge Search – Decision Logic** section of the Planning Prompt. Fini ships defaults (legal or regulatory issues, a customer asking for a human repeatedly) and you add the patterns that matter in your business. A matching trigger routes the conversation to a human and skips knowledge search. See [Controlling when the agent escalates](/en/configuration/prompts#controlling-when-the-agent-escalates).

Fini also classifies the incoming message (**Input Tag Selection**) so the planner knows whether it is a question, an escalation request, a complaint, and so on. Your [Tags](/en/configuration/tags) define the categories.

## 4. Attributes load the customer's context

[User Attributes](/en/api-reference/attributes) fetch customer data from your systems, such as plan, account status, billing date or recent orders. Each attribute's data collection chain runs and reports **Success** or **Failed** in the trace.

Attributes are what turn a generic answer into a personal one. They also drive logic: attributes are available as conditions in Reply Rules, an attribute with **Use in Rulebooks** enabled can be used in Rulebook Checks, and folder-level **Attribute filters** in [Articles](/en/knowledge/articles#attribute-filters) gate which knowledge the agent may retrieve for this customer (for example, Enterprise setup articles only when `plan = Enterprise`).

<Tip>
  A failed attribute is the most common cause of "the agent didn't know something it should have known." The field is `null`, and the agent falls back to a generic answer. Check **Executed User Attributes** in AI Steps first.
</Tip>

## 5a. A Rulebook workflow runs deterministically

If Planning selected an [Intent Rule](/en/automations/rulebook), the runtime walks that rule's behavior tree depth-first. The LLM is used only inside individual nodes; the tree walker decides which node runs next, so identical inputs produce identical execution paths.

| Node | What it does in the conversation |
| - | - |
| **Check** | Tests a condition on system fields, tags, attributes or tree variables. Fails the branch if false. |
| **Read** | Extracts structured information from the conversation into a tree variable. |
| **Tool** | Calls one of your [Actions](/en/api-reference/actions) (refund, cancel, look up) and stores the outputs as tree variables. |
| **Form** | Collects typed input from the customer in the widget, with **Form Error** nodes for validation. |
| **Reply** | Stages instructions for the reply, with `${variable}` placeholders filled from tree variables. |

**Steps** and **Fallback** nodes arrange the leaves into sequences and alternatives. A failed Check short-circuits a Steps sequence, which is how a workflow stops cleanly when a customer isn't eligible. A Reply node can also schedule an [inactivity follow-up](/en/automations/rulebook#inactivity-follow-ups) while the conversation is **Waiting for customer**.

This is the part of Fini that "takes actions." Refunds, cancellations, address changes, card replacements and identity checks run as trees. See the [Cancellation flow walkthrough](/en/walkthroughs/cancellation-flow) for a full build.

## 5b. Or the agent answers from approved knowledge

If no rule matches, or a rule ran but staged no Reply, the agent falls through to default behavior: answering from knowledge, asking a clarifying question, or staying silent, depending on your Reply Rules.

Fini answers from **Articles**, not from raw Sources. Content enters through [Sources](/en/knowledge/sources) and [Magic Articles](/en/knowledge/magic-articles), passes through [Review](/en/knowledge/review), and only approved, published Articles are what the agent treats as authoritative. Articles are scoped per agent with the top-right selector in [Articles](/en/knowledge/articles#assigning-knowledge-to-agents), so a support agent and a sales agent can draw on different folders of the same knowledge graph.

Retrieval is RAGless: Fini does not chunk documents or use embeddings. It uses LLMs to reason over a knowledge graph built from your approved knowledge, so an answer is grounded in reviewed content with its conditions intact. For background, see [What is RAGless](https://www.usefini.com/blog/what-is-ragless).

When the agent used knowledge, the titles of the retrieved articles appear pinned under the reply in Inbox, and the conversation's **Used Folders** appear in its metadata.

## 6. The reply is composed

Reply composition brings together the Reply node instructions (if a rule ran), the retrieved knowledge, the customer's attributes, and your [Prompts](/en/configuration/prompts): **Main Guidelines** for tone, formatting and **Predefined Replies** that must be used verbatim, plus the matching Channel Prompt. In AI Steps, **Generate Answer** shows the agent's **Interaction Reasoning**, **Prompt Reasoning** and **Final Answering Strategy** for every LLM-generated reply.

## 7. Guardrails check the reply before delivery

[Guardrails](/en/configuration/guardrails) check generated replies before delivery, using the policies you configure per agent. Built-in checks cover **Internal reasoning leak**, **Banned terms**, **Confidential attributes**, **URL allowlist** and **AI disclosure**, and you can add up to 10 **Custom rule** checks per agent. Each check can be scoped to specific channels.

| Outcome | What happens |
| - | - |
| **Passed** | The reply is sent unchanged. |
| **Rewritten** | A check found a violation; Fini rewrote the reply once and the rewrite passed. |
| **Escalated to a human** | The rewrite was still unsafe or couldn't preserve the reply. Fini sends a handoff message and marks the conversation for escalation. |
| **Check failed, sent as generated** | A check errored or timed out, and the original reply was sent. |

<Warning>
  Guardrails are not a fail-closed security boundary. Review individual verdicts in AI Steps as well as the overall outcome, and use Reply Rules and Planning escalation triggers for topics the agent must never answer.
</Warning>

## 8. Escalation hands off with the trace

A conversation reaches your human team through any of these paths:

* A Planning escalation trigger matched.
* A Rulebook branch ended in a handoff **Reply** that tells the customer a teammate will follow up, for example because an eligibility Check failed or an Action errored.
* The agent hit an article whose **Escalation** field is set to **Yes** in the article editor.
* A Guardrail couldn't produce a safe reply.
* The customer asked for a person.

On a helpdesk, the human picks the ticket up in the tool they already use, with Fini's internal notes and trace context available. On the widget, [Business Rules](/en/automations/business-rules) run on the **On Escalation** trigger to create the ticket in your destination helpdesk (Zendesk, Front, Salesforce, HubSpot or Gorgias), pass the transcript and attributes, and post a final message to the customer. See [Escalation and handoff](/en/use-cases/escalation-and-handoff).

The same exchange, shown between the people and systems involved. This example follows a conversation where a Rulebook workflow calls one of your Actions.

```mermaid theme={null}
sequenceDiagram
    autonumber
    actor C as Customer
    participant S as Surface<br/>widget, email, voice, helpdesk
    participant F as Fini
    participant API as Your API
    actor T as Your teammate

    C->>S: Sends a message
    S->>F: New message
    Note over F: Reply Rules, then Planning
    F->>API: Load User Attributes
    API-->>F: Plan, status, orders
    Note over F: Intent Rule selected, tree walker runs
    F->>API: Tool node calls an Action
    API-->>F: Action outputs as tree variables
    Note over F: Compose reply, Guardrails check
    alt Guardrails pass or rewrite succeeds
        F->>S: Reply, or internal note in shadow mode
        S->>C: Customer sees the reply
    else Escalation trigger, failed Check, Action error, unsafe reply or customer asks for a person
        F->>S: Handoff, marked as escalated
        S->>T: Ticket with transcript, knowledge used and trace
        T->>C: Teammate replies in their usual tool
    end
    Note over F: Output Tag Selection records the outcome
```

Every escalated conversation is tagged with a reason from a fixed taxonomy (for example **Missing Knowledge**, **API or System Failure**, **Customer requested human – after attempt**, **Guardrail or Safety Trigger**), which is what the [Escalations](/en/analytics#escalations) section of Analytics reports on.

## 9. Tags record the outcome

After each exchange, **Output Tag Selection** applies your tag groups to the conversation, with a **Reasoning** paragraph explaining the choice. The mandatory **Conversation Status** group records whether the conversation is resolved, escalated or waiting for the customer; the Inbox status badge, Reply Rules, **Fini Touched** filters and resolution analytics all read from it.

In [Analytics](/en/analytics), every conversation ends in one of three statuses: **Resolved by AI**, **Escalated to Human Team** or **Waiting for Customer**. **AI resolution rate** counts only conversations Resolved by AI. **Deflection rate** is 100% minus **Human escalation rate**, so it also counts conversations still waiting on the customer. Fini treats resolution rate as the number that matters; see [Resolution vs deflection](/en/performance/resolution-vs-deflection).

## 10. The AI Steps trace shows every step

Open any Fini reply in [Inbox](/en/testing/inbox) and click the light bulb icon to see **AI Steps**, the per-message trace. Sections appear in execution order, and a missing section means that step didn't run:

| Section | What it tells you |
| - | - |
| **Planning** | What the agent decided to do with the turn, verbatim. |
| **Relevant Memories** | Memory summaries used for this reply, when any were used. |
| **Executed User Attributes** | Each attribute fetched, with **Success** or **Failed**. |
| **Executed Rule** | Every rule attempted and every node, with green or red status dots and node-type pills. |
| **Generate Answer** | Interaction Reasoning, Prompt Reasoning, Final Answering Strategy. |
| **Input Tag Selection** / **Output Tag Selection** | How the message and the conversation were classified, with reasoning. |
| **Guardrails** | Per-policy verdicts and the reply outcome. |

Use the trace to answer "why did the agent say that?" for any reply, and to show reviewers and auditors exactly what happened on a conversation.

## 11. The conversation improves the agent

Production conversations are the raw material for improvement. Four loops run off Inbox:

<Steps>
  <Step title="Feedback and Refine with AI">
    Leave feedback on a reply, or use [Refine with AI](/en/testing/fix-with-ai) to describe what went wrong. Fini analyzes the trace, drafts a prompt, knowledge or rule change, and replays the conversation to show the before and after. Nothing is applied automatically.
  </Step>

  <Step title="Generate Knowledge and Magic Articles">
    Turn a conversation into knowledge with **Generate Knowledge** (create a new article, update an existing one, or detect duplicates), or paste raw content into [Magic Articles](/en/knowledge/magic-articles). **Status After Generation** decides whether the draft goes to Review or straight to Published.
  </Step>

  <Step title="Background gap and conflict detection">
    Fini continuously scans your knowledge graph and live conversations for **gaps** and **conflicts** and drafts proposed resolutions. These always land in the **In Review** tab of [Review](/en/knowledge/review), never directly in Published.
  </Step>

  <Step title="Lock it in with Test Suite">
    Turn the conversation into a [Test Suite](/en/testing/test-suite) test case with criteria for the expected behavior. Each run replays the customer's messages, generates new replies and evaluates them against those criteria, so a failed case shows a regression before customers see it.
  </Step>
</Steps>

Approved changes flow into Articles, Prompts or the Rulebook, and the next conversation runs through the same pipeline with the improvement in place.

## Related

<CardGroup cols={2}>
  <Card title="What is Fini" icon="circle-info" href="/en/what-is-fini">
    What Fini is, who it is for, and where it runs.
  </Card>

  <Card title="Intent Rules" icon="diagram-project" href="/en/automations/rulebook">
    The full behavior tree execution model and node reference.
  </Card>

  <Card title="Inbox" icon="inbox" href="/en/testing/inbox">
    Read conversations and the AI Steps trace.
  </Card>

  <Card title="Knowledge overview" icon="graduation-cap" href="/en/knowledge/overview">
    How content becomes approved Articles.
  </Card>
</CardGroup>


## Related topics

- [Fini FAQ](/en/faq.md)
- [What is Fini](/en/what-is-fini.md)
- [RFP fact sheet](/en/evaluate/rfp-fact-sheet.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.