Skip to main content
Glama

oto_fleet

Declared configuration of an agent PASS — what a fleet runs, on which table, within which perimeter, and up to which limit. op=create (label + procedure slug + tools allowlist ; optional target namespace + row_filter, execution context model — REQUIRED, one of the catalogue served as runner.models by oto_trigger (refused model_required when omitted: the pass runs on its organization's model key); provider is deduced from it —, and limits max_rows / max_tokens / max_consecutive_failures / max_tokens_per_row — budgets are counted in TOKENS, never money) / list (optionally filtered by status; one CARD per fleet — input_sha256 in place of input, and projection names what it leaves out) / get (the full declaration) / state / update. ⚠️ op=launch ARMS the fleet — it does NOT start any process. The state becomes armed, never running: running is a FACT, not an intent — a worker asked for work and Oto produced this pass's first job. That happens BY ITSELF, usually within seconds: workers poll continuously and Oto makes the work when they ask. No scheduler is involved and none has to be started. An armed still armed after a minute therefore means NO WORKER IS POLLING for this org — not 'nobody has taken it'. Symmetrically, op=stop REQUESTS the stop (stopping); the fleet keeps reserving, calling and SPENDING until none of its jobs is left in flight, at which point Oto states the fact (stopped) at the next poll. Never report a launch on armed, nor a stop on stopping — the gap between the two is also the diagnosis. op=launch is REFUSED with no_runner_armed when no worker polls for this org at all (nothing would ever execute it — reading, updating and op=stop stay open), and with model_not_served when the fleet declares a model no live worker serves: its jobs would wait forever — and model_required for a fleet declared without a model (declare another one). op=state returns the pass PROGRESS aggregated over its jobs — pending, claimed, done, failed, abandoned, tokens consumed, heaviest single row, empty_jobs (finished with no row), stopped_after_write — plus reservable_rows, what the scheduler still sees to serve — and says no_jobs_attached explicitly rather than returning zeros you would read as 'nothing happened'. ⚠️ Those counters count JOBS, never rows: a job that gives its row back unwritten still ends done, so done = jobs_total with failed = 0 is NOT a success. What became of the ROWS is in rows — per final status value, concluded, abandoned (failed, with the reason) and open, read from the table itself — and what each execution concluded is in runs_by_outcome (done / partial / failed / blocked). Report the outcome from rows, and say its scope. The TARGET is frozen at declaration: redirecting a running pass to another table is what declaring exists to prevent; the execution context (provider/model) is frozen too, since changing it mid-flight falsifies the attribution of rows already written — declare another fleet instead — duplicate, never switch. An EXTERNAL scheduler is still served here, and each of its calls names it with taken_by (its own id, stable across its restarts): op=take (armed→running, records taken_by — returned by get and list; taking back a running pass it already holds is a resume and succeeds, one held by ANOTHER scheduler is refused held_by_other), op=beat (heartbeat AND reads back stop_requested in the same call), op=ack_stop (stopping→stopped) — both refused not_the_holder to anyone but the holder. ⚠️ None of them is required any more, and you should not call them: polling alone moves a pass, and op=take would only claim one that was about to start on its own.

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": {
      "op": "<op>"
    },
    "name": "oto_fleet"
  }
}

Input Schema

NameRequiredDescriptionDefault
opYes
_orgNo
inputNo
labelNo
modelNo
toolsNo
reasonNo
statusNo
_run_idNoOBLIGATOIRE à chaque appel dès `run_start` ou `data_claim_next` : sans lui, l'écriture sur une ligne réservée est refusée. Hérité seulement si le serveur tient un run actif — n'y compte pas.
workersNoCap on this campaign's jobs in flight (pending + claimed), default 1. A ceiling, not a head count: the runners polling the queue decide how many actually run (see `runner.workers` on triggers).
fleet_idNo
max_rowsNo
providerNo
taken_byNotake/beat/ack_stop (required): the scheduler's own identifier — stable across its restarts, distinct from any other scheduler.
max_stepsNo
namespaceNocreate: the target table, by id or name. Resolved ONCE, at declaration, in the declarer's scope, and kept as the table's id — served back in `namespace`. A name that several tables carry at the same rank is refused (`datastore_ambigu`).
procedureNo
max_tokensNo
project_idNo
row_filterNo
temperatureNo
max_run_secondsNoPer-row time limit, 60-3600 s. `0` = runner default.
max_tokens_per_rowNo
descriptions_outilsNoWhat the agent reads of each tool description: {defaut: chars served per description (≥ 1), entieres: [tools served uncut]}. Frozen at creation; omitted, the worker's default applies.
max_consecutive_failuresNo

Schema Changelog

Changes observed during successful MCP inspections.

No schema history has been recorded yet.

TDQS

A4.1/5.0
Behavior5/5

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

With no annotations supplied, the description carries the full burden and does so thoroughly: it discloses the state machine and its asynchronous gap ('armed' is an intent, 'running' is a fact; 'stopping' still spends), the rule that the target and execution context are frozen at declaration, and the fact that budgets are counted in tokens, never money. It also warns about reading the wrong counters ('done = jobs_total with failed = 0 is NOT a success') and points the agent to `rows` instead. This is material behavioral context nowhere present in the schema.

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?

The definition is front-loaded with a usable summary and the op enumeration is structured, but it is a dense wall of nested parentheses, bolded warnings and backticked identifiers that is hard to scan at 25 parameters. Some material is redundant or editorial ('the gap between the two is also the diagnosis'), and op=update is named but never explained. The length is defensible for the tool's complexity, but not efficiently spent.

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 25-parameter, ten-operation tool with no annotations and no output schema, the description covers an unusual amount: state transitions, refusal codes, mutation freeze rules, and even return semantics for op=state (rows, runs_by_outcome, reservable_rows, no_jobs_attached). The notable gaps are op=update, whose permitted fields are never described, and the absence of any guidance on which of the ten ops require `fleet_id`.

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?

At 24% schema coverage the description must compensate, and it does for the important inputs: `label`, `procedure`, `tools`, `namespace`, `row_filter`, `model` (REQUIRED, with `provider` deduced from it), and the four token/row limit parameters with their token-not-money semantics, plus `status` and `taken_by` for the scheduler ops. Several parameters remain unexplained anywhere — `max_steps`, `temperature`, `fleet_id`, `input`, `reason`, `project_id`, and `workers` — leaving a real but bounded gap.

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

Purpose4/5

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

The opening sentence defines the resource ('Declared configuration of an agent PASS — what a fleet runs, on which table, within which perimeter, and up to which limit') and the op enum enumerates the lifecycle verbs (create/list/get/state/update/launch/stop/take/beat/ack_stop). It is specific, but the definition relies on unmapped domain vocabulary ('fleet', 'pass', 'perimeter', 'armed') that an agent must infer. Sibling differentiation is only partial — oto_trigger is mentioned solely as the source of `runner.models`, with no statement of when to use oto_fleet versus oto_trigger or oto_procedure.

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?

Guidance on op selection is unusually explicit: 'op=launch ARMS the fleet — it does NOT start any process', and the scheduler ops carry a direct negative instruction ('None of them is required any more, and you should not call them'). Refusal conditions (no_runner_armed, model_not_served, model_required, held_by_other, not_the_holder) tell the agent in advance when a call will be rejected. What is missing is cross-tool routing: nothing says when to declare a fleet here versus configuring a trigger elsewhere.

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.

Resources