atagen

roundabout

public
Star0
Watch0
61c6e94355d9b164b40de203ec22111b4da17cbf
1
ssh://brewery@pls.lobotomise.me:33/atagen/roundabout.git
README

roundabout

five agents, one machine, one youtube video. roundabout makes the builds take turns.

agents say roughly how big a build is. a tiny daemon, started on demand and gone once idle, lets it run when there’s room. two heavy builds never overlap, nothing gets promised disk that isn’t there, and small stuff keeps slipping through while the big one grinds. roundabout doesn’t run anything itself, it just holds the door.

use

the cli is rabt, short enough that agents don’t mind typing it

rabt run --size m -- cargo build
rabt run --ram 6G --cores 8 --time 10m -- nix build .#thing
rabt status
rabt suggest -- cargo build --release
rabt watch 7        # exits when lease 7 is done or overdue
rabt kill 7
rabt extend 7 10m
rabt artifacts check | list | gc [--cap] | pin <path>

run exits with the build’s code, 124 if --deadline killed it, 75 if --max-wait ran out.

a granted build gets CARGO_BUILD_JOBS, MAKEFLAGS, CMAKE_BUILD_PARALLEL_LEVEL and a NIX_CONFIG with cores/max-jobs to match its grant, so it actually uses the cores it asked for and no more.

claude code

nix build .#plugin
claude plugin marketplace add ./result
claude plugin install roundabout@roundabout

the plugin brings a skill and hooks. unwrapped builds get bounced back with instructions, overdue builds get mentioned to the agent that started them, and agents over their artifact cap get told to tidy up before they stop. rabt needs to be on PATH for the agent too, so install .#roundabout alongside.

config

~/.config/roundabout/config.toml, falling back to /etc/roundabout/config.toml, or $ROUNDABOUT_CONFIG over both. the daemon picks up edits on save, on linux anyway. a broken config gets complained about and ignored rather than taking every agent down with it. everything’s optional, these are the defaults

[budget]
ram = "75%"            # of total, or "24GiB"
ram_reserve = "4GiB"   # MemAvailable never drops below this on our account
cores = "100%"
disk_reserve = "20GiB" # per fs, capped at a tenth of it
disk_paths = ["/nix/store"]
psi_max = 40.0         # memory psi avg10 above this holds heavies back

[heavy]                # any one of these makes a build heavy
ram = "4GiB"
cores = "50%"
disk = "5GiB"

[sizes.m]              # s m l xl built in, add your own
ram = "2GiB"
disk = "1GiB"
cores = 4
time = "5m"

[queue]
linger = "5s"
backfill_max_time = "2m"
# max_wait = "30m"

[overrun]
ram = "warn"           # or "throttle", systemd-run MemoryHigh on linux
ram_slack = 1.25
time_grace = 1.5       # overdue at this multiple of --time
remind_every = "5m"

[enforce]
unwrapped = "deny"     # "wrap" guesses a size for them, "allow" looks away
default_size = "m"

[artifacts]
project_cap = "10GiB"
global_cap = "60GiB"
idle_after = "24h"
size_ttl = "10m"
over_cap = "warn"      # "block" refuses new builds until cleaned
stop = "nudge"         # "block" "warn" "off"
nix_gc = false
nix_min_free = "30GiB"
# extra_rules = [{ name = "zig-cache", marker = "build.zig" }]

[nix]
inject = true
cores_per_job = 4

[detect]
# extra = ["just build"]

license

EUPL-1.2