Win loss review
Every month the CRM's closed deals are audited and what they say lands in context/ as one pull request: the ICP verified against won versus lost with a disqualifier, dated insights with counts and denominators, objections from recorded lost reasons, and a client file per closed-won account; a five-line Slack digest says what changed. Never edits a persona, nor the ICP after the first pass.
Set up the win-loss-review 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/win-loss-review
3. Then follow .claude/skills/win-loss-review/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/win-loss-reviewSay this to your agent
Every month, read what our HubSpot won and lost deals say, verify the ICP, and post the digest to #gtm-context.
Illustrative output #
Fictional records, to show the shape of what comes back.
:bar_chart: *Win-loss review Oct 2026*: 23 deals closed
Won 9, lost 14 · lost reason on 11 of 14 · contacts on 19 of 23
Learned: a RevOps title at 6 of 9 won accounts · 8 of 14 losses were under 50 employees · "no budget this quarter" on 5 of 11 reasons
Proposed: add "under 50 employees" as an ICP disqualifier (8 of 14 losses, 0 of 9 wins), in the PR body
PR: https://github.com/northwind/gtm/pull/331
The pull request adds four dated insight/ files, two objection/ files and nine client/ files,
and modifies nothing under icp/ or persona/; the disqualifier waits for a human.
What you will be asked #
| Input | Why | |
|---|---|---|
icp/, insight/, objection/, client/ | Looked up | The disqualifier is the half of an ICP that protects the team’s time, and won versus lost is the only place it comes from with evidence |
Done when #
- the models synced, and the
pipelinesquery returned non-zero won and lost counts cargo-ai cdk checkprints the agent bound to the repository root, andcargo-ai cdk planreports one agent, the models, the bound connectors and two folders- the first pass opened one pull request whose body opens with the two hygiene findings with denominators, then the mode and the won count that set it
outputs/<date>-win-loss-review/README.mdholds every query’s result, with no amount and no emailicp/carries a disqualifier derived from won versus lost, as a new file or as one dated section appended to the seeded oneinsight/holds dated files in the three buckets with counts and denominators, and every title at a won account is mapped to a persona or listed as undetected- with the fill rate under half, no
objection/file exists and the body says why; at or above it, every objection cites two or more deals by id - every
client/file carriesreference_permission: unknownand no amount - nothing under
persona/changed, and any proposed change is in the pull request body with deal ids - the Slack digest is five lines, its numbers match the run record, and the last line is the pull request link
- a monthly run with new deals opened a pull request that adds files and modifies none under
icp/orpersona/; with none it opened no pull request and the digest said so - after merging and
cargo-ai cdk deploy, the verified ICP section is readable from the workspace context repository and an agent with thecontextcapability quotes it back with its tag
What it costs #
CRM extraction bills no credits, and neither do the SQL queries. The recurring cost is one harness
run a month, scaling with how many deals closed since the previous one, plus the first pass over the
whole window. Confirm the extraction price for the workspace’s CRM with
cargo-ai connection integration get hubspot before the first deploy.
Turn what the CRM says about won and lost deals into the knowledge layer every other agent reads. The platform extracts the CRM into models, a Claude Code harness agent audits them with fixed SQL once a month, and the result lands as one pull request and a five-line Slack digest.
What it does #
- Extracts the CRM into models, whole.
crm_deals,crm_accountsandcrm_contacts: every record, every column, no filter in the config. Extraction bills no credits, and the last two are the same models crm-enrichment and crm-deduplication declare. - Audits with fixed SQL. The prompt carries the queries: counts by pipeline, lost reasons, contacts on deals, won versus lost by industry, size and country, titles at won accounts, and the deals since the last run. The agent runs those and no other.
- States the hygiene findings. The lost-reason fill rate and the deal-to-contact rate open every pull request, with their denominators, and decide what can be written.
- Writes, then appends. The first pass verifies
icp/(one dated section if it is seeded) and writesinsight/,objection/andclient/. Every month after adds files and edits none. Personas are never edited; changes are proposals in the pull request body. - Records the run.
outputs/<date>-win-loss-review/README.mdholds each query’s result, which every[R: <query>]tag points to.
Resources #
| File | Resource | Role |
|---|---|---|
infra/agents/win-loss-analyst.ts | defineAgent (claudeCode) | monthly cron, locked Slack channel, no env |
infra/agents/win-loss-analyst.prompt.ts | (not a resource) | the audit’s SQL, the first pass, the monthly append, the digest |
infra/models/crm-deals.ts | defineModel (crm_deals) | every deal, all columns; the queries narrow to closed |
infra/models/crm-accounts.ts | defineModel (crm_accounts) | the accounts behind the deals, shared with the other CRM cookbooks |
infra/models/crm-contacts.ts | defineModel (crm_contacts) | the people at the accounts, shared with the other CRM cookbooks |
infra/connectors/crm.ts | defineConnector (hubspot) | the CRM the models extract, bound |
infra/connectors/anthropic.ts | defineConnector (anthropic) | the model the harness runs on, billed and metered |
infra/connectors/git.ts | defineConnector (github) | the clone, branch, push and PR path, resolved by binding |
infra/connectors/slack.ts | defineConnector (slack) | the digest, through a locked postMessage |
infra/folders/index.ts | defineFolder ×2 | the agent and the models, filed under the cookbook |
Why models, not a script #
The audit is counts and joins, which is what SQL is for. A collector that pages through CRM search results re-implements pagination, filters and aggregation per CRM, and every one of those is a place to return part of the window as if it were all of it. Models leave extraction to the platform, keep the raw deals in Cargo storage rather than in the repository, and are shared: a project that already runs crm-enrichment or crm-deduplication extracts its accounts and contacts once.
Why one source #
A cookbook is a prebuilt approach an agent follows. Give it two kinds of evidence, a page and a
deal, and it has to hold two confidence levels in one run and the reader has to tell them apart
afterwards. So this cookbook holds one: the CRM. The website has web-capture, which seeds what
this one verifies; calls have call-capture.
Placeholders (edit before deploy) #
languageModelon the agent, and the SlackchannelIdon itspostMessageuse.- The lost-reason property, as
LOST_REASON_COLUMNin the prompt, when the portal records it on a custom property.
What it does not do #
It does not read a call, an inbox or a website; run SQL beyond its own queries; write to the CRM; select or write a deal amount; write the workspace context directly; edit a persona, or the ICP after the first pass; or merge its own pull request.
Verify #
From this skill’s folder:
node --import tsx evals/contract.mjs
From the project root:
npm run check && cargo-ai cdk plan