Skip to content

Open source · for Metronome

Let your agent change billing. Previewed, confirmed, proven.

metro is a terminal CLI and agent toolkit that lets you (or Claude Code, Codex, Cursor) add a credit, move a customer to a new plan, clone a package, or add seats in Metronome, with sandbox first, typed confirmation, and readback proof.

Give this to your agent
  • Claude Code
  • Codex
  • Cursor
  • GitHub Copilot
  • Windsurf
set up metro - https://metrocli.com/llms.txt

Works with Claude Code, Codex, Cursor, and any agent with a terminal. Your keys stay in a file on your machine, never in chat.

Prefer to do it yourself? Install in two commands
ledger-adjustment✓ PROOF 2/2readbackexpectedactualbalance.trial_grant1,7001,700ledger entry+500+500confirm-hashsha256:9c41e07a…b7d2hash matchestyped confirmsandboxidempotency key set
  1. preview
  2. confirm
  3. apply
  4. proven
Add a credit✓ readback matches (2/2 fields)

Watch an agent do it

One request, every stage. Read, sandbox, preview, confirm, apply, proof.

You ask in plain words. The agent runs real metro commands, stops at the preview, waits for your apply, then shows the readback.

agent session · sandbox
  1. read
  2. sandbox
  3. preview
  4. confirm
  5. apply
  6. proof

youGive Acme 500 more trial credits in sandbox. Show me before you apply.

agentLooking up Acme first. That's a read, nothing changes.

agentPreview ready: +500 on the trial grant. Reply apply to confirm this exact hash.

youapply

agentDone. metro read it back: 1,700 expected, 1,700 actual.

metro ops who "Acme" --sandbox
[sandbox]  customer  Acme Inc.  cus_••••41c
           contract  Pro annual · active  con_••••9e2
           credits   1,200 remaining on the trial grant
metro ledger-adjustment preflight --name="Acme" \
    --amount=500 --reason="trial extension" --sandbox --out=acme.json
· preview   1 field would change   dry run, nothing sent
removed: balance.trial_grant   1,200
added: balance.trial_grant   1,700
  payload hash  sha256:9c41e07a…b7d2
metro ledger-adjustment apply --file acme.json --sandbox \
    --confirm-hash sha256:9c41e07a…b7d2 --apply
· confirm   hash matches the preview you approved
› apply     POST /v1/contracts/addManualBalanceLedgerEntry  200
✓ proof     readback matches (2/2 fields)
  field                 expected   actual
  balance.trial_grant   1,700      1,700  ✓
  ledger entry          +500       +500   ✓

01Safety ladder

Six steps between your agent and production. Every one of them on by default.

  1. 01read

    Read-only.

    metro starts unable to change anything. Writes are a mode you turn on: metro mode write.

    metro mode
    Operator mode: read-only (source: default)
    Live reads: allowed; live writes: blocked
    
  2. 02sandbox

    Sandbox first.

    Every command takes --sandbox. Production needs its own key and its own flag.

    --sandbox  METRONOME_SANDBOX_KEY
    --prod     METRONOME_PROD_KEY  must differ
    
  3. 03preview

    Preview.

    See the exact API payload and a diff before anything is sent.

    · preview  1 field would change
    removed: contract.ending_before  (none)
    added: contract.ending_before  2026-11-04T15:00:00Z
    Payload hash: sha256:3e9a07c4…c71f
    
  4. 04confirm

    Typed confirm.

    Applying needs the hash of the exact preview you saw. Change one field and the hash no longer matches.

    --confirm-hash sha256:3e9a07c4…c71f
    · confirm  hash matches the preview you saw
    
  5. 05apply

    Apply.

    One call, with an idempotency key, so a retry can't double-charge.

    --confirm-hash sha256:3e9a07c4…c71f --apply
    › apply  POST /v1/contracts/updateEndDate  200
    
  6. 06proof

    Readback.

    metro reads the object back and shows expected vs actual. A green preview is not proof; the readback is.

    Readback: expected versus actual
    fieldexpectedactualmatch
    customer_idcus_••••41ccus_••••41cmatches
    contract.idcon_••••9e2con_••••9e2matches
    contract.ending_before2026-11-04T15:00:00Z2026-11-04T15:00:00Zmatches

    ✓ proof readback matches (3/3 fields)

02Object graph

Metronome's model, in one picture. metro knows how the pieces connect, so your agent doesn't guess.

Fig. 02 Metronome object model

01 / 08 · object

Customer

The account you bill, identified by its ingest aliases.

Watch outSetting ingest aliases replaces the whole list rather than adding to it.

  • CustomertoContract
