Stalled deal nudge
Every Monday each rep gets one Slack digest of their open deals that went quiet: how long since the last logged activity, the line that activity left off on, why the deal is worth a touch now, and a follow-up drafted for them to send.
Set up the stalled-deal-nudge cookbook in this project.
1. If the Cargo CLI is not installed yet, follow every step in https://api.getcargo.io/INSTALL.md
2. From the Cargo project, run: cargo-ai cdk add cookbook/stalled-deal-nudge
3. Then follow .claude/skills/stalled-deal-nudge/SKILL.md. Stop for my approval before any paid call, and stop at "cargo-ai project plan" before deploying anything.$cargo-ai cdk add cookbook/stalled-deal-nudgeSay this to your agent
Every Monday, tell each rep which of their open deals went quiet and draft the follow-up.
Illustrative output #
Fictional records, to show the shape of what comes back.
:hourglass: *Stalled deals · Dana Ruiz · 2026-W41*
_2 open deals with no logged activity in 14+ days._
*Fabrikam — Platform* — Proposal, $64,000, closes Oct 31 · quiet 19 days, flagged 1 Monday running
Last: Sep 17 "Send the security questionnaire and we'll take it to procurement."
Why now: The close date is three weeks out and the questionnaire that unblocks procurement never went.
Draft: > Hi Lee, attaching the completed security questionnaire you asked for on the 17th.
> If procurement needs anything else to keep the Oct 31 date, send it my way today.
*Northwind — Expansion* — Discovery, $22,000, closes Nov 20 · quiet 16 days
Last: Sep 20 "Let's regroup once the Q4 budget is set."
Why now: Q4 budgets were due Oct 1, so the regroup they asked for is now.
Draft: > Hi Priya, you mentioned regrouping once Q4 budget was set. Is this week good?
Five owners had stalled deals, so five digests landed and eleven rows were added to deal_nudges; a
second run that Monday posted nothing.
What you will be asked #
| Input | Why | |
|---|---|---|
QUIET_DAYS (infra/agents/nudger.prompt.ts) | Asked | Too short and the digest is noise reps mute; too long and it reports deals already lost. |
OWNERS (infra/agents/nudger.prompt.ts) | Looked up | An owner missing from the map lands under “Unassigned or unmapped owner”, which nobody reads as theirs. |
channelId (infra/agents/nudger.ts) | Asked | Digests quote deal amounts and prospect lines. Locked so they never land in a customer shared channel. |
Done when #
node --import tsx evals/contract.mjspassescargo-ai cdk planreports the agent, thegtm_opportunities,gtm_accounts,gtm_activitiesanddeal_nudgesmodels, the two connectors and the two folders- the hand-run selection returned only open deals whose latest activity is older than
QUIET_DAYS - the first run posted exactly one digest per owner with stalled deals, in the
references/digest.mdshape, and wrote onedeal_nudgesrow per deal with the digest’s Slackts - a second run the same Monday, once the first run’s ledger rows read back through SQL, posted nothing and added no row
- every
Last:quote exists in thegtm_activitiesrow it came from, with that date - no draft was sent and no deal, account or activity row changed
What it costs #
There is no enrichment provider, no CRM connector and no per-record fan-out: the selection and the last-activity reads are SQL over the workspace’s own models. The one connector action is the Slack post. Immediately before the plan, read its live price:
cargo-ai orchestration action list postMessage --kind connector --integration-slug slack
Say the number out loud; the run posts once per owner with stalled deals. The recurring cost is the
agent run, once a week, billed as LLM tokens through the Anthropic connector. It scales with the
number of stalled deals that week, and maxSteps caps it per run. A crm-backed adaptation adds
the CRM extract: read its price with cargo-ai connection integration get <crm>.
One Slack digest per owner every Monday, listing their open deals with no logged activity in the last fourteen days: the line the last activity left off on, why the deal is worth a touch now, and a follow-up drafted for them to send. The example runs on Cargo native deal, account and activity models with no CRM connector; one agent selects the quiet deals in SQL, and a ledger keeps each deal to one nudge per week. With deals in HubSpot, Salesforce or Attio, the models become connector-backed and the agent stays the same.
What it does #
- Computes each open deal’s last activity in SQL, as the latest logged email, meeting, call or note.
- Each Monday, selects the open deals quiet for
QUIET_DAYSor more, and drops any already nudged this ISO week. - Reads the last note, meeting or call on each, and writes a reason and a draft grounded in it.
- Posts one digest per owner to a locked channel, then records each deal in the ledger.
What’s inside #
Adds 9 resources.
| File | Resource | Role |
|---|---|---|
infra/agents/nudger.ts | defineAgent | the Monday cron, the model reads, the locked Slack post |
infra/agents/nudger.prompt.ts | (not a resource) | the SQL rule, the owner map, research, digest, ledger |
infra/models/gtm-opportunities.ts | defineModel (native deal) | the pipeline: stage, amount, close date, owner, is_closed |
infra/models/gtm-accounts.ts | defineModel (native account) | the company name each deal belongs to |
infra/models/gtm-activities.ts | defineModel (native custom) | one row per logged email, meeting, call or note |
infra/models/deal-nudges.ts | defineModel (native) | the ledger: one row per deal nudged per week |
infra/connectors/slack.ts | defineConnector (slack) | the post path |
infra/connectors/anthropic.ts | defineConnector (anthropic) | the model the agent runs on |
infra/folders/index.ts | defineFolder ×2 | where the agent and the models are filed |
references/digest.md | (not a resource) | the digest shape and the rule for each line |
Why one agent and not a play #
The output is a digest grouped by owner, and grouping is a judgment over the whole list. A play enrolls deals one at a time and would need a second step to gather them back into one post per owner. The agent runs the selection itself, in SQL over a model that holds every deal, so the rule is one readable query in the prompt.
Placeholders (edit before deploy) #
channelIdininfra/agents/nudger.ts: the Slack channel id the digests land in.OWNERSininfra/agents/nudger.prompt.ts:owner_idto the name the digest prints.QUIET_DAYSin the same file: fourteen by default.- The hour and timezone: the cron (UTC) and the timezone named in the trigger
text. languageModel: any Anthropic model the workspace’s connector can reach.
Deals in a CRM #
Swap gtm_opportunities and gtm_activities for connector-backed models that extract every record and every
column, and adapt the column names in the prompt’s SQL. SKILL.md, crm-backed, maps the last
activity property for HubSpot and Salesforce.
What it does not do #
It does not write to the deal models, send the drafts, message a prospect, post anywhere but the locked channel, or edit the workspace context.