Skip to main content
Glama

Run a command as a GPU job

run_job
Destructive

Run one shell command as a job on its own fresh GPU machine. The command runs under bash in /workspace, and the machine stops (billing ends) as soon as the command exits. Billing is the machine's per-hour rate from when it is running until it stops, setup included. ALWAYS set max_runtime_minutes to a realistic upper bound for the command: a job that runs longer is stopped as timed_out. PREFER a list for gpu, e.g. ["H100", "A100-80GB:2", "L40S"]: the GPUs are tried in order, and with no capacity for any of them the job waits (status queued, queue_reason no_capacity, next_attempt_at) up to capacity_wait_minutes (default 30) instead of failing. To send code, pass files (path to text, up to 1 MB in all) or code.git (a repository and ref): it is put in /workspace/code before the command starts, and the command runs there. An agent with a shell and the Runcrate CLI can send a whole directory instead: runcrate run --code . -- . To keep results, write them to $RUNCRATE_OUTPUT_DIR (/workspace/outputs): they are kept 30 days after the job (up to 5 GB), whatever its status; list_job_artifacts and read_job_artifact return them. Or pass storage_id: the volume's files are in /workspace, and files written under /workspace are saved to the volume when the machine stops. For long or flaky work set max_retries: a machine that fails is replaced and the command runs again (RUNCRATE_JOB_ATTEMPT says which attempt), so write checkpoints to the volume and resume from them. count (or params, one variables object per job) runs many copies at once as a group (RUNCRATE_JOB_INDEX, RUNCRATE_JOB_COUNT), max_parallel at a time. The machine also gets the environment's secrets (list_secrets shows their names); variables of the same name win over them. Returns the job (status starting while its machine launches, or queued while it waits), or for count or params the group with its jobs. Its output is in get_job_logs (from after 0, each returned cursor as the next after; follow: true waits up to 25 s for new output; done is true at the end), and its status, exit_code and cost_usd in get_job. Statuses: queued, starting, running, then succeeded, failed, cancelled or timed_out. cancel_job stops a job early; rerun_job runs it again with changes. A retried call is not run twice: the job it already started is returned. The command starts once the GPU driver answers: on machines that install it after boot the job waits in starting for up to 20 minutes, and if the driver is still not ready then, the command runs anyway (usually failing on its GPU calls) and the job log says so. get_job_events shows each setup step. cost_usd covers the machine's whole time, not only the command's: from when its machine came up until it stopped, so setup before the command (pulling the image, waiting for the GPU driver, unpacking code) is included, at each machine's hourly rate (cost_per_hour is the current one's) and with every attempt added up. It is in USD to six decimal places, so a short run is not shown as $0, and while the job runs it is the cost so far. The charge on the billing page can differ slightly: machines billed by the minute are charged whole minutes, including about 30 seconds of teardown, and time some hosts report offline is not charged.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "gpu": "<gpu>",
      "command": "<command>",
      "max_runtime_minutes": "<max_runtime_minutes>"
    },
    "name": "run_job"
  }
}

Input Schema

