act · sequences and steps
Contact policy
Caps, quiet hours and never-contact.
In Sequences and steps
The contact policy is the set of rules that sits above every sequence and every move: who may be contacted, how often, through which channel and when. A sequence asks for a step; the policy decides whether it may go out, delays it, or blocks it and says why. This page lists fifteen rules, the order they run in, and how blocks become training data.
sequence library → steps · the parts → templates · the words → next-best-action · the choice → contact policy · the limits
The policy wins — No sequence, play or campaign can override it. Changing a rule is a versioned change, not an exception.
Blocks are logged — Every block is a row naming the rule, so "we chose not to send" can be studied.
Stop is permanent — A stop request, a block or a report ends contact on every channel and account.
in industry terms
A contact policy is frequency capping plus suppression plus consent.
Marketing platforms split this into suppression lists (never contact), frequency caps (how often) and send windows (when). Sales tools add a rule that only a person sends the first message. Writing them as one policy, checked in one place, is what keeps a growing set of sequences from piling onto the same person.
who — Suppression · Never-contact, stop requests, customers' staff, competitors, people in another campaign.
how often — Frequency caps · Per person, per thread, per day, per account.
when and how — Windows and channel rules · Quiet hours, community rules, platform limits, email law.
how it works
The order the rules run in.
Cheapest and hardest rules first. A move that survives every check goes out; one that hits a delay rule is rescheduled; one that hits a block rule is logged and dropped.
- Move — from the engine
- Suppression — never, stop
- Person caps — DMs, unanswered
- Channel rules — community, limits
- Windows — quiet hours, daily cap
- Allowed — to the founder never
- Block — logged later
- Delay — rescheduled
| Action | Means | Logged as |
|---|---|---|
| block | the move never goes out | policy_block(rule_id, move_id, lead_id) |
| delay | the move waits for the window or tomorrow's cap | policy_delay(rule_id, until) |
| require founder | the move can only be sent by the founder by hand | policy_gate(rule_id) |
| exit | the sequence ends for this person | sequence_exit(reason) |
| never-contact | the person is added to the suppression list | never_added(reason, source) |
the object
The rule, and a block.
Each rule is a versioned record; each block is a row.
| Field | Type | What it holds |
|---|---|---|
rule_id | string | pol.<name> |
version | integer | Bumped on any change to scope, condition or parameters. |
scope | enum | person · thread · community · account · founder_day · channel |
condition | expression | When it applies, in the segment rule grammar. |
action | enum | block · delay · require_founder · exit · never_contact |
params | json | The numbers: max_dms, max_unanswered, window hours. |
block.move_id | id | The move it stopped. |
block.lead_id | id | Who it protected. |
block.would_have_sent | text | The draft that didn't go out, kept as a negative example. |
block.at | timestamp | When. |
one record, as data
{
"rule_id": "pol.one-dm",
"version": 1,
"scope": "person",
"condition": "dms_sent >= 1",
"action": "block",
"params": {
"max_dms": 1
},
"block": {
"move_id": "move_…",
"lead_id": "lead_…",
"would_have_sent": "…",
"at": "2026-10-22T14:03:00Z"
}
}the catalog
Fifteen rules, by scope.
Person rules protect one human; volume rules protect the founder's day and the audience; platform rules protect the accounts; time rules decide when.
pol.first-message-by-founder — Person
The founder sends every first message
VibeDraft drafts; the founder sends. Nothing goes to a stranger automatically.
- scope
- every lead
- action
- require founder
- why
- trust, platform rules, and the product's own rule
pol.one-dm — Person
One private message per person, ever
A DM is spent once. Put the offer in it, not a hello.
- scope
- person, all channels
- action
- block
- param
- max_dms = 1
pol.two-unanswered — Person
At most 2 unanswered messages
Two in a row with no reply and the sequence stops for that person.
- scope
- person
- action
- exit
- param
- max_unanswered = 2
pol.founder-msgs — Person
3 founder messages per person
Hand-sent steps are capped so one lead can't eat the day.
- scope
- person, per campaign
- action
- block
- param
- max_founder_msgs = 3
pol.one-campaign — Person
One campaign per person
At most one owns a person at a time.
- scope
- person
- action
- exclude at segment
- param
- in_campaign = false
pol.stop-words — Person
Stop means stop, immediately
"Stop", "not interested", an unsubscribe, a block or a report ends contact for good.
- scope
- person, all accounts
- action
- never-contact
- why
- the most important guardrail
pol.never — Person
Never-contact list
Customers' staff, competitors, people who asked to stop, and anyone on the founder's never list.
- scope
- person
- action
- block
pol.daily-cap — Volume
5 follow-ups a day
A daily cap across all sequences. Overflow waits for tomorrow, in rank order.
- scope
- founder, per day
- action
- delay
- param
- max_followups_day = 5
pol.thread-cooldown — Volume
One reply per thread
Don't reply twice in the same public thread unless they answered you.
- scope
- thread
- action
- block
- why
- looks like spam to everyone else in it
pol.community-rules — Platform
Follow each community's rules
Many subreddits and groups ban self-promotion or links. Their rules override any sequence.
- scope
- community
- action
- block links or the whole step
- why
- removals and bans
pol.rate-limits — Platform
Platform rate limits
Respect the API and account limits of X, Reddit, Threads, Instagram and TikTok.
- scope
- account
- action
- delay
- why
- account health
pol.email-law — Platform
Email: honest sender, working unsubscribe
Commercial email needs an honest sender and a working opt-out (CAN-SPAM in the US). Cold email to people in the EU needs a lawful basis; check before sending.
- scope
- action
- block without consent or opt-out
- why
- law
pol.quiet-hours — Time
Quiet hours
Steps send inside the person's waking hours when their timezone is known; otherwise inside the founder's.
- scope
- person
- action
- delay
- param
- send window 8:00 to 20:00 local
pol.cross-account — Person
One voice per person across your accounts
If you run several accounts (a personal one and a product one), only one of them works a given lead.
- scope
- person, all your accounts
- action
- block the second account
- why
- two accounts pitching one person reads as spam
pol.log-blocks — Volume
Log every block
A blocked step is a row with the rule that blocked it, never a silent skip.
- scope
- every decision
- action
- log
- why
- negatives are training data
failure modes
What goes wrong, and how to catch it.
How each one shows up, and the check that catches it before it costs a week.
| Failure | How it shows up | How to catch it |
|---|---|---|
| Silent skips | Moves vanish and nobody knows why | Every block and delay is an event with its rule |
| Cap overflow order | Tomorrow's capped moves go out stale | Overflow keeps rank order and is re-scored before sending |
| Unknown timezone | Messages land at night | Fall back to the founder's timezone and a narrow window |
| Two accounts, one person | The same founder gets pitched by both accounts | A cross-account lock on the lead |
| Stop not propagated | They said stop on Reddit, got an email | Stop is person-level, written to the never list, checked on every channel |
data to capture
Record it so a model can learn from it later.
Follows the guide's eight data-spine rules: log the decision, version what decided, freeze the inputs, keep the negatives, log the odds, treat every human touch as a label, keep one chain of ids, keep the raw.
record
- every policy decision: rule, version, move, lead, action, time
- the draft that would have gone out, for blocked moves
- overrides, if a founder ever forces a send, with the reason
- stop requests with where they came from
label
blocked moves as negatives; stop requests and reports as the strongest negative label
trains
whether a cap costs conversions or protects them, and a model of who is about to ask you to stop
test
cap levels and window lengths · randomized between campaigns, guarded by stop-request rates