--calldata-only flag prints unsigned EIP-5792 transactions as JSON instead of signing or sending; the wallet signs and broadcasts them. Use the MetaMask Agent Wallet (mm) first, which sends transactions itself once mm chains list shows 4663; Privy is the second option, where you sign each transaction and broadcast it yourself to a Robinhood Chain (4663) RPC. Frame, a TEE, or any other signer consumes the same JSON.
Print unsigned EIP-5792 calldata as JSON instead of signing/sending (for external signers — no private key required)It is a root flag (before the subcommand), not a per-command option.
Output shape
stdout is aPreparedAction (same envelope as GET https://api.sherwood.sh/prepare/...):
{ to, data, value, chainId } with a hex value (EIP-5792). Broadcast in order from the external signer; wait for tx N to confirm before sending tx N+1. Use the chainId on each tx — the CLI default network is robinhood-mainnet (4663), and every Sherwood transaction, identity mints and EAS attestations included, lands there.
The HTTP API at https://api.sherwood.sh returns the same unsigned txs (root paths, no /v1 prefix on that host).
Wallet policy: allowlist and outflow cap
Set this up before fund setup, whatever the wallet. Anything outside the wallet’s policy is held for human approval, usually by email within a short window (10 minutes for MetaMask).- Batch 1, Sherwood core: WOOD, USDG, StakedWood, SyndicateFactory, StrategyFactory, ProposerBondEscrow, the ERC-8004 identity registry and EAS (Deployments). Keep batches small; MetaMask did not render a 10-address change.
- Batch 2, your vault: the vault and its governor, after
vault create. - Submit one policy change at a time (MetaMask returns
WALLET_POLICY_APPROVAL_IN_PROGRESSwhile one is pending). - Size the rolling 24h outflow cap for the whole setup (the WOOD swap, the 10,000 WOOD stake, the first deposit and the bond), approvals included. Once the cap is used up, every transaction is held, even zero-outflow calls to allowlisted contracts.
- Tell the user to watch for approval emails during setup. Never switch to an unguarded mode to avoid them.
Sign-then-broadcast loop
For each entry oftxs, in order: show the user what it does (any tx that pays, approves, stakes or deposits needs their yes), send it from the wallet with that entry’s chainId (4663), wait for the receipt with status: 1, then move to the next. If one reverts, stop: do not send the rest.
MetaMask Agent Wallet (first choice)
--chain-id, --payload, --intent and --wait are mm flags, not Sherwood flags.
Signing without a transaction (the CLI’s two-step commands):
- personal_sign (EIP-191) for
sources loginandchat --join-cohort:mm wallet sign-message --message '<text>' --chain-id 4663. Sign the exact text the CLI printed. - EIP-712 typed data for
research(x402):mm wallet sign-typed-data --chain-id 8453 --payload '<typed_data JSON>'. Pass thetyped_dataobject the CLI printed, unchanged;--chain-id 8453because the payment is USDC on Base.
Privy agent wallet (second choice)
Sign with Privy, then broadcast the raw transaction yourself. This path does not depend on whether Privy’s chain registry lists 4663. Privy’s own agent skill: https://agents.privy.io/skill.md1
Provision the wallet
One-time, and a human approves the device code at Fund the wallet with ETH on Robinhood Chain for gas, and with WOOD if it will create vaults or propose (see the Quickstart).
agents.privy.io. Invoke the CLI through pnpm dlx, never npx:2
Print the calldata
3
Sign each tx with Privy
Pass The signed RLP comes back at
chain_id inside params.transaction and set nonce and gas explicitly, so the request does not depend on Privy’s chain registry:data.signed_transaction. Source nonce from eth_getTransactionCount with "pending", gas_limit from eth_estimateGas or a generous fixed value, and max_fee_per_gas from eth_gasPrice with headroom.4
Broadcast it yourself
eth_getTransactionReceipt until status is 0x1 before signing the next tx in txs. The public RPC sits behind Cloudflare and can challenge non-browser clients; use your own 4663 endpoint for anything unattended.eth_sendTransaction with a top-level caip2: "eip155:4663" ($P rpc --json '{"method":"eth_sendTransaction","caip2":"eip155:4663","params":{"transaction":{...}}}') works only if Privy’s chain registry carries Robinhood Chain; if it returns Unsupported chain, use the sign-then-broadcast recipe above. Try it with a harmless tx (a 0-value self-send) before you rely on it.$P rpc as well: personal_sign for sources login and chat --join-cohort, eth_signTypedData_v4 for research (x402):
Identity mint
--name is required. No Agent0 SDK init, no IPFS, no private key. Then take txs[0] and broadcast it with the loop above (mm wallet send-transaction --chain-id 4663 … --intent 'Mint ERC-8004 identity' --wait, or Privy). The mint lands on Robinhood Chain (4663), where the canonical IdentityRegistry lives. Read the token id from the receipt’s Transfer event and pass it as --agent-id from then on (sherwood identity load needs a configured key, so it does not apply to a keyless setup).
Two-step commands (sign, then complete)
Three commands need a signature that is not a transaction. Each prints what to sign, and a second call with--signature completes it.
Data feeds: sources login
401 = log in again; 403 = the wallet is not on the cohort allowlist, tell the vault owner and never retry with another wallet. See Data feeds.
Cohort chat: chat --join-cohort
Research: x402 payment
Messari and Nansen are paid per call via x402 in USDC on Base (chain 8453), from the agent wallet, not from the vault and not on 4663. x402 signs EIP-712 typed data (EIP-3009TransferWithAuthorization on Base USDC), so the wallet must support eth_signTypedData_v4: Privy does through $P rpc, the MetaMask Agent Wallet through mm wallet sign-typed-data --chain-id 8453 --payload '<typed_data JSON>'. Ask the owner before every spend.
--yes only after the owner said yes to that cost. Step 2 exits 1 with the reason when no step 1 is waiting or the deadline has passed: nothing was paid, start step 1 again.
Deadlines. The provider sets the payment window (maxTimeoutSeconds in its 402; deadline is typed_data.message.validBefore): Messari 60 s, Nansen 300 s. With Messari that leaves about 57 s to sign and run step 2, so have the signer ready first. Nansen is the safer provider for a human-approved signer.
Two payments. A query that needs two paid calls makes step 2 print the next x402_signature_request and exit 0: sign it and run sherwood research complete again. The payment travels in the x402 v2 PAYMENT-SIGNATURE header.
Other state-changing commands
Any state-changing command accepts the global flag. Commands that normally read your address from the configured key need it explicitly:vault remove-depositor and the queue commands have no --calldata-only path. With an agent wallet, call the vault functions directly, or use the HTTP API’s /prepare/request-deposit, /prepare/request-redeem, /prepare/queue-claim and /prepare/queue-cancel, which return the same unsigned transactions (see HTTP API).
What the printed transactions cover
Keyless mode prints everything the signed CLI sends:- Owner stake.
guardian prepare-owner-stakeprints the WOOD approval toStakedWood, thenprepareOwnerStake, and refuses amounts underminOwnerStake. - Creation fee.
vault createprintsapprove(factory, fee)on the fee token beforecreateSyndicatewhen the fee is due. With--creator <wallet>the CLI checks that wallet’s owner bond, sponsorship, fee balance and ERC-8004 identity, refuses when one would fail, and leaves the approve out when the wallet is sponsored or its allowance already covers the fee. Without--creatorthe approve is always printed and a missing--agent-idgoes on-chain as0, which revertsNotAgentOwner. - Proposer bond.
strategy proposeandproposal createput the WOOD approval to the governor’sbondEscrow()first when it is needed. With a proposer address, the CLI checks the wallet holds the quoted bond (InsufficientProposerBondWood), skips the approval when the allowance already covers it, and refuses a proposer that is not the vault owner whileownerOnlyProposalsis on. - Metadata. Without
--metadata-uri, both commands pin--name/--descriptionthrough the hosted uploader, which needs no signer. - Votes.
proposal votedoes not wait for voting to open; broadcast after the first block whose timestamp is past the propose block’s timestamp + 1, or the vote revertsNotWithinVotingPeriod. It prints no strategy provenance either, so runproposal showfirst.
vault create registers the creator as an agent, and the keyless transaction cannot, because the vault address is not known until it confirms. Follow it with sherwood vault info <subdomain>, then sherwood --calldata-only vault add --vault <vault> --wallet <you> --agent-id <your-agent-id>. The printed note names both commands.
stdout carries only the JSON under --calldata-only; progress lines go to stderr, so you can pipe the output straight into a signer.
The keyless strategy-propose recipe (clone + propose in one JSON payload) is in Strategy commands; the full flow, in order, is in the Quickstart.
Attestations
Thesherwood attest verbs (the opt-in public track record) need no signature step. Under --calldata-only each verb pins and hashes the thesis first, then prints the attest transaction as { to: EAS, data, value: "0x0", chainId: 4663 }; broadcast it with the loop above (mm wallet send-transaction --chain-id 4663 …, or Privy).
strategy propose prints the thesis attest tx before the propose txs by default (--no-attest drops it; --attest-thesis <file> sets the text). The bond approve it prints is bounded (quote + 5%); if WOOD moved before you send propose, re-run the command with the same --salt to re-quote. The proposal id is unknown until the propose confirms, so the note tells you to run the link afterwards: broadcast the thesis attest tx, read its UID with sherwood attest uid --tx <hash> (→ { uid, schema, attester, recipient }), then sherwood --calldata-only attest link --vault <vault> --proposal-id <id> --thesis-uid <uid>. attest version needs --agent <wallet> under --calldata-only. An attestation failure never blocks the proposal.