atagen

roundabout

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

Blame: README.md

93b435e669a5atagen2026-09-27 03:59 UTC1
# roundabout
93b435e669a5atagen2026-09-27 03:59 UTC2
93b435e669a5atagen2026-09-27 03:59 UTC3
five agents, one machine, one youtube video. roundabout makes the builds take turns.
93b435e669a5atagen2026-09-27 03:59 UTC4
93b435e669a5atagen2026-09-27 03:59 UTC5
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.
93b435e669a5atagen2026-09-27 03:59 UTC6
93b435e669a5atagen2026-09-27 03:59 UTC7
## use
93b435e669a5atagen2026-09-27 03:59 UTC8
93b435e669a5atagen2026-09-27 03:59 UTC9
the cli is `rabt`, short enough that agents don't mind typing it
93b435e669a5atagen2026-09-27 03:59 UTC10
93b435e669a5atagen2026-09-27 03:59 UTC11
```
93b435e669a5atagen2026-09-27 03:59 UTC12
rabt run --size m -- cargo build
93b435e669a5atagen2026-09-27 03:59 UTC13
rabt run --ram 6G --cores 8 --time 10m -- nix build .#thing
93b435e669a5atagen2026-09-27 03:59 UTC14
rabt status
93b435e669a5atagen2026-09-27 03:59 UTC15
rabt suggest -- cargo build --release
ecc1cf8df0f5atagen2026-09-27 13:36 UTC16
rabt expect --size l   # building soon, save me a seat
93b435e669a5atagen2026-09-27 03:59 UTC17
rabt watch 7        # exits when lease 7 is done or overdue
93b435e669a5atagen2026-09-27 03:59 UTC18
rabt kill 7
93b435e669a5atagen2026-09-27 03:59 UTC19
rabt extend 7 10m
93b435e669a5atagen2026-09-27 03:59 UTC20
rabt artifacts check | list | gc [--cap] | pin <path>
93b435e669a5atagen2026-09-27 03:59 UTC21
```
93b435e669a5atagen2026-09-27 03:59 UTC22
93b435e669a5atagen2026-09-27 03:59 UTC23
`run` exits with the build's code, 124 if `--deadline` killed it, 75 if `--max-wait` ran out.
93b435e669a5atagen2026-09-27 03:59 UTC24
caac091f257aatagen2026-10-04 11:41 UTC25
a granted build gets `CARGO_BUILD_JOBS`, `MAKEFLAGS`, `CMAKE_BUILD_PARALLEL_LEVEL` and a `NIX_CONFIG` with `cores`/`max-jobs` to match its grant.
caac091f257aatagen2026-10-04 11:41 UTC26
caac091f257aatagen2026-10-04 11:41 UTC27
on linux, `rabt` 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.
ecc1cf8df0f5atagen2026-09-27 13:36 UTC28
ecc1cf8df0f5atagen2026-09-27 13:36 UTC29
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 `rabt 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.
93b435e669a5atagen2026-09-27 03:59 UTC30
93b435e669a5atagen2026-09-27 03:59 UTC31
## claude code
93b435e669a5atagen2026-09-27 03:59 UTC32
93b435e669a5atagen2026-09-27 03:59 UTC33
```
93b435e669a5atagen2026-09-27 03:59 UTC34
nix build .#plugin
93b435e669a5atagen2026-09-27 03:59 UTC35
claude plugin marketplace add ./result
93b435e669a5atagen2026-09-27 03:59 UTC36
claude plugin install roundabout@roundabout
93b435e669a5atagen2026-09-27 03:59 UTC37
```
93b435e669a5atagen2026-09-27 03:59 UTC38
052a1a49371catagen2026-09-27 03:59 UTC39
or on nixos
052a1a49371catagen2026-09-27 03:59 UTC40
052a1a49371catagen2026-09-27 03:59 UTC41
```nix
052a1a49371catagen2026-09-27 03:59 UTC42
imports = [ roundabout.nixosModules.default ];
052a1a49371catagen2026-09-27 03:59 UTC43
programs.roundabout.enable = true;
052a1a49371catagen2026-09-27 03:59 UTC44
programs.roundabout.settings.budget.ram = "16GiB";   # lands in /etc/roundabout/config.toml
052a1a49371catagen2026-09-27 03:59 UTC45
```
052a1a49371catagen2026-09-27 03:59 UTC46
052a1a49371catagen2026-09-27 03:59 UTC47
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`.
052a1a49371catagen2026-09-27 03:59 UTC48
93b435e669a5atagen2026-09-27 03:59 UTC49
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.
93b435e669a5atagen2026-09-27 03:59 UTC50
4e5ca2e20401atagen2026-09-28 11:42 UTC51
## codex
4e5ca2e20401atagen2026-09-28 11:42 UTC52
4e5ca2e20401atagen2026-09-28 11:42 UTC53
```
4e5ca2e20401atagen2026-09-28 11:42 UTC54
nix build .#codex-plugin
4e5ca2e20401atagen2026-09-28 11:42 UTC55
codex plugin marketplace add ./result
4e5ca2e20401atagen2026-09-28 11:42 UTC56
codex plugin add roundabout@roundabout
4e5ca2e20401atagen2026-09-28 11:42 UTC57
```
4e5ca2e20401atagen2026-09-28 11:42 UTC58
4e5ca2e20401atagen2026-09-28 11:42 UTC59
restart codex and review the plugin hooks with `/hooks` before using them. install `.#roundabout` as well so `rabt run` and `rabt 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.
4e5ca2e20401atagen2026-09-28 11:42 UTC60
4e5ca2e20401atagen2026-09-28 11:42 UTC61
on nixos, `programs.roundabout.codex` exposes read-only `hooks`, `skill` and `plugin`, alongside the claude options. the codex hooks deny unwrapped builds and suggest `rabt run` instead of silently rewriting the command, which keeps the normal tool approval flow intact even when `enforce.unwrapped` is set to `wrap`. `rabt run` and `rabt expect` associate builds with the current codex session, and session-end hooks release its expectation.
4e5ca2e20401atagen2026-09-28 11:42 UTC62
4e5ca2e20401atagen2026-09-28 11:42 UTC63
## omp
4e5ca2e20401atagen2026-09-28 11:42 UTC64
4e5ca2e20401atagen2026-09-28 11:42 UTC65
```
4e5ca2e20401atagen2026-09-28 11:42 UTC66
nix build .#omp-plugin
4e5ca2e20401atagen2026-09-28 11:42 UTC67
omp plugin link ./result
4e5ca2e20401atagen2026-09-28 11:42 UTC68
```
4e5ca2e20401atagen2026-09-28 11:42 UTC69
4e5ca2e20401atagen2026-09-28 11:42 UTC70
restart omp after linking. install `.#roundabout` on PATH for the agent's bash tool, or set `ROUNDABOUT_CLI` to the `rabt` 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 `rabt expect` inherit the omp session id through the bash tool's environment. on nixos, `programs.roundabout.omp` exposes read-only `plugin` and `skill` options.
4e5ca2e20401atagen2026-09-28 11:42 UTC71
93b435e669a5atagen2026-09-27 03:59 UTC72
## config
93b435e669a5atagen2026-09-27 03:59 UTC73
56a853ebf254atagen2026-09-27 03:59 UTC74
`~/.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
93b435e669a5atagen2026-09-27 03:59 UTC75
93b435e669a5atagen2026-09-27 03:59 UTC76
```toml
93b435e669a5atagen2026-09-27 03:59 UTC77
[budget]
93b435e669a5atagen2026-09-27 03:59 UTC78
ram = "75%"            # of total, or "24GiB"
93b435e669a5atagen2026-09-27 03:59 UTC79
ram_reserve = "4GiB"   # MemAvailable never drops below this on our account
93b435e669a5atagen2026-09-27 03:59 UTC80
cores = "100%"
93b435e669a5atagen2026-09-27 03:59 UTC81
disk_reserve = "20GiB" # per fs, capped at a tenth of it
93b435e669a5atagen2026-09-27 03:59 UTC82
disk_paths = ["/nix/store"]
93b435e669a5atagen2026-09-27 03:59 UTC83
psi_max = 40.0         # memory psi avg10 above this holds heavies back
93b435e669a5atagen2026-09-27 03:59 UTC84
93b435e669a5atagen2026-09-27 03:59 UTC85
[heavy]                # any one of these makes a build heavy
93b435e669a5atagen2026-09-27 03:59 UTC86
ram = "4GiB"
93b435e669a5atagen2026-09-27 03:59 UTC87
cores = "50%"
93b435e669a5atagen2026-09-27 03:59 UTC88
disk = "5GiB"
93b435e669a5atagen2026-09-27 03:59 UTC89
93b435e669a5atagen2026-09-27 03:59 UTC90
[sizes.m]              # s m l xl built in, add your own
93b435e669a5atagen2026-09-27 03:59 UTC91
ram = "2GiB"
93b435e669a5atagen2026-09-27 03:59 UTC92
disk = "1GiB"
93b435e669a5atagen2026-09-27 03:59 UTC93
cores = 4
93b435e669a5atagen2026-09-27 03:59 UTC94
time = "5m"
93b435e669a5atagen2026-09-27 03:59 UTC95
93b435e669a5atagen2026-09-27 03:59 UTC96
[queue]
93b435e669a5atagen2026-09-27 03:59 UTC97
linger = "5s"
93b435e669a5atagen2026-09-27 03:59 UTC98
backfill_max_time = "2m"
93b435e669a5atagen2026-09-27 03:59 UTC99
# max_wait = "30m"
ecc1cf8df0f5atagen2026-09-27 13:36 UTC100
elastic = true         # hand idle cores to whoever's building
ecc1cf8df0f5atagen2026-09-27 13:36 UTC101
intent_ttl = "20m"     # how long a `rabt expect` or a build keeps its claim
93b435e669a5atagen2026-09-27 03:59 UTC102
93b435e669a5atagen2026-09-27 03:59 UTC103
[overrun]
caac091f257aatagen2026-10-04 11:41 UTC104
ram = "warn"           # or "throttle", MemoryHigh at granted RAM on linux
93b435e669a5atagen2026-09-27 03:59 UTC105
ram_slack = 1.25
93b435e669a5atagen2026-09-27 03:59 UTC106
time_grace = 1.5       # overdue at this multiple of --time
93b435e669a5atagen2026-09-27 03:59 UTC107
remind_every = "5m"
93b435e669a5atagen2026-09-27 03:59 UTC108
93b435e669a5atagen2026-09-27 03:59 UTC109
[enforce]
93b435e669a5atagen2026-09-27 03:59 UTC110
unwrapped = "deny"     # "wrap" guesses a size for them, "allow" looks away
93b435e669a5atagen2026-09-27 03:59 UTC111
default_size = "m"
93b435e669a5atagen2026-09-27 03:59 UTC112
93b435e669a5atagen2026-09-27 03:59 UTC113
[artifacts]
93b435e669a5atagen2026-09-27 03:59 UTC114
project_cap = "10GiB"
93b435e669a5atagen2026-09-27 03:59 UTC115
global_cap = "60GiB"
93b435e669a5atagen2026-09-27 03:59 UTC116
idle_after = "24h"
93b435e669a5atagen2026-09-27 03:59 UTC117
size_ttl = "10m"
93b435e669a5atagen2026-09-27 03:59 UTC118
over_cap = "warn"      # "block" refuses new builds until cleaned
93b435e669a5atagen2026-09-27 03:59 UTC119
stop = "nudge"         # "block" "warn" "off"
93b435e669a5atagen2026-09-27 03:59 UTC120
nix_gc = false
93b435e669a5atagen2026-09-27 03:59 UTC121
nix_min_free = "30GiB"
93b435e669a5atagen2026-09-27 03:59 UTC122
# extra_rules = [{ name = "zig-cache", marker = "build.zig" }]
93b435e669a5atagen2026-09-27 03:59 UTC123
93b435e669a5atagen2026-09-27 03:59 UTC124
[nix]
93b435e669a5atagen2026-09-27 03:59 UTC125
inject = true
93b435e669a5atagen2026-09-27 03:59 UTC126
cores_per_job = 4
93b435e669a5atagen2026-09-27 03:59 UTC127
93b435e669a5atagen2026-09-27 03:59 UTC128
[detect]
93b435e669a5atagen2026-09-27 03:59 UTC129
# extra = ["just build"]
93b435e669a5atagen2026-09-27 03:59 UTC130
```
93b435e669a5atagen2026-09-27 03:59 UTC131
93b435e669a5atagen2026-09-27 03:59 UTC132
## license
93b435e669a5atagen2026-09-27 03:59 UTC133
93b435e669a5atagen2026-09-27 03:59 UTC134
EUPL-1.2