- Move the council config to ~/.claude/agents-council/config.json, which the sandbox cannot write; the installer adds Edit(~/.claude/agents-council/**) to permissions.deny. - Run every kvb hook as /usr/bin/python3 -I and rewrite old bare python3 entries. - Refuse a council root that is a symlink, another uid's, or group or other writable, in watch, queue and radio. - Run worktree_cleanup entries as argv without a shell in /, only for compose project names. - queue block: tokenize every Bash command like bash (quotes, word-start comments, line continuations), and hold each held command to the Bash deny and ask rules of the managed, user and project settings; refuse a hold it cannot parse. - radio: deliver fields on one line of at most 1000 characters, at most 10 rows. Operator step after install: move ~/.config/agents-council/config.json to ~/.claude/agents-council/config.json. MEDUSA acceptances (kvb-think-criticize 2026-11-06, skeptics A and B): ACP-SCAN-028 load_config (config outside the sandbox, Docker residual 093); CODEGEN-SCAN-004 and LLM06 run_cleanup and worktrees_command shell strings (operator config only); SAST-PATH-001 queue hold Popen (the caller's own command in its sandbox); PA-133 radio hook context (peer rows, clipped); JB-SCAN-641/616/2979 clip and MM-SCAN-058 replace (name matches). 🎯 Fix: 90 % 💥 Break: 5 % 💸 Cost: 100 % ⏱️ Time: 100 % 🛡️ Security: 100 % 💰 Value: ? 🏆 Score: 86 🚦 Gate: ✅ 90/5, cost and time <= 100, security 100 % Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.6 KiB
name, description
| name | description |
|---|---|
| kvb-org-queue | Run every heavy job (gate, deploy, build, swarm) through a deterministic queue instead of asking the chair: hotfix first, then register rank. |
${CLAUDE_SKILL_DIR}/scripts/queue.py replaces asking the chair for heavy
slots with one queue that every waiting agent evaluates by the same rules.
Run a heavy job
queue.py hold --kind <kind> --task <register task> -- <command>
Start it in the background (run_in_background or equivalent) and end the
turn: hold waits, runs the command on its grant and exits with its code.
<kind>: a key ofslot_need_gbin~/.claude/agents-council/config.json.<register task>: your openkvb-org-rascitask; its rank places you.--hotfix <slug>: the job proves the register rowhotfix/<slug>(kvb-git-hotfix) and goes first.--need-gb <N>overrides the learned disk need.- Start hold in the job's worktree: its git toplevel is the workdir. Other
runtimes add
--session <id>. - In a worktree the command stays
gate.py run|hold(kvb-check-gate):queue.py hold ... -- python3 <gate.py> run ....
Light runs (no Docker, about a minute) self-admit with
watch.py admit --kind test-nostack (kvb-org-organize).
Order and grant
Every 20 s each waiting hold evaluates the whole queue under one lock:
- Hotfix jobs first, then the register rank (
rasci.py show), one place earlier per whole hour waited, then arrival. - In that order, a job is blocked at disk stage stop or critical, at warn when it needs disk, during a radio-silence mayday, while its kind's slots are taken, or while its workdir runs another job.
- A job whose need would cut below the stop threshold reserves that disk against smaller jobs behind it.
- An unblocked job counts as granted for the jobs behind it: none takes its slot.
- Kinds in
load_limits.kindsalso need CPU and RAM below the limits.
A waiting hold prints a stderr line when its position or reason changes.
History and learning
Every finished job appends a row to the council's queue-history.jsonl:
signature (make <target>, <script>.py <subcommand>), kind, minutes, exit
code, and disk, RAM and CPU at the grant and at their 20 s extremes. The
watch hook of kvb-org-organize keeps them in
~/.local/state/agents-council/ across reboots.
From the last 30 days, once 5 runs exist:
- per signature, the disk need is p90 disk taken plus 1 GB;
- per kind, the slot limit is how many p90 RAM and CPU shares fit between the
median load at the grant and
load_limits, at least 1.
Until then the seeds hold: slot_need_gb[kind] for disk, 1 slot per kind.
The optional slot_limits {kind: N} only caps a limit from above.
Inspect and cancel
queue.py list
queue.py history
queue.py cancel <id>
list shows each job's position, need, wait, ETA and blocking reason; dead
holders drop out. The ETA adds the median minutes left of running jobs
and of the jobs ahead, - while one is unknown. history prints the learned
values per signature and per kind, with each limit's source. cancel removes
your own waiting job; its hold exits 3.
Rules
- Never ask the chair for a heavy slot or announce a grant; the chair handles
only exceptions such as a stuck queue or a hung job (
capacity.mdofkvb-org-organize). - A running job is never cut short for the queue; only the operator orders
one down, and
kvb-git-hotfixmay void a gate. - With
queue_enforce: true, theblockhook (PreToolUse on Bash) refusesheavy_commandsandgate.py run|holdoutsidequeue.py hold. - Without the config, hold exits 2: tell the operator and ask the chair
(
kvb-org-organize) until it exists.