metro commandpreview
metro customer setup preview --file customer.json --sandbox

Source: gotcha-reference.md

02 / 08 · object

Contract

Binds a customer to the prices and terms they are billed on.

Watch outMoving plans ends it with updateEndDate, then creates a successor with a RENEWAL transition.

  • CustomertoContract
  • PackagetoContract
  • ContracttoRate card
  • ContracttoCredits & commits
  • ContracttoInvoice
metro commandpreview
metro contract move-plan preview --file move.json --sandbox

Source: gotcha-reference.md

03 / 08 · object

Package

A reusable contract template, with aliases and a uniqueness_key.

Watch outIts duration sets ending_before on every contract provisioned from it.

  • PackagetoContract
  • PackagetoRate card
metro commandpreview
metro package preview --shape pro-annual --file package.json --sandbox

Source: GOTCHAS.md

04 / 08 · object

Rate card

Holds the prices for your products.

Watch outaddRates takes a starting_at that metro enforces on a UTC hour boundary.

  • PackagetoRate card
  • ContracttoRate card
  • Rate cardtoProduct
metro commandpreview
metro rate-card dimensional preview --file rates.json --sandbox

Source: GOTCHAS.md

05 / 08 · object

Product

Something you sell: a USAGE, FIXED or subscription product.

Watch outUse one USAGE product per tier card with a pricing_group_key, not one per action.

  • Rate cardtoProduct
  • ProducttoBillable metric
metro commandread · plan
metro product inspect --product-id <id> --sandbox --plan

Source: GOTCHAS.md

06 / 08 · object

Billable metric

Turns raw usage events into a number, with COUNT or SUM.

Watch outDimensional pricing needs one compound group key.

  • ProducttoBillable metric
metro commandpreview
metro usage ingest preview --file usage.json --sandbox

Source: SHAPE_CATALOG.md

07 / 08 · object

Credits & commits

Prepaid or granted balances that live on a contract.

Watch outThe access schedule sets the credit type; the invoice schedule must be fiat.

  • ContracttoCredits & commits
metro commandpreview
metro credit preview --shape complimentary-credit-grant --file grant.json --sandbox

Source: gotcha-reference.md

08 / 08 · object

Invoice

The bill a contract produces from usage and scheduled charges.

Watch outPast-dated charges can finalize immediately, and a Metronome void does not refund Stripe.

  • ContracttoInvoice
metro commandread · plan
metro invoice inspect --invoice-id <id> --sandbox --plan

Source: gotcha-reference.md

03Try it

Every command knows its risk. Read, sandbox write, or write with typed confirm.

Try it out
metro init --check · metro status
stdout · exit 1
metro init --check

  key file     ~/.metro/.env  (not created yet)
  ✗ sandbox     missing
  · production  not set (optional). Add it any time: metro init --prod

  Next: metro init

Real output on a fresh machine with no key file. Exit code 1 until a sandbox key works.

stdout · exit 0
metro status - local command center dashboard.
Operator mode: read-only (reads on, writes off)
Workspace intents: 14; catalog: user-bound-catalog
Catalog allowlist: 20 live reads; 8 sandbox writes
Next: Run metro setup init --write, export METRONOME_SANDBOX_KEY, then metro status --check-env --json.

Real output with no keys set. Read-only: metro status never calls the API.

metro commands with their safety class
CommandWhat it doesSafety
metro init --checkChecks your key file and prints the next step.read
metro statusMode, workspace, catalog and endpoint allowlists on one screen.read
metro ops who <name>One customer: active contract, credits and balances.read
metro customer balances --name=Credit and commit balances for one customer.read
metro package listYour packages, active or archived.read
metro tenant snapshot showYour account pattern and catalog summary.read
metro validate --shape <shape>Checks an input file against the shape rules.read
metro credit preview --shape <shape>Builds a credit grant payload and its hash. Sends nothing.read
metro api apply <endpoint-id> --sandboxGuarded write to one of 8 allowlisted endpoints. Sandbox only.sandbox
metro contract move-plan applyMoves a customer to another package.write+confirm
metro contract extend-trial applyExtends a trial end date.write+confirm
metro contract expire applyEnds a contract now or at a set time.write+confirm
metro ledger-adjustment applyAdjusts a credit or commit balance.write+confirm
metro billing-provider cutover applyReplaces a Stripe billing-provider config.write+confirm
metro customer createnewCreates a customer with ingest aliases.write+confirm
metro ratecard createnewCreates a rate card.write+confirm
metro package createnewCreates a package, the template for contracts.write+confirm
metro contract createnewCreates a contract from a package, or direct.write+confirm
metro subscription addnewAdds a subscription to a contract.write+confirm

