Skip to content

Operations ​

Everything runs on one Linux server: nginx in front, native Postgres, and systemd units for the long-lived services.

Environments ​

TEST (live)Production (planned)
Apptest.autorune.xyzautorune.xyz
APItest-api.autorune.xyz (also /api on the app host)api.autorune.xyz
Hiscorestest-hiscores.autorune.xyzhiscores.autorune.xyz
Docsdocs.autorune.xyz (one site for both)
Game worldits own LostCity worlda separate world
Databaseits own Postgres database and roleits own

Each environment gets its own database, secrets and game world. Test and production sessions can't cross, because cookies are host-only.

Services (TEST) ​

UnitWhat it runs
autorune-test-apiThe API. It spawns one agent-runner per running avatar as child processes. Each runner starts its sandbox as a transient systemd scope.
autorune-test-engineThe LostCity game engine from vendor/rs-sdk, bound to loopback by a preload.
autorune-test-gatewayrs-sdk's gateway.
autorune-test-friendrs-sdk's friends server, needed for private messages.

The unit files live in infra/systemd/, and the non-secret config in infra/autorune-api/test.env and infra/rs-sdk/test.env. Secrets live in env files outside git. A graceful API stop leaves every avatar's desired state alone, so running avatars come back on the next start.

Deploying ​

WhatScriptWhere it goes
Appinfra/deploy/test-app.shstatic files to the app's web root
Hiscoresinfra/deploy/test-hiscores.shstatic files to the hiscores web root
Docsinfra/deploy/docs.shstatic files to the docs web root
API, runnerpull main, run migrations if any, restart autorune-test-apirunning avatars resume by themselves

The static sites are built with Bun + Vite (VitePress for docs) and copied with rsync --delete. nginx serves them with long-lived caching for hashed assets and no-cache for HTML.

nginx and TLS ​

  • One vhost config per site group in infra/nginx/, installed into the server's nginx sites-available.
  • Certificates come from Let's Encrypt via certbot (webroot challenge). Port 80 only serves the ACME challenge and redirects everything else to HTTPS.
  • After any change: sudo nginx -t, then sudo systemctl reload nginx (a reload, never a restart).

This docs site ​

sh
cd apps/autorune-docs
bun run dev        # local preview with hot reload
bun run build      # static output in src/.vitepress/dist
bun run linkcheck  # checks every internal link in the build
infra/deploy/docs.sh   # build, check links and the CSP, publish

The pages are Markdown in apps/autorune-docs/src/. Diagrams are Mermaid code blocks. The repository's docs/ folder holds the detailed dev notes; this site is the human-readable source of truth.

Keeping it current. The repository's AGENTS.md makes it a rule: any change to user-visible behaviour, architecture, AI providers, the rs-sdk relationship, security or operations updates the matching page here in the same change, then redeploys with infra/deploy/docs.sh. The deploy refuses to publish a build with a broken internal link or an inline script the CSP doesn't allow.

Search engines. Unlike the app, API and hiscores (which send noindex), this site is meant to be found: it serves a robots.txt that allows everything and a sitemap.xml generated by the build.

Updating rs-sdk ​

vendor/rs-sdk is a pinned, unmodified submodule. Updating means moving the pin. The full procedure and a history of bumps are in the repo's docs/rs-sdk-updates.md. In short:

  1. Bump: in vendor/rs-sdk, fetch, review the new upstream commits and check out the new one. Never edit files there. git -C vendor/rs-sdk status must stay clean.
  2. Read the changes that touch us: engine login/logout and takeover (the lite ↔ browser handover), the MCP server's bot manager and list_bots (the siblings preload), and the SDK API, CLAUDE.md and learnings/ the agents read.
  3. Rebuild what we build from it: the engine's content pack and the webclient bundle, plus bun install and engine migrations where lockfiles or schemas changed.
  4. Test: typecheck and the full test suite. It includes an rs-sdk contract test that imports the real vendored modules AutoRune relies on and points at the code that would break.
  5. Commit the new pin with the list of upstream commits and their impact.
  6. Deploy to TEST: note a running bot's state, restart the engine (and the friends server or gateway if they changed), then the API. Check that bots reconnect by themselves, keep their goals and state, and that PMs still arrive.

Avatars pick up the new rs-sdk (and their regenerated instructions) on their next start.

Updating the engines ​

opencode and Claude Code are installed as pinned, integrity-checked binaries next to older versions (infra/opencode/install.sh, infra/claude-code/install.sh). Bumping one means installing the new version, bumping the pinned version in the runner, re-checking the event and stream shapes the glue relies on, running the tests, and restarting the API.

Master key rotation ​

The master key that wraps AI keys and game passwords can be rotated without downtime. Add the new key, keep the old one as a "previous" key, restart, re-wrap every row with the rotation script, check, then drop the old key. Keep the master key backed up: without it, the stored AI keys and avatar game passwords can't be decrypted.

AutoRune is an experiment built on rs-sdk and LostCity. RuneScape is a trademark of Jagex Ltd; this project is not affiliated with Jagex.