Website · Open app · Docs · X · npm
# merrymen **Autonomous trading agents with signed limits and readable research.** Run merrymen in the [hosted app](https://app.merrymen.dev) or on your own machine. Create an agent, choose its markets and limits, and follow its decisions, positions and trade outcomes from the dashboard or Telegram. **Use it from Claude:** tell Claude “set up merrymen mcp”, or add it in one click: (the one-time code shown in /settings)
→ you're now the owner; only allowlisted chats are obeyed
```
There's an obvious **Chat on Telegram** button right on the dashboard (topbar +
a card) so you don't have to hunt for it.
**Bring it into your Telegram groups.** Your merryman can hang out in a group
like one more person: it answers when it's called, now and then joins in,
remembers the chat, and when someone posts a coin it takes a look, tags them,
and says whether it's in or passing (in trencher mode, its Brain decides and
every limit still applies — a group message can nominate a coin, never order a
trade). It never posts alerts, sizes, prices or P&L, and nothing private.
```
4. Add your bot to a group — it only talks in groups you added it to or approved
(anyone else adds it → it stays silent and DMs you Stay / Leave)
5. To let it follow the chat: @BotFather → /setprivacy → your bot → Disable,
then remove the bot from the group and add it back
(until then it only hears commands and replies to its own messages)
6. /groups in your DM with the bot → every group it knows, with Stay · Leave · Forget
```
Turn it off, turn off "Look at coins people post", or pick how chatty it is in
`/settings` → Telegram → Telegram groups. `/forget` in a group (you) wipes what
it remembers of that group; `/forgetme` (anyone) removes theirs. (These are
your own Telegram groups, not the hosted app's public group chat room.) The
full rules: [`docs/tg-groups.md`](docs/tg-groups.md).
Commands work bare; with an Anthropic key, plain English does too ("how are we
doing?", "pause everything", "send 20 USDG to 0x…", "ping me when QQQ hits 600",
"why did you buy that?"). Voice notes work as well.
| command | does |
|---|---|
| `/status` `/positions` `/pnl` `/trades` | read the live book |
| `/report` · `/brag` · `/why` | daily campfire report · shareable scorecard · explain the last trade |
| `/buy ` `/sell ` | trade (passes the policy wall) |
| `/transfer <0x…> ` | send USDG out — **always asks you to `/confirm`** |
| `/alert > ` `/alerts` `/unalert ` | one-shot price alerts |
| `/pause` `/resume` · `/strategy ` · `/cap ` | steer the worker (cap only tightens) |
| `/name ` · `/soul` · `/remember ` | name it, see who it is, teach it about you |
| `/groups` · `/forget` · `/forgetme` | your Telegram groups (Stay / Leave / Forget) · in a group: wipe its memory of that group · anyone in a group: drop what it remembers of them |
| `/kill` | destroy the grant, stand the band down |
| `/help` | the full list |
**It speaks first, too** (toggle in `/settings`): a ping the moment a trade lands
or the wall turns one back; warnings when the grant nears expiry, drawdown nears
the breaker, or gas runs low; your price alerts; and a **daily campfire report**
at the hour you pick.
**Transfers are refused outright.** A wallet signed today registers no
withdrawal address, so its call policy carries no USDG transfer permission at
all — the chain would refuse the send, and the worker refuses it first rather
than paying gas to be told no. A prompt-injected "send everything to 0xevil"
gets a flat no before anything is built. Money leaves through your owner key
(`merrymen recover`), which no wall can block and no chat message can reach.
Wallets signed before the withdrawal allowlist landed do carry a transfer
permission; for those, `/transfer` still applies its own guards — off by
default, and every transfer echoes the full recipient address and waits for an
explicit `/confirm` (90s). Turn off all state-changing commands with the
**control** toggle for read + chat only.
### Remote control — your merryman runs your PC (OpenClaw-style)
Enable the **remote control** section in `/settings` and your merryman can act on
the machine it runs on, from Telegram:
| capability | what it does |
|---|---|
| 📸 screen · 👁️ vision | `/shot` a screenshot; ask "what am I looking at? / read this error" (Claude vision) |
| 🚀 apps & web | `/open spotify`, `/open github.com` — allowlisted apps, any URL |
| ⚙️ system | `/sys` info, volume, media keys, `/notify`, `/lock`, sleep/shutdown |
| 📂 files · 📋 clipboard | `/ls`, `/get` inside one folder you pick; read/set the clipboard |
| 🖥️ shell · ⌨️ keyboard | `/run` allowlisted commands; `/type`, `/key ctrl+s` |
| 🎙️ voice · 👀 watchers | voice note → command; `/remind 20m …`, `/watch cpu>80`, `/watch file …`, `/watch proc …` |
**The safety model is the point** — it's a hot wallet for your desktop:
- **Off by default**, then **one capability at a time** — nothing runs unless you
turned that group on. `/pc` shows what's enabled; the master switch off kills
all of it instantly.
- **Allowlists for the sharp edges**: shell runs *only* your exact pre-approved
commands (chaining/redirects always refused); files are confined to one root
(no `..` escape); apps to a name list.
- **Confirm gate**: shell, keyboard, file-send, and power never fire until you
reply `/confirm` to the exact action echoed back.
- **Local + logged**: a chat message can only ever emit one command from a closed
set — it can't invent a capability or smuggle a raw command past the allowlist.
Windows is fully supported; macOS/Linux use the standard tools (`screencapture`,
`open`, `pbcopy`, …) and say so where one isn't present. Voice needs an
OpenAI-compatible transcription key (set it in the dashboard).
### Your merryman has a soul
Every merryman is an individual with a name **you** give it — and it grows with
you. Its soul lives as plain markdown in **`~/.merrymen/soul/`** that it keeps up
to date itself (read or edit it with any editor):
| file | what it holds |
|---|---|
| `IDENTITY.md` | who it is — its name (`/name Will Scarlet`), born date |
| `OWNER.md` | what it's learned about **you**, one dated line at a time |
| `JOURNAL.md` | a first-person entry it writes at campfire time |
The longer you ride together, the closer the bond: *new companion* → *trusted
companion* (a week) → *old friend* (a month) → *sworn brother-in-arms* (100
days), with milestone messages and a tone that warms to match. Memory is
**context, never capability** — soul files flavor chat only; every command still
passes the closed enum and the policy wall, and the memory sanitizer refuses
anything address-, key-, or code-shaped, so a poisoned note can't smuggle a
recipient into a prompt.
---
## 5 · Use your merryman from Claude
Hosted Merrymen has an MCP server, so Claude (and Codex, Cursor, VS Code, …)
can work with your agent: check its status, trades and portfolio, explain why
it has or hasn't traded, research tokens, and prepare trades or setting changes
for you to approve.
**Set it up:** tell Claude “set up merrymen mcp”, or add it in one click:
. Other assistants:
. Setup instructions written for AI
assistants: .
In **Claude Code**, from a terminal, either add the server:
```bash
claude mcp add --transport http --scope user merrymen https://mcp.merrymen.dev/mcp
```
or install the plugin **instead** (it includes the server and adds
`/merrymen:status`, `/merrymen:why`, `/merrymen:portfolio`, `/merrymen:week`
and `/merrymen:token`; choose one route, not both):
```bash
claude plugin marketplace add https://github.com/millw14/merrymen.git
claude plugin install merrymen@merrymen
```
Then, in Claude Code, type `/mcp`, choose the Merrymen entry, choose
Authenticate and click Allow.
**What it can and cannot do:** it sees only the agent and the permissions you
allow when you sign in, and you can disconnect it at any time at
[Connected apps](https://app.merrymen.dev/connect/apps). It can suggest trades
or setting changes only if you allowed that, and nothing happens until you
approve each one in Merrymen. It can never move your funds, see your keys, turn
on live trading or loosen your limits. Paper (practice) and live money are
always reported separately. Details: [docs/mcp](docs/mcp/README.md).
---
## Strategies
Pick one in `/settings` (or `/strategy ` from Telegram; `MERRYMEN_STRATEGY`
is the headless fallback):
| name | what it does |
|---|---|
| `steady-basket` (default) | DCA a weighted stock basket per tick; idle cash sweeps to the Morpho vault; pulls cash back when short |
| `weekend-gap` | Enter each leg when its Chainlink feed goes stale (market close), exit when it refreshes (open) — a strategy class that only exists on-chain |
| `llm-strategist` | Claude proposes typed buy/sell/hold at decision windows; deterministic code validates and disposes — the model never sees an address or emits calldata. Needs an Anthropic key |
| `even-keel` 🏹 | Keeps the basket at equal weight — trims winners, tops up laggards — to harvest mean reversion. **Merry Circle** (holder-only) |
| `dip-hunter` 🏹 | Concentrates each tick on the basket token furthest below its rolling high. **Merry Circle** (holder-only) |
| `trencher` | Memecoin discovery and position management with liquidity, momentum and exit checks; live execution and fast mode require separate opt-ins |
### Write your own
Your strategies live in **`~/.merrymen/strategies/`** — hot-reloaded on save,
crash-isolated, and incapable of exceeding the caps you signed (every intent
passes shape validation → the policy wall → quote simulation → the on-chain
session key):
```bash
merrymen strategy new my-bot # commented template in ~/.merrymen/strategies
# edit it, select "my-bot" in /settings — done
```
Default-export `{ name, tick(snapshot, ctx) }` — no imports needed; `ctx` injects
the verified registry (`ctx.tokenBySymbol.QQQ`, `ctx.CASH.USDG`,
`ctx.UNISWAP.swapRouter02`, `ctx.usdg(10)`). See
[strategies/README.md](./strategies/README.md) and
[strategies/example-dip-buyer.mjs](./strategies/example-dip-buyer.mjs).
### Adding your own tokens (memecoins)
The built-in registry is the issuer-backed stock tokens — curated, Chainlink-priced.
Anything else on Robinhood Chain you add yourself in `/settings`: paste the symbol,
the contract address, and its decimals.
**How they're priced.** There's no Chainlink feed for a memecoin, so merrymen reads
the Uniswap v3 pool — but a spot price on a thin pool is worth nothing: anyone with
moderate capital can push it for a block, and that number would feed your equity,
your P&L and your drawdown breaker. So:
- **Valuation uses a 15-minute TWAP**, not spot. Moving it means holding the price
away from the market for the whole window and eating the arbitrage.
- **Two guards, both yours to set.** A minimum pool depth (default $25,000) and a
maximum spot-vs-average gap (default 5%). Live pools on this chain run from ~$3k
to ~$1.2M, so the default admits the deep end and refuses the rest.
- **A refusal is the feature.** When a pool is too thin or is being pushed right
now, the token stays *unpriced* and merrymen says why. Your agent keeps trading
— you can always sell out — but equity, P&L and the breaker pause rather than
running on a number nobody should trust.
- **Most memecoins here price through WETH.** About three quarters of the chain's
pools quote against WETH rather than USDG, so the route is usually two hops. Its
depth is the *shallower* leg — a deep WETH/USDG pool doesn't make a $3k memecoin
pool safe.
Anything valued this way is marked **pool px** in the dashboard and in `/status`,
because it isn't the same quality of claim as a Chainlink feed and shouldn't look
like one.
Three explicit steps, and each one means something different:
1. **Add it** in `/settings` — "know about this." Your agent reads the balance,
prices it, and shows it in your book. It does not trade it.
2. **Select it in the basket** — "trade this." Same act as picking a stock.
3. **Re-sign at `/grant`** — the tradable list is baked into the session key you
signed, so widening it takes a signature. That's the wall doing its job, not a
bug. Free, instant, same wallet, same address, same funds, same caps.
Until step 3, `/settings`, `/grant` and the event feed all say plainly which
tokens your key can't sell — you never find out from a reverted trade.
Most memecoins here have no direct USDG pool, so swaps route through WETH
automatically (`USDG → WETH → TOKEN`). The router holds the middle leg, so this
needs no extra approval and no extra re-sign.
### Keep it running
```bash
merrymen service install
```
Starts your merryman when you log in, and brings it back after a reboot. On
Windows it uses Task Scheduler where it can and the Startup folder where that
would need admin — a trading agent shouldn't be asking for elevation. macOS gets
a launchd agent, Linux a `systemd --user` unit with lingering enabled. All
user-scoped, all removed completely by `merrymen service uninstall`, and
`merrymen doctor` tells you whether it's installed *and* whether it's actually
running — those are different questions.
**What it does not do: run while the computer is off.** Nothing does except a
machine that stays on. If you want that, it's your own always-on box — we're not
going to hold your keys to do it for you.
The desktop app has the same thing as a tray toggle.
### Never a position you can't exit
Buying spends USDG, and every grant can approve USDG generically. **Selling needs
a per-token approval sealed into your signature.** So a token with a live pool but
no approval buys fine and can never be sold — the exit reverts, with your money
inside it.
merrymen refuses the buy. If your key can't sell something, it won't buy it, and
it tells you which symbols and why. A missed trade is recoverable; a position with
no way out is not. Re-sign at `/grant` to widen the list.
This is why the shipped allowlist is verified in **both directions** against live
pools — re-check it yourself any time:
```bash
npx tsx scripts/probe-tradability.mts
```
---
## $MERRYMEN — energy and the Merry Circle
**$MERRYMEN** (on Robinhood Chain — [the token page](https://merrymen.dev/token)) is an agent's
**energy**. **Utility only: no price, no returns, no buyback/burn.** Nothing here says anything
about what the token is worth.
**Energy (hosted service).** An agent runs at full strength while **your wallet and the agent's
own account hold 100,000 $MERRYMEN between them**. Below that it still runs, on about **a tenth**
of a normal day: a tenth of a standard day's paid AI reviews (paced across the day) and of the
new trades it opens on its own — a house figure, not a tenth of your own preset — resetting at
**00:00 UTC**. **Stop-losses, take-profits and orders you place
yourself are never limited** — an allowance on new work is never a lock on the doors — but the
agent's own AI reviews, including of its open positions, are paced with everything else it starts
on its own, so an exit the AI would decide waits for its next review. When
today's allowance is used, the agent tells you once (dashboard, and Telegram if linked), with its
account address and what it would cost to top up. The gate is an operator switch,
`MERRYMEN_ENERGY_GATE` (`observe`, then `1`), and is **never on for a self-hosted install**.
Two ways to top up:
1. **Send $MERRYMEN** on Robinhood Chain to the agent's account (or keep it in your own linked
wallet — both count).
2. **Send USDG and ask the agent in chat to "get its $MERRYMEN".** You confirm a card stating the
most it may spend; it sizes the buy to **cover the shortfall, with a small margin for price
movement (at least $1.00)**, over one pinned route (Uniswap v2, USDG → VIRTUAL → $MERRYMEN) —
the pool fees and the token's own tax are paid out of the USDG — one trade at a time, inside your
signed per-trade limit and worker-enforced daily budget.
The permission for this is sealed into your key when you sign (renew if your key
predates it) and it is **buy-only**: the key can turn USDG into $MERRYMEN in its own account
and can never sell or send it. It moves out only with your owner key (`merrymen recover` /
Withdraw). Paper-mode agents do not spend real USDG on energy — send $MERRYMEN instead, or turn
on Live trading first. The purchase is booked as capital set aside, not as a trading loss.
One wallet powers one account: a linked holder wallet counts for the first merrymen account that
proved it.
**The Merry Circle.** Link a wallet that holds $MERRYMEN by signature in **Settings → Merry
Circle** (the wallet is only ever read — it never becomes a spend key). The same combined balance —
your wallet plus your agent's account — sets your tier:
| tier | hold | perk |
|---|---|---|
| 🌱 **Villager of Sherwood** | 10k+ | **10% off** the platform performance fee · badge · 1× roadmap vote |
| 🏹 **Merry Man** | 100k+ | **full energy** · **25% off** · the bonus strategy pack (`even-keel`, `dip-hunter`) · 3× vote |
| 👑 **Lord of Sherwood** | 1M+ | **50% off** — the lowest we offer · every bonus strategy · 10× vote |
The fee discount is real: merrymen's performance fee is only ever taken on profit above your
high-water mark, and your tier lowers it in the **actual accrual** (shown live in the panel), not
just in the copy. Holders also steer the roadmap — which tokens join the basket, which strategies
ship — weighted by tier ([governance](https://merrymen.dev/governance)). Thresholds live in
[`packages/core/src/token.ts`](./packages/core/src/token.ts); energy's contract is
[`packages/core/src/energy.ts`](./packages/core/src/energy.ts).
---
## For developers
repo layout · clone-dev · env vars · tests
### Layout
- `packages/core` — chain constants, token registry, shared types. Every address
is probed on-chain before it lands here.
- `web` — Next.js dashboard: onboarding, the create-wallet/grant flow, live
positions, trade record (simulation receipts), kill switch, scoreboard,
settings + all APIs.
- `worker` — Node runtime: grant sync → scheduler → strategy tick → policy check
→ simulate → execute → record; the Telegram bridge + PC-control layer; the
backtest harness (`src/backtest.ts`) that runs real strategies through the real
policy layer over synthetic prices.
- `services/brain` — Python research service: evidence evaluation, structured
decisions and model budgets; execution remains in the worker.
- `site` — public website and current brand assets.
- `sdk` — client SDK and build tooling.
- `contracts` — the on-chain drawdown breaker: `BreakerRegistry` +
`KernelBreakerPolicy` (Kernel v3 module type 5 — fails every UserOp once
tripped). `npm test -w @merrymen/contracts`; deployment waits on a funded key.
Until deployed, the breaker is worker-enforced.
### Develop from a clone
```bash
git clone https://github.com/millw14/merrymen && cd merrymen
npm install # prepare hook builds the dashboard
npm run onboard && npm start
# or run halves separately: npm run dev:web · npm run dev:worker
npm run typecheck && npm test
```
### Package a release
```bash
npm ci
npm run pack:release
# After reviewing and testing the generated release/merrymen-.tgz:
npm publish ./release/merrymen-.tgz
```
The release command builds the SDK and dashboard, then stages a tarball with the
patched runtime dependency tree. Native optional packages are installed for the
consumer's platform. Publish that tarball: direct directory `npm pack` and
`npm publish` are blocked because consumers do not inherit this repository's npm
overrides. CI checks an isolated global install, executes its native modules and
audits the packages actually installed. Development installs still use the normal
`package.json` and `package-lock.json`.
### Configuration
The dashboard `/settings` is the source of truth (Anthropic/Rialto/Telegram keys,
bundler + RPC URLs, strategy + every trading knob, the Telegram + PC-control
toggles and allowlists). Saved to `~/.merrymen/settings.json`; secrets are masked
to their last 4 and never echo back to the browser. Precedence:
**settings file > env var > default.** Env vars are the headless fallback:
| var | default | meaning |
|---|---|---|
| `MERRYMEN_HOST` | `127.0.0.1` | dashboard bind host; set `0.0.0.0` for trusted-LAN access |
| `MERRYMEN_BUNDLER_API_KEY` | — | Pimlico API key; the bundler URL is built for your grant's chain automatically |
| `MERRYMEN_BUNDLER_URL` | — | advanced: full 4337 bundler RPC (overrides the key); without either, execution is stubbed |
| `MERRYMEN_SWAP_VENUE` | `uniswap` | `uniswap` = full quote→swap via SwapRouter02; `rialto` = approval-only until API onboarding |
| `MERRYMEN_SLIPPAGE_BPS` | `100` | max slippage vs the QuoterV2 simulation |
| `MERRYMEN_GRANT_FILE` | `~/.merrymen/grant.json` | grant handoff written by the web app |
| `MERRYMEN_STRATEGY` | `steady-basket` | strategy name (see table above) |
| `MERRYMEN_PERF_FEE_BPS` | `1000` | performance fee on profit above the high-water mark (accrual-only) |
| `MERRYMEN_BREAKER_ADDRESS` | — | deployed BreakerRegistry; a tripped breaker halts all intents |
| `MERRYMEN_RIALTO_API_KEY` | — | Rialto integrator key; enables the full quote→swap leg |
| `ANTHROPIC_API_KEY` | — | LLM strategist driver + Telegram natural-language chat + vision |
| `MERRYMEN_TELEGRAM_BOT_TOKEN` | — | @BotFather token; enables the Telegram bridge (all other Telegram + PC-control settings live in `/settings`) |
`npm test` covers the policy mirror, strategies, venue math (slippage, quote
selection, calldata), the ERC-8056 invariant that a stock split is not a crash,
and the Telegram + PC-control safety layer (allowlist enforcement, path-traversal
rejection, capability gating, confirm-park, prompt-injection → no-op).