Skip to main content
Glama

run_command

Execute one-off commands like migrations or seeds inside a deployed app's throwaway container without interrupting the live service; reuse an idempotency key when retrying.

Instructions

Run a one-off command in a deployed service's image (migrations, seeds).

    The command runs in a throwaway container built from the service's
    current image with the same env, secrets, AI/DB bindings and named
    volumes as the live container — the service itself keeps serving.

    **Bounded-synchronous**: this call BLOCKS until the command exits or
    ``timeout_s`` seconds elapse, then returns ``{exit_code, timed_out,
    oom_killed, duration_s, run_id, log_tail, ...}``. Branch on
    ``exit_code``/``timed_out`` — a non-zero exit is a normal 200 result,
    not an error. One run at a time per service (409
    ``service.run_in_progress``).

    Because the call blocks for minutes, **supply your own
    ``idempotency_key`` and REUSE it verbatim if you retry** — that is the
    only thing standing between a client-side read timeout and a migration
    running twice. A retried key REPLAYS an ``idempotent_replay`` envelope,
    NOT the command's output — the run's stdout is deliberately never
    cached at rest. That replay is an HTTP 200 carrying ``code:
    "idempotent_replay"`` and NO ``exit_code``, so check for that code
    before reading ``exit_code``. Re-run under a fresh key if you need the
    output again, or read it from ``diagnose_service``'s ``last_run``.

    **Key reuse protects a COMPLETED run only.** A failed call un-pins the
    key, so a same-key retry really re-executes. In particular ``503
    run.interrupted`` means the container started and was lost — the
    command may have partially applied — and retrying it, with any key,
    runs it again: stop and inspect instead. And if the daemon died
    mid-run, the key stays claimed for 24 h and the retry returns ``409
    idempotency_in_progress``; mint a fresh key once you have confirmed
    the run is over.
    

Input Schema

NameRequiredDescriptionDefault
envNoEnv overrides for this run only (≤ 64 keys); omit for none. They beat the app's config env and its secrets, but lose to platform-computed keys (resolved AI/DB binding vars, ``PORT``, ``NERDIT_RUN_ID``). Put credentials HERE: values are masked in audit, scrubbed from the returned tail and never echoed back.
nameYesName (or row id) of a deployed APP. A model or database is refused with 422 ``run.not_supported`` — their commands and credentials are platform-managed.
commandYesArgv, run unshelled — no globbing, no pipes (wrap in ``["sh", "-c", "…"]`` for those). It REPLACES the image's CMD and is APPENDED to its ENTRYPOINT when one is declared. 1-256 arguments, none empty or NUL-bearing. Never put credentials here: argv is host-visible via ``docker inspect`` and stored verbatim in ``last_run``.
log_tailNoLines of scrubbed output returned. Default 200; clamped to [1, 200] here and again server-side.
timeout_sNoSeconds before the container is killed and ``timed_out: true`` returned. Default 300; floored at 1 and otherwise passed straight through, so a value above ``[services].run_timeout_max_s`` gets the authoritative 422 ``run.timeout_too_large`` instead of being silently truncated.
idempotency_keyNoCaller-chosen key; omit and a fresh one is minted per call. A retry with the same key replays the first result ONLY if that run completed (2xx). Any other outcome — including 503 ``run.interrupted``, where the container started and its exit is unknown — releases the key, so the retry runs the command AGAIN: check ``last_run`` and the app before retrying a migration.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.1.0

TDQS

A4.6/5.0
Behavior5/5

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

With no annotations, the description carries the full burden and does so: blocking semantics, the exact return envelope, the rule that a non-zero exit is a 200 not an error, the one-run-at-a-time 409, and the fact that volumes/env/secrets are shared with the live container. The idempotency deep-dive (replay yields `idempotent_replay` with no `exit_code`; failure un-pins the key; 503 `run.interrupted` may mean partial application; 24h key claim on daemon death) discloses exactly the risky, non-obvious behavior an agent would otherwise get wrong.

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?

Front-loaded with purpose, then behavior, then retry semantics — a sensible order for a blocking mutation. It is long but nearly all of it is load-bearing; the main waste is the idempotency paragraph restating what the `idempotency_key` schema description already says.

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?

No output schema and no annotations, yet the description supplies the return envelope, error codes, timeout behavior, concurrency limit, and credential-masking implications. For a destructive-capable, minutes-blocking operation that is everything an agent needs to call it safely.

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 baseline is 3; the description earns a bump by front-loading the operational consequence of `idempotency_key` and `timeout_s` (non-zero exit vs. timed_out, 422 rather than silent truncation). It does duplicate the schema's own idempotency wording, so the added value is emphasis and retry procedure rather than new meaning.

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 opening sentence names a specific verb and resource ('Run a one-off command in a deployed service's image') and immediately disambiguates with concrete use cases (migrations, seeds). The throwaway-container clause sharpens the scope further, distinguishing it from a restart/redeploy and from the live service's own process.

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 strong when-to-use context (migrations, seeds), an explicit exclusion (models and databases are refused with 422 run.not_supported), and points to `diagnose_service`'s `last_run` when you only need prior output. What it omits is any comparison to siblings that could otherwise do the job, notably `add_hook` for migrations that should run on every deploy rather than once — with ~70 siblings that is a real gap.

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