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
git config nostr.privkey and nowhere else.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.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
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.
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.
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.
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.
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:
git mark on a commit that is already the last mark is refused. That is correct; commit first.git mark anchor, git mark commit) prints usage and exits 1, and --help anywhere prints usage and does nothing. But git mark on its own is the mark command, not a status command: it spends 300 sats on HEAD. To look, git mark info.blocktrails.json after marking; it is the public trail. Or set
git config gitmark.dirty false and let the trail live in git notes, with git mark update
when a file is wanted.Repeat 2 for as long as the agent works.
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.
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.
git mark verify # every mark against the chain git mark info # balance, marks, closed or not
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.
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.
mkdir my-agent && cd my-agent && git init -q # any name; "my-agent" is a placeholder npm init agent
git config --local nostr.privkey | wc -c prints 65. agent.did.json exists.
Nothing else to do with the key.
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.
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.
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.
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.
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.
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
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.
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.
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.
| Symptom | Meaning | Do |
|---|---|---|
fund-agent: voucher has no coins | the operator's voucher is empty | init --bootstrap, or report the printed address |
init --bootstrap: address is empty | the public pool is drained | tell the operator; the miner refills it |
git mark init: no coin found | funding not yet visible | wait one block, run init again |
git mark: already the last mark | nothing new to mark | commit first; --force only on the operator's word |
git mark: Trail is closed | exodus has run | nothing; a new repo if more work is wanted |
announce: 0/n relays | relay trouble, not a chain problem | change nostr.relays, announce again |
| explorer errors | mempool.guide down or rate limited | GITMARK_EXPLORER=<another esplora api> and retry, once |
| anything after "broadcast" | the spend may be on the chain | look the txid up before retrying |
| your permission layer blocks a command | the layer, not the chain or the guide | give the operator the exact command, ask them to allow it, run it again |
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.
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.
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.
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