Skip to main content
Glama

jobd

CI PyPI Python Glama GHCR License: MIT DOI

A self-hostable, GPU-aware job broker for your own machines — with native MCP/agent integration.

Like task-spooler or pueue, but across all your machines — and VRAM-aware.

You have a couple of boxes with GPUs — a workstation, a server, maybe a laptop — wired together over Tailscale or a LAN. You want to fire off training runs, data pipelines, and long batch jobs from anywhere, have them land on whichever machine actually has the VRAM free, survive across sessions, and get preempted cleanly when something more important shows up. You don't have a cloud, a Kubernetes cluster, or a Slurm install, and you don't want one.

jobd is that missing piece: a small broker that turns a handful of personal machines into a single queue — and an LLM agent can drive it directly.

# from any machine on your tailnet:
job submit --project myproj --gpu --vram-required 16 --wait -- python train.py
# → routed to whichever worker has ≥16 GB VRAM free, streamed back to your terminal

Why it exists

Most schedulers assume a datacenter. The lightweight ones that don't (a bare nohup, a tmux session, an ssh-and-pray script) give you nothing: no queue, no VRAM-aware routing, no preemption, no record of what ran where. jobd fills the gap between "ssh in and run it" and "stand up Slurm":

  • VRAM-fit routing. The broker matches each job against live worker capacity (free VRAM / RAM / CPUs, capability tags, arch/OS) and dispatches to a worker that actually fits — instead of you guessing which box is free.

  • Preempt + checkpoint. A higher-priority job can preempt a running one: the worker sends SIGTERM, the workload gets a grace window to checkpoint, then SIGKILL. A preempted job reaches a terminal preempted state with a durable checkpoint to resume from — it isn't silently re-run. (See docs/preemption.md.)

  • Survives sessions. Submit, close your laptop, check back tomorrow. Jobs live in the broker, not your shell.

  • Agent-native. Ships a first-class MCP server so an LLM agent (Claude Code, etc.) can submit, monitor, and babysit jobs as tool calls — the thing most schedulers bolt on as an afterthought, if at all.

  • Yours. One broker process you run on a machine you own. No accounts, no egress, no per-GPU-hour billing. Tailnet-bound by default.

Related MCP server: jungle-grid-mcp-server

Why not just use…?

Tool

What it gives you

Why jobd instead

nohup / tmux / ssh-and-pray

Runs a command on one box

No queue, no VRAM-aware routing, no preemption, no record of what ran where

task-spooler

A real job queue — on a single machine

jobd queues across all your machines and routes by live VRAM/CPU fit

Pueue

The best single-machine command queue daemon

Pueue's own README declares distributed execution out of scope — jobd is that missing layer, plus GPU awareness

HyperQueue

Multi-machine task scheduling with HPC roots, single binary

HQ counts GPUs but doesn't track VRAM, and has no preemption/checkpoint contract or agent interface

Slurm

Datacenter-grade scheduling

Heavy to stand up and operate for 2–3 personal boxes; jobd is one process + a poller per host

SkyPilot / Modal / dstack

Provision and run on clouds + your own machines

SkyPilot's "existing machines" mode installs a k3s cluster on your boxes; dstack wants Docker + passwordless sudo on every host. jobd is one process + a poller — no containers, no sudo, no K8s

Ray

A distributed-compute framework

jobd is a job queue, not a programming model — submit any command, no code changes, GPU-fit routing built in

Closest in spirit are Pueue and task-spooler (single-machine by design) and HyperQueue (multi-machine, HPC-shaped). jobd's niche is the 2–5-GPU homelab: multi-machine live VRAM-fit routing + preempt/checkpoint + a native MCP interface — a combination none of the above offers — with nothing heavier than a Python process per host.

Architecture

flowchart TD
    CLI["job CLI"]:::client --> B
    MCP["jobd-mcp<br/>MCP tools"]:::client --> B
    API["HTTP · SSE"]:::client --> B
    B["<b>jobd broker</b> — FastAPI<br/>queue · matcher · priorities · SQLite"]:::broker
    B <-->|poll · dispatch| WA["worker A<br/>24 GB GPU"]:::worker
    B <-->|poll · dispatch| WB["worker B<br/>8 GB GPU"]:::worker
    B <-->|poll · dispatch| WC["worker C<br/>CPU-only"]:::worker
    classDef client fill:#1f2937,stroke:#4b5563,color:#e5e7eb;
    classDef broker fill:#0e7490,stroke:#155e75,color:#ecfeff;
    classDef worker fill:#14532d,stroke:#166534,color:#dcfce7;

Workers poll the broker (pull model — no inbound connection to a worker); the broker matches each job against live capacity and hands it back on the poll. One broker process, one poller per host.

  • Broker — a FastAPI + SQLite service. Holds the queue, runs the matcher, resolves per-project priorities and defaults, exposes a small HTTP API and an SSE stream. Single source of truth.

  • Workers — lightweight polling agents, one per host. Each advertises live capacity via heartbeat, claims jobs it can run, executes them (shell=False, no shell-injection surface), streams logs back, and honors preemption signals.

  • Clients — the job CLI, the jobd-mcp MCP server, or anything that speaks the HTTP API.

Install

pip install jobd               # broker + CLI
pip install "jobd[mcp]"        # adds the MCP server
pip install "jobd[worker]"     # adds the worker daemon (jobd-worker)

