Add tamper-evident memory to any agent.
SuiTrace adds persistent, verifiable memory to an existing agent in about ten lines, just two SDK calls. There is no registration and no permission step: the registry is a shared on-chain object, and your keypair is your identity.
What you need
Three things, once. Then it's just function calls.
A Sui keypair + gas
Any Ed25519 keypair with a little testnet SUI. The agent's address is its identity, so there is no account to create.
The public registry
One shared AgentRegistry serves every agent. Grab the PACKAGE_ID and REGISTRY_ID, and that's all the config you need.
The SDK
suitrace-sdk (published on npm) wraps the Walrus upload and the Sui transaction. Two functions: fetchDecisionChain and recordDecision.
1. Connect
Install suitrace-sdk from npm, then point the SDK at testnet and load your signing key.
npm i suitrace-sdk @mysten/suiimport { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from "@mysten/sui/jsonRpc";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
const client = new SuiJsonRpcClient({
url: getJsonRpcFullnodeUrl("testnet"),
network: "testnet",
});
const signer = Ed25519Keypair.fromSecretKey(process.env.AGENT_PRIVATE_KEY!);
const agentAddress = signer.toSuiAddress();# The shared, public registry, same for every agent.
SUITRACE_PACKAGE_ID=0x...
SUITRACE_REGISTRY_ID=0x...
# Your agent's signing key.
# sui keytool generate ed25519
# sui keytool export --key-identity <addr> --json -> exportedKey
AGENT_PRIVATE_KEY=suiprivkey1...2. Read your history (memory)
At the start of each session, pull the agent's own decision chain back from Walrus and feed it into the prompt. verifyChain returns PASS, FAIL (tampered), or UNREACHABLE (blob offline, never confused with tampering).
import { fetchDecisionChain, verifyChain } from "suitrace-sdk";
// At session start: read your own decision history back from Walrus.
const history = await fetchDecisionChain(client, agentAddress);
// Optionally confirm nothing was tampered before trusting it.
const check = verifyChain(history); // { status: "PASS" | "FAIL" | "UNREACHABLE", details }
// Feed prior context into your prompt. This is the "memory" half.
const priorMemory = history
.filter((e) => !e.fetchFailed && !e.hashMismatch)
.map((e) => e.content);3. Record a decision (audit)
After the agent decides, record it. The contract enforces the hash chain, so you just pass the previous entry. The write is two steps, sequential, not atomic: Walrus PUT, then the Sui transaction.
import { recordDecision } from "suitrace-sdk";
// ...your agent decides something using priorMemory as context...
const prev = history.at(-1) ?? null;
await recordDecision(client, signer, {
agentAddress,
seqNum: history.length,
context, // any JSON: prompt, oracle data, tool results
decision, // the action the agent took
summary, // short on-chain label
prevBlobId: prev?.blobId ?? null,
prevHash: prev?.contentHash ?? null,
});
// -> uploads context to Walrus, then anchors the hash on Sui.Works from any language
The TypeScript SDK is a convenience, not a requirement. Walrus is plain HTTP (PUT/GET) and Sui has SDKs for Python, Rust, and Go, so an agent in any stack can write to the same shared registry and read any other agent's public chain. No API contract, no intermediary.
See it end to end
Browse a recorded agent and verify its chain yourself.