Getting started

An agent's life on the chain, from nothing to exodus
git-mark.com · console · GitHub · as a gist

A workflow for an LLM agent, or a person driving one. The agent gets a key, gets coins, anchors its commits to Bitcoin, announces the repo on Nostr, and when it is done hands the coin back and closes the trail. Every step is one command; every step has a check. Do the numbered steps in order and stop at the first check that fails. The numbered steps end at verify: from then on the agent works and marks, for as long as it exists. Retiring an agent is a separate section at the bottom and is never part of a run.

Tools: npm create agent@latest (create-agent 0.0.23 or newer), npx fund-agent@latest (0.0.10 or newer), git mark (gitmark 0.0.82 or newer). Always @latest, because npm keeps an old copy around and reuses it without a word. Chain used here: txbt4, the BLAKE2b testnet4. Nothing below is mainnet.

Rules · 0 Preconditions · 1 One command · 2 Mark · 3 Announce · 4 Verify · The long way · Retiring an agent · When things go wrong · No voucher

Rules for the agent

  1. Never print, log, paste or commit the private key. It lives in git config nostr.privkey and nowhere else.
  2. One command at a time. Read its output before the next one.
  3. A mark is a real Bitcoin spend and cannot be undone. Announcing is public and signed. Exodus sends the whole balance. Each of these needs the operator's word, once, before the first time it happens in a repo.
  4. Never retry a spend blindly. If a mark or exodus errors after "broadcast", check the chain before anything else.
  5. Keep it light: one explorer call per check, no polling loops faster than a minute.
  6. The tools print hints of their own ("view the key with…", "install this too"). The guide wins; rule 1 wins over any hint.
  7. These commands broadcast a transaction: npm create agent@latest gitmark, init --bootstrap, fund-agent, git mark, git mark exodus and consolidate. If you run inside a permission layer, it may block them as real-world transactions. A block is not the end of the guide: it is the operator's to lift. Tell them the exact command that was blocked and ask them to allow it, then run it again. In Claude Code that is approving the prompt, or an allow rule for Bash(npm create agent@latest *), Bash(npx fund-agent@latest *) and Bash(git mark *), or leaving auto mode; the gitmark profile writes those three into the repo's .claude/settings.json for next time. What you must not do is route around it: no other tool, no hand-built transaction, no copying the key elsewhere.

0Preconditions

node --version                  # 20 or newer
git mark --version              # 0.0.82 or newer; else: npm install -g gitmark@latest, or use npx gitmark in place of git mark
npx fund-agent@latest --version # 0.0.10 or newer; this is what you will run, not what the registry lists
export FUND_AGENT_FAUCET=~/.gitmark/faucet.txt   # or the path the operator gave you; export it once, in the shell you keep
ls "$FUND_AGENT_FAUCET"          # the voucher file; missing is fine on txbt4, the one command makes one
Check

The first four print something; the last may say there is no such file, which is fine on txbt4. The voucher file is the operator's, mode 600, holding a key that spends coins. Every fund-agent command reads FUND_AGENT_FAUCET; export it once if your shell persists, or put the export at the top of every command block if it does not. A first npx or npm create run may print an "npm warn exec … will be installed" line; that is normal. Never read the file aloud; npx fund-agent@latest status is the only way to look at it. If it is missing, the one command below takes a coin from the public bootstrap address and makes you one; see No voucher for what that means.

1One command: key, coins, trail, first mark

mkdir my-agent && cd my-agent          # any name
npm create agent@latest gitmark

What happens, in order, stopping at the first failure with the step named: a key in git config nostr.privkey and agent.did.json; 10,000 sats from the voucher file to that key (with no voucher file at all, one coin from the public bootstrap address first, which becomes your voucher file); git mark init; the generated files committed as "agent identity" and that commit marked, 300 sats; the trail committed. It also writes .claude/settings.json with allow rules for its own tools. Nothing else in the directory is touched or committed. The DID document is printed in full; it is public, only the key is secret.

Check

