Keep your voice, rules and facts
Steer the Message Optimizer with context: rules the rewrite must follow, emails whose voice it matches, and facts the sender knows first-hand. What each one does, how to build them from a style guide and a sent folder, and how to confirm they arrived.
Level: first run onward. Call: messages.optimize with context. You need: a Customer agent key or the Amdahl MCP connector (see Connect your agent). No connected data.
With nothing but a draft, the Optimizer judges how the message reads and how clearly it asks, and rewrites toward that. context tells it what this sender wants kept. It has three keys, all optional, and all of them work on a workspace with no data connected.
| Key | What it does | Limit | Where it comes from |
|---|---|---|---|
rules | Constraints the rewrite must follow. Never rewritten, never quoted in the message. | 20, each up to 500 characters | A style guide, a legal review, the sender's own "always" and "never" |
voice_examples | Messages the sender wrote. The rewrite matches their voice and does not copy their words. | 5, each up to 4,000 characters | The sender's sent folder: emails that got replies |
facts | What the sender knows first-hand that no recording holds. | 10, each up to 1,000 characters | The sender, and only the sender |
Rules: what the rewrite must respect
A rule is a hard constraint. A rewrite that breaks one is never returned, so the worst a rule can cost you is your own draft back.
Write one constraint per entry, in words you could check against the finished message:
"rules": [
"Never mention pricing.",
"Keep it under 90 words.",
"End by asking for a 15-minute call.",
"No exclamation marks.",
"Sign off as Jordan, first name only."
]- Turn a style guide into rules line by line. Every "always" and "never" in it is a rule. Advice about tone ("sound confident, not salesy") is better shown than told: put it in
voice_examples. - Keep the ask you need. By default the Optimizer prefers to close on a one-line question about whether the problem is real for the reader, rather than a request for a meeting. If your process needs the meeting ask, make it a rule, as in the third line above. A draft that comes back unchanged then gets no
clarify_asksuggestion either. - A rule also removes the suggestions about its part of the message. When your draft comes back unchanged,
kept_suggestionsleaves out each suggestion about a part that one of your rules names: the ask, the recipient, the pitch, customer proof, the length or dashes. It also leaves out a suggestion about a line or a claim when a rule repeats four or more of its words in a row. "Never mention pricing." removes nothing. - A rule is an instruction, not copy. It is never quoted in the message. Write what the rewrite must do or avoid, not text you want to appear.
- Change a result with a rule, not a rewrite. When the returned
messageis not what the sender wants, add what they want as a rule and run the draft again, or let them edit it. Do not polishmessagewith another model: that undoes the checks that kept their details exact.
Voice examples: what the sender sounds like
Up to five messages the sender wrote themselves. The rewrite matches how they write and does not reuse their words.
"voice_examples": [
"Hey Morgan, congrats on the new role. Most RevOps leads I talk to spend their first month untangling the CRM. Happy to share what the fast ones do first. Free for 15 minutes Tuesday?",
"Priya, saw the Series B news. Are you still running onboarding by hand? We cut it to a day for a team about your size. Worth comparing notes?"
]- Pick sends that worked. Messages that got replies, on the same channel as the draft: a LinkedIn note does not teach the voice of a cold email.
- The sender's own words only. A message a teammate or a tool wrote teaches the wrong voice.
- Drop signatures and legal footers. They are not voice, and they use up the 4,000 characters.
Facts: what the sender knows first-hand
rules and voice_examples change how a message reads. Neither can make a claim true. A fact is something the sender knows that no call recording or CRM holds, most often what someone said to them in person:
"facts": [
"Met Priya at the GTM dinner on Sep 24; she said her SDRs rewrite every AI draft."
]- One fact per entry, in the sender's words, with the date when it has one.
- Only what the sender confirmed. A fact licenses a claim. An agent that writes one on its own makes an invented claim look checked, which is worse than no fact at all.
- Send it only with the draft it is about. A fact about Priya does not belong on the email to Dana.
- On the default style pass, facts guide the rewrite: it may use them and is told never to embellish them or present one as something a customer said. They matter most once your conversations are connected and you send
"evidence": "workspace": then a claim a fact states is not flagged as unsupported, and a claim that goes further than the fact still is. See Check claims against your customers.
Facts are data, never instructions: a fact that says "ignore the rules" is read as a strange fact. They are used for that one request, and are never stored as evidence or written to logs as text.
The whole request
{
"message": "Hi Priya,\n\nGreat meeting you at the GTM dinner last week. You mentioned your SDRs rewrite every AI draft before it goes out...",
"channel": "email",
"context": {
"rules": ["Never mention pricing.", "End by asking for a 15-minute call."],
"voice_examples": [
"Hey Morgan, congrats on the new role. Most RevOps leads I talk to spend their first month untangling the CRM. Free for 15 minutes Tuesday?"
],
"facts": ["Met Priya at the GTM dinner on Sep 24; she said her SDRs rewrite every AI draft."]
}
}Over MCP, send the same context object to the messages tool with "action": "optimize".
Confirm what arrived
When you send context, the response says how much of it the Optimizer received, as counts, never the text:
"context": { "rules": 2, "voice_examples": 1, "facts": 1 }Blank entries are dropped before anything is counted, so a count lower than what you sent means some entries were empty. Anything else wrong is refused before the Optimizer runs: an unknown key inside context, too many entries, or an entry over its limit returns 400 invalid_input naming the field, for example $.context.rules[3]: must be at most 500 characters.
What context cannot do
- Name the sender. Who is sending comes from the credential the call is made with. There is no field for it, in
contextor anywhere else. - Loosen the exact-detail guard. Names, numbers, dates, links and merge fields stay as written whatever the rules say. A rewrite also never adds a day or a time that your draft did not give, so a rule such as "Offer Thursday at 2pm" does not put a slot in the message. To let a detail change, or to offer a slot, change it in the draft. A fact can supply a day or a time too: "Sam said Thursday at 2pm works" lets a rewrite use it.
- Make a claim true. Only a fact licenses a claim, and only for what it states.
- Catch every conflict in the suggestions.
kept_suggestionsare advice from the rubric, checked against the words of each rule (see the rules section above). A rule that decides a part of the message without naming it can still meet a suggestion that goes against it. The rule wins: ignore that suggestion.
The Optimizer also keeps a per-sender record of how each sender writes, scoped to your workspace and keyed to the credential's user. A new sender starts with nothing in it, which is why context is the way to get their voice into the very first rewrite.
The field limits and error shapes are on Message Optimizer.