NameRequiredDescriptionDefault
gpuYesGPU type, e.g. "A4000", or a list to try in order, e.g. ["H100", "A100-80GB:2"]; ":2" sets that entry's GPU count, 1, 2, 4 or 8 (see list_gpu_types). A list waits for capacity on any of them.
codeNoA git repository to fetch into /workspace/code before the command starts (a shallow fetch of ref).
nameNoJob name, up to 63 characters (default job-<first 8 characters of the id>)
tagsNoLabels to find the job by later with list_jobs tag, e.g. {"team": "ml", "run": "sweep-3"}. At most 20; keys are lower case letters, digits and _ . : -
countNoRun this many copies as a group (1 to 100). Each sees RUNCRATE_JOB_INDEX (0-based) and RUNCRATE_JOB_COUNT.
filesNoFiles to put in /workspace/code before the command starts: relative path to text, e.g. {"train.py": "...", "configs/base.yaml": "..."}. Up to 1 MB in all. Use code.git for more.
imageNoContainer image to run the command in (optional). /workspace is mounted, the GPUs are passed in, and the image is pulled before the max runtime starts. If the machine cannot pass GPUs into a container, the job fails before the command runs, unless allow_cpu_container is true. The image needs bash or sh. For a private image, pass image_registry_auth. Leave it out to run directly on the machine.
paramsNoOne variables object per job, merged over variables, e.g. [{"LR": "0.1"}, {"LR": "0.01"}] for a sweep. Instead of count.
regionNoOnly run in this region, matched as for instances (optional; omit for any region)
commandYesShell command, run with bash in /workspace (in /workspace/code when code or files are given), e.g. "pip install -r requirements.txt && python train.py". Up to about 5 KB of ordinary shell; put longer scripts in files.
retry_onNoWhat is retried, with max_retries: machine_failure (always on) and nonzero_exit (the command failed).
templateNoOS template from list_templates (default ubuntu-devbox)
gpu_countNoGPUs on the machine: 1, 2, 4 or 8 (default 1)
variablesNoEnvironment variables for the command, e.g. {"HF_TOKEN": "hf_..."}. Keys use letters, digits and underscores. They win over the environment's secrets of the same name. Values are stored only encrypted, never returned. To pick the Runcrate environment the job runs in, use environment.
workspaceNoWorkspace ID (optional: defaults to the authenticated workspace)
storage_idNoVolume ID from list_volumes or create_volume (optional). Its files are in /workspace, and files written under /workspace are saved to it when the machine stops. Pass one to keep outputs. The volume must be in the same workspace and environment and not attached to another machine.
environmentNoEnvironment name (optional: defaults to the environment this session acts in)
max_retriesNoRun the command again on a new machine this many times at most when an attempt fails (default 0). A machine failure is always retried; a failing command only with retry_on or retry_exit_codes. The volume is saved after each attempt.
webhook_urlNohttps URL that gets a signed POST when the job finishes (optional). It is signed like this workspace's webhooks, or, when it has none, with a webhook_secret returned once in this answer.
max_parallelNoWith count or params: how many of the group run at once (default all). The rest wait, queue_reason max_parallel.
idempotency_keyNoOptional: the same key within 24 hours returns the job it started instead of starting another. Derived from this call when left out.
retry_exit_codesNoRetry only when the command exits with one of these codes (takes precedence over nonzero_exit).
include_communityNoLet community hosts run it (off by default: datacenter machines only). A community host is run by an independent host, not a datacenter: the host operates the hardware and can access the machine, and it is not available on reserved terms. Only when the user asked for community hosts.
allow_cpu_containerNoRun the image without GPUs when the machine cannot pass them into a container, instead of failing (default false).
image_registry_authNoSign in to the image's registry before the pull, with two env values named here (never the values themselves).
max_runtime_minutesYesRequired. Longest the command may run, in minutes (1 to 10080, 7 days), counted from when it starts, for each attempt. Set a realistic bound for this command: past it the job is stopped as timed_out.
capacity_wait_minutesNoHow long to wait for capacity on any of the GPUs before failing (0 to 1440, default 30). 0 fails at once.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed6 schema fields changed
    • changedInput schema / properties / gpu / description
      Previous value: -"GPU type, e.g. \"A4000\", or a list to try in order, e.g. [\"H100\", \"A100-80GB:2\"]; \":2\" sets that entry's GPU count (see list_gpu_types). A list waits for capacity on any of them."New value: +"GPU type, e.g. \"A4000\", or a list to try in order, e.g. [\"H100\", \"A100-80GB:2\"]; \":2\" sets that entry's GPU count, 1, 2, 4 or 8 (see list_gpu_types). A list waits for capacity on any of them."
    • changedInput schema / properties / gpu_count / description
      Previous value: -"Number of GPUs (1 to 8, default 1)"New value: +"GPUs on the machine: 1, 2, 4 or 8 (default 1)"
    • addedInput schema / properties / gpu_count / enum
      Added value: +[
      +  1,
      +  2,
      +  4,
      +  8
      +]
    • removedInput schema / properties / gpu_count / maximum
      Removed value: -8
    • removedInput schema / properties / gpu_count / minimum
      Removed value: -1
    • addedInput schema / properties / include_community
      Added value: +{
      +  "description": "Let community hosts run it (off by default: datacenter machines only). A community host is run by an independent host, not a datacenter: the host operates the hardware and can access the machine, and it is not available on reserved terms. Only when the user asked for community hosts.",
      +  "type": "boolean"
      +}
  2. Changed5 schema fields changed
    • removedInput schema / properties / env
      Removed value: -{
      -  "additionalProperties": {
      -    "type": "string"
      -  },
      -  "description": "Environment variables for the command, e.g. {\"HF_TOKEN\": \"hf_...\"}. Keys use letters, digits and underscores. Values are stored only encrypted, never returned. To pick a Runcrate environment, use environment instead.",
      -  "type": "object"
      -}
    • changedInput schema / properties / environment / description
      Previous value: -"Environment name (optional, defaults to main)"New value: +"Environment name (optional: defaults to the environment this session acts in)"
    • changedInput schema / properties / params / description
      Previous value: -"One env object per job, merged over env, e.g. [{\"LR\": \"0.1\"}, {\"LR\": \"0.01\"}] for a sweep. Instead of count."New value: +"One variables object per job, merged over variables, e.g. [{\"LR\": \"0.1\"}, {\"LR\": \"0.01\"}] for a sweep. Instead of count."
    • addedInput schema / properties / variables
      Added value: +{
      +  "additionalProperties": {
      +    "type": "string"
      +  },
      +  "description": "Environment variables for the command, e.g. {\"HF_TOKEN\": \"hf_...\"}. Keys use letters, digits and underscores. They win over the environment's secrets of the same name. Values are stored only encrypted, never returned. To pick the Runcrate environment the job runs in, use environment.",
      +  "type": "object"
      +}
    • changedInput schema / properties / workspace / description
      Previous value: -"Workspace ID (optional — defaults to authenticated workspace)"New value: +"Workspace ID (optional: defaults to the authenticated workspace)"
  3. Changed21 schema fields changed
    • addedInput schema / properties / allow_cpu_container
      Added value: +{
      +  "description": "Run the image without GPUs when the machine cannot pass them into a container, instead of failing (default false).",
      +  "type": "boolean"
      +}
    • addedInput schema / properties / capacity_wait_minutes
      Added value: +{
      +  "description": "How long to wait for capacity on any of the GPUs before failing (0 to 1440, default 30). 0 fails at once.",
      +  "maximum": 1440,
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • addedInput schema / properties / code
      Added value: +{
      +  "description": "A git repository to fetch into /workspace/code before the command starts (a shallow fetch of ref).",
      +  "properties": {
      +    "git": {
      +      "properties": {
      +        "ref": {
      +          "description": "Branch, tag or commit (default: the default branch)",
      +          "type": "string"
      +        },
      +        "token_env": {
      +          "description": "For a private repository: the name of the env variable or secret holding a token",
      +          "type": "string"
      +        },
      +        "url": {
      +          "description": "https URL of the repository, without credentials",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "url"
      +      ],
      +      "type": "object"
      +    }
      +  },
      +  "required": [
      +    "git"
      +  ],
      +  "type": "object"
      +}
    • changedInput schema / properties / command / description
      Previous value: -"Shell command, run with bash in /workspace, e.g. \"pip install -r requirements.txt && python train.py\". Up to about 5 KB of ordinary shell; put longer scripts in a file on a volume and run that."New value: +"Shell command, run with bash in /workspace (in /workspace/code when code or files are given), e.g. \"pip install -r requirements.txt && python train.py\". Up to about 5 KB of ordinary shell; put longer scripts in files."
    • addedInput schema / properties / count
      Added value: +{
      +  "description": "Run this many copies as a group (1 to 100). Each sees RUNCRATE_JOB_INDEX (0-based) and RUNCRATE_JOB_COUNT.",
      +  "maximum": 100,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedInput schema / properties / files
      Added value: +{
      +  "additionalProperties": {
      +    "type": "string"
      +  },
      +  "description": "Files to put in /workspace/code before the command starts: relative path to text, e.g. {\"train.py\": \"...\", \"configs/base.yaml\": \"...\"}. Up to 1 MB in all. Use code.git for more.",
      +  "type": "object"
      +}
    • addedInput schema / properties / gpu / anyOf
      Added value: +[
      +  {
      +    "type": "string"
      +  },
      +  {
      +    "items": {
      +      "type": "string"
      +    },
      +    "maxItems": 8,
      +    "minItems": 1,
      +    "type": "array"
      +  }
      +]
    • changedInput schema / properties / gpu / description
      Previous value: -"GPU type, e.g. A4000 or H100 (see list_gpu_types)"New value: +"GPU type, e.g. \"A4000\", or a list to try in order, e.g. [\"H100\", \"A100-80GB:2\"]; \":2\" sets that entry's GPU count (see list_gpu_types). A list waits for capacity on any of them."
    • removedInput schema / properties / gpu / type
      Removed value: -"string"
    • addedInput schema / properties / idempotency_key
      Added value: +{
      +  "description": "Optional: the same key within 24 hours returns the job it started instead of starting another. Derived from this call when left out.",
      +  "type": "string"
      +}
    • changedInput schema / properties / image / description
      Previous value: -"Container image to run the command in (optional). /workspace is mounted, and the image is pulled before the max runtime starts. The GPUs are passed into the container only on machines with the NVIDIA container runtime; otherwise the job log says so and the command runs in the container without GPUs. The image needs bash or sh. Leave it out to run directly on the machine, where the GPUs are always available."New value: +"Container image to run the command in (optional). /workspace is mounted, the GPUs are passed in, and the image is pulled before the max runtime starts. If the machine cannot pass GPUs into a container, the job fails before the command runs, unless allow_cpu_container is true. The image needs bash or sh. For a private image, pass image_registry_auth. Leave it out to run directly on the machine."
    • addedInput schema / properties / image_registry_auth
      Added value: +{
      +  "description": "Sign in to the image's registry before the pull, with two env values named here (never the values themselves).",
      +  "properties": {
      +    "password_env": {
      +      "description": "Name of the env variable or environment secret holding the registry password or token",
      +      "type": "string"
      +    },
      +    "username_env": {
      +      "description": "Name of the env variable or environment secret holding the registry user",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "username_env",
      +    "password_env"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / max_parallel
      Added value: +{
      +  "description": "With count or params: how many of the group run at once (default all). The rest wait, queue_reason max_parallel.",
      +  "maximum": 100,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • addedInput schema / properties / max_retries
      Added value: +{
      +  "description": "Run the command again on a new machine this many times at most when an attempt fails (default 0). A machine failure is always retried; a failing command only with retry_on or retry_exit_codes. The volume is saved after each attempt.",
      +  "maximum": 10,
      +  "minimum": 0,
      +  "type": "integer"
      +}
    • changedInput schema / properties / max_runtime_minutes / description
      Previous value: -"Required. Longest the command may run, in minutes (1 to 1440), counted from when it starts. Set a realistic bound for this command: past it the job is stopped as timed_out."New value: +"Required. Longest the command may run, in minutes (1 to 10080, 7 days), counted from when it starts, for each attempt. Set a realistic bound for this command: past it the job is stopped as timed_out."
    • changedInput schema / properties / max_runtime_minutes / maximum
      Previous value: -1440New value: +10080
    • addedInput schema / properties / params
      Added value: +{
      +  "description": "One env object per job, merged over env, e.g. [{\"LR\": \"0.1\"}, {\"LR\": \"0.01\"}] for a sweep. Instead of count.",
      +  "items": {
      +    "additionalProperties": {
      +      "type": "string"
      +    },
      +    "type": "object"
      +  },
      +  "maxItems": 100,
      +  "minItems": 1,
      +  "type": "array"
      +}
    • addedInput schema / properties / retry_exit_codes
      Added value: +{
      +  "description": "Retry only when the command exits with one of these codes (takes precedence over nonzero_exit).",
      +  "items": {
      +    "maximum": 255,
      +    "minimum": 1,
      +    "type": "integer"
      +  },
      +  "maxItems": 32,
      +  "type": "array"
      +}
    • addedInput schema / properties / retry_on
      Added value: +{
      +  "description": "What is retried, with max_retries: machine_failure (always on) and nonzero_exit (the command failed).",
      +  "items": {
      +    "enum": [
      +      "machine_failure",
      +      "nonzero_exit"
      +    ],
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / tags
      Added value: +{
      +  "additionalProperties": {
      +    "type": "string"
      +  },
      +  "description": "Labels to find the job by later with list_jobs tag, e.g. {\"team\": \"ml\", \"run\": \"sweep-3\"}. At most 20; keys are lower case letters, digits and _ . : -",
      +  "type": "object"
      +}
    • addedInput schema / properties / webhook_url
      Added value: +{
      +  "description": "https URL that gets a signed POST when the job finishes (optional). It is signed like this workspace's webhooks, or, when it has none, with a webhook_secret returned once in this answer.",
      +  "type": "string"
      +}
  4. First observed

TDQS

A4.3/5.0
Behavior3/5

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

Annotations already declare destructive=true and openWorld=true, and the description adds substantial context beyond them: billing runs from machine start until stop (setup included), the job is killed at max_runtime_minutes as timed_out, queuing vs failing on capacity, and a 20-minute wait for the GPU driver. However, it is noticeably in tension with idempotentHint=false when it says "a retried call is not run twice: the job it already started is returned" – an agent could read that as dedup for identical calls, though the schema makes clear dedup is key-based.

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

Conciseness3/5

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

It is front-loaded well – the command, the machine's lifetime, and the max_runtime_minutes mandate come first – but the whole thing is one dense paragraph of roughly 400 words mixing setup, billing, retries, fan-out and cost accounting. The closing cost_usd/billing-rounding sentences are the least essential and would be better placed on get_job.

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 27-parameter, no-output-schema tool, it covers what an agent needs: the return value (the job, or the group for count/params), the status lifecycle, where logs and artifacts live, and the cost model. Nothing critical for calling it correctly is left implicit.

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 the schema baseline already carries the parameter meanings; the description still adds real decision guidance beyond it, notably "PREFER a list for gpu" with the ordered fallback/queue behavior, the instruction to always set a realistic max_runtime_minutes, and the checkpoint-and-resume pattern for max_retries. It does not add syntax for most of the remaining 20+ optional params, which the schema handles alone.

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?

Opens with a specific verb and resource: "Run one shell command as a job on its own fresh GPU machine." It distinguishes itself from siblings like create_instance (persistent machine), ssh_execute (interactive shell) and run_schedule_now by stating it is a one-shot command on a fresh, ephemeral machine.

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?

Explicit routing is everywhere: files vs code.git vs the CLI directory upload, count vs params for fan-out, storage_id to persist outputs, max_retries for long/flaky work, and it names follow-up tools (get_job_logs, get_job, cancel_job, rerun_job, list_job_artifacts). It even states the exclusion for include_community ("Only when the user asked for community hosts").

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.