Your CSV
Your own CSV of people, judged by an AI filter, given two intro lines each, and written to a local CSV, for one model key and cents on the model
What you'll learn
You have a CSV of people and an Anthropic key, and you want them judged and written with your own prompts.
- map CSV columns to gtme's field names
- plan and simulate before spending anything
- run armed and read what the model cost
- change a prompt and re-run
This needs a CSV of people with a header row, and an Anthropic API key. If you haven't seen a pipeline run yet, See it run needs neither.
It spends cents on the model for the armed run, and $0 to simulate and plan. Nothing sends, because the delivery target is a file on your machine. Each row's name, title, and company domain go to Anthropic with your prompts for the filter and compose steps. Nothing else leaves the machine.
Make a new folder with its own ledger, so nothing from See it run counts as already delivered, and fetch the pipeline with its three sample people:
mkdir -p gtme-mine && cd gtme-mine
export GTME_LEDGER=./ledger.db
curl -fsSLO https://raw.githubusercontent.com/gtme-run/gtme/main/examples/my-csv.yaml
curl -fsSLO https://raw.githubusercontent.com/gtme-run/gtme/main/examples/contacts.csv
The file you fetched
my-csv.yaml reads a CSV, keeps the people a prompt says fit, writes two lines for each, and appends them to out.csv. Here it is with the comments stripped:
columns: maps each canonical field, the standard name every step reads, to your header for it. It already matches contacts.csv, so run it as shipped first.
Run the sample
-
Simulate it for $0:
gtme run my-csv.yaml --simulateThe output is similar to the following:
simulate: recorded responses only — no network, no spend, nothing sends, nothing persists ... out: 3 in, 0 out, 0 cached, 0 filtered, 0 failed, 3 held (dry run) ... out: resolved variables for 3 record(s) — review, then run again without --dry-run to arm: jane.doe@acme.com first_line: "Fixture first line for jane.doe@acme.com" ps_line: "Fixture ps line for jane.doe@acme.com" ... total: $0 (estimated) spentSimulate answers the AI steps from fixtures, canned answers that say so. It holds delivery the same way a dry-run does, and "held (dry run)" is the CLI's wording for that. The resolved variables are the values each kept row would get.
-
Store your key.
gtmeprompts for it, so the key never appears on the command line:gtme secret set ANTHROPIC_API_KEY -
Plan:
gtme plan my-csv.yamlA missing key is a warning at plan time, not an error. Without one, each AI step shows the following:
warning: optional credential ANTHROPIC_API_KEY is not set; this step will fail at run time if it needs it warning: optional credential ANTHROPIC_WORKSPACE_ID is not set; this step will fail at run time if it needs it est/record: ?The
ANTHROPIC_WORKSPACE_IDwarning stays; ignore it unless your key is workspace-scoped. Plan prints a cost per record when a step declares one. The?means the model cost is metered, so the receipt is where you see it. -
Run it for real. This run is armed. It spends on the model for
fitandlines, and it sends nothing.gtme run my-csv.yamlrun 01M3D1R0CE22N0DJ4DCTFC0R7D (my-csv) source [info]: read 3 rows from contacts.csv source: sourced 3 records fit: 3 in, 3 out, 0 cached, 0 filtered, 0 failed lines: 3 in, 3 out, 0 cached, 0 filtered, 0 failed ... run 01M3D1R0CE22N0DJ4DCTFC0R7D — done step adapter in out empty cached filtered failed cost avoided source csv/source 0 3 - 0 - - $0 - fit ai/filter 3 3 - 0 - - $0.0027 - lines ai/compose 3 3 - 0 - - $0.0051 - out csv/deliver 3 3 - 0 - - $0 - total: $0.0078 (estimated) spentRead
coston thefitandlinesrows for what the model cost: under a cent for three people. On theoutrow,outcounts the rows written toout.csv. All three passed the filter this time; the ledger keeps the verdict either way. -
Run it again:
gtme run my-csv.yamlrun 01M3D1R9N6HMB6TF7K2NNCERN3 (my-csv) source [info]: read 3 rows from contacts.csv source: sourced 3 records fit: 3 in, 0 out, 3 cached, 0 filtered, 0 failed lines: 3 in, 0 out, 3 cached, 0 filtered, 0 failed out: 3 in, 0 out, 0 cached, 0 filtered, 0 failed, 3 already delivered run 01M3D1R9N6HMB6TF7K2NNCERN3 — done step adapter in out empty cached filtered failed cost avoided source csv/source 0 3 - 0 - - $0 - fit ai/filter 3 0 - 3 - - $0 ? lines ai/compose 3 0 - 3 - - $0 ? out csv/deliver 3 0 - 0 - - $0 - out: 3 already delivered total: $0 spent, $0.0000+? avoided via cache (6 records skipped)On both AI rows,
cachedmatchesinand the cost is $0, because every judgment is in the ledger. The?underavoidedis the model's metered price, which the receipt can't restate; the first receipt already told you it was $0.0078. Theoutrow writes nothing, andout: 3 already deliveredcounts the three rows already inout.csv.
Run your file
We recommend 10 rows first. Trim your CSV, then point path: at the sample:
head -n 11 CSV_FILE > sample.csv
Replace CSV_FILE with your file's name.
Edit columns: for your headers, rewrite both prompts, then simulate, plan, and run. A header like "Full Name" maps itself to full_name. The three fields in uses: must be mapped or plan stops, naming the field and listing the headers it found. A blank cell still goes to the model, and the receipt counts it, such as 1 missing title. Any other header is kept as csv.<header>.
When the sample reads right, set path: to the full file. The full run skips the 10 rows it already judged, and out.csv gets none of them twice.
Questions after the first run
-
Does a new prompt re-judge? Yes, because a changed
template:changes the step's judgment signature, and the cache matches only the same prompt on the same inputs. -
What's in
out.csv? It holds the kept rows only:identity_key,first_line, andps_line. Addfull_name: full_nameundervariables:to carry the name. -
Why was someone filtered out?
gtme show KEYprints the fields, not the verdict. The model's reason is in the ledger:gtme query "SELECT i.identity_key, e.detail ->> 'reason' AS reason FROM step_events e JOIN identities i ON i.id = e.identity_id WHERE e.step_id = 'fit' AND e.event = 'done' AND e.detail ->> 'pass' = 0"
Next
Iterate covers tuning the filter and running again. If your next step is your vendors, Your stack swaps the CSV for them.