Skip to main content
Glama

The problem

Run three or four agents at once and each one decides on its own to train a model, run an eval sweep, build a Docker image or render something. They all grab the same GPU. VRAM runs out (CUDA out-of-memory, or silent spill into system RAM on Windows), two trainings slow each other to a crawl, your game stutters, audio crackles, and nobody knows who's using what or for how long.

Related MCP server: agent-bus-mcp

What firefighter does

  • ๐ŸŽค You always come first. It watches your keyboard and mouse, fullscreen apps, games (3D-engine use), 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 a second 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 only when its VRAM need fits, and that need is learned from the command's past runs. Projects that have used 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 posts prices for three tiers: spot (leftovers, โ…“ price), normal, and urgent (2ร—, only when you're waiting on the result). Every reply an agent already gets ends with one line: when each tier would start, what it costs against the agent's budget, the odds the GPU is busy over the next 2 hours, a quiet hour to aim for, and a do: with the one recommended action. The advice never tells an agent to outbid anyone, so the whole market costs about 60 tokens and there's no bidding war to win.

  • ๐Ÿ›ก๏ธ Fallbacks for careless or rogue agents. Heavy processes an agent starts outside firefighter are found and adopted anyway: idle priority, billed 1.5ร—, preempted first. That makes skipping the queue strictly worse than using it. Other guards cover queue flooding (per project and in total), new project names that try to get a fresh budget (all new projects share one small daily pool), chronic under-estimates (ร—1.25), VRAM hoarding (ร—3), lease overruns (ร—2, preempted first), leases over 24 h, extensions after a short backfill, and one agent cancelling or re-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 control characters 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). On macOS/Linux a job still running 10 s before the deadline gets SIGINT (Ctrl+C) before SIGTERM; on Windows it keeps the full grace period, then is stopped. It's requeued under the same id and the agent 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 step boundary โ†’ suspend (for jobs that ignore the pause) โ†’ checkpoint-and-exit with automatic requeue when 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're using 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), any CPU count (Windows processor groups past 64 included), any RAM size. Each GPU job is placed on the card it was admitted on, in that vendor's own numbering. On mixed machines a job goes to the NVIDIA cards unless it says otherwise (--gpu-vendor amd|intel|any). Every PC runs its own firefighter; nothing goes over the network.

  • ๐Ÿ”Œ Set and forget. setup starts 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 new session (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 own format; uninstall removes 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. For GPU numbers you need nvidia-smi (NVIDIA driver) or rocm-smi (AMD). On Linux, idle detection uses GNOME, KDE or another freedesktop ScreenSaver desktop, or xprintidle; headless machines count 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 undoes autostart, the rule blocks and the MCP entries. Then delete the binary and, if you want to forget budgets 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 and docker 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 allow agents 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, with firefighter config set <key> <value>. Agents can read the policy through the firefighter_config MCP tool, and can change it 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:

  1. CPU set. Jobs always live outside your CPU reserve (Windows, Linux).

  2. Cooperative pause (GPU jobs, while your state holds the GPU): firefighter creates the file at FIREFIGHTER_PAUSE_FILE. A job that honors it creates FIREFIGHTER_PAUSED_FILE and sleeps until the pause file is gone.

  3. Suspend: if the job hasn't acknowledged within 10 s (or, where per-process GPU counters exist, acknowledged but kept computing), it's suspended. It stays suspended while you need the GPU. Past 60 s, if the memory it holds is what you're short of, it's stopped and requeued (it ignored the pause, so it can't checkpoint). --evict never jobs stay suspended until you're done.

  4. Checkpoint: when RAM or VRAM (per card) stays under your reserve for 20 s, or when a spot job has run its 10-minute minimum and an in-budget job is waiting on what it holds, firefighter lifts any pause and creates FIREFIGHTER_CHECKPOINT_FILE. The job gets 60 s to save and exit. On Unix it then gets a SIGTERM, and 10 s later it's killed. A job that exits with 75, or exits at all after the request, is put back in line under the same id. --evict force jobs are killed at once (and put back in line the same way).

  5. Kill: if available RAM drops under 3%, one job is killed at once, even mid-grace, and the next 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 Windows or macOS, so the job has to cooperate. firefighter protocol prints a short Python helper you call 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, learned history, receipts, the hour-of-week occupancy), STATUS.md (a status snapshot rewritten every 15 s for 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 setup finds (see the list above, T3 Code's providers included): MCP and the rules are wired up automatically.

  • Claude Code plugin: a live status-line entry, /firefighter, and a guard that sends heavy Bash commands 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 .vsix is on every release).

  • Anything else: firefighter statusline gives one line for any status bar (Claude Code's statusLine, tmux, starship), and firefighter events streams 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 than about 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? Install firefighter. New sessions read the rule block and register the MCP server, so they queue GPU work through 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 whole card free and starts its own job, so together they ask for more VRAM than the card has. firefighter starts a GPU job only when its VRAM need fits on one card next to what's already running and your reserve; 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 card has room (gpu.max_jobs per card). With more than one GPU, each card takes jobs on its own and a job goes to the least busy card that fits.

Is there an MCP server for queuing GPU jobs? firefighter mcp, registered for every agent setup finds. 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 use switch 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 needs the 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 are protected by the reserve. firefighter run -- docker run ... labels the container so firefighter can pin, 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 60 seconds outside firefighter, it gets adopted. It's put on idle priority, charged to its project, and evicted first under pressure.

Can agents cheat the market? Prices are posted, not auctioned, so there's no bidding game. A bid of 10 costs double and buys at most 30 minutes of lead. Budgets belong to projects, so running more jobs doesn't buy more turns. Runtimes are checked against each command's history. Agents can read the policy but not change it unless you set guard.agents_can_configure. An agent with shell access could still edit firefighter's files directly. firefighter is a referee for cooperative agents, 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 CPU and RAM.

Research

docs/how-it-works.md maps every paper's idea to the code that uses it, with the numbers, and lists what isn't implemented and why. The policy comes from a survey of about 40 repos 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. The full 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 a real daemon, and scripts the human, memory pressure and a GPU through FIREFIGHTER_FAKE_FILE. It covers GPU turns that never overlap, VRAM admission, game pause and resume, RAM-pressure checkpoint and 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, then tests both one-command installers.

Security notes

  • The guard, setup and both installers refuse to run as administrator or root: any agent of yours can read the token and write its files, so anything elevated would lend those rights to every agent. It runs as you, binds only 127.0.0.1, and keeps 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 TCP connection, not by what it claims; only that client can start the job), on containers labeled for 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 process chain reaches a terminal window (Windows Terminal, iTerm, GNOME Terminal, ...; or sshd) with no agent 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 owned by the system (root on macOS/Linux; TrustedInstaller, SYSTEM or Administrators on Windows), or a real sshd session started by root (a Linux text-console login, whose parent is init, doesn't count: an agent's detached process ends up there too). A terminal installed just for your user (a kitty or WezTerm download, Scoop, an app you dragged into /Applications, a Nix profile) doesn't count. The desktop shell, a classic console started from it, tmux and screen don't count either (an agent can open those silently); from them, add --force for other projects' jobs and for adopt. Anything else, including detached helpers and agents hosted in node or an IDE, is an agent session limited to its own work and its project; from an IDE terminal, add --force to manage another project's job. An agent that opens a window in a terminal you already have running (wt.exe, open -a Terminal, a silent ssh localhost) passes for you there too. These are guardrails against accidents, not a boundary against a hostile agent with your shell.

  • firefighter_submit runs a command as you, outside an agent's own sandbox; its MCP annotations say 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, a locked npm toolchain for the extension, and least-privilege tokens, and carry signed build provenance. 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 the next 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 polite path 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 by accident. Shared build servers on the guard.keep_alive list (MSBuild nodes, VBCSCompiler, ...) are spared when the job ends normally; if its client is killed, they go with it.

Available Tools

5 tools
firefighter_jobB

Change your job: extend (minutes = more lease), urgent / normal (tier, while waiting), cancel.

NameRequiredDescriptionDefault
idYesJob id
actionYesextend | urgent | normal | cancel
minutesNoFor extend

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden. It does add real behavioral context beyond structured fields: extend adds lease minutes, urgent/normal changes the job's tier while it waits. But it says nothing about whether cancel is destructive or reversible, what happens to a job already running, permission requirements, or error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short, front-loaded sentence with no filler; every clause maps to an action. The telegraphic phrasing ('tier, while waiting') is terse to the point of being cryptic, but it is not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, the definition covers what each action does at a high level and the parameters are fully documented in the schema. It falls short on consequences, state preconditions, and return behavior, which an agent would want before invoking a job-changing operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description genuinely adds meaning: it explains that minutes applies only to extend and translates the action values urgent/normal into a tier change. That clarification of conditional parameter relevance goes beyond the flat enum-free schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description says 'Change your job' and enumerates four actions (extend, urgent, normal, cancel), which gives a rough sense of a job-control tool. However, it never states what a 'job' is or what the overall effect of the call is, and it does not distinguish this tool from siblings like firefighter_wait or firefighter_plan. The intent is inferable but vague.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Parenthetical hints imply when each action applies: extend when more lease time is needed, urgent/normal to change tier 'while waiting', cancel to abort. That is implicit usage guidance per action, but there is no explicit when-not, no mention of prerequisites (e.g. must the job be in a waiting state?), and no routing to alternative sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firefighter_planB

Announce heavy work later so others plan around it (reserves nothing). done=true removes your project's plans.

NameRequiredDescriptionDefault
atNoHH:MM or now
doneNoRemove
whatNoWhat
gpu_pctNoGPU %
minutesNoMinutes
projectNoProject
vram_gbNoVRAM GB

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose two important behaviours: the plan reserves nothing, and done=true deletes the project's plans (a broader blast radius than a single record). It omits confirmation of idempotency, permissions, and what happens when all seven optional parameters are omitted. Useful but incomplete for an unannotated mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the core purpose before the done=true deletion caveat. No wasted words, though the terseness edges toward under-specification rather than elegant brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a seven-parameter, unannotated tool with no output schema, the description leaves major gaps: what a 'plan' is, default values, which parameters are meaningful together, and what the call returns. It never states that all parameters are optional or what an empty call does. An agent could invoke it correctly only by guessing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is nominally 100%, so the baseline of 3 applies, but the schema descriptions are extremely thin ('What', 'Remove', 'Project'), adding little real meaning. The description does clarify done=true's effect at project scope and implies 'at' is a time-of-day or 'now'. Nothing explains how at, minutes, gpu_pct, and vram_gb interact.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource: announcing future heavy work so others can plan around it, plus a removal mode via done=true. The parenthetical 'reserves nothing' implicitly separates it from firefighter_submit, though it never names that sibling directly. The dual create/delete behaviour in one tool slightly blurs the single stated purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It says the tool is for announcing work 'later', and that done=true removes plans, but gives no explicit when-to-use versus firefighter_submit, firefighter_job, or firefighter_wait, and no exclusion or prerequisite guidance. Routing is left entirely to inference from the tool names. An agent could easily confuse this with actually submitting work.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firefighter_statusA
Read-only

The shared machine in a few lines: the human, what runs until when, the queue, budgets, plans, do:. Pass minutes (and gpu) to also price a job without queuing it.

NameRequiredDescriptionDefault
gpuNo...on the GPU
minutesNoPrice a job of this runtime
projectNoYour project (folder name)
vram_gbNo...needing this VRAM

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only annotations, it discloses the important behavior that pricing does not enqueue a job. It also sets expectations for a short, multi-section response, though operational details such as pricing freshness or data scope are not covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences front-load the status purpose and then introduce the optional pricing behavior without procedural filler. The telegraphic phrasing is efficient, but fragments such as "the human" and "do:" sacrifice some readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An agent can make a basic status call or request a non-queuing quote, and the description supplies some output expectations despite the lack of an output schema. However, opaque output terminology, incomplete parameter interactions, and no explicit sibling routing leave notable gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already describes all four parameters, the description adds the useful interaction that minutes, optionally with gpu, enables a pricing mode without submission. It does not similarly explain how project or vram_gb affect the status result or quote.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description identifies two clear functions: a brief overview of the shared machine and an optional job-price estimate. It lists useful status contents and distinguishes pricing from queuing, although cryptic terms such as "the human" and "do:" reduce precision.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for a basic status call and explicitly explains when to supply minutes and gpu for pricing. The phrase "without queuing it" helps distinguish this from submission, but it does not name sibling tools or explain when to prefer firefighter_job or firefighter_plan.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firefighter_submitA
Destructive

Queue heavy work (GPU, or CPU over ~1 min) on this shared machine. Returns one line: job id, start estimate, cost, do: (next step). Then call firefighter_wait. Runs the command as you, outside any agent sandbox, with your network and files: only submit what you'd run in your own shell.

NameRequiredDescriptionDefault
cwdYesAbsolute working directory
gpuNoNeeds the GPU
netNoNetwork-heavy (downloads, uploads); known installers and downloads are detected
nameNo'<project> <what>'
spotNoLeftover time only; 1/3 price, paused first
ram_gbNoPeak RAM GB, if known
urgentNoOnly when the human waits on the result; 2x price
commandYesShell command
minutesYesHigh-end runtime guess; a lease, billed 2x past 1.25x
vram_gbNoPeak VRAM GB, if known
gpu_vendorNoGPUs the job can use: nvidia, amd, intel or any (default NVIDIA if present)

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and openWorldHint=true, and the description adds meaningful context beyond them: the command runs as the user, outside any agent sandbox, with the user's network and files, plus an explicit caution to only submit what you'd run in your own shell. It also discloses the return shape ('one line: job id, start estimate, cost, do: (next step)'), so the agent knows what comes back and what to do next.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the core purpose and threshold, then sequencing, then the safety-critical caveat last. No filler, and each sentence carries distinct information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter destructive job-submission tool with no output schema, the description covers purpose, when to submit, sequencing, execution environment, and the shape of the response. It leaves unstated what happens on failure or how to poll progress outside of firefighter_wait, but the essentials for calling it safely are present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter including cost modifiers (spot, urgent, minutes lease) is already documented in the schema. The description adds no parameter-level meaning beyond that; its remaining content concerns execution environment and return value, not argument semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Queue heavy work') and scopes it precisely with the inclusion threshold ('GPU, or CPU over ~1 min') and the shared-machine context. It is clearly distinguishable from siblings by naming firefighter_wait as the immediate follow-up.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a concrete use condition (heavy work: GPU, or CPU over ~1 min) and an explicit next step ('Then call firefighter_wait'), which routes the agent correctly after submission. It stops short of stating when not to use it (e.g. short CPU work, or when firefighter_plan/status is the better starting point), so it is not fully explicit about alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

firefighter_waitA
Read-only

Wait up to ~45 s on a job. One line, short if nothing changed; receipt and log tail when done.

NameRequiredDescriptionDefault
idYesJob id
timeout_sNoSeconds, max 50

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint/openWorldHint annotations, the description discloses the blocking behavior, the approximate maximum wait, and two distinct return shapes ('one line, short if nothing changed' versus 'receipt and log tail when done'). It stops short of saying what is returned if the timeout elapses without a state change.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact clauses with the wait scope front-loaded and the outcome variants second; there is no filler and every clause conveys information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully sketches the return values, and it covers the timeout dimension. The main remaining gap is the timeout-expiry case, which an agent would need to interpret the 'short if nothing changed' result correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented; the description only reinforces timeout_s with '~45 s', and that figure is slightly at odds with the schema's stated max of 50. Baseline 3 applies since the schema carries the parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Wait ... on a job') plus a rough duration, so an agent knows this blocks until progress or completion. It does not, however, explicitly contrast itself with siblings like firefighter_status or firefighter_job, which also inspect a job.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'Wait up to ~45 s on a job' implies the use case (blocking until a job advances or finishes) versus one-shot polling, but there is no explicit when-to-use/when-not guidance or named alternative among the siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedfirefighter_job
    • First observedfirefighter_plan
    • First observedfirefighter_status
    • First observedfirefighter_submit
    • First observedfirefighter_wait

TDQS

A3.7/5.0

Scored across 5 tools

Disambiguation4/5

Each tool covers a distinct phase of the job lifecycle: submit queues work, wait blocks for completion, status reports the machine, job mutates an existing job, and plan announces future intent. The only mild overlaps are wait vs. status (both surface job state) and status's pricing mode vs. submit, but the descriptions make the boundaries clear enough.

Naming Consistency4/5

All tools share a consistent firefighter_ prefix, giving a predictable namespace. The suffixes mix verbs (submit, wait) with nouns (status, job, plan), so the pattern isn't a pure verb_noun scheme, but it is readable and internally coherent.

Tool Count5/5

Five tools is well-scoped for a shared-machine job queue: submit, wait, inspect, modify, and plan. Each tool maps to a real user need with no filler.

Completeness4/5

The surface covers the full lifecycle: queue, poll, inspect, mutate (extend/tier/cancel), and pre-announce plans. Minor gaps existโ€”no explicit way to list your own jobs or fetch full logs on demand (logs surface only via wait's tail), but agents can work around this with status and repeated waits.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    agent-mq is a message queue that enables AI coding agents to communicate with each other across sessions and machines. Agents can send messages, delegate tasks, and coordinate work โ€” all through MCP tools. Supports Claude Code, Cursor, Codex, OpenClaw, and any MCP-compatible tool. UUID-based authentication with per-user data isolation. Self-hostable with Docker.
    7
    2
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A local MCP server that connects AI coding agents (Claude Code, Codex, Cursor, etc.) on the same machine via a shared message bus, enabling them to chat, delegate tasks, and collaborate privately without cloud or internet.
    73 npm
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables AI agents to delegate scoped tasks across multiple providers like Codex, Claude Code, and Antigravity through a single local MCP server, with quota monitoring, notifications, and remote control via messaging apps.
    13
    2
    Apache 2.0