Loading…
gathering yarn balls…
Cat Game Research
Frontier
Dev-log transmissions from the expedition

Loop and Kill: Endless Build Automation

A new pair of build controls gives us continuous rebuild loops with automatic backoff, and a single command to stop any runaway build.

The endless build problem

Whether you are iterating on a level in the editor, landing a large refactor, or keeping a build server fed with fresh binaries, the question is the same: how do I keep building without becoming the build? You start a compile, switch context, come back, run another, and another. Scale that to a server that is supposed to produce artifacts around the clock, and the problem becomes management overhead. Someone has to baby-sit the process, and someone has to stop it cleanly when it goes wrong.

We added two controls to the build wrapper to remove that overhead: loop and kill. One tells the build system to run forever with a safe backoff. The other tells it to stop, and to take the whole process tree with it.

60s
Normal Wait
5m
Backoff After 3 Failures
1
Command to Stop
∞
Loop Forever

How the loop works

When you start a build with the loop flag, the wrapper runs one build, waits, then runs the next build using the same preset and targets. Success or failure, it keeps going. The default wait is one minute, which is enough time to save a few files without the system sitting idle, and short enough that a passing build produces a fresh artifact quickly.

If something breaks and stays broken, the loop does not spiral. After three consecutive failures, the wait stretches to five minutes. That gives the operator time to read the log, fix the underlying problem, or stop the loop, while preventing the machine from thrashing on the same error.

1
Start the loop with the desired preset and targets.
2
Build runs as a separate child process so the loop can observe the exit code.
3
Wait 60 seconds on success or after the first two failures.
4
Back off to 5 minutes after three consecutive failures.

How to use it

The commands are intentional surface area, not background services. They are meant to be run in a terminal, a tmux session, or a supervised server process.

# Run the default build on a 60-second loop
./scripts/build.sh --loop

# Loop a specific preset and target
./scripts/build.sh --loop linux-debug engine

# Stop any running loop or in-progress build
./scripts/build.sh --kill

The loop is especially useful when you are parked on a single target. Change a header, save, and the next build is already queued. If the compile breaks, the loop backs off so the log is not flooded with the same failure.

The kill switch

A build is never a single process. It spawns compilers, asset importers, VPak packers, shader compilers, and their children. Stopping the top script is not enough; you can end up with orphan workers still holding locks or consuming cores. The kill command walks the process tree, terminates descendants first, sends a graceful stop to the build groups, then force-kills anything that refuses to exit.

Process group safety
Kill targets process groups, not just individual PIDs. That means the build wrapper, the compiler it called, and the asset worker it forked all stop together. The command also filters out its own process group so it never commits accidental suicide.

Build server and game server

The primary use case is the build server. A machine can now sit in a supervised loop producing artifacts for the game server to pick up. If the build breaks because an upstream file is temporarily missing, the five-minute backoff prevents noise. When an operator needs to drain the server for maintenance, --kill ends the loop and cleans the worker tree without a manual process search.

The same control pattern is designed to be portable to the game server lifecycle. A server process can be wrapped in a similar loop-and-kill contract: run, observe, wait, restart, and stop as a tree. The build wrapper was the first consumer because the build is where our largest process trees live, but the semantics—loop with backoff, kill as a group—apply anywhere we need supervised repetition.

What changed in the contract

The build wrapper now exposes two new surface controls. They are documented in the CLI reference, the build workflow, and the agent instructions so that everyone—humans and agents—uses the same verbs. No extra daemon is required. No state file is left behind. The loop is just the build, repeated, with a policy.

# Example: keep a debug build server producing binaries
./scripts/build.sh --loop linux-debug game engine tools

The next time you find yourself running the same build command for the tenth time in a row, or you need a build server that heals itself without human attention, the loop will already be waiting.

← All transmissions