@totalreclaw/totalreclaw 3.3.1-rc.1 → 3.3.1-rc.2
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/CHANGELOG.md +119 -0
- package/SKILL.md +71 -301
- package/extractor.ts +28 -4
- package/gateway-url.ts +70 -74
- package/index.ts +570 -23
- package/llm-client.ts +111 -7
- package/llm-profile-reader.ts +127 -0
- package/package.json +2 -2
- package/retype-setscope.ts +474 -0
- package/tool-gating.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,125 @@ All notable changes to `@totalreclaw/totalreclaw` (the OpenClaw plugin) are docu
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.3.1-rc.2] — 2026-04-22
|
|
8
|
+
|
|
9
|
+
Follow-up RC for the 3.3.1-rc.1 QA NO-GO
|
|
10
|
+
(`docs/notes/QA-plugin-3.3.1-rc.1-20260422-0121.md` in
|
|
11
|
+
`totalreclaw-internal`). Fixes 3 ship-stoppers + 1 serious non-blocker
|
|
12
|
+
identified by the first real-user-flow QA under the 2026-04-22 chat-only
|
|
13
|
+
discipline, plus several UX gaps flagged by Pedro's agent (Hermes) during
|
|
14
|
+
parallel Telegram testing. All 3.3.1-rc.1 provider-agnostic LLM work is
|
|
15
|
+
preserved.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **`gateway-url.ts` — drop `child_process` subprocess probe.** The rc.1
|
|
20
|
+
implementation shelled out to `tailscale status --json` via
|
|
21
|
+
`child_process.execFileSync` to discover the local MagicDNS hostname.
|
|
22
|
+
This tripped the OpenClaw dangerous-code scanner's shell-execution
|
|
23
|
+
rule and **blocked every `openclaw plugins install @totalreclaw/totalreclaw`**.
|
|
24
|
+
rc.2 swaps to a passive probe: `os.networkInterfaces()` detects a
|
|
25
|
+
`tailscale*` NIC carrying a CGNAT IPv4 (100.64/10), and we surface
|
|
26
|
+
the raw IP as the auto-detected host. Operators who want a proper
|
|
27
|
+
`https://<magicdns>.ts.net` URL now set
|
|
28
|
+
`plugins.entries.totalreclaw.config.publicUrl` explicitly (documented
|
|
29
|
+
in SKILL.md). The six-layer URL cascade is otherwise unchanged.
|
|
30
|
+
|
|
31
|
+
- **`check-scanner.mjs` — add shell-execution rule (catches `child_process`).**
|
|
32
|
+
Scanner-sim now mirrors the real OpenClaw `shell-execution` rule that
|
|
33
|
+
trips on any `child_process` substring (no context gate). Prevents a
|
|
34
|
+
repeat of the rc.1 regression. See `skill/scripts/check-scanner.mjs`
|
|
35
|
+
SHELL_EXEC_PATTERN.
|
|
36
|
+
|
|
37
|
+
- **`totalreclaw_forget` — route through `submitFactBatchOnChain` and write
|
|
38
|
+
tombstones at legacy v3.** The rc.1 implementation used the single-fact
|
|
39
|
+
`submitFactOnChain` path and wrote the tombstone at protobuf v4, which
|
|
40
|
+
the subgraph did NOT reflect as `isActive=false`. rc.2 mirrors the
|
|
41
|
+
pin/unpin tombstone shape exactly (legacy v3, `source="tombstone"`,
|
|
42
|
+
single-payload batch via `submitFactBatchOnChain`). Also adds
|
|
43
|
+
UUID-shape validation on `factId` to reject LLM hallucinations
|
|
44
|
+
("forget that I live in Porto" passed as the factId) with a clear
|
|
45
|
+
message pointing the agent at `totalreclaw_recall` first.
|
|
46
|
+
|
|
47
|
+
- **`totalreclaw_forget` tool description** — rewritten from terse
|
|
48
|
+
("Delete a specific memory by its ID.") to agent-instructive with a
|
|
49
|
+
recall-first workflow hint. Fixes the rc.1 QA failure where the LLM
|
|
50
|
+
hallucinated "Done" without actually calling the tool.
|
|
51
|
+
|
|
52
|
+
- **`chatCompletion` — exponential-backoff retry for 429 / timeouts.**
|
|
53
|
+
rc.1 QA: 5 of 6 extraction windows returned 0 raw facts because zai
|
|
54
|
+
429s and timeouts had no retry path. rc.2 adds a retry wrapper:
|
|
55
|
+
3 attempts with 1s → 2s → 4s backoff; 30s per-attempt timeout;
|
|
56
|
+
fail-fast on 4xx-other-than-429. Every extractor callsite
|
|
57
|
+
(`extractFacts`, `extractFactsForCompaction`, `comparativeRescoreV1`,
|
|
58
|
+
`extractDebriefFacts`) opts in to the retry + logger. See
|
|
59
|
+
`isRetryable()` for the classification list.
|
|
60
|
+
|
|
61
|
+
- **`llm-profile-reader.ts` — fallback to legacy `models.json` format.**
|
|
62
|
+
rc.1 QA VPS had `~/.openclaw/agents/<agent>/agent/models.json` (the
|
|
63
|
+
pre-auth-profiles shape, `{ providers: { zai: { apiKey: "..." } } }`)
|
|
64
|
+
not `auth-profiles.json`. The auto-resolve silently no-op'd.
|
|
65
|
+
rc.2 adds a 5th cascade tier: `readAllProfileKeys` reads
|
|
66
|
+
auth-profiles.json FIRST (takes precedence on overlap), then merges
|
|
67
|
+
in models.json entries for any provider not already covered.
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
|
|
71
|
+
- **`totalreclaw_onboard`** (agent tool) — lets the agent drive the
|
|
72
|
+
non-interactive onboard flow from chat without shelling out. Generate
|
|
73
|
+
mode only (restore still requires `openclaw totalreclaw onboard --mode
|
|
74
|
+
restore` in the local terminal for security). Returns scope address +
|
|
75
|
+
credentials path; NEVER returns the mnemonic. Directly wraps
|
|
76
|
+
`runNonInteractiveOnboard` in-process.
|
|
77
|
+
|
|
78
|
+
- **`totalreclaw_pair`** (agent tool) — lets the agent start a pairing
|
|
79
|
+
session from chat and relay the URL + PIN + QR ASCII to the user.
|
|
80
|
+
Built on the same `createPairSession` + `buildPairingUrl` surface the
|
|
81
|
+
CLI uses, no subprocess. The recovery phrase still never crosses the
|
|
82
|
+
LLM — it's generated/entered in the BROWSER and uploaded E2EE.
|
|
83
|
+
|
|
84
|
+
- **`totalreclaw_retype`** (agent tool) — reclassify an existing memory
|
|
85
|
+
from one taxonomy type to another (claim/preference/directive/
|
|
86
|
+
commitment/episode/summary). Writes a new v1.1 claim with the updated
|
|
87
|
+
type, tombstones the old fact on-chain. rc.1 QA confirmed this tool
|
|
88
|
+
was documented in SKILL.md but NOT registered — agents couldn't call
|
|
89
|
+
it.
|
|
90
|
+
|
|
91
|
+
- **`totalreclaw_set_scope`** (agent tool) — move an existing memory to
|
|
92
|
+
a different scope (work/personal/health/family/creative/finance/misc/
|
|
93
|
+
unspecified). Same write pattern as retype. Also previously
|
|
94
|
+
documented-not-registered; rc.1 QA showed agents falling back to a
|
|
95
|
+
hallucinated delete+re-store workaround.
|
|
96
|
+
|
|
97
|
+
- **`skill/plugin/retype-setscope.ts`** — new pure-logic module
|
|
98
|
+
supporting the two agent tools above. Tightly mirrors pin.ts but
|
|
99
|
+
without the idempotent-status short-circuit (user may be confirming
|
|
100
|
+
a prior auto-extraction label) and without feedback wiring.
|
|
101
|
+
|
|
102
|
+
- **`skill/plugin/gateway-url.test.ts`** — unit coverage for the new
|
|
103
|
+
passive Tailscale + LAN detection. 17 cases, all green.
|
|
104
|
+
|
|
105
|
+
- **`skill/plugin/retype-setscope.test.ts`** — 31 cases covering arg
|
|
106
|
+
validation, successful rewrites, fact-not-found, submit failure,
|
|
107
|
+
malformed-blob, invalid-type/scope.
|
|
108
|
+
|
|
109
|
+
- **`skill/plugin/llm-client-retry.test.ts`** — 29 cases for the retry
|
|
110
|
+
wrapper: isRetryable classification, backoff behaviour, fail-fast on
|
|
111
|
+
non-retryable errors, logger interaction.
|
|
112
|
+
|
|
113
|
+
- **`skill/plugin/llm-profile-reader.test.ts`** — 13 additional cases
|
|
114
|
+
for models.json parsing + combined reader.
|
|
115
|
+
|
|
116
|
+
### Preserved from rc.1
|
|
117
|
+
|
|
118
|
+
All the rc.1 LLM-autoresolve work carries forward unchanged:
|
|
119
|
+
- 4-tier cascade (plugin config → openclawProviders → auth-profiles →
|
|
120
|
+
env). With rc.2's `models.json` fallback it's effectively 5 tiers.
|
|
121
|
+
- `openclaw totalreclaw onboard --non-interactive --json --mode` CLI.
|
|
122
|
+
- `openclaw totalreclaw pair generate --json` CLI.
|
|
123
|
+
- `extraction.llm` plugin-config override block.
|
|
124
|
+
- Synchronous HTTP-route registration, manifest `kind` drop, etc.
|
|
125
|
+
|
|
7
126
|
## [3.3.1-rc.1] — 2026-04-22
|
|
8
127
|
|
|
9
128
|
First release candidate for 3.3.1. Comprehensive patch release addressing
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: totalreclaw
|
|
3
3
|
description: "End-to-end encrypted memory for AI agents — portable, yours forever. XChaCha20-Poly1305 E2EE: server never sees plaintext."
|
|
4
|
-
version: 3.3.1-rc.
|
|
4
|
+
version: 3.3.1-rc.2
|
|
5
5
|
author: TotalReclaw Team
|
|
6
6
|
license: MIT
|
|
7
7
|
homepage: https://totalreclaw.xyz
|
|
@@ -22,325 +22,95 @@ metadata:
|
|
|
22
22
|
- persistent-context
|
|
23
23
|
---
|
|
24
24
|
|
|
25
|
-
# TotalReclaw
|
|
25
|
+
# TotalReclaw — Agent Guide
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
You are operating inside a host that has the TotalReclaw memory plugin loaded. This file tells you WHAT to call and WHEN. Every sentence is a rule.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
## Setup state
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
# 1. Install the skill (registers instructions + tool surface)
|
|
33
|
-
openclaw skills install totalreclaw
|
|
31
|
+
Before any memory tool, check `~/.totalreclaw/credentials.json`:
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
- **Missing, empty, malformed, or no `mnemonic` key** -> NOT set up. You MUST NOT generate a phrase in chat, and you MUST NOT ask the user to paste one. Route:
|
|
34
|
+
- Local gateway: call `totalreclaw_onboarding_start` (or `totalreclaw_onboard` if available); both return a pointer to `openclaw totalreclaw onboard`.
|
|
35
|
+
- Remote gateway (VPS / Docker / no TTY): call `totalreclaw_pair` (v3.3.1+), OR instruct the user to run `openclaw totalreclaw pair generate --json`. Present the returned `{url, pin, qr_ascii}` to the user. The phrase is entered in their browser, never in this conversation.
|
|
36
|
+
- **Present with a valid `mnemonic`** -> active. Use the tools below.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
# On native install:
|
|
40
|
-
openclaw restart
|
|
41
|
-
# Inside Docker:
|
|
42
|
-
docker restart openclaw-qa
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
The two-step install is necessary because OpenClaw separates "skill metadata" (what this file describes) from "plugin code" (the compiled TypeScript that runs). Skipping step 2 leaves the user with instructions but no tools. Skipping step 3 leaves the tools installed but unbound — calls fail silently.
|
|
46
|
-
|
|
47
|
-
Some OpenClaw versions support a single-step `openclaw plugins install @totalreclaw/totalreclaw` that auto-registers the skill; if so, you can skip step 1.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Recovery Phrase — CRITICAL SAFETY RULES
|
|
52
|
-
|
|
53
|
-
### RULE 1 — Never generate, display, or transmit a recovery phrase in chat.
|
|
38
|
+
## Core rules
|
|
54
39
|
|
|
55
|
-
The recovery phrase is
|
|
40
|
+
1. **Phrase safety (NON-NEGOTIABLE).** The recovery phrase is a secret. Never generate one in chat, never echo one back, never log one in reasoning / tool payloads, never pass one to another tool. Direct users to `cat ~/.totalreclaw/credentials.json | jq -r .mnemonic`.
|
|
41
|
+
2. **Use the tools, not inline state.** `totalreclaw_remember` stores; `totalreclaw_recall` retrieves. Don't re-ask the user for past facts; don't paraphrase memories as your own recollection.
|
|
42
|
+
3. **Gateway restart is required after install.** If tools fail right after `openclaw plugins install @totalreclaw/totalreclaw`, tell the user to run `openclaw restart` or `docker restart openclaw-qa`.
|
|
56
43
|
|
|
57
|
-
|
|
58
|
-
- Produce a 12-word phrase yourself and paste it into the chat. You **cannot** compute a valid BIP-39 checksum, and even if you could, this leaks the phrase.
|
|
59
|
-
- Ask the user to paste their recovery phrase into the chat. If they do, explicitly tell them to delete the message and use the CLI flow instead.
|
|
60
|
-
- Display a phrase that another tool returned via chat output.
|
|
44
|
+
## Decision tree — which tool, when
|
|
61
45
|
|
|
62
|
-
|
|
46
|
+
- **Fact-shaped content** (preferences, identity, commitments, decisions, directives, episodes): `totalreclaw_remember`. Don't ask permission for obvious user facts.
|
|
47
|
+
- **Question about the past** ("what do you remember about…", "do I like…"): `totalreclaw_recall`.
|
|
48
|
+
- **"Pin that" / "remember permanently"**: `totalreclaw_pin`. **"Unpin" / "can forget that"**: `totalreclaw_unpin`.
|
|
49
|
+
- **"Forget X" / "delete that memory"**: `totalreclaw_forget` with the fact's id.
|
|
50
|
+
- **"That's a preference, not a claim"**: `totalreclaw_retype`.
|
|
51
|
+
- **"Put that under work"**: `totalreclaw_set_scope`.
|
|
52
|
+
- **"Export my memories"**: `totalreclaw_export`.
|
|
53
|
+
- **"What's my TotalReclaw status?"**: `totalreclaw_status`.
|
|
54
|
+
- **"Set up TotalReclaw"** (no credentials): route per the Setup-state section above.
|
|
55
|
+
- **"Import my Mem0 / ChatGPT / Claude / Gemini history"**: `totalreclaw_import_from` with `dry_run=true` first. Show the estimate, confirm, then run without `dry_run`. For >50 chunks, use `totalreclaw_import_batch` and report progress.
|
|
56
|
+
- **"Upgrade" / "I want Pro"**: `totalreclaw_upgrade` returns a Stripe URL. After upgrade, offer `totalreclaw_migrate` (dry-run first) to move testnet memories to mainnet.
|
|
63
57
|
|
|
64
|
-
|
|
58
|
+
## Tool surface
|
|
65
59
|
|
|
66
|
-
|
|
60
|
+
Tools work only when credentials are active AND the gateway has been restarted post-install. If a tool returns "onboarding required", route back to onboarding.
|
|
67
61
|
|
|
68
|
-
|
|
62
|
+
| Tool | Key params |
|
|
63
|
+
|------|------------|
|
|
64
|
+
| `totalreclaw_remember` | `text`, optional `type` (default `claim`), `importance` |
|
|
65
|
+
| `totalreclaw_recall` | `query`, optional `k` (default 8, max 20) |
|
|
66
|
+
| `totalreclaw_forget` | `factId` |
|
|
67
|
+
| `totalreclaw_pin` / `totalreclaw_unpin` | `factId`, optional `reason` |
|
|
68
|
+
| `totalreclaw_retype` | `factId`, `newType` |
|
|
69
|
+
| `totalreclaw_set_scope` | `factId`, `scope` |
|
|
70
|
+
| `totalreclaw_export` | optional `format` (`json` / `markdown`) |
|
|
71
|
+
| `totalreclaw_status` | (none) |
|
|
72
|
+
| `totalreclaw_upgrade` | (none) |
|
|
73
|
+
| `totalreclaw_migrate` | optional `confirm` (dry-run by default) |
|
|
74
|
+
| `totalreclaw_import_from` / `totalreclaw_import_batch` | `source`, `file_path` or `content`, `dry_run` |
|
|
75
|
+
| `totalreclaw_consolidate` | optional `dry_run` |
|
|
76
|
+
| `totalreclaw_onboarding_start` / `totalreclaw_onboard` | (none) — returns CLI pointer |
|
|
77
|
+
| `totalreclaw_pair` | optional `mode` (`generate` / `import`) — returns `{url, pin, qr_ascii, expires_at_ms}` |
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
openclaw totalreclaw onboard
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
This runs a terminal wizard. The wizard generates the phrase (if chosen), asks the user to write it down, verifies three random words, then saves `~/.totalreclaw/credentials.json`. The phrase never leaves the user's terminal.
|
|
79
|
+
## Taxonomy
|
|
75
80
|
|
|
76
|
-
**
|
|
77
|
-
|
|
78
|
-
```sh
|
|
79
|
-
openclaw totalreclaw onboard --non-interactive --json --mode generate
|
|
80
|
-
```
|
|
81
|
+
**Types:** `claim` (default) / `preference` / `directive` (reusable rule) / `commitment` (future intent) / `episode` (event) / `summary` (derived synthesis).
|
|
81
82
|
|
|
82
|
-
|
|
83
|
+
**Scopes:** `work` / `personal` (default) / `health` / `family` / `creative` / `finance` / `misc`.
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
For restore:
|
|
87
|
-
|
|
88
|
-
```sh
|
|
89
|
-
openclaw totalreclaw onboard --non-interactive --json --mode restore --phrase "word1 word2 ..."
|
|
90
|
-
```
|
|
85
|
+
## If a tool fails
|
|
91
86
|
|
|
92
|
-
|
|
87
|
+
- Tell the user plainly. Don't retry blindly.
|
|
88
|
+
- "onboarding required" -> route per Setup-state above.
|
|
89
|
+
- "No LLM available for auto-extraction" (startup only, v3.3.1+) -> provider key not reachable. Point at `~/.openclaw/agents/<agent>/agent/auth-profiles.json` or the `plugins.entries.totalreclaw.config.extraction.llm` override.
|
|
90
|
+
- Silent extraction failures -> suggest `openclaw totalreclaw status` or check `~/.totalreclaw/billing-cache.json` for rate-limit signals.
|
|
93
91
|
|
|
94
|
-
|
|
92
|
+
## Minimum viable interaction pattern
|
|
95
93
|
|
|
96
|
-
```sh
|
|
97
|
-
openclaw totalreclaw pair generate
|
|
98
|
-
# or for agent-driven:
|
|
99
|
-
openclaw totalreclaw pair generate --json
|
|
100
94
|
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
| Name | Type | Required | Description |
|
|
117
|
-
|------|------|----------|-------------|
|
|
118
|
-
| text | string | Yes | The fact or information to remember |
|
|
119
|
-
| type | string | No | Type of memory: `claim`, `preference`, `directive`, `commitment`, `episode`, `summary`. Default: `claim` |
|
|
120
|
-
| importance | integer | No | 1-10. Default: auto-detected by extraction LLM |
|
|
121
|
-
|
|
122
|
-
**Returns:** `{ factId, status: "stored", importance, encrypted: true }`
|
|
123
|
-
|
|
124
|
-
### totalreclaw_recall
|
|
125
|
-
|
|
126
|
-
Search and retrieve relevant memories from long-term storage.
|
|
127
|
-
|
|
128
|
-
**Parameters:**
|
|
129
|
-
|
|
130
|
-
| Name | Type | Required | Description |
|
|
131
|
-
|------|------|----------|-------------|
|
|
132
|
-
| query | string | Yes | Natural language query |
|
|
133
|
-
| k | integer | No | Results to return. Default 8, max 20 |
|
|
134
|
-
|
|
135
|
-
**Returns:** `{ memories: [{ id, text, type, importance, score }], count }`
|
|
136
|
-
|
|
137
|
-
### totalreclaw_forget
|
|
138
|
-
|
|
139
|
-
Soft-delete a specific fact.
|
|
140
|
-
|
|
141
|
-
**Parameters:** `{ factId: string }` — the UUID of the fact to delete.
|
|
142
|
-
|
|
143
|
-
### totalreclaw_pin
|
|
144
|
-
|
|
145
|
-
Pin a memory so auto-resolution can never supersede it. Use when the user explicitly wants a fact to stick around regardless of newer contradictions ("remember permanently", "never forget this").
|
|
146
|
-
|
|
147
|
-
**Parameters:** `{ factId: string, reason?: string }`
|
|
148
|
-
|
|
149
|
-
### totalreclaw_unpin
|
|
150
|
-
|
|
151
|
-
Remove a pin, returning the memory to normal decay / resolution.
|
|
152
|
-
|
|
153
|
-
**Parameters:** `{ factId: string }`
|
|
154
|
-
|
|
155
|
-
### totalreclaw_retype
|
|
156
|
-
|
|
157
|
-
Change the v1 taxonomy type of an existing memory (e.g. reclassify a misdetected `claim` as a `preference`).
|
|
158
|
-
|
|
159
|
-
**Parameters:** `{ factId: string, newType: "claim"|"preference"|"directive"|"commitment"|"episode"|"summary" }`
|
|
160
|
-
|
|
161
|
-
### totalreclaw_set_scope
|
|
162
|
-
|
|
163
|
-
Set the memory scope — `personal` (private to this user) or `shared` (available to delegates).
|
|
164
|
-
|
|
165
|
-
**Parameters:** `{ factId: string, scope: "personal"|"shared" }`
|
|
166
|
-
|
|
167
|
-
### totalreclaw_export
|
|
168
|
-
|
|
169
|
-
Export all memories in plaintext.
|
|
170
|
-
|
|
171
|
-
**Parameters:** `{ format?: "json"|"markdown" }` — default `json`
|
|
172
|
-
|
|
173
|
-
### totalreclaw_status
|
|
174
|
-
|
|
175
|
-
Check billing + subscription status.
|
|
176
|
-
|
|
177
|
-
**Parameters:** `{}` (no arguments)
|
|
178
|
-
|
|
179
|
-
**Returns:** `{ tier, quota, usage, resetsAt, upgradeUrl? }`
|
|
180
|
-
|
|
181
|
-
### totalreclaw_upgrade
|
|
182
|
-
|
|
183
|
-
Get a Stripe checkout URL to upgrade to Pro (unlimited memories on Gnosis mainnet).
|
|
184
|
-
|
|
185
|
-
**Parameters:** `{}`
|
|
186
|
-
|
|
187
|
-
### totalreclaw_migrate
|
|
188
|
-
|
|
189
|
-
Migrate testnet (Base Sepolia) memories to mainnet (Gnosis) after upgrading to Pro.
|
|
190
|
-
|
|
191
|
-
**Parameters:** `{ confirm?: boolean }` — dry-run by default; set `confirm: true` to execute.
|
|
192
|
-
|
|
193
|
-
### totalreclaw_import_from
|
|
194
|
-
|
|
195
|
-
Import memories from other agent-memory tools (Mem0, MCP Memory Server, etc.).
|
|
196
|
-
|
|
197
|
-
**Parameters:** `{ source, api_key?, source_user_id?, content?, file_path?, namespace?, dry_run? }`
|
|
198
|
-
|
|
199
|
-
### totalreclaw_consolidate
|
|
200
|
-
|
|
201
|
-
Scan all memories and merge near-duplicates.
|
|
202
|
-
|
|
203
|
-
**Parameters:** `{ dry_run?: boolean }`
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## When to Use Each Tool
|
|
208
|
-
|
|
209
|
-
### totalreclaw_remember
|
|
210
|
-
|
|
211
|
-
Use when:
|
|
212
|
-
- The user explicitly asks you to remember something ("remember that...", "note that...", "don't forget...")
|
|
213
|
-
- You detect a significant preference, decision, or fact useful in future conversations
|
|
214
|
-
- The user corrects or updates previous information about themselves
|
|
215
|
-
- You observe important context about the user's work, projects, or preferences
|
|
216
|
-
|
|
217
|
-
Do NOT use for:
|
|
218
|
-
- Temporary info only relevant to the current turn
|
|
219
|
-
- Things the user explicitly says are temporary
|
|
220
|
-
- Generic knowledge that isn't user-specific
|
|
221
|
-
|
|
222
|
-
### totalreclaw_recall
|
|
223
|
-
|
|
224
|
-
Use when:
|
|
225
|
-
- The user asks about their past preferences, decisions, or history
|
|
226
|
-
- You need context about their projects, tools, or working style
|
|
227
|
-
- The user asks "do you remember..." or "what did I tell you about..."
|
|
228
|
-
- You're unsure about a preference and want to check before assuming
|
|
229
|
-
- Starting a new conversation to load relevant context
|
|
230
|
-
|
|
231
|
-
Do NOT use for:
|
|
232
|
-
- Every single message — use sparingly, at most once per conversation start or when explicitly relevant
|
|
233
|
-
- General knowledge questions unrelated to the user
|
|
234
|
-
|
|
235
|
-
### totalreclaw_pin / totalreclaw_unpin
|
|
236
|
-
|
|
237
|
-
Use `pin` when the user says something like "remember this permanently", "always keep this", or "this is important — don't forget". Use `unpin` when they say "you can forget that", "it's no longer relevant", etc.
|
|
238
|
-
|
|
239
|
-
### totalreclaw_set_scope
|
|
240
|
-
|
|
241
|
-
Use when the user indicates a memory should be shared with delegates ("share this with my team", "make this visible to everyone I work with") or scoped back to personal ("only for me", "private").
|
|
242
|
-
|
|
243
|
-
---
|
|
244
|
-
|
|
245
|
-
## Configuration
|
|
246
|
-
|
|
247
|
-
All configuration lives under `plugins.entries.totalreclaw.config.*` in the OpenClaw config. The full 3.3.1 schema:
|
|
248
|
-
|
|
249
|
-
```yaml
|
|
250
|
-
plugins:
|
|
251
|
-
entries:
|
|
252
|
-
totalreclaw:
|
|
253
|
-
config:
|
|
254
|
-
# Public URL for QR pairing (optional — auto-detected if Tailscale or LAN)
|
|
255
|
-
publicUrl: https://gateway.example.com:18789
|
|
256
|
-
|
|
257
|
-
# Extraction tuning (all optional)
|
|
258
|
-
extraction:
|
|
259
|
-
enabled: true # default true
|
|
260
|
-
interval: 3 # turns between auto-extractions
|
|
261
|
-
maxFactsPerExtraction: 15 # hard cap per turn
|
|
262
|
-
model: glm-4.5-flash # shorthand override (just the model id)
|
|
263
|
-
llm: # full provider override block
|
|
264
|
-
provider: zai # zai|openai|anthropic|gemini|groq|deepseek|mistral|openrouter|xai|together|cerebras
|
|
265
|
-
model: glm-4.5-flash
|
|
266
|
-
apiKey: <your-key>
|
|
267
|
-
baseUrl: https://api.z.ai/api/coding/paas/v4 # self-hosted / custom gateway only
|
|
95
|
+
User: "I live in Porto and prefer PostgreSQL."
|
|
96
|
+
-> totalreclaw_remember({text: "User lives in Porto", type: "claim"})
|
|
97
|
+
-> totalreclaw_remember({text: "User prefers PostgreSQL over MySQL", type: "preference"})
|
|
98
|
+
-> respond naturally, don't list what you just saved.
|
|
99
|
+
|
|
100
|
+
User: "What do you remember about me?"
|
|
101
|
+
-> totalreclaw_recall({query: "user facts preferences identity"})
|
|
102
|
+
-> summarize returned facts in your reply.
|
|
103
|
+
|
|
104
|
+
User: "Set me up for TotalReclaw."
|
|
105
|
+
-> check ~/.totalreclaw/credentials.json. If missing:
|
|
106
|
+
local: totalreclaw_onboarding_start (or totalreclaw_onboard)
|
|
107
|
+
remote: totalreclaw_pair -> present URL + PIN + QR
|
|
108
|
+
-> follow the tool's instructions. Never invent a phrase.
|
|
268
109
|
```
|
|
269
110
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
TotalReclaw needs a small LLM to extract facts from conversations. Resolution order (highest priority first):
|
|
273
|
-
|
|
274
|
-
1. **Plugin config** — `plugins.entries.totalreclaw.config.extraction.llm.{provider,apiKey}`
|
|
275
|
-
2. **OpenClaw provider config** — `api.config.models.providers`
|
|
276
|
-
3. **OpenClaw auth profiles** — keys stored in `~/.openclaw/agents/<agent>/agent/auth-profiles.json`. This is where most users have their provider keys; 3.3.1 added it as a resolution tier.
|
|
277
|
-
4. **Environment variables** — `ZAI_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, `GROQ_API_KEY`, `DEEPSEEK_API_KEY`, `MISTRAL_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`, `TOGETHER_API_KEY`, `CEREBRAS_API_KEY`
|
|
278
|
-
|
|
279
|
-
If none of these resolve, auto-extraction is cleanly disabled and a single INFO message is logged at startup — manual `totalreclaw_remember` still works.
|
|
280
|
-
|
|
281
|
-
### QR Pairing URL Resolution
|
|
282
|
-
|
|
283
|
-
For `openclaw totalreclaw pair generate`, the gateway's externally-reachable URL is resolved in this order:
|
|
284
|
-
|
|
285
|
-
1. `plugins.entries.totalreclaw.config.publicUrl` — explicit override
|
|
286
|
-
2. `gateway.remote.url` — OpenClaw's own remote-gateway URL
|
|
287
|
-
3. `gateway.bind === 'custom'` + `gateway.customBindHost`
|
|
288
|
-
4. Tailscale MagicDNS auto-detect (`tailscale status --json` → `https://<magicdns>`, assumes `tailscale serve` on 443)
|
|
289
|
-
5. LAN IPv4 auto-detect — first non-loopback non-virtual interface (warns: only reachable from same network)
|
|
290
|
-
6. `http://localhost:<port>` fallback (warns: only works on this machine)
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
## Security
|
|
295
|
-
|
|
296
|
-
1. **E2EE** — all memories are encrypted client-side with XChaCha20-Poly1305. The server never sees plaintext.
|
|
297
|
-
2. **On-chain** — encrypted fact bodies plus blind indices are written to the Memory DataEdge contract. Free tier = Base Sepolia (84532); Pro tier = Gnosis mainnet (100).
|
|
298
|
-
3. **Recovery phrase stays local** — it lives only in `~/.totalreclaw/credentials.json` with mode 0600 and in the user's own backup. Never in chat, never in the session transcript, never in an LLM request.
|
|
299
|
-
4. **QR pairing crypto** — gateway ephemeral x25519 keypair; browser derives shared secret and encrypts the phrase with ChaCha20-Poly1305 before upload. Gateway private key never leaves disk.
|
|
300
|
-
|
|
301
|
-
### What NOT to do
|
|
302
|
-
|
|
303
|
-
- Do NOT write facts or preferences to `MEMORY.md`. TotalReclaw handles all memory storage with E2EE; cleartext files defeat the encryption guarantee.
|
|
304
|
-
- Do NOT call `totalreclaw_remember` for temporary or in-session context.
|
|
305
|
-
- Do NOT paste recovery phrases or API keys into chat replies to "help" the user — that echoes them into the LLM log.
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Memory Types (v1 Taxonomy)
|
|
310
|
-
|
|
311
|
-
TotalReclaw v1 uses six canonical types:
|
|
312
|
-
|
|
313
|
-
| Type | Description | Example |
|
|
314
|
-
|------|-------------|---------|
|
|
315
|
-
| claim | Objective assertion about the user / world | "Lives in Lisbon, Portugal" |
|
|
316
|
-
| preference | Likes, dislikes, choices | "Prefers dark mode in all applications" |
|
|
317
|
-
| directive | Instruction the user gave to remember / enforce | "Always use TypeScript for new projects" |
|
|
318
|
-
| commitment | Promise or commitment the user made | "Will deploy v1 to mainnet by end of Q1" |
|
|
319
|
-
| episode | Notable event or experience | "Deployed v1.0 to production on March 15" |
|
|
320
|
-
| summary | Key outcomes from discussions | "Agreed to use phased rollout for mainnet migration" |
|
|
321
|
-
|
|
322
|
-
The extraction LLM auto-selects the type. Use `totalreclaw_retype` if you detect a classification error.
|
|
323
|
-
|
|
324
|
-
---
|
|
325
|
-
|
|
326
|
-
## Troubleshooting
|
|
327
|
-
|
|
328
|
-
- **`plugins.allow is empty`** — OpenClaw warning, not a TotalReclaw bug. Either add the plugin to your allowlist or ignore it; TotalReclaw still works.
|
|
329
|
-
- **`TotalReclaw extraction LLM: not configured`** at startup — auto-extraction is disabled because no provider key was found. Configure a provider in `~/.openclaw/agents/<agent>/agent/auth-profiles.json`, or set `plugins.entries.totalreclaw.config.extraction.llm.{provider,apiKey}`. Manual `totalreclaw_remember` still works.
|
|
330
|
-
- **Tool call returns "onboarding required"** — run `openclaw totalreclaw onboard` on the host, OR `openclaw totalreclaw pair generate` if the gateway is remote.
|
|
331
|
-
- **`invalid config: must NOT have additional properties`** — your config references a key the plugin doesn't accept. The 3.3.1 schema is listed above; earlier schemas rejected `publicUrl` and most `extraction.*` keys (fixed in 3.3.1).
|
|
332
|
-
- **Routes return 404 after `plugins install`** — you need to restart the gateway. `openclaw restart` or `docker restart openclaw-qa`.
|
|
333
|
-
|
|
334
|
-
---
|
|
335
|
-
|
|
336
|
-
## Plugin architecture (informational)
|
|
337
|
-
|
|
338
|
-
- `index.ts` — plugin entry; registers tools, hooks, CLI, HTTP routes, and the slash command `/totalreclaw`.
|
|
339
|
-
- `llm-client.ts` + `llm-profile-reader.ts` — LLM auto-resolution cascade (3.3.1).
|
|
340
|
-
- `gateway-url.ts` — Tailscale / LAN host autodetect for pairing URLs.
|
|
341
|
-
- `pair-http.ts` — `/plugin/totalreclaw/pair/{finish,start,respond,status}` HTTP routes.
|
|
342
|
-
- `pair-cli.ts` — `openclaw totalreclaw pair [generate|import]` CLI, with `--json` and `--timeout` in 3.3.1.
|
|
343
|
-
- `onboarding-cli.ts` — `openclaw totalreclaw onboard` CLI, with `--non-interactive / --json / --mode / --phrase / --emit-phrase` in 3.3.1.
|
|
344
|
-
- `config.ts` — centralized env-var reads (keeps scanner surface clean).
|
|
111
|
+
## What NOT to do
|
|
345
112
|
|
|
346
|
-
|
|
113
|
+
- Do NOT write memories to `MEMORY.md` or any cleartext file — that defeats E2EE.
|
|
114
|
+
- Do NOT call `totalreclaw_remember` for transient in-session context.
|
|
115
|
+
- Do NOT paste recovery phrases or API keys into chat.
|
|
116
|
+
- Do NOT run `npx @totalreclaw/mcp-server setup` — deprecated path that corrupts credentials.
|
package/extractor.ts
CHANGED
|
@@ -754,7 +754,12 @@ export async function extractFactsForCompaction(
|
|
|
754
754
|
response = await chatCompletion(config, [
|
|
755
755
|
{ role: 'system', content: COMPACTION_SYSTEM_PROMPT },
|
|
756
756
|
{ role: 'user', content: userPrompt },
|
|
757
|
-
]
|
|
757
|
+
], {
|
|
758
|
+
// 3.3.1-rc.2: retry transient 429 / timeout (same policy as extractFacts).
|
|
759
|
+
retry: { attempts: 3, baseDelayMs: 1000 },
|
|
760
|
+
timeoutMs: 30_000,
|
|
761
|
+
logger,
|
|
762
|
+
});
|
|
758
763
|
} catch (err) {
|
|
759
764
|
const msg = err instanceof Error ? err.message : String(err);
|
|
760
765
|
logger?.warn?.(`extractFactsForCompaction: chatCompletion threw: ${msg}`);
|
|
@@ -907,7 +912,11 @@ export async function extractDebrief(
|
|
|
907
912
|
const response = await chatCompletion(config, [
|
|
908
913
|
{ role: 'system', content: systemPrompt },
|
|
909
914
|
{ role: 'user', content: `Review this conversation and provide a debrief:\n\n${conversationText}` },
|
|
910
|
-
]
|
|
915
|
+
], {
|
|
916
|
+
// 3.3.1-rc.2: retry transient 429 / timeout.
|
|
917
|
+
retry: { attempts: 3, baseDelayMs: 1000 },
|
|
918
|
+
timeoutMs: 30_000,
|
|
919
|
+
});
|
|
911
920
|
|
|
912
921
|
if (!response) return [];
|
|
913
922
|
return parseDebriefResponse(response);
|
|
@@ -1313,7 +1322,14 @@ export async function comparativeRescoreV1(
|
|
|
1313
1322
|
response = await chatCompletion(config, [
|
|
1314
1323
|
{ role: 'system', content: COMPARATIVE_PROMPT_V1 },
|
|
1315
1324
|
{ role: 'user', content: userPrompt },
|
|
1316
|
-
]
|
|
1325
|
+
], {
|
|
1326
|
+
// 3.3.1-rc.2: retry transient 429 / timeout (rescore is an inner
|
|
1327
|
+
// call after extractFacts — if extraction backs off successfully
|
|
1328
|
+
// the rescore usually also passes on first try, but keep symmetry).
|
|
1329
|
+
retry: { attempts: 3, baseDelayMs: 1000 },
|
|
1330
|
+
timeoutMs: 30_000,
|
|
1331
|
+
logger,
|
|
1332
|
+
});
|
|
1317
1333
|
} catch (err) {
|
|
1318
1334
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1319
1335
|
logger?.warn?.(`comparativeRescoreV1: chatCompletion threw: ${msg}`);
|
|
@@ -1422,7 +1438,15 @@ export async function extractFacts(
|
|
|
1422
1438
|
response = await chatCompletion(config, [
|
|
1423
1439
|
{ role: 'system', content: systemPrompt },
|
|
1424
1440
|
{ role: 'user', content: userPrompt },
|
|
1425
|
-
]
|
|
1441
|
+
], {
|
|
1442
|
+
// 3.3.1-rc.2: the headline fix for the rc.1 QA NO-GO — 5/6 extraction
|
|
1443
|
+
// windows failed on zai 429 + timeouts with no retry. 3 attempts with
|
|
1444
|
+
// 1s → 2s → 4s backoff recovers virtually all transient rate-limit
|
|
1445
|
+
// hiccups. Graceful timeout: per-attempt 30s, total worst-case 30+1+30+2+30+4≈97s.
|
|
1446
|
+
retry: { attempts: 3, baseDelayMs: 1000 },
|
|
1447
|
+
timeoutMs: 30_000,
|
|
1448
|
+
logger,
|
|
1449
|
+
});
|
|
1426
1450
|
} catch (err) {
|
|
1427
1451
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1428
1452
|
logger?.warn?.(`extractFacts: chatCompletion threw: ${msg}`);
|