gtme

skill
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Gecti
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Run outbound campaigns from Claude Code: YAML pipelines, an append-only ledger, nothing sent twice.

README.md

/gtme: run outbound campaigns from Claude Code

/gtme is a CLI and a Claude Code plugin. You describe a campaign in
your own words, Claude writes it as a small YAML pipeline, and /gtme runs
it against your vendors. An append-only ledger remembers every fact, so a
re-run pays only for what's new and nobody gets the same message twice.

The /gtme console in Claude Code: one prompt runs a pipeline, the re-run pays nothing, and the send waits for your yes

▶ Watch the 42-second demo.
One prompt runs a pipeline, the re-run pays nothing, and the send waits for
your yes. More at gtme.run.

Get started in three steps

  1. Install the binary.

    brew install gtme-run/tap/gtme     # macOS and Linux, arm64 and amd64
    
  2. Add the plugin in Claude Code.

    /plugin marketplace add gtme-run/gtme
    /plugin install gtme@gtme-run
    
  3. Type /gtme. The console opens beside the chat. Ask for a campaign,
    or start with "See it run" in START.md, which needs no
    keys and spends nothing.

Other ways to install, and building from a checkout, are under
Install.

From a sentence to a sent campaign

Four prompts in Claude Code, and what each one returns. Every command is
the one Claude runs for you, and every output comes from a real run.

1. You ask for the campaign.

Find VPs and heads of marketing at 50 to 200 person SaaS companies in
Apollo. Keep the ones likely to own outbound tooling, write a first line
and a PS from their recent posts, and add them to my Q3 VP Marketing
campaign in Instantly. Five people to start.

Claude writes apollo-to-instantly.yaml:

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: email

2. You ask for a rehearsal.

Dry-run it against my real accounts.

Claude runs gtme run apollo-to-instantly.yaml --dry-run:

run 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) spent

Five people found, judged, enriched, and drafted for fourteen cents. The
send step checked the campaign and held all five.

3. You say send.

Looks good. Send it.

Claude asks before the armed run, and you confirm. Then it runs
gtme run apollo-to-instantly.yaml, which adds the five to the campaign.

4. You run it again.

Run it again.

Claude runs gtme run apollo-to-instantly.yaml again:

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 comes back from the ledger at $0, and idempotency: email
keeps the send from adding anyone twice.

The console

Claude Code folds a command's output to one line, so the plugin carries a
console: a pane beside the chat that /gtme opens, and that a run the
agent starts opens by itself. It shows the latest run's steps as they
move, with the receipt's counts and spend. When a human/* step is
waiting on you, each record gets its controls there (approve or reject, a
review label, a draft to edit), and every answer is recorded in the
ledger. The console never runs anything that spends or sends; that stays
with you. plugin/README.md has the details.

The four skills behind it are /gtme:create-pipeline,
/gtme:run-pipeline, /gtme:create-adapter, and /gtme:analyze. Claude
picks one from what you ask, or you can call one by name.

Under the hood

Outbound tooling assumes you want a UI, credits, and someone else's opinion
of your workflow. If you'd rather have a CLI, a ledger you can query, YAML
you can diff, and receipts for every dollar — this is that. Campaigns are
pipelines. Adapters are data. Judgment is versioned. Everything replays.

What it is

  • A single static binary (gtme) that executes campaign pipelines
    defined in YAML. No daemon, no hosted anything, no login.
  • An append-only SQLite ledger as the data bus. Steps never pass
    records to each other — they read a projection of what's known and write
    facts back, with provenance, confidence, and freshness on every value.
    What your pipelines learn accumulates; what a run did is receipted.
  • Contracts everywhere. Every step declares needs and provides as
    JSON Schema against a canonical field registry, so gtme plan proves a
    pipeline coherent — end to end — before a single record moves or a cent
    is spent. AI steps live behind the same contract as everything else.
  • Adapters as data. Most vendor APIs are CRUD over HTTP, so most
    adapters here are bindings: declarative YAML interpreted by one
    generic engine — auth, pagination, extraction, error mapping,
    idempotency, cost, all frozen at authoring time. The moment an
    integration needs real logic, it graduates to a process adapter speaking
    NDJSON over stdin/stdout, in any language.

