Check claims against your customers
Once your conversations are connected, send evidence: workspace and the Message Optimizer also checks a draft against what your own customers said. It lists the claims nothing backs and keeps them unless you say otherwise. When to turn it on, how to read it, and when the full eval is the better call.
Level: once your data is connected. Call: messages.optimize with "evidence": "workspace". You need: a Customer agent key or the Amdahl MCP connector, and a workspace with synced conversations.
Everything in the other Optimizer cookbooks works with nothing connected: the default is a style pass that judges how a draft reads and how clearly it asks. This is the step after. Connect your CRM and call recorder, and the same call can also check what the draft claims against what your customers actually said, and tell you which claims nothing backs.
Check there is something to read
Evidence needs synced conversations. GET /search/overview returns a row count per surface; anything above 0 on interactions means there is something to grade against:
curl -s "https://app.amdahl.ai/api/platform/v1/search/overview" -H "X-API-Key: $AMDAHL_KEY" | jq '.data.surfaces[] | {surface, row_count}'If the counts look low, check that your sources are still syncing. GET /setup/status (over MCP, the connections tool with "action": "setup_status") lists every connection that needs attention, under needs_attention in its connections section, for example one that needs you to sign in to the source again. See Check your setup.
On a workspace with nothing synced yet the call below still succeeds. It is graded as a style pass, and the response says so in evidence.reason.
The call
The same request as always, plus one field:
{
"message": "Hi Priya,\n\nSaw Ledgerline moved invoicing in-house last quarter. Most finance teams we work with lose a week at every month-end close after a move like that.\n\nTallyworks reconciles every invoice as it lands, and teams like yours close 60% faster in the first month.\n\nWorth 15 minutes on Thursday?\n\nJordan",
"channel": "email",
"evidence": "workspace"
}It is slower than the style pass, because each grading reads quotes from your conversations. Keep the 180-second client timeout.
What changes
Default (evidence off) | evidence: "workspace" | |
|---|---|---|
| Graded on | How the draft reads and how clearly it asks | That, plus four dimensions against your customers' own words: relevant_positioning, grounding, verified_specifics and differentiation |
| Claims | Not checked. unsupported_claims is null. | Each claim nothing in your conversations backs is listed in unsupported_claims, and kept in the message unless you say otherwise |
| The rewrite | Written from the draft and your context | Also reads up to 8 customer quotes, to ground what it says. It never quotes them or presents them as the recipient's words. |
| Before and after | No score: a second model re-checks the rewrite on yes/no questions | lift: your draft and the rewrite re-graded blind against the same quotes, when a rewrite reached that re-grade |
| Speed | Usually under 30 seconds | Slower |
Read evidence first
"evidence": { "requested": "workspace", "used": true }Say a draft was checked against your customers only when used is true. When it is false, reason says why, and none of these is an error (the rewrite still came back):
reason | What happened |
|---|---|
corpus_empty | The workspace has no conversations to read yet. |
evidence_unavailable | This environment does not read customer conversations, so the run was a style pass. |
evidence_read_failed | The read failed and the four evidence dimensions were not graded. A retry may succeed. |
Claims nothing backs
This response is illustrative: the company and its claims are made up. Its shape is exactly what the live API returns, trimmed to the claim fields and two notes.
{
"data": {
"ok": true,
"unchanged": true,
"summary": "Kept your version: the rewrite dropped a claim this request asked to keep, so it was discarded. Nothing in your workspace's conversations backs 3 claims in this message. Check them before you send it.",
"evidence": { "requested": "workspace", "used": true },
"on_unsupported": "flag",
"unsupported_claims": [
{
"span": "Saw Ledgerline moved invoicing in-house last quarter",
"kind": "about_recipient",
"why": "No conversation with Ledgerline mentions this, and no fact was sent with the draft.",
"dimension": "grounding",
"status": "kept",
"fix": [
{ "action": "add_fact", "how": "if it is true, re-run with context.facts: [\"Saw Ledgerline moved invoicing in-house last quarter\"]" },
{ "action": "add_evidence", "how": "cite a source, or run evals.run with include_external" },
{ "action": "rephrase" }
]
},
{
"span": "Most finance teams we work with lose a week at every month-end close after a move like that",
"kind": "product_or_outcome",
"why": "Customers describe slower closes after a systems change, but none puts it at a week.",
"dimension": "grounding",
"status": "rewrite_rejected",
"fix": [{ "action": "rephrase" }]
},
{
"span": "teams like yours close 60% faster in the first month",
"kind": "about_recipient",
"why": "No quote states a close-time figure.",
"dimension": "verified_specifics",
"status": "kept",
"fix": [{ "action": "add_evidence", "how": "cite a source, or run evals.run with include_external" }, { "action": "rephrase" }]
}
],
"notes": [
{
"code": "unsupported_claims_kept",
"audience": "developer",
"says": "3 claims couldn't be matched to your workspace's conversations. See unsupported_claims before sending. They were kept because on_unsupported is flag. Ask the user about each one. If it is true, re-run with it in context.facts. If it has a source, add the evidence. Otherwise, offer to re-run with on_unsupported: \"remove\". Never remove one without asking."
},
{
"code": "rewrite_rejected_for_claim_loss",
"audience": "developer",
"says": "A rewrite was discarded because it dropped 1 of the claims this request asked to keep (on_unsupported: flag). The previous version stands. The score played no part in this."
}
]
}
}Each entry is one claim, copied exactly from the draft in span, with what happened to it in status:
kept: still in the returned message. By default (on_unsupported: "flag") every claim stays, because it may be the one thing the sender knows and the conversations do not.rewrite_rejected: still there because a rewrite that dropped it was thrown away. Here that is why the whole draft came back unchanged.removed: the rewrite cut or softened it. That only happens when you asked for it.
While any claim is still in the message, do not call the draft ready, and neither will summary. Go through them with the sender, one at a time:
- True, and they know it first-hand? Re-run with it in
factsinsidecontext, in their words. A fact that states the claim clears it; one that says less does not. See Keep your voice, rules and facts. - It has a source (a press release, a public case study)? Cite it, or check it with
evals.runandinclude_external. - Neither? Offer to re-run with
"on_unsupported": "remove", which lets the rewrite soften or cut the listed claims, or let the sender reword it.
Never re-run with remove without asking. And neither mode changes the grade: a claim nothing backs still fails grounding.
Reading lift on an evidence run
When a rewrite reaches the blind re-grade, lift carries the before and after on a 1 to 5 scale, with what was measured (the numbers here are illustrative):
"lift": {
"before": 3.14,
"after": 3.71,
"delta": 0.57,
"method": "blind_regrade_pinned",
"dimensions": ["cta_clarity", "differentiation", "grounding", "human_tone", "length_discipline", "relevant_positioning", "verified_specifics"],
"quotes": 20,
"returned": "rewrite"
}A different model from the one the rewrite was chosen with grades your draft and the rewrite, one call each, neither told which is which, against the same quotes. quotes says how many it read. It is the only before-and-after score in the response, so it is the only one to quote, and it is null whenever nothing reached the re-grade (as in the kept draft above). Field by field: Reading lift.
To show a person how the draft got there, add "include_tries": true: tries lists every version the run scored, draft first. Those scores come from the Optimizer's own grader during the search, so they show the path, not proof. Never quote the first try against the last as an improvement; quote lift. See Reading tries.
Optimizer or eval
Both read the same conversations. They answer different questions:
| You want | Use |
|---|---|
| A better version of this draft, in the sender's voice, with the claims nothing backs flagged | The Optimizer, with evidence: "workspace" |
| Every rubric line passed or failed, with the customer quotes behind each verdict | The eval |
| A better prompt for the agent or template that writes the drafts | The eval, in its default rewrite mode |
| A send or hold bit for a pipeline | The eval with mode: "gate". See Gate before send. |
To use both on one message, run the eval first to get the claims grounded, then optimize the grounded version into the sender's voice. Keep the two verdicts apart in whatever you hand back: see Keep two verdicts apart.
Every field is on Message Optimizer.