Every write+confirm command runs preflight first and applies only with --confirm-hash. Most take --json. The full list is metro --help.

04Usage to proof

Usage in. Proof out.

Metronome turns usage into invoices. metro makes every change to that pipeline provable.

  1. +500 credits✓ readback 2/2
  2. plan → annual✓ readback 3/3
  3. seats 12 → 15✓ readback 1/1
6
safety steps, on by default
1
idempotency key per apply
0
writes without a typed confirm

05For agents

Built to be read by agents. And still a pleasure for humans.

  • Metronome
  • Claude Code
  • Codex
  • Cursor
  1. Metronome
  2. Claude Code
  3. Codex
  4. Cursor
  5. metro

Your billing system, driven by the agent you already use.

Logos are the owners' trademarks.

  • AGENTS.md

    ~/.metro/AGENTS.md

    Architecture, rules and the exact commands, in one file your agent reads first.

    # metro: operating manual for agents
    
    You are an agent using `metro`, an open-source CLI for Metronome billing. This file is your manual. `metro init` copies it to `~/.metro/AGENTS.md`. Read all of it before you run a command that talks to Metronome.
    
    ## 1. What metro is
    ## 2. Metronome in two minutes
    ## 3. Set up (agent steps)
    ## 4. The safety contract
    ## 5. Learn the tenant before you act
    ## 6. Provisioning workflow
    ## 7. Which docs and skills to load
    ## 8. Report a doorway
    

    excerpt · title and section headings

    Read AGENTS.md on GitHub
  • llms.txt

    metrocli.com/llms.txt

    Every docs page as plain markdown, indexed.

    # metro
    
    > metro is an open-source CLI for Metronome billing, for any Metronome tenant. It is read-only by default. …
    …
    ## Safety rules
    
    - Read-only by default. Writes need `metro mode write`, set by the human.
    - Sandbox first. Always pass `--sandbox` or `--prod`; metro never picks production on its own.
    - Ladder: preview (prints `payloadHash`) > show the human > apply with `--confirm-hash` > read back > report expected vs actual.
    - Production only with the human's explicit typed yes in chat for that specific change.
    - Never print or echo keys. Never cat ~/.metro/.env.
    

    excerpt · the safety rules

    Open llms.txt
  • SKILL.md × 9

    skills/

    Metronome API knowledge for packages, contracts, invoicing, seats and more, ready to load as skills.

    skills/
    ├─ metro/SKILL.md
    ├─ metronome-customers-hierarchies/SKILL.md
    ├─ metronome-danger-zone/SKILL.md
    ├─ metronome-ingestion-events/SKILL.md
    ├─ metronome-invoicing/SKILL.md
    ├─ metronome-packages-contracts/SKILL.md
    ├─ metronome-pricing-catalog/SKILL.md
    ├─ metronome-stripe-delivery/SKILL.md
    └─ metronome-subscriptions-seats/SKILL.md
    

    the skill names, from each SKILL.md

    Read the metro skill on GitHub

What your agent will do

  1. Install metro.
  2. Create ~/.metro/.env and ask you to paste your sandbox key into it.youPaste your sandbox key into ~/.metro/.env in your editor. Your keys stay in a file on your machine, never in chat.
  3. Check the key with a read-only call.
  4. Learn your catalog.
  5. Propose a change as a preview, wait for your yes, apply, and show the readback.
agent session · first run

youset up metro - https://metrocli.com/llms.txt

agentReading llms.txt. First, install metro.

git clone --depth 1 https://github.com/metrocli/metro.git ~/.metro/src \
    && bash ~/.metro/src/scripts/install-global.sh
OK: metro is installed from ~/.metro/src.
metro init --agent
metro init (agent mode: no prompts)
✓ Created ~/.metro/.env (mode 600) with empty placeholders.
ASK THE HUMAN TO DO THIS (do not ask them to paste keys into chat):
  1. Open https://app.metronome.com/sandbox/developer/api-tokens and create a token.
  2. Open ~/.metro/.env in an editor and paste it after METRONOME_SANDBOX_KEY=
  3. Save the file and tell you "done".
Then run: metro init --check
metro is in read-only mode. Operating manual: ~/.metro/AGENTS.md

agentI created ~/.metro/.env. Create a sandbox token, open the file in your editor, paste it after METRONOME_SANDBOX_KEY=, save, and tell me done. Please don't paste the key here.

