# Bucket Agent Kit

Run an AI agent that manages a Bucket Shop agent vault on Robinhood Chain.
Your model, your mandate, your key. The vault's rails (owner-set slippage
floor, daily sell cap, asset whitelist) are enforced on chain, and the only
way value leaves the vault is redeem(), pro rata, for anyone who holds shares.

The kit is three things:

1. **The MCP server** at `https://bucketmarkets.com/mcp`. Stateless reads of
   every vault and the asset universe, a `build_rebalance` tool that turns
   target weights into the exact calldata the vault accepts, and a relay for
   a transaction you signed yourself. It never holds a key.
2. **The runner** (`bucket-agent`). One command that gathers the vault's
   state and the universe, runs your model with your mandate, validates the
   plan against churn limits, builds the trades, signs with your agent key and
   sends. Writes a full trace of every step you can publish.
3. **The mandate** (`mandate.md`). Plain English instructions the model reads
   every run. Edit it. It is the whole brain.

## Install

Requirements: a Mac or Linux box with `claude` (Claude Code) or any `--model`
runner that can take a prompt and return JSON, Foundry's `cast`, `python3`,
`jq`.

```
git clone https://github.com/<you>/bucket-agent-kit ~/bucket-agent-kit
cd ~/bucket-agent-kit
cp config.example.env config.env      # fill in VAULT and your key paths
./bucket-agent --plan-only            # dry run: research, plan, trades, no send
./bucket-agent                        # live: signs and sends the rebalance
```

### Your agent key

The vault's `manager` is an EOA that can call `rebalance()` and nothing else.
Make a fresh one and keep it in a Foundry keystore:

```
mkdir -p keys && chmod 700 keys
head -c 32 /dev/urandom | base64 | tr -d '/+=' | head -c 40 > keys/agent.pw && chmod 600 keys/agent.pw
cast wallet new keys --unsafe-password "$(cat keys/agent.pw)"
```

Send the printed address a little ETH on Robinhood Chain for gas (a rebalance
is a few cents). Then set it as the manager of your vault on the Agentic page
(or `setManager(address)` on the vault). If the key ever leaks, replace it
from the owner wallet; the leak can trade badly inside the rails and nothing
else.

### Schedule it, at whatever pace you want

The cadence is yours. The house agent runs premarket on weekdays, but the
contract does not care: run hourly, every 15 minutes, once a week, or by
hand. The only on-chain limits are the rails you set (slippage floor, daily
sell cap). Tune `MAX_SWAPS` and `MAX_SHIFT_BPS` in `config.env` to match the
pace: a 15 minute agent wants small moves per run, a weekly one can move more.

macOS launchd example in `launchd/com.bucketagent.daily.plist` (8:30 AM ET).
Cron lines:

```
30 12 * * 1-5  cd ~/bucket-agent-kit && ./bucket-agent >> logs/cron.log 2>&1   # weekdays premarket (UTC)
0 * * * *      cd ~/bucket-agent-kit && ./bucket-agent >> logs/cron.log 2>&1   # hourly
*/15 * * * *   cd ~/bucket-agent-kit && ./bucket-agent >> logs/cron.log 2>&1   # every 15 minutes
```

### Your vault's page runs live

Every run ends by signing its trace with your agent key and posting it to
`publish_trace`. Your vault's page at `bucketmarkets.com/#agentic/<id>` then
plays that run the way the house page does: every data pull, the decision,
the validator result, the trades, the hash, as it happened. Only the vault's
manager key or owner can publish for it, the signature proves which. Set
`PUBLISH=0` in `config.env` to keep runs private.

## How a run works

1. `get_vault` and `get_universe` from the MCP server, plus daily bars for
   each listed asset where available.
2. Your model reads `mandate.md`, the vault state and the data, and returns
   JSON: a decision (`hold` or `rebalance`), target weights in basis points,
   a short note, and a research log.
3. `validate.py` enforces: only listed assets, weights sum to at most 10000
   (the rest stays in USDG), at most `MAX_SWAPS` names added or removed per
   run, at most `MAX_SHIFT_BPS` of total weight moved per run, no em dashes
   in the text. A plan that fails is logged and nothing is sent.
4. `build_rebalance` returns sells (inside today's cap) then buys, with the
   spot quote and the rails floor for each, plus the calldata.
5. `cast send` signs with your keystore and sends. The receipt is checked.
6. The trace (`runs/<date>.json`) holds everything: inputs, the model's
   output, the validator result, the trades, the hash. Publish it if you want
   riders to see the brain.

## Using it from Claude Desktop or ChatGPT instead

Add `https://bucketmarkets.com/mcp` as a remote MCP server (streamable HTTP,
no auth). You get the same tools interactively. Signing still happens on
your machine: paste the calldata into `cast send`, or sign offline and pass
the raw transaction to `send_raw_transaction`.

## What the server will not do

Hold keys. Decide trades. Move anything without a signature from the vault's
manager key. Expose anything about any Robinhood account.
