A campaign is the container for how a set of qualified accounts gets approached. It holds the sequence, the message rules, the sending identity and the conditions under which it stops. It does not hold a list of contacts — accounts enter and leave as their qualification changes.
Campaign anatomy#
- audiencequeryrequired
- Which qualified accounts belong here, expressed as conditions on tier, ICP, window state and evidence family — not as an uploaded list. An account that stops matching leaves the campaign on its own.
- sequencestep[]required
- The ordered steps, their delays and their intent. See below.
- identitymailbox[]required
- Which mailboxes may send for this campaign, and the from-name and signature used. See connecting a mailbox.
- windowsend_windowrequired
- The recipient-local hours and days sending is permitted. Defaults exclude nights and Sundays; see send windows.
- approvalalways | threshold | neverrequired
- Whether a human reviews before send. A-tier accounts are always reviewed regardless of this setting.
- stop_conditionscondition[]optional
- What halts the campaign automatically. Every campaign gets a default set; you can add to them but not remove the safety ones.
Sequences and steps#
A step has an intent, not just a delay. The intent constrains what the message is allowed to do, which is what stops a follow-up from being the first message with “just bumping this” on top.
| Intent | The message may | The message may not |
|---|---|---|
| Open | State one specific observation about the company and one consequence of it. | Ask for a meeting on a specific date, or attach anything. |
| Substantiate | Add a second piece of evidence, or a concrete example of the consequence. | Repeat the opening claim in different words. |
| Redirect | Ask whether someone else owns this, and offer to stop. | Restate the pitch. |
| Close | State plainly that this is the last message and how to reopen it. | Contain a new argument, or a deadline the sender invented. |
Default sequence lengths follow tier: two steps for A, three or four for B. There is no seven-step sequence available, because by step five the evidence that justified contact has usually decayed past the point where the messages can honestly refer to it.
Message generation#
Messages are generated per account from that account’s evidence, under three hard constraints.
- Every factual claim must map to an evidence record. Generation is given the records, not the internet. A draft containing an unsupported claim is rejected and regenerated, not published with a hedge.
- One claim per message. Two observations in an opening message read as research theatre and dilute both.
- The ask is proportionate to the evidence. Moderate evidence produces a question. Strong evidence, stacked, produces a request for a conversation. Weak evidence does not produce a message at all.
Voice comes from your own material — the same sources the ICP builder read, plus any messages you have edited. Editing a draft is the highest-signal correction available; the edit is kept and the difference is what teaches the generator, not a star rating.
{
"id": "MSG-90144",
"account_id": "ACC-19022",
"campaign_id": "CMP-204",
"step": 1,
"intent": "open",
"subject": "second depot + ops hire",
"claims": [
{ "text": "you have opened a second depot", "evidence": "EV-2308" },
{ "text": "and are hiring your first Head of Operations", "evidence": "EV-2291" }
],
"unsupported_claims": [],
"approval": "pending",
"queued_for": "2026-08-05T09:00:00+01:00"
}unsupported_claims should always be empty. If it is not, the draft is held and flagged — that array existing at all is the check, and it is why the generator cannot quietly invent a detail to make a sentence flow better.
Variants and the bandit#
Campaigns can carry several variants of a step. They are not split evenly and no significance claim is ever made, because the arithmetic does not support one: reaching a reliable verdict between two variants needs far more positive outcomes per arm than a normal workspace produces in a quarter.
Instead, allocation is adaptive. Variants that are producing classified positive outcomes receive more of the traffic; variants that are not receive less, but never zero, so a variant that was unlucky early can recover.
- Allocation
- adaptive, minimum 10% floor per active variant
- Outcome measured
- classified reply, weighted by classification
- Opens / clicks
- not measured — tracking is off by default
- Significance claims
- none
Stop conditions#
Every campaign halts itself on the conditions below. The first four cannot be removed; they are the difference between an automated system and an unattended one.
| Condition | Default | Removable |
|---|---|---|
| Hard bounce rate over a rolling window exceeds a threshold | 3% | No |
| Spam complaint received | Any | No |
| Unsubscribe or explicit opt-out from the domain | Any | No |
| A reply is received from the account | Any | No |
| Reply classified as not interested | Any | Yes |
| Account leaves the audience query | Any | Yes |
| Daily send volume for a mailbox is exceeded | Per mailbox cap | Yes |
| Manual pause | — | — |
A reply stops the sequence for that account immediately, including replies that arrive while a later step is already queued. This is checked at send time as well as at queue time, because the gap between the two is exactly where the embarrassing follow-up gets sent.
Approvals#
Approval is a review queue, not a rubber stamp. Each item shows the draft, the claims it makes, the evidence behind each claim and the decision record that qualified the account.
| Action | Effect | Feeds back as |
|---|---|---|
| Approve | Queued for the next slot in the send window | Nothing — approval is the neutral action |
| Edit and approve | Your version is sent | A diff, used to correct voice and structure |
| Reject draft | Regenerated once with your reason as a constraint | A generation constraint for this campaign |
| Reject account | Removed from the campaign, account demoted | A candidate ICP exclusion |
Rejecting the account is a stronger action than rejecting the draft and they are kept separate deliberately. “This message is wrong” and “this company is wrong” are different corrections, and collapsing them into one button loses the more valuable half.
Next: sending — what happens to an approved message.