GTM as code
gtme is a CLI for GTM data pipelines: a small YAML file describes a campaign, the runner executes it against vendor adapters, and an append-only ledger remembers every fact, so re-runs cost less and nothing is delivered twice.
name: apollo-to-instantly
version: 1
source:
use: apollo/search
with:
query: "saas"
titles: ["vp marketing", "head of marketing"]
employee_ranges: ["50,200"]
limit: 5
steps:
- id: icp-filter
use: ai/filter
uses: [first_name, title, company_name]
with:
template: >
Keep only contacts likely to own outbound tooling decisions.
batch_size: 25
...
- id: personalize
use: ai/compose
when: icp-filter.passed
uses: [recent_posts, role_history]
with:
template: >
Write first_line and ps_line using recent_posts and role_history.
first_line references something specific and recent; ps_line is one
short, low-pressure sentence. No flattery, no exclamation marks.
batch_size: 25
- id: send
use: instantly/add-to-campaign
with:
campaign: 0198a0b1-2c3d-4e5f-8a9b-0c1d2e3f4a5b # the campaign id
variables:
first_line: first_line
ps_line: ps_line
idempotency: emailrun 01M3D1ZTKBQBS57C9WPK8NQM60 — done (dry run — nothing sent)
step adapter in out empty cached filtered failed cost avoided
source apollo/search 0 5 - 0 - - $0 -
icp-filter ai/filter 5 5 - 0 - - $0.0105 -
reveal apollo/enrich 5 5 - 0 - - $0.0500 -
linkedin harvest/profile 5 5 - 0 - - $0.0600 -
personalize ai/compose 5 5 - 0 - - $0.0232 -
send instantly/add-to-campaign 5 0 - 0 - - $0 -
send: preflight ok — campaign "Q3 VP Marketing" (0198a0b1-2c3d-4e5f-8a9b-0c1d2e3f4a5b) — 3 check(s) (✓ campaign active, ✓ variable first_line referenced, ✓ variable ps_line referenced)
total: $0.1437 (estimated) spentThat's a dry run against live Apollo, Harvest, Anthropic, and Instantly. Apollo returned five people by title and company size, and the AI judge kept all five. Apollo revealed their contact details, Harvest pulled their LinkedIn profiles, and the model wrote two lines for each. The send step checked the campaign and held all five, so nothing went out. The run cost fourteen cents.
After an armed run adds the five to the campaign, run it again and the paid steps come back from the ledger:
step adapter in out empty cached filtered failed cost avoided
source apollo/search 0 5 - 0 - - $0 -
icp-filter ai/filter 5 0 - 5 - - $0 ?
reveal apollo/enrich 5 0 - 5 - - $0 $0.0500
linkedin harvest/profile 5 0 - 5 - - $0 $0.0600
personalize ai/compose 5 0 - 5 - - $0 ?
send instantly/add-to-campaign 5 0 - 0 - - $0 -
send: 5 already delivered
total: $0 (estimated) spent, $0.1100+? avoided via cache (20 records skipped)Every paid step reads cached 5 and spends $0. The Apollo and Harvest rows show their dollars under avoided, and the AI rows show a ?, which is why the total ends in +?. The send step reads 5 already delivered: the five are already in the campaign, and idempotency: email keeps a re-run from adding anyone twice. That isn't a saving, so it isn't counted as cached.
Install
brew install gtme-run/tap/gtme # macOS and Linux, arm64 and amd64The formula installs one static binary. Nothing runs in the background, and there's no account to create. The example runs five people because that's the size we recommend for a first run; limit: is the line to raise after that. Install covers the release tarball, go install, and building from a checkout.
Start has four ways to begin, sorted by what you have on hand. The first needs no keys and spends nothing.