Use gtme from Claude Code
Install the gtme plugin in Claude Code, describe a goal in plain words, and take the pipeline it writes from plan to an armed run
What you'll learn
You use Claude Code and want it to build and run a gtme pipeline for you, and you want to know which parts stay yours.
- how to add the gtme plugin and which skill fires when
- what a session looks like from your goal to an armed run
- what you say to Claude Code, and where you step in
Goal: you give Claude Code this request, and you end with for-sdr.csv, one opening line per senior signup. Claude Code turns it into a pipeline file and runs it:
Every Monday I export trial signups to signups.csv. Keep the VPs, heads,
and directors, write each one a line our SDR can open with, and put
them in a CSV for the SDR.
Before you start
You need Claude Code, a terminal, and gtme installed. For agents has the rules Claude Code follows. This guide is what the session looks like from your side of the chat.
This guide needs no keys and spends $0. The pipeline reads a CSV and writes a CSV, with no vendor and no model. The only thing it sends is a file on your machine, for-sdr.csv.
You do steps 1 to 3 yourself. From step 4 on, Claude Code runs every command shown and reads the output back to you; the blocks show what it ran. We describe what Claude Code says in plain words, because its wording changes from run to run. Every gtme output on the page is real.
Where you step in:
- Say yes to the plan. The skill reads its plan back before it builds anything.
- Read the dry-run. It shows exactly what would be written or sent. On a pipeline with a vendor or a model step, the dry-run is also the first command that costs money, and the agent tells you what it will spend before it runs it.
- Say send. On a vendor target, such as an Instantly campaign, nothing arms until you reply to "Send it?" after reading the dry-run.
- Enter keys yourself. When plan names a missing key, run
gtme secret set KEY_NAMEin your own terminal and paste the key there, never in the chat.
These are the agent's rules plus your read; gtme itself can't tell who ran a command.
Steps
-
Install gtme. Follow Install, then check it:
gtme versionThe output is similar to the following:
gtme v0.6.1If
gtmeisn't found, finish Install before going on, because every skill calls it. -
Add the plugin. In Claude Code, enter these two lines:
/plugin marketplace add gtme-run/gtme /plugin install gtme@gtme-runClaude Code now has four skills, and it picks one from what you say, so you rarely call one by name:
You say something like Skill that fires "Find the senior people in this signup list" /gtme:create-pipeline"Run it," "does this work," "send it" /gtme:run-pipeline"gtme doesn't have Hunter" /gtme:create-adapter"What did last week's run cost?" /gtme:analyzeThe skills read what gtme can do from the gtme you installed, so they match your version (ADR-007, the decision record behind that).
-
Say what you want, in your words. Save this as
signups.csvin an empty folder, and start Claude Code in that folder:First Name,Email,Job Title,Company Website Jane,jane.doe@acme.com,VP Marketing,acme.com Bob,bob@globex.io,Head of Growth,globex.io Carol,carol@initech.dev,Software Engineer,initech.dev Dev,dev@umbrella.co,Director of Sales,umbrella.co Erin,erin.wu@hooli.com,Marketing Intern,hooli.comThen enter the request from the goal. The create-pipeline skill asks what it can't infer, such as which tools you use and how many people a run should cover. Then it reads its plan back in one paragraph and waits for your yes. It doesn't ask you to read YAML.
-
Let it build and plan, one step at a time. The skill writes a file and runs
gtme planafter each step it adds. Plan spends nothing and calls no network. Here's the file it ends with,trial-signups.yaml:name: trial-signups version: 1 source: use: csv/source with: path: signups.csv columns: { title: Job Title } steps: - id: senior use: sql/filter with: query: > SELECT identity_id FROM current_values WHERE field = 'title' AND (value LIKE 'VP%' OR value LIKE 'Head of%' OR value LIKE 'Director%') - id: opener use: text/compose uses: [first_name, title] provides: [opener] with: template: > {{ record.first_name | default: "Hi there" }}, thanks for trying us. Most teams with a {{ record.title }} start with the weekly report, so that's where I'd look first. - id: out use: csv/deliver with: path: for-sdr.csv variables: email: email first_name: first_name opener: trial-signups.opener idempotency: emailPipeline trial-signups: source csv/source, then senior (sql/filter), then opener (text/compose), then delivers with out (csv/deliver), once per email. Every step writes to the ledger, and cached, AI, and deliver steps read it first. You don't need to read it; it's here so you recognize it later.
seniorkeeps rows by title,openerfills in a sentence per person withtext/compose, andoutwrites the file. Those are the filter, compose, and deliver roles.If the draft leaves out the
columns:line, plan stops on it:gtme plan trial-signups.yamlgtme: step "opener": needs title, which no earlier step provides (available: company_website, csv.job_title, email, first_name)The error names the fix: your header
Job Titlecame in ascsv.job_title, so the agent maps it totitleand plans again. The output ends with the following:... send surface: 1 deliver step(s) out → csv/deliver (touch scope: trial-signups) available fields after the last step: company_website, email, first_name, title, trial-signups.opener plan ok — nothing has been spentsend surfaceis the list of places this pipeline can write to. Here there's one, and it's a local file. -
Rehearse it with
--simulate. When plan is clean, Claude Code says it's built and moves on by itself, without waiting for you. The run-pipeline skill runs the whole file offline, the lowest rung of the gate ladder:gtme run trial-signups.yaml --simulateThe output is similar to the following:
simulate: recorded responses only — no network, no spend, nothing sends, nothing persists ... step adapter in out empty cached filtered failed cost avoided source csv/source 0 5 - 0 - - $0 - senior sql/filter 5 3 - 0 2 - $0 - opener text/compose 3 3 - 0 - - $0 - out csv/deliver 3 0 - 0 - - $0 - ... total: $0 spentFive came in,
seniorfiltered Carol and Erin, and three were held atout. Nothing persists, sofor-sdr.csvdoesn't exist yet. -
Read the dry-run. A dry-run runs every step for real except delivery, and prints what each delivery would carry:
gtme run trial-signups.yaml --dry-runThe output is similar to the following:
dry run: deliver steps will resolve and receipt their variables, but nothing sends ... out: resolved variables for 3 record(s) — review, then run again without --dry-run to arm: jane.doe@acme.com email: "jane.doe@acme.com" first_name: "Jane" opener: "Jane, thanks for trying us. Most teams with a VP Marketing start with the weekly report, so that's where I'd look first." ... total: $0 spentThe agent reads these lines back to you. This is the moment to say "make the opener shorter" or "drop the directors," and Claude Code edits the file, plans again, and brings you a new dry-run.
-
Arm it. Arming, the run that writes and sends for real, is the same command with no flag:
gtme run trial-signups.yamlThe output is similar to the following:
... step adapter in out empty cached filtered failed cost avoided source csv/source 0 5 - 0 - - $0 - senior sql/filter 5 3 - 0 2 - $0 - opener text/compose 3 0 - 3 - - $0 ? out csv/deliver 3 3 - 0 - - $0 - total: $0 spent, $0.0000+? avoided via cache (3 records skipped)outwrote 3 rows.openershowscached 3because the dry-run already wrote those lines to the ledger, and the armed run read them back. The?meanstext/composehas no price to report, and because it calls nothing, the skip saved $0.The target here is a file on your machine, so the agent can arm it after you've seen the dry-run's total line, here $0. On a vendor target, it stops and asks "Send it?" first, and an earlier "go ahead, don't ask again" doesn't count as that reply.
What you have now
You have trial-signups.yaml, and a for-sdr.csv your SDR can work from. It holds Jane, Bob, and Dev, each with an opener. The first column, identity_key, is how gtme recognizes each person across runs, here their email (Identity keys).
identity_key,email,first_name,opener
jane.doe@acme.com,jane.doe@acme.com,Jane,"Jane, thanks for trying us. Most teams with a VP Marketing start with the weekly report, so that's where I'd look first."
...
To check it, ask Claude Code to run it again. The receipt shows out with 0 out and out: 3 already delivered, because idempotency: email means nobody gets written twice:
...
out csv/deliver 3 0 - 0 - - $0 -
out: 3 already delivered
...
Next Monday, replace signups.csv with the new export, start Claude Code in the same folder, and say "run the trial signups." New rows get openers, and last week's people are skipped.
Next
- Your CSV swaps the SQL rule and the fill-in sentence for a model that judges and writes, with one key you enter.
- Your stack delivers to a vendor, where the arm gate is yours.
gtme secretstores the keys a vendor pipeline asks for, from your own terminal.