Invoke an agent
Prepare for programmatic execution using stable inputs and observable runs.
Programmatic invocation should behave like calling a typed function: provide valid input, receive an execution identity, and observe the run until it reaches a terminal state.
Define a stable contract
Before integrating, make the agent's required input and output explicit. Avoid parsing prose when a structured schema can represent the result.
The caller should know:
- which agent or published interface it is invoking;
- the required input shape;
- whether execution is synchronous, streamed, or asynchronous;
- how to observe and cancel the run;
- which terminal states are possible.
Know what an output schema guarantees
Agent and team contracts use a bounded, object-rooted profile of JSON Schema
Draft 2020-12. A configured schema must
be a JSON object whose root declares "type": "object". The $schema keyword
is optional; when present, it must identify Draft 2020-12. $ref and
$dynamicRef may point to definitions inside the same schema with a #
reference. Guest Machines never retrieves a remote schema.
An otherwise successful model response must be one exact, finite JSON document.
Surrounding prose, Markdown fences, trailing content, duplicate object keys, and
non-finite numbers such as NaN do not count as structured output. Validation
uses JSON types exactly: it does not turn strings into numbers, remove unknown
fields, or insert missing fields. In particular, JSON Schema's default keyword
is documentation and does not supply a value. Additional object properties are
allowed by JSON Schema unless your contract sets "additionalProperties": false.
Format assertions are enforced for color, date, date-time, duration,
email, hostname, idn-email, idn-hostname, ipv4, ipv6, iri,
iri-reference, json-pointer, regex, relative-json-pointer, time,
uri, uri-reference, uri-template, and uuid. An unknown format makes the
schema invalid instead of silently becoming an annotation.
Invalid or unbounded schemas are rejected when the agent or team is saved. The profile allows at most:
- 64 KiB of canonical schema JSON;
- 32 levels of schema nesting;
- 2,048 schema nodes;
- 512 declared properties across the schema;
- 2,048 characters in one
description; and - 1,024 characters in one
pattern.
Provider-native structured output helps the model produce the right shape, but it is not the verifier. Guest Machines validates the final result against the original contract, including constraints that a model provider could not enforce while generating.
Treat execution and verification as separate outcomes. status=completed means
the execution lifecycle finished; it does not prove that the returned result is
correct. Inspect verification_status as well:
verifiedmeans every required platform check passed;unverifiedmeans execution completed without evidence from a required verifier;verification_failedmeans at least one required check failed;not_evaluatedmeans no verification result exists yet, including when execution stops before a verifier can run.
Output-schema verification runs only after execution has produced an otherwise
successful terminal result. A schema mismatch changes the run to
status=failed with verification_status=verification_failed; it is not a
completed but partially valid result. A pause, cancellation, provider outage,
tool failure, or other operational failure stops before this check and remains
not_evaluated.
When file delivery is part of the contract, set
input_data.require_artifact=true. A run that creates at least one downloadable
file passes the required artifact_requirement check. If it finishes without a
file, the run fails with
artifact.required_not_published and verification_failed. If the agent also
has an output_schema, the result-format and file checks are both required and
both must pass.
Verification is scoped to the checks that ran. Passing output-schema validation proves that the JSON structure met the declared contract. It does not prove that its facts are true, that its reasoning is sound, or that it completed the requested task well.
Failed checks report property paths and constraint names without exposing the rejected output values.
Provide files to a run
The product UI calls these files. In the API, each file has an artifact record. Upload a new artifact once, then reference its ID from an agent, team, or pipeline start. Existing ready artifacts can be referenced the same way without uploading their bytes again.
Upload a new artifact
The upload body is the file itself: application/octet-stream, not JSON,
base64, or multipart form data. Declare its exact byte length and lowercase
SHA-256 digest. This Bash example calculates both values, uploads the bytes,
and captures the immutable artifact identity returned by the 201 response:
set -euo pipefail
: "${GSMC_TOKEN:?Set GSMC_TOKEN to a Guest Machines bearer token}"
file_path="./dataset.csv"
file_name="$(basename "$file_path")"
file_size="$(wc -c < "$file_path" | tr -d '[:space:]')"
file_sha256="$(openssl dgst -sha256 "$file_path" | awk '{print $NF}')"
upload_key="$(uuidgen | tr '[:upper:]' '[:lower:]')"
artifact_json="$(
curl --fail-with-body --silent --show-error \
--request POST \
--url "https://api.guestmachines.com/api/v1/artifacts" \
--url-query "file_name=${file_name}" \
--header "Authorization: Bearer ${GSMC_TOKEN}" \
--header "Content-Type: application/octet-stream" \
--header "Idempotency-Key: ${upload_key}" \
--header "X-Upload-Size: ${file_size}" \
--header "X-Content-SHA256: ${file_sha256}" \
--data-binary "@${file_path}"
)"
artifact_id="$(jq -r '.id' <<< "$artifact_json")"
artifact_sha256="$(jq -r '.sha256' <<< "$artifact_json")"curl supplies Content-Length for --data-binary. It is optional—chunked
uploads are supported—but when a client sends it, it must agree with
X-Upload-Size. The server verifies the declared byte count before returning
201, so the returned artifact is already ready.
Keep upload_key stable only while retrying this exact filename, description,
size, and checksum.
A delegated token is locked to the organization that issued it, and a service
principal is likewise organization-bound; neither needs X-Org-Id. A direct
human session can use that header to select one of the user's active
memberships. A user-session or delegated-token upload is private to that user.
A service-principal upload is shared with its organization because a service
principal has no user owner.
A service principal that has a resource allowlist cannot call this upload operation. Use a service principal without a resource allowlist, or a delegated token when the upload should belong privately to its user. Giving an allowlisted principal access to the target agent does not allow uploads.
Attach the returned artifact
Put the returned artifact_id into the next start request. Pin the same digest
with expected_sha256 so admission fails if your client selected different
bytes than it intended:
: "${AGENT_ID:?Set AGENT_ID to the agent UUID}"
run_key="$(uuidgen | tr '[:upper:]' '[:lower:]')"
jq -n \
--arg artifact_id "$artifact_id" \
--arg sha256 "$artifact_sha256" \
'{
input_data: {task: "Analyze the attached dataset"},
artifact_inputs: [{
artifact_id: $artifact_id,
alias: "dataset",
expected_sha256: $sha256
}]
}' |
curl --fail-with-body --silent --show-error \
--request POST \
--url "https://api.guestmachines.com/api/v1/agents/${AGENT_ID}/run" \
--header "Authorization: Bearer ${GSMC_TOKEN}" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: ${run_key}" \
--data-binary @-The upload needs runs:create. Attaching it needs runs:read in addition to
the target's invocation scope (agents:invoke in this example). Grant
runs:read as well if the caller will poll or inspect the run.
Reuse an existing artifact
The same artifact_inputs shape accepts a ready artifact created by an earlier
run:
{
"input_data": {
"task": "Analyze the attached dataset"
},
"artifact_inputs": [
{
"artifact_id": "10000000-0000-4000-8000-000000000001",
"alias": "dataset",
"expected_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
]
}Use List artifacts to find
ready uploads and run outputs visible to the caller, or
list a run's artifacts
when the producing run is known. expected_sha256 is optional, but including
it prevents the new run from starting if it does not match the immutable bytes
your client selected.
Resource-allowlisted service principals have a deliberately narrower artifact
view. Their artifact lists omit every run-produced output. They can list, read,
download, preview, delete, or attach a caller upload only when that exact
artifact UUID is in the principal's resource allowlist. Allowlisting an agent,
run, or other related resource is not enough, and artifact_inputs admission
does not bypass this check.
The alias is the short name the receiving run uses to find the file. It does
not rename the original file. Every alias in one request must be different.
Before starting the new run, Guest Machines confirms that the caller can read the artifact and gives the new run access to it. Its contents are not automatically added to the prompt or model context; the agent chooses whether to read the file.
Providing or reading a file does not prove that the run used it correctly or
that the result is correct, and does not add an outcome-verification check. A
caller upload is input, not run-produced output, so it cannot satisfy
require_artifact.
List a run's artifact bindings
returns the files provided to a run and their safe source details. Its default
scope=inputs excludes files created by the receiving run; use scope=all when
debugging every file the run could access.
This reuse mechanism applies only to files. Structured outputs remain
pass-by-value: submit the saved JSON object as the next run's input_data, or
use ordinary pipeline input/output mappings. An authorized client can retrieve
the complete object from Retrieve a run.
There is no generic API reference that lets one run open another run's
structured output directly.
Scope the machine caller
Use a service principal with the minimum invoke and run-observation scopes. A successful authentication does not bypass resource visibility or allowlist rules: the agent being invoked must be shared with the organization, or explicitly granted to the principal, because a service principal can never reach a private resource. See authentication.
If the agent can ask a user a question or request tool approval, use a delegated
token instead. Grant runs:read to retrieve the pending interaction and
runs:edit to answer it. The same delegated user who started the run must make
that decision; service principals and administrator overrides cannot.
See the HITL API flow.
Make starts retry-safe
For endpoints that accept Idempotency-Key, generate one stable value per intended execution. Reuse it only when retrying the same payload. Reusing a key with different input should be treated as a conflict.
Attribute the spend
In a shared organization, send project_tag, ticket_tag, and cost_center_tag alongside the run's input to record what the work belonged to. Each is optional and at most 255 characters; blank values are stored as none. They are a reporting dimension only — no budget, limit, or approval reads them — and they surface in the runs list filters and the organization's chargeback export.
Set them on the call that starts the work. Child runs inherit from their parent, so a fan-out or a pipeline reports as one unit, and the values are fixed once the run starts. An integration that fires the same job repeatedly is usually better served by a schedule or an inbound webhook, which carries the tags in its own configuration rather than repeating them per call.
Where the details are
Run an agent documents the request and response, the failure modes, and the scope it needs, with request samples in seven languages. Runs covers observing execution to a terminal state, retrieving files created by runs, and inspecting the API records for files provided to a run.
Team and pipeline invocation use the same artifact_inputs request shape. Service-principal keys are supported, but runs started by them have no acting user. Use a delegated token when a workflow depends on user-only tools such as ask_user or send_email.
First-party SDKs are not published yet. Operation identifiers in the reference are frozen, so a client generated from the contract keeps working.