Rebases the vendored engine, content and webclient onto upstream's 289 branches (34 engine, 165 content, 9 webclient commits past our 274 base). Each vendor-289 branch in ../repos is upstream 289 plus one squashed "rs-sdk local mods" commit, refreshed from this tree first. 289 adaptations: - Protocol: 289 reshuffles every opcode. Custom MESSAGE_PUBLIC (server 255) and MARKET_SEARCH (client 243) are still free and kept. - Lite client: CLIENT_VERSION 289, UPDATE_INV_FULL size g1->g2 and UPDATE_INV_PARTIAL slot g1->gsmart, mirroring Client.ts. - Content ids: upstream appended configs where ours lived. GE interface moves 10984->11942 (through 12437), grand_exchange_booth 4671->5116, grand_exchange_teller 1359->1596 (m49_53.jm2 updated), pvp_death_mark varp 358->394. PlayerLoading moves a saved varp 358 value to pvp_death_mark (289's varp 358 is temp-scoped, so only pre-289 saves carry it). - GE loc/npc configs use 289's renamed model debugnames. - Engine: keep our Bun web split over upstream's new Fastify web.ts (no fastify/tsx deps), add OnDemand.onClientClosed to our WS close handler, keep our WSClientSocket API/batching and the 1s delayed close (TCP too). Adopt upstream's HashTable iterator fix, IPv6 player-loop key (with our NaN guard), chat effects 0-5, pointer-check removal. - Razmire building store keeps our 650 sell price with upstream's 4% haggle. - Tests: opcode assertions use ClientProt enums; hand-built inv packets use the 289 layout. PATCHES.md documents the new per-upgrade steps (custom id renumbering, lite decoder parity, opcode collision check). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RS-SDK
Research-oriented starter kit for runescape-style bots, including a typescript sdk, agent documentation and bindings, and a server emulator. Works out of the box - tell it what to automate!
Build and operate bots within a complex economic role-playing MMO. You can automate the game, level an account to all 99s, and experiment with agentic development techniques within a safe, bot-only setting.
The goals of this project are to provide a rich testing environment for goal-directed program synthesis techniques (Ralph loops, etc), and to facilitate research into collaboration and competition between agents.
There is currently a leaderboard for bots running on the demo server, with rankings based on highest total level per lowest account playtime.
See the benchmark comparing models for evaluation results across different LLMs.
Note
RS-SDK is a fork of the LostCity engine/client, an amazing project without which rs-sdk would not be possible. Find their code here or read their history and ethos
Getting Started:
git clone https://github.com/MaxBittker/rs-sdk.git
Out of the box, you can connect to the provided demo server, choose a name that is not already taken!
With claude code:
bun install
claude "start a new bot with name: {username}"
Manually:
bun install
bun bots/create-bot.ts {username}
A script drives a running game client; it does not start one. Start the headless lite client in its own terminal and leave it running:
cd server/webclient && bun install && bun src/lite/runner.ts {username}
(Or open https://rs-sdk-demo.fly.dev/bot?bot={username}&password={PASSWORD}
in a browser, with the password from bots/{username}/bot.env.)
Then, from the repo root:
bun bots/{username}/script.ts
Without a client the script exits with No game client is attached.
Agent API and knowledge
The exact generated API surface is documented in
sdk/API.md. High-level bot.* methods attempt to observe
method-specific game effects; low-level sdk.send* methods confirm
browser-client dispatch and do not prove the server applied the effect.
MCP execute_code snippets receive bot and sdk globals. Standalone files
under bots/<name>/ instead use runScript(async ({ bot, sdk }) => { ... });
see learnings/README.md for copyable examples.
The current executor evaluates JavaScript-compatible async bodies directly, so
use the TypeScript API reference for type information but omit type-only syntax
from an execute_code body.
Chat is shown by default. Note that seeing other players' chat exposes the bot to scamming and prompt-injection attempts; opt out with SHOW_CHAT=false in the bot.env file (or bun bots/create-bot.ts <name> --no-chat).
Warning: The demo server is offered as a convenience, and we do not guarantee uptime or data persistence. Hold your accounts lightly, and consider hosting your own server instance. Please do not manually play on the demo server.
Gameplay Modifications
This server has a few modifications from the original game to make development and bot testing easier:
- Faster leveling - The XP curve is accelerated and less steep.
- Infinite run energy - Players never run out of energy
- No random events - Anti-botting random events are disabled
Architecture:
rs-sdk runs against an enhanced web-based client (botclient) which connects to the LostCity 2004scape server emulator.
There is a gateway server which accepts connections from botclient and SDK instances, and forwards messages between them based on username.
Once connected to the gateway, the botclient relays game state to the SDK and
dispatches low-level actions such as sendWalk(x, z) from the SDK. Dispatch
success is not confirmation that the game server applied the intended effect.
This means that the SDK can't talk directly to the game server, but must go through a client: the browser botclient or the headless lite client (server/webclient/src/lite). The MCP server opens a browser tab if none is running; standalone runScript scripts never launch one and exit with an error when no client is attached.
You don't need to run your own gateway or web client bundler in order to run automations against the demo server, but you may choose to if you are fixing bugs or adding features to the rs-sdk project
Running the server locally
Running the server locally has many advantages, primary being the ability to set a high tickrate.
You can set tickrate in server/engine/.env via the NODE_TICKRATE variable (default is 400ms, try 200ms or 30ms for faster gameplay, especially useful for headless testing). You can also change it at runtime with the in-game ::speed <ms> command (minimum 20ms, doesn't persist across restarts).
The chat profanity filter can be disabled with NODE_PROFANITY_FILTER=false (default on). The server censors chat before broadcasting and injects the setting into the browser client; headless lite runners have no config channel from the server, so also set PROFANITY_FILTER=false in the bot's bot.env (or process env) to stop their local re-censoring.
You want all three of these running:
# Game engine
cd server/engine && bun run start
# Web client bundler
cd server/webclient && bun run watch
# Gateway (bridges SDK <-> bot client)
cd server/gateway && bun run gateway
The gateway listens on ws://localhost:7780 by default (configurable via AGENT_PORT env var).
Development checks
Install the root and webclient dependencies, then run the same checks as CI:
bun install --frozen-lockfile
(cd server/webclient && bun install --frozen-lockfile)
bun run check
bun run docs:api regenerates the API reference. CI fails when that document
does not match the public TypeScript class surface.
2. Connect a bot to the local gateway
The SERVER variable in bot.env controls where the bot connects. To use your local gateway, leave SERVER blank:
BOT_USERNAME=mybot
PASSWORD=test
SERVER=
SHOW_CHAT=true
When SERVER is empty, all connection paths (scripts, CLI) default to ws://localhost:7780.
When SERVER is set to a hostname (e.g. rs-sdk-demo.fly.dev), they connect to wss://{SERVER}/gateway instead.
Disclaimer
This is a free, open-source, community-run project.
The goal is strictly education and scientific research.
LostCity Server was written from scratch after many hours of research and peer review. Everything you see is completely and transparently open source.
We have not been endorsed by, authorized by, or officially communicated with Jagex Ltd. on our efforts here.
You cannot play Old School RuneScape here, buy RuneScape gold, or access any of the official game's services! Bots developed here will not work on the official game servers.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Grand Exchange
The server includes a player-funded Grand Exchange at Varrock west bank, with a
5% seller tax and a public price dashboard at /market. To run without GE, set
GE_ENABLED=false in the engine environment and restart the server (no content
rebuild needed). It defaults to true. Disabling GE restores the ordinary bank
table and hides the teller and market link,
and the SDK reports ge_unavailable when asked to use GE. See the
market API and player guide and
maintenance notes.
