Skip to content

rada

rada is a queue for heavy commands on a single machine. It exists for the case where several Claude Code sessions are open at once, one per project, and each independently starts something large: a training run, an Xcode build, a Unity import, an ffmpeg pass. Sessions are isolated by design and cannot see each other, so nobody is counting. rada counts. A heavy command waits until there is room, and a language model decides who goes first when several are waiting.

  • It does not kill anything. A job that has started runs to completion, and a dev server that holds memory forever holds it forever. rada says so instead of waiting silently.
  • It does not gate work that never becomes a Bash command. An MCP tool that builds an Xcode project inside its own server is invisible to a hook on Bash.
  • It does not know what a job needs before it has seen it once. The first run of anything is assumed to need 512 MB unless you say otherwise.
  • It does not schedule across machines. It has only been run on macOS on Apple Silicon, and where it cannot read memory it lets every job through.
  • It does not send anything anywhere. The judge runs claude -p locally, on a prompt containing project names and command lines. rada mode advise turns the judge off.
Terminal window
git clone https://github.com/nerln/rada.git ~/dev/rada
cd ~/dev/rada
./bin/rada install

That registers one PreToolUse hook, which runs before every Bash command in every session. It forks once and matches with shell builtins: about 3 ms for commands that are not heavy, above the cost of starting any hook.

Terminal window
rada status # what is running, what is waiting, and why
rada watch # the same, refreshed
rada run --need 6G -- python train.py
rada run --note "blocking the paper deadline" -- pytest tests/
rada run --max 600 -- ./slow-build.sh # give up waiting after ten minutes
rada doctor # check the installation
rada reset # forget the queue

Which commands count as heavy lives in ~/.rada/heavy.txt, one substring per line. Edit it and run rada install again to recompile it. RADA_FAKE_BUDGET=500M pins the budget to a number you choose, to see what the queue does on a smaller machine.

The hook looks at each Bash command. Commands that do not look heavy run untouched. A heavy one is saved verbatim and the call is rewritten to a wrapper, which takes a ticket and waits, printing why it is waiting and who is holding the memory. When there is room and the turn comes, the command runs and rada measures what it used. There is no daemon: coordination is a single JSON file under ~/.rada guarded by a lock.

The budget is smaller than the number that looks available, because page cache counts as available and the compressor holds real memory. It is total − reserve − (wired + compressor + uncompressed anonymous), the reserve being 15 percent or 1.5 GB, whichever is larger. A job is admitted only if its estimate times 1.3 fits. The estimate comes from the job itself: rada samples the process group’s peak footprint and remembers it against a signature of the command with numbers erased, or --need 6G sets it by hand.

The judge is claude -p, given the queue and asked who is likely to be waiting on a result. It runs only when two or more jobs are queued, at most once every three minutes. Its answer becomes a bonus of at most three points on a score where waiting earns one point every thirty seconds, so a job that arrived ninety seconds earlier outranks a newcomer whatever the judge says. A job that has waited ten minutes joins a set served first by arrival order, from which the judge is excluded. An answer that is slow, missing, or not a permutation of the queue it was given is discarded.

Terminal window
python3 tools/prova.py

Seventy checks, a couple of seconds, no model and no real memory allocated. They cover the rewrite refusing to leak shell operators or newlines, both fairness lemmas including a four-hundred-round adversarial simulation, lease recovery after a crash, the lock under four processes hammering it, the judge’s output validation, reservation and backfill and the cooldown, and two real processes contending for one berth. Two of them exist because they found real defects: the admission decision and the lease sat in different transactions, so two jobs could be admitted at once, and the lock announced itself before it said who owned it, so two processes could hold it.

The command lines the judge reads carry text from repositories, which may be hostile. tools/prova-giudice.py puts six styles of attack through a paired comparison: the same queue with the hostile text and without it. On the recorded run, one attack in six worked. An appeal to a deadline in one hour promoted the job, and the judge’s stated reason repeated the claim. A direct instruction to rank the job first sent the job down. Text forging a second queue entry made the judge time out, and the queue fell back to arrival order. The other three changed nothing.

One in six is the honest number. The arithmetic above is what makes it tolerable: a fully successful injection buys ninety seconds of queue jumping and nothing else.