Use cases

  • Outbound campaigns — source → enrich → AI-judge → AI-compose →
    deliver, with the send gated behind a human-reviewable receipt.
  • Enrichment that stops re-billing you — freshness-windowed caching
    means top-ups and re-runs pay only for what the ledger doesn't already
    know; the receipt prints what the cache saved.
  • Qualify/send decomposition — a cheap qualify pipeline fills a
    group (a durable, hand-editable set); a separate send pipeline
    consumes it, records touches, and suppresses re-contacts by window.
    AI verdicts become recorded decisions: an identity is judged once per
    scope, not re-rolled on every run.
  • Research enrichment — http/enrich fetches a page to markdown as a
    ledger fact (with mandatory freshness — web content rots), and AI steps
    judge the stored content. Fetch once, judge many.
  • Deterministic transforms in SQL — sql/transform and sql/filter run
    declared, read-only queries over the ledger: derive fields, bucket
    titles, gate on "3+ known contacts at this company" — no AI spend for
    computable questions.
  • The universal floor — CSV in, groups in; any-URL POST out, CSV
    out. Anything with an export or an import button is wireable
    today, even before a proper adapter exists.
  • Portable campaigns — gtme freeze --bundle snapshots a run into a
    self-contained folder (pipeline + bindings + fixtures + hash manifest)
    that runs, simulates, and diffs anywhere.

Architecture

                  pipeline.yaml  (the only authoring surface)
                        │
                    gtme plan ──── contracts, credentials, cost — $0
                        │
   ┌────────────────────┼─────────────────────────────┐
   │ runner             ▼                             │
   │   ┌─────────┐  ┌────────┐  ┌─────────┐  ┌─────────┐
   │   │ source  │→ │ enrich │→ │ ai/sql  │→ │ deliver │   steps see only
   │   └────┬────┘  └───┬────┘  └────┬────┘  └────┬────┘   projections,
   │        │  ▲        │  ▲         │  ▲         │  ▲      never the ledger
   ├────────┼──┼────────┼──┼─────────┼──┼─────────┼──┼──┐
   │        ▼  │        ▼  │         ▼  │         ▼  │  │
   │   ledger (append-only SQLite)                      │
   │     identities · field_values (facts + provenance) │
   │     runs · step_events · costs · deliveries        │
   │     groups · group_events (decisions about sets)   │
   │     payloads (raw responses — cache, purgeable)    │
   └────────────────────────────────────────────────────┘

The load-bearing choices:

  • The ledger is the bus. Cache-aware waterfalls, resume after a crash,
    cost attribution, and "what do we know about this person" as a SQL query
    all fall out of one structural decision: facts live in the ledger, not
    in a stream between steps.
  • Two adapter tiers. Bindings (YAML, interpreted, cannot execute code)
    for anything that sells an API; NDJSON processes for anything that must
    be fought for. Both speak the same wire protocol and pass the same
    conformance kit: golden vendor payloads in → canonical records out.
  • A closed grammar. The pipeline surface is a small, enumerable set of
    keys — no expression language, no DSL to hallucinate. Expressivity comes
    from composing a small vocabulary against a canonical field registry.
  • The gate ladder: simulate → plan → dry-run → armed. Simulation
    executes the whole pipeline from conformance fixtures — no network, no
    keys, deterministic. Plan proves contracts. Dry-run does everything but
    deliver, rendering exactly what would send. Arming is the same command
    without the flag.
  • Agent-operable by design. gtme help --agent emits the full CLI and
    adapter surface as one machine-readable document, and gtme help --bindings the contract for authoring an adapter it does not ship;
    every error names its fix; every question about state has a deterministic answer path. An
    agent can author a pipeline and validate its structure and behavior
    before a human reviews one artifact and arms it.

Why engineers who do GTM

Speed to deploy. A new vendor integration is a YAML file — the Apollo
source adapter shipped here is ~150 lines of declarative binding
(see it), and the authoring
loop is generate → conformance-test → done, which is exactly the loop a
coding agent closes well. APIs that publish OpenAPI are bind-time targets,
not build projects. The universal floor means day one is never blocked on
an adapter existing.

Rapid iteration. Simulation makes behavior checkable offline before
credentials exist. The cache makes iteration cheap: change a prompt and
re-run — enrichments skip, only judgment re-spends. Filter verdicts and
their reasons land in the ledger, so tuning a prompt is a SQL query over
what the model actually decided, not vibes. Freeze any run back into the
exact YAML that produced it.

Safety. Delivery is the one destructive edge and it is gated three
ways: the dry-run receipt is a per-record approval artifact a human reads
before arming; idempotency keys make re-runs structurally unable to
double-send; suppression windows enforce contact policy across pipelines.
Everything upstream is replayable because the ledger is append-only.
Blank merge fields never send. Groups freeze AI judgment into recorded,
inspectable decisions instead of per-run dice rolls.

Cost. Every step's spend lands in the receipt, attributed per record
and per model. The cache prints what it saved you, not just what you
spent. Fetch-once economics: N AI steps across M runs reuse one paid
enrichment while it's fresh. Raw vendor responses are retained (bounded,
TTL'd, evictable) so improving an extraction back-fills from payloads
you already paid for — at zero vendor spend.

