phase 3 · act
Sequences and steps
Go deeper
A sequence is a playbook's messages in order: which step goes out, on which day, on which channel, who sends it, and what ends it. Steps are reusable components, so one "follow-up DM" step can sit in ten sequences and be tested once. This page defines both objects, then lists 17 step components and 12 sequences built from them.
playbook · the strategy → campaign · one run of it → sequence · the steps, in order → step · one component → touch · one message sent
rule 1 — Steps are components, not copy. · A step is a type, a channel, a wait, a template and its exit rules. Build it once and reuse it everywhere.
rule 2 — Every step has a way out. · A reply, a stop request, a signup or a bounce ends the sequence for that person. No step runs blind.
rule 3 — Every sent step leaves a touch_id. · That id travels into links, replies and signups. Without it, nothing after "sent" can be learned.
what it is
A sequence is a cadence. A step is a touch.
Sales tools call the same thing a sequence or a cadence: an ordered set of touches with waits between them, run on one person until they reply or the steps run out. Here a playbook says why and what to offer; the sequence says exactly what goes out, and when.
Sequence — cadence · outreach sequence · Ordered steps with day offsets and exit rules. Belongs to one playbook; many campaigns can run it.
Step — touch · task · One unit: reply, DM, email, post, wait, branch or hand-off. A reusable component with its own template and variants.
Exit rule — stop condition · What ends the sequence for one person: replied, asked to stop, converted, bounced, or out of steps.
Contact policy — frequency cap · guardrail · Limits that sit above every sequence: how often one person can be messaged, by whom, and when never.
static sequence — A fixed script · Day 0 reply, day 2 follow-up, day 7 email. Easy to read, easy to test one step at a time. Breaks when a person does something the script didn't expect.
dynamic sequence
One best move at a time
Each day, rank the possible next steps for each lead and take the best one the contact policy allows. The library below still matters: its steps are the moves the engine chooses from.
the objects
Two objects: the step, and the sequence that orders them.
Write a step down in this shape before it goes in any sequence. If a field is blank, the step isn't ready: usually the exit rule or the sender is missing.
| Step field | What it holds |
|---|---|
step_id | Stable id, e.g. step.dm.follow_up. Never reused for a different step. |
version | Bumped whenever the template, wait or exit rules change, so results never mix versions. |
type | One of the 16 components below: public_reply, dm, follow_up_dm, email, wait, branch, task… |
channel | Where it goes out: Reddit thread, X reply, X DM, email, Threads, your own post. |
wait | Offset from the previous step ("+2 days") or from the trigger ("day 0"), plus a send window in the person's local time. |
template | Template id and its variants (A, B…). Each variant carries a prompt version, so drafts are comparable. |
sender | you (founder sends by hand), scheduled (queue posts it at the time) or system (no message, e.g. a wait). |
condition | When this step runs at all: only if they replied, only if the reply was positive, only on day ≥ 3. |
exit | What ends the sequence for this person: replied, asked to stop, converted, bounced, out of steps. |
tracked_link | Optional short link whose clicks carry the touch_id back. |
emits | touch_id on send; a blocked step emits the policy rule that blocked it instead. |
| Sequence field | What it holds |
|---|---|
sequence_id | Stable id, e.g. seq.lead_to_waitlist. |
version | Bumped when any step is added, removed or reordered. |
playbook | The play it belongs to, from the Playbook Library. |
goal | The one rung it's trying to reach: reply, waitlist join, trial, payment. |
entry | Who may start it: tier, trigger, freshness, never already in a campaign. |
steps | Ordered list of step_id + version + offset. |
exit | Sequence-wide exits, on top of each step's own. |
policy | The contact policy it runs under. |
{
"sequence_id": "seq.lead_to_waitlist",
"version": 3,
"playbook": "lead-to-waitlist",
"goal": "waitlist_join",
"entry": {
"tiers": [
"Hot",
"Warm"
],
"fresh_within_h": 72,
"not_in_campaign": true
},
"steps": [
{
"step_id": "step.public_reply",
"version": 2,
"offset": "day 0",
"channel": "reddit_thread",
"sender": "you",
"template": {
"id": "tpl.helpful_reply",
"variants": [
"A",
"B"
]
},
"exit": [
"asked_to_stop"
],
"note": "never names the product, never links"
},
{
"step_id": "step.light_touch",
"version": 1,
"offset": "after they answer",
"channel": "same_thread",
"sender": "you",
"condition": "replied"
},
{
"step_id": "step.send_brief",
"version": 4,
"offset": "next",
"channel": "dm",
"sender": "you",
"template": {
"id": "tpl.brief_offer",
"variants": [
"A"
]
},
"tracked_link": true
},
{
"step_id": "step.nudge",
"version": 1,
"offset": "+3 days",
"channel": "same_dm",
"sender": "you",
"condition": "no_reply",
"exit": [
"replied",
"asked_to_stop",
"joined_waitlist"
]
}
],
"exit": [
"joined_waitlist",
"asked_to_stop",
"out_of_steps"
],
"policy": "policy.default",
"emits": [
"touch_id per sent step",
"policy_block per blocked step"
]
}the library
17 step components, 12 sequences built from them.
Then the sequences, each shown as its chain of steps with day offsets. you marks a step the founder sends by hand; scheduled goes out from the queue; system needs no message at all. Nothing goes to a stranger automatically.
Step components
Reach · the first touch in a public or private place
step.public_reply — you
Public reply
- channel
- Reddit thread, X reply, forum
- wait
- day 0, within the trigger's freshness window
- exits
- replied · asked to stop
- records
- thread url, reply text, draft vs sent, minutes from signal to reply
Helpful first, no link, never names the product. The answer is the pitch.
step.dm — you
Direct message
- channel
- X DM, Reddit chat
- wait
- only after a public touch, or when they asked
- exits
- replied · asked to stop · blocked
- records
- touch_id, text, whether they had engaged first
The contact policy allows one per person ever. Spend it on the brief, not a hello.
step.email — scheduled
- channel
- wait
- day 0 for warm lists; never to a scraped address
- exits
- replied · unsubscribed · bounced
- records
- touch_id, subject, opens if tracked, bounce class
Only to people who gave you the address: signups, waitlist, past customers.
step.comment_keyword — scheduled
Comment-a-keyword reply
- channel
- X, Threads, Instagram
- wait
- minutes after they comment the keyword
- exits
- delivered · asked to stop
- records
- post id, keyword, commenter, delivery status
They asked for it by commenting, so the reply is expected. The reply carries the tracked link.
Follow up · a second or third touch after the first
step.follow_up_dm — you
Follow-up DM
- channel
- same DM thread
- wait
- +2 to +4 days, only if no reply
- exits
- replied · asked to stop · out of steps
- records
- touch_id, days since last touch, reply class
One nudge, then stop. Ask a question they can answer in one line.
step.email_follow_up — scheduled
Email follow-up
- channel
- same email thread
- wait
- +3 days
- exits
- replied · unsubscribed · converted
- records
- touch_id, position in thread, reply class
Reply-to-self keeps the thread together. Two at most.
step.light_touch — you
Light touch
- channel
- same public thread
- wait
- after they answer
- exits
- went quiet · asked to stop
- records
- reply text, their answer's class
A short answer to what they asked back. Keeps the thread warm before any private message.
Your own channels · posts that reach many people at once
step.quote_post — you
Quote post
- channel
- X, Threads
- wait
- same day as their post
- exits
- engaged · ignored
- records
- quoted post id, your text, their response
Adds something to their post in public. Use when the person is a builder others follow.
step.own_post — scheduled
Own post
- channel
- X, Threads, LinkedIn, your blog
- wait
- day 7 or later, turns the thread into content
- exits
- n/a: one-to-many
- records
- post id, metrics at 10 min, 30 min, 1 h, 1 day, 7 days
Turn a common answer into a post. Reaches the people who never posted their question.
Logic · timing and branching; no message
step.wait — system
Wait
- channel
- none
- wait
- a fixed delay or until a time window opens
- exits
- n/a
- records
- planned vs actual send time
Waits are steps too, so their length can be tested.
step.branch — system
Branch on reply class
- channel
- none
- wait
- immediately after a reply
- exits
- n/a
- records
- reply class (positive, question, not now, stop) and the branch taken
Positive goes to the offer; a question gets an answer; not now waits 30 days; stop ends everything.
Hand-off · moves the person to a goal or to you
step.task — you
Task for the founder
- channel
- your queue
- wait
- due the same day
- exits
- done · skipped · snoozed
- records
- task type, minutes to complete, skip reason
Anything that needs a human: a call, a personal intro, checking their site before writing.
step.send_brief — you
Send their brief
- channel
- DM or email
- wait
- after a positive reply or a light touch
- exits
- opened · replied · joined
- records
- touch_id, brief id, link clicks
The offer for VibeDraft: a brief of their own product, with the people asking for it right now.
step.add_waitlist — system
Add to waitlist
- channel
- waitlist page
- wait
- when they say yes
- exits
- joined · declined
- records
- signup with first and last touch_id
Records the conversion with the touch that earned it.
step.offer_call — you
Offer a call
- channel
- DM or email
- wait
- only after two positive replies
- exits
- booked · declined · no reply
- records
- booking time, show or no-show
For high-value leads only. A call offered too early ends threads.
step.tracked_link — system
Tracked link
- channel
- inside any step
- wait
- attached to the step that sends it
- exits
- clicked · never clicked
- records
- link id, touch_id, click time, landing page
Not sent on its own: it rides inside a message so the click maps back to the step.
Exit · ends the sequence cleanly
step.exit — system
Stop / exit
- channel
- none
- wait
- immediately on any exit condition
- exits
- n/a
- records
- exit reason, step reached, days in sequence
Ends cleanly and frees the person for other campaigns later, unless they asked to stop.
Sequences
Listen and reply
seq.lead_to_waitlist —
Lead to waitlist
Listen and reply — playbook: Lead to waitlist
- goal
- waitlist join
- entry
- Hot or Warm lead, never contacted
day 0
you
the one thing that fixes what they posted
after they answer
you
a short answer to what they asked back
next
you
their brief, with the waitlist; once
one nudge
you
did the brief show anyone worth answering?
exits joined · asked to stop · out of steps
seq.reddit_pain_to_dm —
Reddit pain reply to DM
Listen and reply — playbook: Listen and reply
- goal
- reply, then a DM
- entry
- a pain post in a watched subreddit, under 48 hours old
day 0
you
answer the thread; offer the template only if asked
on reply
system
positive or question → DM; stop → exit
+1 day
you
the template or a 5-minute look, no pitch
+4 days
you
one nudge, only if they engaged
exits replied · asked to stop · out of steps
seq.x_pain_reply —
X pain reply
Listen and reply — playbook: Signal-based outbound
- goal
- profile visit, then reply
- entry
- an X post matching a pain phrase, under 24 hours old
day 0
you
reply with one concrete step
same day
you
only if they're a builder others follow
+2 days
you
if they answered, answer back
exits replied · ignored · asked to stop
seq.beta_invite — template
Beta invite
Listen and reply — playbook: Beta tester recruiting
- goal
- active testers
- entry
- replied to the call-out and fits the brief
day 0
you
qualify: are you in this situation right now?
on yes
you
set it up with them, 15 minutes
+3 days
you
feedback call: three questions
+10 days
you
ask to quote one line
exits used it twice · declined · asked to stop
seq.review_responder — template
Competitor review responder
Listen and reply — playbook: Comparison interception
- goal
- reply, then trial
- entry
- a 1 to 3 star review of a competitor, under 14 days old
day 0
you
only where replies are allowed; answer the complaint, not the vendor
on reply
system
positive → offer; else exit
+1 day
you
what switching takes, in their words
exits replied · ignored · asked to stop
Your own channels
seq.comment_keyword —
Comment a keyword
Your own channels — playbook: Comment a keyword
- goal
- hand-raise, then signup
- entry
- someone comments the keyword on your post
minutes
scheduled
the resource they asked for, with a tracked link
+2 days
you
did it help? one line
on positive
system
log the signup with its touch
exits joined · asked to stop
seq.waitlist_countdown — template
Waitlist countdown
Your own channels — playbook: Waitlist countdown
- goal
- waitlist joins
- entry
- your audience; no individual entry
day 1
scheduled
say what's coming; link in the reply
days 2 to 13
scheduled
one pain per day
on signup
scheduled
confirm and ask one question
day 14
scheduled
open the doors; email before posting
exits campaign window ends
seq.launch_day — template
Launch day
Your own channels — playbook: Launch week, or launch again
- goal
- launch-week signups
- entry
- launch scheduled on a directory
day -7
scheduled
tell your list the date
day 0
scheduled
the launch post
day 0
you
answer every comment within the hour
day 1
scheduled
the results, with numbers
day 7
scheduled
the week after: who's still using it
exits window ends
Customer lifecycle
seq.warm_reactivation — template
Warm list reactivation
Customer lifecycle — playbook: Warm list reactivation
- goal
- reply or return visit
- entry
- signed up or joined the waitlist 30+ days ago, inactive
day 0
scheduled
what changed since they signed up, one line each
+3 days
scheduled
one question: what were you hoping it would do?
on reply
system
positive → task; not now → wait 30 days
on positive
you
personal reply
exits replied · unsubscribed · returned
seq.stalled_trial — template
Stalled trial rescue
Customer lifecycle — playbook: Stalled trial rescue
- goal
- activation
- entry
- trial day 2 with no first key action
day 2
scheduled
the one step that predicts paying, with a link straight to it
day 4
scheduled
offer to set it up for them
on reply
you
do the setup together
day 6
system
stop before the trial ends
exits activated · converted · unsubscribed
seq.failed_payment — template
Failed payment recovery
Customer lifecycle — playbook: Failed payment recovery
- goal
- payment recovered
- entry
- Stripe reports a failed payment
hour 0
scheduled
plain note: the card failed, here's the update link
+3 days
scheduled
second note, still friendly
+6 days
you
personal message if they're a long-time customer
exits paid · canceled
seq.win_back — template
Win-back
Customer lifecycle — playbook: Win-back
- goal
- resubscribe
- entry
- canceled 30 to 90 days ago
day 30
scheduled
what changed since they left, tied to their cancel reason
+7 days
scheduled
one question: what would bring you back?
on positive
you
only if they answered
exits resubscribed · unsubscribed · out of steps
guardrails
The contact policy sits above every sequence.
A sequence asks for a step; the policy decides whether it may go out. Blocked steps are logged with the rule that blocked them, because "we chose not to send" is training data too.
01 — One private message per person, ever · A DM is spent once. Put the brief in it, not a hello.
02 — At most 2 unanswered messages · Two in a row with no reply and the sequence stops for that person.
03 — 3 founder messages per person · Hand-sent steps are capped, so one lead can't eat the day.
04 — 5 follow-up messages a day · A daily cap across all sequences. Overflow waits for tomorrow, in rank order.
05 — Never contact · Customers' staff, competitors, people who asked to stop, and anyone on the founder's never list.
06 — Quiet hours · Steps send inside the person's waking hours when their timezone is known; otherwise inside yours.
07 — One campaign per person · A person is in at most one campaign at a time, so one sequence owns them.
08 — Log every block · A blocked step is a row with the rule that blocked it, never a silent skip.
how it connects
From playbook to touch, and back to what paid.
PLAYBOOK — why and what to offer
CAMPAIGN — who, when, which arm
sequence — the steps, in order
step — one component
touch — one message sent, with touch_id
OUTCOME — reply, click, signup, payment
Read it left to right to run a sequence; right to left to attribute a payment to the step that earned it.
data to capture
Record every step so the drafts and the timing can learn.
Optimizes: the drafts and their timing. Every draft, every edit and every send is a labeled example, if it's recorded in this shape.
Record
- every draft: prompt version, randomized slot, variant type, register, full text
- the decision: shipped, shipped edited or discarded, with edit distance, edit locus (hook, body, ending) and seconds to decide
- a touch_id on each sent step, with sent time against suggested time
- every blocked step, with the policy rule that blocked it
- the founder's exact words when he logs what he sent
Label
- kept as-is, edited or discarded
- draft-versus-posted pairs (the posted text wins)
- reply and reply class within 7 days
- exit reason per person
Trains
- a draft reward model from preference pairs
- opener and template choice per step
- a send-time model per channel
- the best number of steps before stopping
Test
- opener, hook, length, proof, send time, number of steps
- randomized per draft, using the prompt version and slot
- wait lengths, as steps of their own
- one knob at a time, sized before launch