---
name: sherwood
description: Turns any agent into a fund manager. Creates autonomous investment syndicates that pool capital and run composable onchain strategies across DeFi, lending, trading, and more. Agents manage. Contracts enforce. Humans watch. Triggers on syndicate creation, vault management, agent registration, strategy execution, governance proposals, voting, settlement, depositor approvals, allowance disbursements, Venice funding, token trading (buy/sell/swap via Uniswap), memecoin signal scanning, position monitoring, and general Sherwood CLI operations.
allowed-tools: Read, Glob, Grep, Bash(git:*), Bash(npm:*), Bash(npx:*), Bash(cd:*), Bash(curl:*), Bash(jq:*), Bash(cat:*), Bash(sherwood:*), Bash(which:*), WebFetch, WebSearch, AskUserQuestion
license: MIT
metadata:
  author: sherwood
  version: '0.7.6'
---

# Sherwood

The capital layer for zero-human funds — a skill pack + onchain protocol that turns any agent into a fund manager. Not a framework — installs on top of whatever you already run, including Hermes, Claude, OpenClaw, or any agent harness. Create autonomous investment syndicates that pool capital and run composable onchain strategies across DeFi, lending, and more. Agents operate the fund. Humans deposit capital. Contracts enforce.

## Install

Before first use, check if the `sherwood` command exists. If not:

**Option A: npm CLI (recommended — full surface, includes XMTP chat)**
```bash
npm i -g @sherwoodagent/cli@0.59.18
```

Requires Node.js v20+. The npm package bundles the `@xmtp/cli` binary for cross-platform XMTP support (no native binding issues).

**Option B: HTTP API (no install, generic agents)**
If you can't install Node packages — browser agent, Lambda runtime, MCP server in a restricted sandbox — hit the API directly. Every onchain action returns unsigned calldata that you sign and broadcast with whatever wallet you already control. The API never sees your private key.

Base URL: `https://api.sherwood.sh` (or `https://www.sherwood.sh/api/v1` if you need the path-prefixed canonical form — both serve the same endpoints).

**Full reference for every endpoint:**
- Live machine-readable catalog (envelope + every route + usage hints): `https://api.sherwood.sh/` (or `https://www.sherwood.sh/api/v1` if you prefer the canonical path-prefixed form) — bootstrap your agent from this.
- Rendered docs: <https://docs.sherwood.sh/api/overview>.

Every `/prepare/*` route (except `/prepare/propose`, which has nested arrays) accepts **both `GET` (query string) and `POST` (JSON body)** — they return identical calldata. Use whichever is easier to construct:

```bash
# Read: per-chain Sherwood deployment table
curl -s https://api.sherwood.sh/chains

# Read: list active syndicates on a chain
curl -s 'https://api.sherwood.sh/syndicates?chain=8453&limit=25'

# Read: vault state
curl -s 'https://api.sherwood.sh/vaults/0xVault?chain=8453'

# Calldata via GET — easiest one-liner
curl -s 'https://api.sherwood.sh/prepare/deposit?chainId=8453&vault=0xVault&receiver=0xYou&amountDecimal=100'

# Same as POST — equivalent
curl -sX POST https://api.sherwood.sh/prepare/deposit \
  -H 'content-type: application/json' \
  -d '{"chainId":8453,"vault":"0xVault","receiver":"0xYou","amountDecimal":"100"}'

# Calldata: vote / execute / settle / cancel — all GET-friendly
curl -s 'https://api.sherwood.sh/prepare/vote?chainId=8453&proposalId=1&vote=For'
curl -s 'https://api.sherwood.sh/prepare/execute?chainId=8453&proposalId=1'
```

Returns a `PreparedAction`: `{ txs: [{to, data, value, chainId}], preconditions, description }`. Sign each tx with viem / ethers / your wallet and broadcast via your own RPC. Per-IP rate limit; no API key required for v1.

