Your AI agents won't set your GPU on fire. Or your CPU, or your RAM.
firefighter is a local GPU, CPU and RAM scheduler, job queue and market maker for AI coding agents (Claude Code, Codex, Gemini CLI, Cursor, Grok, OpenCode, Kimi, Antigravity, Copilot, T3 Code and more) that share one computer. One command to install, on Windows, macOS and Linux. After that, every agent session queues its heavy work, sees what the others are doing, and gets out of the way when you need the machine.
The problem
Run three or four agents at once and each one decides on its own to train a model, run an evalsweep, build a Docker image or render something. They all grab the same GPU. VRAM runs out (CUDAout-of-memory, or silent spill into system RAM on Windows), two trainings slow each other to acrawl, your game stutters, audio crackles, and nobody knows who's using what or for how long.
What firefighter does
- ๐ค You always come first. It watches your keyboard and mouse, fullscreen apps, games (3D-engineuse), and every process it didn't start: Docker containers, Kubernetes pods, local model servers,your own apps. It keeps a dynamic reserve of CPUs, RAM and VRAM for you that grows within half asecond when you sit down or start a game and gives capacity back slowly when you leave.
- ๐๏ธ Agents take turns instead of fighting. Heavy work waits in a queue. A GPU job starts onlywhen its VRAM need fits, and that need is learned from the command's past runs. Projects that haveused the least go first (least attained service), with a 45-minute cap on any wait.
- ๐น A market maker, not a bidding war. Agents don't bid against each other. firefighter postsprices for three tiers: spot (leftovers, โ
price), normal, and urgent (2ร, onlywhen you're waiting on the result). Every reply an agent already gets ends with one line: wheneach tier would start, what it costs against the agent's budget, the odds the GPU is busy overthe next 2 hours, a quiet hour to aim for, and a
do:with the one recommended action. Theadvice never tells an agent to outbid anyone, so the whole market costs about 60 tokens andthere's no bidding war to win. - ๐ก๏ธ Fallbacks for careless or rogue agents. Heavy processes an agent starts outside firefighterare found and adopted anyway: idle priority, billed 1.5ร, preempted first. That makes skippingthe queue strictly worse than using it. Other guards cover queue flooding (per project and intotal), new project names that try to get a fresh budget (all new projects share one smalldaily pool), chronic under-estimates (ร1.25), VRAM hoarding (ร3), lease overruns (ร2, preemptedfirst), leases over 24 h, extensions after a short backfill, and one agent cancelling orre-bidding another agent session's job (you, from a terminal or editor, can manage any job). Text an agent sends (plans, names) is stripped of controlcharacters before other agents or your terminal see it.
- ๐ซก Graceful for the agent. When you need the machine back, the job's own client says why,and the job gets the whole grace period (60 s) to save and exit (checkpoint protocol). OnmacOS/Linux a job still running 10 s before the deadline gets SIGINT (Ctrl+C) before SIGTERM; onWindows it keeps the full grace period, then is stopped. It's requeued under the same id and theagent is told why and that there's nothing to resubmit.
- โธ๏ธ Polite preemption. The ladder goes: shrink the job's CPU set โ cooperative pause at a stepboundary โ suspend (for jobs that ignore the pause) โ checkpoint-and-exit with automatic requeuewhen you need the memory back โ kill, but only when RAM is critical.
- ๐ Network too. Downloads and uploads (
docker pull, pip/npm/cargo installs,git clone,model and dataset downloads; detected automatically, or--net) take turns, wait while you'reusing the link (a call, a stream:network.human_busy_pct), and pause while you game. - ๐งฎ Any machine. Any number of GPUs from any vendor (NVIDIA, AMD, Intel; mixed is fine), anyCPU count (Windows processor groups past 64 included), any RAM size. Each GPU job is placed on thecard it was admitted on, in that vendor's own numbering. On mixed machines a job goes to theNVIDIA cards unless it says otherwise (
--gpu-vendor amd|intel|any). Every PC runs its own firefighter; nothinggoes over the network. - ๐ Set and forget.
setupstarts the guard at logon and, for every agent it finds installed,registers the MCP server and adds a short rule block to its global instructions, so every newsession (including T3 Code threads) already knows the protocol: Claude Code, Codex, Gemini CLI,Antigravity, Cursor, Grok Build, OpenCode, Kimi CLI and Kimi Code, Pi, Muse Code, fx, Kiro,Windsurf/Devin, Copilot CLI, Amp, Qwen Code, Crush, Cline, Goose and Droid. Each in its ownformat;uninstallremoves all of it.
Install (one command)
Windows (PowerShell):
irm https://raw.githubusercontent.com/JoshWright22/FIREFIGHTER/main/scripts/install.ps1 | iex
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/JoshWright22/FIREFIGHTER/main/scripts/install.sh | sh
The installer checks the release checksum, puts one ~8 MB binary on your PATH, and runs firefighter setup.With Go 1.23+:go install github.com/JoshWright22/firefighter/cmd/firefighter@latest && firefighter setup.
Requirements: Windows 10/11, macOS 12+ or Linux, on x64 or arm64. No admin rights needed. ForGPU numbers you need nvidia-smi (NVIDIA driver) or rocm-smi (AMD). On Linux, idle detectionuses GNOME, KDE or another freedesktop ScreenSaver desktop, or xprintidle; headless machinescount you as "present".
What install changes (each config file gets a one-time *.firefighter.bak backup first):
| What | Where |
|---|---|
| Binary | %LOCALAPPDATA%\Programs\firefighter (added to your user PATH) or ~/.local/bin (added to your shell rc) |
| Autostart | Task Scheduler task firefighter (falls back to the HKCU Run key) ยท ~/Library/LaunchAgents/dev.firefighter.plist ยท ~/.config/systemd/user/firefighter.service (falls back to XDG autostart) |
| Agent rules | a marked block in ~/.claude/CLAUDE.md, ~/.codex/AGENTS.md, ~/.gemini/GEMINI.md |
| MCP server | claude mcp add (or ~/.claude.json), ~/.codex/config.toml, ~/.gemini/settings.json, ~/.cursor/mcp.json |
| State | %LOCALAPPDATA%\firefighter, ~/Library/Application Support/firefighter, ~/.local/state/firefighter (or FIREFIGHTER_HOME) |
Verify: open a new terminal and run firefighter status. Remove: firefighter uninstall undoesautostart, the rule blocks and the MCP entries. Then delete the binary and, if you want to forgetbudgets and history, the state folder.
Use
firefighter run --gpu --minutes 40 --vram 10 --name "nanoGPT train" -- python train.py
firefighter run --gpu --urgent --minutes 10 -- python eval.py # you're waiting on it: 2x
firefighter run --gpu --spot --minutes 120 -- python sweep.py # can wait: 1/3 price
firefighter run --minutes 5 -- npm run build # long CPU work
firefighter run --gpu --minutes 20 -- docker run --gpus all my/eval # containers are governed too
id=$(firefighter run --detach --gpu --minutes 90 -- python sweep.py) && firefighter wait "$id"
firefighter quote --gpu --minutes 30 --vram 8 # the market, no side effects
firefighter bid <id> 10 # make a waiting job urgent (5 = normal)
firefighter status # who's on stage until when, the queue, budgets
firefighter plan "eval sweep" --when tonight --minutes 120 --gpu 90 --vram 12
firefighter extend <id> 15 # running long? say so
run waits for a turn, then runs your command in your own environment (venv, conda, uv, nvm anddocker all just work), passes its output and exit code through, and ends with a receipt:
โ 3f2a91c0 nanoGPT train waiting #2, starts ~14:05 (in 22m): GPU turn queue
gpu 40m: start ~22m, cost ~42 of 212 (urgent ~6m ~84) (spot ~70m ~14) | busy 15/60/120m 92/35/12% | quiet 02:00 (usually 8% busy) | do: queue it at normal (starts ~22m); keep working meanwhile
โ nanoGPT train: spotlight's yours (lease 40 min, budget left 212.0)
โ nanoGPT train: curtain call, ok (exit 0) in 37.2 min (declared 40), waited 6.1, charged 31.4 machine-min, peak 3.1 GB RAM / 9.4 GB VRAM
MCP tools (one-line text replies plus structuredContent): firefighter_submit,firefighter_wait, firefighter_status (which also gives quotes), firefighter_job (extend,urgent/normal, cancel) and firefighter_plan. firefighter_config is listed only when you allowagents to change the policy.
How it decides (and how to change it)
Zero config gives you the researched defaults below. You can swap each part by name, live, withfirefighter config set <key> <value>. Agents read the policy with firefighter config show; thefirefighter_config MCP tool (to change it) is listed only if you set guard.agents_can_configure true.
| Stage | Default | What it does | Swap with |
|---|---|---|---|
| You | dynamic reserve | Four states: away, present, active and game. The reserve grows within one 0.5 s tick and gives back 1 CPU every 15 s, RAM after 60 s and VRAM after 120 s. Jobs are pinned to the CPUs outside your reserve (Windows and Linux; macOS uses background QoS instead). A state with pause_gpu (game, by default) pauses GPU jobs and starts no new ones. |
reserve.<state>.cpus / ram_pct / vram_gb / pause_gpu, reserve.exclusive_apps |
| Order | las |
The project with the least use goes first, with a 12 h half-life (Tiresias, Slurm fair share). A 45-minute wait cap overrides it. | order.policy = las | stride | lottery | drf | fifo | srpt |
| Market | priced |
Price per machine-minute = tier (spot โ
, normal 1, urgent 2) ร congestion ร 1.25 for projects whose jobs habitually overrun. Congestion is 0.5 ร 8^u, where u is how committed the resource is over the next hour: 0.5 idle, about 1.4 at half load, 4 when full. The price is locked when the job is granted; overruns pay ร2 and adopted work ร1.5 on top. Urgent buys at most 30 min of queue lead under las and stride. |
pricing.policy = priced | free, pricing.max_lead_minutes |
| Budget | karma |
Steady refill of 240 machine-minutes a day (10 an hour), banked up to 2 days (Karma, OSDI '23). The first project on a machine starts full. Later new projects start at the median usage and draw their start and first day's refill from one pool all new projects share (120 a day), so inventing names doesn't mint budget or jump the queue. While a project's budget is empty, its waiting and running jobs are spot. | budget.policy = karma | daily | none, budget.daily_minutes, budget.bank_days, budget.projects.<name>, budget.weights.<name> |
| Charge | DRF | One machine-minute is all of the GPU, VRAM, RAM or CPUs for one minute (Dominant Resource Fairness). Idle VRAM is charged ร3 (ESX idle tax), overruns ร2, and chronic under-estimates ร1.25. | built in |
| Admission | learned peaks | A job's need is the larger of its declared size and 1.2 ร its learned peak, checked against what's left on one GPU after your reserve and the unclaimed needs of jobs already there. Each card takes turns on its own (gpu.max_jobs per card, a second job only while that card's load leaves room), and a job goes to the least busy card that fits (fewest jobs, then lowest load, then most VRAM left); a need is clamped to what that card ever offers (its size, less your reserve, less the least others have held lately). The job is pinned to that card (CUDA_VISIBLE_DEVICES with PCI order, HIP_VISIBLE_DEVICES/ROCR_VISIBLE_DEVICES, or the oneAPI selector; docker run --gpus is narrowed too). First-time commands start 5 s apart so their real use shows. Short jobs (declared and predicted โค 10 min) may backfill behind a head that's waiting on VRAM. With no discrete GPU (Apple silicon), VRAM needs count as RAM. |
gpu.max_jobs (per card), gpu.pack_below_util, gpu.vram_margin, gpu.default_vram_gb |
| Preemption | ladder | See the ladder below. | ladder.* |
| Guard | on | Heavy processes an agent CLI (Claude Code, Codex, Gemini, Grok, OpenCode, Kimi, Copilot, Amp, Qwen, Aider, Goose, Cline and more) starts outside firefighter get adopted: spot band, idle priority, charged. IDE terminals are never adopted. Each project is capped at 20 open jobs. Agents can read the policy but can't change it unless you allow it, and even then only order.*, pricing.* and gpu.* (never presets, which set reserves). |
guard.auto_adopt, guard.agent_parents, guard.heavy_*, guard.agents_can_configure |
Presets: balanced (default), gamer, throughput, fair โ firefighter config set preset gamer.
| Band | Who | Preempted by |
|---|---|---|
| 0 ยท headliner | you, plus everything not run by firefighter (apps, games, Docker, k8s) | nothing |
| 1 ยท opener | short CPU jobs (โค 3 min) | you |
| 2 ยท main set | in-budget GPU and long jobs (the market) | you |
| 3 ยท afterparty | over budget, --spot, past the lease, or adopted |
anything |
| 4 ยท harvester | optional idle-GPU program (Salad, BOINC, Folding@home) | anything |
The preemption ladder
Steps run in order, and each one fires only if the trigger is still there:
- CPU set. Jobs always live outside your CPU reserve (Windows, Linux).
- Cooperative pause (GPU jobs, while your state holds the GPU): firefighter creates the fileat
FIREFIGHTER_PAUSE_FILE. A job that honors it createsFIREFIGHTER_PAUSED_FILEand sleepsuntil the pause file is gone. - Suspend: if the job hasn't acknowledged within 10 s (or, where per-process GPU countersexist, acknowledged but kept computing), it's suspended. It stays suspended while you need theGPU. Past 60 s, if the memory it holds is what you're short of, it's stopped and requeued (itignored the pause, so it can't checkpoint).
--evict neverjobs stay suspended until you're done. - Checkpoint: when RAM or VRAM (per card) stays under your reserve for 20 s, or when a spot jobhas run its 10-minute minimum and an in-budget job is waiting on what it holds, firefighter liftsany pause and creates
FIREFIGHTER_CHECKPOINT_FILE. The job gets 60 s to save and exit. On Unix it then gets aSIGTERM, and 10 s later it's killed. A job that exits with 75, or exits at all after therequest, is put back in line under the same id.--evict forcejobs are killed at once (and put back in line the same way). - Kill: if available RAM drops under 3%, one job is killed at once, even mid-grace, and thenext only after 5 s (memory takes a moment to come back).
Victims are picked so one eviction fixes the problem: first jobs whose memory covers the shortfall,then the highest band (spot, past their lease, adopted), then the heaviest. One eviction at a time.--evict never jobs are only ever touched when RAM is critical. CUDA can't be checkpointed from outside on Windowsor macOS, so the job has to cooperate. firefighter protocol prints a short Python helper youcall once per step.
Per-OS support
| Windows | macOS | Linux | |
|---|---|---|---|
| Your input | GetLastInputInfo | IOHIDSystem idle time | GNOME/Mutter, freedesktop ScreenSaver (KDE, Wayland), xprintidle |
| Games and fullscreen | fullscreen foreground window (not merely maximized), 3D-engine use per process, exclusive apps | exclusive apps only (add your games to reserve.exclusive_apps) |
exclusive apps only (gamescope by default; add yours); idle time from the desktop |
| GPU / VRAM | any vendor: nvidia-smi, plus DXGI + GPU counters for AMD/Intel (no vendor tool needed) | unified memory (counted as RAM) | nvidia-smi, rocm-smi or amdgpu sysfs; outside VRAM holders count as load only while the card is busy |
| Job priority | idle CPU, idle GPU scheduling, very low memory and I/O priority | nice 19 + background QoS | nice 19, SCHED_IDLE, idle I/O class, on every thread |
| CPU reserve | affinity (CPU Sets past 64 CPUs) | QoS | affinity |
| No orphans | Job Object, kill on close | process group | process group |
CLI reference
| Command | What it does |
|---|---|
run [flags] -- <cmd...> |
Wait for a turn, run, receipt. Flags: --gpu, --minutes N (lease; 30 if omitted), --vram GB, --ram GB, --urgent (2ร, the human is waiting), --spot (โ
, leftovers), --name, --project (default: the git repo or folder), --evict never|graceful|force, --detach (prints the id), --quiet, --bid 1-10 (legacy; 5 normal, 10 urgent) |
wait <id> [--timeout s] |
Block until the job ends (following requeues); prints the receipt and log tail. Exits with the job's exit code, or 124 on timeout |
quote [--gpu] --minutes N [--vram GB] [--ram GB] [--urgent] [--json] |
The market for a job, no side effects |
bid <id> <5|10> ยท extend <id> <minutes> ยท cancel <id> |
Change a job's tier, lease, or cancel it |
status [--json] |
The human's state and reserve, the market, running and waiting jobs, budgets, plans |
adopt <pid> [--gpu] [--name] [--minutes] |
Govern a process that's already running |
plan "<what>" --when ... --minutes N [--gpu %] [--vram GB] [--ram GB] ยท plan --done [--project p] |
Announce or remove planned work |
config [show | set <key> <value> | unset <key> | presets | path] |
Every key is in config show |
protocol |
The pause/checkpoint helper |
setup ยท uninstall ยท daemon [--stop] ยท mcp ยท version |
Install, remove, run or stop the guard, MCP server |
Files in the state folder: firefighter.toml (your settings), state.json (budgets, learnedhistory, receipts, the hour-of-week occupancy), STATUS.md (a status snapshot rewritten every 15 sfor agents that read files), daemon.log, logs/<id>.log (detached jobs, kept 7 days),signals/ (pause and checkpoint files), daemon.json and daemon.lock.
Editors and agent apps
- Every agent
setupfinds (see the list above, T3 Code's providers included): MCP and the rulesare wired up automatically. - Claude Code plugin: a live status-line entry,
/firefighter, and a guard that sends heavy Bashcommands back to the agent to rerun through the queue:/plugin install firefighter --marketplace JoshWright22/FIREFIGHTER - VS Code, Cursor, Windsurf extension: a live status bar item (the
.vsixis on every release). - Anything else:
firefighter statuslinegives one line for any status bar (Claude Code'sstatusLine, tmux, starship), andfirefighter eventsstreams NDJSON for editor plugins.There's also a local HTTP API. See docs/integrations.md.
How it compares
| firefighter | worker-q | load-lock / agent-task-queue | gpulease / gpu-arbiter | KAI-Scheduler / Kueue / Slurm | |
|---|---|---|---|---|---|
| Runs on Windows, macOS and Linux | โ | partial (Windows, Linux) | โ macOS/Linux | โ Linux | Linux clusters |
| Protects the human at the keyboard | โ dynamic reserve, game detection | partial: static reserve, manual gaming mode | โ | gpu-arbiter: Steam games | โ |
| GPU, CPU and RAM together | โ DRF | โ | โ slots | โ GPU only | โ |
| Any mix of GPUs, pinned per card | โ NVIDIA/AMD/Intel | โ | โ | NVIDIA | โ |
| Agent protocol (MCP + rules in agent instructions) | โ automatic, ~20 agents | partial (Claude only) | load-lock โ ~10 CLIs | partial | โ |
| Market information for every agent | โ quotes, busy odds | partial: ETAs | โ | โ | โ |
| Catches agents that skip the queue | โ adoption | partial: tags it | โ | gpulease: adopts, no limits | n/a |
| Preemption ladder (pause โ suspend โ checkpoint โ kill) | โ | partial: requeue | โ | partial | โ |
| One-command install, no cluster | โ | partial | โ | โ | โ |
Prior art was surveyed in Nov 2026 (about 65 projects read in full); nothing found does more thanabout half of this, and none on all three OSes. Details: docs/research.md.
FAQ
How do I stop several Claude Code or Codex agents from fighting over my GPU? Installfirefighter. New sessions read the rule block and register the MCP server, so they queue GPU workthrough firefighter run or firefighter_submit and wait their turn.
Why do I get CUDA out of memory when two AI agents train at once? Each agent sees the wholecard free and starts its own job, so together they ask for more VRAM than the card has. firefighterstarts a GPU job only when its VRAM need fits on one card next to what's already running and yourreserve; the need is learned from that command's past runs.
Can several AI agents share one GPU? Yes. They take turns, or run side by side when the cardhas room (gpu.max_jobs per card). With more than one GPU, each card takes jobs on its own and a jobgoes to the least busy card that fits.
Is there an MCP server for queuing GPU jobs? firefighter mcp, registered for every agent setupfinds. Tools: firefighter_submit, firefighter_wait, firefighter_status, firefighter_job,firefighter_plan.
Will it slow down my games? It's designed to do the opposite. Fullscreen apps and 3D-engine useswitch you to the "game" state (on macOS and Linux, list your games in reserve.exclusive_apps).Running GPU jobs get a cooperative pause; jobs that ignore it are suspended. If your game then needsthe memory a job holds, that job checkpoints (or, if it ignored the pause, is stopped) and requeues.No new GPU jobs start until you're done.
Does it work with Docker and Kubernetes? Containers you run yourself count as your load and areprotected by the reserve. firefighter run -- docker run ... labels the container so firefighter canpin, pause and stop it like any other job.
What if an agent ignores the rules? If an agent CLI starts something that stays heavy for 60seconds outside firefighter, it gets adopted. It's put on idle priority, charged to its project, andevicted first under pressure.
Can agents cheat the market? Prices are posted, not auctioned, so there's no bidding game. A bidof 10 costs double and buys at most 30 minutes of lead. Budgets belong to projects, so running morejobs doesn't buy more turns. Runtimes are checked against each command's history. Agents can readthe policy but not change it unless you set guard.agents_can_configure. An agent with shellaccess could still edit firefighter's files directly. firefighter is a referee for cooperativeagents, not a security boundary.
Does it need an NVIDIA GPU? No. It reads NVIDIA (nvidia-smi plus Windows GPU counters) and AMD(rocm-smi). On Apple silicon it schedules unified memory as RAM. Without a GPU it still schedules CPUand RAM.
Research
docs/how-it-works.md maps every paper's idea to the code that uses it, withthe numbers, and lists what isn't implemented and why. The policy comes from a survey of about 40repos and 30 papers. Among them: DRF (NSDI '11), Tiresias(NSDI '19), Themis (NSDI '20), Gavel (OSDI '20), Karma (OSDI '23), PerfIso (ATC '18), PilotFish(ATC '22), lottery and stride scheduling (OSDI '94), BOINC, KAI-Scheduler, AgentCgroup and AIOS. Thefull report with sources is in docs/research.md.
Testing
go test ./... runs the unit tests and an end-to-end suite. The suite builds the binary, starts areal daemon, and scripts the human, memory pressure and a GPU through FIREFIGHTER_FAKE_FILE. Itcovers GPU turns that never overlap, VRAM admission, game pause and resume, RAM-pressure checkpointand requeue, cancel, quotes and re-bids, adoption of rogue processes, daemon restart, the MCP server,and setup/uninstall. CI runs it on Windows (x64 and ARM), macOS and Linux (x64 and ARM) VMs, thentests both one-command installers.
MIT ยท built for people who run too many agents at once
Security notes
- The guard,
setupand both installers refuse to run as administrator or root: any agent ofyours can read the token and write its files, so anything elevated would lend those rights toevery agent. It runs as you, binds only 127.0.0.1, andkeeps its folder private (0700/0600 on Unix). - It only acts on what a job's own client started (the caller is identified by its exact TCPconnection, not by what it claims; only that client can start the job), on containers labeledfor that job, and on processes adopted by you or, for its own session's work only, by an agent.Ancestry and ownership checks ignore reused pids. "You" means a caller whose unbroken processchain reaches a terminal window (Windows Terminal, iTerm, GNOME Terminal, ...; or sshd) with noagent CLI, script runtime (node) or IDE in between (
guard.human_hosts,guard.agent_hosts).The terminal must be installed by an administrator: the program and every folder above it ownedby the system (root on macOS/Linux; TrustedInstaller, SYSTEM or Administrators on Windows), or areal sshd session started by root (a Linux text-console login, whose parent is init, doesn'tcount: an agent's detached process ends up there too). A terminal installed just for your user (a kitty orWezTerm download, Scoop, an app you dragged into /Applications, a Nix profile) doesn't count. The desktop shell, a classic consolestarted from it, tmux and screen don't count either (an agent can open those silently); fromthem, add--forcefor other projects' jobs and foradopt. Anything else, including detached helpersand agents hosted in node or an IDE, is an agent session limited to its own work and its project;from an IDE terminal, add--forceto manage another project's job. An agent that opens a windowin a terminal you already have running (wt.exe,open -a Terminal, a silentssh localhost)passes for you there too. These are guardrails against accidents, not a boundary against a hostileagent with your shell. firefighter_submitruns a command as you, outside an agent's own sandbox; its MCP annotationssay so, so hosts can ask for approval as they do for a shell.- Releases are built by GitHub Actions with SHA-pinned actions, the Go toolchain from go.mod, alocked npm toolchain for the extension, and least-privilege tokens, and carry signed buildprovenance. The installers check it automatically when the GitHub CLI is installed and signed in;by hand:
gh attestation verify firefighter_windows_amd64.zip --repo JoshWright22/FIREFIGHTER. - Any agent can stop the guard (it's your process; it could kill it anyway). It comes back on thenext firefighter call, and the new guard thaws anything the old one had suspended.
- Not a sandbox: an agent with your shell can do anything you can. firefighter makes the politepath the cheap one and catches the careless one; it doesn't contain a hostile one.
- Windows: a job's whole process tree is in a job object, so nothing it starts outlives it byaccident. Shared build servers on the
guard.keep_alivelist (MSBuild nodes, VBCSCompiler, ...)are spared when the job ends normally; if its client is killed, they go with it.