BotGuilds

What this is

One persistent world, ticking forever at a fixed rate. You register a guild, run a bot, and your bot plays: it recruits characters, sends them into the dungeon, fights, loots, trades, and brings the gold home. There are no matches and no rounds — if your bot is offline, your characters simply stand still and rest.

You can absolutely write your bot by hand — the whole interface fits on this page — but the game is built for playing through a coding agent: tell it what you want your guild to do, point it at the starter kit (which ships agent-ready docs), and iterate. Your strategy is the game; the Python is negotiable.

This page is the interface, not the game. It tells you how to talk to the server and what every message means. It does not tell you how the world works — what the stats do, what things cost, how combat resolves, what magic and crafting actually are, what lives up there or what it drops. None of that is written down anywhere. You find it out by playing, and by mining the database your bot keeps.

1. Get playing in three steps

a. Register your guild. The token is shown once — copy it.

Already have a guild? Paste your guild_token.json to sign this browser in:

b. Get the starter kit — a working bot plus the client library. Clone it:

git clone /starter.git my-bot

or download starter_kit.zip if you would rather not use git. Same files either way; cloning means git pull picks up updates to the client library. The kit holds two example bots — starter_bot.py (wander and punch) and farmer_bot.py (remembers the map, path-finds, retreats and sells) — plus AGENTS.md, a reference written for your coding agent.

c. Run it:

pip install pyzmq
python starter_bot.py

Your token file carries the server address that works from where you registered — the client speaks ZeroMQ to it. Details in the starter kit's README.

The starter bot works unmodified: it recruits a full party, embarks, wanders and punches whatever it meets. You fork it by rewriting one method, on_frame. Auth, reconnects and logging are already handled by the library. Then open the Player tab and watch your party go.

2. The tick

Every tick (default 0.25 s — the live value is tick_seconds in your hello_ok config) the server collects at most one action per character, resolves them all, and sends you one frame per world you have characters in. A second action for the same character in the same tick replaces the first.

A character you send nothing for rests. Resting is a real move, not a wasted tick — but the details of what it restores, and how fast, are the game's to keep.

3. The frame

A frame carries your own characters in full, plus what your characters can currently see, plus the events that happened where they could see them. Vision is limited and blocked by terrain; what reaches you is what the frame says reaches you. Other guilds' characters show name, look, outfit, position, a health fraction and what they last held in hand — never their stats, statuses or inventory.

{"type": "frame", "tick": 10412, "world": "vale", "bounds": [72, 200],
 "next_refresh": {"band": 2, "in_ticks": 1180},
 "chars": [{"char_uid": "g_ab12_c1", "pos": [14, 87], "hp": 22, "max_hp": 36,
            "stamina": 40, "mana": 10, "stats": {...}, "gifts": ["str", "agi"],
            "spells": [], "spell_cap": 1, "essences": [], "essence_cap": 2,
            "thread": null, "carry": {"used": 7, "cap": 27},
            "craft": null, "xp": 45, "inventory": [...],
            "equipment": {"hand": {...}, "offhand": null, "outfit": "..."}}],
 "visible": {"tiles": [[12, 85, "floor", 210], ...], "entities": [...],
             "items": [...], "gold": [...], "surfaces": [...]},
 "events": [{"kind": "attack", "attacker": 311, "target": 902, "dmg": 5, ...}]}

Every field above is yours to interpret. Items carry a tier, a bulk, a list of uses — the verbs that item answers to, which is how you learn what it is for — and a desc that hints and never gives numbers. Events name what happened; correlating them with what you did is the game.

The village frame has no visible; it carries your guild block (gold, guild inventory, market listings, where your characters are) and the shop stock. The guild inventory is grouped: interchangeable items share one descriptor with a count and an item_ids list. Any of those ids works in pickup (withdraw), sell, and list; drop, use and the craft actions only see a character's own kit — withdraw first.

4. Actions

Send a list of action dicts. Every target is a tile [x, y] — never an entity id. Rejected actions cost nothing and come back as action_err with a reason string; reading those reasons is the fastest way to learn the rules.

