cancelJob
ChatGPTStop a running job: files the cancel, and the daemon stops your workload within one poll interval (about 15 seconds plus the stop) and releases the machine, or your share of a shared one, ending your spend at that point. getStatus shows the request as cancelRequestedAtMs at once (cancelState requested), and the job reads cancelled only once the stop is CONFIRMED (cancelEnforcedAtMs set, cancelState enforced); if the stop cannot be proven the job reads lost with cancelState unconfirmed and the last evidence in cancelStopDetail. Pass an optional reason (short human-readable text, truncated at 500 chars) to record WHY; it is stored opaquely and returned by getStatus as cancelReason so a client can see why a job was cancelled.
describeDataset
ChatGPTMeasure a public https dataset URL and return its exact sizeBytes, sha256 and contentType, plus suggestedEntry — a filled-in element of the spec's datasets[] array you can paste straight in. Call it before submitJob whenever you want datasets[] to stage and verify a file: sizeBytes and sha256 are REQUIRED on every entry, and this is how you get them without pulling the data down to your own machine first. We read the URL from our side, stream it through a hash and keep no copy. Free, books nothing, and it never reads the caller's filesystem. https only, and only addresses on the public internet: a loopback, private, link-local or otherwise reserved host is refused, and so is a redirect that leads to one. There is an upper size limit and a limit on how often one session may call it; both refusals say so plainly. You do NOT need this when your command downloads its own data with curl or wget — datasets[] is the verified-staging path, and only that path needs a hash declared up front.
estimateExecution
ChatGPTPrice a job before committing: Symbioza selects compatible compute internally and returns estimatedPriceUsd — what the job is expected to bill you — and runtime (basis, referenceSeconds, boundSeconds, note): what runtime the price assumes and where the run would be stopped, derived by Symbioza from the budget and the machine, never asked of the user. Free, books nothing. Use to check feasibility before submitJob. When no machine on the market matches the spec, this answers with a refusal in place of a price — the same shape submitJob refuses in: a reason, a machine-readable code (no_compute) and one action (relax_spec_or_retry) — so branch on those rather than on the sentence; the call is still free and still books nothing. image must be one of the images we have verified launch on our machines — an image must ship an ssh client to be launched: pytorch/pytorch:2.4.1-cuda12.1-cudnn9-runtime, pytorch/pytorch:2.4.0-cuda12.1-cudnn9-runtime, tensorflow/tensorflow:2.15.0. Any other image is refused with code invalid_spec, action fix_spec and a supportedImages list, before anything is booked or charged. budgetUsd is what you are willing to spend on the job, and you are never billed more than that. Every dollar figure returned by any tool here is in that same unit: what you pay. It also returns account: availableUsd (what this account can spend right now, promotional credit included), promoUsd and promoExpiresAtMs, promoJobCapUsd (the most promotional credit any one job may use — a larger budget needs paid balance for the rest), coversThisJob (would submitJob accept this spec's budget today), claimableUsd (free compute credit this account could still take, or null), nextAction ("add_funds" or "claim_credit", null when the job is already covered), claimUrl and topupUrl. It also returns specDigest, a fingerprint of the exact spec and budget priced here: pass it to submitJob and a spec or budget changed since this estimate is refused with invalid_spec instead of run. Read the account before submitJob so a funding problem is something you fix rather than something you discover from a refusal — claiming credit needs no payment. Declare datasetGb as the total data the box will ingest, including data it downloads itself, so a host too slow to pull it in time is filtered before booking. Declare gpu.minCudaVersion (e.g. 13.0) if your image pins a CUDA build — it filters the market here too, so the price you get back is for a host that can actually run your image. Only when the user explicitly requires a particular model for their own benchmark, declare gpu.gpuNameExact: true with gpu.gpuName to price only that exact card model, with every substitute refused — the price then reflects the instrument a measurement actually needs. Add gpu.minPowerLimitW to price only boards at or above that TDP, since one model name covers several. May also return advisory warnings/notes (additive, may be absent) — e.g. ingest_may_exceed_deadline when the declared datasetGb cannot move inside maxRuntimeSeconds over the link the selected host advertises (or the rate we measured on that box before), and ingest_not_predicted when that host publishes no link speed and we have never measured one. Advisory ONLY: it never refuses and never changes the ranking or price; it is about the box we would book for you, not about your data's source, whose speed we do not measure from here.
getArtifact
ChatGPTResults of a finished job: your workload's exitCode, the artifact manifest (path/sha256/status, with time-boxed download links when offsite storage is configured), deliveryComplete + deliveryDetail, priceUsd (the charge, the same number getStatus returns) with priceStatus ("provisional" while billing is being reconciled, "final" once settled for good), checkpoint. The charge shown after completion may change while billing is reconciled. Your total charge for the job, including retries, will not exceed your approved budget.
getStatus
ChatGPTProgress of a submitted job by executionId: status/stage, units, budgetUsd, deadline, heartbeat age, transfer, storage, incidents. budgetUsd is what you are willing to spend on the job, and you are never billed more than that. Once the job is over, priceUsd is what it has billed — including a run that failed or was cancelled, and never above budgetUsd — and priceStatus says whether that number can still move: "provisional" while billing is being reconciled, "final" once it is settled for good. The charge shown after completion may change while billing is reconciled. Your total charge for the job, including retries, will not exceed your approved budget. artifactsReady is true once the job has finished and at least one file was delivered; getArtifact's deliveryComplete says whether every file arrived. nextAction is one machine-actionable hint from a fixed set ("poll getStatus", "getArtifact", "read cancelReason, fix, resubmit", "check incidents; workload failed, fix and resubmit", "check incidents; nothing of yours ran, resubmit", "check incidents; resubmit", "resubmit"), or null. Read it before you touch the spec: a failed job says "nothing of yours ran" when every attempt died before your command started (provisioning, verification or data staging), and "fix and resubmit" only when your own workload ran and failed. When status is "cancelled", cancelReason carries the human-readable reason the job was cancelled (e.g. a box that failed the declared minDiskGb), or null if none was given — read it before resubmitting so you do not re-enter the same fault. Poll after submit.
listJobs
ChatGPTList the jobs THIS account has submitted, newest first — the tool to reach for when you do not have an executionId in hand (a fresh session, a lost id, "what am I still running?"). Each row carries executionId, submittedAtMs, the spec's image, budgetUsd, status, stage, artifactsReady and the same nextAction hint getStatus returns; call getStatus for the full detail of any one of them. Returns count (rows served) and totalCount (jobs you have) — when they differ the list was truncated to the newest limit. Free, books nothing, and scoped: it never returns a job another account submitted.
submitJob
ChatGPTAsk the user for budgetUsd — never choose one for them — and call submitJob only after the user has approved the estimate and that budget. Run a containerized workload on a rented cloud machine sized to the spec — GPU, and as much disk as minDiskGb asks for, so the local machine's disk and bandwidth are irrelevant (the box downloads datasets itself). Enqueues and returns a durable executionId immediately (status "queued"); the daemon provisions, runs, harvests artifacts and tears down, all under the budgetUsd ceiling. Write every deliverable to /workspace/artifacts/ — only that directory is harvested and returned by getArtifact; a command that saves its model to the working directory or any other path finishes with nothing delivered. image must be one of the images we have verified launch on our machines — an image must ship an ssh client to be launched: pytorch/pytorch:2.4.1-cuda12.1-cudnn9-runtime, pytorch/pytorch:2.4.0-cuda12.1-cudnn9-runtime, tensorflow/tensorflow:2.15.0. Any other image is refused with code invalid_spec, action fix_spec and a supportedImages list, before anything is booked or charged. budgetUsd is what you are willing to spend on the job, and you are never billed more than that. Call estimateExecution first if you have not priced this spec — it also tells you whether this account can cover the budget, and whether it holds free compute credit still to claim. A refusal here carries a machine-readable code (unauthorized, invalid_spec, budget_too_low, insufficient_balance, no_compute, unavailable, refused) and one action (authenticate, fix_spec, raise_budget, add_funds, claim_credit, relax_spec_or_retry, retry_later, contact_support), so branch on those rather than on the sentence; a refusal books no machine and charges nothing. insufficient_balance with action claim_credit means free credit is waiting on the account — claim it at https://symbioza.dev/app and resubmit. OPTIONAL: if your workload can count its own work, write /workspace/artifacts/.symbiosa/metrics.json with {"unit": "configuration", "units_planned": 100, "units_completed": 100, "elapsed_seconds": 4821} — unit is free text naming what you counted, partial progress is valid evidence on a failed run, and the whole file is optional (omit it and throughput is simply recorded as UNKNOWN; do not invent a unit to fill it in). It is recorded as observed evidence about your workload and never affects what you are charged; a missing, malformed or incoherent file changes nothing about the run. You may disconnect and poll getStatus later. If an attempt fails and the job is moved to a replacement machine, the newest checkpoint streamed off the previous box (files named ckpt_step<N>.pt, N = digits) is pushed onto the new box under /workspace/.symbiosa/resume/ (outside the artifacts directory) and SYMBIOSA_RESUME is set to its absolute path there — your command must load that file to continue, or the attempt restarts from the beginning. The variable is unset on a first attempt, when no checkpoint was kept, when kept checkpoints span more than one directory (multi-arm layouts are not restored), when checkpoint.enabled is false, when the box lacks disk headroom, or when the push failed; restore is best-effort salvage and never fails a run. Work since the last streamed checkpoint is lost, and the push's hash check proves the transfer, not that the checkpoint itself is intact. Set pinHost: true for a benchmark or measurement workload whose numbers are only comparable on ONE machine: the job then FAILS instead of being moved to a replacement box, because a silent host swap would make the results meaningless; no retry, resize or reroute buys a second machine for a pinned job. It is a refusal, not a migration — nothing holds the original machine. Only when the user explicitly requires a particular model for their own benchmark, set gpu.gpuNameExact: true alongside gpu.gpuName to pin the CARD MODEL the same way: only that model is booked and every substitute is refused, including a faster one, because when the measured quantity is the hardware a better card is …