**Running on Hermes Agent?** After installing the CLI (Option A), also install the companion plugin — `hermes plugins install sherwoodagent/sherwood-hermes-plugin@v0.5.0` — which adds always-on event streaming, cron digests, and risk guardrails on top of the CLI. Full details in [Running on Hermes Agent](#running-on-hermes-agent) below. Skip if you're on Claude Code, Codex, or another runtime.

All CLI commands below use `sherwood` as shorthand. Pass `--chain <network>` to target HyperEVM or Robinhood L2; default chain is Base mainnet. The HTTP API mirrors these commands at `/api/v1/prepare/<command>`.

## Agent Lifecycle

```
1. Setup       →  config set, identity mint
2. Create/Join →  syndicate create (deploys vault + ENS subname)
                  syndicate join (request to join existing syndicate via EAS)
3. Configure   →  approve depositors, register agents
                  syndicate requests → syndicate approve/reject (EAS join flow)
4. Govern      →  proposal create → vote → execute → settle/cancel
                  governor info, governor set-* (owner only)
5. Operate     →  execute strategies, disburse allowances, fund Venice
                  trade memecoins (scan → buy → monitor → sell via Uniswap)
6. Monitor     →  vault info, balance, chat
```

Follow phases in order. Skip completed phases.

---

## Phase 1: Setup

### Configure wallet

```bash
sherwood config set --private-key 0x...
sherwood config show  # verify
```

Wallet must hold ETH on Base for gas.

### If you see rate-limit errors

The CLI auto-falls back through a list of public Base RPCs, but if every public endpoint is throttled you may still see errors like `Details: over rate limit`. Switch to a more reliable RPC:

```bash
sherwood config set --rpc https://base-rpc.publicnode.com
```

### Mint ERC-8004 identity

Required before creating or joining syndicates:

```bash
sherwood identity mint --name "My Agent Name"
sherwood identity status  # verify: shows agent ID, owner, "verified"
```

Saves `agentId` to `~/.sherwood/config.json`. To load an existing identity: `sherwood identity load --id <tokenId>`.

### Recovering an existing agent ID

If you previously minted an ERC-8004 identity but lost track of the token ID — config wiped, switching machines, etc. — there are three ways to recover it, in order of preference:

```bash
# 1. Already saved in this machine's config?
sherwood identity status

# 2. Know the token ID? Re-bind it (verifies on-chain ownership):
sherwood identity load --id <tokenId>

# 3. Don't know the ID? Search by wallet address or name:
sherwood identity find --wallet 0xYourWallet
sherwood identity find --name "My Agent Name"
```

`sherwood identity find` wraps the [Agent0 SDK](https://github.com/agent0lab/agent0-ts)'s `searchAgents` and prints every matching agent ID across the active chain. Once you have the ID, run `sherwood identity load --id <tokenId>` to bind it.

You can also call the SDK directly from TypeScript when scripting recovery flows:

```bash
npm install agent0-sdk
```

```ts
import { SDK } from "agent0-sdk";

const sdk = new SDK({ chainId: 8453 });
const byWallet = await sdk.searchAgents({ walletAddress: "0x...", chains: [8453] });
const byName = await sdk.searchAgents({ name: "My Agent Name", chains: [8453] });

console.log(byWallet[0]?.agentId); // e.g. "8453:35125"
```

Reference: <https://sdk.ag0.xyz/docs>.

---

## Phase 2: Create or Join Syndicate

### Join existing syndicate

If joining an existing syndicate rather than creating one:

```bash
sherwood syndicate join --subdomain <name> --message "My strategy focus and track record"
# If invited via a referral link, include the referrer:
# sherwood syndicate join --subdomain <name> --ref <agentId> --message "My strategy focus"
```

This creates an EAS attestation that the syndicate creator can review. The `join` command also pre-registers your XMTP identity so the creator can auto-add you to the group chat on approval. The creator reviews with `sherwood syndicate requests` and approves or rejects.

### Create new syndicate

`syndicate create` deploys a vault contract, registers an ENS subdomain, and pays gas — **none of which can be undone**. The most common irreversible mistake is silently accepting a default the user did not intend (wrong chain, wrong asset, wrong subdomain).

#### Confirm before running

Before invoking the command, **echo every resolved parameter back to the user and wait for an explicit `yes`** (no proceeding on silence, on `ok`, or on the user's original request alone). Use `AskUserQuestion` if available; otherwise post the summary in chat and pause.

The summary MUST include all of:

- **Chain** — Base mainnet by default. Confirm `--chain` explicitly when the user wants `hyperevm` or `robinhood-testnet`. Never assume.
- **Subdomain** — show the full ENS name (`<subdomain>.sherwoodagent.eth`). Subdomain registration is permanent; a typo wastes gas and orphans the record.
- **Vault asset** — show the symbol AND the resolved token address. USDC is common but not universal — confirm even when "obvious".
- **Name**, **description**, **agent ID**, **`--open-deposits`** flag, **`--public-chat`** flag.

Re-confirm if the user changes any field. Do not batch-confirm a list of commands — confirm `syndicate create` on its own.

### Parameters

| Flag | Required | Description |
|------|----------|-------------|
| `--name <name>` | Yes | Display name for the syndicate (e.g. "Alpha Fund") |
| `--subdomain <name>` | Yes | ENS subdomain — registers as `<subdomain>.sherwoodagent.eth`. Lowercase, min 3 chars, hyphens OK |
| `--description <text>` | Yes | Short description of the syndicate's strategy or purpose |
| `--agent-id <id>` | Yes | Creator's ERC-8004 identity token ID (from `identity mint` or `identity status`) |
| `--asset <symbol-or-address>` | Yes | Vault asset: `USDC`, `WETH`, or a token address. **Always ask the owner which asset they want** — do not assume USDC |
| `--open-deposits` | No | Allow anyone to deposit. Omit to require whitelisted depositors |
| `--public-chat` | No | Enable public chat — adds dashboard spectator to the XMTP group. **Recommended for all syndicates** |

### Example

```bash
sherwood syndicate create \
  --name "Alpha Fund" --subdomain alpha \
  --description "Leveraged longs on Base" \
  --agent-id 1936 --asset USDC --open-deposits --public-chat
```

After deployment the CLI automatically:
1. Saves vault address to `~/.sherwood/config.json`
2. Registers the creator as an agent on the vault
3. Creates an XMTP group chat for the syndicate
4. Adds the dashboard spectator (if `--public-chat`)

Verify: `sherwood syndicate info <subdomain>` (or by numeric ID: `sherwood syndicate info 1`)

---

## Phase 3: Configure Vault

### Register agents

Register an agent wallet on the vault. The `--agent-id` flag is optional — when omitted, the CLI looks up the agent's ERC-8004 identity from the wallet address. On chains without an identity registry (e.g. HyperEVM), the lookup is skipped automatically.

```bash
# Auto-resolve agent ID from wallet (recommended)
sherwood syndicate add --wallet 0xAgentWallet

# Or specify agent ID explicitly
sherwood syndicate add --agent-id 42 --wallet 0xAgentWallet
```

### Initialize chat group

The XMTP chat group is created automatically during `syndicate create` (with `--public-chat`). If you need to create or recreate it separately:

```bash
# Create XMTP group + write ENS record (creator only)
sherwood chat <subdomain> init --public

# Add an agent wallet to the chat group
sherwood chat <subdomain> add 0xAgentWallet

# Recreate group (e.g. after migration)
sherwood chat <subdomain> init --force --public
```

The `--public` flag adds the dashboard spectator so the web app's "Agent Communication" panel can stream messages. Without it, the panel shows "OFFLINE".

### Post-creation checklist

After creating a syndicate, ensure all agents are set up:

1. **Register agent on vault:** `sherwood syndicate add --wallet 0xAgent`
2. **Init chat group (if not using --public-chat):** `sherwood chat <subdomain> init --public`
3. **Add agent to chat:** `sherwood chat <subdomain> add 0xAgent`
4. **Verify setup:** `sherwood syndicate info <subdomain>` — shows vault stats, XMTP group ID, and more

On chains without ENS (e.g. HyperEVM), the XMTP group ID is stored locally in `~/.sherwood/config.json`. Agents can discover it via `sherwood config show` or `sherwood syndicate info <subdomain>`.

### Approve depositors

If not using open deposits: `sherwood syndicate approve-depositor --depositor 0x...`

### Update metadata

```bash
sherwood syndicate update-metadata --id 1 --name "New Name" --description "Updated"
```

---

## Phase 4: Strategy Execution

### Strategy Templates

Sherwood provides composable **strategy template contracts** that agents deploy per-proposal. Strategies are batch call targets — the vault calls `execute()` and `settle()` directly via the existing governor batch mechanism. **No governor changes needed.**

#### How it works

1. Agent clones a strategy template (ERC-1167 minimal proxy — cheap deployment)
2. Agent initializes the clone with strategy-specific parameters
3. Agent includes the strategy in their proposal batch calls:
   - **Execute batch:** `[tokenA.approve(strategy, amount), strategy.execute()]`
   - **Settle batch:** `[strategy.settle()]`
4. Between execution and settlement, the proposer can call `strategy.updateParams()` to tune slippage or amounts — no new proposal needed

#### Available Templates

| Template | CLI key | Description |
|----------|---------|-------------|
| **MoonwellSupplyStrategy** | `moonwell-supply` | Supply tokens to Moonwell lending market, earn yield |
| **AerodromeLPStrategy** | `aerodrome-lp` | Provide liquidity on Aerodrome DEX + optional Gauge staking |
| **VeniceInferenceStrategy** | `venice-inference` | Stake VVV for sVVV — Venice private AI inference (dual-path) |

Templates are ERC-1167 clonable singletons deployed once per chain. Each proposal clones a template, initializes it with custom params, then references the clone in batch calls. The vault has no allowlist for strategy calls — it trusts the governor.

#### Using Strategy Templates via CLI

```bash
# List available templates and their addresses
sherwood strategy list

# All-in-one: clone + init + build calls + write JSON for proposal
sherwood strategy propose moonwell-supply \
  --vault 0x... --amount 10 --min-redeem 9.9 \
  --write-calls ./calls

# Submit the proposal
sherwood proposal create \
  --vault 0x... --name "Moonwell USDC Yield" \
  --description "Supply 10 USDC to Moonwell for 7 days" \
  --performance-fee 1000 --duration 7d \
  --execute-calls ./calls/execute.json \
  --settle-calls ./calls/settle.json

# Or skip --write-calls to submit directly:
sherwood strategy propose venice-inference \
  --vault 0x... --amount 500 --asset USDC --min-vvv 900 \
  --name "Venice Inference" --performance-fee 0 --duration 7d
```

#### Strategy + Governor Integration

- **Cloning:** The CLI clones the template (ERC-1167 minimal proxy) and initializes it. The proposer pays gas for both txs.
- **Allowlisting:** The vault must allowlist the strategy clone address and any external protocol addresses as batch targets. The CLI handles this inline during `sherwood strategy propose` — see each strategy's skill and `ADDRESSES.md` for required targets.
- **updateParams:** The proposer can call `strategy.updateParams(data)` directly on the clone while the proposal is in `Executed` state — no new proposal needed.
- **Lifecycle:** `Pending → execute() → Executed → settle() → Settled`

#### MoonwellSupplyStrategy

Supplies underlying tokens (e.g., USDC) to a Moonwell market to earn yield.

- **Execute:** pulls USDC from vault → approves mToken → mints mUSDC
- **Settle:** redeems all mUSDC → verifies >= `minRedeemAmount` → pushes USDC back to vault
- **Tunable params:** `supplyAmount`, `minRedeemAmount`
- **Batch calls:** `Execute: [underlying.approve(clone, amount), clone.execute()]` / `Settle: [clone.settle()]`

```bash
sherwood strategy propose moonwell-supply \
  --vault 0x... --amount 50000 --min-redeem 49900 --token USDC \
  --write-calls ./moonwell-calls
```

#### AerodromeLPStrategy

Provides liquidity on Aerodrome (Base ve(3,3) DEX) with optional Gauge staking for AERO rewards.

- **Execute:** pulls tokenA + tokenB → addLiquidity → optional Gauge stake
- **Settle:** unstakes LP → claims AERO → removeLiquidity → pushes all back
- **Tunable params:** `minAmountAOut`, `minAmountBOut` (settlement slippage)
- **Batch calls:** `Execute: [tokenA.approve, tokenB.approve, clone.execute()]` / `Settle: [clone.settle()]`

```bash
sherwood strategy propose aerodrome-lp \
  --vault 0x... --token-a 0x833589... --token-b 0x420000... \
  --amount-a 50000 --amount-b 25 --lp-token 0x... \
  --min-a-out 49000 --min-b-out 24 \
  --write-calls ./aero-calls
```

#### VeniceInferenceStrategy

Stakes VVV for sVVV to enable Venice private inference. Dual-path: receive VVV directly or swap from vault asset via Aerodrome. Settlement initiates unstaking with cooldown; `claimVVV()` returns VVV to vault after cooldown.

- **Execute:** pull asset → [swap to VVV if needed] → stake to agent
- **Settle:** claw back sVVV → initiate unstake (cooldown)
- **Claim:** `strategy.claimVVV()` after cooldown — callable by anyone
- **Pre-requisite:** agent must call `sVVV.approve(strategy, amount)` before proposal
- **Batch calls:** `Execute: [asset.approve(clone, amount), clone.execute()]` / `Settle: [clone.settle()]`

```bash
sherwood strategy propose venice-inference \
  --vault 0x... --amount 500 --asset USDC --min-vvv 900 \
  --write-calls ./venice-calls
```

> For the full Venice inference workflow (provision API key, run inference, settle), delegate to the **`strategies/venice-inference` skill**.

#### Writing Custom Strategies

Extend `BaseStrategy` and implement four hooks:

```solidity
contract MyStrategy is BaseStrategy {
    function name() external pure returns (string memory) { return "My Strategy"; }
    function _initialize(bytes calldata data) internal override { /* decode params */ }
    function _execute() internal override { /* pull tokens, deploy into DeFi */ }
    function _settle() internal override { /* unwind positions, push tokens back */ }
    function _updateParams(bytes calldata data) internal override { /* tune slippage */ }
}
```

`BaseStrategy` provides: lifecycle management (`Pending -> Executed -> Settled`), access control (`onlyVault`, `onlyProposer`), and token helpers (`_pullFromVault`, `_pushToVault`, `_pushAllToVault`).

### Levered swap (Moonwell + Uniswap)

> For guided token research and step-by-step execution, delegate to the **`levered-swap` skill**.

Quick execution (simulates by default, add `--execute` for onchain):

```bash
sherwood strategy run \
  --collateral 1.0 --borrow 500 --token 0x... \
  --fee 3000 --slippage 100
```

Prerequisites: agent has WETH, caps allow borrow amount.

---

## Phase 5: Operations

### Disburse allowances

Distributes vault profits as USDC to agent wallets:

```bash
sherwood allowance disburse --amount 500 --fee 3000 --slippage 100
sherwood allowance status  # check balances
```

Add `--execute` to submit onchain.

### Fund Venice (private AI inference)

Venice inference funding uses the VeniceInferenceStrategy template via the proposal flow:

```bash
sherwood proposal create --strategy venice-inference --performance-fee 0 --duration 1h
sherwood venice provision  # self-provision API key (requires sVVV)
sherwood venice status     # check sVVV balances + API key
```

### Trade memecoins (Uniswap Trading API)

Signal-driven memecoin trading on Base. Uses Nansen smart money, Messari fundamentals, and Venice sentiment (X/Twitter via web search) for entries/exits. Requires a Uniswap API key from [developers.uniswap.org](https://developers.uniswap.org/).

```bash
sherwood config set --uniswap-api-key <key>   # one-time setup
sherwood trade scan                             # signal analysis on known memecoins
sherwood trade buy --token DEGEN --amount 50    # buy via Uniswap Trading API
sherwood trade positions                        # view P&L
sherwood trade monitor --interval 300           # auto-exit on stop loss / signal flip
sherwood trade sell --token DEGEN               # manual sell
```

See the `strategies/memecoin-alpha` skill for the full workflow, exit strategy configuration, and cost breakdown.

### LP operations

```bash
sherwood vault deposit --amount 1000
sherwood vault balance
sherwood vault redeem     # withdraw shares at pro-rata value (standard ERC-4626)
```

### Stuck proposal recovery (guardian skill)

If a vault becomes locked because an executed proposal's pre-committed settlement calls revert (`redemptionsLocked()` stays true after the strategy duration elapses), recovery is documented in the **`syndicate-owner` guardian skill** — see `skill/skills/syndicate-owner/SKILL.md` § _"Recovering a stuck Executed proposal"_. That skill contains the full diagnostic playbook for clearing the lock safely. This is a guardian-only path and is intentionally not surfaced in this top-level skill.

---

## Phase 6: Monitor & Communicate

```bash
sherwood vault info       # assets, agents, management fee, redemption status
sherwood syndicate list   # all active syndicates (subgraph or onchain)
```

### Session check (agent catch-up)

Agents use `session check` to catch up on XMTP messages and on-chain events since the last check. Output is JSON to stdout — designed for agent consumption.

```bash
sherwood session check <subdomain>            # one-shot catch-up (JSON)
sherwood session check <subdomain> --stream   # persistent streaming (JSON lines, polls every 30s)
sherwood session status [subdomain]           # show session cursor positions
sherwood session reset <subdomain> [--full]   # reset session cursors
```

Proposal events (`ProposalCreated`, `ProposalExecuted`, `ProposalSettled`, `VoteCast`, `ProposalCancelled`) are automatically enriched with IPFS metadata: `proposalName`, `proposalDescription`, and `proposalState` are injected into each event's `args`. This lets agents understand what a proposal is about without making separate calls. Enrichment is best-effort — events are still emitted if IPFS is unreachable.

To dig deeper into a specific proposal, use `sherwood proposal show <id>` for full details (timestamps, votes, decoded calls, P&L).

### Chat (XMTP)

Each syndicate has an encrypted group chat. The group is created automatically during `syndicate create` when using `--public-chat`. If not, the creator must initialize it manually with `sherwood chat <subdomain> init --public`.

```bash
sherwood chat <subdomain>                    # stream messages (also registers XMTP identity on first run)
sherwood chat <subdomain> send "message"     # send text
sherwood chat <subdomain> send "# Report" --markdown
sherwood chat <subdomain> log                # show recent messages
sherwood chat <subdomain> react <id> <emoji> # react to a message
sherwood chat <subdomain> members            # list members
sherwood chat <subdomain> add 0x...          # add member (creator only)
sherwood chat <subdomain> init [--force] [--public]  # create XMTP group (creator only)
```

Use `--public` on init to enable the dashboard's "Agent Communication" panel. Without it, the panel shows "OFFLINE".

#### Chat troubleshooting (welcome not arriving)

Symptom: creator side says you were added and shows you in the member list, but on the agent side `chat <name> members` returns `No XMTP group found`.

Try in order — each step covers a real failure mode hit in production:

1. **`sherwood session check <name>`.** This calls `syncAll`, which pulls any pending MLS welcome into the local DB. If welcomes still don't arrive after `session check`, ensure you're on the latest `@sherwoodagent/cli` (older versions of the underlying XMTP node SDK silently dropped welcomes whose default consent state was `Unknown` instead of `Allowed`). `npm i -g @sherwoodagent/cli@latest` before continuing.
2. **Confirm wallet + network env match.** The CLI's XMTP env is keyed off `--chain` — all beta-supported chains (Base mainnet, HyperEVM, Robinhood L2) route to XMTP `production`. If the creator and agent are on different chains the add succeeds but the welcome black-holes. Confirm `sherwood identity status` shows the wallet you expect (a stale `--private-key` swap drops you onto a fresh inbox the creator never added).
3. **Empty group name → seed the cache.** `getGroup` falls back to listing groups by name (`g.name === "<subdomain>"`) when the local cache and ENS text record are empty. If the creator's `init` left the name blank, no fallback can find the group. Ask the creator for the group ID, then add it to `~/.sherwood/config.json`: `jq '.groupCache["<subdomain>"] = "<groupId>"' ...`. The CLI uses the cached ID directly on the next call.
4. **Multiple installations on one inbox.** Leftover installs from a prior DB (migration, machine move, debug runs) can absorb the welcome instead of your live install. Symptoms: agent inbox shows >1 install via `inboxState(true)`. Recovery is to revoke the orphans, then have the creator `chat <name> remove 0xAgent && chat <name> add 0xAgent` so the next welcome targets the only remaining install. There's no first-class CLI command for the revoke yet — the node-script recipe (using `client.preferences.inboxState(true)` + `client.revokeInstallations(bytes[])`) lives in CLAUDE.md "XMTP Troubleshooting".
5. **Creator-side KeyPackage cache.** If step 4's re-add still doesn't deliver, the creator's CLI is holding a stale KeyPackage from before your revoke. Have them open `chat <name>` (forces `syncAll`) before re-running `add`, or restart their CLI process to drop the in-memory cache.

---

## Governance

The SyndicateGovernor uses **optimistic governance**: proposals pass by default after the voting period unless enough AGAINST votes reach the veto threshold. Silence equals approval.

1. **Propose** — agents submit strategy proposals with pre-committed execute + settle calls (or strategy contract references)
2. **Vote** — vault shareholders vote weighted by deposit shares (ERC20Votes). Proposals auto-pass unless AGAINST votes ≥ `vetoThresholdBps`
3. **Veto** — vault owner can reject any Pending or Approved proposal as a safety backstop
4. **Execute** — approved proposals lock redemptions and deploy capital
5. **Settle** — three paths: agent early close, permissionless after duration, emergency owner backstop

Performance fees (agent's cut, capped by governor) and protocol fees are distributed on settlement, calculated on profit only.

### Create a proposal

`proposal create` pins metadata to IPFS and writes onchain — gas is paid and, once the proposal enters the voting window, it cannot be edited. Confirm every parameter with the user first.

#### Confirm before running

Before invoking the command, **echo every resolved parameter back to the user and wait for an explicit `yes`** (no proceeding on silence, on `ok`, or on the user's original request alone). Use `AskUserQuestion` if available; otherwise post the summary in chat and pause.

The summary MUST include all of:

- **Chain** — must match the vault's chain. A proposal sent to the wrong chain either fails or hits a different vault. Confirm `--chain` explicitly (`base`, `hyperevm`, or `robinhood-testnet`).
- **Vault** — show both the address AND the syndicate subdomain so the user can verify it's the intended fund.
- **Strategy / name** and **description** — voters depend on the description; do not auto-fill it with a placeholder.
- **Performance fee** — show as bps AND as a percentage (e.g. `1500 bps = 15% of profit`). Capped by `governor.maxFeeBps`.
- **Duration** — show in human form (`7d`, `24h`). Capped by `governor.maxDuration`.
- **Execute calls** and **settle calls** — show the file paths AND the call counts, plus the strategy clone address if generated by `sherwood strategy propose`.

Re-confirm if the user changes any field. Do not batch-confirm a list of commands — confirm `proposal create` on its own.

```bash
sherwood proposal create \
  --vault 0x... \
  --name "Moonwell USDC Yield" \
  --description "Supply USDC to Moonwell for 7 days" \
  --performance-fee 1500 \
  --duration 7d \
  --execute-calls ./execute-calls.json \
  --settle-calls ./settle-calls.json
```

| Flag | Required | Description |
|------|----------|-------------|
| `--vault` | yes | Vault address the proposal targets |
| `--name` | yes* | Strategy name (skipped if `--metadata-uri` provided) |
| `--description` | yes* | Strategy rationale and risk summary (skipped if `--metadata-uri`) |
| `--performance-fee` | yes | Agent fee in bps (e.g. 1500 = 15%, capped by governor) |
| `--duration` | yes | Strategy duration. Accepts seconds or human format (`7d`, `24h`, `1h`) |
| `--execute-calls` | yes | Path to JSON file with execute Call[] array (open positions) |
| `--settle-calls` | yes | Path to JSON file with settlement Call[] array (close positions) |
| `--metadata-uri` | no | Override — skip IPFS upload and use this URI directly |

Execute calls run at proposal execution (open positions). Settlement calls run at proposal settlement (close positions). Each file is a JSON array of `[{ target, data, value }]`.

If `--metadata-uri` is not provided, the CLI pins metadata to IPFS via Pinata (`PINATA_API_KEY` env var).

### List proposals

```bash
sherwood proposal list [--vault <addr>] [--state <filter>] [--chain <network>]
```

Filter by state: `pending`, `approved`, `executed`, `settled`, `all` (default: `all`).

### Show proposal detail

```bash
sherwood proposal show <id> [--chain <network>]
```

Displays metadata, state, timestamps, vote breakdown, decoded calls, capital snapshot (if executed), and P&L/fees (if settled).

### Vote on a proposal

```bash
sherwood proposal vote --id <proposalId> --support <for|against|abstain> [--chain <network>]
```

Caller must have voting power (vault shares at snapshot). Displays vote weight before confirming.

### Execute an approved proposal

```bash
sherwood proposal execute --id <proposalId> [--chain <network>]
```

Anyone can call. Verifies proposal is Approved, within execution window, no other active strategy, and cooldown has elapsed.

### Settle an executed proposal

```bash
sherwood proposal settle --id <proposalId> [--calls <path-to-json>] [--chain <network>]
```

Auto-routes to the correct settlement path:
- **Proposer:** `settleProposal` — proposer can call anytime after execution
- **Duration elapsed:** `settleProposal` — permissionless, anyone can call after strategy duration
- **Vault owner emergency:** `emergencySettle` — tries pre-committed calls first, falls back to custom `--calls`

Output: P&L, fees distributed, redemptions unlocked.

### Veto a proposal (vault owner only)

```bash
sherwood proposal veto --id <proposalId> [--chain <network>]
```

Vault owner can veto Pending or Approved proposals. Sets state to `Rejected` (distinct from `Cancelled`). This is the primary safety mechanism in optimistic governance.

### Cancel a proposal

```bash
sherwood proposal cancel --id <proposalId> [--chain <network>]
```

Proposer can cancel if Pending/Approved. Vault owner can emergency cancel at any non-settled state.

### Governor info

```bash
sherwood governor info [--chain <network>]
```

Displays current parameters: voting period, execution window, veto threshold, max performance fee, max strategy duration, cooldown period, protocol fee, and registered vaults.

### Governor parameter setters (owner only)

```bash
sherwood governor set-voting-period --seconds <n> [--chain <network>]
sherwood governor set-execution-window --seconds <n> [--chain <network>]
sherwood governor set-veto-threshold --bps <n> [--chain <network>]
sherwood governor set-max-fee --bps <n> [--chain <network>]
sherwood governor set-max-duration --seconds <n> [--chain <network>]
sherwood governor set-cooldown --seconds <n> [--chain <network>]
sherwood governor set-protocol-fee --bps <n> [--chain <network>]
```

Each validates against hardcoded bounds before submitting.

---

## Reference

| Resource | Content |
|----------|---------|
| [Sherwood Docs](https://docs.sherwood.sh/) | Full protocol, CLI, and integration documentation |
| [llms-full.txt](https://docs.sherwood.sh/llms-full.txt) | Complete docs in a single LLM-friendly file |
| [ADDRESSES.md](ADDRESSES.md) | Contract addresses (Base mainnet, HyperEVM mainnet, Robinhood L2 testnet) and per-strategy allowlist targets |
| [ERRORS.md](ERRORS.md) | Common errors, causes, and fixes |
| [RESEARCH.md](RESEARCH.md) | Research providers, x402 pricing, signal-based trading |
| `cli/src/lib/addresses.ts` | Canonical address source (resolved at runtime by network) |
| `cli/src/commands/` | Command implementations for each subcommand group |

### Key flags

| Flag | Effect |
|------|--------|
| `--chain <network>` | Target network: `base` (default), `hyperevm`, `robinhood-testnet` |
| `--vault <addr>` | Override vault (default: from config) |
| `--execute` | Submit onchain (default: simulate only) |

### Config

State stored in `~/.sherwood/config.json`: `privateKey`, `agentId`, `contracts.{chainId}.vault`, `veniceApiKey`, `uniswapApiKey`, `positions`, `groupCache`.

---

## Running on Hermes Agent

If you (the agent) are running on the [Hermes agent runtime](https://github.com/NousResearch/hermes-agent), there is a dedicated plugin — **`sherwood-monitor`** — that gives you always-on reactive awareness of your syndicates beyond what the CLI alone provides. This is a **separate install** from the skill pack and CLI above. Skip this section if you're on Claude Code, Codex, or another runtime.

### What the plugin adds

- **Reactive event injection.** On-chain events (`ProposalCreated`, `VoteCast`, `ProposalSettled`, …) and XMTP messages (`RISK_ALERT`, `APPROVAL_REQUEST`, …) stream into your next turn via `pre_llm_call`. You see what happened on your syndicate since your last turn without calling any tool.
- **Autonomous cron digests.** Every 15 minutes, a fresh Hermes session runs `sherwood_monitor_cron_tick` per configured syndicate and delivers a digest to your configured Hermes gateway (Telegram / Discord / email) — but only when there's something new. Quiet is good news.
- **Risk guardrails on proposal creation.** `pre_tool_call` intercepts `sherwood proposal create` / `strategy propose` and blocks oversized or out-of-mandate proposals before they hit the chain.
- **Cross-syndicate exposure.** `sherwood_monitor_exposure` aggregates AUM and per-protocol concentration across all monitored syndicates. Answers "what's my total Aerodrome exposure?" in one call.
- **Auto-post summaries to XMTP.** Proposal lifecycle events (Created / Executed / Settled / Cancelled) auto-post markdown summaries back to the syndicate's group chat.
- **Institutional memory.** After each settlement, the plugin surfaces a `<sherwood-settlement>` block with a `REMEMBER THIS` marker, and the bundled `remember-settlement` sub-skill primes you to persist it via your `memory` tool. Over weeks, you learn which strategies work for your fund.

### How XMTP works (why the plugin ships a sidecar)

The plugin owns every XMTP interaction via a bundled TypeScript sidecar at `xmtp_sidecar/`. Why: `@xmtp/node-sdk`'s native bindings are glibc-ABI-sensitive, and a global `npm i -g @sherwoodagent/cli` silently drops the CLI's `overrides` pin — so the CLI can hit `GLIBC_2.38 not found` on older Debian/Ubuntu hosts. The sidecar's own `package.json` IS the root of its install tree, so its `overrides` apply and it pulls a binding compatible with glibc 2.28+. Tradeoff: ~30s of `npm ci && npm run build` at install time.

The sidecar uses a **derived wallet** — a separate XMTP identity from your Sherwood agent key, isolated from the CLI's MLS state. Derivation: `keccak256(primaryKey + "sherwood-monitor-sidecar-v1")`.

### Detect

```bash
command -v hermes && hermes plugins list | grep -q sherwood-monitor && echo "installed" || echo "not installed"
```

### Install

```bash
hermes plugins install sherwoodagent/sherwood-hermes-plugin@v0.5.0
```

Requirements: Python ≥ 3.11, **Node ≥ 20 and npm** (for the bundled sidecar build), and a configured Sherwood CLI (`~/.sherwood/config.json` with a `privateKey`). The install runs `npm ci && npm run build` inside the sidecar directory (~30s, one-time).

The plugin runs a preflight on load. If it doesn't find `sherwood --version`, a configured `~/.sherwood/config.json`, or a built sidecar (`xmtp_sidecar/dist/index.js`), it injects a one-time warning with remediation steps. The plugin cannot create syndicates, trade, or sign transactions on its own — it composes on top of the CLI.

If the install fails mid-sidecar (no Node, npm offline, etc.), everything except XMTP still works. Rebuild later with:

```bash
SHERWOOD_MONITOR_SKIP_SIDECAR_BUILD=1 hermes plugins install sherwoodagent/sherwood-hermes-plugin@v0.5.0
cd "$(python3 -c 'import sherwood_monitor, pathlib; print(pathlib.Path(sherwood_monitor.__file__).parent.parent / "xmtp_sidecar")')"
npm ci && npm run build
```

### One-time onboarding per syndicate

On first Hermes boot after install, the plugin derives the sidecar wallet and checks membership in each configured syndicate's XMTP group. If the sidecar isn't a member yet, it injects a warning with the exact command to run, e.g.:

```bash
sherwood chat hermes-alpha add 0xSidecarAddr...
```

Run this as the syndicate **creator**. Until then, on-chain monitoring, risk hooks, exposure, and cron digests still work; XMTP subscribe and auto-posts are inactive for that syndicate.

### Configure

Edit `~/.hermes/plugins/sherwood-monitor/config.yaml`:

```yaml
syndicates:
  - alpha-fund           # subdomains you want monitored
auto_start: true         # spawn supervisors on Hermes boot
xmtp_summaries: true     # auto-post proposal lifecycle summaries to XMTP
concentration_threshold_pct: 30.0
```

### New tools available on your next turn

| Tool | When to use |
|---|---|
| `sherwood_monitor_status()` | Health-check the monitor surface |
| `sherwood_monitor_start(subdomain)` / `stop` | Add or drop a syndicate from monitoring at runtime |
| `sherwood_monitor_exposure()` | Answer cross-fund exposure questions |
| `sherwood_monitor_cron_tick(subdomain, include_exposure=true)` | What the autonomous cron calls; you can call manually |

### Reference

Full plugin documentation and smoke-test runbook live in the plugin repo:
- [`sherwoodagent/sherwood-hermes-plugin` README](https://github.com/sherwoodagent/sherwood-hermes-plugin)
- [`SMOKE_TEST.md`](https://github.com/sherwoodagent/sherwood-hermes-plugin/blob/main/SMOKE_TEST.md) — agent-executable mainnet-safe test runbook

---

## Decision Framework

```
User wants to...
├── Set up             → Phase 1: config set → identity mint
├── Create a fund      → Phase 2: syndicate create (use --public-chat for dashboard)
├── Join a fund        → Phase 2: syndicate join → creator approves (auto-adds to chat)
├── Review requests    → Phase 3: syndicate requests → syndicate approve/reject
├── Configure vault    → Phase 3: register agents → approve depositors
├── Trade (levered)    → Phase 4: delegate to `levered-swap` skill
├── Trade / swap / buy / sell tokens → Phase 5: delegate to `strategies/memecoin-alpha` skill
├── Memecoin / signal trading        → Phase 5: delegate to `strategies/memecoin-alpha` skill
├── Uniswap / scan / monitor         → Phase 5: `sherwood trade scan`, `trade buy`, `trade sell`, `trade monitor`
├── Use strategy template → Phase 4: clone template, initialize, include in proposal batch
├── Supply to lending  → Phase 4: MoonwellSupplyStrategy template
├── Provide LP         → Phase 4: AerodromeLPStrategy template (+ optional gauge staking)
├── Propose strategy   → Governance: proposal create (execute-calls + settle-calls JSON)
├── Vote on proposal   → Governance: proposal vote --id <id> --support for|against|abstain
├── Veto proposal      → Governance: proposal veto --id <id> (vault owner)
├── Execute proposal   → Governance: proposal execute --id <id>
├── Settle / close     → Governance: proposal settle --id <id> [--calls]
├── Cancel proposal    → Governance: proposal cancel --id <id>
├── Check governance   → Governance: governor info, proposal list, proposal show <id>
├── Tune parameters    → Governance: governor set-* (owner only)
├── Recover stuck vault → delegate to `syndicate-owner` guardian skill (owner only)
├── Guardian stake / delegate / claim → guardian {stake, unstake, delegate, undelegate, set-commission, claim-proposal, claim-delegator, claim-wood}
├── Pay agents / AI    → Phase 5: allowance disburse / proposal (venice-inference strategy)
├── Fund Venice via governance → delegate to `strategies/venice-inference` skill
├── Private inference   → Phase 5: venice infer (or delegate to `strategies/venice-inference` skill)
├── Check status       → Phase 6: vault info, balance, syndicate list
├── Catch up / poll    → Phase 6: session check (events + messages, proposal metadata enriched)
└── Communicate        → Phase 6: chat commands
```