actionargswhere
movedir: N/S/E/W (diagonals exist)map — moving S off row 0 returns to the village
ridedir: N/S/E/Wmap, on the right terrain
attacktarget [x,y]map
chargetarget [x,y]map, with the right weapon
castspell [, essence, target, focus]map — the forms you know are in your char frame
throwitem_id, targetmap
useitem_id [, target]anywhere
pickup / drop[item_id] / item_idanywhere; in the village these move items out of and into the guild inventory
equipslot [, item_id]anywhere — slots: hand, offhand, outfit, trinket, boots; a bare slot takes the item off
opentargetmap, adjacent
spend_xpstatanywhere
saytextmap, 40 characters
tasteitem_idanywhere (destructive)
brewitem_idsanywhere
smelt / forgeitem_ids / product, item_idsanywhere
buy / sellkind / item_idvillage
list / unlist / buy_listingitem_id, price / listing_idvillage
recruit[name]village
renamenamevillage, max 32 characters
embarkmap, char_uidsvillage

recruit, embark, buy, list, unlist and buy_listing are guild-level: send them with no char_uid.

Actions cost stamina, and some cost mana; a character acts only when it can afford what it is asking for. brew, smelt and forge occupy the character until the work finishes — watch craft on your char frame. There are caps on how many characters you can field per map, across all maps, and keep alive at once; the config in hello_ok names them and exceeding one errors.

5. Characters

Characters have six stats — str dex int vit end agi — that you raise with spend_xp, and two gifts rolled at recruitment that are cheaper to raise. What each stat governs, what it costs, and where it caps are yours to measure. There are no classes. Recruiting is free.

Death is permanent. A dead character drops its whole inventory and equipment on its tile — for anyone to pick up. Your guild keeps its gold and guild inventory.

Unattended parties come home. A character you send no action to for a long stretch is recalled to the village, and your village frame gets a recalled event naming it. Resting counts as unattended — send any action, even say, to keep a party in the field. Nothing is lost; you just have to embark again.

When no guild has anyone fielded, the server stops simulating and only ticks for a few seconds after a request. Your bot does not need to know: it keeps receiving village frames, and anything it sends wakes the world.

6. The maps

Three worlds, and you choose which to embark on. All run bottom to top: you arrive at the bottom, the exit is the bottom edge (move S from row 0), and it gets harder the further north you push. The village frame lists them under maps. What is in them — terrain, encounters, what roams, what waits at the top — is yours to discover.

mapsize
vale — The Vale72 x 200
mines — The Embermines64 x 176
spire — The Hollow Spire56 x 208

Maps refresh. Each one regenerates a horizontal band at a time, on a schedule. Every map frame carries next_refresh, and a band_refresh_warning event fires ahead of it. Loot left in a refreshed band is gone, and band boundaries shift over time — trust the frame, not a memorized row.

7. Economy

Gold is guild-level. The shop sells a small stock of basics and buys anything back for much less than it charges — which is exactly why the player market exists: list items at your own price, other guilds buy them, and the seller keeps every coin. Listings are public in every village frame. Guild inventory is free and infinite.

8. Connecting

ZeroMQ DEALER to the server's bot port, one JSON object per message. The client library does this for you; if you want to write your own:

-> {"type": "hello", "guild_id": "g_ab12", "token": "…"}
<- {"type": "hello_ok", "tick": 10411, "config": {...}, "guild": {...}}
<- {"type": "hello_err", "reason": "bad_token"}   check your guild_token.json
<- {"type": "frame", ...}                one per world per tick
-> {"type": "actions", "tick": 10412, "actions": [ ... ]}
<- {"type": "action_err", "char_uid": "…", "reason": "out_of_range"}
<- {"type": "server_pause"}              live restart — reconnect shortly
<- {"type": "kick", "reason": "superseded"}   another session hello'd as you
-> {"type": "bye"}                       polite hangup, optional

A new hello for your guild retires the previous session, so you never run two bots against each other by accident. A slow bot just misses ticks.

9. What isn't written down

Almost everything. This page is the wire: how to connect, what you may send, what comes back. The world behind it is deliberately undocumented — the stats and what they drive, what actions cost, how damage and armor resolve, how magic and crafting work, the items, outfits, enemies, recipes, containers, traps, terrain, what roams, what guards the top of a map. Nothing here lists any of it, and nothing else will.

Your bot's local database (guild_log.db) records every frame, event, action and error it has ever seen. That is where your map knowledge, your bestiary, your drop tables and your recipe book come from — you build them by playing. Log everything, compare outcomes, and work it out. Go find out.

Open your guild page →