Install

brew install gtme-run/tap/gtme     # macOS and Linux, arm64 and amd64

The tap installs the
prebuilt binary from the releases
page
, verified against
the checksums.txt published beside it; without Homebrew, do the same by
hand — untar, put gtme on your PATH, gtme init. With Go 1.24+, go install github.com/gtme-run/gtme/cmd/gtme@latest builds the tagged
release straight from the module. Building from a checkout is git clone

  • ./install.sh, which also installs the repo's example external
    adapters so the README quickstart works offline.
    Then add the Claude Code plugin with the two /plugin lines in
    Get started. Whichever way,
    START.md is the next page: four ways to start,
    each one pipeline file, each ending in a receipt.

The adapters

What ships today, and the vendor adapters the registry serves — see
ADAPTERS.md for each one's config and behavior, or
gtme help --agent for the machine-generated, always-current surface of
what the binary carries. Adapters marked (registry) install with
gtme adapters add <id>:

In csv/source · group-as-source · apollo/search (registry)
Enrich apollo/enrich (registry) · harvest/profile (registry) · harvest/recent-posts (registry) · http/enrich (any URL → markdown or JSON) · sql/transform
Judge ai/filter · sql/filter · ai/review
Write ai/compose · text/compose (a template, no model)
Ask human/filter · human/compose · human/review · agent/* (the same three, answered by an agent)
Out instantly/add-to-campaign (registry) · attio/assert (registry) · http/deliver (any URL) · csv/deliver · group/deliver (the next stage)

Adding your own doesn't require touching this repo: drop a binding.yaml
into ~/.gtme/adapters/<name>/ and the id resolves immediately.

Steps a person answers

A human/* step puts judgment in the pipeline without pretending a model
made it. At a terminal gtme run walks the records and asks; anywhere
else — cron, CI, a pipe — every record waits in the ledger, and gtme answer records the verdict later. Either way the answer lands as a fact
with the person's name in its provenance, and the run collects it exactly
as it collects a deferred batch.

gtme run review.yaml                      # ends "pending — 12 awaiting human/review"
gtme show --run last --pending            # read what is waiting
gtme answer last [email protected] --set grade=B --note "too generic"
gtme run review.yaml                      # collects the answers, continues

agent/* is the same three steps for an agent that answers with its own
judgment rather than a person's; it never prompts, and --as puts its
name in the ledger.

Five things worth knowing before you put one in a pipeline:

  • Under cron, a pipeline with a participant step waits. A pending run
    is resumed, not re-sourced, so nothing new is picked up until someone
    answers. The pattern that avoids it is two pipelines: the reviewing one
    a person runs, ending in a group:, and the scheduled one sourcing from
    that group. gtme plan prints a note when a deliver step follows a
    person.
  • Ctrl-C mid-walk is safe. The records you answered are settled, the
    rest stay pending, and the run ends pending rather than failed.
  • The latest answer before collection wins. Answers are ledger state,
    idempotent per record; answering again replaces the earlier one.
  • An unchanged value is not asked twice. A person's judgment is cached
    like a model's: rewrite the draft and it comes back, leave it alone and
    it does not. cache: 0d or respend: true ask again on purpose.
  • A review labels; it never gates. when: <review>.passed fails plan.
    Use a filter when the answer should stop a record.

A campaign is a folder

Everything that defines a campaign is text, so a campaign works the way
the rest of your engineering does: a directory under version control.

q3-outbound/
  qualify.yaml          # source → enrich → ai/filter ⇒ group (cheap, run often)
  send.yaml             # group → compose → deliver (deliberate, gated)
  contacts.csv          # input data, when the source is a file

Pipelines diff in code review. Prompt changes are commits. A colleague's
campaign is a git pull. And when a run is worth keeping,
gtme freeze --bundle snapshots it into a self-contained artifact:

bundle/
  manifest.json         # format version, source run id, sha256 per file
  pipeline.yaml         # the exact config that ran
  adapters/             # every referenced binding, at its frozen version,
    apollo-search/      #   with its fixtures — so the bundle simulates offline
  registry/             # the field vocabulary the contracts speak

gtme run <bundle> accepts the folder anywhere a pipeline path goes,
verifies every hash first, and resolves the bundle's own bindings ahead of
whatever the machine has installed. Contracts travel; your ledger,
credentials, and input data stay yours. The natural unit for a playbook, a
handoff, or a per-client repo.

The Claude Code plugin in plugin/ carries four skills — create a pipeline from a goal, run one up the ladder, add a
vendor, analyze the ledger — each a procedure that reads its facts from
gtme help --agent at run time. Five such playbooks ship in bundles/: qualify → group →
send, an email waterfall, the account shape, events via CSV + cron, and
posts to engagers via a traverse. Every one simulates offline from the
checkout (cd bundles/<pattern> && gtme run . --simulate) and CI proves
it; each README says what its receipt shows and which rung comes next.

Build from a checkout

git clone https://github.com/gtme-run/gtme && cd gtme
./install.sh        # builds gtme, installs it to ~/.local/bin, runs gtme init

install.sh is deliberately boring: it compiles from the checkout and
copies one static binary into place — no curl-pipe-to-shell, no network
fetch. It warns you if ~/.local/bin isn't on your PATH (add it to your
shell profile, or run PREFIX=/usr/local ./install.sh instead). Prefer
not to install? make build gives you ./bin/gtme and every command
below works with that path.

The zero-key demo — run a whole campaign, offline, right now:

gtme adapters add apollo/search apollo/enrich instantly/add-to-campaign   # keyless: verified, then pinned
gtme run examples/demo.yaml --simulate

The Apollo source serves its conformance fixtures, the AI steps answer
synthetically (and are marked synthetic in provenance), the reveal step
prints its estimated charge, and delivery is held with its variables
resolved into the receipt — Instantly's campaign check is skipped and
says so, because a simulated run reads no target. One sourced record has no email — Apollo's
locked-email placeholder is treated as absent, never as an identity key —
so it is keyed by name hash; both held records then read "Jane Doe",
because the reveal fixture answers every lookup with the same sanitized
person. Fixtures are canned responses, and the receipt says SIMULATED
so nobody mistakes them for data. Run it twice: the receipts are
identical, because a simulated run persists nothing.

The zero-key top-up — the second receipt, on a ledger that persists:

gtme run examples/hello.yaml        # three people scored at $0.01 each, one kept, out.csv written
gtme run examples/hello.yaml        # again: 3 cached, $0.0300 avoided, nothing delivered twice

demo/enrich is the binary's own synthetic enrichment: no vendor, no key,
deterministic scores labelled synthetic in the value itself, at a stated
pretend price — so the receipt's cached and avoided columns fill in
for real, and every dollar it prints is labelled demo/enrich wherever it
appears. The SQL filter and the CSV delivery are the real adapters. What
this proves is the mechanism, not the savings: the counter is real, the
$0.03 is not. The same column with a vendor's real price is the ladder
below, and a second run of apollo-to-instantly.yaml at campaign size
is where it turns into money.

Then with real keys, the same file climbs the ladder:

gtme secret set APOLLO_API_KEY        # prompts, no echo
gtme secret set ANTHROPIC_API_KEY
gtme secret set INSTANTLY_API_KEY     # the campaign whose id is in the file must exist
gtme plan examples/demo.yaml          # contracts + cost, still $0
gtme run  examples/demo.yaml --dry-run  # everything but delivery
gtme run  examples/demo.yaml          # armed
gtme run  examples/demo.yaml          # again: cache skips, zero re-delivery

Then interrogate what happened — no log spelunking:

gtme show [email protected] --provenance   # every fact, who wrote it, when
gtme runs last                             # the receipt, reconstructed
gtme query "SELECT field, value FROM current_fields ..."
gtme groups                                # decisions about sets, with tallies

Further exploration

  • SPEC.md — the canon. Every observable behavior, DECIDED
    sections, acceptance criteria. The binary is built from this document;
    code that diverges from it is a bug even when it works.
  • DECISIONS.md — the why: the ADR log, including the
    autopsy of why Singer died twice and how the field registry and binding
    tier answer both causes.
  • VALIDATION.md — the receipts: real campaigns, real
    API drift absorbed, real dollar amounts, findings logged honestly.
  • ADAPTERS.md — every shipped adapter, what it does,
    and the config that matters.
  • spec/bindings/ — vendor adapters as reviewable,
    diffable YAML, with the conformance fixtures that double as simulation.
  • PROCESS.md — how design conversations become spec, and
    why nothing is decided until it's in the repo.
  • ROADMAP.md — named, deliberately deferred: the expand
    role, payload re-extraction, an OpenAPI→binding codegen skill, and more.
  • CONTRIBUTING.md — the contribution surface is
    adapters, and most adapters are one reviewable YAML file; here's the
    shape and the checklist.
  • gtme help --agent — the whole surface, machine-readable, for your
    agent; gtme help --bindings — the binding contract (schema, discovery
    path, a reference binding) when it needs an adapter that is not here.

License

Apache-2.0

Yorumlar (0)

Sonuc bulunamadi