Skip to navigation

Execute Agents as Jobs

View as Markdown

An execute-agent job (agents.execute) runs an agent once, to completion, as a scheduled platform job. You give it an agent and a prompt; the platform schedules a container, runs the agent until it finishes or times out, saves everything the run produced, and exits.

This is the bounded counterpart to Deploy Agents. A deployment is a service that stays up waiting for requests. An execute job is a single unit of work with a beginning and an end — you are asking an agent to do one thing, not to be available.

When to Use a Job Instead of a Deployment

Agent deploymentExecute-agent job
ShapeLong-running serviceOne bounded run
Invoked byHTTP request through the Agents gatewayJob submission
LifetimeUntil you undeployUntil the agent finishes or the timeout fires
ResultAn HTTP responseDurable job results you fetch later
Cost when idleHolds resourcesNone — nothing runs between jobs
Good forChat, interactive sessions, anything latency-sensitive with many callersBatch work, scheduled analysis, long autonomous tasks, one-off tasks over a set of files

Reach for a job when the work is long enough that holding an HTTP connection open is the wrong shape, when the run produces files rather than a reply, or when the agent only needs to exist for the duration of one task.

The CLI and Python SDK connect to the deployment in your current CLI context. To connect to a local or remote deployment, see Connect with CLI Contexts.

# Confirm the deployment and workspace in the current context
nemo config view

These examples use the default workspace. If your current CLI context uses a different workspace, run nemo config set --workspace default first. To check, run nemo config view.


How It Works

  1. Submission resolves and snapshots everything. When the job is created, the platform resolves the agent reference, resolves and merges the agent environment, and validates any working-directory references. A bad agent name, a missing secret, or a nonexistent fileset fails your create request rather than the run. The resolved config, compute, and secret references are snapshotted onto the job, so a later edit to the underlying entities does not change what an already-submitted job runs.
  2. The job runs the agent once. The scheduled step stages the working directory, invokes the agent through Fabric with your prompt, and waits up to timeout_seconds for a result.
  3. Everything is saved as job results. The input working directory, the output working directory, the run’s artifacts, and Fabric’s own run record are all saved and downloadable after the job finishes — including when it fails.

Submit a Job

The examples below use the calculator agent that ships with the source checkout. Register it first if you have not already:

nemo agents register \
--name calculator-agent \
--agent-config plugins/nemo-agents/examples/nemo-agent-config/calculator-agent/agent.yaml
nemo agents execute \
--agent calculator-agent \
--input "What is 12 multiplied by 8?"

The command prints the created job record, including the generated name you use to track it.

Job Spec Fields

FieldRequiredDescription
agentYesAn Agent entity name, a workspace/name ref, or an inline agent definition.
inputYes, unless the agent declares a default_inputThe prompt handed to the agent.
contextNoPer-run parameters handed to the agent alongside the prompt. Must match the agent’s context_schema when it declares one.
environmentNoA workspace/name ref to a stored AgentEnvironment, or an inline environment. Supplies secrets, environment variables, tool settings, and compute.
workdirNoThe working directory the agent starts from.
timeout_secondsNoMaximum time to wait for a result. Defaults to 3600 (one hour).
auto_telemetryNoAutomatically configures supported ATIF telemetry to export to Intake. Defaults to true.
imageNoThe container image to run the agent in. Defaults to the platform’s task image.
post_run_actionDependsA post-run action contributed by an installed plugin. Required only when the agent declares several actions and not agents.noop.

The CLI generates one flag per spec field (--agent, --input, --environment, --workdir.base-workdir, --timeout-seconds, --auto-telemetry, --image, --post-run-action.kind). Fields that do not reduce to a single flag — an inline agent, an inline environment, context, workdir.artifact_mounts, post_run_action.config — are supplied with --spec (a JSON string) or --spec-file (a YAML or JSON file). Individual flags override values from the supplied spec.

