The builder could only create games; nothing noticed when a live template
stopped working, and there was no way to tell whether a builder change made
it better or worse.
- repair -id ID: boots an existing template as nodes run it; if it fails,
the same investigation as for a draft runs and the model changes only what
the diagnosis says. The worker handles "repair" jobs (gameId from the
panel) and opens "fix(games): repair ..." on draft/<id>; a template that
boots as it is reports "nothing to repair" and opens no PR. The boot and
fix loop is now shared by builds and repairs.
- validate.yml runs weekly and boot-tests every game; failed games are sent
to the panel (X-GBR-Event: games_boot_failed) to queue repairs.
- eval -ids all: builds games that already have a template from scratch,
blind, and scores each draft against it (boots, same image and app, ports,
ready line, settings found) into eval.md and eval.json.
- research skips our own sites, so neither research nor eval reads our
templates back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The drafter no longer grows one conversation. Each request is the rules
and facts, the model's latest template, what is wrong now and one line per
earlier round, so long builds can't push the facts out of the model's
32K context (Ollama drops the oldest part silently). The image's scripts
in the facts are capped at 24000 characters in all, and diagnosis check
results at 16000.
- Every model call logs its prompt and answer tokens, with a warning near
the context limit.
- unsafeCommands: a draft whose startup command or installConfig pipes a
download into a shell, decodes base64, uses eval, raw network tools or
/dev/tcp, sudo/su, setuid bits, writes /etc, touches cron/systemd/firewall,
or looks like a miner goes back to the model. AUTHORING.md has the rule.
- The PR summary lists every address nodes would download from under
"Review carefully", marks the measured checks as measured, and labels the
research notes as the model's reading, not checked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every container the node-agent starts gets /usr/sbin/docker-init, and SteamCMD
rewrites its own config.vdf on every run. Counted as files written outside the
volumes, they made every build look like it loses saves. A folder whose only
changes were logs no longer counts either, and a folder followed by a
same-named file (worlds, worlds.bak) is no longer taken for a file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's boot test gave every blank password-like setting a throwaway value. A
real deploy only fills x-generate fields, so a template whose server won't
start without one passed CI and failed for the first owner who deployed it.
boottest-payload now fills only x-generate fields, for CI and the builder
alike. The old behaviour is kept as -fill-blank-passwords, used only by
the builder's second boot to tell whether an empty setting is why a draft
fails. Messages and AUTHORING.md no longer say boot tests fill passwords;
a server that needs a join password gets x-generate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Launch options must be documented. A draft passed an option its server
doesn't have; servers ignore unknown options, so it booted and passed every
boot test while its setting did nothing. build now reads the pages research
based the variant on, in full, and the drafter rejects any launch option in
the startup command that none of them, nor the image's own scripts, mention.
Shell tools' options (mkdir -p, [ -n ...]) are skipped; the check is off
without sources.
The builder is game-agnostic:
- AUTHORING.md (the model's rules), the research prompt and the schema
describe the rules without naming a game.
- The draft prompt no longer includes real templates from the repo. Its
format example is one invented server (no real command, options, ports or
app id), checked by TestExampleTemplateFollowsTheRules.
- Comments, help texts, BUILDER.md and test fixtures use invented names and
values.
- TestBuilderIsGameAgnostic reads every game's name and id from games/ and
fails if any appears in the builder's code, tests, rules, schemas or docs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The second Valheim build stopped before its boot test: told that
test.yaml's password "looks like a credential; map it under 'secrets'",
the model mapped it to a CI secret nobody created, and boottest-payload's
missing-secret exit ended the build.
- The validator now says to remove a test password first (boot tests fill
password settings with a throwaway value); secrets only when the server
can't start without a real one.
- Drafts with test.yaml 'secrets' fail the draft checks.
- build turns boottest-payload's missing-secret exit into feedback for the
model instead of an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two problems a draft can boot fine with but break once an owner changes a
setting, both in the builder's Valheim draft:
- splitSettings: text settings used unquoted on the command line, directly
or through ARGS="-name ${SERVER_NAME}"; ./server $ARGS, so "GBRHosting -
My Server" reaches the game as several arguments. Suggests quoting or a
bash array.
- portSettings: game-port settings whose default isn't in defaultPorts, or
that owners can change although nodes always publish the same container
port. Internal ports (RCON, REST) and {PUBLIC_PORT_n} values are left out.
Both run on drafts only; AUTHORING.md gets the matching rules.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 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 the bot account.
- Dockerfile.builder, a workflow publishing gbr-builder:latest, and
BUILDER.md. Everything about where it runs comes from environment
variables; deployment files live outside this public repo.
draft now keeps its conversation in a drafter, so build can send boot
failures back to the same model session. The boot-test runner comment no
longer names its VM.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`gbrgames draft -name <game> -image <image> [-steam-app ID]
[-first-boot report.json]` has a model write games/<id>/game.yaml and
test.yaml, then checks them like any template and sends problems back
for up to three fix rounds. Ollama (default qwen3.8:27b, OLLAMA_URL) or
Gemini (GEMINI_API_KEY).
The model gets AUTHORING.md (new: the house rules, from how nodes really
run servers and today's bugs: x-generate passwords, no published RCON
ports, containerUser, heap below the limit, env var naming, ready lines),
the inspect-image facts, the first-boot report and the two smallest
templates as examples. With Ollama the answer is forced into the
template schema, tightened for drafts so ports, install config, settings
and their descriptions can't be left out or null.
On top of validation and the image checks, drafts must:
- be complete: player ports, >=3 settings each described, real memory,
a readyPattern or settleSec
- name settings so they reach the container as variables the image reads
(ServerPassword -> SERVER_PASSWORD when the image reads SERVER_PASS)
- not leave files first boot saw outside /server (lost on every start)
A first boot showing the image dies within seconds on permission errors
(it needs root) stops the draft before any model call. A missing
readyPattern is filled from first boot's verified suggestion.
Valheim, which we have no template for: lloesche/valheim-server was
rejected as root-only; via SteamCMD (app 896660) qwen3.8:27b on a local
3090 Ti wrote a passing template in two rounds (~1 min). It is about
70% there: it chose "--save-dir /server", which Valheim doesn't have
(-savedir), and missed -crossplay and 2457/udp. The save check is a text
check; booting the draft itself is the next step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>