Author a GTM skill in getcargohq/gtm-skills (one-off CLI job or deployed pipeline). Use when creating, adding, scaffolding, or reviewing a new skill, SKILL.md, cookbook, or pipeline folder in gtm-skills.
Installs into .claude/skills of the current project.
Are you the author of Create Gtm Skill?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/getcargohq-create-gtm-skill)
---
name: create-gtm-skill
description: >-
Author a GTM skill in getcargohq/gtm-skills (one-off CLI job or deployed
pipeline). Use when creating, adding, scaffolding, or reviewing a new
skill, SKILL.md, cookbook, or pipeline folder in gtm-skills.
---
# Create a GTM skill
This is an authoring skill for people writing this repo. It is not a
customer skill and does not install with `npx skills add`. The canonical
copy lives in `.agents/skills` so Codex, Claude Code, and Cursor all load
the same file (the last two via symlink).
Read `CONTRIBUTING.md` first. That file is the contract the validators
enforce; this file is the procedure.
One folder at the repo root is one customer skill. Install path:
`npx skills add getcargohq/gtm-skills/<name>`.
## 1. Pick the kind
| Kind | Frontmatter | Job |
| -------- | --------------------------- | -------------------------------------------------------------------------- |
| one-off | `metadata.source: one-off` | Runs once in a turn: exact `cargo-ai` command and a price |
| pipeline | `metadata.source: cookbook` | Deploys a standing play. Customer copy says **pipeline**, never "cookbook" |
`metadata.source` must be exactly one of those two strings. The validator
uses `cookbook` as the internal discriminator. Do not put that word in
README, plugin listings, skill body, or examples. Customers learn: some
skills run once; some deploy a pipeline that keeps running.
If the same job exists both ways, they compete for prompts. Pin the seam in
`evals/routing.jsonl`: one case that must hit the pipeline, one that must
hit the one-off sibling.
Name the folder after the job, not the vendor. `name` in frontmatter equals
the folder name. The slug is what an agent matches before it opens the file,
so the kind has to be readable from the name:
| Kind | Shape | Examples |
| --------- | --------------------- | ------------------------------------------------------ |
| one-off | verb + object | `enrich-company-data`, `score-leads`, `build-tam-list` |
| pipeline | the standing practice | `tam-building`, `account-scoring`, `crm-enrichment` |
| migration | `x-to-cargo` | `clay-to-cargo` |
A verb says "do this once." A standing noun says "keep this running." That
is how `build-tam-list` and `tam-building` stay apart, and why
`score-leads` pairs with `account-scoring` rather than `score-accounts`.
Do not give both kinds the same stem.
`enrich-crm` would read as a one-off next to `enrich-company-data`. A
pipeline that keeps CRM records filled is `crm-enrichment`. Contacts later
stay in that same slug. Accounts that are not in a CRM, if they land, are
`account-enrichment`. Planned pipelines stay nouns (`contact-sourcing`,
`signal-based-tam`, `rep-cockpit`). Do not rename existing skills to force
`-ing` vs `-ment`; the kind matters more than the suffix.
Inside a cookbook, resource slugs are snake_case: plays, workflows, tools,
agents, segments and folders (`score_accounts`, `enrich_crm_contact`,
`account_enrichment`, `tam_tier_analyst`, `tam_tier_a`,
`crm_enrichment_plays`), the same as the connectors and models the CDK
already requires it of. Workers and apps are the exception: the CDK requires
kebab-case for them. File names stay kebab-case (`score-accounts.ts`). A slug
is the resource's identity in `cargo.state.json`, so renaming one after a
deploy creates a new resource and orphans the old one: get it right before
the first deploy.
A model that extracts a system you hold (a CRM, a warehouse) pulls all the
data. Never filter or pick columns in its `config`: extract every record and
every column, and narrow in the SQL or the play filter that reads it. A
filter in the config is a second place the question is asked, invisible to
anyone reading the queries, and changing it means a redeploy and a
re-extraction instead of an edited query. A paid search source is the
exception, because there the search is the data source rather than a filter
on it: `aiArk.fetchCompanies` or a Sales Navigator search bills per returned
record, so its query in `config` is what decides what you buy.
**Native models first.** A worked example runs on Cargo native models, not a CRM connector, so it
deploys on a bare workspace. When the outcome needs accounts, contacts, opportunities or activity,
declare the shared `gtm_*` models exactly as `references/native-models.md` defines them;
`scripts/check-native-models.mjs` fails on drift. The CRM is the `crm-backed` variation.
## 2. Description (the only text before load)
Four parts, in order:
1. The job in one sentence
2. `Triggers:` literal quoted phrases a user would type
3. Proper nouns (connectors, CRM, CDK)
4. `Skip when:` the sibling skill that should win instead
Quote any YAML value that contains colon-space. Unquoted, the installer
skips the file with a warning nobody reads.
## 3. Write the kind
### One-off
Copy the structure of `enrich-company-data/SKILL.md`:
- Setup (CLI install, login, session stamp)
- Do the job (exact `cargo-ai orchestration action execute` / `execute-batch`)
- Example (see below)
- What it costs (table of `integration.action` → credits)
- Worth knowing / Going further / star ask
Slugs and prices are not yours to invent. `validate.ts` asserts every
`integrationSlug`/`actionSlug` and every credit number against
`getcargohq/cargo-skills` playbooks. Copy from a sibling, then run
`node scripts/validate.ts`.
Register: `skills.sh.json`, `hooks/skill-loads.sh`, root `README.md` table.
### Pipeline
Copy the section order from `tam-building/SKILL.md`. The validator requires
these headings:
1. Honest banner: `**State: to-be-approved.**`
2. `## The outcome`
3. `## Example` (see below)
4. `## Put it in your project` (copy the procedure from `tam-building`; each
skill carries its own)
5. `## What you will be asked` — derive before ask; more than ~4 asked rows
means you skipped lookups
6. `## What you can change` — offer unprompted; every variation has a cost
7. `## What should not change` — name the concrete symptom if violated
8. `## Done when`
9. `## What it costs`
10. `## Composes into`
Folder:
```
<name>/
SKILL.md
README.md
infra/ # or models/, plays/, agents/ — whatever the outcome needs
references/ # supporting agent docs; never a nested SKILL.md
evals/acceptance.md
```
Isolation: every model and connector the resources import lives in this
folder. No relative import may leave it. Two pipeline skills may both
carry an `accounts` model; the placing agent rewires to the project's
existing one.
Resources must earn their deploy:
- Do not wrap a single connector action in a tool. That is a one-off.
- Do not declare a segment that restates the play's own filter.
- Do not add `examples/example.md` until a live install has sanitized
audit findings, mappings, a plan summary, and lookup-backed credits.
- A folder of CDK with no `SKILL.md` does not belong at the root. Older
examples live in history: `git checkout 305cd88 -- <name>`, then write
the skill.
**Credits.** Pipeline markdown must not contain a numeric credit amount.
Fetch live prices at run time (`cargo-ai connection integration get <slug>`).
One-offs quote playbook numbers; pipelines do not.
**Write the system you write back to.** If the outcome updates a CRM
record, the play runs on that CRM extract and matches the CRM record id.
Do not sit a native `unifyAccounts` / `ids` map between the play and the
write — the run looks successful and nothing lands.
**One shape in the file.** A new pipeline's checked example runs on the
shared `gtm_*` native models (`references/native-models.md`); its
`crm-backed` variation names the HubSpot swap, and Salesforce and Attio adapt
that (connector, extractor, record-id, write action, fill-blank guard). A
pipeline whose whole job is a CRM (crm-enrichment, crm-deduplication) keeps
HubSpot as its checked example. No parallel branches.
CDK workflow bodies must compile. These fail `cargo-cdk check` / `plan`:
`undefined`/`void`, comma / SequenceExpression, `Date#getTime()`.
Register: `skills.sh.json` (its stage, at its place in the order: the order is
what an agent suggests next), `hooks/skill-loads.sh`,
root README pipeline table, `.github/data/approvals.json` with
`state: to-be-approved` and empty evidence.
### Both kinds: personas and the example
`validate.ts` requires these of every skill; the site renders them before
anyone installs.
- `metadata.personas`, right after `metadata.source`: 1–3 of
`sales-development`, `account-executive`, `revops`, `sales-leadership`,
`marketing`, `gtm-engineering`, primary first.
- `## Example`, in exactly this shape:
```
## Example
> Find work emails for the 40 people in webinar-attendees.csv.
Illustrative output, fictional records:
<table or fenced block, about 20 lines at most>
<one closing line with the result in numbers>
```
Fictional companies on the `.example` TLD. A one-off's credits must add up
from its own cost table; a pipeline quotes none and shows what the deployed
play writes. Never a command in it, and never a table row that opens on a
backticked `integration.action` cell — the validator reads that as a price.
## 4. Finish
```sh
node scripts/build-catalog.mjs
node scripts/generate-llms-txt.ts
npm run typecheck
npm run validate
npm run format:check
```
`catalog.json` and `llms.txt` are generated. Edit SKILL.md, then regenerate.
Do not claim an outcome for a pipeline skill until it is approved (demo
workspace + two implementations in `approvals.json`). The banner in
`SKILL.md` must match that file exactly.
## Anti-patterns
- A new root skill that is the same job as an existing slug with extra
words (`crm-account-enrichment` vs `crm-enrichment`)
- A pipeline named like a one-off (`enrich-crm`, `score-accounts`,
`build-tam`) or a one-off named like a pipeline (`tam-building` for a
list today)
- Customer-facing "cookbook"
- Hardcoded credits in a pipeline
- Stub walkthroughs that restate `SKILL.md`
- `PLACEHOLDER` values that survive into a "done" template when the
checked example can use real HubSpot (or whatever) property names
- Asking the operator for anything a connector or live schema can answer