youCreates a sandbox token, pastes it into ~/.metro/.env in an editor, saves. The key never enters the chat.

youdone

metro init --check
  key file     ~/.metro/.env  (mode 600)
  ✓ sandbox     working · •• customers · • rate cards  from ~/.metro/.env
  · production  not set (optional). Add it any time: metro init --prod
  Next: metro status

agentThe sandbox key works. That was a read-only call. Next I learn your catalog, so I use your real IDs.

metro catalog bind --sandbox --write
# discovers products, rate cards, credit types into ~/.metro/profiles.json

agentOne change to start: 500 more trial credits for Acme, on sandbox. Preview first.

metro ledger-adjustment preflight --name="Acme" --amount=500 \
    --reason="trial extension" --sandbox --out=acme.json
· preview   1 field would change   dry run, nothing sent
removed: balance.trial_grant   1,200
added: balance.trial_grant   1,700
  payload hash  sha256:9c41e07a…b7d2

agentReply apply to confirm this exact hash.

youapply

metro ledger-adjustment apply --file acme.json --sandbox \
    --confirm-hash sha256:9c41e07a…b7d2 --apply
✓ proof     readback matches (2/2 fields)

agentDone. metro read it back: 1,700 expected, 1,700 actual.

06Install

Install. Two commands, then metro init.

Agent

Give this to your agent
set up metro - https://metrocli.com/llms.txt

Paste it into Claude Code, Codex, Cursor, or any agent with a terminal. It reads llms.txt and runs the steps.

git

terminal · git
git clone --depth 1 https://github.com/metrocli/metro.git ~/.metro/src \
  && bash ~/.metro/src/scripts/install-global.sh \
  && metro init

Needs Node 18 or newer. Installs into ~/.metro/src, then runs metro init.

npm

terminal · npmcoming with the first npm release
npm i -g @metrocli/metro && metro init

@metrocli/metro is not on npm yet. Until it is, use .

metro init · interactive
metro init

  metro · Metronome in your terminal

  Step 1 of 4  Create your key file
  ✓ Created ~/.metro/.env  (private: only your user can read it)

  Step 2 of 4  Add your sandbox key  (start here, it can't touch real billing)
    1. Open https://app.metronome.com/sandbox/developer/api-tokens
    2. Click "Create token", name it "metro", copy it.
    3. Paste it here (input is hidden), or press Enter to paste it into the file yourself:

  › ••••••••••••••••••••
  ✓ Sandbox key saved to ~/.metro/.env as METRONOME_SANDBOX_KEY
  … Checking it with a read-only call
  ✓ Connected to your Metronome sandbox · •• customers · • rate cards

  Step 3 of 4  Production key  (optional, you can add it later)
    Only add this when you're ready for metro to read real billing.
    Writes to production still need write mode plus a typed confirmation for every change.
    Create one at https://app.metronome.com/developer/api-tokens
  Add a production key now? (y/N) › n
  · Skipped. Add it any time: metro init --prod

  Step 4 of 4  Safety mode
  ✓ metro is in read-only mode. It can look, preview and validate, but not change anything.
    When you want changes applied: metro mode write

  You're set. Try:
    metro status                        what metro can see
    metro catalog bind --sandbox        learn your products and rate cards
    metro ops who "Acme" --sandbox      find a customer

  Using an agent? Tell it: "read ~/.metro/AGENTS.md and run metro status"

Key input is hidden. Tenant counts redacted.

metro init --agent · no prompts
metro init --agent
metro init (agent mode: no prompts)

✓ Created ~/.metro/.env (mode 600) with empty placeholders.

ASK THE HUMAN TO DO THIS (do not ask them to paste keys into chat):
  1. Open https://app.metronome.com/sandbox/developer/api-tokens and create a token.
  2. Open ~/.metro/.env in an editor and paste it after METRONOME_SANDBOX_KEY=
  3. Save the file and tell you "done".

Then run: metro init --check

metro is in read-only mode. Operating manual: ~/.metro/AGENTS.md
metro init --check
metro init --check

  key file     ~/.metro/.env  (mode 600)
  ✗ sandbox     missing
  · production  not set (optional). Add it any time: metro init --prod

  Next: Paste your sandbox key into ~/.metro/.env after METRONOME_SANDBOX_KEY=, then run: metro init --check
metro init --check
metro init --check

  key file     ~/.metro/.env  (mode 600)
  ✓ sandbox     working · •• customers · • rate cards  from ~/.metro/.env
  · production  not set (optional). Add it any time: metro init --prod

  Next: metro status

Real output from an empty HOME. The second check runs after the human says done; counts redacted.