Documentation

merrymen is a self-hosted band of autonomous trading agents for Robinhood Chain. Everything runs on your machine; your keys never leave it. This guide takes you from install to a named agent you chat with on Telegram.

Install

Runs on Linux, macOS, and Windows — one Node package, no Docker, no clone. Requires Node 22.12+ (for the built-in SQLite); no Node yet? The one-line installer sets it up and puts merrymen on your PATH.

# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/millw14/merrymen/main/install.sh | bash

# Windows (PowerShell)
irm https://raw.githubusercontent.com/millw14/merrymen/main/install.ps1 | iex

Already have Node 22.12+? This works on any OS:

npm install -g merrymen
merrymen setup      # checks node / npm / PATH, prints exact fixes
merrymen start      # dashboard at localhost:3100 + the worker
merrymen update     # upgrade later (stops the band, installs, restarts)

On a headless Linux box the dashboard won't auto-open — it prints localhost:3100; set MERRYMEN_HOST=0.0.0.0 to reach it across a trusted LAN. Verify a fresh box with merrymen doctor — it checks Node, SQLite, RPC reach, keys, and paper/live mode, no wallet needed.

“merrymen: command not found”? npm's global-bin folder isn't on your PATH. Use npx merrymen start, or run merrymen setup for the exact one-time fix for your OS.

