warm-outbound-engine
Skill6 starsChanged 2 months agoMITView on GitHub
This skill should be used when the user wants to run the LinkedIn Warm Outbound skill, or asks to \"scrape LinkedIn post engagers\", \"build outbound from people engaging with my market\", \"find warm leads on LinkedIn\", \"turn LinkedIn engagement into a sequence\", \"write outreach from what people commented\", \"offer each lead a free personalized resource\", \"auto-reply to LinkedIn or cold email replies\", or \"put my LinkedIn outbound on autopilot\", or wants recurring engagement-sourced prospecting staged into HeyReach, Instantly, AgentMail or their own Gmail. Runs on the superagnt MCP: LinkedIn post + engager data, first-party enrichment, workspace database, and one sending lane of the user's choice, with a research-backed cold outreach library and a recurring version that runs daily or every other day. Stages campaigns stopped; starting a sequence is always the human's.
In this repository27 other files it gives its agents.
- attio-crmSkill
- company-enrichmentSkill
- dub-linksSkill
- email-finderSkill
- exa-searchSkill
- facebook-dataSkill
- heyreach-outreachSkill
- instagram-dataSkill
- instantly-outreachSkill
- lead-enrichmentSkill
- linkedin-dataSkill
- reddit-dataSkill
- seo-dataSkill
- social-dataSkill
- tiktok-dataSkill
- web-scrapingSkill
- x-twitter-dataSkill
- youtube-dataSkill
- agency-outboundSkill
- audience-radarSkill
- competitor-ad-researchSkill
- competitor-mindshareSkill
- gtm-prospecting-deskSkill
- newsletter-autopilotSkill
- shortform-script-engineSkill
- super-seoSkill
- video-multiplierSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 11 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈11
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 36
Read when step 1 set a first_touch_asset.
- Distinctive: line 50
If that fails, say so once and proceed: the steps below stand alone.
- Distinctive: line 55
If none are listed, wait about 10 seconds and check again before concluding superagnt isn't connected or falling back to web search.
- Distinctive: line 119
Ask once, in one message, and draft what you can from their website so they only have to correct it:
- Distinctive: line 138
Create the tables. If they exist from an earlier version of this skill, add the missing columns instead of recreating them:
- Distinctive: line 211
Write more phrases like the families with replies.
- Distinctive: line 240
Prefer posts with real engagement.
- Distinctive: line 276
Check the profile URL first (free): a missing or malformed one never becomes a paid call.
- Very specific: line 295
Only for leads that cleared the bar, and only when the lane sends email: data_agnt_people_email_finder from name + domain, then always …
- Very specific: line 310
Read references/cold-outreach-playbook.md before writing a single message.
- Very specific: line 329
Write each lead's message into leads.first_message and tag opener_variant (plain, or asset when step 1 set a first_touch_asset).
- Distinctive: line 417
In every lane: stage, do not start: Add the leads, leave the campaign stopped, and report what is waiting.
- Distinctive: line 433
This client's own scheduler: If the client can schedule a recurring task whose runs have the superagnt tools, set the sweep up there.
- Distinctive: line 490
Every report carries the score distribution line ("scored N: X qualified, Y under the bar, Z gated"), which tells thin sourcing apart from …
- Very specific: line 501
Stage, never start: No campaign is started, activated or resumed by this skill.
- Distinctive: line 512
Never invent: No made-up personalization, numbers or claims about a lead's business, in a message or an asset.
- Very specific: line 517
Never scrape a post's engagers twice, and never contact a linkedin_url already in leads.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
LinkedIn Warm Outbound
Outbound sourced from engagement, not from a list. Every lead in the table
did something in public first: reacted to, or commented on, a post about the
problem you solve. Builds on the base lead-generation skill for the
enrichment mechanics — read that for per-tool detail; this one adds the
engagement source, the scoring gate, the first message, and the four sending
lanes.
The intended arc: run it once end to end in this client, look at what it staged, then put it on autopilot: the same sweep daily or every other day, on this client's own scheduler or a deployed superagnt agent (step 7).
The outreach library
This skill ships a reference library in references/, researched September
2026 from full YouTube transcripts (Alex Hormozi, Nick Abraham, Alex
Berman), Nick Abraham's LinkedIn outreach posts on X, and agnt_'s own
production system. Read the matching file before the step that needs it,
and prefer it over generic outreach folklore.
references/icp-scoring-rubric.md: the two-layer scorer (a narrow gate, then one holistic score against the ICP description) and the weekly calibration loop. Read before step 4.references/cold-outreach-playbook.md: targeting, connection requests, first messages, follow-ups, replies, sending limits and benchmarks, per lane. Read before step 5.references/free-resource-first-touch.md: build each qualified lead a personalized asset from their own data and offer it instead of a pitch. Read when step 1 set afirst_touch_asset.references/webhook-auto-reply.md: vendor webhooks into a deployed agent that classifies replies, logs them, and drafts or sends answers under approval.references/autopilot-agent-team.md: the deployed version of step 7, a recurring agent team on superagnt: the team shape, data jobs for the per-lead work, cadence, cost, and how real deployments broke.
For LinkedIn via HeyReach, also load the platform's own doctrine:
agnt_guidance_load({ "name": "linkedin-outreach" }).
No references/ folder next to this file (a harness that saved only
SKILL.md)? Fetch the one you need from
https://raw.githubusercontent.com/superagnt/plugins/main/plugins/warm-outbound-engine/skills/warm-outbound-engine/references/<file>.
If that fails, say so once and proceed: the steps below stand alone.
Step 0 — tools
Codex: superagnt's tools can take a few seconds to appear in a new chat. If none are listed, wait about 10 seconds and check again before concluding superagnt isn't connected or falling back to web search.
agnt_tools_list_enabled; if missing on a flat server:
agnt_tools_enable({ "families": ["data:linkedin", "database"] }) (the
first-party data_agnt_* people/company tools are always on). A grouped
server already serves every data source and the database: nothing to enable.
That is the whole first run — do not enable a sending lane yet.
requires_upgrade → confirm_url to the user → wait → re-run. (The
warm-outbound-engine skill endpoint pre-enables these two.)
Tool names on grouped servers
This skill writes flat (per-operation) names. New servers list grouped tools
instead: one tool per resource with an action argument. Flat names still
resolve there but are not listed, so most clients will not let you call
them. The calls this skill makes:
| Flat | Grouped tool, action |
data_linkedin_search_posts / _search_post_by_hashtag | data_linkedin_search: posts / hashtag_posts |
data_linkedin_get_company_s_post | data_linkedin_companies: posts |
data_linkedin_get_profile_s_posts | data_linkedin_activity: posts |
data_linkedin_get_post_reactions | data_linkedin_posts: reactions |
data_linkedin_get_profile_post_comment | data_linkedin_posts: comments |
data_linkedin_get_profile_data_by_url | data_linkedin_profiles: profile_by_url |
data_linkedin_get_company_by_domain | data_linkedin_companies: by_domain |
data_agnt_companies_enrich | data_agnt_companies: enrich |
data_agnt_people_email_finder / _email_verifier | data_agnt_contacts: find_email / verify_email |
agnt_db_select | agnt_db_read: select |
agnt_db_insert / agnt_db_upsert | agnt_db_write: insert / upsert |
agnt_db_execute_sql | agnt_db_sql: execute_sql |
agnt_tools_enable | agnt_tools_write: enable |
agnt_guidance_load | agnt_guidance_read: load |
connection_heyreach_campaign_get_by_id / _get_sequence | connection_heyreach_campaigns_read: get / sequence |
connection_heyreach_list_add_leads_v2 | connection_heyreach_list_members_write: add_leads |
connection_heyreach_campaign_add_leads_v2 | connection_heyreach_campaign_leads_write: add |
connection_heyreach_campaign_start | connection_heyreach_campaigns_write: start |
connection_instantly_listcampaign | connection_instantly_campaigns_read: list |
connection_instantly_bulkaddleads | connection_instantly_leads_write: add |
connection_instantly_activatecampaign | connection_instantly_campaigns_write: activate |
connection_agentmail_create_inbox | connection_agentmail_inboxes_write: create |
connection_agentmail_create_draft | connection_agentmail_drafts_write: create |
connection_agentmail_send_draft / _reply_to_message | connection_agentmail_messages_send: send_draft / reply |
connection_agentmail_list_messages | connection_agentmail_messages_read: list |
connection_gmail_save_draft | connection_gmail_mail_write: save_draft |
connection_gmail_send_email | connection_gmail_mail_send: send |
agnt_tools_list_enabled keeps its name on both surfaces. connection_* tools
are grouped the same way as the rest; the lane calls are in the table.
Grouped data calls return a markdown table that drops fields this skill
keys on. Pass response_format: "json" on every LinkedIn call in steps 3
and 4: you get every field of the view instead of the default columns. Then
posts carry urn (the comments call takes it) and url; reactions carry
urn (the member id for linkedin_member_urn) and url (the reactor's
profile); comments carry author_url (the commenter's profile) and url,
which is the link to the comment itself, never a lead's profile. For any
field the view does not carry, such as a post author's profile URL, pass
response_format: "raw": the full payload, exactly what the flat tool
returns.
Step 1 — the ICP, and the searches it implies (first run only)
Ask once, in one message, and draft what you can from their website so they only have to correct it:
- who buys, in their words: the roles that own the problem, the kind of
company, the situation in which they feel it, and who looks close but
never buys. This becomes the ICP description the score reads
(
references/icp-scoring-rubric.md); - where they can sell, and who never to contact: competitors, customers, partners, their own team;
- a watchlist: the competitors whose posts their buyers react to, and 5 to 10 creators whose audience is the buyer. Optional, and the steadiest source there is;
- which channel they send from: HeyReach, Instantly, AgentMail or Gmail (recorded now, enabled at step 6);
- optionally, what they could give a prospect for free that proves they are
good at their job (a report, a teardown, a sample list, a working setup of
their product). See
references/free-resource-first-touch.md; if they have nothing, skip it and the plain opener still works.
Create the tables. If they exist from an earlier version of this skill, add the missing columns instead of recreating them:
icp_profile(id, sells text, problem text, icp_description text,
trigger_signals text, target_geography text, personas text,
do_not_contact text, qualify_threshold int default 50,
lane text, first_touch_asset text, updated_at timestamptz)
watchlist(linkedin_url unique, kind text, name text, added_at timestamptz)
leads(id, person, linkedin_url unique, linkedin_member_urn unique, title,
company, company_domain, email, email_verified boolean,
source_kind text, pond text, source_post_url, engagement text,
engagement_text text, persona text, fit_score int, fit_reason text,
opener_variant text, first_message text, status text,
staged_at timestamptz, replied_at timestamptz, reply_intent text,
updated_at timestamptz)
search_history(term, kind, pond, searched_at default now())
scraped_posts(post_url unique, post_urn, pond, term_used, author, snippet,
scraped_at)Then write the answers to icp_profile (agnt_db_insert) and the watchlist
(kind is competitor or creator). The do-not-contact list goes in before
the first scrape: engager lists are full of competitors, and messaging one
is the fastest way to get your outreach posted about.
Upsert key on leads is linkedin_url — it is the only identifier that
survives a job change. LinkedIn also spells the same person as an encoded
member id (ACoA…) in some payloads, so keep linkedin_member_urn too and
dedupe on both. On a grouped server the default markdown view leaves out
the member id and a commenter's profile URL: request
response_format: "json" (see Step 0).
Step 2 — choose this run's sources, then write its searches
Where you fish matters more than how hard. There are three ponds, and only one of them is the obvious one:
- Buyer behavior (write these first). Posts written by people who have the problem right now: hiring for the function ("hiring a [role that owns the problem]"), scaling or straining ("our [process] is breaking"), evaluating ("anyone using a [category] tool for [job]?"), or the pain stated plainly at the end of a bad week. On these posts the author is a lead too, and the strongest one there is: writing the post is the intent signal.
- The watchlist. The recent posts of the competitors and creators in
watchlist. Everyone reacting to a competitor's product content is already shopping; a creator's audience is the buyer by construction. - Topic. Keywords and hashtags for the space. The widest pond and the noisiest: people who talk about a category for a living are often the ones selling into it, which is why it is one pond of three.
Over a week, aim for roughly 40% buyer-behavior searches, 30% watchlist and 30% topic. A run gives its searches to one or two ponds rather than all three shallowly; the first run covers all three.
Do not keep a fixed keyword menu. Generate 3–6 fresh searches per run
from the ICP description, steered by two queries. Run both with
agnt_db_execute_sql; agnt_db_select can't express a join or a
now() - interval filter:
-- what has actually converted, per pond and term
SELECT sp.pond, sp.term_used, count(l.id) AS leads,
count(*) FILTER (WHERE l.fit_score > 50) AS qualified,
count(*) FILTER (WHERE l.replied_at IS NOT NULL) AS replied
FROM scraped_posts sp JOIN leads l ON l.source_post_url = sp.post_url
GROUP BY 1, 2 ORDER BY replied DESC, qualified DESC;
-- what not to repeat yet
SELECT term FROM search_history WHERE searched_at > now() - interval '14 days';Write more phrases like the families with replies; drop the phrasing patterns that produced leads and no replies. Never reuse a term from the 14-day window; everything older is fair game again. Give the next run's searches to the pond that is producing.
The single highest-leverage rule here: write the language your BUYER posts in, not the language your industry sells in. Category and execution terms ("shelf reset", "category review", "Q3 launch at Target") surface posts whose engagers are buyers. Vendor/martech terms ("retail media network", "martech stack") surface posts engaged with by other vendors, and a run of those poisons the table with people who will never buy. Test every generated term: would a buyer plausibly write or react to a post using this phrase?
Insert each term into search_history with its kind (keyword,
hashtag, watchlist) and pond as soon as its search call returns,
zero results included, so a run that dies halfway keeps the history of what
it actually searched. A term whose call failed (credits, provider error) is
not recorded and stays eligible next run.
Step 3 — the sweep
- Find the candidate posts:
data_linkedin_search_postsfor keyword searches (buyer behavior and topic),data_linkedin_search_post_by_hashtagfor hashtags (topic only), and for a watchlist entrydata_linkedin_get_company_s_post(a company page) ordata_linkedin_get_profile_s_posts(a person), taking its 1–2 most engaged posts from the last couple of months. 3–5 posts per run across all ponds — that cap is deliberate, it is the run's whole data cost. - Prefer posts with real engagement; a post with 4 reactions is not worth a scrape when a 90-reaction one is in the same result set.
- Skip posts already in
scraped_posts. Record the rest, with theirpond, as you take them. data_linkedin_get_post_reactionsfor reactors,data_linkedin_get_profile_post_commentfor commenters (grouped:data_linkedin_postsactionsreactionsandcomments, withresponse_format: "json"). Take a reactor's profile fromurland member id fromurn; take a commenter's profile fromauthor_url, never from the comment'surl. Recordengagement('reacted' | 'commented') per lead — commenters convert better and are worth a different opener. Keep what they did inengagement_text: the comment itself for commenters, the reaction type for reactors. It is the one personalization hook every lead comes with.- On a buyer-behavior post written by a person, add the author as a
lead too (
source_kind = 'author', with the post itself asengagement_text); everyone else issource_kind = 'engager'. Never add a competitor as the author of its own post, and drop the employees of a watched company when you pull its engagers. - Drop anyone whose
linkedin_urlorlinkedin_member_urnis already inleads. Dedup at the source, never at send time. A grouped call's default markdown table has no member id, and on comments itsurlis the comment link, so a dedupe against it silently lets duplicates through: fetch the json view first.
Geography and other filters belong on the enriched profile, not on the search payload. LinkedIn's post-search results omit location for plenty of genuinely in-market posters; filtering there silently starves the funnel. Take the lead, filter it in step 4.
Step 4 — score, then enrich
Two layers, in this order, from references/icp-scoring-rubric.md (read it
before the first scoring pass). The score gates the spend: a lead that
fails it never costs an email lookup.
- Check the profile URL first (free): a missing or malformed one never becomes a paid call.
data_linkedin_get_profile_data_by_url→ real title, company, location, and the canonical profile URL. Dedupe again on both keys.- The gate: reject only an explicitly out-of-region location or an
empty or fake profile (
fit_score = 3, with the reason), and drop anyone on the do-not-contact list. Never judge the role here: a gate that guesses at fit from a headline starves the funnel. data_agnt_companies_enrich(ordata_linkedin_get_company_by_domain) → domain, size, industry. Research the company further only when the score can't be settled without it.- The score: one holistic judgment against
icp_profile.icp_description:fit_score0–100, a two- or three-sentencefit_reasonthat cites the evidence and names the uncertainty, and apersonaonly when confident. Above the bar (qualify_threshold, default 50) qualifies, and an unresolved maybe qualifies; a score at or under it needs a concrete wrong-way reason. Below the bar →status = 'disqualified'and stop: no email lookup, no message, ever. - Only for leads that cleared the bar, and only when the lane sends email:
data_agnt_people_email_finderfrom name + domain, then alwaysdata_agnt_people_email_verifier. LinkedIn URL → email is not a one-step lookup. Unverified staysemail_verified = false; those rows are still workable on LinkedIn. Whenicp_profile.laneis HeyReach, skip both calls. agnt_db_upsertwithstatusmoving new → scored → enriched → staged, so a failed run resumes instead of restarting.enrichedmeans ready to message. Never overwrite a known value with a blank.
Above ~500 leads a run, this belongs in a data job rather than a longer
session — one cheap structured call per lead
(references/autopilot-agent-team.md).
Step 5 — write the first touch
Read references/cold-outreach-playbook.md before writing a single
message; it has the rules per lane. The ones that matter most:
- The message has one job: a reply. It reads one-to-one. No company intro, no feature list, no calendar link in the first touch.
- Open with the topic they engage with, never the creator. "Saw you've
been in a lot of conversations about
<topic>" works; "saw you liked<creator>'s post" reads as surveillance and gets screenshotted back to the creator. For commenters, the substance of what they said (engagement_text) is fair game, in your own words; never quote it back or link the post. For authors (source_kind = 'author'), their own post is the natural opener ("saw you're hiring your first SDRs"): it's their public statement, not someone else's audience. A generic compliment is worse than nothing. - Give before you ask, then ask small. A yes/no question or permission to send something useful, not a meeting.
- Never invent a detail or a number. Exact figures from their own data, or none at all.
Write each lead's message into leads.first_message and tag
opener_variant (plain, or asset when step 1 set a
first_touch_asset). With an asset, build it for the top-scored leads first
and offer it in the message: references/free-resource-first-touch.md.
Show the user the first five messages (and the first five assets) before anything is staged. After they approve the style, show a sample each run.
Step 6 — stage into the lane, once
Enable only the lane recorded in icp_profile.lane. Four lanes:
HeyReach — LinkedIn sequences
agnt_tools_enable({ "families": ["connection:heyreach"] }), then load the
platform's HeyReach doctrine once:
agnt_guidance_load({ "name": "linkedin-outreach" }). The campaign engine
owns delivery (timing, acceptance, reply-stop); this skill owns judgment
(who, what to say, what to do with replies).
- The user builds the campaign in HeyReach: the sequence, a sender
account, created with "Create empty list". Read it before touching it:
connection_heyreach_campaign_get_by_idfor the status,connection_heyreach_campaign_get_sequencefor the variables each step uses. - Personalization rides on the lead at enrollment and can't be changed
afterwards. Pass the whole first message as one custom variable
(
customUserFields: [{ "name": "fullMessage", "value": ... }]) and make the sequence's message step just that variable; also fill every other variable the sequence references, plusfirstName,lastName,companyNameandposition. A missing variable falls back to generic copy silently. Write the message to the row, read it back, then enroll. - Stage without starting:
connection_heyreach_list_add_leads_v2into the campaign's lead list works while the campaign is paused, and nothing sends until the user resumes it.connection_heyreach_campaign_add_leads_v2only works on an active campaign and starts delivery for those leads, so use it only when the user has said the campaign is live and wants leads flowing into it. - Leads already in HeyReach are skipped silently: a successful call does
not mean every lead was added. Stamp
staged_atonly on rows you can see in the list afterwards.
Two settings that decide whether this works: send a blank connection request (a request carrying a pitch converts materially worse than an empty one), and turn on exclude-in-other-campaigns so one person never appears in two sequences.
Instantly — email sequences
agnt_tools_enable({ "families": ["connection:instantly"] })
connection_instantly_listcampaign to pick the persona-matched campaign,
then read its first step to see which variable it expects.
connection_instantly_bulkaddleads with campaign_id, the verified-email
rows only (an unverified address in an Instantly campaign is a bounce
charged against the sending domain), and skip_if_in_workspace: true. The
first message rides in the lead's personalization field or a
custom_variables key that the step references.
AgentMail — an inbox the agent owns
agnt_tools_enable({ "families": ["connection:agentmail"] })
connection_agentmail_create_inbox once (its own domain — never the user's
primary), then connection_agentmail_create_draft per lead (to,
subject, text; never send_at) and connection_agentmail_send_draft
when the user releases them. Replies come back through
connection_agentmail_list_messages /
connection_agentmail_reply_to_message, which is what makes this lane the
one where the agent can actually hold the thread.
Gmail — the user's own mailbox
Nothing to enable: a connected mailbox is already on. Once the user has
connected Gmail, connection_gmail_* is served on the workspace MCP like
any connected vendor; agnt_tools_enable cannot connect it. Not connected
yet → ask the user to connect Gmail on their superagnt connections page,
then re-run agnt_tools_list_enabled.
connection_gmail_save_draft per lead (to, subject, body as HTML)
puts each first message in the user's Drafts, where they review and send it
themselves. That is the default. connection_gmail_send_email sends for real
from the user's own address, gated only by their client's tool approval, so
call it only on an explicit instruction for that run. For the standing
version (step 7), wire the same ops onto the deployed agent as flat tools
entries: { kind: "integration", provider_id: "gmail", operation_id:
"save_draft" } and "send_email", where every send surfaces for approval.
In every lane: stage, do not start. Add the leads, leave the campaign stopped, and report what is waiting. Pressing start is the user's act, and it is the last point at which a bad list can still be caught.
Step 7 — put it on autopilot
One batch is not the product. A list built once and never refilled goes quiet within weeks: the sequence outruns the leads and the channel looks dead. Once a run has worked end to end and the user liked what it staged, offer the standing version: the same sweep (steps 2 to 6), run daily or every other day. Smaller, more frequent runs keep the leads fresh (people who engaged in the last day or two are the warm ones), keep each run cheap, and keep the sending account under its limits.
There are two ways to run it. Offer whichever fits the user:
- This client's own scheduler. If the client can schedule a recurring
task whose runs have the superagnt tools, set the sweep up there. Each
run starts with no chat history, which is fine: the ICP, the leads and
the search history are in the workspace database, and the run reads them
like step 2 does. Write the task so a fresh session can do it alone: run
this skill's sweep for the stored ICP, the lane, the per-run cap, stage
and never start, then report. Runs use the user's plan for this client;
data calls still spend superagnt data credits. A scheduled run starts with
nobody signed in, so check two things before promising it: the client can
run unattended on this machine (its own sign-in, such as a long-lived token
for Claude Code, or an API key or ChatGPT login for Codex), and something
will fire it (the client's own scheduler, cron or launchd). Test one
unattended run. Every run reads strangers' posts and comments, nobody is
there to approve a tool call, and superagnt doesn't gate tools for a
client. So give the scheduled run an allowlist in its client permissions,
not a deny list: the
agnt_*anddata_*tools in the table under Step 0, the lane's read tool, and its one staging call:connection_heyreach_list_members_write(HeyReach),connection_instantly_leads_write(Instantly) orconnection_gmail_mail_write(Gmail drafts). Nothing that sends or starts goes on it: notconnection_gmail_mail_send,connection_agentmail_messages_send,connection_heyreach_inbox_send,connection_heyreach_campaigns_write,connection_heyreach_campaign_leads_write(its add can resume a paused campaign),connection_instantly_emails_sendorconnection_instantly_campaigns_write, nor their flat names on a per-operation server. The AgentMail lane stays out of this route: an AgentMail draft created withsend_atsends itself, and no permission stops that, so run it attended or on the deployed agent. In the test run, check the scheduled run's tool list: none of those tools may appear. If the client can't restrict a scheduled run's tools, use the deployed agent. Have each run report into a table or dashboard view the user reads, not only a log, and have the next attended session check the last run'ssearched_atso a dead schedule gets noticed. If you are not sure the client can schedule, or that its scheduled runs see the superagnt tools, say so and use the other way. - A deployed superagnt agent on a schedule. For when the client can't
schedule, runs must happen with the user's machine off, replies should be
answered as they arrive, or the volume calls for splitting the work.
references/autopilot-agent-team.mdcovers the team shape (who does the judgment, what moves into a data job to cut AI cost, what webhooks trigger) and the ways real deployments of this exact motion have broken. Agent runs spend AI credits.
The reply side is references/webhook-auto-reply.md either way: without it
leads.replied_at stays empty, step 2's steering query has nothing to learn
from, and the engine generates volume without ever getting warmer.
Confirm the cadence and the expected spend with the user before scheduling
or deploying anything, and hand over the confirm_url on any
requires_upgrade (a plan limit, spent data credits, or a trial that
ended).
Step 8 — report
From the table, never from memory (agnt_db_select): posts scraped, new
leads, how many cleared the score bar, how many staged and into what, and
the reply rate per search-term family, per pond and per opener_variant.
Every report carries the score distribution line ("scored N: X qualified, Y
under the bar, Z gated"), which tells thin sourcing apart from a bar set too
high; when nothing qualified, list the five closest calls with their reasons
instead of an empty table. Once replies flow back: replies by intent and the
median time to answer one. Once a week, run the calibration loop in
references/icp-scoring-rubric.md with the user.
Name the terms that earned replies and the terms that did not — that
paragraph is what the next run reads.
Hard rules
- Stage, never start. No campaign is started, activated or resumed by
this skill.
connection_heyreach_campaign_startandconnection_instantly_activatecampaignare the user's to call. - Never send from the user's own mailbox without an explicit instruction for that run. Drafts are the default in the Gmail and AgentMail lanes.
- Replies to humans are approved. A deployed reply agent sends only what
the user approved, unless the user explicitly relaxed a named reply class
(
references/webhook-auto-reply.md). - One lane. Enabling all four loads hundreds of tools into the context for no gain, and staging the same person into two channels is how a warm lead becomes a complaint.
- Never invent. No made-up personalization, numbers or claims about a lead's business, in a message or an asset.
- The do-not-contact list is absolute. Nobody on it is looked up, staged or messaged, ever. A lead under the score bar never costs an email lookup, an asset or a message.
- Never scrape a post's engagers twice, and never contact a
linkedin_urlalready inleads.
<!-- skill_id: warm-outbound-engine · source: https://github.com/superagnt/plugins -->Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

