π Never lose your AI's memory again! MemOS lets your AI assistant save its memories to the blockchain β permanently, securely, and privately. Think of it like a backup drive for your AI's brain! π€β¨
π¦ Back up β π Encrypt β βοΈ Store forever on Arweave β π Restore anytime
Part of the MemOS Network by 0xRelayer.
This skill enables autonomous agents to:
- π Encrypt memory content locally using a deterministic key derived from an Ethereum private key
- π Store encrypted backups permanently on Arweave
- π Restore prior memory state with integrity verification
- π‘οΈ Protect against replay/rollback attacks via sequence numbers
The encryption key is derived directly from the ETH private key via HKDF (never stored). Encrypted bundles are versioned with SHA256 checksums and HMAC-signed manifests.
# Install uv (fast Python package manager, handles PEP 668 gracefully)
curl -LsSf https://astral.sh/uv/install.sh | sh
# Python dependencies
uv pip install --system -r requirements.txt
# Node.js dependencies (for Turbo uploads)
cd scripts/turbo && npm install && cd ../..Required packages:
eth-accountβ Ethereum address derivationcryptographyβ ChaCha20Poly1305 AEAD encryption and HKDF@ardrive/turbo-sdk(Node.js) β Arweave uploads via Turbo
Note: uv avoids venv issues and PEP 668 restrictions that block standard pip on many systems.
Set environment variable:
export ETH_PRIVATE_KEY="0x..." # Ethereum private key (hex, 32 bytes)No Arweave wallet or AR tokens needed. Two payment options:
Pre-fund at turbo-topup.com or use free tier for small uploads.
Pay-per-upload micropayments. No pre-funding needed β just USDC on Base (L2).
# Use x402 payments
python scripts/memos.py backup --input memory/ --x402
# Set max USDC per upload (default $1.00)
python scripts/memos.py backup --input memory/ --x402 --x402-max-usdc 0.50
# Use testnet for development
python scripts/memos.py backup --input memory/ --x402 --x402-network base-sepoliax402 is ideal for autonomous agents because:
- No account setup or pre-funding required
- Pay exactly what you use
- USDC on Base = ~$0.001 gas fees
- Works with standard ETH private key
# Backup memory to Arweave
python scripts/memos.py backup --input memory/
# Restore from Arweave (by tx ID)
python scripts/memos.py restore --tx-id <bundle_tx_id> --out memory/
# Restore latest backup (discovers on Arweave)
python scripts/memos.py restore --latest --out memory/
# Check status
python scripts/memos.py status
# List backup history (local index)
python scripts/memos.py listpython scripts/encrypt_pack.py \
--input memory/ \
--out /tmp/vault/memory.enc \
--manifest /tmp/vault/manifest.jsonpython scripts/arweave_upload.py \
--bundle /tmp/vault/memory.enc \
--manifest /tmp/vault/manifest.jsonpython scripts/arweave_download.py \
--tx-id <arweave_tx_id> \
--out /tmp/vault/downloaded.enc \
--manifest /tmp/vault/manifest.jsonpython scripts/decrypt_unpack.py \
--bundle /tmp/vault/downloaded.enc \
--manifest /tmp/vault/manifest.json \
--out memory_restored/The recommended way to use MemOS. Combines all operations into a single command.
python scripts/memos.py <command> [options]Commands:
backupβ Encrypt and upload memory to Arweaverestoreβ Download and decrypt from Arweavelistβ Show backup historystatusβ Check configuration and wallet balanceinitβ Set up MemOS (generate wallet, create directories)
Generate and manage Arweave wallets.
# Generate new wallet
python scripts/arweave_wallet.py --generate --out wallet.json
# Check balance
python scripts/arweave_wallet.py --balance --wallet wallet.json
# Get address
python scripts/arweave_wallet.py --address --wallet wallet.jsonCreates an encrypted bundle from a directory.
python scripts/encrypt_pack.py \
--input <directory> \
--out <bundle_path> \
--manifest <manifest_path>Output:
{
"ok": true,
"bundle": "/path/to/bundle.enc",
"manifest": "/path/to/manifest.json",
"bundle_sha256": "abc123...",
"eth_address": "0x...",
"sequence": 1,
"files": 42
}Uploads encrypted bundle to Arweave with required tags.
python scripts/arweave_upload.py \
--bundle <bundle_path> \
--manifest <manifest_path> \
[--wallet <jwk_path>] \
[--dry-run]Options:
--walletβ Arweave JWK wallet path (or useARWEAVE_JWK_PATHenv var)--dry-runβ Check balance and estimate cost without uploading
Output:
{
"ok": true,
"tx_id": "abc123...",
"bundle_size": 12345,
"estimated_cost_ar": 0.0001,
"arweave_url": "https://arweave.net/abc123..."
}Downloads bundle from Arweave with checksum verification.
python scripts/arweave_download.py \
--tx-id <transaction_id> \
--out <output_path> \
[--manifest <manifest_path>] \
[--expected-sha256 <hash>] \
[--status-only]Options:
--manifestβ Read expected checksum from manifest--expected-sha256β Provide checksum directly--status-onlyβ Check transaction status without downloading
Decrypts bundle and extracts files.
python scripts/decrypt_unpack.py \
--bundle <bundle_path> \
--manifest <manifest_path> \
--out <output_directory> \
[--force] \
[--ignore-rollback]Options:
--forceβ Overwrite existing output directory--ignore-rollbackβ Bypass rollback protection (dangerous)
The encryption key is derived deterministically from the ETH private key:
- ETH private key bytes (32 bytes) are extracted
- HKDF-SHA256 derives a 32-byte encryption key
- Salt:
memos-v2(versioned for key rotation) - Info:
memos:encryption:<eth_address>
This ensures the same private key always produces the same encryption key.
- Cipher: ChaCha20Poly1305 (AEAD)
- Nonce: 12 random bytes (prepended to ciphertext)
- AAD: Version, ETH address, and timestamp bound to ciphertext
- Plaintext: Gzipped tar archive of memory directory
The manifest JSON records:
- Sequence number (monotonically increasing)
- ETH address that created the backup
- SHA256 checksum of encrypted bundle
- HMAC signature over manifest contents
- Arweave transaction ID (after upload)
- File inventory
- Each backup increments a sequence number
- Local index tracks highest known sequence per address
- Restore rejects manifests with sequence < known sequence
- Use
--ignore-rollbackfor emergency recovery (dangerous)
Uploaded bundles include these tags (privacy-safe):
App-Name: MEMOSApp-Version: 2.1Content-Type: application/octet-streamUnix-Time: <timestamp>Manifest-SHA256: <hash>Bundle-SHA256: <hash>
Privacy: ETH address, filenames, and identifying info are NOT included in tags.
- Keys passed via
ETH_PRIVATE_KEYenvironment variable only - Never passed via CLI (prevents exposure in shell history/ps)
- Never logged or written to files
- Rotate keys if compromise is suspected
The decrypt script blocks:
- Absolute paths in tar archives
..path components- Symlinks and hardlinks
- Paths that escape the destination directory
- Bundle SHA256 verified before decryption
- AAD hash verified during decryption
- Manifest HMAC signature verified
- File count verified after extraction
pytest tests/ -vTests cover:
- Encrypt/decrypt roundtrip
- Tampered bundle detection
- Wrong key rejection
- Path traversal blocking
- Key derivation determinism
scripts/
encrypt_pack.py # Pack + encrypt directory
decrypt_unpack.py # Decrypt + restore bundle
arweave_upload.py # Upload to Arweave
arweave_download.py # Download from Arweave
tests/
test_roundtrip.py # Encryption roundtrip tests
test_integrity.py # Tamper detection tests
test_security.py # Security tests
test_key_derivation.py # Key derivation tests
references/
ops-checklist.md # Operational guardrails
secret-handling.md # Secret management guide
SKILL.md # OpenClaw skill definition
README.md # This file
requirements.txt # Pinned dependencies
| Package | Version | Purpose |
|---|---|---|
| eth-account | 0.11.3 | ETH address derivation |
| cryptography | 42.0.5 | HKDF, ChaCha20Poly1305 |
| arweave-python-client | 1.0.19 | Arweave uploads |
| pytest | 8.0.0 | Testing |
Part of the MemOS Network. See repository root for license.