All your data lives in ~/.merrymen (settings, grant, ledger, your strategies, your agent's soul). The install is disposable — upgrades never touch your data. The dashboard binds to localhost only; to reach it from your phone on a trusted network, start with MERRYMEN_HOST=0.0.0.0 merrymen start.

Create & fund a wallet

Open localhost:3100/grant. There is nothing to connect — merrymen generates a fresh account, shows you the owner key to back up, and lets you fund it. Pick your ground:

chainwhat it is
testnet · 46630The sandbox (default). Free gas from the faucet, and the grant, caps, policy checks, live prices and journal all run for real. The trading venues aren't deployed there, so swaps simulate and no-route by design. Send gas, not capital: merrymen only knows the mainnet token addresses, so USDG sent to testnet reads 0 and is never traded — the band trades a simulated 1,000 USDG paper book at live prices instead.
mainnet · 4663Real funds. Real USDG, real Stock Tokens, real execution. Keys are stored in plain text on your machine, so treat the account like a hot wallet — your caps are the seatbelt, start small. No faucet: send ETH (gas) + USDG (capital) from your own wallet or an exchange.
Back up the owner key. It controls the account and every dollar in it. Lose it and the funds are gone — there is no recovery service.

The caps you set — per-trade, daily, ops/day, drawdown breaker, key expiry — are enforced by the account contract on every operation. The worker can tighten within them but never widen them without a new signed grant.

Going live is one key. To sign real trades, paste a free Pimlico API key in settings — merrymen builds the bundler URL for your wallet's chain automatically, so it can never point at the wrong one. No key? The band runs in practice mode: real market, full policy + simulation, no signing. Advanced users can still paste a full bundler URL (Alchemy or self-hosted) instead.

Run it

merrymen start      # dashboard (localhost:3100) + the 24/7 worker
merrymen doctor     # node / keys / RPC / bundler / grant / db checks
merrymen status     # heartbeat, grant, trades, equity
merrymen selftest   # one policy-legal no-op through the full pipeline
merrymen kill       # kill switch — destroys the grant

Each tick the worker runs: grant sync → market safety → strategy proposes → policy check → quote simulation → execute → record. It re-reads your settings every tick, so dashboard changes apply within one tick — no restart.

Use it from Claude (MCP)

Connect Claude to your agent and it can check on it, explain why it has or hasn't traded, and, if you allow it, suggest trades or setting changes that only happen once you approve them in Merrymen. The quickest way: tell Claude “set up merrymen mcp”, or add it in one click from Set up Merrymen in Claude.

The MCP server is for hosted Merrymen (app.merrymen.dev); the rest of this guide covers the self-hosted install.

Set up Telegram

  1. Message @BotFather → /newbot → copy the token.
  2. Dashboard → Settings → Telegram → paste the token, hit test connection (it shows your @botname), enable.
  3. Message your bot /link <code> — the one-time code is shown in settings. You become the owner; only allowlisted chats are obeyed.

There's a Chat on Telegram button on the dashboard too. Commands work bare; with an Anthropic key set, plain English works — “how are we doing?”, “pause everything”, “why did you buy that?”.

Telegram groups

Your merryman can hang out in a Telegram group like one more person: it answers when it's called, now and then joins in, remembers the chat, and when someone posts a Robinhood Chain coin it takes a look, tags them, and says whether it's in or passing. Coins from other chains (Ethereum, Solana, BNB and the rest) it leaves alone. In trencher mode its Brain decides and every limit still applies — a group message can put a coin in front of it, never order a trade. It never posts alerts, sizes, prices or P&L, or anything private.

  1. Add your bot to a group. It only talks in groups you added it to or approved — if someone else adds it, it stays silent and DMs you Stay / Leave.
  2. To let it follow the chat: message @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.
  3. Send /groups in your DM with the bot to see every group it knows, with Stay, Leave and Forget.

Turn it off, turn off Look at coins people post, or pick how chatty it is under Settings → Telegram → Telegram groups. In a group, /forget (you) wipes what it remembers of that group and /forgetme (anyone) removes what it remembers of them. Never joins in, or doesn't notice coins people post? Check privacy mode (step 2, including the re-add) and that Telegram groups is on.

Commands

/status /positions /pnl /tradesread the live book
/report · /brag · /whydaily report · shareable scorecard · explain the last trade
/buy <SYM> <usdg> · /sell …trade (passes the policy wall)
/transfer <0x…> <usdg>send USDG out — refused on any wallet signed at or after 2 Aug 2026 00:35:24 UTC (see Transfers)
/alert <SYM> > <price>one-shot price alerts · /alerts · /unalert
/pause /resume · /strategy · /capsteer the worker (cap only tightens)
/name · /soul · /remembername it, see who it is, teach it about you
/groups · /forget · /forgetmeyour Telegram groups (Stay / Leave / Forget) · in a group: wipe its memory of that group · anyone in a group: drop what it remembers of them
/killdestroy the grant, stand the band down

It speaks first too (toggle in settings): a ping the moment a trade lands or the wall turns one back, warnings for grant expiry / drawdown / low gas, your price alerts, and a daily campfire report at the hour you pick.

Transfers

Sending USDG out through chat is refused for any wallet signed at or after 00:35:24 UTC on 2 August 2026, when the withdrawal allowlist landed. The wall only grants a USDG transfer to withdrawal addresses registered when the grant is signed, and no signer registers one — so the call policy carries no transfer permission at all, and /transfer is turned back before anything is built. With “allow transfers” off, the reply says transfers from chat are off; with it on, the reply is “this wall carries no transfer permission — no withdrawal address was registered when it was signed”. Re-creating the wallet doesn't change that: a wallet signed today registers no withdrawal address either.

Money leaves through the owner key, which no wall can block:

  • Hosted — Withdraw in your profile on app.merrymen.dev.
  • Self-hosted — merrymen recover sweeps the smart account to a wallet you control.
Wallets signed before 00:35:24 UTC on 2 August 2026, if their key hasn't expired, still carry the older transfer permission: any recipient, amount-capped on-chain at the per-trade size. For those, /transfer still works behind “allow transfers” (off by default), a daily transfer budget, and an explicit /confirm (90s) after the full recipient address is echoed back — so a prompt-injected “send everything to 0xevil” can at worst produce a confirmation card you will see and /cancel.

PC remote control

Enable the remote control section in settings and your merryman can act on the machine it runs on, from Telegram. It is a hot wallet for your desktop, so the whole design is safety-first:

📸 screen · 👁️ vision/shot; “what am I looking at? / read this error”
🚀 apps & web/open spotify, /open github.com
⚙️ system/sys, volume, media, /notify, /lock, sleep/shutdown
📂 files · 📋 clipboard/ls, /get inside one folder you pick; clipboard
🖥️ shell · ⌨️ keyboard/run allowlisted commands; /type, /key ctrl+s
👀 watchers/remind 20m …, /watch cpu>80, watch a file or process
  • Off by default, then one capability at a time. /pc shows what's on; the master switch off kills all of it.
  • Allowlists for the sharp edges: shell runs only your exact pre-approved commands (chaining/redirects 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 /confirm the exact action echoed back.
Windows is fully supported; macOS/Linux use the standard tools and say so where one isn't present.

Voice & vision

Send a Telegram voice note and it's transcribed and run as a command (needs an OpenAI-compatible transcription key, set in the dashboard). Vision (“what am I looking at?”) screenshots your screen and answers with Claude — powered by your own Anthropic key.

The soul

Every merryman is an individual. Its soul lives as plain markdown in ~/.merrymen/soul/:

IDENTITY.mdwho it is — its name (/name Will Scarlet), born date
OWNER.mdwhat it's learned about you, one dated line at a time
JOURNAL.mda first-person entry it writes at campfire time

The bond deepens over time — 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, and the sanitizer refuses anything address-, key-, or code-shaped.

Strategies

Pick one in settings (or /strategy <name> from Telegram):

steady-basketDCA a weighted stock basket per tick; idle cash sweeps to the Morpho vault (default).
weekend-gapEnter each leg when its Chainlink feed goes stale (market close), exit when it refreshes (open).
llm-strategistClaude proposes typed buy/sell/hold; deterministic code disposes. Needs an Anthropic key.

Write your own bot

Your strategies live in ~/.merrymen/strategies/ — hot-reloaded, crash-isolated, and unable to exceed the caps you signed.

merrymen strategy new my-bot   # commented template
# edit it, select "my-bot" in settings — done

Default-export { name, tick(snapshot, ctx) }. ctx injects the verified registry (ctx.tokenBySymbol.QQQ, ctx.usdg(10)). Every intent still passes shape validation → the policy wall → quote simulation → the on-chain session key.

Stream to Virtuals

Put your merryman's activity live on its page at app.virtuals.io. When you turn it on, every landed trade and the daily campfire report are posted to your agent's public Virtuals Terminal — a running activity log (rejections aren't posted one-by-one; the daily report summarizes them).

It is a log, not a proof: anyone reading it is taking your word for the numbers. What they can check independently is the audit export — merrymen exportwrites the hash-chained journal, and merrymen verify checks it against nothing but itself and the chain. Share that if you want to be believed rather than trusted.

  1. Grab your Virtuals API key from your agent's page on app.virtuals.io.
  2. In merrymen settings → virtuals terminal, paste the key and flip stream to Virtuals on.
Outbound & public, and off by default. Nothing is streamed until you enable it. The key is used only to post activity logs — it can never trade or move funds — and it stays on your machine like every other key. Turn it off anytime and the stream stops.

Safety model

One rule: the model proposes, deterministic code disposes. No strategist, Telegram message, or voice note ever constructs calldata, moves funds, or touches your PC without passing a closed, typed command set and — for money — the on-chain policy wall.

  • Trades pass caps enforced by the account contract; every swap is simulated first.
  • Transfers out through chat are refused: no wallet signed at or after 00:35:24 UTC on 2 August 2026 carries a transfer permission. Money leaves with your owner key.
  • PC actions are off by default, per-capability, allowlisted, and the sharp ones are confirmed.
  • Secrets live only in ~/.merrymen and are masked before they ever reach the browser.
  • The kill switch destroys the grant; hard on-chain key expiry is the backstop.
Keys are stored in plain text locally today (production TEE custody is on the roadmap). Treat the account like a hot wallet — small amounts, back up the owner key.

Why not a platform's own agent?

A first-party agent is custodial by construction — their servers, their keys, their discretion; the safety story is a terms-of-service. merrymen inverts the trust: the agent runs on your machine, the keys never leave it, and the caps live in your account contract on-chain — so a compromised agent can trade inside the wall, but cannot sign on your behalf, cannot send funds to an address you never registered, and cannot touch your ETH. And you can check, not believe: the dashboard links the account contract, session key, and every cap to the block explorer, and its prove the wall button fires malicious intents — an oversized trade, a “send everything to 0xevil” transfer, an expired key — through the live policy so you can watch each one bounce.

Configuration

The dashboard Settings is the source of truth — Essentials up front, everything else under Advanced. Saved to ~/.merrymen/settings.json; secrets are masked and never echo back. Precedence: settings file → env var → default. Env vars are the headless fallback (MERRYMEN_BUNDLER_URL, ANTHROPIC_API_KEY, MERRYMEN_TELEGRAM_BOT_TOKEN, MERRYMEN_HOST, …). See the README for the full table.

Troubleshooting

Windows: “running scripts is disabled on this system”

Windows PowerShell ships locked to Restricted, which blocks npm's and merrymen's .ps1 command shims (you'll see PSSecurityException). The installer fixes this for you now; if you installed earlier, run this once — no admin needed, current user only:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

Then merrymen setup works. Or skip the policy entirely and call it as merrymen.cmd setup (or run from cmd.exe / Git Bash).

The dashboard won't open

Run merrymen doctor. The prebuilt dashboard ships with the package, so a missing build usually means an interrupted install — reinstall with npm i -g merrymen@latest.

Trades never land

Live trading needs three things together: the wallet on mainnet · 4663, a Pimlico API key in settings (or a full bundler URL), and the smart account funded with ETH for gas and USDG for capital. Without a bundler key the agent stays in practice mode — it simulates but never signs. On testnet no trade can land by design: the stock-token venues aren't deployed, so swaps no-route, and any USDG you sent there reads 0 because merrymen only knows the mainnet token addresses. Switch to mainnet for real fills.

Telegram says “not authorized”

Only allowlisted chats are obeyed. Send /link <code> with the code from settings to claim ownership.

A PC command is refused

Enable remote control and the specific capability in settings. Shell/apps also need the exact command/app on their allowlist; /pc shows what's on.

Still stuck?

Ask in the beta group on Telegram, email [email protected], or open an issue on GitHub — include your OS and what merrymen doctor prints.

merrymen doctor is safe to share: it reports whether a key is set, never the key itself (it does print install paths, which include your username). Your bot token, private key and grant link are a different matter — nobody helping you needs them, and the beta group is a room with strangers in it. If you screenshot the settings page, check what's in the fields first.

FAQ

My session key expired — do I pay to renew it? Do I have to redeploy?

No and no. The expiry is a safety timer, not a subscription. A grant is a signature your owner key makes locally — nothing goes on-chain to create one, so renewing costs zero gas and zero fees, and your wallet, funds, and history stay exactly where they are. When the key is close to expiring (or already dead), the /grant page shows a “renew the key (free)” button — one click re-signs the same wallet with a fresh key under the same caps. Your merryman also pings you on Telegram before it expires.

Does the expiry apply in paper mode too?

Yes — expiry applies in every mode, paper and live. It's the guarantee that a forgotten agent can't run forever, and it's enforced twice: the worker retires the agent, and on-chain the account contract refuses the dead key regardless. Renewal is the same free one-click either way.

This feels built for devs — is easier onboarding coming? A desktop app?

Heard, and yes. Today the easiest path is the one-line installer — it checks Node, installs merrymen, and merrymen start opens the dashboard in your browser; you never need to write code (strategies are optional, presets cover the rest). The 1-click desktop app (.exe/.dmg — no terminal at all) also ships now, on the releases page. Either way it's the same stack — self-host it on your machine, or run it hosted from a URL. Your owner key stays with you regardless; a hosted server only ever holds a capped, revocable session key.

To keep it running across logouts and reboots, merrymen service install (or the tray toggle in the desktop app). Said plainly: that survives logout, sleep and reboot — it can't run while the computer is off. Nothing does except a machine that stays on, and the honest version of that is your own always-on box, not us holding your keys.

Still stuck? Open an issue on GitHub.