@toon-protocol/rig 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +370 -213
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,252 +1,409 @@
1
1
  # @toon-protocol/rig
2
2
 
3
- Git-to-TOON write path core — build git objects and NIP-34 events for the Rig control plane. Ships the **`rig`** CLI: a 1:1 git experience with a TOON remote. rig owns a handful of TOON verbs (table below); **every other command is passed through to system `git` verbatim** — `rig status` runs `git status`, `rig add -p`, `rig commit`, `rig rebase -i`, all behave exactly like git (same output, same prompts, same exit code).
3
+ **Git, with a TOON remote.** `rig` is a drop-in `git` wrapper that publishes your
4
+ repository to the TOON network — a decentralized control plane where repo state
5
+ lives in NIP-34 Nostr events and the objects live on Arweave.
4
6
 
5
- | command | owner | what it does |
6
- | --- | --- | --- |
7
- | `rig identity create` | rig (free) | mint a fresh BIP-39 identity into the encrypted keystore the phrase is shown ONCE. Removes the cold-start wall |
8
- | `rig identity show` | rig (free) | the active identity's source + derived pubkey (never the phrase) |
9
- | `rig identity import` | rig (free) | write an existing phrase (read from stdin, never argv) to the keystore |
10
- | `rig init` | rig (free) | one-shot repo setup: git repo (offers to `git init`, or `--git-init`) + identity (offers to generate one) + `toon.*` git config + repo-local git commit-author from your nostr identity (so `rig commit` works out of the box) |
11
- | `rig remote add/remove/list` | rig (free) | relays as REAL git remotes (`origin` = default publish target) |
12
- | `rig clone <relay-url> <owner>/<repo-id> [dir]` | rig (free) | bootstrap a repo from TOON: relay state + SHA-verified Arweave objects → a real, push-capable git repository. Shadows `git clone` |
13
- | `rig fetch [remote]` | rig (free) | download the missing object delta + update `refs/remotes/<remote>/*` (no merge — `rig merge origin/main`). Shadows `git fetch` |
14
- | `rig push [remote] [refspecs...]` | rig (paid) | the TOON push: Arweave upload + NIP-34 refs publish. Shadows `git push` — plain-git pushes stay available by running `git push` directly |
15
- | `rig issue list` / `rig issue show <id>` | rig (free) | the repo's issues + comments from the terminal (state derived from kind:1630-1633, latest wins) |
16
- | `rig pr list` / `rig pr show <id>` | rig (free) | the repo's patches/PRs; `show` prints the full patch text (pipe it to `git am`) |
17
- | `rig issue create` | rig (paid) | file an issue (kind:1621) |
18
- | `rig comment <root-event-id>` | rig (paid) | comment (kind:1622) on an issue/patch |
19
- | `rig pr create` | rig (paid) | publish a patch (kind:1617) from real `git format-patch` |
20
- | `rig pr status <event-id> <state>` | rig (paid) | set issue/patch status (kind:1630–1633). **Was `rig status` before v2** |
21
- | `rig help` / `rig --version` | rig | usage / version |
22
- | everything else | **git** | executed as `git <args...>` with rig's stdio and git's exit code |
23
-
24
- ## `rig` quickstart
7
+ - **Reads are free** clone, fetch, and browse issues/PRs need no identity, no
8
+ wallet, nothing configured.
9
+ - **Writes are paid**pushing objects and publishing events spends from a
10
+ payment channel funded by your wallet. Writes are permanent and non-refundable.
11
+ - **Standalone by default** `rig` embeds its own payment client built from your
12
+ seed phrase. No daemon is required (though a running `toon-clientd` makes paid
13
+ commands faster see [Daemon as accelerator](#daemon-as-accelerator)).
14
+
15
+ `rig` owns a handful of TOON verbs (`init`, `remote`, `clone`, `fetch`, `push`,
16
+ `issue`, `pr`, `comment`, `identity`, `fund`, `balance`, `channel`). **Every other
17
+ command passes through to system `git` verbatim** `rig status`, `rig add -p`,
18
+ `rig commit`, `rig rebase -i` all behave exactly like git.
19
+
20
+ ---
21
+
22
+ ## Install
25
23
 
26
24
  ```sh
27
25
  npm install -g @toon-protocol/rig
26
+ rig --version
27
+ ```
28
+
29
+ Requires Node.js and a system `git` on your `PATH` (rig shells out to it for all
30
+ passthrough commands and object plumbing).
31
+
32
+ ---
33
+
34
+ ## From your code to a published repo
35
+
36
+ This is the full happy path: an idea on your disk → a repository anyone can clone
37
+ from TOON. It uses the shared **devnet** (free faucet money) so you can complete
38
+ it end to end without spending anything real.
39
+
40
+ ### 1. Start with your code
41
+
42
+ Already have a git repo? `cd` into it. Starting fresh? An empty directory is fine —
43
+ `rig init` will offer to `git init` for you in the next step.
44
+
45
+ ```sh
46
+ mkdir hello-toon && cd hello-toon
47
+ echo "# hello-toon" > README.md
48
+ ```
49
+
50
+ ### 2. Create an identity
28
51
 
29
- # 0. start anywhere an empty directory is fine; `rig init` (step 2) will
30
- # offer to `git init` it for you.
31
- mkdir my-repo && cd my-repo
52
+ Your identity is a BIP-39 seed phrase; its derived Nostr pubkey is who *owns* the
53
+ repo, and its wallet is what *pays* for writes. Mint one on the spot — the phrase is
54
+ shown **once**, so write it down. It's stored in an encrypted keystore under
55
+ `~/.toon-client`.
32
56
 
33
- # 1. identity — mint one on the spot (no BIP-39 tooling needed). The seed
34
- # phrase is shown ONCE (write it down) and stored in an encrypted keystore
35
- # under ~/.toon-client.
57
+ ```sh
36
58
  rig identity create
37
- rig identity show # active source + derived pubkey (never the phrase)
38
- # Already have a phrase? Bring it instead of generating:
39
- export RIG_MNEMONIC="abandon abandon … about" # env, or…
40
- echo 'RIG_MNEMONIC="abandon abandon … about"' >> .env # project .env (gitignore it!)
41
- rig identity import # …or import it into the keystore (reads stdin)
42
-
43
- # 2. one-shot repo setup (free): writes toon.repoid + toon.owner to the
44
- # repo's local git config and reports which identity source is active.
45
- # Not a git repo yet? `rig init` offers to `git init` here (or pass
46
- # --git-init). No identity yet? It offers to generate one (or pass
47
- # --generate-identity). `--git-init --generate-identity` is a fully
48
- # non-interactive fresh setup: empty dir → rig-ready in one command.
49
- # It ALSO sets the repo-local git commit-author from your nostr identity
50
- # (never --global) so `rig commit`/`git commit` work out of the box and
51
- # every commit is attributed to the signer: user.email = <npub>@nostr,
52
- # user.name = your kind:0 profile display name when published (read
53
- # best-effort from a relay) else the npub. Re-run to refresh the name.
54
- rig init # default repo id = directory name
55
- rig init --repo-id my-repo # or pick one
56
-
57
- # 3. add your relay as an origin (free) — a REAL git remote, so
58
- # `git remote -v` shows it and git tooling round-trips it
59
- rig remote add origin wss://relay.example
60
- rig remote list # names + URLs; --json for machines
61
- rig remote remove origin
62
-
63
- # 4. work exactly like git — unowned commands pass through to system git.
64
- # `rig commit`/`git commit` already work: `rig init` set this repo's
65
- # author to your nostr identity (no `git config user.*` step needed).
66
- rig status # IS `git status`
67
- rig add -p && rig commit -m "fix"
68
- rig log --oneline # pagers, colors, prompts all behave like git
69
- rig rebase -i HEAD~3 # interactive works (stdio is inherited)
70
-
71
- # 5. push (paid) — defaults to the "origin" remote, exactly like git
72
- rig push # plan + price the current branch, confirm, push
73
- rig push main v1.0.0 --yes # specific refs, skip the confirm prompt
74
- rig push staging main # push via another configured remote
75
- rig push --all --tags --json # machine-readable plan/receipts (agents)
76
-
77
- # issues, comments, patches, and statuses use the same rig init config:
78
- rig issue create --title "Fix the flux" --body "It broke." # kind:1621
79
- echo "longer body" | rig issue create --title t --yes # body via stdin
80
- rig comment <root-event-id> --body "Nice catch." # kind:1622
81
- rig pr create --title "Add feature" --range main..feature # kind:1617 with
82
- # REAL format-patch text
83
- rig pr status <event-id> applied # kind:1631
84
- # (bare `rig status` is git's)
59
+ rig identity show # your active pubkey + npub (never the phrase)
85
60
  ```
86
61
 
87
- ### The second contributor (reads are FREE)
62
+ Already have a phrase? Bring it instead: `export RIG_MNEMONIC="abandon abandon … about"`
63
+ (or `rig identity import`, which reads the phrase from stdin). See
64
+ [Identity](#identity) for the full resolution order.
65
+
66
+ ### 3. Set up the repo
88
67
 
89
- Someone published a repo on TOON? You can pick it up with **nothing
90
- configured** no identity, no wallet, no channel. Reads are free:
68
+ One free command wires everything together: it writes `toon.repoid` / `toon.owner`
69
+ into the repo's **local** git config, and sets the repo-local git commit author to
70
+ your Nostr identity so `rig commit` works out of the box.
91
71
 
92
72
  ```sh
93
- npm install -g @toon-protocol/rig
73
+ rig init # repo id defaults to the directory name
74
+ # rig init --repo-id hello-toon # …or name it explicitly
75
+ # rig init --git-init --generate-identity # fully non-interactive fresh setup
76
+ ```
77
+
78
+ Not a git repo yet? `rig init` offers to `git init` (or pass `--git-init`). No
79
+ identity yet? It offers to generate one (or pass `--generate-identity`).
80
+
81
+ ### 4. Point at a relay
82
+
83
+ Relays are configured as **real git remotes**. Add the shared devnet relay as
84
+ `origin` — this is your default publish target, and it also tells `rig fund` (next
85
+ step) which faucet to use.
86
+
87
+ ```sh
88
+ rig remote add origin wss://relay-ws.devnet.toonprotocol.dev
89
+ rig remote list
90
+ ```
91
+
92
+ ### 5. Fund your wallet
93
+
94
+ Pushing is paid, so your wallet needs a balance. On devnet, `rig fund` drips test
95
+ funds (native coin **and** USDC) to every supported chain — it's free and needs no
96
+ faucet URL because it infers devnet from your `origin` remote.
97
+
98
+ ```sh
99
+ rig fund # devnet faucet drip (Mina can take ~75s)
100
+ rig balance # confirm the funds landed
101
+ ```
102
+
103
+ > On any non-devnet network there is no faucet: `rig fund` prints your wallet
104
+ > address(es) so you can fund them externally, then `rig push` draws from there.
105
+
106
+ ### 6. Commit your work
107
+
108
+ This is just git — unowned commands pass straight through, and step 3 already set
109
+ your commit author.
94
110
 
95
- # 1. clone — relay state + SHA-verified Arweave objects → a real git repo
96
- # (owner as npub1… or 64-char hex; dir defaults to the repo id)
97
- rig clone wss://relay.example npub1…/their-repo
98
- cd their-repo # toon.* config + origin remote already set
99
-
100
- # 2. read the tracker from the terminal
101
- rig issue list # issues + derived state (latest status wins)
102
- rig issue show <event-id> # one issue + its comments
103
- rig pr list --state open # patches/PRs
104
- rig pr show <event-id> --json | jq -r .pr.content | git am # apply a patch
105
-
106
- # 3. stay current — fetch downloads only the missing delta
107
- rig fetch # updates refs/remotes/origin/*, like git fetch
108
- rig merge origin/main # integrating is plain git (passthrough)
109
-
110
- # 4. ready to contribute back? writes are paid — add an identity + funds:
111
- export RIG_MNEMONIC="abandon abandon … about"
112
- export TOON_CLIENT_NETWORK=devnet # shared devnet: enables `rig fund` (no faucet URL needed)
113
- rig fund # devnet faucet drip
114
- rig issue create --title "found a bug" --body "details" # kind:1621
115
- rig push # or publish commits (your own repos)
111
+ ```sh
112
+ rig add -A
113
+ rig commit -m "initial commit"
116
114
  ```
117
115
 
118
- Note: freshly pushed objects can take **10-20 minutes** to become fetchable
119
- from Arweave gateways — `rig clone`/`rig fetch` right after a push reports
120
- the missing SHAs honestly; retry after propagation. A failed clone never
121
- leaves a partial repository behind.
116
+ ### 7. Push the paid publish
122
117
 
123
- ### Strict `--json` stdout (machine consumers)
118
+ `rig push` uploads your objects to Arweave and publishes the NIP-34 refs event
119
+ (plus the repo announcement on the first push). It prints a **fee table** — refs,
120
+ object count, bytes, itemized and total fee — and asks you to confirm before
121
+ spending. On this first paid write it **opens a payment channel from your funded
122
+ wallet automatically** (recorded and reused on later pushes; no manual
123
+ `rig channel open` needed).
124
124
 
125
- With `--json`, stdout carries **exactly one JSON document** — everything human-facing (identity reports, deprecation nudges, migration hints, chain-selection rationales, discovery warnings, progress lines, even stray `console.log` output from dependencies) is routed to stderr, so `rig <command> --json | jq` always parses. Errors emit one machine envelope (`{"error": "<code>", "detail": …}`) on stdout with the human detail on stderr and a non-zero exit; runs that fail before producing output (usage errors, pre-payment refusals) still emit a backstop error envelope. `--json` is a per-subcommand flag on the commands rig owns, **not** a global rig flag — see the passthrough note below.
125
+ ```sh
126
+ rig push # plan + price the current branch, confirm, then publish
127
+ # rig push main --yes # a specific ref, skipping the confirm prompt
128
+ ```
126
129
 
127
- ### Git passthrough
130
+ That's it — your repository is live on TOON. 🎉
128
131
 
129
- Any subcommand rig does not own is executed as `git <args...>` verbatim: the exact argv tail is handed to the system git with `stdio: 'inherit'` (interactive commands, pagers, colors, and prompts work), and git's exit code is rig's exit code (a child killed by a signal maps to the shell convention 128+N). rig-owned verbs always take precedence — in particular `rig push` is the TOON transport and shadows `git push`; plain-git pushes remain available by calling `git push` directly. If no system git is installed, passthrough fails with a clear error (exit 127).
132
+ ### 8. Verify it's live
130
133
 
131
- The passthrough is exempt from the `--json` contract: `rig status --json` runs `git status --json` (git rejects the flag), and flags before the subcommand (`rig --json status`) are not rig's either — the whole argv passes through to git untouched.
134
+ Clone it back from a clean directory (a free read) to prove the round-trip. Use
135
+ your own pubkey as the owner — `rig identity show` prints it as an `npub1…`.
132
136
 
133
- ### Identity
137
+ ```sh
138
+ cd /tmp
139
+ rig clone wss://relay-ws.devnet.toonprotocol.dev npub1youriden…/hello-toon
140
+ cd hello-toon && rig log --oneline
141
+ ```
142
+
143
+ You can also browse the repo (code, commits, issues, PRs) in the **Rig web UI**,
144
+ which reads the same relay + Arweave data your CLI just wrote.
145
+
146
+ > **Propagation note:** freshly pushed objects can take **10–20 minutes** to become
147
+ > fetchable from Arweave gateways. A `rig clone` / `rig fetch` right after a push
148
+ > reports any not-yet-propagated SHAs honestly — just retry after a few minutes. A
149
+ > failed clone never leaves a partial repo behind.
150
+
151
+ ### Keep working
134
152
 
135
- The CLI is **standalone by default**: it embeds its own payment client built
136
- from your seed phrase (`@toon-protocol/client` is a regular dependency,
137
- installed automatically with the package) — no daemon is ever required.
153
+ Iterate exactly like git; re-pushing only pays for **new** objects (uploads are
154
+ content-addressed, so known objects are skipped for free).
155
+
156
+ ```sh
157
+ rig add -p && rig commit -m "add a feature"
158
+ rig push
159
+ ```
138
160
 
139
- **No phrase yet? Generate one — `rig identity create`.** It mints a fresh
140
- BIP-39 mnemonic (via the client's generator — no external BIP-39 tooling),
141
- shows it ONCE with a backup warning, and writes it to the encrypted keystore
142
- under `TOON_CLIENT_HOME`. It refuses to overwrite an existing identity without
143
- `--force`. `rig identity show` reports the active source + pubkey (never the
144
- phrase); `rig identity import` writes an existing phrase (read from stdin,
145
- never a CLI argument) to the keystore. `--json` on **`create`** is the ONE
146
- sanctioned path that emits the phrase (in a `mnemonic` field — treat as
147
- secret); `show`/`import` never do. `rig init` also offers to generate on a
148
- chain miss (or `rig init --generate-identity`).
161
+ ### Collaborate
162
+
163
+ Issues, comments, and patches are paid writes against the same repo config; reading
164
+ them is free.
165
+
166
+ ```sh
167
+ # reads (free)
168
+ rig issue list
169
+ rig pr list --state open
170
+ rig pr show <event-id> --json | jq -r .pr.content | git am # apply a patch locally
171
+
172
+ # writes (paid)
173
+ rig issue create --title "Fix the flux" --body "It broke."
174
+ rig comment <root-event-id> --body "Nice catch."
175
+ rig pr create --title "Add feature" --range main..feature
176
+ rig pr status <event-id> applied
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Command reference
182
+
183
+ | command | cost | what it does |
184
+ | --- | --- | --- |
185
+ | `rig identity create` | free | mint a fresh BIP-39 identity into the encrypted keystore — the phrase is shown ONCE |
186
+ | `rig identity show` | free | the active identity's source + derived pubkey (never the phrase) |
187
+ | `rig identity import` | free | write an existing phrase (read from stdin, never argv) to the keystore |
188
+ | `rig init` | free | one-shot repo setup: git repo + identity + `toon.*` config + repo-local git commit-author from your Nostr identity |
189
+ | `rig remote add/remove/list` | free | relays as REAL git remotes (`origin` = default publish target) |
190
+ | `rig fund [--chain <c>]` | free | devnet faucet drip (native + USDC) to the active identity's wallet; prints addresses to fund externally off-devnet |
191
+ | `rig balance` | free | the active wallet's multi-chain balances |
192
+ | `rig clone <relay-url> <owner>/<repo-id> [dir]` | free | bootstrap a repo from TOON: relay state + SHA-verified Arweave objects → a real git repo. Shadows `git clone` |
193
+ | `rig fetch [remote]` | free | download the missing object delta + update `refs/remotes/<remote>/*`. Shadows `git fetch` |
194
+ | `rig push [remote] [refspecs...]` | **paid** | the TOON push: Arweave upload + NIP-34 refs publish. Shadows `git push` |
195
+ | `rig issue list` / `rig issue show <id>` | free | the repo's issues + comments from the terminal |
196
+ | `rig pr list` / `rig pr show <id>` | free | the repo's patches/PRs; `show` prints the full patch text (pipe to `git am`) |
197
+ | `rig issue create` | **paid** | file an issue (kind:1621) |
198
+ | `rig comment <root-event-id>` | **paid** | comment (kind:1622) on an issue/patch |
199
+ | `rig pr create` | **paid** | publish a patch (kind:1617) from real `git format-patch` |
200
+ | `rig pr status <event-id> <state>` | **paid** | set issue/patch status (kind:1630–1633) |
201
+ | `rig channel list/open/close/settle` | free / **paid** | inspect or manage the payment channels paid commands hold |
202
+ | `rig help` / `rig --version` | free | usage / version |
203
+ | everything else | — | executed as `git <args...>` with rig's stdio and git's exit code |
204
+
205
+ Every paid command supports `--yes` (skip the confirm prompt; **required** when
206
+ stdin is not a TTY) and `--json` (a `--json` run *without* `--yes` is a free
207
+ estimate — nothing is executed or paid).
208
+
209
+ ---
210
+
211
+ ## Money: fund, balance, channels
212
+
213
+ Paid commands spend from a **payment channel** — an on-chain-collateralized channel
214
+ between your wallet and a payment peer, from which each write draws an off-chain
215
+ claim. You rarely touch this directly:
216
+
217
+ - **`rig fund`** tops up your wallet (devnet faucet, or prints addresses to fund
218
+ externally). Both the native coin (gas) and USDC (collateral) are needed.
219
+ - **`rig balance`** shows what your wallet holds across chains.
220
+ - **Channels open lazily.** The first paid write opens a channel from your funded
221
+ wallet and records it under `~/.toon-client` (`rig-channels.json`); later writes
222
+ resume the same channel instead of opening a new one.
223
+ - **`rig channel list`** (free) shows current holdings and nonce watermarks.
224
+ **`rig channel open`** pre-opens one (or `--deposit`s more collateral) using the
225
+ exact lazy-open path; **`rig channel close`** starts the settlement challenge
226
+ window; **`rig channel settle`** releases collateral once the window elapses.
227
+
228
+ The `open`/`close`/`settle` lifecycle commands are on-chain wallet operations (gas +
229
+ collateral movement), so they follow the same confirm idiom as `push`: they print
230
+ what will happen, then require `--yes` or an interactive confirm.
231
+
232
+ ---
233
+
234
+ ## Strict `--json` stdout (machine consumers)
235
+
236
+ With `--json`, stdout carries **exactly one JSON document** — everything
237
+ human-facing (identity reports, deprecation nudges, progress lines, even stray
238
+ `console.log` from dependencies) is routed to stderr, so `rig <command> --json | jq`
239
+ always parses. Errors emit one machine envelope (`{"error": "<code>", "detail": …}`)
240
+ on stdout with the human detail on stderr and a non-zero exit. `--json` is a
241
+ per-subcommand flag on the commands rig owns, **not** a global rig flag.
242
+
243
+ ## Git passthrough
244
+
245
+ Any subcommand rig does not own is executed as `git <args...>` verbatim: the exact
246
+ argv tail is handed to system git with `stdio: 'inherit'` (interactive commands,
247
+ pagers, colors, and prompts work), and git's exit code becomes rig's exit code (a
248
+ child killed by a signal maps to the shell convention 128+N). rig-owned verbs always
249
+ take precedence — in particular `rig push` is the TOON transport and shadows
250
+ `git push`; plain-git pushes remain available by calling `git push` directly. If no
251
+ system git is installed, passthrough fails with a clear error (exit 127).
252
+
253
+ The passthrough is exempt from the `--json` contract: `rig status --json` runs
254
+ `git status --json` (git rejects the flag), and flags before the subcommand
255
+ (`rig --json status`) pass through to git untouched.
256
+
257
+ ## Identity
258
+
259
+ The CLI is **standalone by default**: it embeds its own payment client built from
260
+ your seed phrase (`@toon-protocol/client` is a regular dependency, installed
261
+ automatically) — no daemon is ever required.
262
+
263
+ **No phrase yet? Generate one — `rig identity create`.** It mints a fresh BIP-39
264
+ mnemonic, shows it ONCE with a backup warning, and writes it to the encrypted
265
+ keystore under `TOON_CLIENT_HOME`. It refuses to overwrite an existing identity
266
+ without `--force`. `rig identity show` reports the active source + pubkey (never the
267
+ phrase); `rig identity import` writes an existing phrase (read from stdin, never a
268
+ CLI argument) to the keystore. `--json` on **`create`** is the ONE sanctioned path
269
+ that emits the phrase (in a `mnemonic` field — treat as secret); `show`/`import`
270
+ never do.
149
271
 
150
272
  The mnemonic is resolved along one precedence chain — highest first:
151
273
 
152
274
  1. `RIG_MNEMONIC` environment variable
153
- 2. `TOON_CLIENT_MNEMONIC` environment variable — deprecated alias, warns on
154
- stderr; rename it to `RIG_MNEMONIC`
155
- 3. project-local `.env` — found by walking up from the working directory
156
- (through the repo root); ONLY the `RIG_MNEMONIC` line is parsed out of it
157
- (rig never loads arbitrary env from the file, and never requires it).
158
- **Gitignore it** the phrase must never be committed.
159
- 4. the shared `~/.toon-client` state dir (`TOON_CLIENT_HOME` override):
160
- encrypted keystore (`keystorePath` + `TOON_CLIENT_KEYSTORE_PASSWORD`),
161
- then the `mnemonic` config field
275
+ 2. `TOON_CLIENT_MNEMONIC` environment variable — deprecated alias, warns on stderr;
276
+ rename it to `RIG_MNEMONIC`
277
+ 3. project-local `.env` — found by walking up from the working directory (through
278
+ the repo root); ONLY the `RIG_MNEMONIC` line is parsed out of it. **Gitignore
279
+ it** the phrase must never be committed.
280
+ 4. the shared `~/.toon-client` state dir (`TOON_CLIENT_HOME` override): encrypted
281
+ keystore (`keystorePath` + `TOON_CLIENT_KEYSTORE_PASSWORD`), then the `mnemonic`
282
+ config field
162
283
 
163
284
  Every paid command reports which source is active and the derived pubkey
164
- (`Identity: <pubkey> (from …)`, and an `identity` object in `--json`
165
- output) — the phrase itself is never printed and never written to git config
166
- or any repo file.
167
-
168
- ### Daemon as accelerator (#279)
169
-
170
- Every standalone paid command pays a fixed bootstrap cost (relay discovery,
171
- peer negotiation, channel resume). Two things remove most of it:
172
-
173
- - **Automatic daemon delegation** when a running `toon-clientd` on the
174
- loopback control port (`TOON_CLIENT_HTTP_PORT`, default 8787) holds the
175
- **same identity**, paid write commands (`push`, `issue`, `comment`,
176
- `pr create`, `pr status`) delegate to its `/git/*` routes instead of
177
- bootstrapping an embedded client. The daemon already owns the payment
178
- channel's cumulative-claim watermark, so one process signs all claims
179
- the exact safety property the pre-#279 nonce-guard *refusal* protected,
180
- achieved by delegation instead. The identity match is confirmed against
181
- `GET /status` **before** anything is sent. A daemon on a different
182
- identity, or no daemon at all, runs standalone as always. The chosen path
183
- prints on stderr (`rig: paid path: …`) and lands in `--json` envelopes as
184
- `"path": "daemon" | "standalone"`. Note: the single-event daemon routes
185
- publish via the daemon's configured relay route; a resolved relay that
186
- differs from it draws a warning. Commands the daemon has **no route
187
- for** `rig fund`, `rig balance`, `rig channel open|close|settle` — always
188
- run standalone; the on-chain channel mutations among them still refuse
189
- while a same-identity daemon runs (they must not race its live claims):
190
- stop the daemon for those.
191
- - **Standalone topology cache** the resolved network topology (announce
192
- discovery, payment-peer pick, settlement-chain selection incl. the
193
- funded-chain probes) is cached under `TOON_CLIENT_HOME`
194
- (`rig-topology-cache.json`), keyed by relay + identity + explicit config,
195
- for 15 minutes (`RIG_TOPOLOGY_TTL_MS` overrides; `0` disables). A cached
196
- topology that fails to bootstrap is invalidated and re-resolved live
197
- automatically. Money state (claim watermarks, channel map) is never
198
- cached.
199
-
200
- The `rig` bin also exits as soon as a command finishes and stdio is flushed:
201
- the embedded client can leave a keep-alive socket that would otherwise hold
202
- the process open for ~30 more seconds which was, in fact, the bulk of the
203
- uniform "~32s per paid command" the #279 study measured.
204
-
205
- ### Pushing
206
-
207
- `rig push [remote] [refspecs...]` uploads the object delta to Arweave (paid, content-addressed a re-push never re-pays for known objects) and publishes the NIP-34 refs event (kind:30618; plus the kind:30617 announcement on first push). It renders the fee table (refs with classification, objects, bytes, itemized + total fee) and asks for confirmation before spending — writes are permanent and non-refundable. `--yes` skips the prompt (and is required when stdin is not a TTY); `--json` without `--yes` is a pure estimate (nothing executed). `--force` allows non-fast-forward updates; `--repo-id <id>` overrides the configured repo id.
208
-
209
- Repo addressing (`30617:<owner>:<repoId>`) comes from the `toon.repoid`/`toon.owner` git config keys `rig init` writes — an unconfigured repo is a clear "run `rig init`" error, and pushing never mutates git config. Objects over 95KB are a hard error in v1 (large-object support: toon-client#235).
210
-
211
- ### Relays are origins
212
-
213
- Relays are configured as **real git remotes** (`rig remote add` is `git remote add` underneath — `git remote -v` shows them, and remotes added with plain git work too, as long as the URL is `ws://`/`wss://`/`http://`/`https://`):
214
-
215
- - `rig remote add origin <relay-url>` / `rig remote remove <name>` / `rig remote list` (`--json` supported). Junk URLs are rejected at add time; an existing name is refused with a `git remote set-url` hint.
216
- - `rig push` publishes via `origin`; `rig push <remote> [refspecs...]` via a named remote. Git-like resolution: when the first positional matches a configured remote name it is the remote, otherwise it is a refspec and the remote defaults to `origin`. No usable remote a clear ``no origin configured — run `rig remote add origin <relay-url>` `` error.
285
+ (`Identity: <pubkey> (from …)`, and an `identity` object in `--json` output) — the
286
+ phrase itself is never printed and never written to git config or any repo file.
287
+
288
+ ## Daemon as accelerator
289
+
290
+ Every standalone paid command pays a fixed bootstrap cost (relay discovery, peer
291
+ negotiation, channel resume). Two things remove most of it:
292
+
293
+ - **Automatic daemon delegation** — when a running `toon-clientd` on the loopback
294
+ control port (`TOON_CLIENT_HTTP_PORT`, default 8787) holds the **same identity**,
295
+ paid write commands (`push`, `issue`, `comment`, `pr create`, `pr status`)
296
+ delegate to its `/git/*` routes instead of bootstrapping an embedded client. The
297
+ daemon already owns the payment channel's cumulative-claim watermark, so one
298
+ process signs all claims. The identity match is confirmed against `GET /status`
299
+ **before** anything is sent; a daemon on a different identity, or none at all,
300
+ runs standalone. The chosen path prints on stderr (`rig: paid path: …`) and lands
301
+ in `--json` as `"path": "daemon" | "standalone"`. Commands the daemon has no route
302
+ for `rig fund`, `rig balance`, `rig channel open|close|settle` always run
303
+ standalone (the on-chain channel mutations among them refuse while a same-identity
304
+ daemon runs, so as not to race its live claims: stop the daemon for those).
305
+ - **Standalone topology cache** the resolved network topology (announce discovery,
306
+ payment-peer pick, settlement-chain selection) is cached under `TOON_CLIENT_HOME`
307
+ (`rig-topology-cache.json`), keyed by relay + identity + explicit config, for 15
308
+ minutes (`RIG_TOPOLOGY_TTL_MS` overrides; `0` disables). A cached topology that
309
+ fails to bootstrap is invalidated and re-resolved live. Money state (claim
310
+ watermarks, channel map) is never cached.
311
+
312
+ The `rig` bin also exits as soon as a command finishes and stdio is flushed, rather
313
+ than letting the embedded client's keep-alive socket hold the process open for ~30s.
314
+
315
+ ## Pushing
316
+
317
+ `rig push [remote] [refspecs...]` uploads the object delta to Arweave (paid,
318
+ content-addressed a re-push never re-pays for known objects) and publishes the
319
+ NIP-34 refs event (kind:30618; plus the kind:30617 announcement on first push). It
320
+ renders the fee table (refs with classification, objects, bytes, itemized + total
321
+ fee) and asks for confirmation before spending writes are permanent and
322
+ non-refundable. `--yes` skips the prompt (and is required when stdin is not a TTY);
323
+ `--json` without `--yes` is a pure estimate (nothing executed). `--force` allows
324
+ non-fast-forward updates; `--repo-id <id>` overrides the configured repo id.
325
+
326
+ Repo addressing (`30617:<owner>:<repoId>`) comes from the `toon.repoid` / `toon.owner`
327
+ git config keys `rig init` writes — an unconfigured repo is a clear "run `rig init`"
328
+ error, and pushing never mutates git config. Objects over 95KB are a hard error in
329
+ v1 (large-object support: toon-client#235).
330
+
331
+ ## Relays are origins
332
+
333
+ Relays are configured as **real git remotes** (`rig remote add` is `git remote add`
334
+ underneath — `git remote -v` shows them, and remotes added with plain git work too,
335
+ as long as the URL is `ws://`/`wss://`/`http://`/`https://`):
336
+
337
+ - `rig remote add origin <relay-url>` / `rig remote remove <name>` / `rig remote list`
338
+ (`--json` supported). Junk URLs are rejected at add time.
339
+ - `rig push` publishes via `origin`; `rig push <remote> [refspecs...]` via a named
340
+ remote. Git-like resolution: when the first positional matches a configured remote
341
+ name it is the remote, otherwise it is a refspec and the remote defaults to
342
+ `origin`.
217
343
  - The event commands take `--remote <name>` (default `origin`).
218
- - `--relay <url>` stays as an **ad-hoc override** on every paid command: it bypasses the configured remotes entirely (for push, every positional is then a refspec).
219
- - One relay URL per remote: a remote with multiple URLs (`git remote set-url --add`) is refused **before anything is uploaded, published, or paid** — rig publishes to exactly one relay per paid command.
220
- - Migration from v0.1: a configured `git config toon.relay` still works as a fallback when no relay `origin` exists (paid commands print a one-line deprecation nudge), and `rig init` migrates it to a real `origin` remote automatically. The `toon.relay` key is removed in v0.3.
344
+ - `--relay <url>` stays as an **ad-hoc override** on every paid command: it bypasses
345
+ the configured remotes entirely.
346
+ - One relay URL per remote: a remote with multiple URLs is refused **before**
347
+ anything is uploaded, published, or paid.
221
348
 
222
- The single-event subcommands follow the same paid-write discipline as push — the per-event fee is quoted and confirmed before publishing; `--yes` skips, `--json` without `--yes` is a free estimate:
349
+ The single-event subcommands follow the same paid-write discipline as push — the
350
+ per-event fee is quoted and confirmed before publishing; `--yes` skips, `--json`
351
+ without `--yes` is a free estimate:
223
352
 
224
353
  - `rig issue create --title <t> [--body <b> | --body-file <f> | stdin] [--label <l>]…` — kind:1621.
225
354
  - `rig comment <root-event-id> --body <b> [--parent-author <pubkey>] [--marker root|reply]` — kind:1622.
226
- - `rig pr create --title <t> (--range <A..B> | --patch-file <f>) [--body <b> | --body-file <f>] [--branch <name>]` — kind:1617; `--range` runs real `git format-patch --stdout` locally and derives the `commit`/`parent-commit` tags. A multi-commit range publishes ONE event carrying the whole series (cover-letter threading is out of scope in v1). `--body`/`--body-file` attach the PR description in a dedicated `description` tag — the event content stays pure format-patch output, so `rig pr show`'s patch text still pipes straight into `git am`.
227
- - `rig pr status <target-event-id> <open|applied|closed|draft>` — kind:1630–1633, with the repo `a` tag attached. (This was top-level `rig status` before v2; bare `rig status` now passes through to `git status`.)
228
-
229
- `--repo-id`/`--owner` override the git config address (use `--owner` for repos you don't own).
230
-
231
- ### Cloning & fetching (free reads, #278)
232
-
233
- `rig clone <relay-url> <owner>/<repo-id> [dir]` reconstructs the repository from public data alone: the kind:30618 `arweave` sha→txId map drives parallel downloads across the gateway fallback chain (SHAs the map misses resolve via the Arweave GraphQL `Git-SHA` tag index), **every body is verified against its SHA-1 before it is written** (verification doubles as object-type discovery; corrupt/tampered content is rejected), and the repository is materialized through git's own plumbing — `git hash-object -w --stdin -t <type>` (written SHA re-checked), `git update-ref`, HEAD from the 30618 symref, checked-out worktree. Everything happens in a temp dir moved into place on success, so a failed clone never leaves a partial repo. `rig fetch [remote]` is the same pipeline as a delta: only locally-missing objects are downloaded, and `refs/remotes/<remote>/*` (tags → `refs/tags/*`) move with a `git fetch`-style report.
234
-
235
- `rig issue list|show` and `rig pr list|show` are pure relay reads (kind:1621/1617 by the repo `#a` tag; state from kind:1630-1633, latest wins; kind:1622 comments under `show`), tolerant of the devnet relay's non-canonical EVENT payload encodings.
355
+ - `rig pr create --title <t> (--range <A..B> | --patch-file <f>) [--body <b> | --body-file <f>] [--branch <name>]` —
356
+ kind:1617; `--range` runs real `git format-patch --stdout` locally and derives the
357
+ `commit`/`parent-commit` tags. A multi-commit range publishes ONE event carrying
358
+ the whole series. `--body`/`--body-file` attach the PR description in a dedicated
359
+ `description` tag — the event content stays pure format-patch output, so
360
+ `rig pr show`'s patch text still pipes straight into `git am`.
361
+ - `rig pr status <target-event-id> <open|applied|closed|draft>` — kind:1630–1633.
362
+
363
+ `--repo-id` / `--owner` override the git config address (use `--owner` for repos you
364
+ don't own).
365
+
366
+ ## Cloning & fetching (free reads)
367
+
368
+ `rig clone <relay-url> <owner>/<repo-id> [dir]` reconstructs the repository from
369
+ public data alone: the kind:30618 `arweave` sha→txId map drives parallel downloads
370
+ across the gateway fallback chain (SHAs the map misses resolve via the Arweave
371
+ GraphQL `Git-SHA` tag index), **every body is verified against its SHA-1 before it
372
+ is written**, and the repository is materialized through git's own plumbing
373
+ (`git hash-object -w`, `git update-ref`, HEAD from the 30618 symref, checked-out
374
+ worktree). Everything happens in a temp dir moved into place on success, so a failed
375
+ clone never leaves a partial repo. `rig fetch [remote]` is the same pipeline as a
376
+ delta: only locally-missing objects are downloaded, and `refs/remotes/<remote>/*`
377
+ (tags → `refs/tags/*`) move with a `git fetch`-style report.
378
+
379
+ `rig issue list|show` and `rig pr list|show` are pure relay reads (kind:1621/1617 by
380
+ the repo `#a` tag; state from kind:1630-1633, latest wins; kind:1622 comments under
381
+ `show`).
236
382
 
237
383
  ## Library
238
384
 
239
- No signing or payment code lives in the core that stays behind the `Publisher` seam:
240
-
241
- - `objects.ts` — git object construction with SHA-1 envelope hashing: `createGitBlob`, `createGitTree`, `createGitCommit`, `createGitTag` (annotated tags), the `GitObject`/`GitObjectType` types, `hashGitObject`, and the `MAX_OBJECT_SIZE` (95KB) upload guard constant.
242
- - `nip34-events.ts` — NIP-34 event builders returning `UnsignedEvent` (caller signs and publishes): `buildRepoAnnouncement` (30617), `buildRepoRefs` (30618, incl. `arweave` sha→txId tags), `buildIssue` (1621), `buildComment` (1622), `buildPatch` (1617, optional real `git format-patch` content), `buildStatus` (1630–1633).
243
- - `repo-reader.ts` — `GitRepoReader`, read-only local-repo access via injection-safe `execFile` git plumbing: `listRefs`, `objectsBetween`(+`WithPaths`), `readObjects`, `statObjects`, `isAncestor`, `formatPatch`, `resolveRef`.
244
- - `remote-state.ts` — `fetchRemoteState`, the "what does the remote have?" reader: kind:30617/30618 relay fetch (NIP-33 latest-wins across a plural relay list) + `resolveMissing` Arweave GraphQL Git-SHA fallback; `queryRelay` (tolerant NIP-01 REQ→EOSE) is exported for other readers.
245
- - `object-fetch.ts` / `read-pipeline.ts` / `materialize.ts` (#278) the read path: `fetchTxBytes`/`downloadGitObjects` (gateway fallback + concurrency cap + SHA-1 verification-as-type-discovery, `ObjectIntegrityError` on mismatch), `referencedShas`/`walkClosure` (object-graph closure, gitlink-aware), `collectRepoObjects` (the clone/fetch collection engine separating fatal gaps from unreachable ones), and `writeGitObject(s)`/`updateRef`/`setHeadSymref` (git plumbing writers with hostile-refname gating).
246
- - `npub.ts` dependency-free bech32 `npubToHex`/`hexToNpub`/`ownerToHex` (NIP-19 pubkey addressing for `rig clone`).
247
- - `publisher.ts` the `Publisher` interface (paid transport seam): `getFeeRates`, `uploadGitObject`, `publishEvent`. Implemented by the daemon (#227) and the standalone embedded client (#228).
248
- - `push.ts` — `planPush` (ref classification, object delta minus known sha→txId hints, oversize hard error, fee estimate) and `executePush` (uploads ref tips last, then ONE cumulative kind:30618 merging the full arweave map, kind:30617 first on first push; crash-resume safe via content-addressed skip).
249
- - `routes.ts` — the JSON wire shapes of the daemon's `/git/*` control routes (bigints as decimal strings, Maps as records) + the matching `serializePushPlan`/`serializePushResult` helpers, shared with `@toon-protocol/client-mcp` and consumed by the CLI's #279 delegated fast path (`cli/daemon-session.ts`).
250
- - `cli/` — the `rig` bin: `init` (#248), `remote` (#249, relays as real git remotes + the shared relay resolution), `push` (#229), the single-event `issue`/`comment`/`pr create`/`pr status` subcommands (#231, nested under `pr` since #250), the git passthrough (#250, `dispatch.ts` + `git-passthrough.ts`), and the #279 daemon-as-accelerator delegation (`daemon-session.ts`), standalone by default with the `identity.ts` resolution chain.
251
-
252
- Pure builders promoted from the proven Rig E2E seed pipeline (`packages/rig-web/tests/e2e/seed/lib`). Part of [epic #222](https://github.com/toon-protocol/toon-client/issues/222) and [epic #246](https://github.com/toon-protocol/toon-client/issues/246).
385
+ `rig` is also the git-to-TOON write-path core. No signing or payment code lives in
386
+ it — that stays behind the `Publisher` seam:
387
+
388
+ - `objects.ts` — git object construction with SHA-1 envelope hashing: `createGitBlob`,
389
+ `createGitTree`, `createGitCommit`, `createGitTag`, `hashGitObject`, and the
390
+ `MAX_OBJECT_SIZE` (95KB) upload guard.
391
+ - `nip34-events.ts` — NIP-34 event builders returning `UnsignedEvent`:
392
+ `buildRepoAnnouncement` (30617), `buildRepoRefs` (30618), `buildIssue` (1621),
393
+ `buildComment` (1622), `buildPatch` (1617), `buildStatus` (1630–1633).
394
+ - `repo-reader.ts` — `GitRepoReader`, read-only local-repo access via injection-safe
395
+ `execFile` git plumbing.
396
+ - `remote-state.ts` `fetchRemoteState`, the "what does the remote have?" reader.
397
+ - `object-fetch.ts` / `read-pipeline.ts` / `materialize.ts` — the read path
398
+ (gateway fallback + concurrency cap + SHA-1 verification, object-graph closure,
399
+ git plumbing writers with hostile-refname gating).
400
+ - `npub.ts` — dependency-free bech32 `npubToHex` / `hexToNpub` / `ownerToHex`.
401
+ - `publisher.ts` — the `Publisher` interface (paid transport seam), implemented by
402
+ the daemon and the standalone embedded client.
403
+ - `push.ts` — `planPush` (ref classification, object delta, fee estimate) and
404
+ `executePush` (crash-resume safe via content-addressed skip).
405
+ - `routes.ts` — the JSON wire shapes of the daemon's `/git/*` control routes.
406
+ - `cli/` — the `rig` bin.
407
+
408
+ Part of [epic #222](https://github.com/toon-protocol/toon-client/issues/222) and
409
+ [epic #246](https://github.com/toon-protocol/toon-client/issues/246).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toon-protocol/rig",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Git-to-TOON write path core — build git objects and NIP-34 events for the Rig control plane",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Green",