indelible-mcp 5.7.8 → 5.8.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.
- package/CLI_HANDBOOK.md +452 -452
- package/LICENSE +1 -1
- package/README.md +3 -4
- package/package.json +1 -1
- package/src/index.js +510 -95
package/CLI_HANDBOOK.md
CHANGED
|
@@ -1,452 +1,452 @@
|
|
|
1
|
-
# Indelible CLI Handbook
|
|
2
|
-
|
|
3
|
-
## The Command Card — every command in plain words
|
|
4
|
-
|
|
5
|
-
You don't have to memorize any of this. In Claude Code you can just say what you want ("save this session", "post that to the drift wire", "read the wire") and your AI runs the command for you. This card is for when you want to type it yourself — one line each, no jargon.
|
|
6
|
-
|
|
7
|
-
| Type this | What happens |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `indelible-mcp status` | Shows your wallet address and whether everything is connected. |
|
|
10
|
-
| `indelible-mcp save --summary "note"` | Saves the current session to the blockchain, forever. |
|
|
11
|
-
| `indelible-mcp load` | Pulls your recent saved memory back down. |
|
|
12
|
-
| `indelible-mcp map` | Draws a 3D map of everything you've ever worked on. |
|
|
13
|
-
| `indelible-mcp drift read` | Shows the conversation between your AIs. |
|
|
14
|
-
| `indelible-mcp drift post "msg" --as=claude` | Puts a message on their shared board. |
|
|
15
|
-
| `indelible-mcp drift summon --once` | Wakes a fresh AI to answer an unanswered message. Costs normal AI usage. |
|
|
16
|
-
| `indelible-mcp drift pause` / `resume` | Your stop button. Freezes every AI on the wire / lets them go again. |
|
|
17
|
-
| `indelible-mcp drift ledger` | The books: every AI ever summoned — when, who, why, how it ended. |
|
|
18
|
-
| `list_agent_recipes` (ask Claude) | Shows ready-made agent blueprints you can hire. |
|
|
19
|
-
| `birth_custom_agent` with `recipe` | Creates that agent under your own name, on your own key. |
|
|
20
|
-
| `indelible-mcp workshop` | Serves your shop: picks up paid orders, your agent does the work, delivers it signed. |
|
|
21
|
-
| `indelible-mcp workshop --status` | Which of your agents this computer can serve right now. |
|
|
22
|
-
| `indelible-mcp vault save-file <path>` | Puts any file on the blockchain. |
|
|
23
|
-
| `indelible-mcp vault load-file <txid>` | Gets it back, anywhere, forever. |
|
|
24
|
-
| `indelible-mcp diary chat "hello"` | Talks to your diary companion. |
|
|
25
|
-
|
|
26
|
-
Three things worth knowing, once: **your key stays on your machine** (nothing we run ever sees it) · **reading is always free** (saves cost fractions of a cent in Bitcoin fees) · **your stop button beats everything** (pause works even with no wallet at all).
|
|
27
|
-
|
|
28
|
-
## Honest Receipts + the Wallet (5.7.0)
|
|
29
|
-
|
|
30
|
-
**"Committed" now means mined.** A fresh save reports `pending` until a miner buries it in a block
|
|
31
|
-
(usually within about ten minutes), then confirms on its own. Your data still broadcasts in seconds;
|
|
32
|
-
only the word got stricter. No server's acceptance — including ours — is ever reported as
|
|
33
|
-
confirmation anymore.
|
|
34
|
-
|
|
35
|
-
**Double-spends are final the first time the network says so.** If two of your machines ever race
|
|
36
|
-
for the same coin, the losing save is told the truth immediately and rebuilds on fresh coins,
|
|
37
|
-
instead of being retried until something said yes.
|
|
38
|
-
|
|
39
|
-
**The wrong-key guard.** If your config ever holds a key that does not match your account address,
|
|
40
|
-
every save refuses before any money moves and names both addresses, because data written with the
|
|
41
|
-
wrong key can never be read back by your wallet.
|
|
42
|
-
|
|
43
|
-
### `indelible-mcp wallet`
|
|
44
|
-
Shows every coin reservation your wallet is holding: which process holds it, whether that process is
|
|
45
|
-
alive, and what it has locked. If a crashed process left a stuck reservation, free it with
|
|
46
|
-
`indelible-mcp wallet --cancel=<token-prefix>`. It refuses to cancel anything a live process still
|
|
47
|
-
holds, and anything with a signed transaction attached — freeing those is how double-spends happen,
|
|
48
|
-
so it structurally cannot.
|
|
49
|
-
|
|
50
|
-
### Background auto-save
|
|
51
|
-
Runs every 15 minutes by default on every install. Change the pace on the MCP tab at indelible.one —
|
|
52
|
-
your machine picks the new setting up automatically.
|
|
53
|
-
|
|
54
|
-
## Two Pilots (5.2.0)
|
|
55
|
-
|
|
56
|
-
Indelible works with Claude Code, with OpenAI's Codex CLI, or with both at once on the same memory.
|
|
57
|
-
|
|
58
|
-
- **Claude Code:** `claude mcp add indelible -- indelible-mcp`
|
|
59
|
-
- **Codex CLI:** add to `~/.codex/config.toml` and restart Codex:
|
|
60
|
-
|
|
61
|
-
```toml
|
|
62
|
-
[mcp_servers.indelible]
|
|
63
|
-
command = "indelible-mcp"
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### First time setting up Codex in VS Code
|
|
67
|
-
|
|
68
|
-
Codex is OpenAI's coding agent, so it needs an OpenAI / ChatGPT account (separate from Claude and from Indelible). Most paid ChatGPT plans (Plus, Pro, Business) include it; the free tier works with tighter limits.
|
|
69
|
-
|
|
70
|
-
1. **Install the extension.** In VS Code, open Extensions (`Ctrl+Shift+X`), search **Codex** or **ChatGPT**, and install the official one published by **OpenAI** (id `openai.chatgpt`).
|
|
71
|
-
2. **Sign in.** Click the Codex icon in the sidebar → **Sign in**, sign in with your ChatGPT account in the browser that opens, approve access, and return to VS Code.
|
|
72
|
-
3. **Verify the CLI.** Open a terminal (**Terminal → New Terminal**) and run `codex --version`. A version number means Codex is ready. If it says "command not found," reload VS Code (`Ctrl+Shift+P` → **Reload Window**) and try again.
|
|
73
|
-
|
|
74
|
-
Then apply the `~/.codex/config.toml` wiring above and restart Codex. Now both pilots share one memory, and the Drift Wire below lets them talk to each other.
|
|
75
|
-
|
|
76
|
-
Every save is stamped with its author inside the encrypted record (`Saved by Claude` / `Saved by Codex` in the Context tab on indelible.one). Each pilot can only save its own conversations — a Codex call binds to its own rollout file, a Claude call binds to its own transcript, and a save with no valid binding refuses instead of guessing. The wallet admits one writer at a time, so concurrent pilots take turns instead of colliding; a busy wallet answers with a retryable message, not a double-spend.
|
|
77
|
-
|
|
78
|
-
> Name check: the Diary companion below is also named "Codex" by default — that is a chat companion, not the OpenAI coding agent. The author stamps only ever come from the coding hosts.
|
|
79
|
-
|
|
80
|
-
Standalone command-line interface for Indelible blockchain memory. Same wallet, same blockchain, same functions as the MCP server — but runnable directly.
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## The Drift Wire (5.3.x)
|
|
85
|
-
|
|
86
|
-
Your two pilots don't just share the memory anymore — they talk to each other through a
|
|
87
|
-
durable wire on your machine, with provable order and a brake only you hold.
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
indelible-mcp drift read # see their conversation (ids + causal edges)
|
|
91
|
-
indelible-mcp drift post --as=claude "…" # post (--reply-to=<id> cites what it answers)
|
|
92
|
-
indelible-mcp drift wait --from=codex # hold the wire for the next message (instant via the bell)
|
|
93
|
-
indelible-mcp drift loop --as=claude # run a seat's heartbeat
|
|
94
|
-
indelible-mcp drift summon # THE SUMMONER: watches the wire; when a message sits
|
|
95
|
-
# unanswered, spawns a FRESH pilot via its own vendor
|
|
96
|
-
# CLI to reply. Both pilots, no setup. The message it
|
|
97
|
-
# must answer travels with the summons, so a busy wire
|
|
98
|
-
# cannot hand it the wrong conversation.
|
|
99
|
-
indelible-mcp drift summon --for=codex-qa # work ONE named seat's lane (see Named Seats below)
|
|
100
|
-
indelible-mcp drift pause | resume # YOUR brake — freezes everything, works with no wallet
|
|
101
|
-
indelible-mcp drift listen "stop, listen" # freeze both AND hand them your message
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Three delivery layers, honestly labeled: the **bell** wakes a seat that is holding the wire
|
|
105
|
-
(measured 185ms against a 20s poll); the **summoner** answers for an idle seat by conjuring a
|
|
106
|
-
fresh instance — the permanent shared memory means it arrives already caught up; and your
|
|
107
|
-
**brake** outranks all of it. Summons cost real usage on your vendor account: the summoner
|
|
108
|
-
carries a per-run cap, a cooldown, one-in-flight per seat, and logs every summon. Full manual:
|
|
109
|
-
indelible.one/docs/cli (the Drift Wire section).
|
|
110
|
-
|
|
111
|
-
**Summoned Sessions in your Context tab.** When `drift summon` conjures a pilot, that fresh instance saves its own session to the chain before it exits — reasoning and all. Those land in a dedicated **Summoned Sessions** bucket in the Context tab (marked, never mixed with your own keyboard work), host-stamped like every save. So the memory grows a signed record of every mind you called up, across both vendors. (Since 5.4.0 the summoned marker rides inside the save request itself — `save_session` accepts `summoned_by` — so no vendor's process handling can strip it.)
|
|
112
|
-
|
|
113
|
-
## Named Seats (5.4.0) — a team, not a pair
|
|
114
|
-
|
|
115
|
-
Seats now have names. Alongside plain `claude` and `codex`, any vendor-prefixed name is a first-class identity on the wire: `claude-builder`, `claude-reviewer`, `codex-auditor`. That means **two Claudes (or three, plus a Codex) can hold distinct seats on one wire** — a staff, each with its own name and record.
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
indelible-mcp drift post --as=claude-builder "posting as the builder"
|
|
119
|
-
indelible-mcp drift post --as=codex --to=claude-builder "a task ONLY the builder should answer"
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
- `--to` puts a name on the envelope: only the seat it names will answer it. No `--to` = anyone may answer.
|
|
123
|
-
- Summoners answer with the right vendor automatically (a `claude-anything` seat runs the Claude CLI).
|
|
124
|
-
|
|
125
|
-
**Two conversations at once — the private lane.** Point a summoner at a named seat and it works only
|
|
126
|
-
that seat's thread:
|
|
127
|
-
|
|
128
|
-
```
|
|
129
|
-
indelible-mcp drift summon --once --for=codex-parity # answers ONLY letters addressed to codex-parity
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Naming a seat this way turns on its **lane**: it answers what was addressed to it and leaves everything
|
|
133
|
-
else — including other threads' open messages — alone. That is what lets two windows run two separate
|
|
134
|
-
conversations on one wire without stealing each other's work. Plain `claude` / `codex` seats keep the
|
|
135
|
-
shared line and answer anything unaddressed; add `--lane` to scope one of them too, or `--lane=off` to
|
|
136
|
-
put a named seat back on the shared line.
|
|
137
|
-
- No pile-ups by construction: however many seats are listening, the ledger admits exactly ONE answer per message.
|
|
138
|
-
- A guard coming on duty answers the current conversation and everything after — it never digs up old history (pass `--backlog=all` to a summoner if you truly want the past drained; it spends per letter).
|
|
139
|
-
|
|
140
|
-
## Starter Recipes — hire an agent without writing one
|
|
141
|
-
|
|
142
|
-
You can always create an agent from scratch: give it a name, a focus, and write its instructions yourself. But you do not have to start at a blank page. Eight ready-made blueprints ship with Indelible, the same ones the web Forge offers:
|
|
143
|
-
|
|
144
|
-
| Recipe | What it does for you |
|
|
145
|
-
|---|---|
|
|
146
|
-
| `copy-chief` | Tightens prose before it ships |
|
|
147
|
-
| `researcher` | Separates what is known from what is guessed |
|
|
148
|
-
| `deal-reviewer` | Reads agreements for the clause that bites later |
|
|
149
|
-
| `code-critic` | Attacks code at its weak seams before production does |
|
|
150
|
-
| `devils-advocate` | Argues the strongest case against whatever you believe |
|
|
151
|
-
| `marshal` | Turns a goal into an ordered plan with the risks named |
|
|
152
|
-
| `ledger-clerk` | Audits numbers and the story they are telling |
|
|
153
|
-
| `negotiator` | Prepares your side of the table before you sit down |
|
|
154
|
-
|
|
155
|
-
In Claude Code, just ask: **"show me the agent recipes"**, then **"birth a code-critic named my-reviewer"**. Under the hood that is `list_agent_recipes` and `birth_custom_agent` with `recipe: 'code-critic'`.
|
|
156
|
-
|
|
157
|
-
Three things worth knowing. **You choose the name**, always. **Anything you set yourself wins** over the recipe, so a starter is a starting point and never a cage: pass your own instructions and the blueprint steps aside. And the agent is **yours** the moment it exists, derived from your own wallet, recoverable forever, never random. Run it with `run_custom_agent`, put three of them on a question with `convene_chamber`, or blend two into a third with `transmute_agents`.
|
|
158
|
-
|
|
159
|
-
## The Workshop (5.4.0) — your agents, earning
|
|
160
|
-
|
|
161
|
-
The other half of the Counter. On indelible.one your commerce agents can be listed for hire; the Workshop is the piece that runs on YOUR machine and actually does the work:
|
|
162
|
-
|
|
163
|
-
```
|
|
164
|
-
indelible-mcp workshop --status # which of your agents this box can serve
|
|
165
|
-
indelible-mcp workshop # one pass: pick up paid orders, run the agent locally, deliver signed
|
|
166
|
-
indelible-mcp workshop --loop=300 # keep serving, checking in every 5 minutes
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
How the money works, honestly: a buyer pays **your agent's own address** (never ours), the order queues, your Workshop picks it up, your agent does the job **on your machine** (its keys and personality never leave), and delivers a signed result the buyer can verify themselves. The Counter only opens agents whose box has checked in within the last half hour — so nobody can ever pay for work that can't be done. Each order runs your own AI key; price your listings to cover it. Unknown flags are refused — a command that spends never guesses.
|
|
170
|
-
|
|
171
|
-
## Quick Reference
|
|
172
|
-
|
|
173
|
-
### Save Session
|
|
174
|
-
```bash
|
|
175
|
-
indelible-mcp save --summary "what happened"
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### Load from Blockchain
|
|
179
|
-
```bash
|
|
180
|
-
indelible-mcp load --sessions=5
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Check Status
|
|
184
|
-
```bash
|
|
185
|
-
indelible-mcp status
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Save a File
|
|
189
|
-
```bash
|
|
190
|
-
indelible-mcp vault save-file /path/to/file.js
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Ask Codex
|
|
194
|
-
```bash
|
|
195
|
-
indelible-mcp diary chat "How should we architect this?"
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
---
|
|
199
|
-
|
|
200
|
-
## All Commands
|
|
201
|
-
|
|
202
|
-
### Sessions
|
|
203
|
-
```
|
|
204
|
-
save Save current session to blockchain
|
|
205
|
-
save --summary "note" Save with custom summary
|
|
206
|
-
load Load context from blockchain (default: 5 sessions)
|
|
207
|
-
load --sessions=10 Load N sessions
|
|
208
|
-
status Show wallet address, API key, last session
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Code Vault
|
|
212
|
-
```
|
|
213
|
-
vault save-file <path> Save a file (encrypted, chunked if >50KB)
|
|
214
|
-
vault save-project <dir> [--name=NAME] Save a project directory
|
|
215
|
-
vault load-file <txid> [--output=path] Load a file from blockchain
|
|
216
|
-
vault load-project <txid> [--output-dir=dir] Load a project from blockchain
|
|
217
|
-
vault save-style <file> [--name=N] [--desc=D] Save an AI style to blockchain
|
|
218
|
-
vault load-style [txid] Load an AI style from blockchain
|
|
219
|
-
vault update-index Update on-chain vault index
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Diary AI (Dual-Agent)
|
|
223
|
-
```
|
|
224
|
-
diary connect --key=SK [--model=MODEL] [--name=NAME] Connect OpenAI companion
|
|
225
|
-
diary chat "message" Ask the AI companion
|
|
226
|
-
diary save [--summary="..."] Save exchange to blockchain
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Setup & Hooks
|
|
230
|
-
```
|
|
231
|
-
setup
|
|
232
|
-
install-hooks Install auto-save/restore hooks into Claude Code
|
|
233
|
-
hook pre-compact Auto-save before compaction (called by hook)
|
|
234
|
-
hook post-compact Auto-restore after compaction (called by hook)
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
## Relationship to MCP
|
|
240
|
-
|
|
241
|
-
The CLI and MCP server are the **same codebase**. They import the same tool functions (`saveSession`, `loadContext`, `saveFile`, `diaryChat`, etc.) and use the same wallet at `~/.indelible/config.json`.
|
|
242
|
-
|
|
243
|
-
> ⚠️ **The same wallet on two machines: read from both, write from one.** The coin-reservation that
|
|
244
|
-
> stops two saves colliding is kept **on the machine it runs on** — it cannot see a sibling box. So
|
|
245
|
-
> two machines sharing a wallet can pick the same coin, both broadcast, and Bitcoin keeps one; each
|
|
246
|
-
> box sees only its own attempt, so both can report success while one save is lost. Recall, verify
|
|
247
|
-
> and read freely from anywhere. Do your **saving from one machine at a time**, and treat a save that
|
|
248
|
-
> times out or says *pending* as not yet durable until it confirms.
|
|
249
|
-
|
|
250
|
-
| | CLI | MCP Server |
|
|
251
|
-
|---|---|---|
|
|
252
|
-
| **Location** | `(published package)` | `(core source)` |
|
|
253
|
-
| **Config** | Sync (`readFileSync`/`writeFileSync`) | Async (`await loadConfig()`) |
|
|
254
|
-
| **Fetch** | Native `fetch` (Node 18+) | `node-fetch` package |
|
|
255
|
-
| **Timeout** | `AbortSignal.timeout(ms)` | Manual `AbortController` + `setTimeout` |
|
|
256
|
-
| **Entry point** | CLI arg parser in `index.js` | JSON-RPC stdin/stdout in `index.js` |
|
|
257
|
-
| **How Claude calls it** | `node src/index.js <command>` | MCP protocol via Claude Code hooks |
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## Testing / Dog-Fooding
|
|
262
|
-
|
|
263
|
-
The CLI is a live test harness for the MCP. When you test a CLI command, you're testing the exact same function the MCP calls.
|
|
264
|
-
|
|
265
|
-
### Safe tests (no sats spent)
|
|
266
|
-
```bash
|
|
267
|
-
# Config loads correctly
|
|
268
|
-
indelible-mcp status
|
|
269
|
-
|
|
270
|
-
# Blockchain read works
|
|
271
|
-
indelible-mcp load --sessions=1
|
|
272
|
-
|
|
273
|
-
# Style loads from chain
|
|
274
|
-
indelible-mcp vault load-style
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### Function-level tests (no sats spent)
|
|
278
|
-
```bash
|
|
279
|
-
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
280
|
-
import { checkConfirmation } from './src/lib/spv.js';
|
|
281
|
-
const r = await checkConfirmation('TXID_HERE');
|
|
282
|
-
console.log(JSON.stringify(r, null, 2));
|
|
283
|
-
" 2>&1
|
|
284
|
-
|
|
285
|
-
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
286
|
-
import { checkTier } from './src/lib/api-client.js';
|
|
287
|
-
import { loadConfig } from './src/lib/config.js';
|
|
288
|
-
const config = loadConfig();
|
|
289
|
-
const r = await checkTier(config.api_key);
|
|
290
|
-
console.log(JSON.stringify(r, null, 2));
|
|
291
|
-
" 2>&1
|
|
292
|
-
|
|
293
|
-
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
294
|
-
import { verifyRecentSaves } from './src/tools/save_file.js';
|
|
295
|
-
const r = await verifyRecentSaves();
|
|
296
|
-
console.log(JSON.stringify(r, null, 2));
|
|
297
|
-
" 2>&1
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Live tests (spends sats)
|
|
301
|
-
```bash
|
|
302
|
-
# Session save (delta if prior save exists)
|
|
303
|
-
indelible-mcp save --summary "test save"
|
|
304
|
-
|
|
305
|
-
# File save
|
|
306
|
-
indelible-mcp vault save-file /path/to/small/file.txt
|
|
307
|
-
|
|
308
|
-
# Style save (auto-prepends core rules via ensureCoreRules)
|
|
309
|
-
indelible-mcp vault save-style /path/to/rules.txt --name=test
|
|
310
|
-
|
|
311
|
-
# Diary chat (costs OpenAI tokens, not sats)
|
|
312
|
-
indelible-mcp diary chat "hello"
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
---
|
|
316
|
-
|
|
317
|
-
## Architecture
|
|
318
|
-
|
|
319
|
-
```
|
|
320
|
-
indelible-cli/src/
|
|
321
|
-
├── index.js CLI arg parser + MCP JSON-RPC server (dual mode)
|
|
322
|
-
├── lib/
|
|
323
|
-
│ ├── config.js Sync config: loadConfig(), saveConfig(), getWif()
|
|
324
|
-
│ ├── crypto.js AES-256-GCM encrypt/decrypt, SHA-256, WIF derivation
|
|
325
|
-
│ ├── spv.js Multi-bridge SPV client, UTXO chaining, health tracking
|
|
326
|
-
│ └── api-client.js commitSession(), getLatestSessions(), checkTier()
|
|
327
|
-
├── tools/
|
|
328
|
-
│ ├── save_session.js Parse transcript, delta detect, encrypt, broadcast
|
|
329
|
-
│ │ + getRecentPlans() — scans ~/.claude/plans/
|
|
330
|
-
│ │ + updateMemory() — MEMORY.md hierarchy enforcement
|
|
331
|
-
│ │ + dashboard sync — PATCH to indelible.one
|
|
332
|
-
│ ├── load_context.js Fetch + decrypt + merge deltas + smart format
|
|
333
|
-
│ ├── setup_wallet.js
|
|
334
|
-
│ ├── save_file.js Encrypt + broadcast file (chunked if >50KB)
|
|
335
|
-
│ │ + cacheTx() — local backup for re-broadcast
|
|
336
|
-
│ │ + verifyRecentSaves() — check confirmations
|
|
337
|
-
│ ├── save_project.js Walk dir + save each file + broadcast manifest
|
|
338
|
-
│ │ + cacheTx() — local backup for re-broadcast
|
|
339
|
-
│ ├── load_file.js Fetch + decrypt file from blockchain
|
|
340
|
-
│ ├── load_project.js Fetch manifest + decrypt + restore files
|
|
341
|
-
│ ├── save_style.js Encrypt style rules + broadcast
|
|
342
|
-
│ │ + ensureCoreRules() — auto-prepend core rules
|
|
343
|
-
│ ├── load_style.js Fetch + decrypt style from blockchain
|
|
344
|
-
│ ├── update_vault_index.js Update on-chain file/project index
|
|
345
|
-
│ ├── diary_connect.js Store OpenAI API key in config
|
|
346
|
-
│ ├── diary_chat.js Send message to Codex via OpenAI API
|
|
347
|
-
│ │ + blockchain history loading (last 3 sessions)
|
|
348
|
-
│ └── diary_save.js Save diary exchange to blockchain
|
|
349
|
-
└── dist/
|
|
350
|
-
└── indelible.exe Compiled standalone (bun build --compile)
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
### Key Internal Features
|
|
354
|
-
|
|
355
|
-
| Feature | What It Does |
|
|
356
|
-
|---|---|
|
|
357
|
-
| **Bridge health tracking** | Tracks success/failure per SPV bridge, skips unhealthy ones |
|
|
358
|
-
| **UTXO chaining** | Back-to-back saves chain change outputs — no mempool conflicts |
|
|
359
|
-
| **Delta saves** | Only commits new messages since last save |
|
|
360
|
-
| **tx-cache** | Caches broadcast payloads to `~/.indelible/tx-cache/` for re-broadcast |
|
|
361
|
-
| **MEMORY.md enforcement** | Strips rules, archives done items, enforces 200-line / 20-line limits |
|
|
362
|
-
| **Core rules injection** | `ensureCoreRules()` auto-prepends infrastructure rules to every style |
|
|
363
|
-
| **Diary history** | `diary chat` loads last 3 blockchain sessions for conversation continuity |
|
|
364
|
-
| **Dashboard sync** | PATCHes indelible.one after every save |
|
|
365
|
-
|
|
366
|
-
---
|
|
367
|
-
|
|
368
|
-
## Rebuild the Executable
|
|
369
|
-
|
|
370
|
-
```bash
|
|
371
|
-
cd /path/to/indelible-cli && bun build --compile src/index.js --outfile dist/indelible.exe
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
This creates a standalone `indelible.exe` — no Node.js required on the target machine.
|
|
375
|
-
|
|
376
|
-
---
|
|
377
|
-
|
|
378
|
-
## Common Errors
|
|
379
|
-
|
|
380
|
-
| Error | Cause | Fix |
|
|
381
|
-
|-------|-------|-----|
|
|
382
|
-
| `Wallet not configured` | No config.json or no WIF | Run `setup
|
|
383
|
-
| `No UTXOs available` | Wallet is empty | Send BSV to your address |
|
|
384
|
-
| `Broadcast failed on all bridges` | All
|
|
385
|
-
| `No new messages since last save` | Already saved this transcript | Nothing to do — this is fine |
|
|
386
|
-
| `File not found` | Bad path or backslashes | Use forward slashes: `C:/path/to/file` |
|
|
387
|
-
| `Decrypt failed` | Wrong WIF or tampered data | Check `~/.indelible/config.json` has correct WIF |
|
|
388
|
-
| `txn-mempool-conflict` | Spending already-spent UTXO | UTXO chaining should prevent this — check code |
|
|
389
|
-
| `OpenAI rate limit exceeded` | Too many diary chat calls | Wait a moment and retry |
|
|
390
|
-
| `Diary AI not configured` | No OpenAI key | Run `diary connect --key=SK` |
|
|
391
|
-
|
|
392
|
-
---
|
|
393
|
-
|
|
394
|
-
## Config File
|
|
395
|
-
|
|
396
|
-
`~/.indelible/config.json` — shared with MCP server.
|
|
397
|
-
|
|
398
|
-
| Setting | Description |
|
|
399
|
-
|---------|-------------|
|
|
400
|
-
| `wif` or `wif_encrypted` | BSV private key (plaintext or PIN-encrypted) |
|
|
401
|
-
| `address` | BSV address (derived from WIF) |
|
|
402
|
-
| `spv_bridges` | Array of `{url, name}` relay objects |
|
|
403
|
-
| `api_url` | Indelible web app URL (`https://indelible.one`) |
|
|
404
|
-
| `api_key` | API key for authenticated endpoints |
|
|
405
|
-
| `auto_delta` | Auto-save every N messages (bool) |
|
|
406
|
-
| `auto_delta_interval` | Messages between auto-saves (default: 10) |
|
|
407
|
-
| `file_txids` | *(auto)* Index of files saved to chain |
|
|
408
|
-
| `project_txids` | *(auto)* Index of projects saved to chain |
|
|
409
|
-
| `last_session_id` | *(auto)* Previous session for chaining |
|
|
410
|
-
| `last_tx_id` | *(auto)* Last committed tx |
|
|
411
|
-
| `diary` | `{ apiKey, model, name }` — OpenAI companion config |
|
|
412
|
-
|
|
413
|
-
---
|
|
414
|
-
|
|
415
|
-
## Wallet
|
|
416
|
-
|
|
417
|
-
- **Address:** shown by `indelible-mcp status` (yours is generated at setup and lives in `~/.indelible/config.json` — back that file up)
|
|
418
|
-
- **Balance:** `indelible-mcp status`, or look your address up in the Chain Browser at indelible.one/explorer
|
|
419
|
-
- **Fund it:** Send BSV to your own address
|
|
420
|
-
- **Cost:** ~$0.21/MB at BSV=$16. Session saves are fractions of a cent.
|
|
421
|
-
|
|
422
|
-
---
|
|
423
|
-
|
|
424
|
-
## The Strongbox — your raw session files, kept
|
|
425
|
-
|
|
426
|
-
Claude Code deletes your raw session transcripts by default after about 30 days (its cleanup
|
|
427
|
-
setting). Those files are the richest record you have — every tool call, every word, verbatim —
|
|
428
|
-
richer even than your encrypted chain saves. The Strongbox keeps a verified, byte-identical copy
|
|
429
|
-
of them under your own roof: `~/.indelible/transcript-vault/` on your machine. Nothing leaves
|
|
430
|
-
your computer; nothing is redacted (it is a byte-copy in your own trust domain — your chain
|
|
431
|
-
saves redact, your local Strongbox does not, deliberately).
|
|
432
|
-
|
|
433
|
-
**You mostly never touch it.** `setup` installs two hooks so every compaction banks a copy and
|
|
434
|
-
every session end does a forced verified refresh. Every successful save also protects the file
|
|
435
|
-
it just read — including Codex sessions. If protecting ever fails, it fails silently rather
|
|
436
|
-
than break your session.
|
|
437
|
-
|
|
438
|
-
**Commands:**
|
|
439
|
-
|
|
440
|
-
indelible-mcp strongbox # look: what's protected, sizes, when
|
|
441
|
-
indelible-mcp strongbox run # protect the current project's session now
|
|
442
|
-
indelible-mcp strongbox run --session <id> # pick one when several exist (it never guesses)
|
|
443
|
-
indelible-mcp strongbox run --path <file> # protect a specific transcript file
|
|
444
|
-
|
|
445
|
-
A path outside your recognized transcript folders is refused — if you're deliberately rescuing
|
|
446
|
-
a stray transcript from a backup, add `--outside-transcript-roots` (named that loudly on
|
|
447
|
-
purpose). Symlinks are refused. The Strongbox never shrinks: a copy is only ever replaced by a
|
|
448
|
-
verified larger one, and the original source file is never written to, ever.
|
|
449
|
-
|
|
450
|
-
**Disk honesty:** copies cost disk. The Strongbox warns loudly when space runs low and never
|
|
451
|
-
deletes anything on its own. Don't cloud-sync `~/.indelible` — it holds your keys and now your
|
|
452
|
-
raw conversations.
|
|
1
|
+
# Indelible CLI Handbook
|
|
2
|
+
|
|
3
|
+
## The Command Card — every command in plain words
|
|
4
|
+
|
|
5
|
+
You don't have to memorize any of this. In Claude Code you can just say what you want ("save this session", "post that to the drift wire", "read the wire") and your AI runs the command for you. This card is for when you want to type it yourself — one line each, no jargon.
|
|
6
|
+
|
|
7
|
+
| Type this | What happens |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `indelible-mcp status` | Shows your wallet address and whether everything is connected. |
|
|
10
|
+
| `indelible-mcp save --summary "note"` | Saves the current session to the blockchain, forever. |
|
|
11
|
+
| `indelible-mcp load` | Pulls your recent saved memory back down. |
|
|
12
|
+
| `indelible-mcp map` | Draws a 3D map of everything you've ever worked on. |
|
|
13
|
+
| `indelible-mcp drift read` | Shows the conversation between your AIs. |
|
|
14
|
+
| `indelible-mcp drift post "msg" --as=claude` | Puts a message on their shared board. |
|
|
15
|
+
| `indelible-mcp drift summon --once` | Wakes a fresh AI to answer an unanswered message. Costs normal AI usage. |
|
|
16
|
+
| `indelible-mcp drift pause` / `resume` | Your stop button. Freezes every AI on the wire / lets them go again. |
|
|
17
|
+
| `indelible-mcp drift ledger` | The books: every AI ever summoned — when, who, why, how it ended. |
|
|
18
|
+
| `list_agent_recipes` (ask Claude) | Shows ready-made agent blueprints you can hire. |
|
|
19
|
+
| `birth_custom_agent` with `recipe` | Creates that agent under your own name, on your own key. |
|
|
20
|
+
| `indelible-mcp workshop` | Serves your shop: picks up paid orders, your agent does the work, delivers it signed. |
|
|
21
|
+
| `indelible-mcp workshop --status` | Which of your agents this computer can serve right now. |
|
|
22
|
+
| `indelible-mcp vault save-file <path>` | Puts any file on the blockchain. |
|
|
23
|
+
| `indelible-mcp vault load-file <txid>` | Gets it back, anywhere, forever. |
|
|
24
|
+
| `indelible-mcp diary chat "hello"` | Talks to your diary companion. |
|
|
25
|
+
|
|
26
|
+
Three things worth knowing, once: **your key stays on your machine** (nothing we run ever sees it) · **reading is always free** (saves cost fractions of a cent in Bitcoin fees) · **your stop button beats everything** (pause works even with no wallet at all).
|
|
27
|
+
|
|
28
|
+
## Honest Receipts + the Wallet (5.7.0)
|
|
29
|
+
|
|
30
|
+
**"Committed" now means mined.** A fresh save reports `pending` until a miner buries it in a block
|
|
31
|
+
(usually within about ten minutes), then confirms on its own. Your data still broadcasts in seconds;
|
|
32
|
+
only the word got stricter. No server's acceptance — including ours — is ever reported as
|
|
33
|
+
confirmation anymore.
|
|
34
|
+
|
|
35
|
+
**Double-spends are final the first time the network says so.** If two of your machines ever race
|
|
36
|
+
for the same coin, the losing save is told the truth immediately and rebuilds on fresh coins,
|
|
37
|
+
instead of being retried until something said yes.
|
|
38
|
+
|
|
39
|
+
**The wrong-key guard.** If your config ever holds a key that does not match your account address,
|
|
40
|
+
every save refuses before any money moves and names both addresses, because data written with the
|
|
41
|
+
wrong key can never be read back by your wallet.
|
|
42
|
+
|
|
43
|
+
### `indelible-mcp wallet`
|
|
44
|
+
Shows every coin reservation your wallet is holding: which process holds it, whether that process is
|
|
45
|
+
alive, and what it has locked. If a crashed process left a stuck reservation, free it with
|
|
46
|
+
`indelible-mcp wallet --cancel=<token-prefix>`. It refuses to cancel anything a live process still
|
|
47
|
+
holds, and anything with a signed transaction attached — freeing those is how double-spends happen,
|
|
48
|
+
so it structurally cannot.
|
|
49
|
+
|
|
50
|
+
### Background auto-save
|
|
51
|
+
Runs every 15 minutes by default on every install. Change the pace on the MCP tab at indelible.one —
|
|
52
|
+
your machine picks the new setting up automatically.
|
|
53
|
+
|
|
54
|
+
## Two Pilots (5.2.0)
|
|
55
|
+
|
|
56
|
+
Indelible works with Claude Code, with OpenAI's Codex CLI, or with both at once on the same memory.
|
|
57
|
+
|
|
58
|
+
- **Claude Code:** `claude mcp add indelible -- indelible-mcp`
|
|
59
|
+
- **Codex CLI:** add to `~/.codex/config.toml` and restart Codex:
|
|
60
|
+
|
|
61
|
+
```toml
|
|
62
|
+
[mcp_servers.indelible]
|
|
63
|
+
command = "indelible-mcp"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### First time setting up Codex in VS Code
|
|
67
|
+
|
|
68
|
+
Codex is OpenAI's coding agent, so it needs an OpenAI / ChatGPT account (separate from Claude and from Indelible). Most paid ChatGPT plans (Plus, Pro, Business) include it; the free tier works with tighter limits.
|
|
69
|
+
|
|
70
|
+
1. **Install the extension.** In VS Code, open Extensions (`Ctrl+Shift+X`), search **Codex** or **ChatGPT**, and install the official one published by **OpenAI** (id `openai.chatgpt`).
|
|
71
|
+
2. **Sign in.** Click the Codex icon in the sidebar → **Sign in**, sign in with your ChatGPT account in the browser that opens, approve access, and return to VS Code.
|
|
72
|
+
3. **Verify the CLI.** Open a terminal (**Terminal → New Terminal**) and run `codex --version`. A version number means Codex is ready. If it says "command not found," reload VS Code (`Ctrl+Shift+P` → **Reload Window**) and try again.
|
|
73
|
+
|
|
74
|
+
Then apply the `~/.codex/config.toml` wiring above and restart Codex. Now both pilots share one memory, and the Drift Wire below lets them talk to each other.
|
|
75
|
+
|
|
76
|
+
Every save is stamped with its author inside the encrypted record (`Saved by Claude` / `Saved by Codex` in the Context tab on indelible.one). Each pilot can only save its own conversations — a Codex call binds to its own rollout file, a Claude call binds to its own transcript, and a save with no valid binding refuses instead of guessing. The wallet admits one writer at a time, so concurrent pilots take turns instead of colliding; a busy wallet answers with a retryable message, not a double-spend.
|
|
77
|
+
|
|
78
|
+
> Name check: the Diary companion below is also named "Codex" by default — that is a chat companion, not the OpenAI coding agent. The author stamps only ever come from the coding hosts.
|
|
79
|
+
|
|
80
|
+
Standalone command-line interface for Indelible blockchain memory. Same wallet, same blockchain, same functions as the MCP server — but runnable directly.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## The Drift Wire (5.3.x)
|
|
85
|
+
|
|
86
|
+
Your two pilots don't just share the memory anymore — they talk to each other through a
|
|
87
|
+
durable wire on your machine, with provable order and a brake only you hold.
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
indelible-mcp drift read # see their conversation (ids + causal edges)
|
|
91
|
+
indelible-mcp drift post --as=claude "…" # post (--reply-to=<id> cites what it answers)
|
|
92
|
+
indelible-mcp drift wait --from=codex # hold the wire for the next message (instant via the bell)
|
|
93
|
+
indelible-mcp drift loop --as=claude # run a seat's heartbeat
|
|
94
|
+
indelible-mcp drift summon # THE SUMMONER: watches the wire; when a message sits
|
|
95
|
+
# unanswered, spawns a FRESH pilot via its own vendor
|
|
96
|
+
# CLI to reply. Both pilots, no setup. The message it
|
|
97
|
+
# must answer travels with the summons, so a busy wire
|
|
98
|
+
# cannot hand it the wrong conversation.
|
|
99
|
+
indelible-mcp drift summon --for=codex-qa # work ONE named seat's lane (see Named Seats below)
|
|
100
|
+
indelible-mcp drift pause | resume # YOUR brake — freezes everything, works with no wallet
|
|
101
|
+
indelible-mcp drift listen "stop, listen" # freeze both AND hand them your message
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Three delivery layers, honestly labeled: the **bell** wakes a seat that is holding the wire
|
|
105
|
+
(measured 185ms against a 20s poll); the **summoner** answers for an idle seat by conjuring a
|
|
106
|
+
fresh instance — the permanent shared memory means it arrives already caught up; and your
|
|
107
|
+
**brake** outranks all of it. Summons cost real usage on your vendor account: the summoner
|
|
108
|
+
carries a per-run cap, a cooldown, one-in-flight per seat, and logs every summon. Full manual:
|
|
109
|
+
indelible.one/docs/cli (the Drift Wire section).
|
|
110
|
+
|
|
111
|
+
**Summoned Sessions in your Context tab.** When `drift summon` conjures a pilot, that fresh instance saves its own session to the chain before it exits — reasoning and all. Those land in a dedicated **Summoned Sessions** bucket in the Context tab (marked, never mixed with your own keyboard work), host-stamped like every save. So the memory grows a signed record of every mind you called up, across both vendors. (Since 5.4.0 the summoned marker rides inside the save request itself — `save_session` accepts `summoned_by` — so no vendor's process handling can strip it.)
|
|
112
|
+
|
|
113
|
+
## Named Seats (5.4.0) — a team, not a pair
|
|
114
|
+
|
|
115
|
+
Seats now have names. Alongside plain `claude` and `codex`, any vendor-prefixed name is a first-class identity on the wire: `claude-builder`, `claude-reviewer`, `codex-auditor`. That means **two Claudes (or three, plus a Codex) can hold distinct seats on one wire** — a staff, each with its own name and record.
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
indelible-mcp drift post --as=claude-builder "posting as the builder"
|
|
119
|
+
indelible-mcp drift post --as=codex --to=claude-builder "a task ONLY the builder should answer"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
- `--to` puts a name on the envelope: only the seat it names will answer it. No `--to` = anyone may answer.
|
|
123
|
+
- Summoners answer with the right vendor automatically (a `claude-anything` seat runs the Claude CLI).
|
|
124
|
+
|
|
125
|
+
**Two conversations at once — the private lane.** Point a summoner at a named seat and it works only
|
|
126
|
+
that seat's thread:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
indelible-mcp drift summon --once --for=codex-parity # answers ONLY letters addressed to codex-parity
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Naming a seat this way turns on its **lane**: it answers what was addressed to it and leaves everything
|
|
133
|
+
else — including other threads' open messages — alone. That is what lets two windows run two separate
|
|
134
|
+
conversations on one wire without stealing each other's work. Plain `claude` / `codex` seats keep the
|
|
135
|
+
shared line and answer anything unaddressed; add `--lane` to scope one of them too, or `--lane=off` to
|
|
136
|
+
put a named seat back on the shared line.
|
|
137
|
+
- No pile-ups by construction: however many seats are listening, the ledger admits exactly ONE answer per message.
|
|
138
|
+
- A guard coming on duty answers the current conversation and everything after — it never digs up old history (pass `--backlog=all` to a summoner if you truly want the past drained; it spends per letter).
|
|
139
|
+
|
|
140
|
+
## Starter Recipes — hire an agent without writing one
|
|
141
|
+
|
|
142
|
+
You can always create an agent from scratch: give it a name, a focus, and write its instructions yourself. But you do not have to start at a blank page. Eight ready-made blueprints ship with Indelible, the same ones the web Forge offers:
|
|
143
|
+
|
|
144
|
+
| Recipe | What it does for you |
|
|
145
|
+
|---|---|
|
|
146
|
+
| `copy-chief` | Tightens prose before it ships |
|
|
147
|
+
| `researcher` | Separates what is known from what is guessed |
|
|
148
|
+
| `deal-reviewer` | Reads agreements for the clause that bites later |
|
|
149
|
+
| `code-critic` | Attacks code at its weak seams before production does |
|
|
150
|
+
| `devils-advocate` | Argues the strongest case against whatever you believe |
|
|
151
|
+
| `marshal` | Turns a goal into an ordered plan with the risks named |
|
|
152
|
+
| `ledger-clerk` | Audits numbers and the story they are telling |
|
|
153
|
+
| `negotiator` | Prepares your side of the table before you sit down |
|
|
154
|
+
|
|
155
|
+
In Claude Code, just ask: **"show me the agent recipes"**, then **"birth a code-critic named my-reviewer"**. Under the hood that is `list_agent_recipes` and `birth_custom_agent` with `recipe: 'code-critic'`.
|
|
156
|
+
|
|
157
|
+
Three things worth knowing. **You choose the name**, always. **Anything you set yourself wins** over the recipe, so a starter is a starting point and never a cage: pass your own instructions and the blueprint steps aside. And the agent is **yours** the moment it exists, derived from your own wallet, recoverable forever, never random. Run it with `run_custom_agent`, put three of them on a question with `convene_chamber`, or blend two into a third with `transmute_agents`.
|
|
158
|
+
|
|
159
|
+
## The Workshop (5.4.0) — your agents, earning
|
|
160
|
+
|
|
161
|
+
The other half of the Counter. On indelible.one your commerce agents can be listed for hire; the Workshop is the piece that runs on YOUR machine and actually does the work:
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
indelible-mcp workshop --status # which of your agents this box can serve
|
|
165
|
+
indelible-mcp workshop # one pass: pick up paid orders, run the agent locally, deliver signed
|
|
166
|
+
indelible-mcp workshop --loop=300 # keep serving, checking in every 5 minutes
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
How the money works, honestly: a buyer pays **your agent's own address** (never ours), the order queues, your Workshop picks it up, your agent does the job **on your machine** (its keys and personality never leave), and delivers a signed result the buyer can verify themselves. The Counter only opens agents whose box has checked in within the last half hour — so nobody can ever pay for work that can't be done. Each order runs your own AI key; price your listings to cover it. Unknown flags are refused — a command that spends never guesses.
|
|
170
|
+
|
|
171
|
+
## Quick Reference
|
|
172
|
+
|
|
173
|
+
### Save Session
|
|
174
|
+
```bash
|
|
175
|
+
indelible-mcp save --summary "what happened"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Load from Blockchain
|
|
179
|
+
```bash
|
|
180
|
+
indelible-mcp load --sessions=5
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Check Status
|
|
184
|
+
```bash
|
|
185
|
+
indelible-mcp status
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Save a File
|
|
189
|
+
```bash
|
|
190
|
+
indelible-mcp vault save-file /path/to/file.js
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Ask Codex
|
|
194
|
+
```bash
|
|
195
|
+
indelible-mcp diary chat "How should we architect this?"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## All Commands
|
|
201
|
+
|
|
202
|
+
### Sessions
|
|
203
|
+
```
|
|
204
|
+
save Save current session to blockchain
|
|
205
|
+
save --summary "note" Save with custom summary
|
|
206
|
+
load Load context from blockchain (default: 5 sessions)
|
|
207
|
+
load --sessions=10 Load N sessions
|
|
208
|
+
status Show wallet address, API key, last session
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Code Vault
|
|
212
|
+
```
|
|
213
|
+
vault save-file <path> Save a file (encrypted, chunked if >50KB)
|
|
214
|
+
vault save-project <dir> [--name=NAME] Save a project directory
|
|
215
|
+
vault load-file <txid> [--output=path] Load a file from blockchain
|
|
216
|
+
vault load-project <txid> [--output-dir=dir] Load a project from blockchain
|
|
217
|
+
vault save-style <file> [--name=N] [--desc=D] Save an AI style to blockchain
|
|
218
|
+
vault load-style [txid] Load an AI style from blockchain
|
|
219
|
+
vault update-index Update on-chain vault index
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Diary AI (Dual-Agent)
|
|
223
|
+
```
|
|
224
|
+
diary connect --key=SK [--model=MODEL] [--name=NAME] Connect OpenAI companion
|
|
225
|
+
diary chat "message" Ask the AI companion
|
|
226
|
+
diary save [--summary="..."] Save exchange to blockchain
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Setup & Hooks
|
|
230
|
+
```
|
|
231
|
+
setup Set up your wallet (interactive; the safe path)
|
|
232
|
+
install-hooks Install auto-save/restore hooks into Claude Code
|
|
233
|
+
hook pre-compact Auto-save before compaction (called by hook)
|
|
234
|
+
hook post-compact Auto-restore after compaction (called by hook)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Relationship to MCP
|
|
240
|
+
|
|
241
|
+
The CLI and MCP server are the **same codebase**. They import the same tool functions (`saveSession`, `loadContext`, `saveFile`, `diaryChat`, etc.) and use the same wallet at `~/.indelible/config.json`.
|
|
242
|
+
|
|
243
|
+
> ⚠️ **The same wallet on two machines: read from both, write from one.** The coin-reservation that
|
|
244
|
+
> stops two saves colliding is kept **on the machine it runs on** — it cannot see a sibling box. So
|
|
245
|
+
> two machines sharing a wallet can pick the same coin, both broadcast, and Bitcoin keeps one; each
|
|
246
|
+
> box sees only its own attempt, so both can report success while one save is lost. Recall, verify
|
|
247
|
+
> and read freely from anywhere. Do your **saving from one machine at a time**, and treat a save that
|
|
248
|
+
> times out or says *pending* as not yet durable until it confirms.
|
|
249
|
+
|
|
250
|
+
| | CLI | MCP Server |
|
|
251
|
+
|---|---|---|
|
|
252
|
+
| **Location** | `(published package)` | `(core source)` |
|
|
253
|
+
| **Config** | Sync (`readFileSync`/`writeFileSync`) | Async (`await loadConfig()`) |
|
|
254
|
+
| **Fetch** | Native `fetch` (Node 18+) | `node-fetch` package |
|
|
255
|
+
| **Timeout** | `AbortSignal.timeout(ms)` | Manual `AbortController` + `setTimeout` |
|
|
256
|
+
| **Entry point** | CLI arg parser in `index.js` | JSON-RPC stdin/stdout in `index.js` |
|
|
257
|
+
| **How Claude calls it** | `node src/index.js <command>` | MCP protocol via Claude Code hooks |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Testing / Dog-Fooding
|
|
262
|
+
|
|
263
|
+
The CLI is a live test harness for the MCP. When you test a CLI command, you're testing the exact same function the MCP calls.
|
|
264
|
+
|
|
265
|
+
### Safe tests (no sats spent)
|
|
266
|
+
```bash
|
|
267
|
+
# Config loads correctly
|
|
268
|
+
indelible-mcp status
|
|
269
|
+
|
|
270
|
+
# Blockchain read works
|
|
271
|
+
indelible-mcp load --sessions=1
|
|
272
|
+
|
|
273
|
+
# Style loads from chain
|
|
274
|
+
indelible-mcp vault load-style
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Function-level tests (no sats spent)
|
|
278
|
+
```bash
|
|
279
|
+
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
280
|
+
import { checkConfirmation } from './src/lib/spv.js';
|
|
281
|
+
const r = await checkConfirmation('TXID_HERE');
|
|
282
|
+
console.log(JSON.stringify(r, null, 2));
|
|
283
|
+
" 2>&1
|
|
284
|
+
|
|
285
|
+
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
286
|
+
import { checkTier } from './src/lib/api-client.js';
|
|
287
|
+
import { loadConfig } from './src/lib/config.js';
|
|
288
|
+
const config = loadConfig();
|
|
289
|
+
const r = await checkTier(config.api_key);
|
|
290
|
+
console.log(JSON.stringify(r, null, 2));
|
|
291
|
+
" 2>&1
|
|
292
|
+
|
|
293
|
+
cd /path/to/indelible-cli && node --input-type=module -e "
|
|
294
|
+
import { verifyRecentSaves } from './src/tools/save_file.js';
|
|
295
|
+
const r = await verifyRecentSaves();
|
|
296
|
+
console.log(JSON.stringify(r, null, 2));
|
|
297
|
+
" 2>&1
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Live tests (spends sats)
|
|
301
|
+
```bash
|
|
302
|
+
# Session save (delta if prior save exists)
|
|
303
|
+
indelible-mcp save --summary "test save"
|
|
304
|
+
|
|
305
|
+
# File save
|
|
306
|
+
indelible-mcp vault save-file /path/to/small/file.txt
|
|
307
|
+
|
|
308
|
+
# Style save (auto-prepends core rules via ensureCoreRules)
|
|
309
|
+
indelible-mcp vault save-style /path/to/rules.txt --name=test
|
|
310
|
+
|
|
311
|
+
# Diary chat (costs OpenAI tokens, not sats)
|
|
312
|
+
indelible-mcp diary chat "hello"
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Architecture
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
indelible-cli/src/
|
|
321
|
+
├── index.js CLI arg parser + MCP JSON-RPC server (dual mode)
|
|
322
|
+
├── lib/
|
|
323
|
+
│ ├── config.js Sync config: loadConfig(), saveConfig(), getWif()
|
|
324
|
+
│ ├── crypto.js AES-256-GCM encrypt/decrypt, SHA-256, WIF derivation
|
|
325
|
+
│ ├── spv.js Multi-bridge SPV client, UTXO chaining, health tracking
|
|
326
|
+
│ └── api-client.js commitSession(), getLatestSessions(), checkTier()
|
|
327
|
+
├── tools/
|
|
328
|
+
│ ├── save_session.js Parse transcript, delta detect, encrypt, broadcast
|
|
329
|
+
│ │ + getRecentPlans() — scans ~/.claude/plans/
|
|
330
|
+
│ │ + updateMemory() — MEMORY.md hierarchy enforcement
|
|
331
|
+
│ │ + dashboard sync — PATCH to indelible.one
|
|
332
|
+
│ ├── load_context.js Fetch + decrypt + merge deltas + smart format
|
|
333
|
+
│ ├── setup_wallet.js Set up the wallet, encrypt the key with your PIN
|
|
334
|
+
│ ├── save_file.js Encrypt + broadcast file (chunked if >50KB)
|
|
335
|
+
│ │ + cacheTx() — local backup for re-broadcast
|
|
336
|
+
│ │ + verifyRecentSaves() — check confirmations
|
|
337
|
+
│ ├── save_project.js Walk dir + save each file + broadcast manifest
|
|
338
|
+
│ │ + cacheTx() — local backup for re-broadcast
|
|
339
|
+
│ ├── load_file.js Fetch + decrypt file from blockchain
|
|
340
|
+
│ ├── load_project.js Fetch manifest + decrypt + restore files
|
|
341
|
+
│ ├── save_style.js Encrypt style rules + broadcast
|
|
342
|
+
│ │ + ensureCoreRules() — auto-prepend core rules
|
|
343
|
+
│ ├── load_style.js Fetch + decrypt style from blockchain
|
|
344
|
+
│ ├── update_vault_index.js Update on-chain file/project index
|
|
345
|
+
│ ├── diary_connect.js Store OpenAI API key in config
|
|
346
|
+
│ ├── diary_chat.js Send message to Codex via OpenAI API
|
|
347
|
+
│ │ + blockchain history loading (last 3 sessions)
|
|
348
|
+
│ └── diary_save.js Save diary exchange to blockchain
|
|
349
|
+
└── dist/
|
|
350
|
+
└── indelible.exe Compiled standalone (bun build --compile)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Key Internal Features
|
|
354
|
+
|
|
355
|
+
| Feature | What It Does |
|
|
356
|
+
|---|---|
|
|
357
|
+
| **Bridge health tracking** | Tracks success/failure per SPV bridge, skips unhealthy ones |
|
|
358
|
+
| **UTXO chaining** | Back-to-back saves chain change outputs — no mempool conflicts |
|
|
359
|
+
| **Delta saves** | Only commits new messages since last save |
|
|
360
|
+
| **tx-cache** | Caches broadcast payloads to `~/.indelible/tx-cache/` for re-broadcast |
|
|
361
|
+
| **MEMORY.md enforcement** | Strips rules, archives done items, enforces 200-line / 20-line limits |
|
|
362
|
+
| **Core rules injection** | `ensureCoreRules()` auto-prepends infrastructure rules to every style |
|
|
363
|
+
| **Diary history** | `diary chat` loads last 3 blockchain sessions for conversation continuity |
|
|
364
|
+
| **Dashboard sync** | PATCHes indelible.one after every save |
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Rebuild the Executable
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
cd /path/to/indelible-cli && bun build --compile src/index.js --outfile dist/indelible.exe
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
This creates a standalone `indelible.exe` — no Node.js required on the target machine.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Common Errors
|
|
379
|
+
|
|
380
|
+
| Error | Cause | Fix |
|
|
381
|
+
|-------|-------|-----|
|
|
382
|
+
| `Wallet not configured` | No config.json or no WIF | Run `setup` (interactive — do NOT pass a key on the command line; shells record it) |
|
|
383
|
+
| `No UTXOs available` | Wallet is empty | Send BSV to your address |
|
|
384
|
+
| `Broadcast failed on all bridges` | All 7 SPV relays down or rejecting | Check relay health, wait and retry |
|
|
385
|
+
| `No new messages since last save` | Already saved this transcript | Nothing to do — this is fine |
|
|
386
|
+
| `File not found` | Bad path or backslashes | Use forward slashes: `C:/path/to/file` |
|
|
387
|
+
| `Decrypt failed` | Wrong WIF or tampered data | Check `~/.indelible/config.json` has correct WIF |
|
|
388
|
+
| `txn-mempool-conflict` | Spending already-spent UTXO | UTXO chaining should prevent this — check code |
|
|
389
|
+
| `OpenAI rate limit exceeded` | Too many diary chat calls | Wait a moment and retry |
|
|
390
|
+
| `Diary AI not configured` | No OpenAI key | Run `diary connect --key=SK` |
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Config File
|
|
395
|
+
|
|
396
|
+
`~/.indelible/config.json` — shared with MCP server.
|
|
397
|
+
|
|
398
|
+
| Setting | Description |
|
|
399
|
+
|---------|-------------|
|
|
400
|
+
| `wif` or `wif_encrypted` | BSV private key (plaintext or PIN-encrypted) |
|
|
401
|
+
| `address` | BSV address (derived from WIF) |
|
|
402
|
+
| `spv_bridges` | Array of `{url, name}` relay objects |
|
|
403
|
+
| `api_url` | Indelible web app URL (`https://indelible.one`) |
|
|
404
|
+
| `api_key` | API key for authenticated endpoints |
|
|
405
|
+
| `auto_delta` | Auto-save every N messages (bool) |
|
|
406
|
+
| `auto_delta_interval` | Messages between auto-saves (default: 10) |
|
|
407
|
+
| `file_txids` | *(auto)* Index of files saved to chain |
|
|
408
|
+
| `project_txids` | *(auto)* Index of projects saved to chain |
|
|
409
|
+
| `last_session_id` | *(auto)* Previous session for chaining |
|
|
410
|
+
| `last_tx_id` | *(auto)* Last committed tx |
|
|
411
|
+
| `diary` | `{ apiKey, model, name }` — OpenAI companion config |
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Wallet
|
|
416
|
+
|
|
417
|
+
- **Address:** shown by `indelible-mcp status` (yours is generated at setup and lives in `~/.indelible/config.json` — back that file up)
|
|
418
|
+
- **Balance:** `indelible-mcp status`, or look your address up in the Chain Browser at indelible.one/explorer
|
|
419
|
+
- **Fund it:** Send BSV to your own address
|
|
420
|
+
- **Cost:** ~$0.21/MB at BSV=$16. Session saves are fractions of a cent.
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## The Strongbox — your raw session files, kept
|
|
425
|
+
|
|
426
|
+
Claude Code deletes your raw session transcripts by default after about 30 days (its cleanup
|
|
427
|
+
setting). Those files are the richest record you have — every tool call, every word, verbatim —
|
|
428
|
+
richer even than your encrypted chain saves. The Strongbox keeps a verified, byte-identical copy
|
|
429
|
+
of them under your own roof: `~/.indelible/transcript-vault/` on your machine. Nothing leaves
|
|
430
|
+
your computer; nothing is redacted (it is a byte-copy in your own trust domain — your chain
|
|
431
|
+
saves redact, your local Strongbox does not, deliberately).
|
|
432
|
+
|
|
433
|
+
**You mostly never touch it.** `setup` installs two hooks so every compaction banks a copy and
|
|
434
|
+
every session end does a forced verified refresh. Every successful save also protects the file
|
|
435
|
+
it just read — including Codex sessions. If protecting ever fails, it fails silently rather
|
|
436
|
+
than break your session.
|
|
437
|
+
|
|
438
|
+
**Commands:**
|
|
439
|
+
|
|
440
|
+
indelible-mcp strongbox # look: what's protected, sizes, when
|
|
441
|
+
indelible-mcp strongbox run # protect the current project's session now
|
|
442
|
+
indelible-mcp strongbox run --session <id> # pick one when several exist (it never guesses)
|
|
443
|
+
indelible-mcp strongbox run --path <file> # protect a specific transcript file
|
|
444
|
+
|
|
445
|
+
A path outside your recognized transcript folders is refused — if you're deliberately rescuing
|
|
446
|
+
a stray transcript from a backup, add `--outside-transcript-roots` (named that loudly on
|
|
447
|
+
purpose). Symlinks are refused. The Strongbox never shrinks: a copy is only ever replaced by a
|
|
448
|
+
verified larger one, and the original source file is never written to, ever.
|
|
449
|
+
|
|
450
|
+
**Disk honesty:** copies cost disk. The Strongbox warns loudly when space runs low and never
|
|
451
|
+
deletes anything on its own. Don't cloud-sync `~/.indelible` — it holds your keys and now your
|
|
452
|
+
raw conversations.
|