Files
gbr-games/BUILDER.md
T
gregandClaude Opus 5.5 dcb07cfed7
Validate game templates / validate (push) Successful in 20s
Validate game templates / boot-test (push) Skipped
Validate game templates / publish (push) Skipped
feat(builder): research, build and a worker for the AI builder on our own hardware
- research: searches SearXNG, reads the best pages through the reader, has the
  model list the server's variants, then checks every Docker image and Steam
  app it named for real before an admin sees it.
- build: first boot of the variant's images (skipping ones that need root),
  a draft by the model, then the draft deployed with the node-agent's
  BootTest like CI does; crashes, error lines and saves outside /server go
  back to the model, three boots at most.
- worker: polls the panel's builder queue (outbound only), runs research or
  build in a fresh clone, streams the output as the job log, and opens the
  result as a pull request from gbr-bot.
- Dockerfile.builder, a workflow publishing gbr-builder:latest, compose and
  env files for the builder VM, and BUILDER.md.

draft now keeps its conversation in a drafter, so build can send boot
failures back to the same model session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 12:40:14 -04:00

4.3 KiB

AI builder (gbrgames worker)

The panel's AI builder (Admin → Games → AI Config Generator) is run by a worker on our own hardware, not on the panel's droplet and not in CI:

Panel (droplet)                           Builder VM (home lab)
───────────────                           ─────────────────────────────────────────────
admin starts a job ──► queued    ◄─poll── gbrgames worker (Docker)
progress / log / variants        ◄─post──   research: SearXNG + page reader + Ollama (3090)
"Review draft PR"                           build: first boot → draft → boot with the node-agent
                                            → branch draft/<id>-<job> + PR as gbr-bot ──► CI (validate + boot test)
  1. Research (gbrgames research -name N): searches the web, reads the best pages, and has the model list the server's variants (edition, image or SteamCMD app, startup, ports). Every image and Steam app is checked for real (docker manifest inspect, anonymous steamcmd +app_info_print) before the admin sees it.
  2. The admin picks a variant in the panel.
  3. Build (gbrgames build -name N -variant @v.json): first boot of the image untouched (first-boot), a draft by the model (draft, rules in AUTHORING.md), then the draft is deployed with the node-agent's BootTest, the same check CI runs. Failures (crash, error lines, saves written outside /server) go back to the model, three boots at most.
  4. The worker pushes games/<id>/ to a branch and opens a pull request as gbr-bot. A draft that validates but never booted still gets a PR, titled WIP:, with what's left listed. Nothing reaches players until a person merges it and enables the game.

The worker only connects out (to the panel, Gitea, Ollama, SearXNG); nothing needs to reach the VM.

The VM

A Proxmox VM of its own, so builds never compete with CI boot tests on VM 126: Debian 13, 4+ cores (host CPU type), 24 GB RAM (ARK-sized servers need ~16 GB), 150 GB disk (SteamCMD downloads), Docker.

# as root
curl -fsSL https://get.docker.com | sh
git clone https://www.gitea.gbreed.com/gbreed-public/gbr-games.git /opt/gbr-games

Isolated network: game servers booted here must not reach the LAN. Same setup as the runner (RUNNER.md, step 1):

mkdir -p /opt/gbr-boottest
cp /opt/gbr-games/scripts/runner/setup-boottest-network.sh /opt/gbr-boottest/
chmod +x /opt/gbr-boottest/setup-boottest-network.sh
cp /opt/gbr-games/scripts/runner/gbr-boottest-network.service /etc/systemd/system/
systemctl daemon-reload && systemctl enable --now gbr-boottest-network

Worker:

mkdir -p /opt/gbr-builder/work && cd /opt/gbr-builder
cp /opt/gbr-games/scripts/builder/docker-compose.yml .
cp /opt/gbr-games/scripts/builder/env.example .env && chmod 600 .env   # then fill it in
docker compose up -d && docker logs -f gbr-builder

gbr-builder:latest is published by .gitea/workflows/builder-image.yml whenever cmd/ changes on main; watchtower on the VM updates the worker within five minutes.

Accounts and secrets

Where Name What
Builder .env GITEA_TOKEN Token of the gbr-bot Gitea user (Write on gbr-games, scope repository read/write)
Builder .env + panel env BUILDER_TOKEN Shared secret the panel checks on /api/v1/builder/**; any long random string
Builder .env OLLAMA_URL, SEARXNG_URL, READER_URL The 3090's Ollama, SearXNG, and the page reader

Running a build by hand

On any machine with Docker and the gbr-boottest network (the builder VM, or the runner):

export OLLAMA_URL=http://192.168.4.30:11434 SEARXNG_URL=http://192.168.4.38:8080 READER_URL=http://192.168.4.38:3000
go run ./cmd/gbrgames research -name Valheim -out research.json
# pick a variant from research.json into v.json, then:
go run ./cmd/gbrgames build -name Valheim -variant @v.json -out build.json

The draft lands in games/<id>/, first-boot reports in firstboot-out/.

Housekeeping

Like the runner: a weekly docker system prune -af --filter "until=168h" keeps images and SteamCMD downloads in check. Each job removes its clone; boot tests remove their containers and volumes.