---
title: Support
description: "A support agent that answers from what was promised and shipped, not the thread in front of it."
---

In support, the world model is one current picture per account: what the customer is entitled to, what is broken for them, what has been promised in writing, and what the agent must not say. When a support agent picks up a ticket from Northwind, an enterprise customer, the thread in front of it (or a CRM card someone pasted in) is rarely Northwind's actual situation. A belief state that lives outside the model holds that situation instead, so the agent reads the account's real state before every reply rather than answering from the thread.

## The world

The **environment** is the account. The customer, their plan and entitlements, their open and historical tickets, and the relationships that tie those together. This ticket is the third recurrence of that export bug. This requester is the org admin, so what they ask for actually moves billing. Ground truth is split across the helpdesk, the CRM, and the running product, which is precisely why no single message holds it.

## What streams in

The agent's **observations** arrive from everywhere the relationship lives:

- support tickets and their status changes
- chat and email transcripts
- internal Slack threads about the account
- CRM fields, billing events, and entitlement changes

Each one revises what the agent believes about the account: its current state, and what it is allowed to do next.

## The belief state

The account's live state is a set of claims. Each carries an explicit posterior and its provenance, sitting next to the gaps the agent knows it hasn't filled.

```
┌──────────────────────────────────────────────────────────────┐
│  ACCOUNT STATE - Northwind Co.                               │
│                                                              │
│  ● "On the Enterprise plan (SSO + priority SLA)"  98% │ CRM  │
│  ● "Export to CSV times out on >50k rows"         88% │ 3 tix│
│    └─ recurrence of BUG-4471 (supersedes "one-off")          │
│  ● "Promised a fix by Friday in writing"          80% │ email│
│  ● "Churn risk: renewal in 40d, owner went quiet" 61% │ Slack│
│                                                              │
│  Gap: "Has the export fix shipped to their region?"          │
│  ⚠ Contradiction: agent A said "fix shipped"; the build      │
│    record shows the account is still on the old build        │
└──────────────────────────────────────────────────────────────┘
```

Read the percentages as the agent's confidence, each tied to a source it can name. The plan is near-certain because it comes straight from CRM. The churn read sits at 61% because it rests on one quiet account owner and a months-old outage, not a hard signal. The agent knows the difference, so it leans hard on the plan and treats the churn read as a hypothesis worth a call.

When two agents touch the same account, their pictures fuse into one. "We already told them it's fixed" and "it isn't fixed for them yet" cannot coexist quietly. They surface as a flagged contradiction before they become a second broken promise.

## What we're after

The **intent** is to resolve the customer's issue without over-promising. Success is a correct answer that stays inside the account's entitlements and SLA, with nothing committed that engineering hasn't. The limiting factor is the unverified account fact most in the way of that answer, here whether the export fix has actually shipped to their region.

| | |
|---|---|
| **Goal** | Resolve the issue without over-promising. |
| **Success** | A correct, in-entitlement, in-SLA answer; no uncommitted promises. |
| **Limiting factor** | "Has the export fix shipped to their region?" |

The engine ranks the agent's next moves against this intent, not against raw uncertainty. A fact the agent is unsure about only rises to the top when closing it actually moves the goal.

## The policy

A support world has firm rules that hold no matter what any single reply wants to say:

| Policy bucket | In a support account |
|---|---|
| **Invariants** | Never promise an unshipped feature or a date engineering hasn't committed. Honor the plan's entitlements, no more. |
| **Source hierarchy** | Billing and CRM state lead a chat claim. A shipped build leads a "should be fixed soon." |
| **Conventions** | Tone, escalation path, when to loop in the account owner. |
| **Avoid** | Issuing credits beyond authority. Speculating about root cause on the record. |

When two sources disagree, the hierarchy decides which one the agent trusts. The build record beats the optimistic chat note every time.

## The actions

What the agent may do in this world, classified by blast radius:

| Action | Safety class | Effect |
|---|---|---|
| `tag`, `summarize`, `lookup-entitlement` | **info** | Read-only. |
| `reply`, `escalate`, `update-ticket` | **mutates** | Changes the account's record or the customer's experience. |
| `issue-refund`, `grant-exception` | **needs-approval** | Gated on a human with the authority. |

Today, policy and actions are a modeling lens you encode. You express the invariants, the source hierarchy, and the safety classes in *how* your agent observes and acts. The engine doesn't yet take a registered policy and enforce it for you; a declarative config surface is on the roadmap. So treat these tables as the contract your agent enforces, not one the engine enforces on its behalf. What the engine supplies is the picture each decision rests on, plus a record of what every action changed, so a supervisor can audit it after the fact.

## Plan & act

```ts
import Beliefs from 'beliefs'

const beliefs = new Beliefs({
  apiKey: process.env.BELIEFS_KEY,
  agent: 'support-agent',
  namespace: 'acct:northwind',
  writeScope: 'space',
})

// 1. Orient: read the current picture; the ranked next moves ride back on it
const context = await beliefs.before('Customer asks if the export bug is fixed for them')
const [move] = context.moves   // top-ranked, already in hand; no extra call
// → { action: 'gather_evidence', subType: 'check-deploy-region', valueOfInformation: 0.8, ... }

// 2. Act: your agent dispatches the tool the move points to
const deploy = await runTool(move.subType)   // 'check-deploy-region' → your deploy-status lookup

// 3. Fold the result back in; it becomes the next observation
await beliefs.after(JSON.stringify(deploy), { tool: 'deploy_api', source: 'release' })
```

Here the move the engine ranks first is `check-deploy-region`, not `reply`. The agent holds an 80% promise and a build record that disagrees with a teammate, so the highest-value thing it can do is close the gap before it answers. That is the judgment a recall layer can't make. A RAG store would hand the agent the cheery chat note and the promise email with equal weight and let it confirm a fix that never shipped to that region. thinkⁿ ranks the lookup above the reply, and once the deploy result folds back in, the agent answers from what is true for that account. The audit trail comes with it: every belief the agent leaned on, and what each action changed, is on the record for a supervisor to walk back.

<Callout type="info" title="Emerging: plan several moves ahead">
As an account accumulates history, the agent can forecast which move most reduces churn risk before it acts: `beliefs.forecast.predict(['escalate', 'offer-workaround', 'schedule-call'])`. These forecasts stay deliberately low-confidence until the workspace has enough resolved outcomes to calibrate them against what actually happened.
</Callout>

<CardGroup cols={2}>
  <DocsCard title="Operations" description="A production line as a world model: equipment, inventory, and safety policy." href="/dev/cases/operations" />
  <DocsCard title="World model" description="The full frame: environment, observations, belief, policy, actions." href="/dev/core/world" />
</CardGroup>
