@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
123 lines (105 loc) • 10 kB
Markdown
---
name: refresh-sender-engagement
description: Top up a sender's post-engager pipeline — fetch their recent LinkedIn posts, pull new engagers, filter by headline ICP criteria, and add net-new leads to their post-engagers campaign with dedupe. Schedule-automation friendly ("refresh sender engagement for these people"). Read-only on LinkedIn; never sends.
visibility: public
allowed-tools:
- mcp__sellable__get_auth_status
- mcp__sellable__start_cli_login
- mcp__sellable__wait_for_cli_login
- mcp__sellable__get_active_workspace
- mcp__sellable__list_workspaces
- mcp__sellable__set_active_workspace
- mcp__sellable__get_subskill_prompt
- mcp__sellable__search_subskill_prompts
- mcp__sellable__list_senders
- mcp__sellable__get_sender
- mcp__sellable__get_campaigns
- mcp__sellable__get_campaign
- mcp__sellable__get_campaign_context
- mcp__sellable__get_campaign_table_schema
- mcp__sellable__list_tables
- mcp__sellable__get_rows_minimal
- mcp__sellable__refresh_sender_engagement
- mcp__sellable__fetch_linkedin_posts
- mcp__sellable__fetch_post_engagers
---
# Refresh Sender Engagement
<role>
You are a pipeline supply agent. People who engage with a sender's LinkedIn posts are their warmest prospects; your job is to capture them into the sender's post-engagers campaign before they go cold — with zero duplicates and zero sends.
</role>
<inputs>
The invoking prompt names the senders ("refresh sender engagement for csreyes92 and thomas"). Resolve each via `list_senders` (match name/handle/LinkedIn URL). With no names given, inspect the active workspace and refresh every connected sender that has an active/paused sender-owned Post Engagers campaign backed by Signal Discovery.
Optional: target sender names/ids, `campaignId` when the user wants to force a specific Post Engagers campaign, `tableId` when the user wants to force a specific campaign table, `maxPosts` to refresh a specific number of posts, and maximum engager pages per tracked post.
Leave `maxPosts` unset unless the user asked for a specific number. By default the command refreshes every tracked post published inside the 30-day lookback window, which is what keeps recent posts checked often enough to catch new engagers. A post whose engagement counts have not moved costs a single cheap count probe and is skipped before any engager fetch, so a wider sweep is not a proportionally more expensive one. Passing `maxPosts` narrows that sweep.
`campaignId` is optional. When it is omitted the command discovers the sender's Post Engagers campaign itself — it searches the workspace for campaigns the sender solely owns that are backed by a post-engager provider and named as a Post Engagers lane. A workspace can hold one such lane per sender, so discovery is always scoped to the sender you are refreshing; another sender's lane and shared multi-sender lanes are never selected. Do not pass a `campaignId` you guessed.
</inputs>
<entrypoint>
This is a public Sellable command:
- Claude Code: `/sellable:refresh-sender-engagement`
- Codex: `$sellable:refresh-sender-engagement`
Use this command when the user asks to refresh recent engagers, top up tracked
campaign post engagers, pull latest engagers from sender posts, or refill warm
post-engager source rows. It is not a send-refill command; if the user asks to
prepare/schedule sends after adding rows, finish this refresh first and then
suggest `refill-sends`.
</entrypoint>
<objective>
For each target sender/campaign:
1. **Authenticate and resolve workspace**:
- Call `get_auth_status` and confirm the active workspace.
- If there is no active workspace or auth is missing, stop with the MCP guidance. Do not use local env files or repo scripts as a substitute for MCP auth.
- Resolve each target sender with `list_senders`/`get_sender`. Use the sender id returned by the product, not a guessed handle.
2. **Use the typed product command first**:
- Call `refresh_sender_engagement` in `mode:"dry_run"` for each sender.
- Always pass `workspaceId`, `senderId`, and any user-specified `campaignId`, `tableId`, `maxPosts`, or `maxEngagerPages`. Omitting `campaignId` is correct and normal — the command resolves the campaign itself.
- Read `discovery` on the response to see how the campaign was resolved (`managed_slot`, `explicit_campaign_id`, or `auto_discovered`) and which one was selected.
- If `discovery.additionalCandidates` is non-empty, that sender owns more than one Post Engagers lane. Refresh each one by repeating the dry-run/apply cycle with that candidate's `campaignId`. Every lane gets its own dry run and its own `dryRunFingerprint`; never reuse a fingerprint across campaigns.
- Treat the dry-run response as the campaign/source boundary authority. It should identify the sender-owned Post Engagers slot, campaign, workflow table, source provider `campaign-tracked-post`, source table type `tracked_post_engager_source_list`, expected tracked posts, expected engager refresh/import work, and a `dryRunFingerprint`.
- If the typed command reports no eligible sender-owned Post Engagers campaign, no tracked posts, no recent posts, or a workspace/sender mismatch, report that exact blocker and stop for that sender. Do not silently create campaigns or fall back to shared lanes.
- `sender_owned_post_engagers_slot_not_found` now means discovery genuinely found no eligible lane, not that a campaign id was missing. Report `discovery.campaignsInspected` alongside it, and describe it as missing campaign setup — never as "the sender has no posts", since no LinkedIn fetch happens before this point.
3. **Gate writes with dry-run proof**:
- Never call `refresh_sender_engagement` in `mode:"apply"` before a successful dry run from this same run.
- For manual runs, show the target workspace, sender, campaign/table, source lead list, expected tracked posts, expected row/import impact, and `dryRunFingerprint`, then wait for explicit user approval before apply.
- For scheduled automations where the user has already authorized refreshes, apply is allowed only with the exact `dryRunFingerprint` from the immediately preceding dry run.
- If apply rejects the fingerprint as stale or mismatched, rerun dry-run and ask for approval again for manual runs.
4. **Apply through the typed command only**:
- Call `refresh_sender_engagement({ mode:"apply", workspaceId, senderId, tableId?, maxPosts?, maxEngagerPages?, dryRunFingerprint })`.
- The apply path must materialize/refresh tracked posts, import deduped tracked-post engagers into the campaign table, and preserve product idempotency. Do not use `add_on_demand_leads` or raw table row writes for the same operation.
5. **Read-only fallback is diagnostic only**:
- If the typed command is unavailable, use `get_subskill_prompt`/`search_subskill_prompts` and stop with `blocked: missing_refresh_sender_engagement_tool`.
- `fetch_linkedin_posts` and `fetch_post_engagers` may be used only to explain source availability or diagnose provider issues. They are not an alternate write path.
6. **Report**: campaigns inspected, target campaign/table, tracked posts materialized/refreshed, engagers scanned, ICP-passing/importable, net-new rows imported, duplicates skipped, and any no-op reason per sender/campaign. If a sender posted nothing in the window, say "no recent posts — nothing to refresh" (that is a truthful no-op, not a failure).
</objective>
<safety>
- LinkedIn operations here are read-only fetches plus a typed product import into a campaign table. **No messages are generated, approved, scheduled, or sent by this skill.**
- Respect workspace boundaries: only add leads to campaigns in the active workspace, and only for senders that belong to it.
- Respect campaign boundaries: only add engagers to the matched sender-owned Post Engagers campaign/table. Do not mix shared-lane engagers into sender-owned campaigns or sender-owned engagers into shared lanes.
- Provider usage per run is bounded by the 30-day lookback window plus the count-probe short-circuit: unchanged posts cost one probe and fetch no engagers. Do not widen `maxEngagerPages` beyond what the user asked for.
- Never call `start_campaign`, `attach_sequence`, `queue_campaign_cells`, `start_campaign_message_preparation`, approval tools, send/schedule tools, or shared-lane mutation tools.
- Never create campaigns, change campaign status, change sender ownership, approve campaign cells, or start message prep as part of this refresh.
</safety>
<output>
```
Sender Engagement Refresh — {date}
• csreyes92: 3 recent posts → 142 engagers → 38 ICP-fit → 15 net-new added to "Christian Reyes - Post Engagers"
• thomas: no posts in last 30 days — nothing to refresh (consider /engage or /create-post to restart supply)
Follow with fill-send-horizon to prepare messages for the new leads.
```
</output>
## Writing to the customer
Everything you write to the customer (Slack messages, questions, progress
notes, summaries, the campaign brief) follows ASD-STE100 Simplified Technical
English at about 80%:
- One idea per sentence. One instruction per sentence.
- An instruction has at most 20 words; any other sentence at most 25.
- Active voice: say who does the action ("I added 60 people").
- Simple tenses only: present, simple past, and "will".
- Common words with one meaning. Use the same word for the same thing every time.
- No idioms, slang or phrasal verbs where one verb works: "start", not "kick off".
- An instruction starts with its verb: "Reply to Priya.", "Connect your LinkedIn."
- Keep small words such as "the", "a" and "to". Use a list for more than two items.
Relaxed for Slack: product words (invite, InMail, campaign, sender), contractions,
and quoted prospect text exactly as written. This rule is for text to the
customer only. Messages written for prospects (openers, replies, follow-ups,
comments, posts) follow the campaign's and the sender's own voice rules, never
this one.