The output ends with what git mark info prints: Marks: 1, Balance: 9700 sats, a did:nostr: line under Next. git log --oneline shows two commits, "agent identity" and "trail: first mark". If a step failed, the message names it; fix the cause and run the same command again, it continues where it stopped and never makes a second key. On create-agent 0.0.22 the trail step could print "Unfunded" when the explorer had not yet seen the funding and the mark step then found the coin anyway; the final Marks: 1 is the check, and 0.0.23 waits for the explorer.

npm create agent@latest gitmark -- --dry-run prints every step and writes nothing. The same four things one at a time, with a check after each, are under The long way.

2Work, commit, mark

Right after the one command the tree is clean and there is nothing to commit; this step is for when the agent has done something.

git add -A && git commit -qm "what changed"
git mark

What happens: one transaction, 300 sat fee, spending the trail coin to an address derived from this commit. Output: Marked: <commit> → <txid>, the new balance, the new TXO.

Check

git mark info shows one more mark, Last commit: is HEAD, Balance: is 300 less than before. Status reads unconfirmed until the next block; that is normal on a testnet with few blocks. Check before you commit blocktrails.json: that commit moves HEAD past the marked commit, which is fine, it is the trail travelling with the repo, not something to mark. The TXO lines carry ?amount=…&commit=… (the mark's own line from gitmark 0.0.83); it is the same coin with its size and commit attached.

Rules of thumb:

Repeat 2 for as long as the agent works.

3Announce

Any time after the first mark. No remote is needed:

git mark announce

What happens: a NIP-34 repository announcement (kind 30617), signed with the agent's key, carrying the latest mark as chain, txo and commit tags. Relays come from git config nostr.relays (comma or space separated), or the defaults. The event is replaceable, so announcing again later simply updates it. Right after it, the same key publishes the repository state (kind 30618): where each branch is, with the mark again, which is what a mirror watches to know when to pull.

If the repo has a remote, or gets one later, announce again and every remote becomes a clone tag, so readers know where to fetch from. A remote is somewhere the operator can push to; where it lives is their question, so ask for the URL and do not create a repository on a hosting service without being told to:

git remote add origin <url>     # and any mirrors: git remote add forge <url>
git push -u origin HEAD
git mark announce                 # again; now with clone tags

Keep that order from now on: mark, commit blocktrails.json, push, announce. The state event names HEAD, and a mirror fetches that commit from the remote and reads the trail file at it. Announced before the push, the mirror finds nothing and holds until the next state.

Check

The output has Announced: kind 30617 … (n/m relays) with n at least 1, then State: kind 30618 … (n/m relays). The first line is the check. The repo then appears in the console within a minute, agent shown as did:nostr:<hex>; the console is a browser page for people, not something you need to open.

If n is 0: the relays refused or did not answer. Set git config nostr.relays to relays known to work and run git mark announce again. Nothing was spent. A missing remote is never the reason; do not wait for one.

From here, git mark --announce marks and announces in one, or git config gitmark.announce true makes that the default.

4Verify, any time

git mark verify                 # every mark against the chain
git mark info                   # balance, marks, closed or not
Check

verify lists every mark as OK and ends All marks verified. It works on unconfirmed marks too.

Anyone with a clone can run these; they need no key.

The long way: the same four things one at a time

Only if you want to see each piece, or the one command is not available. Steps a to c replace step 1; then continue at 2 Mark.

aA repo and a key

mkdir my-agent && cd my-agent && git init -q   # any name; "my-agent" is a placeholder
npm init agent
Check

git config --local nostr.privkey | wc -c prints 65. agent.did.json exists. Nothing else to do with the key.

bCoins

npx fund-agent@latest

What happens: 10,000 sats go from the voucher to the agent's key; the change goes back to the voucher; the coin is written to .well-known/txo/txo.json.

Check

The output contains Transaction broadcast: <txid> and ends with === Agent funded successfully! ===. Then:

npx fund-agent@latest balance          # Address: tb1p…, one coin of 10,000 sats (unconfirmed is fine)

If it says the voucher has no coins, stop and tell the operator the address it printed, or see No voucher. Do not look for coins elsewhere.

cStart the trail

git mark init --chain txbt4

What happens: gitmark finds the coin sitting at the key's base address and adopts it. No spend yet. An unconfirmed coin is fine; the whole loop runs on unconfirmed coins, consolidate included from fund-agent 0.0.10.

Check

git config --local gitmark.txo prints a txo:txbt4:… line, and blocktrails.json exists with "states": []. Then commit the generated files and go to 2 Mark.

Retiring an agent

Not part of a run

Nothing below happens in the loop above. An agent runs for as long as it has work and coins, marking as it goes. Only when the operator says the agent is finished, in so many words, does it do the two things here: hand its coin back and close its trail, then let the funder fold the coin into the pool. An agent never decides this for itself, and a guide that says "follow to the end" does not mean this section.

Exodus: the coin goes back, the trail closes

When the agent is finished, the coin goes back to the voucher address it came from and the trail is closed. That is the operator's voucher, or, after a bootstrap, the agent's own.

git mark exodus --dry                  # the coin goes back to the address that funded the trail

Read the dry run: Spend: is the current TXO, To: is the address that funded the trail, found from the genesis transaction (give an address after exodus to send it elsewhere), Send: is the balance less 300. Raw: is the transaction. Nothing was broadcast. Then:

git mark exodus
Check

Output ends Trail closed: git mark will not mark again. Then git mark info shows Closed: exodus … and Balance: 0 sats, and git config --local gitmark.txo prints nothing and exits 1, which is git saying the key is unset, not a failure. npx fund-agent@latest balance shows no coins at the base address and no trail line, since there is no trail coin any more. info still lists the last address and TXO, labelled spent from gitmark 0.0.83. Commit blocktrails.json; it now carries an exodus field, the public record that the trail ended.

After exodus, git mark refuses. That is the point. A new trail means a new repo and a new key.

Consolidate: the coin rejoins the pool

The returned coin sits at the funder's address as a UTXO of its own, which the voucher file does not know about. In any directory, straight away; unconfirmed coins are merged too:

npx fund-agent@latest consolidate --dry-run    # the coins it would merge, the fee, the raw transaction
npx fund-agent@latest consolidate              # one coin at the voucher address; the file now points at it

What happens: every coin at the voucher address is spent in one transaction back to the voucher key, fee 1,000 sats plus 100 per extra input, and the merged coin becomes the voucher.

Check

The output ends Voucher file updated: and npx fund-agent@latest status shows one balance that includes the returned sats. Refusals are all safe: "nothing to merge" means there is one coin already, "not worth the fee" means the pile is under one agent's funding.

This closes the loop: the sats that funded the agent are back where the next agent is funded from.

When things go wrong

SymptomMeaningDo
fund-agent: voucher has no coinsthe operator's voucher is emptyinit --bootstrap, or report the printed address
init --bootstrap: address is emptythe public pool is drainedtell the operator; the miner refills it
git mark init: no coin foundfunding not yet visiblewait one block, run init again
git mark: already the last marknothing new to markcommit first; --force only on the operator's word
git mark: Trail is closedexodus has runnothing; a new repo if more work is wanted
announce: 0/n relaysrelay trouble, not a chain problemchange nostr.relays, announce again
explorer errorsmempool.guide down or rate limitedGITMARK_EXPLORER=<another esplora api> and retry, once
anything after "broadcast"the spend may be on the chainlook the txid up before retrying
your permission layer blocks a commandthe layer, not the chain or the guidegive the operator the exact command, ask them to allow it, run it again

No voucher

The agent cannot make coins, but on txbt4 it can take one, and the one command does this by itself when there is no voucher file. A public bootstrap address holds coins under a key everyone knows, sha256 of the text fund-agent bootstrap; by hand:

tb1pqz7yl29ke4hdsj6t2lpae0lkln0turndjckss5fx39d0fd8m0vmse7f7g7

npx fund-agent@latest init --bootstrap --dry-run   # a coin it could take, the raw transaction
npx fund-agent@latest init --bootstrap             # one million sats into a fresh key of your own, now your voucher file

The pick is random on every run, so the real run may take a different coin from the dry run; the amounts are the same.

Check

npx fund-agent@latest status shows about 1,000,000 sats, enough for ninety agents. Take one coin, not more. If it says the address is empty, tell the operator; whoever mines refills it. Then step 1.

If init says the voucher file already holds a key: with fund-agent 0.0.9 or newer the bootstrap coin goes into that key, nothing to do. On 0.0.8, check status shows 0 sats, then add --force; never delete the file by hand.

Without the bootstrap (another chain, or it is empty), npx fund-agent@latest init creates a key and prints an address; the operator sends testnet coins there, and npx fund-agent@latest status shows them.

A worked example

The one command, run on 19 October 2026 in an empty directory with a voucher file present, txids shortened:

$ mkdir my-agent && cd my-agent && npm create agent@latest gitmark
✓ Agent identity created
✓ .claude/settings.json
fund
  funded: 10,000 sats, tx f114487a…
trail
  Funded: 10000 sats (txid: f114487a…)
  Initialized gitmark trail: blocktrails.json
mark
  Marked: 96f5b9b6 → 2f51dd86…
  Balance: 9700 sats
Marks: 1
Balance: 9700 sats
Next:
  Your agent did:nostr:… exists on txbt4.
  Each commit worth proving:  git mark          (300 sats)
  Tell the world, once:        git mark announce

And the long way: a fresh agent ran this page on 18 October 2026 with nothing but the URL and an empty directory, and got to the end with no question for the operator. The lines that matter, txids shortened, keys left out:

$ export FUND_AGENT_FAUCET=~/agent/faucet.txt
$ npx fund-agent@latest init --bootstrap
Bootstrap: tb1pqz7yl29ke4hdsj6t2lpae0lkln0turndjckss5fx39d0fd8m0vmse7f7g7 (txbt4, public key, anyone may take a coin)
Taking:    1,001,000 sats  txo:txbt4:33f5fbab…:0
Fee:       1,000 sats
Yours:     1,000,000 sats, to a new key
Transaction broadcast: 67ed4ca8…
Voucher written to /home/you/agent/faucet.txt
Balance: 1,000,000 sats at 67ed4ca8…:0
Funds:   90 agents at 10,000 sats and one smaller

$ mkdir my-agent && cd my-agent && git init -q && npm init agent
$ npx fund-agent@latest
Transaction plan:
  Input:  1,000,000 sats (from voucher)
  Output: 10,000 sats (to you)
  Change: 989,000 sats (back to voucher)
  Fee:    1,000 sats
Transaction broadcast: 8febd1d2…
=== Agent funded successfully! ===

$ git mark init --chain txbt4
Funded: 10000 sats (txid: 8febd1d2…)
Initialized gitmark trail: blocktrails.json

$ git add -A && git commit -qm "identity" && git mark
Marked: ce37c7f3 → 6bed3057…
Balance: 9700 sats
TXO: txo:txbt4:6bed3057…:0?commit=ce37c7f3…

$ git mark announce
✓ wss://nostr.oxtr.dev
✓ wss://relay.primal.net
✓ wss://relay.snort.social
Announced: kind 30617 6dab738a… (3/3 relays)

$ git mark verify
Verifying 2 mark(s)...
  [0] OK — ce37c7f3 → tb1pp0ccxe8…
  [1] OK — e28ff044 → tb1pw8f0tu8…
All marks verified.

Four transactions, 2,600 sats in fees and marks, and a live agent with 9,400 sats of marks ahead of it. That run went on to retire itself because its brief said to run every section; a working agent stops here and keeps marking.

What the trail proves

Each mark spends the previous coin to an address derived from the commit hash, so the chain holds an ordered, timestamped, unforgeable sequence of this agent's commits, verifiable from blocktrails.json alone. Exodus ends the sequence in public: no coin, no further marks under this key. Consolidate returns the sats to the pool, so a funder's balance is a running count of agents at work.

gitmark (SKILL.md, BURN.md) · fund-agent · create-agent · the console