@nifinet: https://x.com/nifinet/status/2066933179169329303
Summary
A detailed guide to building a signal-based outbound engine for sales distribution in 2026, with six stages and copyable prompts to automate prospecting using AI.
View Cached Full Text
Cached at: 06/17/26, 01:45 AM
How to Win Distribution in 2026
Distribution in 2026 comes down to one system, and it is not a stack of channels. It is a signal-based outbound engine: it watches for the moment a company enters your market, decides whether that moment is worth a message, writes from the real trigger, checks itself, and learns from what comes back.
I run one across Sortlist on fourteen agents for about four hundred dollars a month. Last night they watched funding rounds, hires at companies we sell to, and accounts that mentioned a problem we solve. This morning there was a short ranked list of who to talk to and why.
This is the whole build.
Every stage has a prompt you can copy, and they are not six separate tricks. Each one hands its output to the next, and they run as one loop. The repo at the end wires them together so you can clone it and run it.
The shape
One loop, six stages, and a record they all share.
javascriptICP -> extract -> score -> write -> check -> send/log ^ | |________ learn (weekly) __________|
The engine loop: ICP, extract, score, write, check, send and log, with a weekly learn step
The engine loop: ICP, extract, score, write, check, send and log, with a weekly learn step
**You write your ICP once. Extraction turns raw activity into clean signals.
**Scoring reads those signals against everything you already know about the account and decides who is worth a message. Writing drafts from the trigger. A check catches anything wrong before it sends. Every touch is logged to a record per company, and a weekly learning step reads the outcomes and re-weights what the engine chases. The output of each stage is the input of the next. The record in the middle is what makes the whole thing more than a mail merge.
Here is each stage, with its prompt.
Stage 0: sharpen the ICP
Everything keys off who you are trying to reach, and most ICPs are mush. Turn a loose description into something the engine can score against. You run this once and reuse the output everywhere.
javascriptYou turn a loose company description into a tight ICP the engine can score against.
INPUT
- A few sentences about who we sell to and who we do not.
WRITE
- fit: the 3-5 firmographic and behavioral traits a good account has.
- not_fit: the 2-3 traits that disqualify an account.
- strongest_signal: the one signal combination that means “reach out today” for us.
OUTPUT (JSON only) { “fit”: [“…”], “not_fit”: [“…”], “strongest_signal”: “…” }
It returns a tight fit, not-fit, and strongest-signal block. The scoring stage reads it on every account.
Stage 1: turn activity into signals
Detection is not “watch everything.” It is reading a stream of raw activity, job posts, funding news, social moves, web mentions, and pulling out the few that are real company moves. This is the step that turns noise into structured signals the rest of the loop can use.
Extraction: raw activity becomes a few tagged signals
Extraction: raw activity becomes a few tagged signals
javascriptYou read raw activity and pull out buying signals. Ignore anything that is not a real company move.
INPUT
- text: a block of raw activity. Job posts, funding news, social moves, web mentions.
FOR EACH real signal
- account: the company name
- bucket: one of funding, job, company, social, first_party
- summary: one factual sentence that quotes the concrete detail (the amount, the role, the date)
- source: where it came from
RULES
- One company can produce several signals. Keep them separate.
- Skip vague noise. A signal is a specific, datable move, not a general mention or an opinion.
OUTPUT (JSON only) { “signals”: [ { “account”: “…”, “bucket”: “…”, “summary”: “…”, “source”: “…” } ] }
It outputs a list of signals, each tagged with the account, the bucket, and a one-line factual summary. Group them by company before anything else, because two moves on one account in a week beat one move anywhere else.
Then the signals feed straight into scoring.
Stage 2: decide who is worth a message
Now the judgment. A signal is not a reason to send, it is a question: is this account worth a message now, why this week, which play. The scoring step answers it from the new signals plus the account’s full history, the record I will come back to. A third funding signal means one thing for a company you have never touched and the opposite for one you emailed twice and never heard back from.
This is the call we hand to Claude.
On our own LinkedIn engine it watches who engages with a post, cross-references the other signals, and only messages the people already showing intent. We stopped contacting people and started listening first.
javascriptYou score one account for a signal-based outbound engine. Decide if it earns a message right now.
INPUT
- icp: the fit / not-fit / strongest-signal block from Stage 0
- new_signals: what just moved for this account
- history: every past signal, message, reply and outcome, or “none”
- days_since_last_touch: a number, or “never”
SCORE 80-100 strong fit and a high-intent signal: funding, a budget-owner hire, or two signals in one week 50-79 good fit, one solid signal 1-49 weak fit, or a single soft signal like a lone like
RULES
- If days_since_last_touch is under 7, prefer “nurture” or “skip”, never a first touch.
- “why_now” must quote the real signal, never a generic value prop.
- “skip” is a normal answer. Most accounts are a skip.
OUTPUT (JSON only) { “score”: 0-100, “why_now”: “one sentence that quotes the trigger”, “play”: “first_touch | follow_up | nurture | skip” }
It returns a score, a why_now that quotes the real trigger, and a play. A skip is a normal answer. The why_now becomes the seed for the next stage.
Stage 3: write from the trigger
The writing step takes the why_now and the play and drafts a message that opens on what the account actually did, links it to one problem you solve, and asks for one small thing.
javascriptYou write the first message for a signal-based outbound engine.
INPUT
- trigger: the exact thing the account did
- why_now: the one-line reason from the scoring step
- play: first_touch | follow_up | nurture
- problem: one sentence on what you solve
WRITE
- First line names what they just did. Never “Hi {{firstName}}”, never a template opener.
- One sentence links that trigger to the problem you solve.
- One small ask: fifteen minutes, or a one-pager.
- Three to five sentences, plain language, mixed length. No fake urgency, no “just circling back”, no em dashes.
OUTPUT (JSON only) { “subject”: “6-9 words”, “body”: “3-5 sentences” }
If the same message could have gone out a month ago, the signal got skipped. The draft goes straight to the check.
Stage 4: check it before it sends
This is the stage most people skip, and it is what keeps an autonomous engine from emailing a confident, wrong claim to your whole list. A separate pass reads the draft as a skeptic: does every claim trace back to the real trigger, is the opener real, is there exactly one low-friction ask.
javascriptYou are the last check before a message sends. Assume it is wrong until it proves it is right.
INPUT
- trigger: the real thing the account did
- draft: { subject, body }
CHECK
- Every claim in the draft is supported by the trigger. No invented facts, no guessed metrics.
- The first line names the real trigger. No “Hi {{firstName}}”, no template opener.
- One ask, low friction. No fake urgency, no “just circling back”.
- Plain language, mixed length, no em dashes.
If it passes, return it unchanged. If not, fix it and say what was wrong.
OUTPUT (JSON only) { “pass”: true, “reason”: “what was wrong, or ‘clean’”, “subject”: “…”, “body”: “…” }
It returns the message, fixed if it had to be, or flagged if it could not be saved. Only a clean draft reaches a human or a send.
Stage 5: remember, and learn
Two things carry the load here. T
he record is the per-company memory every stage reads and writes: every signal seen, every message sent, every reply, every outcome. Keep it, or the engine treats a warm account like a cold one and reads as a stalker.
The learning step runs weekly, not per message. It reads the outcomes and re-weights which signals are worth chasing, and it names the copy that is winning. Ours even rewrites its own outreach copy after enough sends: try a version, score the replies, keep it or drop it.
javascriptYou tune the engine from what actually happened. You run weekly, not per message.
INPUT
- outcomes: a list of { bucket, copy_variant, result }, where result is replied | meeting | no_reply | bounced
- current_weights: the weight per signal bucket today
DECIDE
- Re-weight each bucket by its win rate (meetings and replies over total touches). Keep a floor so no bucket drops to zero.
- Name the copy variant with the best reply rate, if there is a real sample.
OUTPUT (JSON only) { “weights”: { “funding”: 0.0, “job”: 0.0, “company”: 0.0, “social”: 0.0, “first_party”: 0.0 }, “best_variant”: “…” }
The new weights feed back into Stage 2 on the next run. That feedback is the difference between an engine that improves and a script that does not.
Run it together
Here is the wiring. One pass of the loop, in order:
-
Load the ICP block from Stage 0, cached.
-
Pull the last day of activity and run extract. You get a list of signals.
-
Group the signals by company.
-
For each account, read its record and run score. Drop the skips.
-
For each survivor, run write, then check.
-
Print the clean drafts as a ranked shortlist, or send them, and log every touch to the record.
-
Once a week, run learn over the outcomes and save the new weights.
The handshake between stages is plain JSON.
Extract outputs signals, score consumes signals and outputs a why_now, write consumes the why_now and outputs a draft, check consumes the draft and outputs a clean one. The record is the shared state in the middle, written on every touch and read on every score. Put it on a schedule:
javascript0 8 * * * cd distribution-engine && python run.py
By the time you open your laptop there is a ranked shortlist with a reason next to each name. No list to build, no subject lines to guess.
Clone it and run it
I put the whole thing in a repo: the six prompts, the record, and the script that chains them. It runs out of the box on example activity with a stub model, so you can watch the loop go end to end before wiring anything in. Then point it at your own activity, plug your Claude call into one function, and schedule it. Comment “GTM” to get it.
Mind you, it will not dedupe ten sources or manage your deliverability. It is enough to run a real signal-based motion and feel the difference from sending on a list.
Or use the full one
The repo is the simple version. The full one is yourmax.ai, the agent we built at Sortlist. It runs the same loop for you: it learns your best-fit buyer, watches the signals, drafts the LinkedIn and email message with the real reason attached, and waits for your approval before anything sends.
You connect the tools you already use and describe the routine you want in chat. It is live now, in limited demos.
Why I bet on this
For ten years I have watched what companies type the moment they decide to hire someone. The lesson never moved: the search is the last step, not the first. By the time a company runs it, the budget shifted weeks ago and the shortlist already has names on it. Everything before that search, the role that reopened, the competitor they started following, is visible earlier if you build to see it.
None of this is hard to build.
It is unglamorous, which is why most teams keep paying for volume instead. That is exactly why it pays for the people who build it now.
Similar Articles
@nifinet: https://x.com/nifinet/status/2064397495036440907
A detailed guide on building an AI-powered GTM (go-to-market) brain using Claude Code, covering five core components—Sense, Remember, Judge, Act, Learn—to automate account-based outreach with judgment, not just volume.
@DanKornas: Sales teams often need to detect buying signals, enrich contacts, and run outreach without relying on a black-box SaaS.…
Signal is an open-source AI sales intelligence and outreach automation workspace that teams can self-host, featuring signal recipes, Claude-backed chat, contact enrichment, and multi-step email sequences.
@nifinet: https://x.com/nifinet/status/2078851409068654639
A guide on building a self-improving outbound system using Codex, where the AI agent reads past outcomes, edits scoring and playbook files, runs tests, and proposes pull requests for human approval. It emphasizes treating go-to-market logic as versioned code that improves from market feedback.
I built an AI agent that researches prospects and generates personalized outreach drafts in under 60 seconds. Looking for feedback from SDRs and founders.
Built an AI agent that researches prospects and generates personalized email and LinkedIn outreach drafts in under 60 seconds, seeking feedback from SDRs and founders.
@TechByMarkandey: been waiting for this one…
Sendio launches Claude Opus 5 for Sales, an AI sales agent that automatically finds leads, writes personalized messages, and books demos.