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 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 9 | the cli is `roundabout`, 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 | ``` |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 12 | roundabout run --size m -- cargo build |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 13 | roundabout run --ram 6G --cores 8 --time 10m -- nix build .#thing |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 14 | roundabout status |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 15 | roundabout suggest -- cargo build --release |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 16 | roundabout expect --size l # building soon, save me a seat |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 17 | roundabout watch 7 # exits when lease 7 is done or overdue |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 18 | roundabout kill 7 |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 19 | roundabout extend 7 10m |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 20 | roundabout artifacts check | list | gc [--cap] [--project] | pin <path> |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 21 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 22 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 23 | `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 | 24 | |
caac091f257a | atagen | 2026-10-04 11:41 UTC | 25 | a granted build gets `CARGO_BUILD_JOBS`, `MAKEFLAGS`, `CMAKE_BUILD_PARALLEL_LEVEL` and a `NIX_CONFIG` with `cores`/`max-jobs` to match its grant. |
caac091f257a | atagen | 2026-10-04 11:41 UTC | 26 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 27 | on linux, `roundabout` creates a transient scope through the systemd user manager's D-Bus `StartTransientUnit` method. the command waits until its scope is active, then runs with its original environment and terminal I/O. `CPUQuotaPerSecUSec` caps CPU time at the granted core count, and `MemoryMax` caps the whole build at its granted RAM multiplied by `overrun.ram_slack`, with at least the granted RAM available. these limits cover descendants too, even when a tool ignores the job-count environment variables. linux requires a running systemd user manager and user bus, a failed scope refuses the build rather than running it without limits. other platforms retain the job-count environment variables without cgroup enforcement. |
ecc1cf8df0f5 | atagen | 2026-09-27 13:36 UTC | 28 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 29 | the grant can be bigger than the ask. idle cores go to whoever's building, minus what other sessions have said they'll want via `roundabout expect`. spare cores never hold up admission, oversubscribing cpu only slows things down, but each one is charged ram at the build's own ram per core since more jobs eat more memory. a session's build counts as an `expect` too, so agents that forget still leave a mark. `--exact` opts out. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 30 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 31 | ## claude code |
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 | nix build .#plugin |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 35 | claude plugin marketplace add ./result |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 36 | claude plugin install roundabout@roundabout |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 37 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 38 | |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 39 | or on nixos |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 40 | |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 41 | ```nix |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 42 | imports = [ roundabout.nixosModules.default ]; |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 43 | programs.roundabout.enable = true; |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 44 | programs.roundabout.settings.budget.ram = "16GiB"; # lands in /etc/roundabout/config.toml |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 45 | ``` |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 46 | |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 47 | that installs roundabout and a socket-activated systemd user unit for the daemon (`socketActivation = false` to let clients spawn it instead). `programs.roundabout.claude` has read-only `hooks`, `skill` and `plugin` for whatever writes your claude config, e.g. `settings.hooks = config.programs.roundabout.claude.hooks`. |
052a1a49371c | atagen | 2026-09-27 03:59 UTC | 48 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 49 | 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. `roundabout` needs to be on PATH for the agent too, so install `.#roundabout` alongside. |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 50 | |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 51 | ## codex |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 52 | |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 53 | ``` |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 54 | nix build .#codex-plugin |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 55 | codex plugin marketplace add ./result |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 56 | codex plugin add roundabout@roundabout |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 57 | ``` |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 58 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 59 | restart codex and review the plugin hooks with `/hooks` before using them. install `.#roundabout` as well so `roundabout run` and `roundabout expect` are on PATH. codex can also load the hooks directly from `~/.codex/hooks.json` or a trusted project's `.codex/hooks.json` using the `hooks` object in `result/plugins/roundabout/hooks/hooks.json`. use one installation route to avoid duplicate reminders. |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 60 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 61 | on nixos, `programs.roundabout.codex` exposes read-only `hooks`, `skill` and `plugin`, alongside the claude options. the codex hooks deny unwrapped builds and suggest `roundabout run` instead of silently rewriting the command, which keeps the normal tool approval flow intact even when `enforce.unwrapped` is set to `wrap`. `roundabout run` and `roundabout expect` associate builds with the current codex session, and session-end hooks release its expectation. |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 62 | |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 63 | ## omp |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 64 | |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 65 | ``` |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 66 | nix build .#omp-plugin |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 67 | omp plugin link ./result |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 68 | ``` |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 69 | |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 70 | restart omp after linking. install `.#roundabout` on PATH for the agent's bash tool, or set `ROUNDABOUT_CLI` to the `roundabout` binary for the extension. the plugin bundles the skill and checks shell builds before they run. it also delivers overdue reminders, checks artifact caps before the main agent stops, and releases expectations when a session closes or switches. wrapped builds and `roundabout expect` inherit the omp session id through the bash tool's environment. on nixos, `programs.roundabout.omp` exposes read-only `plugin` and `skill` options. |
4e5ca2e20401 | atagen | 2026-09-28 11:42 UTC | 71 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 72 | ## config |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 73 | |
56a853ebf254 | atagen | 2026-09-27 03:59 UTC | 74 | `~/.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 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 75 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 76 | ```toml |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 77 | [budget] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 78 | ram = "75%" # of total, or "24GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 79 | ram_reserve = "4GiB" # MemAvailable never drops below this on our account |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 80 | cores = "100%" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 81 | disk_reserve = "20GiB" # per fs, capped at a tenth of it |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 82 | disk_paths = ["/nix/store"] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 83 | psi_max = 40.0 # memory psi avg10 above this holds heavies back |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 84 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 85 | [heavy] # any one of these makes a build heavy |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 86 | ram = "4GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 87 | cores = "50%" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 88 | disk = "5GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 89 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 90 | [sizes.m] # s m l xl built in, add your own |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 91 | ram = "2GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 92 | disk = "1GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 93 | cores = 4 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 94 | time = "5m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 95 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 96 | [queue] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 97 | linger = "5s" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 98 | backfill_max_time = "2m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 99 | # max_wait = "30m" |
ecc1cf8df0f5 | atagen | 2026-09-27 13:36 UTC | 100 | elastic = true # hand idle cores to whoever's building |
fdad58f8133a | atagen | 2026-10-25 23:14 UTC | 101 | intent_ttl = "20m" # how long a `roundabout expect` or a build keeps its claim |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 102 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 103 | [overrun] |
caac091f257a | atagen | 2026-10-04 11:41 UTC | 104 | ram = "warn" # or "throttle", MemoryHigh at granted RAM on linux |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 105 | ram_slack = 1.25 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 106 | time_grace = 1.5 # overdue at this multiple of --time |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 107 | remind_every = "5m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 108 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 109 | [enforce] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 110 | unwrapped = "deny" # "wrap" guesses a size for them, "allow" looks away |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 111 | default_size = "m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 112 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 113 | [artifacts] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 114 | project_cap = "10GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 115 | global_cap = "60GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 116 | idle_after = "24h" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 117 | size_ttl = "10m" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 118 | over_cap = "warn" # "block" refuses new builds until cleaned |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 119 | stop = "nudge" # "block" "warn" "off" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 120 | nix_gc = false |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 121 | nix_min_free = "30GiB" |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 122 | # extra_rules = [{ name = "zig-cache", marker = "build.zig" }] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 123 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 124 | [nix] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 125 | inject = true |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 126 | cores_per_job = 4 |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 127 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 128 | [detect] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 129 | # extra = ["just build"] |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 130 | ``` |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 131 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 132 | ## license |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 133 | |
93b435e669a5 | atagen | 2026-09-27 03:59 UTC | 134 | EUPL-1.2 |