Account scoring
Score every account against your ICP on a schedule: a deployed agent tiers each company in a Cargo model (tam-building's, or your CRM companies) A / B / C / disqualified against the ICP and rubric in workspace context, and the tier, a two-sentence reason and evidence are written onto the row and, optionally, the matching HubSpot or Salesforce company. New companies are tiered hourly; the book is re-scored weekly or on any window set.
Set up the account-scoring 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/account-scoring
3. Then follow .claude/skills/account-scoring/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/account-scoringSay this to your agent
Tier every company in our TAM against the ICP and the rubric in our context repo, and keep new ones tiered as they land.
Illustrative output #
Fictional records, to show the shape of what comes back.
| Company (domain) | tier | tier_reason | tier_evidence_url |
|---|---|---|---|
| Northwind (northwind.example) | A | Fits the firmographics: 240-person B2B software company in the US. Has a GTM engineer on staff, which the rubric ranks as the strongest sign. | https://northwind.example/careers/gtm-eng |
| Fabrikam (fabrikam.example) | C | Fits industry, size and country. No technical revenue role and no public automation practice was found, so nothing lifts it above C. | |
| Tailspin (tailspin.example) | disqualified | Services-only consultancy with no software product, which the ICP lists as a disqualifier. The sourced industry label was misleading. | https://tailspin.example/about |
Every row also gets tiered_at and lands in tier_a_accounts, tier_b_accounts,
tier_c_accounts or disqualified_accounts. With crmWriteback set to HubSpot, northwind.example’s
company record gets cargo_tier = A, the same rationale in cargo_tier_reason, and today’s date in
cargo_tiered_at. The report closes on the tier distribution and one
recommended next step.
What you will be asked #
| Input | Why | |
|---|---|---|
| icp | Looked up | The rubric decides against it. A tier that cannot name the ICP line it came from is a guess, and the evaluator fails it |
| tier_rubric | Asked | It is the one input that is genuinely a decision about the business: what “work it now” means here |
| model | Looked up | The workflow interpolates these columns into the prompt. A renamed one hands the agent an undefined |
| languageModel | Looked up | Judgment quality and the cost per company both live here |
| rescoreAfter | Looked up | How often a tiered company is judged again. Shorter re-bills the whole book more often |
| crmWriteback | Asked | Reps read the CRM, not the Cargo row. A property that does not exist is a write that ends green and lands nothing |
Done when #
- the ICP and the tiering rubric are in the workspace context, and the rubric was approved
- the pilot tiered ten rows, and one A, one C and one disqualified were checked against the rubric by hand
- every row in the model carries a tier the rubric defines, a rationale naming the deciding lines, and a
tiered_atstamp, and no row carries one without the others - the four segments resolve, and their counts sum to the tiered row count
- the agent’s evaluator pass rate is at or above its threshold
- with
crmWritebackset, one piloted company read back from the CRM carries the same tier, reason and scored-at date as its row - editing the rubric in the context repo changes the next tier with no deploy
- the report gave the tier distribution, actual credits against the pilot’s estimate, and one recommended next step
node --import tsx evals/contract.mjspasses against the adapted resources
What it costs #
Tiering is one agent run per company, billed as LLM tokens through the bound connector, plus
the web searches the agent decides to make. maxSteps is the per-company ceiling, and the rubric’s
one-question-one-search rule is what keeps a normal row far below it. The pilot is how you learn
the real number: read actual credits for the ten rows, then multiply by the untiered row count
before approving the backfill.
After the backfill, the play only tiers what arrives (changeKinds: ["added"]) and what goes stale
after rescoreAfter, so the steady-state cost follows how many companies tam-building lands and how
short that window is, not how often the cron fires. A weekly window bills every account every week.
The CRM write-back is one connector action per tiered company; the pilot’s actual credits include it.
Score accounts against your ICP in three steps: get the accounts into a Cargo
model, tier each one with an agent that reads your rubric, and write the tier
back where reps work. This cookbook deploys all three: the write lands on the
Cargo row, and on the matching HubSpot or Salesforce company when you name one
in infra/settings.ts.
cargo-ai cdk add cookbook/account-scoring
- Accounts in. The play reads a Cargo companies model:
tam_companies, which tam-building syncs, or your CRM’s companies model: any model with an id, a name and a domain, its columns mapped into the workflow input. - Scored. An agent tiers each row A, B, C or disqualified against the ICP
and
tiering-rubric.mdin your workspace context, with a two-sentence reason and the page that decided it. - Scores out. The tier, reason, evidence URL and a
tiered_atstamp are written onto the row and land in four segments. SetcrmWritebackininfra/settings.tsand the same run then updates the matching CRM company (by domain, or by record id when the play runs on a CRM model) with tier, reason and scored-at, in three properties you create and name. It updates, never creates, and writes no other field. The default isnone.
// infra/settings.ts
export const crmWriteback: CrmWriteback = {
crm: "hubspot", // "none" | "hubspot" | "salesforce"
matchOn: "domain", // or "id" on a CRM companies model
matchProperty: "domain", // hs_object_id, or Id / your domain field on Salesforce
fields: {
tier: "cargo_tier",
reason: "cargo_tier_reason",
scoredAt: "cargo_tiered_at",
},
};
How often, and how many #
- Schedule. The play runs hourly and tiers only rows that enter its filter:
never tiered, or tiered longer ago than
rescoreAfterininfra/settings.ts. It is"6 months"by default;"7 days"re-scores the whole book weekly, and re-bills every account each week. The value is<n> days,<n> monthsor<n> years; write a week as7 days. - Volume. The accounts already in the model are tiered by one backfill batch (references/run.md); after that, only new and stale rows. Cost is one agent run per company, so 100,000 accounts is 100,000 agent runs on the backfill. Pilot ten rows first and multiply:
cargo-ai orchestration batch create --workflow-uuid <tierAccountWorkflowUuid> \
--data '{"kind":"filter","modelUuid":"<tamCompaniesUuid>","limit":10}' \
--wait-until-finished
Score a CSV of companies once #
“Which companies in this CSV are worth it?” is a one-time answer, not a
pipeline: this cookbook scores a model, not a file. Use the one-off
score-leads skill
(npx skills add getcargohq/gtm-skills/score-leads), which asks for your ICP
criteria, enriches each domain in the CSV and returns a score, reason and tier
per row. Install this cookbook when the same list should stay scored.
What it does #
- Judges against your own rubric. The ICP and
tiering-rubric.mdlive in the context repo. Edit the rubric and the next tier changes, with no deploy. - Looks up only what the row does not hold. Firmographics were settled by tam-building’s filter. The agent searches once, to settle the doubt that would change the tier, and records the page.
- Writes a reason a rep can argue with. Every tier carries two sentences naming the rubric lines that decided it, the evidence URL, and a stamp.
- Hands downstream work four segments.
tier_a_accountsis what contact sourcing and engagement run on;disqualified_accountsis what they suppress. - Runs without a CRM, writes to one when you name it. It tiers
tam_companiesin Cargo by default;crmWritebackadds the CRM update described above.
How it works #
flowchart TD
tam["tam_companies<br/>from tam-building"]
play["tier_accounts play<br/>untiered or stale rows · hourly · added only"]
agent["account_tier_analyst<br/>reads ICP + rubric from context · webSearch"]
write["write tier · rationale · evidence · tiered_at<br/>onto the row"]
segments["tier_a / tier_b / tier_c / disqualified segments"]
crm["update the matching CRM company<br/>tier · reason · scored-at<br/>only when crmWriteback names a CRM"]
tam --> play --> agent --> write --> segments
write -.-> crm
| File | Resource | Role |
|---|---|---|
infra/models/tam-companies.ts | defineModel | a copy of tam-building’s model, plus the four tier columns |
infra/agents/tier-analyst.ts | defineAgent | the judgment: context and webSearch, no write access |
infra/plays/tier-accounts.ts | definePlay | the writes, and the eligibility filter on tiered_at |
infra/settings.ts | (not a resource) | rescoreAfter and crmWriteback, the two settings |
infra/connectors/crm.ts | defineConnector | the CRM, bound; declared only when crmWriteback names one |
infra/segments/tiers.ts | defineSegment ×4 | one per tier the agent can emit |
infra/connectors/anthropic.ts | defineConnector | the LLM, bound |
infra/connectors/ai-ark.ts | defineConnector | the model copy’s source; dropped when tam-building is present |
infra/folders/index.ts | defineFolder ×3 | models, agents and plays, named after the skill |
this skill’s context/tiering-rubric.md | (not a resource) | example rubric to copy into the project’s context/ |
Placeholders (edit before deploy) #
- The rubric: copy
context/tiering-rubric.mdinto the project’scontext/beside the ICP, and rewrite every tier for your business. - The model: when tam-building is installed, move the four
additionalColumnsonto itstam_companiesand delete this copy. languageModelininfra/agents/tier-analyst.ts.infra/settings.ts:rescoreAfter, andcrmWritebackif the tier should reach the CRM.
Cost #
One agent run per company, in LLM tokens plus any web searches, capped by
maxSteps. The pilot measures it on ten rows before the backfill is approved.
After that the play only tiers what arrives and what goes stale.
Verification #
node --import tsx evals/contract.mjs # the graph boundaries, from the compiled registry
cargo-ai cdk types && cargo-ai cdk check && cargo-ai cdk plan
evals/acceptance.md is the line-by-line acceptance test.
Composes into #
contact-sourcing on tier A, agentic-engagement, new-hire-detection.
Works best after tam-building.