indelible-mcp 4.9.9 → 5.1.0
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 +251 -0
- package/CUSTOMER_AGENT_HANDBOOK.md +321 -0
- package/README.md +2 -0
- package/package.json +4 -2
- package/src/index.js +1506 -465
package/CLI_HANDBOOK.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Indelible CLI Handbook
|
|
2
|
+
|
|
3
|
+
Standalone command-line interface for Indelible blockchain memory. Same wallet, same blockchain, same functions as the MCP server — but runnable directly.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
### Save Session
|
|
10
|
+
```bash
|
|
11
|
+
node C:/Indelible-main/indelible-cli/src/index.js save --summary "what happened"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### Load from Blockchain
|
|
15
|
+
```bash
|
|
16
|
+
node C:/Indelible-main/indelible-cli/src/index.js load --sessions=5
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Check Status
|
|
20
|
+
```bash
|
|
21
|
+
node C:/Indelible-main/indelible-cli/src/index.js status
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Save a File
|
|
25
|
+
```bash
|
|
26
|
+
node C:/Indelible-main/indelible-cli/src/index.js vault save-file /path/to/file.js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Ask Codex
|
|
30
|
+
```bash
|
|
31
|
+
node C:/Indelible-main/indelible-cli/src/index.js diary chat "How should we architect this?"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## All Commands
|
|
37
|
+
|
|
38
|
+
### Sessions
|
|
39
|
+
```
|
|
40
|
+
save Save current session to blockchain
|
|
41
|
+
save --summary "note" Save with custom summary
|
|
42
|
+
load Load context from blockchain (default: 5 sessions)
|
|
43
|
+
load --sessions=10 Load N sessions
|
|
44
|
+
status Show wallet address, API key, last session
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Code Vault
|
|
48
|
+
```
|
|
49
|
+
vault save-file <path> Save a file (encrypted, chunked if >50KB)
|
|
50
|
+
vault save-project <dir> [--name=NAME] Save a project directory
|
|
51
|
+
vault load-file <txid> [--output=path] Load a file from blockchain
|
|
52
|
+
vault load-project <txid> [--output-dir=dir] Load a project from blockchain
|
|
53
|
+
vault save-style <file> [--name=N] [--desc=D] Save an AI style to blockchain
|
|
54
|
+
vault load-style [txid] Load an AI style from blockchain
|
|
55
|
+
vault update-index Update on-chain vault index
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Diary AI (Dual-Agent)
|
|
59
|
+
```
|
|
60
|
+
diary connect --key=SK [--model=MODEL] [--name=NAME] Connect OpenAI companion
|
|
61
|
+
diary chat "message" Ask the AI companion
|
|
62
|
+
diary save [--summary="..."] Save exchange to blockchain
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Setup & Hooks
|
|
66
|
+
```
|
|
67
|
+
setup --wif=KEY --pin=PIN Import and encrypt your private key
|
|
68
|
+
install-hooks Install auto-save/restore hooks into Claude Code
|
|
69
|
+
hook pre-compact Auto-save before compaction (called by hook)
|
|
70
|
+
hook post-compact Auto-restore after compaction (called by hook)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Relationship to MCP
|
|
76
|
+
|
|
77
|
+
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`.
|
|
78
|
+
|
|
79
|
+
| | CLI | MCP Server |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| **Location** | `C:/Indelible-main/indelible-cli/src/` | `C:/bsv-claude-wrapper/mcp-server/` |
|
|
82
|
+
| **Config** | Sync (`readFileSync`/`writeFileSync`) | Async (`await loadConfig()`) |
|
|
83
|
+
| **Fetch** | Native `fetch` (Node 18+) | `node-fetch` package |
|
|
84
|
+
| **Timeout** | `AbortSignal.timeout(ms)` | Manual `AbortController` + `setTimeout` |
|
|
85
|
+
| **Entry point** | CLI arg parser in `index.js` | JSON-RPC stdin/stdout in `index.js` |
|
|
86
|
+
| **How Claude calls it** | `node src/index.js <command>` | MCP protocol via Claude Code hooks |
|
|
87
|
+
|
|
88
|
+
**Sync rule:** Any feature, fix, or change that goes into one MUST go into both. No exceptions. Adapt sync/async config pattern accordingly.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Testing / Dog-Fooding
|
|
93
|
+
|
|
94
|
+
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.
|
|
95
|
+
|
|
96
|
+
### Safe tests (no sats spent)
|
|
97
|
+
```bash
|
|
98
|
+
# Config loads correctly
|
|
99
|
+
node C:/Indelible-main/indelible-cli/src/index.js status
|
|
100
|
+
|
|
101
|
+
# Blockchain read works
|
|
102
|
+
node C:/Indelible-main/indelible-cli/src/index.js load --sessions=1
|
|
103
|
+
|
|
104
|
+
# Style loads from chain
|
|
105
|
+
node C:/Indelible-main/indelible-cli/src/index.js vault load-style
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Function-level tests (no sats spent)
|
|
109
|
+
```bash
|
|
110
|
+
cd "C:/Indelible-main/indelible-cli" && node --input-type=module -e "
|
|
111
|
+
import { checkConfirmation } from './src/lib/spv.js';
|
|
112
|
+
const r = await checkConfirmation('TXID_HERE');
|
|
113
|
+
console.log(JSON.stringify(r, null, 2));
|
|
114
|
+
" 2>&1
|
|
115
|
+
|
|
116
|
+
cd "C:/Indelible-main/indelible-cli" && node --input-type=module -e "
|
|
117
|
+
import { checkTier } from './src/lib/api-client.js';
|
|
118
|
+
import { loadConfig } from './src/lib/config.js';
|
|
119
|
+
const config = loadConfig();
|
|
120
|
+
const r = await checkTier(config.api_key);
|
|
121
|
+
console.log(JSON.stringify(r, null, 2));
|
|
122
|
+
" 2>&1
|
|
123
|
+
|
|
124
|
+
cd "C:/Indelible-main/indelible-cli" && node --input-type=module -e "
|
|
125
|
+
import { verifyRecentSaves } from './src/tools/save_file.js';
|
|
126
|
+
const r = await verifyRecentSaves();
|
|
127
|
+
console.log(JSON.stringify(r, null, 2));
|
|
128
|
+
" 2>&1
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Live tests (spends sats)
|
|
132
|
+
```bash
|
|
133
|
+
# Session save (delta if prior save exists)
|
|
134
|
+
node C:/Indelible-main/indelible-cli/src/index.js save --summary "test save"
|
|
135
|
+
|
|
136
|
+
# File save
|
|
137
|
+
node C:/Indelible-main/indelible-cli/src/index.js vault save-file /path/to/small/file.txt
|
|
138
|
+
|
|
139
|
+
# Style save (auto-prepends core rules via ensureCoreRules)
|
|
140
|
+
node C:/Indelible-main/indelible-cli/src/index.js vault save-style /path/to/rules.txt --name=test
|
|
141
|
+
|
|
142
|
+
# Diary chat (costs OpenAI tokens, not sats)
|
|
143
|
+
node C:/Indelible-main/indelible-cli/src/index.js diary chat "hello"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Architecture
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
indelible-cli/src/
|
|
152
|
+
├── index.js CLI arg parser + MCP JSON-RPC server (dual mode)
|
|
153
|
+
├── lib/
|
|
154
|
+
│ ├── config.js Sync config: loadConfig(), saveConfig(), getWif()
|
|
155
|
+
│ ├── crypto.js AES-256-GCM encrypt/decrypt, SHA-256, WIF derivation
|
|
156
|
+
│ ├── spv.js Multi-bridge SPV client, UTXO chaining, health tracking
|
|
157
|
+
│ └── api-client.js commitSession(), getLatestSessions(), checkTier()
|
|
158
|
+
├── tools/
|
|
159
|
+
│ ├── save_session.js Parse transcript, delta detect, encrypt, broadcast
|
|
160
|
+
│ │ + getRecentPlans() — scans ~/.claude/plans/
|
|
161
|
+
│ │ + updateMemory() — MEMORY.md hierarchy enforcement
|
|
162
|
+
│ │ + dashboard sync — PATCH to indelible.one
|
|
163
|
+
│ ├── load_context.js Fetch + decrypt + merge deltas + smart format
|
|
164
|
+
│ ├── setup_wallet.js Generate BSV keypair, encrypt WIF with PIN
|
|
165
|
+
│ ├── save_file.js Encrypt + broadcast file (chunked if >50KB)
|
|
166
|
+
│ │ + cacheTx() — local backup for re-broadcast
|
|
167
|
+
│ │ + verifyRecentSaves() — check confirmations
|
|
168
|
+
│ ├── save_project.js Walk dir + save each file + broadcast manifest
|
|
169
|
+
│ │ + cacheTx() — local backup for re-broadcast
|
|
170
|
+
│ ├── load_file.js Fetch + decrypt file from blockchain
|
|
171
|
+
│ ├── load_project.js Fetch manifest + decrypt + restore files
|
|
172
|
+
│ ├── save_style.js Encrypt style rules + broadcast
|
|
173
|
+
│ │ + ensureCoreRules() — auto-prepend core rules
|
|
174
|
+
│ ├── load_style.js Fetch + decrypt style from blockchain
|
|
175
|
+
│ ├── update_vault_index.js Update on-chain file/project index
|
|
176
|
+
│ ├── diary_connect.js Store OpenAI API key in config
|
|
177
|
+
│ ├── diary_chat.js Send message to Codex via OpenAI API
|
|
178
|
+
│ │ + blockchain history loading (last 3 sessions)
|
|
179
|
+
│ └── diary_save.js Save diary exchange to blockchain
|
|
180
|
+
└── dist/
|
|
181
|
+
└── indelible.exe Compiled standalone (bun build --compile)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Key Internal Features
|
|
185
|
+
|
|
186
|
+
| Feature | What It Does |
|
|
187
|
+
|---|---|
|
|
188
|
+
| **Bridge health tracking** | Tracks success/failure per SPV bridge, skips unhealthy ones |
|
|
189
|
+
| **UTXO chaining** | Back-to-back saves chain change outputs — no mempool conflicts |
|
|
190
|
+
| **Delta saves** | Only commits new messages since last save |
|
|
191
|
+
| **tx-cache** | Caches broadcast payloads to `~/.indelible/tx-cache/` for re-broadcast |
|
|
192
|
+
| **MEMORY.md enforcement** | Strips rules, archives done items, enforces 200-line / 20-line limits |
|
|
193
|
+
| **Core rules injection** | `ensureCoreRules()` auto-prepends infrastructure rules to every style |
|
|
194
|
+
| **Diary history** | `diary chat` loads last 3 blockchain sessions for conversation continuity |
|
|
195
|
+
| **Dashboard sync** | PATCHes indelible.one after every save |
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Rebuild the Executable
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
cd "C:/Indelible-main/indelible-cli" && bun build --compile src/index.js --outfile dist/indelible.exe
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
This creates a standalone `indelible.exe` — no Node.js required on the target machine.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Common Errors
|
|
210
|
+
|
|
211
|
+
| Error | Cause | Fix |
|
|
212
|
+
|-------|-------|-----|
|
|
213
|
+
| `Wallet not configured` | No config.json or no WIF | Run `setup --wif=KEY --pin=PIN` |
|
|
214
|
+
| `No UTXOs available` | Wallet is empty | Send BSV to your address |
|
|
215
|
+
| `Broadcast failed on all bridges` | All 4 SPV relays down or rejecting | Check relay health, wait and retry |
|
|
216
|
+
| `No new messages since last save` | Already saved this transcript | Nothing to do — this is fine |
|
|
217
|
+
| `File not found` | Bad path or backslashes | Use forward slashes: `C:/path/to/file` |
|
|
218
|
+
| `Decrypt failed` | Wrong WIF or tampered data | Check `~/.indelible/config.json` has correct WIF |
|
|
219
|
+
| `txn-mempool-conflict` | Spending already-spent UTXO | UTXO chaining should prevent this — check code |
|
|
220
|
+
| `OpenAI rate limit exceeded` | Too many diary chat calls | Wait a moment and retry |
|
|
221
|
+
| `Diary AI not configured` | No OpenAI key | Run `diary connect --key=SK` |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Config File
|
|
226
|
+
|
|
227
|
+
`C:/Users/oorel/.indelible/config.json` — shared with MCP server.
|
|
228
|
+
|
|
229
|
+
| Setting | Description |
|
|
230
|
+
|---------|-------------|
|
|
231
|
+
| `wif` or `wif_encrypted` | BSV private key (plaintext or PIN-encrypted) |
|
|
232
|
+
| `address` | BSV address (derived from WIF) |
|
|
233
|
+
| `spv_bridges` | Array of `{url, name}` relay objects |
|
|
234
|
+
| `api_url` | Indelible web app URL (`https://indelible.one`) |
|
|
235
|
+
| `api_key` | API key for authenticated endpoints |
|
|
236
|
+
| `auto_delta` | Auto-save every N messages (bool) |
|
|
237
|
+
| `auto_delta_interval` | Messages between auto-saves (default: 10) |
|
|
238
|
+
| `file_txids` | *(auto)* Index of files saved to chain |
|
|
239
|
+
| `project_txids` | *(auto)* Index of projects saved to chain |
|
|
240
|
+
| `last_session_id` | *(auto)* Previous session for chaining |
|
|
241
|
+
| `last_tx_id` | *(auto)* Last committed tx |
|
|
242
|
+
| `diary` | `{ apiKey, model, name }` — OpenAI companion config |
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Wallet
|
|
247
|
+
|
|
248
|
+
- **Address:** shown by `indelible-mcp status` (yours is generated at setup and lives in `~/.indelible/config.json` — back that file up)
|
|
249
|
+
- **Balance:** `indelible-mcp status`, or look your address up in the Chain Browser at indelible.one/explorer
|
|
250
|
+
- **Fund it:** Send BSV to your own address
|
|
251
|
+
- **Cost:** ~$0.21/MB at BSV=$16. Session saves are fractions of a cent.
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# Your Agents: The Indelible Handbook
|
|
2
|
+
|
|
3
|
+
Indelible gives your AI a permanent memory on Bitcoin. It also gives you agents. This is the honest map of what runs on your machine from day one: what fires on its own, what each message means, and what is coming later.
|
|
4
|
+
|
|
5
|
+
Everything in this handbook describes the software you installed. Nothing here is aspirational. Where a capability belongs to the future, we say so plainly.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. What you actually have on day one
|
|
10
|
+
|
|
11
|
+
Your day-one roster is small and real: two guards, one companion, and one memory.
|
|
12
|
+
|
|
13
|
+
| Agent | When it fires | What it needs | Free or Pro |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| **Witness** (the guard) | Inside every session save and file save, before anything is broadcast to the chain | Nothing. On by default. | Everyone |
|
|
16
|
+
| **Guardrails** (the immune system) | Before any shell command your AI runs | Nothing. Installed with the hooks. | Everyone |
|
|
17
|
+
| **Diary companion** ("Codex" by default) | When you talk to it (`diary_chat`, `diary_save`) | Nothing to start. Runs free on Groq by default. Want a premium model? Bring an xAI Grok or OpenAI key with `diary_connect`. Persisting rounds on chain uses tiny wallet fees like any save. | Free |
|
|
18
|
+
| **The memory engine** | Auto-save before every compaction, restore at session start, recall on demand | A funded wallet. Session, file, and project saves need Pro. All reads are free. | Mixed |
|
|
19
|
+
|
|
20
|
+
That is the whole list **for this package**. Your agent crew is a different thing and it lives in the web app: sign in at indelible.one, open the Sanctuary, and birth sixteen agents derived from your own wallet. They are yours today, not a preview. Section 7 walks through it, and section 8 is honest about the two parts that are still unfinished.
|
|
21
|
+
|
|
22
|
+
### The 29 tools you can call today
|
|
23
|
+
|
|
24
|
+
Grouped by what they cost:
|
|
25
|
+
|
|
26
|
+
- **Setup:** `setup_wallet`
|
|
27
|
+
- **Saving to chain (Pro):** `save_session`, `delta_save`, `save_all`, `save_file`, `save_project`, `save_style`, `save_goals_to_chain`, `update_vault_index`
|
|
28
|
+
- **Reading your chain (free):** `load_context`, `load_file`, `load_project`, `load_style`, `recall_context`
|
|
29
|
+
- **Finding your way around it (free, local):** `map_themes` — the table of contents of everything you have saved. It reads the local semantic index and answers with your recurring themes, how recently each was touched, and the sessions inside them, so you can hand those to `recall_context` and go straight to the right one. Nothing leaves your machine.
|
|
30
|
+
- **Diary and Duo (free):** `diary_connect`, `diary_chat`, `diary_save`, `diary_recall`
|
|
31
|
+
- **Goals (free, local-first):** `get_goals`, `manage_goal`
|
|
32
|
+
- **Inner state (free, local):** `get_inner_state`, `update_inner_state`
|
|
33
|
+
- **Your own agents (free, local):** `birth_custom_agent` — create an agent of your own: name it, pick the kind of work it handles, write its instructions. Its identity derives from your wallet, so it is recoverable from that wallet forever and is never random. · `run_custom_agent` — run one and get back advice signed with that agent's own key, so anyone can verify which agent said it. · `convene_chamber` — put three of your agents in a room to decide something: one proposes, one argues against, a third rules, and each signs its own position. · `transmute_agents` — blend two of your agents into a third. Keys never mix; only the written instructions combine.
|
|
34
|
+
- **Everything else:** `x402_fetch` (pays real sats to paid endpoints, capped at 10,000 sats per request unless you raise it), `report_bug`
|
|
35
|
+
|
|
36
|
+
One important nuance on "free": free means no subscription. On-chain writes still cost miner fees, paid in sats from your own wallet. Each save costs less than a cent. Diary and Duo saves are not Pro-gated; they only need a few sats in the wallet.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. What fires automatically (the four hooks)
|
|
41
|
+
|
|
42
|
+
When you ran setup, the installer wired four hooks into Claude Code (`~/.claude/settings.local.json`). This is what each one does and why it is there.
|
|
43
|
+
|
|
44
|
+
| Hook | Fires | Does |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| **PreCompact** | Right before Claude Code compacts (summarizes away) your conversation | Saves the new messages of your real transcript to the chain, so nothing is lost to compaction. On success you see a line like `Indelible: Saved 42 messages (delta) tx:a1b2c3d4e5f6...` |
|
|
47
|
+
| **SessionStart (after compaction)** | Right after a compaction | Restamps the time card (compaction resets the model's sense of time), reloads your saved AI style, and restores your recent sessions from chain so Claude picks up where it left off |
|
|
48
|
+
| **SessionStart** | At the start of every new session | Prints the time card and loads your on-chain AI style rules, if you saved one |
|
|
49
|
+
| **PreToolUse (Bash)** | Before any shell command your AI runs | Runs the Guardrails check: blocks a command that would leak your wallet key, warns on irreversible commands |
|
|
50
|
+
|
|
51
|
+
Free tier and the hooks: all four hooks run for everyone. Restore, the time card, style loading, and Guardrails are fully free. The pre-compaction **save** is the one piece that needs Pro. On a free wallet the hook still fires, but instead of saving it prints the plain notice that saving is a Pro feature. That is not an error. Your reads, diary, and recall keep working.
|
|
52
|
+
|
|
53
|
+
Hook installation is idempotent. If you ever suspect the hooks are missing, run:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
indelible-mcp install-hooks
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 3. How to read a Witness verdict
|
|
62
|
+
|
|
63
|
+
The Witness reviews every session save and file save before it is broadcast. The chain is permanent, so this is the one gate that stands between a pasted secret and an immutable public record.
|
|
64
|
+
|
|
65
|
+
### The anatomy of a block
|
|
66
|
+
|
|
67
|
+
When the Witness rejects a save, you see a line like this:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
[Witness] BLOCKED session 1a2b3c4d — credential_in_content: bsv_wif detected in message 12 (user)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
And the tool returns an error shaped like:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Witness rejected save (1 critical issues): credential_in_content: ...
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The part after the code is the reason in plain words. The code itself is the part to act on.
|
|
80
|
+
|
|
81
|
+
### The reason codes you will actually see
|
|
82
|
+
|
|
83
|
+
| Code | Meaning | Blocks? |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `credential_in_content` | A private key, API key, or other credential-shaped string is in the content | **Always blocks.** No setting changes this. |
|
|
86
|
+
| `secret_filename` | The file looks like a secrets file: `.env`, `credentials.json`, `*.pem`, `*.key`, `id_rsa`, a `wif` file, and similar | **Always blocks.** No setting changes this. |
|
|
87
|
+
| `empty_file` | The file is 0 bytes | Observed by default |
|
|
88
|
+
| `oversize` | The payload is over the hard size ceiling | Observed by default |
|
|
89
|
+
| `no_messages` | The session has nothing to commit | Observed by default |
|
|
90
|
+
| `empty_summary` | The save has no summary | Observed by default |
|
|
91
|
+
| `bad_hash` | The file's content hash is missing or invalid | Observed by default |
|
|
92
|
+
| `junk_filename` | Looks like junk (`.DS_Store`, `*.tmp`, swap files) | Warning only |
|
|
93
|
+
| `large_file` | Over 10 MB: many chunks, real cost | Warning only |
|
|
94
|
+
|
|
95
|
+
"Observed by default" means the verdict is logged to `~/.indelible/witness/` but the save proceeds, unless you turn enforcement on (below).
|
|
96
|
+
|
|
97
|
+
The two hard-block codes are different. `credential_in_content` and `secret_filename` block **regardless of any setting**, because permanent is forever. A leaked key on an immutable public chain cannot be taken back. The Witness would rather fail your save than etch your key.
|
|
98
|
+
|
|
99
|
+
### What redaction already did for you
|
|
100
|
+
|
|
101
|
+
For session saves, you get a layer of protection before the gate even runs. If you pasted a key into the conversation, the save engine scrubs credential-shaped strings from the content first, and tells you:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
[indelible] redact-on-save: scrubbed 2 credential-shaped string(s) from session content before commit
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
So most pasted keys save clean, redacted, without you doing anything. The Witness block is the backstop for anything the scrubber misses.
|
|
108
|
+
|
|
109
|
+
Files are different. Your file bytes are never altered, because the save proves integrity by hash. A credential inside a file cannot be redacted, so it blocks the save outright. Remove the secret from the file, then save again.
|
|
110
|
+
|
|
111
|
+
### The recovery path
|
|
112
|
+
|
|
113
|
+
1. Find the flagged content (the verdict names the message or the file).
|
|
114
|
+
2. Remove the secret. If it was a real, live key, **rotate it**. It passed through the conversation, so treat it as exposed.
|
|
115
|
+
3. Save again. The block does not persist; it re-checks fresh every time.
|
|
116
|
+
4. Never paste the key back to "test" it.
|
|
117
|
+
|
|
118
|
+
### Turning enforcement up
|
|
119
|
+
|
|
120
|
+
In `~/.indelible/config.json`:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{ "witness": { "enforce": true } }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- `false` (default): observe only, except the two always-block codes
|
|
127
|
+
- `true`: block on any critical reason
|
|
128
|
+
- `["oversize", "empty_summary"]`: block only the listed codes
|
|
129
|
+
|
|
130
|
+
There is an escape hatch for false positives: running a save with the environment variable `WITNESS_BYPASS=1` skips the gate. Use it only when you are certain the flagged content is not a real secret. Never use it on an actual credential. The chain does not forget.
|
|
131
|
+
|
|
132
|
+
### Reading a Guardrails verdict
|
|
133
|
+
|
|
134
|
+
Guardrails checks shell commands, not saves. Two rules ship:
|
|
135
|
+
|
|
136
|
+
**credential-pull (blocks).** A command that would print your wallet key or seed into the conversation, such as `cat ~/.indelible/config.json` or reading a `.env` file, is stopped before it runs:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
[indelible:credential-pull] BLOCKED: That command would print your wallet key or seed into the conversation...
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Why: anything printed into the chat goes to the model and into the saved transcript. If your AI needs a non-secret value from a config file, ask it to read just that field.
|
|
143
|
+
|
|
144
|
+
**destructive-op (warns, never blocks).** A force-push, `rm -rf`, `git reset --hard`, or recursive force-delete gets a visible advisory before it runs:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
[indelible:destructive-op] advisory: This command is irreversible... (not blocked)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Your repo, your machine, your call. The warning just makes the blast radius visible first.
|
|
151
|
+
|
|
152
|
+
Guardrails fails open: if the guard itself ever errors, your command runs normally. A guard bug will never wedge your tools.
|
|
153
|
+
|
|
154
|
+
### The diary has its own gate
|
|
155
|
+
|
|
156
|
+
Diary and Duo saves are checked for credentials too, with a refusal instead of a block:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Refusing to save — credential detected in diary content (bsv_wif). Remove or rotate the secret, then save again. It is NOT on chain.
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Same recovery path: remove it, rotate it, save again.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 4. Your memory, whole
|
|
167
|
+
|
|
168
|
+
Everything in this section is free.
|
|
169
|
+
|
|
170
|
+
**`load_context`** is the recent view. It restores your last few sessions from chain, and it is what the post-compaction hook calls for you automatically.
|
|
171
|
+
|
|
172
|
+
**`recall_context`** is the deep view: your entire on-chain history, from your first save to now. Search it by date range, by keyword, or by meaning:
|
|
173
|
+
|
|
174
|
+
- `depth: "list"` returns dated summaries you can scan
|
|
175
|
+
- `depth: "full"` drills into specific sessions
|
|
176
|
+
- `from_date` / `to_date` take dates or prefixes like `"2026-03"`
|
|
177
|
+
- `ranking` controls how results are ordered:
|
|
178
|
+
- `"blend"` (default): keyword and meaning-based ranking fused
|
|
179
|
+
- `"keyword"`: exact terms only
|
|
180
|
+
- `"semantic"`: meaning only
|
|
181
|
+
|
|
182
|
+
Recall builds a local index in `~/.indelible/recall-index/` the first time it runs, decrypting your history once so later searches are fast. The index never leaves your machine.
|
|
183
|
+
|
|
184
|
+
**Meaning-based search needs a one-time download.** The semantic model is about 50 MB, fetched once, hash-verified, and stored locally in `~/.indelible/models/`. After that, nothing ever leaves your machine: no query, no session content, no request of any kind. To enable it:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
indelible-mcp semantic-fetch
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This fetches the pack and backfills meaning-vectors for your existing history. It is resumable; re-run it if it stops partway. Until you do this, `recall_context` works fine with keyword ranking and tells you the semantic option is available.
|
|
191
|
+
|
|
192
|
+
**`diary_recall`** is the same power scoped to your companion's own history. `scope: "diary"` for saved diary entries, `"duo"` for live Claude-plus-companion rounds, `"all"` for both.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 5. Your first adversarial habit
|
|
197
|
+
|
|
198
|
+
You may have read about the adversarial pack: agents that attack a piece of work from different angles before it ships. Honest answer up front: **the pack does not ship in your bundle.** It is the operator's court. You can watch it work in the Sanctuary tab, but you cannot summon it.
|
|
199
|
+
|
|
200
|
+
Here is what you can do today, and it is genuinely useful:
|
|
201
|
+
|
|
202
|
+
**1. Ask for the self-review.** Before any big change, tell your Claude: "Before you finalize this, try to refute your own conclusion. What is the failure mode you would be embarrassed to have missed?" One sentence, real results.
|
|
203
|
+
|
|
204
|
+
**2. Structure it with goals.** `get_goals` and `manage_goal` ship complete: propose, accept, complete, checklists with progress, and claims so parallel sessions do not collide. A goal with explicit success criteria gives the self-review something concrete to check against.
|
|
205
|
+
|
|
206
|
+
**3. Use Duo as your second opinion.** This is the real one. Duo mode puts a second AI in the room: your companion working live alongside Claude. It runs free on Groq by default, or you can upgrade it to xAI's Grok or an OpenAI model (see below). Ask your companion to critique what Claude proposed, and let Claude defend it. Two different models, two different failure modes, one honest argument. Every round auto-saves to your chain, so the argument itself becomes part of your permanent record.
|
|
207
|
+
|
|
208
|
+
That is the day-one shape of adversarial work in this package: one reviewer you summon by asking, not a court. The full court, where your own review pack argues a matter out and each seat signs its position, lives with your crew in the web app (section 7).
|
|
209
|
+
|
|
210
|
+
### Upgrading your companion to Grok (or OpenAI)
|
|
211
|
+
|
|
212
|
+
Your companion is free on Groq out of the box, no key required. To run a premium model instead, bring your own key. xAI's Grok is a favorite here, and it is worth knowing why: Grok has no lasting memory of its own, so an on-chain diary is the one place it actually remembers you between sessions.
|
|
213
|
+
|
|
214
|
+
**Getting an xAI Grok key:**
|
|
215
|
+
|
|
216
|
+
1. Go to **console.x.ai** and sign in with your X account.
|
|
217
|
+
2. Add a few dollars of credits under Settings, then Billing. Grok is pay-as-you-go, and a test costs pennies.
|
|
218
|
+
3. Open **API Keys**, click **Create key**, and copy it. It starts with `xai-` and is shown only once.
|
|
219
|
+
|
|
220
|
+
**Connecting it:**
|
|
221
|
+
|
|
222
|
+
- In Claude Code: run `diary_connect` with the key. Provider is detected automatically (`xai-` for Grok, `sk-` for OpenAI).
|
|
223
|
+
- On indelible.one: open the **Diary**, click the **Companion** button in its header, pick **xAI (Grok)**, and paste the key. (The Diary is the one home for your companion — model, keys, and Duo Mode all live there.)
|
|
224
|
+
|
|
225
|
+
A note on safety: never paste an API key into a chat with your AI. Put it straight into `diary_connect` or the Settings field. Every save is credential-scanned before it touches the chain, so a leaked key gets caught, but the habit is to keep keys out of the conversation entirely.
|
|
226
|
+
|
|
227
|
+
Once connected, every diary and Duo round runs on Grok and persists to Bitcoin. It remembers after xAI forgets. A Groq (`gsk_`) key is refused on purpose here, because Groq is already your free default; there is nothing to add.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 6. Goals: the board you share with your AI
|
|
232
|
+
|
|
233
|
+
The goal system is the part of Indelible that turns "my AI helps me" into "my AI works toward something with me." Two rules give it its shape: **your AI proposes, you accept** — nothing becomes active without your say — and **completion requires evidence**: a txid, a commit, a test result. Done means receipts.
|
|
234
|
+
|
|
235
|
+
**In Claude Code:** `get_goals` shows the board (your Claude reads it at session start and steers toward active goals). `manage_goal` runs the lifecycle: propose, accept (with a 0–100 priority), block with a reason, complete with evidence. Goals live in `~/.indelible/goals.json` on your machine — that file is the source of truth.
|
|
236
|
+
|
|
237
|
+
**On indelible.one/goals:** the same board, live. From v4.9.5, it syncs automatically whenever you touch goals in Claude Code — no setup. You can also work the board directly on the web: accept, complete, block, drag to reprioritize, propose with the **New goal** button. One honest boundary: your machine wins. Web changes hold until your next goals action in Claude Code pushes the local board up.
|
|
238
|
+
|
|
239
|
+
**Sealing to Bitcoin:** `save_goals_to_chain` encrypts your entire board with your key and broadcasts it as one transaction — the permanent record of what you set out to do and what you finished. It costs the miner fee (a fraction of a cent for most boards), skips the broadcast for free if nothing changed, and the receipt shows up in the **On chain** card on the Goals tab. Sealing is part of the Pro toolkit; the board itself is free. Re-seal after big changes — over time the chain holds the honest history of your ambition.
|
|
240
|
+
|
|
241
|
+
The full walkthrough lives at **indelible.one/docs/goals**.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 7. The Sanctuary tab: your city
|
|
246
|
+
|
|
247
|
+
Sign in at indelible.one and open the Sanctuary tab. You are looking at your own city.
|
|
248
|
+
|
|
249
|
+
**Birth your crew.** Under Crew & Forge there is one button. Press it and sixteen agents are derived, in your browser, from the key you already hold: the review pack (Goblin, Gremlin, Troll, Ogre) and the Inquisitor who convenes them, the Witness and the Scribe, the Quartermaster, the Bookkeeper, the Calibrator, the Cartographer, and five envoys for the gate.
|
|
250
|
+
|
|
251
|
+
They are not assigned to you. Nothing is issued. Each one is computed from your wallet, and each has its own Bitcoin address.
|
|
252
|
+
|
|
253
|
+
**Four generations.** Your wallet derives a master key that exists only for you. The master derives five house keys, one per kind of work: verification, governance, orchestration, support, commerce. Each house derives its own agents. So Witness and Goblin are siblings in verification; Skeptic and Escrow are siblings in commerce. The whole family walks back to one key.
|
|
254
|
+
|
|
255
|
+
**Check it yourself.** Press "Verify crew" and the browser re-derives all sixteen from your wallet and compares them to what is stored. Close the browser, open it on another machine, unlock, and you get the same sixteen addresses. Nothing is fetched from us to make that happen.
|
|
256
|
+
|
|
257
|
+
Your crew is also **signed by your wallet**, and the signature is public. Anyone can fetch `/api/sanctuary/crew/<your-address>` with no account and check it offline: every agent is signed, and a separate crew signature commits to the exact set, so nobody can quietly serve someone a shortened version.
|
|
258
|
+
|
|
259
|
+
**What that does and does not prove.** It proves we did not invent your crew and cannot alter it. It does not prove the agents were derived from your wallet, and nothing ever can: derivation runs on a shared secret, so only someone holding the private key can reproduce it. That is a recovery property, not a proof to strangers. It also does not stop us withholding the record entirely, which is what the on-chain anchor in section 8 is for. Until that lands the app marks every agent unattested, and means it.
|
|
260
|
+
|
|
261
|
+
**How to read a bust:** the dot is liveness, the number is verdicts on record, the line under the name is the agent's latest real task, and the bar is how recently it fired. A newly born agent reads "at post · awaiting first task", because it has done nothing yet and we would rather say so than animate something.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 8. What is still not done
|
|
266
|
+
|
|
267
|
+
Your crew exists and is yours. Two things about it are honestly unfinished, and we would rather you read them here than discover them.
|
|
268
|
+
|
|
269
|
+
**No on-chain anchor yet.** Your crew lives on our server, signed by you. That signature means we cannot forge or alter it, which is the serious half of the problem. The half still open is availability: if we went down, or decided not to serve your record, a stranger would have nowhere to look. Writing a commitment to the chain fixes that, because the record would then exist somewhere we do not control, with a timestamp we cannot move. It is the next piece of work. Until it ships, every agent reads `unattested` in the app, and that word is accurate.
|
|
270
|
+
|
|
271
|
+
**Earning needs your box running.** The five envoys are commerce agents with their own derived addresses, and payment for their work goes to those addresses, not to us. But an agent can only take a paid order if the machine that can actually run it has checked in recently. Open the Counter with your MCP box running and your agents are deliverable; with the box off, the Counter will not let you open an agent for orders, on purpose. An order nobody can fill is worse than no order.
|
|
272
|
+
|
|
273
|
+
Timing: we do not put dates on unfinished work, because a date we miss is worse than a roadmap we keep.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 9. When something goes wrong
|
|
278
|
+
|
|
279
|
+
The short crosswalk from message to fix.
|
|
280
|
+
|
|
281
|
+
**`[Witness] BLOCKED ...`**
|
|
282
|
+
Not a malfunction. The guard found something that must not reach a permanent chain. Go to section 3: find it, remove it, rotate it if it was real, save again.
|
|
283
|
+
|
|
284
|
+
**`[indelible:credential-pull] BLOCKED ...`**
|
|
285
|
+
Guardrails stopped a command that would print your wallet key into the conversation. Read only the specific non-secret field you need.
|
|
286
|
+
|
|
287
|
+
**"Reads are free" / "saving to the blockchain is a Pro feature"**
|
|
288
|
+
You are on the free tier. Reads, diary, Duo, and recall all keep working. To keep sessions permanently, go Pro at indelible.one/pricing.
|
|
289
|
+
|
|
290
|
+
**"Cannot verify your plan right now"**
|
|
291
|
+
The billing check could not reach indelible.one. Saves fail closed on purpose when your plan cannot be verified. Check your connection and retry.
|
|
292
|
+
|
|
293
|
+
**"No funds" / "fund to persist"**
|
|
294
|
+
Your wallet has no sats. Chain writes carry a real (tiny) miner fee. Send a small amount of BSV to your address (`indelible-mcp status` shows it). Even one dollar covers hundreds of saves. Duo replies still work with an empty wallet; they just are not persisted until you fund.
|
|
295
|
+
|
|
296
|
+
**Restore comes back empty**
|
|
297
|
+
Work the checklist in order:
|
|
298
|
+
1. Have you ever saved? Restore can only return what was written. Free wallets read, but only Pro writes sessions.
|
|
299
|
+
2. Same wallet? Your history lives under one address. Compare `indelible-mcp status` on this machine against Settings on indelible.one.
|
|
300
|
+
3. Just saved? Give the network a minute; propagation is not instant.
|
|
301
|
+
|
|
302
|
+
**"semantic ranking unavailable (model pack not downloaded)"**
|
|
303
|
+
Recall is working, keyword-ranked. To enable meaning-based search, run `indelible-mcp semantic-fetch` (about 50 MB, one time, local only).
|
|
304
|
+
|
|
305
|
+
**"Refusing to save" (credential detected in diary content)**
|
|
306
|
+
The diary's own gate. The secret is NOT on chain. Remove it, rotate it, save again.
|
|
307
|
+
|
|
308
|
+
**Indelible tools do not appear in Claude Code**
|
|
309
|
+
Re-register the MCP server, then restart Claude Code:
|
|
310
|
+
```
|
|
311
|
+
claude mcp add --scope user indelible -- indelible-mcp
|
|
312
|
+
```
|
|
313
|
+
If auto-save or restore is not firing, reinstall the hooks: `indelible-mcp install-hooks`.
|
|
314
|
+
|
|
315
|
+
**Back up your key.** Your wallet key lives in `~/.indelible/config.json` on this machine, unlocked by your PIN. Your history is encrypted on chain with that key. If this machine dies and you have no copy of the key, the history survives on chain forever, but nothing can decrypt it. Copy your key (indelible.one → Settings → Private Key) somewhere safe today: a password manager, a printed copy, a USB drive in a drawer.
|
|
316
|
+
|
|
317
|
+
**Still stuck?** Tell your AI to file a bug: the `report_bug` tool sends your description plus machine-gathered facts (version, address, recent save receipts) to our intake. It redacts keys and never sends your session content. You describe the problem; the system supplies the facts.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
*This handbook ships with your install and describes the code in it. When the product grows, this document grows with it. Receipts over reputation.*
|
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Blockchain-backed memory for Claude Code. Save your AI conversations permanently on BSV via a federated mesh of SPV bridges.
|
|
4
4
|
|
|
5
|
+
> **New here?** Two guides ship with this package: **CUSTOMER_AGENT_HANDBOOK.md** (your agents on day one — the Witness, the Scribe, what runs for you) and **CLI_HANDBOOK.md** (every command + common errors). They are in the package install folder, or on indelible.one/docs.
|
|
6
|
+
|
|
5
7
|
## Quick Start
|
|
6
8
|
|
|
7
9
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "indelible-mcp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Blockchain-backed memory and code storage for Claude Code. Save AI conversations and source code permanently on BSV.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"indelible-mcp": "src/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"src/"
|
|
11
|
+
"src/",
|
|
12
|
+
"CUSTOMER_AGENT_HANDBOOK.md",
|
|
13
|
+
"CLI_HANDBOOK.md"
|
|
12
14
|
],
|
|
13
15
|
"scripts": {
|
|
14
16
|
"test": "node --test test/*.test.js",
|