@engramx/client 0.15.0-rc.3 → 0.16.0-rc.10
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/README.md +262 -26
- package/dist/EngramClient.d.ts +235 -229
- package/dist/EngramClient.js +446 -1247
- package/dist/EngramClient.js.map +1 -1
- package/dist/MarketClient.d.ts +137 -0
- package/dist/MarketClient.js +228 -0
- package/dist/MarketClient.js.map +1 -0
- package/dist/ProfileManager.d.ts +4 -4
- package/dist/SessionManager.d.ts +3 -3
- package/dist/SessionManager.js +1 -1
- package/dist/SessionManager.js.map +1 -1
- package/dist/actionReceipt.d.ts +67 -0
- package/dist/actionReceipt.js +76 -2
- package/dist/actionReceipt.js.map +1 -1
- package/dist/auth.d.ts +16 -0
- package/dist/auth.js +38 -5
- package/dist/auth.js.map +1 -1
- package/dist/certifiedAudit.d.ts +32 -6
- package/dist/certifiedAudit.js +75 -14
- package/dist/certifiedAudit.js.map +1 -1
- package/dist/cli.js +100 -26
- package/dist/cli.js.map +1 -1
- package/dist/encryption.d.ts +30 -12
- package/dist/encryption.js +13 -15
- package/dist/encryption.js.map +1 -1
- package/dist/idl.d.ts +69 -0
- package/dist/idl.js +242 -0
- package/dist/idl.js.map +1 -0
- package/dist/index.d.ts +12 -18
- package/dist/index.js +58 -9
- package/dist/index.js.map +1 -1
- package/dist/ledgerfsHash.js +1 -1
- package/dist/ledgerfsHash.js.map +1 -1
- package/dist/lineage.js +8 -5
- package/dist/lineage.js.map +1 -1
- package/dist/memoryArchive.d.ts +428 -0
- package/dist/memoryArchive.js +504 -0
- package/dist/memoryArchive.js.map +1 -0
- package/dist/migrate.js +31 -4
- package/dist/migrate.js.map +1 -1
- package/dist/openEngram.d.ts +55 -0
- package/dist/openEngram.js +185 -0
- package/dist/openEngram.js.map +1 -0
- package/dist/pair.d.ts +33 -2
- package/dist/pair.js +56 -9
- package/dist/pair.js.map +1 -1
- package/dist/types.d.ts +246 -307
- package/dist/version.d.ts +8 -0
- package/dist/version.js +45 -0
- package/dist/version.js.map +1 -0
- package/dist/wire.d.ts +76 -0
- package/dist/wire.js +79 -0
- package/dist/wire.js.map +1 -0
- package/package.json +11 -19
- package/dist/bootstrap.d.ts +0 -21
- package/dist/bootstrap.js +0 -71
- package/dist/bootstrap.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ TypeScript SDK for EngramX — persistent, decentralized memory for AI agents on
|
|
|
4
4
|
|
|
5
5
|
## What is this
|
|
6
6
|
|
|
7
|
-
EngramX (Engram Externalized)
|
|
7
|
+
EngramX (Engram Externalized) keeps an engram — its owner's memory, session history, wallet and record — in an ICP canister, and an AI agent paired with it reads and appends there. If the machine the agent runs on dies, gets hacked, or is replaced, the agent resumes on a new machine with the engram intact.
|
|
8
8
|
|
|
9
|
-
This package is the
|
|
9
|
+
This package is the SDK an agent uses to read and write the engram it is paired with.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -14,6 +14,10 @@ This package is the client SDK that agents use to read and write their engram.
|
|
|
14
14
|
pnpm add @engramx/client
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
⟨2026-10-02⟩ A release candidate is published under npm's `next` tag — `pnpm add @engramx/client@next`
|
|
18
|
+
— and `latest` is the last final release. A release candidate of 0.16.0 pairs only with a 0.16.0
|
|
19
|
+
engram (see "What you can actually call today" below).
|
|
20
|
+
|
|
17
21
|
## Quickstart
|
|
18
22
|
|
|
19
23
|
```typescript
|
|
@@ -22,7 +26,7 @@ import { EngramClient } from '@engramx/client';
|
|
|
22
26
|
const engram = new EngramClient({
|
|
23
27
|
canisterId: 'xxxxx-xxxxx-xxxxx-xxxxx-xxx',
|
|
24
28
|
sessionKeyPath: '~/.engramx/session.key',
|
|
25
|
-
clientLabel: 'my-agent', // identifies this
|
|
29
|
+
clientLabel: 'my-agent', // identifies this agent in the engram's cross-model reuse set
|
|
26
30
|
});
|
|
27
31
|
|
|
28
32
|
// At the START of a session: load everything the agent remembers, ready to inject as a
|
|
@@ -35,31 +39,99 @@ const ctx = await engram.startSession();
|
|
|
35
39
|
console.log(`loaded ${ctx.includedFiles}/${ctx.totalFiles} files`);
|
|
36
40
|
|
|
37
41
|
// AS THE AGENT WORKS: append (append-only; the canister concatenates the delta)
|
|
38
|
-
const
|
|
42
|
+
const receipt = await engram.appendMemory('memory/daily.md', '## Notes\nSomething happened.');
|
|
43
|
+
// receipt = { version, seq, head }. `head` is the audit-chain head this write advanced to, hex —
|
|
44
|
+
// the evidence the write landed, verifiable by a third party against the chain and its anchor.
|
|
45
|
+
// Carry it forward: reading the file back later returns content, not proof.
|
|
39
46
|
|
|
40
47
|
// Point reads: one file, or several at once
|
|
41
48
|
const file = await engram.readMemory('MEMORY.md');
|
|
42
49
|
const files = await engram.readMemoryBatch(['MEMORY.md', 'memory/daily.md']);
|
|
43
50
|
|
|
44
|
-
// Wallet reads need canReadWallet, which the DEFAULT
|
|
51
|
+
// Wallet reads need canReadWallet, which the DEFAULT agent grant does NOT include — the
|
|
45
52
|
// default is read + append memory, no wallet, deliberately. Ask the owner for a grant with
|
|
46
53
|
// wallet access before uncommenting:
|
|
47
54
|
// const balance = await engram.walletBalance();
|
|
48
55
|
```
|
|
49
56
|
|
|
57
|
+
### What you can actually call today (2026-08-17)
|
|
58
|
+
|
|
59
|
+
Two things in the snippet above are worth stating plainly rather than letting you discover them.
|
|
60
|
+
|
|
61
|
+
**`sessionSystemPrompt()` / `startSession()` work, and nothing in this repository calls them.**
|
|
62
|
+
They shipped in `0.15.0` and are in this release ⟨corrected 2026-10-02: this said 0.15.0 "is the
|
|
63
|
+
current `latest` on npm", which stops being true the moment 0.16.0 is promoted, and this README
|
|
64
|
+
ships inside the package⟩, so a new agent can call them today — notes elsewhere saying the
|
|
65
|
+
published package predates this surface are stale. But every
|
|
66
|
+
reference to them in this repo and in the dashboard is *teaching copy*: the connect guide, the
|
|
67
|
+
landing page snippet, the docs page. Every shipped consumer — the CLI, the stdio MCP server's
|
|
68
|
+
profile tools, the OpenClaw plugin — still reads memory the older way, with `readMemory`,
|
|
69
|
+
`readMemoryBatch` and `listMemoryFiles`. So: the API is real and supported, the on-chain reuse
|
|
70
|
+
accounting behind it is real, and you would be its first production caller. Treat the absence of an
|
|
71
|
+
in-repo consumer as a reason to report what breaks, not as a warning that it does not work.
|
|
72
|
+
|
|
73
|
+
The 2026-08-17 charter diet (below) deleted a lot of caller-less methods and **deliberately kept
|
|
74
|
+
these two.** Zero in-repo callers was the reason to look at them; it was not the reason to decide.
|
|
75
|
+
Three facts decided it. They are what `npx @engramx/mcp connect` *instructs* whoever builds a new
|
|
76
|
+
SDK-lane agent to call, verbatim, in the guide the dashboard's connect page renders — deleting a method
|
|
77
|
+
while still telling people to call it is the failure this whole exercise exists to prevent.
|
|
78
|
+
`startSession()` is the only read on the **update** path, so it is the only one the canister can
|
|
79
|
+
count toward the engram's cross-model reuse metric; a query read leaves no trace, because the IC
|
|
80
|
+
discards query-path state changes. And they are the difference between "load everything this agent
|
|
81
|
+
remembers" being one call or being a loop written by hand and subtly wrong.
|
|
82
|
+
An entry point with no in-repo caller is unexercised, not dead.
|
|
83
|
+
|
|
84
|
+
**`appendMemory` returns a receipt in this package, and a bare version number in `0.15.0`.** The
|
|
85
|
+
receipt is part of the 0.16.0 interface break this package carries ⟨corrected 2026-10-02 for the
|
|
86
|
+
0.16.0 release candidate's publish: this paragraph called the receipt a thing of "THIS tree" and the
|
|
87
|
+
break "unreleased", which the publish makes false; on 2026-09-30 it had pointed at a changelog in
|
|
88
|
+
the source, which is private during the beta⟩. Against `@engramx/client@0.15.0` the same call
|
|
89
|
+
answers `Promise<bigint>`, and `listBackups` answers a bare array instead of unwrapping a refusal.
|
|
90
|
+
An SDK from either side of that break does not interoperate with an engram from the other.
|
|
91
|
+
⟨corrected 2026-10-02: this ended "so upgrade the canister first and the SDK second" — there is no
|
|
92
|
+
upgrade across this break; 0.16.0 canisters are installed fresh, so pair this package only with a
|
|
93
|
+
0.16.0 engram, and keep the SDK and the canisters on the same side.⟩
|
|
94
|
+
|
|
50
95
|
## Pairing
|
|
51
96
|
|
|
52
|
-
|
|
97
|
+
Pair your agent with an engram:
|
|
53
98
|
|
|
54
99
|
```bash
|
|
55
|
-
# Pair this
|
|
56
|
-
pnpm dlx @engramx/client pair <invite-code> --engram <canister-id> --target openclaw
|
|
100
|
+
# Pair the agent on this machine with the engram and install the OpenClaw plugin
|
|
101
|
+
pnpm dlx @engramx/client@0.16.0-rc.10 pair <invite-code> --engram <canister-id> --target openclaw
|
|
57
102
|
|
|
58
|
-
# Replacement
|
|
103
|
+
# Replacement machine — after pairing, restore memory from the engram
|
|
59
104
|
pnpm dlx @engramx/client migrate --engram <canister-id> --recover
|
|
60
105
|
```
|
|
61
106
|
|
|
62
|
-
`pair` generates `~/.engramx/session.key
|
|
107
|
+
`pair` generates the key for this engram at `~/.engramx/session.key` (and, on the first pairing, the agent's lasting key at `~/.engramx/root.key`), pairs the agent — the CLI prints `Paired as an agent` — and installs the OpenClaw plugin. `migrate` then moves memory, saving a local checkpoint first — run `npx @engramx/client rollback` to undo. Its default direction pushes local memory files to the engram; `--recover` instead restores database backups, and memory files sync automatically on next OpenClaw startup.
|
|
108
|
+
|
|
109
|
+
⟨2026-09-29⟩ From code, pairing is one call: `EngramClient.pairAgent(inviteCode, root)`, or sign the
|
|
110
|
+
statement with `signEnrolment(root, engramId, key, inviteCode)` and call the engram's `pairAgent`
|
|
111
|
+
yourself. The statement no longer carries a `nonce`, and `pairEnrolled` — which re-signed when the
|
|
112
|
+
engram's signature check wrongly refused a valid statement — is no longer exported: ic402 2.16.1
|
|
113
|
+
fixed that check, so a refusal is final. An invite stops working after three failed checks.
|
|
114
|
+
|
|
115
|
+
### An engram of the agent's own ⟨2026-10-01⟩
|
|
116
|
+
|
|
117
|
+
If the owner of the wallet allows it (a standing allowance they set for this agent on the Access
|
|
118
|
+
page), the agent can open an engram of its own through the engram it works in. The owner may be a program. Whoever runs that program is the owner for every purpose on these pages.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npx @engramx/client open-engram --engram <canister-id>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The engram it works in pays to open it, from its own balance, and the agent's lasting key
|
|
125
|
+
(`~/.engramx/root.key`, or `--root-key <path>`) owns what is opened. Approving is giving: what was
|
|
126
|
+
paid in is the agent's from the moment the new engram exists, and nothing is taken back. The command
|
|
127
|
+
reads the allowance first and stops, with nothing spent, when there is none; it never creates a
|
|
128
|
+
lasting key; and it prints the engram's own sentence when the engram refuses. It then prints the
|
|
129
|
+
owner kit's command that acts as the new engram's owner with the same file —
|
|
130
|
+
`npx @engramx/owner --connect --key-file <that file> --registry <id>`, with both filled in — which
|
|
131
|
+
mints an invite for an agent to pair into it. The agent's lasting key is an owner key for the engram
|
|
132
|
+
it opened only; on the engram it works in it stays an agent. The agent's work in an engram its own
|
|
133
|
+
key owns is never counted on its track record. From code: `EngramClient.getChildAllowance(key)`,
|
|
134
|
+
`EngramClient.openChildEngram()`, or `openEngram(options, { io })`, which is the whole command.
|
|
63
135
|
|
|
64
136
|
## Guardian API
|
|
65
137
|
|
|
@@ -72,10 +144,152 @@ Internet Identity authentication. The SDK exposes the read-only side:
|
|
|
72
144
|
const guardians = await engram.listGuardians();
|
|
73
145
|
```
|
|
74
146
|
|
|
75
|
-
The
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
147
|
+
## The charter — who this SDK is for
|
|
148
|
+
|
|
149
|
+
`EngramClient` runs **on the machine an agent runs on, with that agent's key**. An agent is an AI
|
|
150
|
+
agent: a software program, not a person acting on someone's behalf. It is the append-only lane: read
|
|
151
|
+
memory, append to it, run backups, pay for services. The owner lane is a separate package
|
|
152
|
+
(`@engramx/owner`) so that an agent's machine never has owner powers to leak — that split is the
|
|
153
|
+
product, not packaging taste. ⟨2026-10-01⟩ An engram the agent opened with `open-engram` is
|
|
154
|
+
the one exception, and it is the agent's own: its lasting key owns that engram. Over the engram it
|
|
155
|
+
works in, it is still an agent.
|
|
156
|
+
|
|
157
|
+
The lines that hold, unconditionally:
|
|
158
|
+
|
|
159
|
+
- The most dangerous owner primitives are **not here and will not be**: `writeMemory` (whole-file
|
|
160
|
+
overwrite), `addGuardian`, `setProtectedPaths`, `setPaymentPolicy`, `resetMyEngram`. Those live in
|
|
161
|
+
the dashboard at engramx.ai and in `@engramx/owner`.
|
|
162
|
+
- Nothing on this class can widen its own grant. Every method is still gated in the canister by the
|
|
163
|
+
agent record the owner minted; the SDK is a convenience over a wire, never an authority.
|
|
164
|
+
|
|
165
|
+
**The class matched its charter on 2026-08-17.** An audit on 2026-08-16 counted 94 public methods,
|
|
166
|
+
of which 23 had a real (non-test) caller anywhere. The rest had accumulated: roughly two dozen
|
|
167
|
+
owner-console methods and a nearly complete ic402 marketplace library, unused by any shipped surface
|
|
168
|
+
— including the dashboard they deferred to. They were gated in the canister, so their presence
|
|
169
|
+
widened nobody's authority; what it did was make this README's claim about the SDK false. The owner
|
|
170
|
+
ratified the diet and it has landed: **94 public methods → 49**, and the Candid interface this SDK
|
|
171
|
+
declares to the canister went from 108 method names to 39.
|
|
172
|
+
|
|
173
|
+
**What left, so you can find it if you were calling it.**
|
|
174
|
+
|
|
175
|
+
> **⟨CORRECTED 2026-08-26.⟩** This paragraph used to say the methods behind *every* name below were
|
|
176
|
+
> "LIVE and unchanged — this removed the SDK's wrapper, not the surface", with `keccak256` as the
|
|
177
|
+
> single exception. Measured against the served `.did` files at 0.16.0, that was wrong for **29 of
|
|
178
|
+
> the 45 names**: 15 moved to the market canister, 14 are gone from both, and of the 16 that are
|
|
179
|
+
> still on the engram some were renamed. A reader following the old sentence would have built a raw
|
|
180
|
+
> Candid actor against methods that reject with `IC0536 method not found`, from a README that told
|
|
181
|
+
> them the surface was untouched. The four groups below are measured, not asserted.
|
|
182
|
+
|
|
183
|
+
**1. Still on the engram — a raw Candid actor or `@engramx/owner` reaches these.** Only the SDK
|
|
184
|
+
wrapper went. *(16 names)*
|
|
185
|
+
|
|
186
|
+
`listMemoryLog`, `exportMemoryRange`, `previewCondense`, `applyCondense`, `listMemoryExportReceipts`,
|
|
187
|
+
`listCondenseCheckpoints`, `repudiateMemoryWrite`, `getAgentWriteReview`,
|
|
188
|
+
`markAgentWritesReviewed`, `ownerWithdraw`, `deleteBackup`, `openSession`, `sessionReadMemory`,
|
|
189
|
+
`sessionAppendMemory`, `getEngramCard`, `getEvmAddress`
|
|
190
|
+
|
|
191
|
+
⟨2026-09-29⟩ Three of these are served under new names since the vocabulary change: the SDK's
|
|
192
|
+
`getOperatorWriteReview`, `markOperatorWritesReviewed` and `getAgentCard` are the engram's
|
|
193
|
+
`getAgentWriteReview`, `markAgentWritesReviewed` and `getEngramCard` (the vocabulary change: owner,
|
|
194
|
+
agent, guardian).
|
|
195
|
+
|
|
196
|
+
⟨2026-10-07⟩ The memory-log walk is still exported, as a module function rather than a class method:
|
|
197
|
+
`assembleMemoryArchive(fetchPage, options)` takes the engram's own `listMemoryLog` as `fetchPage` —
|
|
198
|
+
an owner-authenticated actor's, bound (`actor.listMemoryLog.bind(actor)`) — reads the page exactly as
|
|
199
|
+
the engram serves it (`{ firstAvailableSeq; head; page : { items; total; withheld } }`, advancing by
|
|
200
|
+
`items.length + withheld`), and `verifyMemoryArchive` checks the archive against an export receipt.
|
|
201
|
+
The `assembleMemoryArchive` in group 4 below is the class method that left.
|
|
202
|
+
|
|
203
|
+
**2. Renamed on the engram — the capability survives under a new name.** *(4 names)*
|
|
204
|
+
|
|
205
|
+
| you called | call instead |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `getRepudiations` | `listRepudiations` |
|
|
208
|
+
| `storageStats` | `getStorageStats` |
|
|
209
|
+
| `getPaymentRequirements` | `previewOpenSession` |
|
|
210
|
+
| `requestSession` | `previewOpenSession` |
|
|
211
|
+
|
|
212
|
+
**3. Moved to the MARKET canister — which is NOT DEPLOYED at 0.16.0.** The commerce surface was
|
|
213
|
+
extracted from the engram into a separate canister, and that canister is deliberately withheld from
|
|
214
|
+
this release. **These names are unreachable today at any address**, and two were renamed in the move
|
|
215
|
+
as well, so they will not answer even once a market exists. *(15 names)*
|
|
216
|
+
|
|
217
|
+
`endSession`, `forceCloseSession`, `uploadContent`, `listContent`, `getContent`, `deleteContent`,
|
|
218
|
+
`createEndpoint`, `listEndpoints`, `getRevenueSummary`, `registerService`, `claimJob`,
|
|
219
|
+
`submitJobResult`, `listJobs`, `getJobStatus`, `getPaymentPolicy`
|
|
220
|
+
— plus `listAllServices` → `listServices` and `getEndpointPurchases` → `listEndpointPurchases`,
|
|
221
|
+
and `uploadContentChunked` / `getContentWithPayment`, whose jobs are now done by `uploadContent`
|
|
222
|
+
and `getContent` there.
|
|
223
|
+
|
|
224
|
+
**4. Gone entirely — no canister serves these and none is planned.** *(the remainder)*
|
|
225
|
+
|
|
226
|
+
`assembleMemoryArchive`, `exportMemoryArchive`, `openPaymentSession`, `createPaymentClient`,
|
|
227
|
+
`submitServiceRequest`, `keccak256`. `getOwnerEvmAddress` folded into `getEvmAddress`.
|
|
228
|
+
|
|
229
|
+
⚠ **`openSession` is on the engram and `endSession` is on the withheld market.** If you open a paid
|
|
230
|
+
session today there is no served method to close it. That asymmetry is a known open issue, not a
|
|
231
|
+
documentation error — do not build a paid flow on it yet.
|
|
232
|
+
|
|
233
|
+
⟨CORRECTED 2026-09-30⟩ "There is no served method to close it" is untrue: the engram serves
|
|
234
|
+
`closeSession`, called by whoever paid for the session (it settles what was spent and refunds the
|
|
235
|
+
rest), and `sysForceCloseSession`, the owner's close for a session whoever paid for it abandoned. The market's
|
|
236
|
+
`endSession` was never the way to close an engram's session.
|
|
237
|
+
|
|
238
|
+
| family | removed from this class |
|
|
239
|
+
|---|---|
|
|
240
|
+
| Memory archive (owner-only on the canister) | `listMemoryLog`, `exportMemoryRange`, `previewCondense`, `applyCondense`, `listMemoryExportReceipts`, `listCondenseCheckpoints`, `assembleMemoryArchive`, `exportMemoryArchive` |
|
|
241
|
+
| Dispute + review | `repudiateMemoryWrite`, `getRepudiations`, `getOperatorWriteReview`, `markOperatorWritesReviewed` |
|
|
242
|
+
| Owner money + storage | `ownerWithdraw`, `storageStats`, `deleteBackup` |
|
|
243
|
+
| ic402 sessions | `getPaymentRequirements`, `requestSession`, `openSession`, `sessionReadMemory`, `sessionAppendMemory`, `endSession`, `forceCloseSession`, `openPaymentSession`, `createPaymentClient` |
|
|
244
|
+
| ic402 content store | `uploadContent`, `uploadContentChunked`, `listContent`, `getContent`, `getContentWithPayment`, `deleteContent` |
|
|
245
|
+
| x402 endpoint registry | `createEndpoint`, `listEndpoints`, `getEndpointPurchases`, `getRevenueSummary` |
|
|
246
|
+
| Marketplace seller side | `registerService`, `listAllServices`, `submitServiceRequest`, `claimJob`, `submitJobResult`, `listJobs`, `getJobStatus` |
|
|
247
|
+
| Misc reads | `getPaymentPolicy`, `getAgentCard`, `getEvmAddress`, `getOwnerEvmAddress` |
|
|
248
|
+
| Module exports | `loadBootstrapConfig` / `saveBootstrapConfig` (no importer in either repo; `saveBootstrapConfig` reached `writeMemory` through an `as unknown as` cast around the very surface this class withholds); the `Vault*` deprecation aliases; the blind `@ic402/client` re-export block — depend on `@ic402/client` directly if you want it, and pin its version yourself |
|
|
249
|
+
|
|
250
|
+
**`keccak256` is the exception: there is no canister method to fall back to** *(corrected
|
|
251
|
+
2026-08-17 — this row sat in the table above under the claim that its canister method was live,
|
|
252
|
+
which was false)*. The engram removed the public `keccak256` query on 2026-08-17 in the same diet.
|
|
253
|
+
It was a consensus round trip, paid for and replicated, to hash bytes the caller already holds, so
|
|
254
|
+
**compute it locally instead** — `import { keccak256 } from 'viem'` (what the EVM e2e suite already
|
|
255
|
+
does), or any keccak library in your language. The Motoko library function
|
|
256
|
+
(`Ic402.EvmAddress.keccak256`) is untouched and still backs the in-canister EIP-191/EIP-712 digests;
|
|
257
|
+
only the public door is gone. Nothing you can compute locally changed value.
|
|
258
|
+
|
|
259
|
+
One thing was **added**, and it is verification-side: `verifyActionReceipt` (with `actionMessage`,
|
|
260
|
+
`actionFields` and the `ActionAuth` type) is now exported from the package entry point. The party
|
|
261
|
+
who needs to check an owner-action receipt is whoever checks the record, reading the audit log, not
|
|
262
|
+
the party that signed it — and until now the only way to reach that verifier was through `ownerWithdraw`, a
|
|
263
|
+
method for signing one. *⟨2026-10-01⟩* `verifyActionReceipt` checks a receipt exactly as the engram
|
|
264
|
+
does — strict RFC 8032, refusing a small-order key, a non-canonical point and a signature with S ≥ L
|
|
265
|
+
— so a receipt verifies here if and only if the engram would have accepted it.
|
|
266
|
+
|
|
267
|
+
One thing was **fixed** on the way past. The SDK declares a subset of the engram's Candid interface,
|
|
268
|
+
and `getEncryptedMemoryKeyForEpoch` was missing from it. `encryption.ts` feature-detects that method
|
|
269
|
+
and, not finding it, refused post-key-rotation content with *"this engram predates epoch-aware
|
|
270
|
+
derivation"* — a sentence that was false for every engram, because the absence was in this package,
|
|
271
|
+
not on the canister. Declaring the name makes the detect able to succeed.
|
|
272
|
+
|
|
273
|
+
**One family that should have gone did not: the encryption owner controls.** `setMemoryEncryption`,
|
|
274
|
+
`migrateMemoryToEncrypted` and `migrateMemoryToPlaintext` are owner-shaped by every test above — the
|
|
275
|
+
toggle is owner-gated and the migrations rewrite whole files through `writeMemory`, which this class
|
|
276
|
+
does not expose. They stayed because the encryption runbook instructs whoever migrates an engram to run
|
|
277
|
+
`EngramClient.migrateMemoryToEncrypted()` **by name**, under a section of cautions worth keeping.
|
|
278
|
+
Deleting a method a runbook tells people to call, while the runbook still tells them to call it, is
|
|
279
|
+
worse than the blemish. Moving the family to `@engramx/owner` is a two-repo change: the doc rider
|
|
280
|
+
first, then the methods.
|
|
281
|
+
|
|
282
|
+
**The removals are a break.** A method this class no longer has fails at the call site, loudly,
|
|
283
|
+
with a `TypeError`; a method the SDK no longer *declares* to the canister fails as a catchable
|
|
284
|
+
`IC0536` reject rather than a decode trap. Neither corrupts data, and both ride the next interface
|
|
285
|
+
cut rather than a patch release. `@engramx/client@0.15.0` on npm still has all of them.
|
|
286
|
+
|
|
287
|
+
**What survives, and the rule that keeps it that way.** Memory core, session start, history and
|
|
288
|
+
ranged/versioned reads, `reviseMemory`, the audit and certified-head reads, guardian and
|
|
289
|
+
approval-request reads, an agent's key-hash rotation, the whole backup lane, and the BUYER half of the
|
|
290
|
+
marketplace: `listServices` → `submitServiceRequestWithPayment` → `pollJobResult`/`getJob` →
|
|
291
|
+
`getJobResult`, with `confirmJob`/`disputeJob` to settle. From here, no method returns to this class
|
|
292
|
+
without a named caller. "A seller might want it" is how the last two dozen got here.
|
|
79
293
|
|
|
80
294
|
## Backup API
|
|
81
295
|
|
|
@@ -104,6 +318,13 @@ const backups = await engram.listBackups('sqlite');
|
|
|
104
318
|
const data = await engram.pullBackupChunk(backupId, 0);
|
|
105
319
|
```
|
|
106
320
|
|
|
321
|
+
`listBackups` **throws on refusal rather than returning `[]`.** An empty array is a claim about the
|
|
322
|
+
engram ("you have no backups"); a refusal is a claim about the caller ("you may not read this"), and
|
|
323
|
+
conflating them is how a destructive restore gets invited. Note that listing needs `canReadBackup`,
|
|
324
|
+
which the default connect-an-agent grant leaves unset — `initBackup`/`pushBackupChunk` need only
|
|
325
|
+
`canAppendMemory`, so an agent can *write* backups it cannot *list* until the owner widens the grant.
|
|
326
|
+
The refusal names the missing permission.
|
|
327
|
+
|
|
107
328
|
## Verify canonical lineage
|
|
108
329
|
|
|
109
330
|
An engram's own `getSpawnedBy()` is a self-report — any fork can claim any spawner.
|
|
@@ -128,24 +349,39 @@ const verdict = await verifyCanonicalLineage(engramId, agent);
|
|
|
128
349
|
// false on a managed engram usually just means one release behind, not suspect.
|
|
129
350
|
```
|
|
130
351
|
|
|
131
|
-
The canonical registry id ships in the SDK as `CANONICAL_REGISTRY_CANISTER_ID
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
different fleet (e.g. staging); the answer is then
|
|
135
|
-
canonicity.
|
|
352
|
+
The canonical registry id ships in the SDK as `CANONICAL_REGISTRY_CANISTER_ID`; it is set to the
|
|
353
|
+
live production registry, so a call with no explicit registry asks the canonical fleet. (If it were
|
|
354
|
+
ever empty again, such a call would report `'indeterminate'` by design — the SDK never guesses at
|
|
355
|
+
canonicity.) Pass `{ registryId }` to ask a different fleet (e.g. staging); the answer is then
|
|
356
|
+
_that fleet's_ testimony, not canonicity.
|
|
136
357
|
|
|
137
358
|
## OpenClaw Integration
|
|
138
359
|
|
|
139
|
-
The `--target openclaw` option on `pair` handles plugin installation and `openclaw.json` configuration automatically. For manual setup or customization, see
|
|
360
|
+
The `--target openclaw` option on `pair` handles plugin installation and `openclaw.json` configuration automatically. For manual setup or customization, see the README of the `@engramx/openclaw` package on npm.
|
|
361
|
+
|
|
362
|
+
## Maturity of the payment and identity surfaces
|
|
363
|
+
|
|
364
|
+
Verified against the canister interface on 2026-08-16. "Stubbed" was doing too much work here, so
|
|
365
|
+
each surface now says what it actually does.
|
|
140
366
|
|
|
141
|
-
|
|
367
|
+
| Surface | State |
|
|
368
|
+
|---|---|
|
|
369
|
+
| **x402 payments — Internet Computer rail** | **Not reachable at 0.16.0.** ICRC-2 approve-and-transfer in ckUSDC. `MarketClient.createJob` settles at submit time and is what the stdio MCP money tools call; it addresses the market canister, which is not in this release (section 3 above). |
|
|
370
|
+
| **x402 payments — EVM rail** | **Implemented, unfunded on mainnet.** EIP-3009 USDC across the five chains in `Env.mo`. Signing and settlement paths exist; there is no funded production traffic, so treat it as untested in anger. |
|
|
371
|
+
| **World ID** | **Live**, as shipped: proof submission, RP-context and verification reads, and the HTTP-outcall transform are all on the interface, with a wired dashboard. |
|
|
372
|
+
| **ERC-8004 listing of the engram** | **Sign-only.** The canister signs its own registration transaction (`signEngramRegistration`) for you to broadcast; it lists the engram, never an agent. It does not broadcast, and it does not track registration state. |
|
|
373
|
+
| **Autonomous outbound spending (tECDSA)** | **Served, inside the owner's limits.** The engram signs stablecoin payment authorisations on EVM chains on an agent's request (`signX402Payment`), within the per-agent limits, the engram-wide daily ceiling and the daily signature count; the signing key is a threshold key derived to the canister, so no single party holds it. ⟨Corrected 2026-09-30. This row said "Dormant by choice. Single-key custody is a total-loss risk; not funded on mainnet." — untrue of the code: the path is live and the key is threshold-derived. What is still yours to do is fund the address you mean to pay from.⟩ |
|
|
142
374
|
|
|
143
|
-
|
|
375
|
+
⟨CORRECTED 2026-09-30⟩ The first row said "Live" and listed two tokens besides ckUSDC. The buyer path
|
|
376
|
+
it names moved to `MarketClient`, which pays in ckUSDC (its default ledger is the ckUSDC ledger), and
|
|
377
|
+
the market it pays is enrolled in the local environment only (`icp.yaml`, `environments`).
|
|
144
378
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
379
|
+
⟨CORRECTED 2026-09-30, same day⟩ The first row then named `MarketClient.submitServiceRequestWithPayment`.
|
|
380
|
+
`MarketClient` has no method of that name: its paying call is `createJob`, and that is what the stdio
|
|
381
|
+
MCP money tools call. `submitServiceRequestWithPayment` and `pollJobResult`, in the charter section
|
|
382
|
+
above, are the buyer path's names from before it moved to `MarketClient`; there they name the family,
|
|
383
|
+
not methods any class serves today.
|
|
148
384
|
|
|
149
385
|
## License
|
|
150
386
|
|
|
151
|
-
|
|
387
|
+
[Apache-2.0](LICENSE) — the same as every EngramX package.
|