Execution Image

The job runs the agent inside a container image. That image must contain the Fabric adapter the agent’s harness names, so the image you need depends on the harness:

  • A bundled harness (claude, codex, or deepagents) needs no image at all. Its harness and adapter ship in the platform’s task image, which is what the job uses when you omit image.
  • Hermes needs a separately packaged execution image because its harness cannot share the platform environment.
  • Your own Fabric adapter needs an image that contains it. Build one with nemo agents package and pass it as image; the packaged image carries both the adapter and the execute task module.

Resolution is, in order: the request’s image; the agents.jobs.default_image platform setting; the execution profile’s default_task_image; the platform CPU tasks image. Setting agents.jobs.default_image changes the default for every execute job on the install, and is unrelated to agents.deployments.default_image, which is the fallback for AgentDeployment images only.

A custom image is pulled with the credentials the jobs runtime already has: the Docker daemon’s for docker mode, and the platform’s image_pull_secrets merged with the execution profile’s for k8s. There is no per-job pull credential, so a private image has to be reachable with those.

Track a Job and Fetch Its Results

An execute job is an ordinary platform job. nemo agents execute submits it; from there it is tracked and read back like any other job, by name (e.g. "calc-run-1" below), using the generic nemo jobs commands. The Python SDK does mirror the whole lifecycle under agents.jobs.execute.

# Block until the job reaches a terminal status, streaming logs
nemo jobs watch calc-run-1
# Or poll it yourself
nemo jobs get-status calc-run-1
nemo jobs tail calc-run-1 -n 200
# List what the run produced, then download one result
nemo jobs results list calc-run-1
nemo jobs results download output_artifacts --job calc-run-1 -o output_artifacts.tar.gz

List an Agent’s Runs

Each execute job records the workspace/name reference of the agent it ran as spec.agent_ref. Use it as a filter to list an agent’s runs. Cross-workspace agent references are supported. Jobs that ran an inline agent are not runs of any persisted agent and thus never match.

nemo jobs list --filter.source nemo-agents-plugin-execute \
--filter '{"spec.agent_ref": {"$in": ["default/calc", "research/calc"]}}'

Result Names

Results download as gzipped tarballs of a directory, or as a single JSON file.

ResultSavedContains
input_workdirAlwaysThe working directory as the agent found it, after staging. The record of what the run was given.
output_workdirAlwaysThe working directory as the agent left it — every file it created or modified.
output_artifactsAlwaysFabric’s per-run artifacts, including the agent process’s captured stdout and stderr.
fabric_run_resultOn a completed runFabric’s run record: status, response, runtime and invocation IDs.
fabric_errorWhen the invocation itself raisedThe error type, message, and whether it was a timeout.

A post-run action can save results of its own alongside these.

output_workdir and output_artifacts are saved on failure too, on a best-effort basis. When a run fails, that may be where the explanation is — the job also logs the tail of the agent’s stderr so the initial diagnosis needs no downloads.

Working Directories

An agent that reads and writes files needs somewhere to do it. workdir builds that directory from the Files service before the agent starts. Stored-agent skills come from the agent’s ethos fileset, staged at the Fabric base before this directory is filled in.

