TAM building
Build your total addressable market (TAM) list and stand it up as a deployed model in Cargo: your ICP, read from your context (or drafted from your website and customer stories), becomes an AI Ark company search setting industries, company size and countries, sized for free before it bills, and lands as one model other pipelines read.
Set up the tam-building 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/tam-building
3. Then follow .claude/skills/tam-building/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/tam-buildingSay this to your agent
Source every B2B software company in the US and the UK with 20 to 500 employees from AI Ark, using the ICP in our context repo.
Illustrative output #
Fictional records, to show the shape of what comes back.
| Criterion | Confirmed | From |
|---|---|---|
| Industries | software development, computer and network security | icp.md: “Industry: …” |
| Company size | 20 to 500 employees | icp.md: “Headcount: 20 to 500” |
| Countries | United States, United Kingdom | the prompt |
| Result | Value |
|---|---|
| Counted pool | 4,812 companies |
Landed in tam_companies | 500 of 500 (limit) |
| By country | United States 71%, United Kingdom 29% |
| By size band | 20-49: 38%, 50-199: 44%, 200-500: 18% |
| No domain and no LinkedIn | 6 rows |
The report closes on one recommended opening: a CRM coverage analysis, since the workspace already holds HubSpot, to see how many of the 500 are already there.
What you will be asked #
| Input | Why | |
|---|---|---|
| icp | Looked up | It is the one thing that cannot be computed. Everything else here is arithmetic on top of it |
| market_minimum | Looked up | These three are the floor of any TAM. Missing one sources a market with no edge in that dimension: every industry, every size, or the whole world, billed per record |
| sourcing_filter | Looked up | A flat map is ignored silently and a guessed enum member matches nothing. Either way you source a market nobody described |
| pool_size | Looked up | It is the only number that turns “is this filter right” into a question with an answer, and it costs nothing to ask |
| limit | Looked up | fetchCompaniesbills per returned record, so this is the invoice. Below the counted pool,limit` also decides which slice you get |
Done when #
- the ICP came from the context repo, or was researched and approved, and is written to
context/icp.md - industries, company size and countries were proposed from
icp.md(or suggested and marked), confirmed by the operator, and all three are in the deployed filter countCompanieswas run for the filter actually deployed, and its number is recorded before any sourcing run- the sync landed rows, and the row count is at or under
limit - the report splits the landed rows by industry, size band and country, and states actual credits against the estimate
- the report ended on the openings, with one recommended
node --import tsx evals/contract.mjspasses against the adapted resources
What it costs #
Read this before pointing the skill at a market-sized filter.
Counting is free, and it is the cheapest insurance in this skill: aiArk.countCompanies takes
the same filter groups as the search and returns the pool size without billing. Run it for every
candidate filter, every time you widen one.
Research bills per call, and only runs when no ICP is written down. Reading the website and
customer stories is one extraction per batch of pages, and each customer’s LinkedIn page is one
enrichment. Fetch the live prices with cargo-ai connection integration get <slug> for each
integration you use, and keep the customer list to the ones named on the site.
Sourcing is the spend, and it is per returned record, not per call. Immediately before every
preview, run cargo-ai connection integration get aiArk and read the current fetchCompanies
entry under credits.costs. Record the CLI version, the lookup time, and the unit price. The
estimate is limit * unit price, which is why limit is the only control that matters: to spend
less, source less.
The sourced model deliberately carries no schedule. See refresh-cadence above for what a
recurring source really costs.
To build a total addressable market (TAM) list the rest of your go-to-market
stack can use, turn your ICP into an AI Ark company search and land the result
as one model in Cargo. This cookbook settles industries, company size and
countries first, sizes the search for free before it bills, and keeps the
companies as tam_companies. Atomic by design: one connector, one model, one
folder.
cargo-ai cdk add cookbook/tam-building
What it does #
- Starts from the ICP you already wrote, or drafts one from evidence. It
reads the workspace context first. When nothing is there, it offers to read
your website and customer stories and enrich your customers’ LinkedIn pages,
and drafts
context/icp.mdfrom what they share. - Settles the minimum before any filter. Industries, company size and
countries, each guessed from
icp.mdwith the line quoted, or suggested and labelled, then confirmed by the operator. - Counts before it sources.
aiArk.countCompaniestakes the same filter groups as the search, returns{"count": N}, and is free. The search bills per returned record, so this is the difference between a market you chose and one you discovered after paying for it. - Puts the ICP in the filter, not in a post-filter. Every returned record is paid for. Narrowing happens where it costs nothing.
- Needs nothing else. No CRM, no LLM, no play, no key, no seat. AI Ark runs
on the connection the workspace already holds, bound with
default: true. - Ends on openings, not on more infrastructure. A CRM coverage analysis, enrichment, deduplication or scoring: each is a separate job the report offers, with its own dependencies.
How it works #
flowchart TD
icp["context/icp.md<br/>read, or drafted from website, customer stories, LinkedIn"]
minimum["industries · company size · countries<br/>confirmed by the operator"]
count["aiArk.countCompanies<br/>free, same filters, run at design time"]
tam["tam_companies<br/>aiArk.fetchCompanies · the ICP filter · limit · no schedule"]
report["Report: companies found, split by industry, size, country"]
next["Openings: CRM coverage · enrichment · dedup · scoring"]
icp --> minimum --> count
count -.->|"shapes"| tam
tam --> report --> next
-
Write the ICP down in the project’s
context/icp.md, or confirm the one that is there. This skill’scontext/icp.mdis the shape. -
Confirm industries, company size and countries. They are the floor of the filter.
-
Translate the ICP into filter groups in
infra/models/tam-companies.ts. They are nested groups, not a flat map, and enum-backed values come from the integration’s autocompletes. -
Count each candidate filter with
aiArk.countCompanies:shellscriptcargo-ai orchestration action execute --wait-until-finished \ --action '{"kind":"connector","integrationSlug":"aiArk","actionSlug":"countCompanies","config":{}}' \ --data '{"industry":{"industry_or":["software development"]},"employeeSize":{"min_employee_count":20,"max_employee_count":500},"companyLocation":{"location_or":["United States"]}}' -
Set
limitto what you are willing to spend on the first run. -
Deploy and sync once, then read the report and pick an opening.
| File | Resource | Role |
|---|---|---|
infra/connectors/ai-ark.ts | defineConnector | AI Ark, bound: no key, no seat, no cookie |
infra/folders/index.ts | defineFolder | the model folder named after the skill |
infra/models/tam-companies.ts | defineModel | the universe: the ICP filter and the budget |
this skill’s context/icp.md | (not a resource) | example ICP to copy into the project’s context/ |
references/sources.md | (not a resource) | the other company sources, with pros and cons |
Why it is atomic #
An agent installing a cookbook sets up every dependency the infra declares. If the TAM model shipped with a CRM extract, a unified model or a tiering agent, every install would wire a CRM connection or an LLM before it could source a single company, including for a company that has neither. Building the TAM needs AI Ark and a written ICP. Everything that acts on the TAM afterwards is a next step with its own cookbook.
Placeholders (edit before deploy) #
- The ICP: copy this skill’s
context/icp.mdinto the project’scontext/, or keep the one already there. The example is a technical B2B software ICP; nothing in it is yours. - The filter groups in
infra/models/tam-companies.tsconfig, always includingindustry,employeeSizeandcompanyLocation. Nested groups,_orto include and_notto exclude, enum values fromlistIndustries/listSeniorities/listDepartmentsAndFunctions/listFundingTypes, numeric ranges as numbers. config.limitin the same file: the per-sync record budget, and the only real cost control.
Cost #
Counting is free. Research, when there is no ICP, bills per page read and per
customer enriched. Sourcing bills per returned record, so the estimate is
limit times the current per-record price: fetch it with
cargo-ai connection integration get aiArk immediately before any preview
rather than trusting a number written here.
The sourced model carries no schedule on purpose. A cron re-runs the same search and re-bills every returned record, including the rows already in the model: a monthly refresh buys the handful of new companies at the price of the whole pool. Sourcing is a deliberate spend.
Alternatives #
AI Ark is the default because it is the only source that counts for free with
the filters it bills on. references/sources.md
compares it with the other sources the contract accepts as a swap:
| Source | Pick it when | Watch out for |
|---|---|---|
| AI Ark | You want the pool size before you commit | Enum-backed filters; per-record billing; 10,000 per sync |
| FullEnrich | Budget matters, or you want a free refresh | No count; no persona, funding or lookalike filter |
| Apollo | The market is defined by hiring or funding | No industry taxonomy (keyword tags only); no free count |
| Sales Navigator | The market is defined by LinkedIn facets | Needs a seat; highest per-record price; no domain; 5,000 per search |
People Data Labs, TheirStack, Ocean.io and CompanyEnrich are covered there too, with the reason each one is not a default TAM source.
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 #
A CRM coverage analysis (how much of the TAM the CRM already holds),
crm-enrichment, crm-deduplication, and account-scoring, which tiers
tam_companies in place.
references/run.md lists them as the report’s openings.