Requires Python ≥ 3.11. Everything ships in the one jobd package: the broker (jobd), the CLI (job), the MCP server (jobd-mcp), and the worker (jobd-worker). The worker's runtime deps (httpx, psutil, pyyaml, nvidia-ml-py) live behind the [worker] extra since they're only needed on machines that actually run jobs. scripts/install-worker.sh sets a worker up under ~/jobd-worker with its own venv and a generated config.

Quickstart (single host)

# 1. start the broker (binds 127.0.0.1:8765 by default)
JOBD_ALLOW_NO_AUTH=1 jobd          # no-auth is fine for a loopback-only broker

# 2. in another shell, install + start a worker pointed at it
pip install "jobd[worker]"
JOBD_URL=http://127.0.0.1:8765 JOBD_WORKER_HOST=local jobd-worker

# 3. submit a job and wait for it
job submit --project demo --wait -- echo hello
job list
job logs <id>

For a real multi-host deployment (Docker broker + systemd workers, Tailscale binding, shared auth token), see docs/security.md and the templates in docker-compose.yml and scripts/. Adding a worker to a running fleet is one command:

job fleet add user@newbox      # ssh in, install pinned to the broker's version,
                               # wire systemd units + the self-update timer,
                               # verify it registers. `job fleet status` shows drift.

Day-2 operations (health, draining a worker, upgrades, token rotation, backups) are in docs/runbook.md.

Supported platforms

Python 3.11+ everywhere.

Component

Linux

macOS

Windows

Broker (jobd)

☑️

☑️ (WSL recommended)

CLI (job) / MCP (jobd-mcp)

☑️

☑️

Worker (jobd-worker)

✅ full

⚠️ degraded

⚠️ degraded

✅ = CI-tested (the test matrix runs on Linux). ☑️ = pure-Python and expected to work, but not exercised by CI — please file an issue if something is broken there.

The worker runs its best on Linux with a systemd user instance: memory caps, process reaping, and preemption use systemd-run --user scopes and cgroups. On non-systemd hosts the worker still executes jobs, but silently drops those guarantees — fine for a single trusted box, not for hard resource isolation. GPU features need NVIDIA + nvidia-ml-py. The broker, CLI, and MCP server are pure-Python and portable.

CLI

job submit -p PROJ [--gpu] [--vram-required N] [--needs TAG]... [--count N | --sweep K=v1,v2]... [--wait] -- CMD...
job list [--state STATE] [--project P] [--array A<id>]   # queue + recent jobs
job status ID | A<id> [--watch]             # one job, or an array's aggregate
job logs ID [-n BYTES]                      # tail captured output
job wait ID                                 # block until terminal
job cancel ID  /  job preempt ID            # stop a job
job workers                                 # fleet snapshot + health
job projects list | set NAME PRI | nudge NAME DELTA
job audit [--project P] [--since 24h]       # event history

job submit --explain dry-runs the resolution (priority, profile, project defaults, host pin) and prints the effective config without enqueuing anything.

Job arrays

Submit N jobs from one template with --count N. Each member is a normal job — it routes, runs, preempts, and checkpoints independently — and {i} in the command is replaced by the member's 0-based index:

job submit -p train --count 8 -- python train.py --fold {i}
# → Submitted array A42: 8 jobs (ids 42..49)

job list --array A42         # the members, with their index annotations
job status A42               # aggregate: state tally + per-member rollup

