93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 1 | # roundabout |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 2 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 3 | five agents, one machine, one youtube video. roundabout makes the builds take turns. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 4 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 5 | 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. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 6 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 7 | ## use |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 8 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 9 | the cli is `rabt`, short enough that agents don't mind typing it |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 10 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 11 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 12 | rabt run --size m -- cargo build |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 13 | rabt run --ram 6G --cores 8 --time 10m -- nix build .#thing |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 14 | rabt status |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 15 | rabt suggest -- cargo build --release |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 16 | rabt watch 7 # exits when lease 7 is done or overdue |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 17 | rabt kill 7 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 18 | rabt extend 7 10m |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 19 | rabt artifacts check | list | gc [--cap] | pin <path> |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 20 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 21 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 22 | `run` exits with the build's code, 124 if `--deadline` killed it, 75 if `--max-wait` ran out. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 23 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 24 | 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. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 25 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 26 | ## claude code |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 27 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 28 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 29 | nix build .#plugin |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 30 | claude plugin marketplace add ./result |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 31 | claude plugin install roundabout@roundabout |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 32 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 33 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 34 | 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. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 35 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 36 | ## config |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 37 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 38 | `~/.config/roundabout/config.toml`, falling back to `/etc/roundabout/config.toml`, or `$ROUNDABOUT_CONFIG` over both. everything's optional, these are the defaults |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 39 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 40 | ```toml |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 41 | [budget] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 42 | ram = "75%" # of total, or "24GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 43 | ram_reserve = "4GiB" # MemAvailable never drops below this on our account |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 44 | cores = "100%" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 45 | disk_reserve = "20GiB" # per fs, capped at a tenth of it |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 46 | disk_paths = ["/nix/store"] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 47 | psi_max = 40.0 # memory psi avg10 above this holds heavies back |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 48 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 49 | [heavy] # any one of these makes a build heavy |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 50 | ram = "4GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 51 | cores = "50%" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 52 | disk = "5GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 53 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 54 | [sizes.m] # s m l xl built in, add your own |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 55 | ram = "2GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 56 | disk = "1GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 57 | cores = 4 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 58 | time = "5m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 59 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 60 | [queue] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 61 | linger = "5s" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 62 | backfill_max_time = "2m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 63 | # max_wait = "30m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 64 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 65 | [overrun] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 66 | ram = "warn" # or "throttle", systemd-run MemoryHigh on linux |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 67 | ram_slack = 1.25 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 68 | time_grace = 1.5 # overdue at this multiple of --time |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 69 | remind_every = "5m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 70 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 71 | [enforce] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 72 | unwrapped = "deny" # "wrap" guesses a size for them, "allow" looks away |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 73 | default_size = "m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 74 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 75 | [artifacts] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 76 | project_cap = "10GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 77 | global_cap = "60GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 78 | idle_after = "24h" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 79 | size_ttl = "10m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 80 | over_cap = "warn" # "block" refuses new builds until cleaned |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 81 | stop = "nudge" # "block" "warn" "off" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 82 | nix_gc = false |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 83 | nix_min_free = "30GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 84 | # extra_rules = [{ name = "zig-cache", marker = "build.zig" }] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 85 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 86 | [nix] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 87 | inject = true |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 88 | cores_per_job = 4 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 89 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 90 | [detect] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 91 | # extra = ["just build"] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 92 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 93 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 94 | ## license |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 95 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 96 | EUPL-1.2 |