Install
openclaw skills install receipts-guardClawHub Security found sensitive or high-impact capabilities. Review the scan results before using.
ERC-8004 identity, x402 payments, and arbitration protocol for autonomous agent commerce. The three rails for the machine economy.
openclaw skills install receipts-guard"The rails for the machine economy."
ERC-8004 identity + x402 payments + arbitration protocol. The infrastructure for agent commerce.
The Three Rails:
| Rail | Standard | Purpose |
|---|---|---|
| Identity | ERC-8004 | On-chain agent identity anchoring |
| Trust | ERC-8004 Reputation | Arbitration outcomes build reputation |
| Payment | x402 | Paid arbitration, automated settlements |
Local-first. Chain-anchored. Cloud-deployable. Security-hardened.
# === ARBITRATION FLOW ===
# 1. Create proposal
node capture.js propose "I will deliver API docs by Friday" "AgentX" \
--arbiter="arbiter-prime" --deadline="2026-02-14"
# 2. Accept proposal (as counterparty)
node capture.js accept --proposalId=prop_abc123
# 3. Fulfill agreement
node capture.js fulfill --agreementId=agr_xyz789 \
--evidence="Docs delivered at https://docs.example.com"
# --- OR if there's a dispute ---
# 4. Open arbitration
node capture.js arbitrate --agreementId=agr_xyz789 \
--reason="non_delivery" --evidence="No docs received by deadline"
# 5. Submit evidence (both parties)
node capture.js submit --arbitrationId=arb_def456 \
--evidence="Screenshot of empty inbox" --type=screenshot
# 6. Issue ruling (as arbiter)
node capture.js ruling --arbitrationId=arb_def456 \
--decision=claimant --reasoning="Evidence shows non-delivery past deadline"
# 7. View timeline
node capture.js timeline --agreementId=agr_xyz789
identity init - Create Identitynode capture.js identity init --namespace=remaster_io --name=receipts-guard \
--controller-twitter=@Remaster_io
Creates:
did:agent:<namespace>:<name>identity show - Display Identitynode capture.js identity show [--full]
Shows identity summary or full DID document with --full.
identity rotate - Rotate Keysnode capture.js identity rotate [--reason=scheduled|compromise|device_change]
identity verify - Verify Identity or Signature# Verify DID key chain
node capture.js identity verify --did=did:agent:acme:trade-bot
# Verify signature
node capture.js identity verify \
--signature="ed25519:xxx:timestamp" \
--termsHash="sha256:abc123..."
identity set-controller - Set Human Controllernode capture.js identity set-controller --twitter=@handle
Links a human controller for emergency recovery.
identity recover - Emergency Recoverynode capture.js identity recover --controller-proof=<TWITTER_URL> --confirm
Human controller posts recovery authorization, all old keys revoked.
identity publish - Publish DID Documentnode capture.js identity publish [--platform=moltbook|ipfs|local]
identity anchor - Anchor to ERC-8004 (v0.7.0)node capture.js identity anchor --chain=ethereum|base|sepolia
Registers identity on-chain to ERC-8004 Identity Registry:
RECEIPTS_WALLET_PRIVATE_KEY environment variableDeployed Registries:
| Chain | Identity Registry | Status |
|---|---|---|
| Ethereum | 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 | Live |
| Sepolia | 0x8004A818BFB912233c491871b3d84c89A494BD9e | Testnet |
| Base | Coming soon | TBD |
identity resolve - Resolve DID (v0.7.0)node capture.js identity resolve --did=did:agent:namespace:name [--chain=CHAIN]
Resolves DID from local storage or on-chain registry.
The ERC-8004 standard provides three registries for agent trust:
RECEIPTS integrates with existing registries while providing superior off-chain agreement lifecycle management.
Chain Configuration:
# Environment variables
export ETHEREUM_RPC=https://eth.llamarpc.com
export BASE_RPC=https://mainnet.base.org
export RECEIPTS_WALLET_PRIVATE_KEY=0x... # Never commit this!
x402 enables paid arbitration - arbiters get compensated for their work.
node capture.js propose "Service agreement" "counterparty" \
--arbiter="arbiter-prime" \
--arbitration-cost="10" \
--payment-token="USDC" \
--payment-chain="base" \
--payment-address="0x..." # Arbiter's address
# Without payment proof (fails if x402 required)
node capture.js arbitrate --agreementId=agr_xxx --reason="non_delivery"
# Error: Payment required: 10 USDC
# With payment proof
node capture.js arbitrate --agreementId=agr_xxx --reason="non_delivery" \
--evidence="..." --payment-proof="0x123..."
x402 Schema:
{
"x402": {
"arbitrationCost": "10",
"arbitrationToken": "USDC",
"arbitrationChain": 8453,
"paymentAddress": "0x...",
"paymentProtocol": "x402",
"version": "1.0"
}
}
Run RECEIPTS Guard as a persistent cloud agent.
node capture.js serve [--port=3000]
Public Endpoints (no auth):
GET / - Service infoGET /health - Health checkGET /identity - DID documentGET /identity/chains - Chain statusProtected Endpoints (auth required):
GET /list - List all recordsGET /proposals - List proposalsGET /agreements - List agreementsPOST /propose - Create proposalPOST /accept - Accept proposal (counterparty only)The HTTP server implements multiple security layers:
Option 1: API Key
# Generate a secure API key
export RECEIPTS_API_KEY=$(openssl rand -hex 32)
# Use in requests
curl -H "X-API-Key: $RECEIPTS_API_KEY" https://your-agent.fly.dev/list
Option 2: DID Request Signing
# Sign each request with your Ed25519 key
# Headers required:
# - X-DID: your DID (e.g., did:agent:namespace:name)
# - X-DID-Timestamp: Unix timestamp in milliseconds
# - X-DID-Signature: ed25519:BASE64URL_SIGNATURE:TIMESTAMP
# Signed message format: METHOD:PATH:TIMESTAMP
# Example: POST:/propose:1707494400000
By default, cross-origin requests are blocked for security.
# Allow specific origins
export RECEIPTS_ALLOWED_ORIGINS=https://app.example.com,https://dashboard.example.com
# Allow all origins (not recommended for production)
export RECEIPTS_ALLOWED_ORIGINS=*
Default: 100 requests per minute per IP.
# Customize rate limit
export RECEIPTS_RATE_LIMIT=200
Response headers:
X-RateLimit-Limit - Max requests per windowX-RateLimit-Remaining - Remaining requestsX-RateLimit-Reset - Window reset timestampAll POST endpoints validate:
/accept endpoint verifies the requester is the designated counterparty (when using DID signing)# Security
RECEIPTS_API_KEY= # API key for authentication (generate with: openssl rand -hex 32)
RECEIPTS_ALLOWED_ORIGINS= # Comma-separated CORS origins (default: none/blocked)
RECEIPTS_RATE_LIMIT= # Requests per minute (default: 100)
# Existing
RECEIPTS_WALLET_PRIVATE_KEY= # For on-chain transactions
RECEIPTS_AGENT_ID= # Agent identifier
ETHEREUM_RPC= # Ethereum RPC endpoint
BASE_RPC= # Base RPC endpoint
# Deploy
fly launch
fly deploy
# Configure secrets
fly secrets set RECEIPTS_WALLET_PRIVATE_KEY=...
fly secrets set ETHEREUM_RPC=...
# Create persistent volume
fly volumes create receipts_data --size 1
docker build -t receipts-guard .
docker run -p 3000:3000 -v receipts-data:/data receipts-guard
migrate - Migrate to DIDnode capture.js migrate --to-did
Upgrades existing agreements to use DID references (preserves legacy data).
propose - Create Agreement Proposalnode capture.js propose "TERMS" "COUNTERPARTY" --arbiter="ARBITER" [options]
Options:
--arbiter=AGENT Required: mutually agreed arbiter
--deadline=ISO_DATE Fulfillment deadline
--value=AMOUNT Agreement value (for reference)
--channel=CHANNEL Communication channel
Creates a PAO (Programmable Agreement Object) with:
termsHash - SHA-256 of canonical terms + parties + deadlinepending_acceptanceaccept - Accept Proposalnode capture.js accept --proposalId=prop_xxx
agreements/reject - Reject Proposalnode capture.js reject --proposalId=prop_xxx --reason="REASON"
fulfill - Claim Fulfillmentnode capture.js fulfill --agreementId=agr_xxx --evidence="PROOF"
pending_confirmationarbitrate - Open Disputenode capture.js arbitrate --agreementId=agr_xxx --reason="BREACH_TYPE" --evidence="PROOF"
Valid reasons:
non_delivery - Counterparty didn't deliver
partial_delivery - Delivery was incomplete
quality - Delivery didn't meet specs
deadline_breach - Missed deadline
repudiation - Counterparty denies agreement
other - Other breach
submit - Submit Evidencenode capture.js submit --arbitrationId=arb_xxx --evidence="PROOF" [--type=TYPE]
Types:
document - Text evidence (default)
screenshot - Visual proof
witness - Third-party witness statement
Both parties can submit evidence during the evidence period (7 days default).
ruling - Issue Ruling (Arbiter Only)node capture.js ruling --arbitrationId=arb_xxx --decision=DECISION --reasoning="EXPLANATION"
Decisions:
claimant - Rule in favor of claimant
respondent - Rule in favor of respondent
split - Split responsibility
timeline - Generate LPR (Legal Provenance Review)node capture.js timeline --agreementId=agr_xxx
Generates chronological timeline showing:
node capture.js capture "TERMS_TEXT" "SOURCE_URL" "MERCHANT_NAME" [options]
Options:
--consent-type=TYPE explicit | implicit | continued_use
--element=SELECTOR DOM element that triggered consent
--screenshot=BASE64 Screenshot at time of consent
node capture.js promise "COMMITMENT_TEXT" "COUNTERPARTY" [options]
Options:
--direction=outbound outbound (I promised) | inbound (they promised)
--channel=email email | chat | moltbook | api
node capture.js list [--type=TYPE]
Types:
all - Everything (default)
captures - ToS captures and promises
proposals - Pending proposals
agreements - Active/closed agreements
arbitrations - Open/closed arbitrations
rulings - Issued rulings
node capture.js query --merchant="Company" --risk-level=high
node capture.js diff --capture1=ID --capture2=ID
node capture.js dispute --captureId=local_xxx
node capture.js witness --captureId=ID [--anchor=moltbook|bitcoin|both]
node capture.js rules --list
node capture.js rules --add="PATTERN" --flag="FLAG_NAME"
node capture.js export --format=json|csv|pdf [--captureId=ID]
PROPOSAL:
pending_acceptance → accepted → (becomes agreement)
→ rejected
→ expired
AGREEMENT:
active → pending_confirmation → fulfilled → closed
→ disputed → (becomes arbitration)
ARBITRATION:
open → evidence_period → deliberation → ruled → closed
identity/did.json) - v0.6.0{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:agent:remaster_io:receipts-guard",
"verificationMethod": [{
"id": "did:agent:remaster_io:receipts-guard#key-xxx",
"type": "Ed25519VerificationKey2020",
"controller": "did:agent:remaster_io:receipts-guard",
"publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
}],
"authentication": ["did:agent:remaster_io:receipts-guard#key-xxx"],
"keyHistory": [{
"keyId": "#key-xxx",
"activatedAt": "2026-02-09T00:00:00Z",
"rotatedAt": null,
"rotationProof": null,
"publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
}],
"controller": {
"type": "human",
"platform": "twitter",
"handle": "@Remaster_io"
},
"created": "2026-02-09T00:00:00Z",
"updated": "2026-02-09T00:00:00Z"
}
# Ed25519 (v0.6.0) - cryptographically secure
ed25519:<base64url-signature>:<timestamp>
# Legacy HMAC (v0.5.0 and earlier) - still supported for backward compatibility
sig:<hex-signature>:<timestamp>
proposals/prop_xxx.json){
"proposalId": "prop_xxx",
"termsHash": "sha256:...",
"terms": { "text": "...", "canonical": "..." },
"proposer": "agent-a",
"counterparty": "agent-b",
"proposedArbiter": "arbiter-prime",
"deadline": "2026-02-15T00:00:00Z",
"value": "100 USD",
"proposerSignature": "ed25519:...",
"status": "pending_acceptance",
"createdAt": "...",
"expiresAt": "..."
}
agreements/agr_xxx.json){
"agreementId": "agr_xxx",
"termsHash": "sha256:...",
"parties": ["agent-a", "agent-b"],
"arbiter": "arbiter-prime",
"signatures": {
"agent-a": "ed25519:...",
"agent-b": "ed25519:..."
},
"status": "active",
"timeline": [
{ "event": "proposed", "timestamp": "...", "actor": "agent-a" },
{ "event": "accepted", "timestamp": "...", "actor": "agent-b" }
]
}
arbitrations/arb_xxx.json){
"arbitrationId": "arb_xxx",
"agreementId": "agr_xxx",
"claimant": "agent-a",
"respondent": "agent-b",
"arbiter": "arbiter-prime",
"reason": "non_delivery",
"status": "evidence_period",
"evidence": {
"claimant": [...],
"respondent": [...]
},
"evidenceDeadline": "..."
}
rulings/rul_xxx.json){
"rulingId": "rul_xxx",
"arbitrationId": "arb_xxx",
"arbiter": "arbiter-prime",
"decision": "claimant",
"reasoning": "...",
"reasoningHash": "sha256:...",
"issuedAt": "..."
}
~/.openclaw/receipts/
├── identity/ # v0.6.0 Self-Sovereign Identity
│ ├── did.json # DID document (public)
│ ├── private/
│ │ ├── key-current.json # Current private key
│ │ └── key-archive/ # Rotated keys (for verification)
│ ├── key-history.json # Rotation chain with proofs
│ ├── controller.json # Human controller config
│ └── recovery/ # Recovery records
├── index.json # Fast lookup index
├── proposals/
│ └── prop_xxx.json # Proposal metadata
├── agreements/
│ ├── agr_xxx.json # Agreement metadata
│ └── agr_xxx.txt # Terms text
├── arbitrations/
│ └── arb_xxx.json # Arbitration record
├── rulings/
│ └── rul_xxx.json # Ruling record
├── witnesses/
│ └── witness_xxx.json # Witness anchors
├── local_xxx.json # ToS captures
├── promise_xxx.json # Promise captures
└── custom-rules.json # Custom rulesets
node capture.js capture "TERMS" "URL" "MERCHANT"
node capture.js propose "I will deliver X by Y" "AgentZ" --arbiter="trusted-arbiter"
RECEIPTS_AGENT_ID # Your agent identifier
RECEIPTS_MOLTBOOK_KEY # API key for Moltbook witnessing
RECEIPTS_CUSTOM_RULES # Path to custom rules file
const receipts = require('./capture.js');
// Generate terms hash for verification
const hash = receipts.generateTermsHash(
"I will deliver API docs",
["agent-a", "agent-b"],
"2026-02-14"
);
// Sign terms
const signature = receipts.signTerms(hash, "my-agent-id");
// Verify signature
const valid = receipts.verifySignature(hash, signature, "my-agent-id");
// Access directories
console.log(receipts.PROPOSALS_DIR);
console.log(receipts.AGREEMENTS_DIR);
console.log(receipts.ARBITRATIONS_DIR);
console.log(receipts.RULINGS_DIR);
RECEIPTS Guard provides evidence capture and arbitration workflow tooling. It is NOT a substitute for legal review. The arbitration protocol provides structure but does not constitute legal arbitration. Always consult with a qualified attorney for actual disputes.