The array is identified as A<id> (the first member's job id). job status A42 exits non-zero if any member ended in a non-completed terminal state, so it composes with shell &&.

For a grid search, use --sweep KEY=v1,v2,v3 (repeatable) instead of --count. The broker fans out the cartesian product of all axes, substituting {KEY} per member; {i} (the flat member index) is also available:

job submit -p train --sweep lr=0.1,0.01 --sweep seed=1,2,3 \
  -- python train.py --lr {lr} --seed {seed} --out run-{i}
# → Submitted array A50: 6 jobs (ids 50..55)   # 2 × 3 = 6 members

--sweep and --count are mutually exclusive, the product is capped at 1000 members, and i is reserved as an axis key. Substitution is a literal {key} replace (not str.format), so JSON literals and shell braces in the command pass through untouched.

Coming from pueue or task-spooler?

The verbs map directly — what changes is that the queue spans every machine you own:

You ran…

With jobd

tsp <cmd> / pueue add -- <cmd>

job submit -p <project> -- <cmd>

tsp -w / pueue follow <id>

job logs -f <id> (or job wait <id>) — streams, exits with the job's own exit code

tsp / pueue status

job list

pueue log <id>

job logs <id>

commands piped to simple_gpu_scheduler

... | job submit -p <project> --stdin — one job per line, fleet-wide

pueue kill <id>

job cancel <id>

pueue group / parallelism limits

projects + priorities (projects.yaml); per-worker slots via JOBD_WORKER_MAX_CONCURRENT_JOBS

What you gain on top: jobs route to whichever machine actually has the VRAM/CPU free, survive any single box rebooting, can be preempted with a checkpoint window instead of killed, and are drivable by an LLM agent over MCP. What you lose: nothing — a one-machine deployment (broker + one worker on the same host) behaves like a network-reachable pueue.

MCP / agent integration

jobd ships an MCP server (jobd-mcp) exposing the queue as nine tools — jobd_submit, jobd_status, jobd_logs, jobd_list, jobd_cancel, jobd_preempt, jobd_events, jobd_workers, jobd_worker_delete. docs/agent-cookbook.md is the worked tour: fire-and-babysit polling, surviving preemption with checkpoints, sweeps, and asking the broker why a job won't schedule.

One-liner for Claude Code:

claude mcp add jobd --env JOBD_URL=http://127.0.0.1:8765 --env JOBD_API_TOKEN=<your-token> -- jobd-mcp

Or point any other MCP client at it:

{
  "mcpServers": {
    "jobd": {
      "command": "jobd-mcp",
      "env": {
        "JOBD_URL": "http://127.0.0.1:8765",
        "JOBD_API_TOKEN": "<your-token>"
      }
    }
  }
}

JOBD_API_TOKEN must match the broker's token, or every call returns 401. Omit it only when the broker runs with JOBD_ALLOW_NO_AUTH=1.

Now an agent can "run this overnight," check on it next session, and route GPU work through the broker instead of colliding on a shared card. The examples/claude-code-hooks/ directory has optional Claude Code hooks that nudge (or hard-block) an agent toward submitting heavy commands through jobd — including a VRAM-aware GPU guard with # NO_GPU / # CONCURRENT_OK / # VRAM=NGB override markers.

Configuration

Three optional YAML files under JOBD_CONFIG_DIR (defaults shipped in config/):

  • projects.yaml — per-project base priority and submit defaults (preemptibility, wall/idle timeouts, host pins, capability requirements). Entries may also declare roots: so a job typed with an unregistered run label is priced by the project whose directory it runs in. See docs/projects-yaml.md for the full resolution model and docs/events.md for the event catalog.

  • profiles.yaml — named resource bundles (--profile gpu-train-large) the matcher uses to size a job.

  • classifier.yaml — rules that auto-suggest a profile from the command string.

All three are optional; with none present, every job runs at the global default priority.

Everything else is environment variables — the complete JOBD_* catalog (broker, worker, CLI/MCP, and the vars provided to workloads) lives in docs/configuration.md, and a CI test keeps it in lockstep with the source in both directions.

Concurrency (multislotting)

By default each worker runs one job at a time (JOBD_WORKER_MAX_CONCURRENT_JOBS=1). Raise it to let a worker bin-pack several jobs that fit side by side:

JOBD_WORKER_MAX_CONCURRENT_JOBS=3 jobd-worker

The matcher is resource-aware, so this is not blind N-up oversubscription. Each in-flight job reserves its vram_gb / ram_gb / cpus footprint, and the worker's heartbeat advertises only what's left (free_vram = raw − Σ in-flight). The broker won't place a job that doesn't fit the remaining headroom. The practical payoff: a CPU-only job and a GPU job run at the same time — the CPU job reserves 0 VRAM, so it never blocks the GPU slot, and vice-versa. Two GPU jobs co-run only if both fit live VRAM (the /next-job admission gate is the final safety net against an overstated ad).

job workers reports each worker's slot usage — running jobs out of max_concurrent — alongside the live resource ad:

// job workers
{ "host": "desktop", "state": "online", "running": 2, "max_concurrent": 3,
  "free_vram_gb": 9.1, "idle_cpus": 6, ... }

Set the limit per worker from its environment (systemd unit, shell, or worker.yaml env) — it's a worker-local knob, not a broker setting.

Retention

By default jobd keeps every job record and .log file forever — history is never lost. On a long-running broker, opt into pruning:

JOBD_JOB_RETENTION_DAYS=30 jobd   # delete terminal jobs + their logs after 30 days

The sweeper deletes jobs in a terminal state whose finished_at is older than the horizon, unlinks their per-job .log, and emits a jobs_pruned event. Freed SQLite pages are reused under WAL, so the DB file stays bounded without a global-locking VACUUM. The default (0) keeps everything; pruning old terminal parents is safe for any still-pending dependents.

Security

The broker has no TCP-layer auth beyond a shared bearer token, so it is meant to run on a trusted network (loopback or a Tailscale tailnet), never on a public interface. Two stacked controls:

  1. Interface bindingJOBD_HOST must be 127.0.0.1 or a Tailscale CGNAT address (100.64.0.0/10), never 0.0.0.0. A CI lint (tests/test_deploy_lint.py) enforces this on the Docker deployment.

  2. Bearer token — set JOBD_API_TOKEN (≥32 random bytes) on every broker/worker/CLI/MCP host. The broker refuses to start without it unless you explicitly set JOBD_ALLOW_NO_AUTH=1. JOBD_ALLOW_NO_AUTH=1 is for a loopback-only broker (JOBD_HOST=127.0.0.1) — for local dev/tests. Combined with a non-loopback JOBD_HOST it exposes an unauthenticated RCE endpoint to your whole tailnet; the broker logs a startup warning if you do this. Don't.

Three endpoints are exempt from both controls/livez, /readyz and /metrics answer with no bearer token and no source-IP check, because a generic HTTP monitor cannot send a token. /metrics is the one that matters: it publishes the broker version, job counts by state, and every worker's hostname and version. No commands, cwd, env or project names — but it does fingerprint the fleet. That is why the JOBD_HOST bind above is load-bearing rather than defence-in-depth: port-forward the broker and you publish that inventory. Full table: Unauthenticated surface.

Full threat model, env-var reference, and token rotation: docs/security.md.

License

MIT — see LICENSE.

Available Tools

9 tools
jobd_cancelA

Cancel a job (queued → cancelled; running → SIGTERM via worker signal poll, ~2s).

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYes
reasonNo

TDQS

A3.8/5.0
Behavior4/5

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

Discloses state transitions and mechanism (SIGTERM via worker signal poll) with approximate delay (~2s). Lacks details on idempotency, permissions, or side effects, but is informative for a cancel action.

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?

Single sentence, front-loaded with essential information, no waste. Efficient and to the point.

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?

Tool is simple with two parameters and no output schema. Description covers behavior well but omits parameter semantics, leaving a gap in completeness.

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

Parameters2/5

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

Schema coverage is 0% and description provides no parameter details. Agent must infer job_id and reason without any format or constraint information.

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?

Description clearly states verb 'Cancel a job' and resource 'job', and specifies behavior for different states (queued vs running) with mechanism (SIGTERM). Distinguishes from siblings like jobd_preempt or jobd_status.

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?

No explicit when-to-use or when-not-to-use guidance. Implies cancellation but does not differentiate from jobd_preempt or mention when to use one over the other.

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

jobd_eventsA

The broker's event stream — the surface that explains WHY, not just what. /jobs says a job is queued; only this says it has been skipped 400 times because no worker advertises cuda-32gb, or that its dependency was cancelled, or that a watchdog killed it. Filter by since (2h/3d/1w), event type, job_id, project, or source (broker|worker). Use when a job is not doing what you expect and jobd_status alone does not explain it.

ParametersJSON Schema
NameRequiredDescriptionDefault
eventNoFilter to one event type. Known types: admission_blocked, auto_preempt, checkpoint_complete, cwd_identity_applied, cwd_refused, cwd_route_warning, dispatch_skip, env_scrubbed, gpu_contention_warning, job_cancelled, job_completed, job_dispatched, job_orphaned, job_resurrected, job_started, job_submitted, job_uncancelled, jobs_pruned, logs_pruned, preflight_warning, reclaim_suppressed, scheduling_timeout, serialization_warning, stale_scope_sweep, submit_warning, sweep_warning, unknown_project, version_drift, watchdog_fired, worker_offline, worker_registered, worker_shutdown, worker_stale. Hook-ingested events may carry custom names beyond these.
limitNoMax rows, newest-last. Broker clamps to 10000.
sinceNoRelative window (2h, 3d, 1w) or an ISO-8601 timestamp. Default: all retained.
job_idNoOnly events for this job.
sourceNoWhich side emitted the event.
projectNoOnly events for this project.

TDQS

A4.4/5.0
Behavior4/5

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

With no annotations, the description carries the burden, and it does well by explaining the nature of the stream: events capture diagnostics like repeated dispatch skips, cancelled dependencies, and watchdog kills. The 'event stream' and 'Filter by' language strongly imply a read-only query, though it never explicitly states read-only or describes the return shape.

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?

The description is compact and front-loaded with the most valuable context first: what this stream uniquely explains. The concrete examples earn their place, and the final sentence gives unambiguous routing guidance without redundancy.

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?

Given no output schema and no annotations, this is a strong diagnostic description: it explains when to use the tool, what kind of information it exposes, and which filters are available. It is not perfect because it does not describe the returned event structure or mention the hook/mcp source values, but it is sufficient for an agent to invoke it 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 description coverage is 100%, so the baseline is 3. The description reinforces the main filters and the since shorthand, but adds little beyond the schema. It even slightly under-specifies source by listing only broker|worker while the schema enum also includes hook and mcp.

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 identifies the resource as 'the broker's event stream' and frames the operation as a filterable diagnostic surface, not just a listing. It explicitly distinguishes itself from /jobs and jobd_status by explaining that it provides the WHY behind job behavior, so an agent can select it over siblings.

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

Usage Guidelines5/5

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

It gives an explicit use condition: 'Use when a job is not doing what you expect and jobd_status alone does not explain it.' It also names the alternative tooling (/jobs, jobd_status) and contrasts their limited explanatory power with this event stream.

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

jobd_listA

List jobs on the broker with per-state counts. Defaults to the active set (queued/assigned/running); filter by state (e.g. ['failed']) or project to find past runs. Each row is a compact summary: job_id, project, state, host, exit_code, queued_at, started_at — call jobd_status for a job's full record. Use to answer 'what is running / queued right now?' or to locate a job id you've lost.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax jobs returned (newest first; clamped to [1,200]). `counts` still covers every job matching the filters; a `truncated` field reports how many were cut.
stateNoStates to include — any of: queued, assigned, running, completed, failed, cancelled, preempted, orphaned, scheduling_timeout. Omit for the active set (queued/assigned/running); pass [] for all states.
projectNoRestrict to one project's jobs (the --project value used at submit).

TDQS

A4.7/5.0
Behavior4/5

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

Discloses default behavior, filtering, row fields, limit clamping, and truncated field. Without annotations, it covers read-only nature and pagination, but lacks mention of authentication or rate limits.

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 sentences, front-loaded with purpose, no redundancy. Every sentence adds value: purpose, filtering options, row contents, and guidance to sibling tool.

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?

Explains row fields and counts, mentions truncated field. No output schema, but adequately describes return structure. Missing explicit sort order (newest first only in schema description), but overall sufficient.

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

Parameters5/5

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

Adds significant meaning beyond schema: explains default state set, provides example filter values, clarifies limit behavior with truncated reporting, and describes project restriction context.

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 clearly states it lists jobs with per-state counts, uses specific verb 'List', and explicitly distinguishes from sibling tool jobd_status for full records.

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

Usage Guidelines5/5

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

Provides explicit use cases: 'what is running / queued right now?' and locating job IDs. States defaults and filtering options, and directs to jobd_status for full details, effectively guiding when to use alternatives.

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

jobd_logsA

Tail the captured stdout/stderr of a job (workers stream output to the broker's per-job log as it runs). Returns log_tail (last tail_bytes, default 8 KiB, max 1 MiB) plus size_bytes/returned_bytes/truncated — works for running AND finished jobs. Use to check progress mid-run, diagnose a failure's traceback, or grab a job's final output.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYesNumeric job id whose captured output to read.
tail_bytesNoHow many bytes from the END of the log to return (server caps reads at 1 MiB). Raise for context, lower for a quick liveness peek.

TDQS

A4.3/5.0
Behavior4/5

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

Discloses that it returns log_tail with configurable tail_bytes (default 8 KiB, max 1 MiB) plus metadata fields, and works for both running and finished jobs. No annotations exist, so the description carries full burden and does so well.

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 sentences, first contains main action and context, second details use cases. Efficient with no wasted words, though the second sentence is slightly dense.

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?

Despite no output schema, the description enumerates return fields (log_tail, size_bytes, returned_bytes, truncated). Covers behavior for running/finished jobs and mentions tail size limits. Sufficiently complete for a log-reading tool.

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. Description adds semantic guidance: for job_id, it specifies 'numeric'; for tail_bytes, it explains purpose and provides usage advice ('Raise for context, lower for a quick liveness peek').

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 clearly states it tails captured stdout/stderr of a job, specifying that it works for running and finished jobs. It distinguishes itself from sibling tools (submit, status, cancel) by being solely for reading logs.

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?

Explicitly lists use cases: check progress mid-run, diagnose failure traceback, grab final output. No explicit when-not-to-use or alternatives, but siblings are unrelated, so the guidance is clear enough.

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

jobd_preemptA

Preempt a running/assigned preemptible job (worker SIGTERMs with grace; final state 'preempted'). Refused if not preemptible or not running.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYes

TDQS

A4.5/5.0
Behavior5/5

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

With no annotations, the description fully discloses the key behavioral traits: sending SIGTERM with grace period, resulting state 'preempted', and conditions for refusal. This covers the core safety and mutability aspects.

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 concise sentences that front-load the action and immediate behavior, with no redundant information. Every word adds value.

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

Completeness5/5

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

For a simple tool with one parameter and no output schema, the description provides complete contextual information: what it does, how it behaves, and when it is not applicable. It is sufficient for correct agent decision-making.

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?

The only parameter (job_id) is not explicitly described in the text, but its purpose is implicitly clear from the tool's action. Schema coverage is 0%, but the description does not add explicit parameter details; baseline 3 is appropriate.

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 clearly states the action (preempt), the target (running/assigned preemptible job), and the specific behavior (SIGTERM with grace, final state 'preempted'). It distinguishes from siblings like jobd_cancel by specifying the preemptible job constraint.

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?

Explicitly states when the tool is refused ('if not preemptible or not running'), providing clear usage context. However, it does not compare to alternatives (e.g., when to use jobd_cancel instead).

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

jobd_statusA

The full JobInfo record for one job_id: state, exit_code, timings, host, and the scheduling internals — depends_on + cascade policy (depends_on_any_exit), pending cancel/preempt signal, resolved profile, requires (gpu/tags/idempotent), host pin, fast_path, timeouts, termination_reason. Use for a quick state check AND for debugging why a job routed/failed/stalled. Pass wait=true to block until terminal or wait_timeout_s.

ParametersJSON Schema
NameRequiredDescriptionDefault
waitNo
job_idYes
wait_timeout_sNoServer clamps to 270.

TDQS

A4.1/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full burden. It discloses that wait=true blocks until terminal and that the timeout is server-clamped to 270s. However, it does not mention error handling, authentication needs, or whether the operation is read-only (implied but not explicit).

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?

The description is a single paragraph that front-loads the record contents, then provides usage guidance, then wait behavior. It is reasonably concise with no wasted words, though it could be slightly tighter.

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?

Given the tool has 3 parameters and no output schema, the description adequately covers the purpose, parameter behaviors, and usage context. It does not describe return format but lists the fields included in the record, which suffices.

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 only 33% (only wait_timeout_s has a schema description). The description adds meaning by explaining the wait parameter (block until terminal) and that wait_timeout_s is clamped to 270. job_id is straightforward but not elaborated. Thus, the description adds significant value beyond the sparse schema.

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 clearly states it returns the full JobInfo record for a job_id and lists specific fields (state, exit_code, timings, host, scheduling internals). It distinguishes itself from sibling tools like jobd_submit, jobd_logs, and jobd_cancel by focusing on status and debugging.

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?

The description explicitly says 'Use for a quick state check AND for debugging why a job routed/failed/stalled.' It also mentions optional wait behavior. However, it does not explicitly state when not to use this tool (e.g., preferring jobd_logs for logs), but the context is clear.

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

jobd_submitA

Submit a job to the jobd broker. Default async; pass wait=true to block up to wait_timeout_s (server clamps to 270).

ParametersJSON Schema
NameRequiredDescriptionDefault
cwdYesAbsolute path; broker validates against worker mount_roots.
gpuNoPin to GPU-capable worker.
hostNoHost alias pin (laptop, desktop-vm).
waitNoSync mode: block until terminal or timeout. For an array submit (count/sweep), waits on every member under one shared deadline and returns an aggregate {array_id, count, job_ids, states, all_completed, members:[{job_id, state, exit_code}]}.
extraNoEscape hatch: idempotent (bool), depends_on (int[]), depends_on_any_exit (bool), priority (int delta), max_wall_s (int), idle_timeout_s (int), scheduling_timeout_s (int 1..604800 — give up and terminate the job as 'scheduling_timeout' if it is still QUEUED after N seconds; omit to wait indefinitely for a capable worker), checkpoint_grace_s (int 1..300), vram_gb (float — explicit GPU VRAM the job needs at dispatch; falls back to cuda-Ngb tier-tag max, then to 2 GB floor for --gpu jobs), count (int 1..1000 — submit a job array of N members, with `{i}` in the command replaced by the 0-based index; response is {array_id, count, job_ids, warnings} instead of a single job), sweep (list of {key, values[]} — parameter-sweep axes; broker fans out the cartesian product, substituting `{key}` per member plus `{i}`; mutually exclusive with count; product capped at 1000), profile (str), env (dict), preemptible (bool), session_id (str), arch (str — pin to a worker CPU arch), os (str — pin to a worker OS).
needsNoTool tags (R, python3, cuda).
commandYesShell command run by the worker shell.
dry_runNoPreview mode: run full validation + routing decision (profile, project defaults, cwd, depends_on, preflight, gpu_contention) and return the would-be plan WITHOUT queueing. Response has state='dry-run', would_route_to (list[host]), would_use_worker (host or null), validation (resolved fields + warnings). Per dry-run convention 2026-05-18.
projectYesScheduling identity. A registered projects.yaml name (matched case- and -/_-insensitively) prices at its priority; an unregistered name is priced by the project whose roots: contain cwd, else by _default. The result's project_label carries the name as typed when the two differ.
wait_timeout_sNoSeconds; permissive — server clamps to 270.

TDQS

A4.4/5.0
Behavior4/5

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

No annotations are provided, so the description carries the burden. It discloses important behavioral details: default async, wait blocking until timeout, server clamping to 270, array/sweep fan-out, dry_run preview behavior, and scheduling_timeout termination semantics. It does not cover all side effects (e.g., what happens on cancellation or resource cleanup), but for a submission tool this is strong behavioral disclosure.

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?

The core description is a tight two-sentence opener that states the default and the wait behavior. The parameter descriptions are long, especially extra, but they are dense with necessary detail for a complex submission API. Some redundancy exists (wait_timeout_s appears in the description and the schema), but the upfront structure is effective.

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

Completeness5/5

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

Despite having no output schema and no annotations, the description covers the key behaviors an agent needs: async/sync modes, clause, dry-run, array/sweep aggregates, and the escape-hatch semantics. For a 10-parameter tool with nested object and array options, this is unusually complete. The only missing piece is the single-job response shape, but the description covers enough to call it correctly.

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 description coverage is 100%, so baseline is 3. The description adds meaningful behavior beyond the schema: wait=true is explained as sync mode with an aggregate response shape, dry_run details are expanded to mention full validation and routing decision, and the extra object is contextualized as an escape hatch with specific key meanings. It still defers most parameter detail to the schema, but the added context is valuable, especially for wait, dry_run, and extra.

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 starts with a clear verb+resource ('Submit a job to the jobd broker'), immediately distinguishing it from sibling tools like jobd_cancel, jobd_logs, or jobd_status. It also states the default behavior (async) and the wait option, so an agent knows both what the tool does and its primary mode distinction.

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?

The description explains when to use wait=true and mentions the server clamp, giving concrete usage context. It does not explicitly name sibling alternatives or state when not to use this tool, but the operation is so central to the sibling set that the default guidance is sufficient. The array and sweep options also add clear usage context for advanced submissions.

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

jobd_worker_deleteA

Remove a worker from the broker registry. The broker refuses (409) if the worker is still online — caller stops the worker process or waits for the heartbeat sweeper first.

ParametersJSON Schema
NameRequiredDescriptionDefault
hostYesWorker host identifier.

TDQS

A4.2/5.0
Behavior4/5

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

Without annotations, the description fully covers behavioral traits: it states the action is destructive, documents the 409 conflict condition, and explains the reason. Missing details about success response or side effects, but sufficient for a simple tool.

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 sentences: first states the action, second explains a critical caveat and remediation. No wasted words, effectively structured.

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 a simple one-parameter tool with no output schema, the description covers purpose, failure mode, and user action. It lacks details on success response or authentication, but overall adequate.

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% with the host parameter described as 'Worker host identifier.' The description does not add further semantic value beyond the schema, meeting the baseline expectation.

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 clearly states 'Remove a worker from the broker registry' with a specific verb and resource. It distinguishes itself from sibling tools like jobd_workers (which likely lists workers) by focusing on deletion.

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?

The description explains that deletion fails with 409 if the worker is online and advises either stopping the worker process or waiting for the heartbeat sweeper. This provides clear usage context, though it does not explicitly compare with other tools.

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

jobd_workersA

Fleet snapshot: every registered worker with state (online/stale/offline), live capacity ad (free_vram_gb, unregistered_vram_gb, free_ram_gb, idle_cpus), capability tags (cuda tiers, arch/os), slot usage (running/max_concurrent), and last_heartbeat — plus an overall health rollup (healthy|degraded|empty). Use before submitting GPU work to see what's free, or to diagnose why a job isn't being dispatched.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

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

No annotations exist, so the description carries full burden. It describes the tool as a read-only snapshot with state, capacity, and health rollup, implying no side effects. It could mention data freshness or limitations, but the description is otherwise transparent about the output.

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?

The description is a single, information-dense sentence with clear front-loading of the core purpose. Every phrase adds value, and there is no redundant or vague wording.

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

Completeness5/5

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

Given no parameters and no output schema, the description thoroughly covers what the tool returns and when to use it. It is complete and actionable for an agent deciding whether to invoke this tool.

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

Parameters5/5

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

The input schema has no parameters, and schema coverage is trivially 100%. The description adds immense value by detailing the output fields and structure, effectively compensating for the lack of an output schema.

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 explicitly states 'Fleet snapshot: every registered worker...' and ends with 'Use before submitting GPU work to see what's free, or to diagnose why a job isn't being dispatched.' This gives a specific verb+resource and clear differentiation from sibling tools like jobd_submit or jobd_list.

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?

The description provides explicit usage context: 'Use before submitting GPU work... or to diagnose why a job isn't being dispatched.' It does not mention when not to use or alternatives, but the guidance is clear and actionable for the primary use case.

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. 2 tool updatesv0.5.44
    • Changedjobd_events1 field changed
      • changedInput schema / properties / event / description
        Previous value: -"Filter to one event type. Known types: admission_blocked, auto_preempt, checkpoint_complete, cwd_refused, dispatch_skip, env_scrubbed, job_cancelled, job_completed, job_dispatched, job_orphaned, job_resurrected, job_started, job_submitted, job_uncancelled, jobs_pruned, logs_pruned, reclaim_suppressed, scheduling_timeout, stale_scope_sweep, submit_warning, sweep_warning, version_drift, watchdog_fired, worker_offline, worker_registered, worker_shutdown, worker_stale. Hook-ingested events may carry custom names beyond these."New value: +"Filter to one event type. Known types: admission_blocked, auto_preempt, checkpoint_complete, cwd_identity_applied, cwd_refused, cwd_route_warning, dispatch_skip, env_scrubbed, gpu_contention_warning, job_cancelled, job_completed, job_dispatched, job_orphaned, job_resurrected, job_started, job_submitted, job_uncancelled, jobs_pruned, logs_pruned, preflight_warning, reclaim_suppressed, scheduling_timeout, serialization_warning, stale_scope_sweep, submit_warning, sweep_warning, unknown_project, version_drift, watchdog_fired, worker_offline, worker_registered, worker_shutdown, worker_stale. Hook-ingested events may carry custom names beyond these."
    • Changedjobd_submit1 field changed
      • changedInput schema / properties / project / description
        Previous value: -"Priority lookup key; falls back to _default."New value: +"Scheduling identity. A registered projects.yaml name (matched case- and -/_-insensitively) prices at its priority; an unregistered name is priced by the project whose roots: contain cwd, else by _default. The result's project_label carries the name as typed when the two differ."
  2. 5 tool updatesv0.5.36
    • Addedjobd_events
    • Addedjobd_list
    • Addedjobd_preempt
    • Addedjobd_worker_delete
    • Addedjobd_workers
  3. 6 tool updatesv0.5.35
    • Removedjobd_list
    • Addedjobd_logs
    • Removedjobd_preempt
    • Addedjobd_status
    • Addedjobd_submit
    • Removedjobd_worker_delete
  4. 5 tool updatesv0.5.34
    • Removedjobd_events
    • Removedjobd_logs
    • Removedjobd_status
    • Removedjobd_submit
    • Removedjobd_workers
  5. 1 tool updatev0.5.31
    • Changedjobd_events1 field changed
      • changedInput schema / properties / event / description
        Previous value: -"Filter to one event type. Known types: admission_blocked, auto_preempt, checkpoint_complete, cwd_refused, dispatch_skip, job_cancelled, job_completed, job_dispatched, job_orphaned, job_resurrected, job_started, job_submitted, job_uncancelled, jobs_pruned, logs_pruned, scheduling_timeout, stale_scope_sweep, submit_warning, sweep_warning, watchdog_fired, worker_offline, worker_registered, worker_shutdown, worker_stale. Hook-ingested events may carry custom names beyond these."New value: +"Filter to one event type. Known types: admission_blocked, auto_preempt, checkpoint_complete, cwd_refused, dispatch_skip, env_scrubbed, job_cancelled, job_completed, job_dispatched, job_orphaned, job_resurrected, job_started, job_submitted, job_uncancelled, jobs_pruned, logs_pruned, scheduling_timeout, stale_scope_sweep, submit_warning, sweep_warning, version_drift, watchdog_fired, worker_offline, worker_registered, worker_shutdown, worker_stale. Hook-ingested events may carry custom names beyond these."
  6. 3 tool updatesv0.5.26
    • Addedjobd_events
    • Removedjobd_job_get
    • Changedjobd_submit1 field changed
      • changedInput schema / properties / extra / description
        Previous value: -"Escape hatch: idempotent (bool), depends_on (int[]), depends_on_any_exit (bool), priority (int delta), max_wall_s (int), idle_timeout_s (int), checkpoint_grace_s (int 1..300), vram_gb (float — explicit GPU VRAM the job needs at dispatch; falls back to cuda-Ngb tier-tag max, then to 2 GB floor for --gpu jobs), count (int 1..1000 — submit a job array of N members, with `{i}` in the command replaced by the 0-based index; response is {array_id, count, job_ids, warnings} instead of a single job), sweep (list of {key, values[]} — parameter-sweep axes; broker fans out the cartesian product, substituting `{key}` per member plus `{i}`; mutually exclusive with count; product capped at 1000), profile (str), env (dict), preemptible (bool)."New value: +"Escape hatch: idempotent (bool), depends_on (int[]), depends_on_any_exit (bool), priority (int delta), max_wall_s (int), idle_timeout_s (int), scheduling_timeout_s (int 1..604800 — give up and terminate the job as 'scheduling_timeout' if it is still QUEUED after N seconds; omit to wait indefinitely for a capable worker), checkpoint_grace_s (int 1..300), vram_gb (float — explicit GPU VRAM the job needs at dispatch; falls back to cuda-Ngb tier-tag max, then to 2 GB floor for --gpu jobs), count (int 1..1000 — submit a job array of N members, with `{i}` in the command replaced by the 0-based index; response is {array_id, count, job_ids, warnings} instead of a single job), sweep (list of {key, values[]} — parameter-sweep axes; broker fans out the cartesian product, substituting `{key}` per member plus `{i}`; mutually exclusive with count; product capped at 1000), profile (str), env (dict), preemptible (bool), session_id (str), arch (str — pin to a worker CPU arch), os (str — pin to a worker OS)."
  7. 1 tool updatev0.5.12
    • Changedjobd_list2 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Advisory cap on returned jobs (the broker currently returns its default window)."New value: +"Max jobs returned (newest first; clamped to [1,200]). `counts` still covers every job matching the filters; a `truncated` field reports how many were cut."
      • changedInput schema / properties / state / description
        Previous value: -"States to include — any of: queued, assigned, running, completed, failed, cancelled, preempted, orphaned, scheduling_timeout. Currently only the first is forwarded to the broker (single state_filter)."New value: +"States to include — any of: queued, assigned, running, completed, failed, cancelled, preempted, orphaned, scheduling_timeout. Omit for the active set (queued/assigned/running); pass [] for all states."
  8. 3 tool updates
    • Changedjobd_job_get1 field changed
      • addedInput schema / properties / job_id / description
        Added value: +"Numeric job id as returned by jobd_submit or shown in jobd_list."
    • Changedjobd_list3 fields changed
      • addedInput schema / properties / limit / description
        Added value: +"Advisory cap on returned jobs (the broker currently returns its default window)."
      • addedInput schema / properties / project / description
        Added value: +"Restrict to one project's jobs (the --project value used at submit)."
      • changedInput schema / properties / state / description
        Previous value: -"States to include. Currently only the first is forwarded to the broker (single state_filter)."New value: +"States to include — any of: queued, assigned, running, completed, failed, cancelled, preempted, orphaned, scheduling_timeout. Currently only the first is forwarded to the broker (single state_filter)."
    • Changedjobd_logs2 fields changed
      • addedInput schema / properties / job_id / description
        Added value: +"Numeric job id whose captured output to read."
      • addedInput schema / properties / tail_bytes / description
        Added value: +"How many bytes from the END of the log to return (server caps reads at 1 MiB). Raise for context, lower for a quick liveness peek."
  9. 9 tool updatesv0.5.5
    • First observedjobd_cancel
    • First observedjobd_job_get
    • First observedjobd_list
    • First observedjobd_logs
    • First observedjobd_preempt
    • First observedjobd_status
    • First observedjobd_submit
    • First observedjobd_worker_delete
    • First observedjobd_workers

TDQS

A4.2/5.0

Scored across 9 tools

Disambiguation4/5

Each tool has a clearly targeted purpose: submit, list, status, logs, events, cancel, preempt, worker list, and worker delete are all distinct. The only mild ambiguity is between cancel and preempt for running jobs, but descriptions clarify the preemptible requirement and final state.

Naming Consistency4/5

All tools share a consistent 'jobd_' prefix, but verb placement varies: some are imperative verbs (jobd_submit, jobd_cancel), some are nouns (jobd_events, jobd_status), and one is noun-verb (jobd_worker_delete). This is mostly readable but not perfectly uniform.

Tool Count5/5

Nine tools is a well-scoped set for a job broker: job lifecycle, monitoring, debugging, and worker management are each covered without unnecessary redundancy. The count feels appropriate for the domain.

Completeness4/5

The core job lifecycle is covered: submit, list, status, cancel, preempt, logs, events, and worker fleet management. Minor gaps like job deletion/purging or retry/resubmit are absent, but agents can work around those with existing tools.

Maintenance

ActivityNo data
ResponsivenessWithin a week

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
    A
    quality
    B
    maintenance
    Jungle Grid MCP Server lets AI agents submit, estimate, monitor, and retrieve logs for GPU workloads through Jungle Grid. It enables agentic execution for inference, training, fine-tuning, and batch jobs without manually choosing GPU providers or infrastructure.
    8
    24 npm
    4
    MIT
  • F
    license
    Not graded
    quality
    A
    maintenance
    An MCP server for monitoring and managing multi-cluster Slurm GPU jobs, enabling AI agents to execute commands, check allocations, and explore logs across HPC clusters.
    1
    -