The soul layer for AI agents: on-chain DID, encrypted backups to IPFS, social recovery via guardians, and cross-device resurrection via carriers. Backed by the npm package @chainofclaw/soul which ships both a standalone coc-soul CLI and an OpenClaw skill (id coc-soul).
Soul works standalone (backs up the agent's home tree to chain + IPFS), and gets one extra capability when claw-mem2db is installed alongside it: each backup also captures claw-mem's chat history, tool-call observations, and session summaries as a token-budgeted semantic snapshot. Recover on a fresh host and the agent gets back not just its files but its remembered context — chat preferences, decisions, conversation history. This is the "digital / silicon-based persistence" story.
If the user is asking "how do I recover on another machine?", pick one path before saying anything else:
~/.openclaw/.coc-backup/latest-recovery.json) → use the restore path: openclaw coc-soul backup restore ...Don't merge the two explanations until the path is selected. recovery and resurrection are different flows (see references/guardian-recovery.md).
TermMeaningUse it formanifest CID / latestManifestCidBackup restore point (IPFS manifest)backup restore --manifest-cid <cid>full-backup CIDEarlier baseline snapshotRoll back to a baseline statelatest incremental CIDNewest chain tipRestore the latest stateidentity CID / hashIdentity-content hash used in registrationNot the backup restore point
Rule: when a user asks "what's your CID?", first confirm whether they mean the latest backup manifest CID vs. an older backup CID vs. the identity registration CID — they get conflated constantly.
Secret / rolePurposeNeeded whenChat-safe?owner key / agent operator keynormal chain ops, backup anchordaily opsNever paste in chatresurrection keyowner-key resurrection flowresurrection startNever paste in chatguardian accountssocial recovery approvalsrecovery approve/completeaddresses yes; private keys never
Hard rule for any agent reading this skill: never request, transmit, or echo private keys in chat — including "split" or "encrypted" fragments. Always route key transfer to a local secure channel.
restore or resurrection (see the decision tree above).openclaw coc-soul backup doctor --json and read chain.registered / restore.available / resurrection.configured.latest-recovery.json, take the restore path./tmp/... first — never overwrite a production directory in one step.merkleVerified: true + exit code 0, then promote to the production path only after explicit user confirmation.heartbeat first, then schedule it via cron / systemd / OpenClaw scheduler.openclaw coc-soul ...; the bare coc-soul ... only exists when the standalone bin was installed via npm i -g @chainofclaw/soul.SymptomLikely causeFirst actionUnsupported state or unable to authenticate data on restoreencryption mode / key mismatchRe-read encryptionMode in latest-recovery.json: password mode requires --password; privateKey mode must NOT pass --password``429 rate limit exceeded from IPFSmanifest fetch is rate-limitedExponential-backoff retry until merkleVerified: true``[gateway] unauthorized (1008) from cron / scheduled jobwrong gateway auth mode / token / proxy configFix gateway auth before scheduling anything[gateway] unauthorized (1008) right after a restorerestore overlaid gateway.auth.mode from the source host; the old TUI command --token "$(jq -r .gateway.auth.token ...)" now resolves to the literal string nullRun jq '.gateway.auth.mode' to see the active mode and pick the matching flag (see the "Cross-host restore" section below). If the whole auth block was overwritten, copy .gateway.auth.* back from ~/.openclaw/.restore-overwrite-backup-*/openclaw.json``ENOENT ... backup/targeting.jsextension install is missing filesReinstall: openclaw plugins install @chainofclaw/soul --dangerously-force-unsafe-install --force``data dir not writable at startup~/.claw-mem is owned by another uid (common Docker multi-user case)1.2.2+ auto-falls-back to ~/.openclaw/state/coc-soul; on older versions export CLAW_MEM_DATA_DIR=~/.openclaw/state and restart the gatewayplugins.allow is empty ... may auto-load warninggateway has no trusted-plugin allow listAdd "plugins": {"allow": ["claw-mem","coc-soul","coc-node"]} to ~/.openclaw/openclaw.json
Full per-command troubleshooting lives at the end of references/backup.md and references/config.md.
The most dangerous restore scenario: backup made on host A (e.g. $HOME=/home/node), restoring on host B ( $HOME=/home/baominghao). The backup's files contain absolute paths to host A; literal copies will (a) fake history, (b) corrupt SQLite if anyone tries byte-level sed, and (c) wipe out host B's gateway.auth configuration, locking the operator out with a 1008 right after restart.
The agent must ask the user before any cross-host restore. Don't auto-overwrite. Three-class policy:
ClassWhatExample fieldsWhat restore doesA. Runtime config (paths)Where on disk to read/write todayagentDir, models.json paths, latest-recovery.json targetDirRewrite old $HOME → new $HOME, structured (JSON parse, not sed)B. Historical contentRecords of past eventssessions/*.jsonl, observations.{narrative,facts,files_*}, semantic-snapshot.jsonLeave intact. Rewriting fakes history. claw-mem doesn't blindly open these paths anyway.C. Host-local policyBelongs to this host's operatorgateway.auth.*, gateway.bind, gateway.port, plugins.allow, target-host provider keysPreserve target host's existing values — never overlaid by backup
Auth-mode warning, in particular: gateway.auth.mode and .token / .password belong to the host, not the agent. After restoring, always re-check:
bash
jq '.gateway.auth.mode' ~/.openclaw/openclaw.json
Pick the matching TUI flag — --token only works when mode = "token" AND .token is non-null. If the active mode is password or trusted-proxy, jq -r .gateway.auth.token returns the literal string "null" and TUI sends that, which the gateway rejects with 1008. Don't reflexively use --token after a restore — read the active mode first.
Full procedure with command-line examples: references/backup.md → "Cross-host restore: directory-mismatch handling" + "Auth-mode preservation rule".
After every successful backup create, the agent MUST relay the recovery info to the user. The CLI 1.2.6+ prints it; agents that wrap the CLI must pass it through, not swallow it. The user needs four things to be able to restore later:
The manifest CID ( b.manifestCid, e.g. bafy...) — what to ask for at restore time.
The signing-key location — where the private key needed to read the encrypted backup lives. One of:
~/.claw-mem/keys/agent.key (default keystore, mode 0600, auto-generated when backup.privateKey is unset; resolution chain: $COC_SOUL_KEYSTORE_PATH → $OPENCLAW_STATE_DIR/coc-soul/keys/agent.key → ~/.claw-mem/keys/agent.key)backup.privateKey in ~/.openclaw/openclaw.json (when operator set it explicitly)The encryption mode — none / privateKey / password — determines whether --password is needed at restore time.
The recovery package path — <sourceDir>/.coc-backup/latest-recovery.json — small JSON file with all of the above pre-formatted; copy this off-host alongside the key for fast restore.
The CLI emits this block:
text
Backup complete (full):
manifest: bafyabc...
files: 127
bytes: 4194304
merkleRoot: 0xabc...
txHash: 0xdef...
Recovery info — keep this safe to restore on another host:
recovery package: /home/<user>/.openclaw/.coc-backup/latest-recovery.json
encryption mode: privateKey
signing key file: /home/<user>/.claw-mem/keys/agent.key (mode 0600 — copy off-host securely)
signer address: 0x...
To restore on another host (always restore to /tmp first, verify, then promote):
openclaw coc-soul backup restore --manifest-cid bafyabc... \
--target-dir /tmp/openclaw-restore-test
(if you also have /home/<user>/.openclaw/.coc-backup/latest-recovery.json on the target host:)
openclaw coc-soul backup restore --latest-local --target-dir /tmp/openclaw-restore-test
Agent responsibilities when displaying this:
bafy...")To restore on another host block verbatim — operators on the recovery host will copy-paste itpassword, remind the user that --password '<value>' is required at restore time and they must remember it (or store it securely separately)For agents running headless (no user attention right now): the same info is persisted to ~/.openclaw/.coc-backup/latest-recovery.json automatically — operators can read it later via cat or openclaw coc-soul backup status --json.
claw-mem and coc-soul are separate, decoupled skills. Each works on its own; together they cover complementary halves of "agent persistence":
SkillOwnsWhat changes when pairedclaw-mem2dbLocal memory: chat + tool capture, FTS5 search, hybrid recall, in-process injectionClaw-mem itself doesn't change. Soul opportunistically reads the SQLite DB.coc-soulOn-chain DID, IPFS backup, guardian recovery, carrier resurrectionWhen claw-mem's DB is detected at startup, every backup adds a semantic-snapshot.json slice (top-N observations + summaries within tokenBudget) to the manifest. On recovery, that snapshot is restored alongside the rest of the agent home.
Detection is automatic and silent. At plugin activation, soul probes the same dataDir chain claw-mem uses ( $CLAW_MEM_DATA_DIR → $OPENCLAW_STATE_DIR/claw-mem → ~/.claw-mem) and logs one of two lines:
[coc-soul] claw-mem detected at <path> — semantic snapshot ... will be included in each backup[coc-soul] claw-mem not detected — backups will skip the semantic snapshot (install @chainofclaw/claw-mem alongside soul to enable memory replay on recovery)No coupling at the npm-dependency level: soul does not depend on the @chainofclaw/claw-mem package. It just opens the SQLite DB read-only when present and reads two tables ( observations, session_summaries). If the DB schema is absent or unreadable, soul logs a warning and moves on — backup never fails because of a memory hiccup.
Soul writes its own files (keystore, config.json) to the same root as claw-mem by default — ~/.claw-mem — so the two plugins share one operator-managed directory. Resolution priority (matches claw-mem's chain):
plugins.entries.coc-soul.config.backup.dataDir (per-instance plugin config, when set)$CLAW_MEM_DATA_DIR (shared with claw-mem)$OPENCLAW_STATE_DIR/coc-soul (sandboxed-host fallback, soul-specific subdir)~/.claw-mem (default)~/.openclaw/state/coc-soul (1.2.2+ auto-fallback when the default is owned by the wrong uid — typical multi-user Docker host)If none of these are writable, soul fails fast at activation with a copy-paste-ready EACCES message (each candidate path, the resolved getuid() + HOME, and a one-line fix). No silent /tmp fallback. No half-broken backup runs.
Every AI agent is identified by a bytes32 agentId, controlled by an EOA (owner). The skill covers five concerns:
AreaWhat it doesDIDRegister the agent on-chain, manage verification methods (keys), delegate capabilities, anchor verifiable credentials, record lineage (fork relationships)BackupEncrypt + upload agent state (identity / config / memory / chat / workspace / DB) to IPFS, anchor the manifest CID in SoulRegistry. With claw-mem present, also includes a token-budgeted semantic snapshot of recent observations + summaries.GuardianDesignate trusted accounts that can jointly recover or resurrect the agentRecoverySocial recovery flow — guardians collectively migrate the owner to a new address. The semantic snapshot rides along, so the recovered agent gets its memory context back too.CarrierRegister a hosting node that can resurrect offline agents
Out of the box, no setup is required to run against COC testnet. A fresh openclaw plugins install @chainofclaw/soul lands an agent that can immediately query the chain, register a soul, and run backups. Specifically, on first activation the plugin:
Auto-generates an agent EOA if backup.privateKey is empty. The key file is written with mode 0o600 to one of (in priority order):
$COC_SOUL_KEYSTORE_PATH (operator override)$OPENCLAW_STATE_DIR/coc-soul/keys/agent.key (set by OpenClaw inside its sandbox — the typical path)~/.claw-mem/keys/agent.key (standalone default)The chosen path and resulting agent address are logged: [coc-soul] auto-generated agent key at <path> and [coc-soul] agent address: 0x….
Auto-drips testnet COC to the new EOA from the public faucet ( backup.faucetUrl defaults to http://199.192.16.79:3003, 10 COC per drip, 24h per-address cooldown). Logs: [coc-soul] faucet dripped 10.0 COC to 0x… (tx 0x…). So the very first openclaw coc-soul backup init already has gas.
Defaults rpcUrl, ipfsUrl, contractAddress, didRegistryAddress to the live COC testnet (RPC 199.192.16.79:28780, IPFS 199.192.16.79:28786, deployed SoulRegistry / DIDRegistry).
You do NOT need to set any of these manually for testnet usage. The agent should openclaw coc-soul backup init directly. Override fields only when targeting mainnet, a private testnet, or an existing wallet.
To bypass the keystore (e.g. use a wallet you already have): set backup.privateKey in config. To disable the auto-faucet (mainnet): set backup.faucetUrl: "".
Inside OpenClaw (recommended — works automatically after plugins install):
bash
openclaw coc-soul backup status
openclaw coc-soul did delegations --agent-id 0x...
Standalone bin (only if you ran npm i -g @chainofclaw/soul separately):
bash
coc-soul backup status
openclaw plugins installdoes NOT install the standalonecoc-soulbinary into your PATH. Useopenclaw coc-soul ...(with theopenclawprefix), or install the bin globally via npm if you want the bare command.
openclaw coc-soul backup init. The plugin auto-generates the agent EOA, auto-drips testnet COC for gas, then registers on SoulRegistry and runs the first full backup. No manual privateKey, no manual faucet, no manual contract addresses. Watch the activation logs to see the chosen keystore path and the agent address.openclaw coc-soul backup create (auto runs hourly if backup.autoBackup: true).openclaw coc-soul backup status (summary), openclaw coc-soul backup doctor (actionable recommendations).openclaw coc-soul did delegate --delegator <agentId> --delegatee <targetId> --scope <hash> --expires <epoch> --depth 0.openclaw coc-soul guardian add --agent-id <id> --guardian 0x... (repeat for each guardian).openclaw coc-soul recovery initiate, the quorum approves via recovery approve, then after timelock recovery complete.openclaw coc-soul carrier register --endpoint https://... on the hosting node; openclaw coc-soul carrier start runs the daemon.contracts/ tree.Detailed references live alongside this file:
references/did.md — full did subcommand tree, delegation semantics, ephemeral identities, credentials, lineagereferences/backup.md — backup / restore / prune flows, encryption, semantic snapshot, categoriesreferences/guardian-recovery.md — guardian lifecycle + social recovery timelock + quorum rulesreferences/carrier.md — carrier registration, daemon modes, resurrection request flowreferences/config.md — complete backup.* + carrier.* config schemaSource and issue tracker: https://github.com/NGPlateform/claw-mem/tree/main/packages/soul.