Skip to content

Apps and jobs

A job is one run on a Simulo GPU machine. You declare it in Python with @app.job, and every job has a type that says what it is for. A preview job checks a task, a train job produces a policy, a play job runs one back to watch or record it, and an eval job measures one against a success rule. Preview explains the four checks and the report a preview job returns. Evaluation explains the success rule and report an eval job returns.

An app is the object that jobs hang off. It names your project and holds what every job needs: the runtime it runs in and any assets or volumes it mounts.

Each file you submit holds exactly one @app.job, and the decorator names the job’s type. The starter that simulo create NAME writes splits a project into five Python files so the task is written once. Four are abbreviated below; Evaluation explains eval.py and its success rule.

# task.py: the app and the learning problem
import simulo
cartpole = simulo.Asset.from_registry("simulo/robot/cartpole:v1")
app = simulo.App("my-app")
class StarterTask(simulo.Task):
...
# preview.py: one preview job
import simulo
from task import StarterTask, app
@app.job(type="preview", system=simulo.SystemType.TIER_1, timeout=15 * 60)
def preview(num_envs: int = 16, checks: str = "all") -> dict:
return simulo.preview(StarterTask(), num_envs=num_envs, checks=checks, video=True)
# train.py: one training job
import simulo
from task import StarterTask, app
@app.job(type="train", system=simulo.SystemType.TIER_1, timeout=10 * 60)
def train(num_envs: int = 16, max_iterations: int = 2) -> dict:
env = simulo.LearningEnv(task=StarterTask(), num_envs=num_envs, device="cuda")
trainer = simulo.RLTrainer(env=env, algorithm="PPO", device="cuda")
try:
stats = trainer.train(max_iterations=max_iterations)
return {"num_envs": num_envs, **stats}
finally:
trainer.close()
env.close()
# play.py: one play job
import simulo
from task import StarterTask, app
@app.job(type="play", system=simulo.SystemType.TIER_1, timeout=15 * 60)
def play(policy: simulo.PolicyCheckpoint, episodes: int = 3) -> None:
env = simulo.LearningEnv(task=StarterTask(with_camera=True), num_envs=1, device="cuda")
player = simulo.RLPlayer(env=env, policy=policy, device="cuda")
try:
player.play(num_episodes=episodes, record=simulo.RecordConfig(include_video=True))
finally:
player.close()
env.close()

simulo run and simulo prepare check this before anything uploads. A file with two jobs is refused with the name and line of each:

two.py declares more than one @app.job:
- a: function a, two.py: line 3
- b: function b, two.py: line 5
Each file holds one job. Move each job into its own file (for example `train.py` and `play.py`), each importing your task from `task.py`.

A file with no job, or a job without type=, is refused the same way with its own instruction.

Type What it does How it starts
train Trains a policy on your task. simulo run train.py
export Converts a policy checkpoint to an ONNX bundle. Simulo runs it for you when you run simulo export.
asset_validation Checks a robot, world, or prop package before it gets a version. Simulo runs it for you when you run simulo asset publish.
play Runs a trained policy to watch or record it. simulo run play.py --policy policy_x:best
eval Measures how well a policy does against one success rule. simulo run eval.py --policy policy_x:best
preview Checks your robot inside its task before training and makes no policy. simulo run preview.py

A play or eval job’s function takes a policy: simulo.PolicyCheckpoint parameter, which --policy policy_x:best or --policy policy_x:latest fills in. An eval file also declares exactly one @app.success rule. See Play a policy and record it, or start with Evaluation before the complete Evaluate a trained policy guide.

Export, preview, play, and eval jobs appear in simulo jobs beside your training jobs, with their type in the first column. Asset validation jobs are started by Simulo, so they appear under simulo jobs --org. simulo jobs --type train shows one type at a time.

@app.success is reserved for evaluation jobs. An eval file needs exactly one; declaring one in any other job file is refused before upload.

Argument Meaning
type= Required. The job type, as a string ("train") or a simulo.JobType member.
system= The GPU tier, as a simulo.SystemType member. See System types.
timeout= The longest the job may run, in seconds. See Job lifecycle.
retries= How many times to run the job again after it fails. Default 0. All attempts share one timeout.
callbacks= Optional behavior such as anomaly capture. See Callbacks and anomaly capture.

A few names are refused at decoration time so a typo can’t pass silently: gpu= (use system=), produces=, and consumes=.

The job function’s own parameters become command-line flags. Underscores turn into dashes, so num_envs becomes --num-envs:

Terminal window
simulo run train.py --num-envs 512 --max-iterations 600
simulo run train.py -h # lists this job's flags

A job returns a JSON-serializable dict, or nothing. simulo result prints it once the job has completed.

  1. Imports your file on your machine. This is discovery: the job body never runs here. Heavy imports written inside with app.runtime.imports(): are recorded instead of resolved, and every asset handle created at module level is noted so its version can be pinned. A handle created inside build() is invisible to this step, so create handles at module level.

  2. Packages the folder. The files become a content-addressed package. .simuloignore keeps files out of it.

  3. Checks the package with the platform. This is the same check simulo prepare runs on its own. See Run and submit.

  4. Uploads it and creates the job. The first lines name the job and, for a training job, the policy it will produce:

    TRAIN job_brisk-heron-4f8k2m
    Policy: policy_brisk-heron-4f8k2m

    Without --detach, simulo run then follows the job’s logs until it ends.

If you are not logged in, simulo run only writes the package locally, and that local package does not run anywhere:

Submitted job 'train' -> package written to .../.simulo/packages/sha256-d522f9012a2c
This wrote a local package only. Log in to submit to the Simulo cloud instead:
simulo login

Add labels to a job when you submit it:

Terminal window
simulo run train.py --tag baseline --tag reward-v2

Tags never change after submission. A tag uses lowercase letters, digits, ., _, or -, up to 64 characters, and a job can have up to 16. simulo jobs --tag and simulo policy list --tag filter by them, and repeating --tag requires every listed tag. The policy a training job makes shows the job’s tags.

Submitting the exact same file and parameters while that job is still queued or running returns the existing job instead of starting a second one. Once it has ended, submitting the same command again starts a new job, training from scratch. Nothing is carried over between jobs unless you ask for it. To keep training a policy you already have, name one of its checkpoints:

Terminal window
simulo run train.py --max-iterations <N> --from policy_brisk-heron-4f8k2m:best

That job makes a new policy and leaves the original unchanged. Policies and checkpoints covers the rules, including what --max-iterations must be.