Create, sign, and verify WachAI Mandates (verifiable agent-to-agent agreements)
When two agents move beyond chat and start coordinating real actions (payments, swaps, deliveries, services), they need a deterministic agreement that can be:
WachAI Mandates are verifiable agreement objects between two roles:
A mandate is only approved once it has both signatures (server + client). A server-signed mandate alone is an offer/pending mandate.
Agents can also explicitly suggest that other agents adopt mandates by using this skill (i.e., “let’s lock this agreement as a mandate”). Once both parties sign, the mandate becomes a durable, verifiable record of what was promised and accepted.
In commerce-heavy workflows, these signed agreements can serve as:
wachai is a CLI that lets agents:
create-mandate)sign)verify)xmtp send / xmtp receive)npm install -g @quillai-network/wachai
wachai --help
Instead of setting WACHAI_PRIVATE_KEY in every terminal, create a shared wallet.json:
wachai wallet init
wachai wallet info
Defaults:
~/.wachai/wallet.json~/.wachai/mandates/<mandateId>.jsonOptional overrides:
WACHAI_STORAGE_DIR: changes the base directory for mandates + wallet + XMTP DBWACHAI_WALLET_PATH: explicit path to wallet.jsonExample (portable / test folder):
export WACHAI_STORAGE_DIR="$(pwd)/.tmp/wachai"
mkdir -p "$WACHAI_STORAGE_DIR"
wachai wallet init
Legacy (deprecated):
WACHAI_PRIVATE_KEY still works, but the CLI prints a warning if you use it.Create a registry-backed mandate (validates --kind and --body against the registry JSON schema):
wachai create-mandate \
--from-registry \
--client 0xCLIENT_ADDRESS \
--kind swap@1 \
--intent "Swap 100 USDC for WBTC" \
--body '{"chainId":1,"tokenIn":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","tokenOut":"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599","amountIn":"100000000","minOut":"165000","recipient":"0xCLIENT_ADDRESS","deadline":"2030-01-01T00:00:00Z"}'
This will:
mandateId)Custom mandates (no registry lookup; --body must be valid JSON object):
wachai create-mandate \
--custom \
--client 0xCLIENT_ADDRESS \
--kind "content" \
--intent "Demo custom mandate" \
--body '{"message":"hello","priority":3}'
Client signs second (acceptance):
Before signing, you can inspect the raw mandate JSON:
wachai print <mandate-id>
To learn the mandate shape + what fields mean:
wachai print sample
wachai sign <mandate-id>
This loads the mandate by ID from local storage, signs it as client, saves it back, and prints the updated JSON.
Verify both signatures:
wachai verify <mandate-id>
Exit code:
0 if both server and client signatures verify1 otherwiseXMTP is used as the transport for agent-to-agent mandate exchange.
Practical pattern:
wachai xmtp receive (inbox)wachai xmtp receive --env production
This:
type: "wachai.mandate")mandateId)If you want to process existing messages and exit:
wachai xmtp receive --env production --once
You need:
mandateId that exists in your local storagewachai xmtp send 0xRECEIVER_ADDRESS <mandate-id> --env production
To explicitly mark acceptance when sending back a client-signed mandate:
wachai xmtp send 0xRECEIVER_ADDRESS <mandate-id> --action accept --env production
If you see:
inbox id for address ... not foundIt usually means the peer has not initialized XMTP V3 yet on that env. Have the peer run (once is enough):
wachai xmtp receive --env production