FieldDescription
base_workdirA Files reference (workspace/fileset or fileset#path/) copied in as the starting tree.
artifact_mountsIndividual fileset artifacts layered on top, each at a relative mount_path.

Mounts are applied after the base tree, so a mount at the same path wins. Mount paths must be relative and must not overlap each other.

# run.yaml
agent: research-agent
input: Review the config and summarize the risks.
workdir:
base_workdir: default/project-source
artifact_mounts:
- ref: default/config-artifact#config.yaml
mount_path: app/config.yaml
- ref: default/notes-artifact#notes.txt
mount_path: notes/notes.txt
nemo agents execute --spec-file run.yaml

Whatever the agent leaves behind in that directory comes back as output_workdir.

Environments, Secrets, and Compute

Execute jobs use the same environment model as deployments. Pass --environment default/research and the environment’s spec is merged into the agent config, its secret references become secret-backed environment variables on the job step, and its compute spec sizes the container.

nemo agents execute \
--agent research-agent \
--environment default/research \
--input "Summarize this repo's dependencies and risks."

Compute is expressed the Kubernetes way on the compute spec. Execute jobs support cpu, memory, and nvidia.com/gpu; any other resource key is rejected at submission rather than silently dropped.

See Agent Environments for how to create the environment, environment spec, and compute spec.

Inline Agents

agent also accepts a full agent definition instead of a reference. The config is validated at submission and snapshotted onto the job, but it is never stored as an Agent entity. This suits an agent composed per request — models chosen by the caller, harness settings scoped to a single run — where there would be nothing to keep in sync afterward.

{
"agent": {
"config_format": "nemo-agents-spec-v1",
"config": {
"config_format": "nemo-agents-spec-v1",
"name": "one-off-analyst",
"default_harness": "deepagents",
"harnesses": {"deepagents": {"kind": "deepagents", "settings": {"deepagents": {}}}},
"models": {
"default": {
"provider": "nvidia",
"model": "nvidia-nemotron-3-5-lightning-30b-a3b",
"api_key_env": "NVIDIA_API_KEY"
}
}
}
},
"input": "Summarize yesterday's failures."
}

Supply it with --spec/--spec-file from the CLI, or as the spec body from the SDK.

Run Context

context carries per-run parameters to the agent as the top level of the Fabric request context, so one agent definition can serve many runs. The platform adds its own fields under the reserved nemo_helix key: job_id, job_workspace, and agent (the workspace/name that ran). A request whose context sets nemo_helix is rejected.

{
"agent": "research/analyst",
"input": "Analyze recent runs.",
"context": {"since": "2026-10-01T00:00:00Z"}
}

The agent receives:

{
"since": "2026-10-01T00:00:00Z",
"nemo_helix": {"job_id": "job-…", "job_workspace": "research", "agent": "research/analyst"}
}

context is stored on the job spec in plaintext. Use it for parameters, not secrets; bind secrets through an environment.

When the agent declares a context_schema, the job’s context is validated against it before the platform adds nemo_helix. A context that does not match fails the create request.

Declare How an Agent Runs

An Agent entity can declare the runs it accepts, so a caller learns about a mistake when it creates the job rather than when the agent misreads it. Set these fields under helix_registration in the agent.yaml you pass to nemo agents register, or as top-level fields of the register request when you use the API:

FieldDefaultDescription
context_schemaNone (any context)A JSON Schema the job’s context must match. Also accepted on an inline agent.
default_inputNoneThe prompt a job uses when it omits input.
post_run_actions["agents.noop"]The post-run action kinds a job may choose. Must name at least one installed kind.
config_format: nemo-agents-spec-v1
name: analyst
helix_registration:
context_schema:
type: object
properties:
since: {type: string, format: date-time}
required: [since]
additionalProperties: false
default_input: Analyze recent runs.
post_run_actions: [insights.analysis]
# ...harnesses, models, and the rest of the agent config

With this agent, a job can omit input, must pass context.since as an RFC 3339 timestamp, and is rejected if it misspells a key such as sinse.

Registration checks that context_schema is a valid JSON Schema (Draft 2020-12 unless it names another dialect in $schema) and that every kind in post_run_actions is installed. A context_schema cannot use references ($ref, $dynamicRef, or $recursiveRef); write each property’s constraints in place.

A job that omits post_run_action gets one from the agent’s declaration:

Declared post_run_actionsJob omits post_run_actionJob names a kind
Includes agents.noopRuns agents.noopMust be a declared kind
Exactly one kindRuns that kind with an empty configMust be that kind
Several kinds, not agents.noopRejected: the job must chooseMust be a declared kind
Inline agent (no declaration)Runs agents.noopAny installed kind

An Agent registered without post_run_actions, including one registered before the field existed, allows only agents.noop. A job for that agent that names any other action is rejected. Add the actions its jobs need under helix_registration.post_run_actions in its agent.yaml, then run nemo agents delete and nemo agents register again. For a deployed agent, nemo agents redeploy does both and redeploys it.

Post-Run Actions

A post-run action is plugin-owned work that turns the agent’s output into something the plugin owns — for example, the Compass plugin’s analysis runs attach an action that saves an analysis-report result and files the insights it found.

  • When it runs. After the agent invocation succeeds, inside the job’s execute step. It does not run when the invocation fails, and it never runs for nemo agents invoke or a deployed agent; only execute jobs have one.
  • Failure. If the action raises, the job fails, even though the agent itself succeeded. fabric_run_result and the working-directory results are saved before the action starts, so they are still available.
  • Results. Anything the action saves appears in the job’s results next to fabric_run_result.

An action is named by post_run_action.kind and configured by post_run_action.config. An Agent entity limits the kinds its jobs may choose to its post_run_actions, and decides what an omitted post_run_action means. An inline agent declares nothing, so its job may name any installed kind, and omitting post_run_action runs agents.noop, which does nothing. Only kinds installed on the platform are accepted, and the config is validated against the action’s own schema; an unknown kind or a malformed config fails the create request rather than the run. The plugin that provides the action must also be installed in the job’s execution image; the job checks this when it starts, and fails before invoking the agent if the action is missing or that version of it rejects the config. If you are using a feature built on execute jobs, its own commands set this for you.

List the actions installed on the platform:

nemo agents post-run-actions list

The same list is available from GET /apis/agents/v2/post-run-actions, which returns each action’s kind, title, and description.

Write a Post-Run Action

A plugin contributes an action by registering a class under the nemo.agents.post_run_actions entry-point group. The entry-point name is the action’s kind:

[project.entry-points."nemo.agents.post_run_actions"]
"my-plugin.publish" = "my_plugin.actions:PublishAction"

The class implements the PostRunAction protocol from nemo_helix_plugin.agents.post_run_actions, which does not depend on the Agents plugin:

from typing import ClassVar
from nemo_helix_plugin.agents.post_run_actions import PostRunActionContext
from pydantic import BaseModel, ConfigDict
class PublishActionConfig(BaseModel):
model_config = ConfigDict(extra="forbid")
destination: str
class PublishAction:
title: ClassVar[str] = "Publish"
description: ClassVar[str] = "Publish the agent's answer to a destination."
config_model: ClassVar[type[PublishActionConfig]] = PublishActionConfig
def after_invoke(self, context: PostRunActionContext) -> None:
config = self.config_model.model_validate(context.config)
...

PostRunActionContext carries the job context (ctx, for saving results), the action’s config, the agent_name, the resolved agent_config the job ran (as snapshotted when the job was created), and Fabric’s fabric_result.

Requirements and Limits

  • Config format. Only nemo-agents-spec-v1 agents can run as execute jobs. Legacy NAT workflow configs are rejected; use nemo agents evaluate or a deployment for those.
  • Fabric environment. The merged agent config must select the local Fabric environment provider. Because an environment spec can override the provider, this is checked after the merge.
  • Timeout. timeout_seconds bounds the wait for a Fabric result and defaults to one hour. A run that exceeds it fails with a saved fabric_error rather than hanging.
  • Reserved environment variables. A secret cannot be bound to an environment variable name the platform injects itself (the NEMO_JOB_* family, NHX_BASE_URL, AGENT_CONFIG_PATH, and similar). The collision is rejected at submission.

Clean Up

Job records and their results persist until you remove them.

nemo jobs cancel calc-run-1 # stop a running job
nemo jobs delete calc-run-1 # remove the record and its results