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.
One job per file
Section titled “One job per file”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 problemimport simulo
cartpole = simulo.Asset.from_registry("simulo/robot/cartpole:v1")app = simulo.App("my-app")
class StarterTask(simulo.Task): ...# preview.py: one preview jobimport 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 jobimport 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 jobimport 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 5Each 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.
Job types
Section titled “Job types”| 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.
What @app.job takes
Section titled “What @app.job takes”| 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:
simulo run train.py --num-envs 512 --max-iterations 600simulo run train.py -h # lists this job's flagsA job returns a JSON-serializable dict, or nothing. simulo result prints it
once the job has completed.
What simulo run does
Section titled “What simulo run does”-
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 insidebuild()is invisible to this step, so create handles at module level. -
Packages the folder. The files become a content-addressed package.
.simuloignorekeeps files out of it. -
Checks the package with the platform. This is the same check
simulo prepareruns on its own. See Run and submit. -
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-4f8k2mPolicy: policy_brisk-heron-4f8k2mWithout
--detach,simulo runthen 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-d522f9012a2cThis wrote a local package only. Log in to submit to the Simulo cloud instead: simulo loginAdd labels to a job when you submit it:
simulo run train.py --tag baseline --tag reward-v2Tags 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.
Every run is fresh
Section titled “Every run is fresh”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:
simulo run train.py --max-iterations <N> --from policy_brisk-heron-4f8k2m:bestThat job makes a new policy and leaves the original unchanged.
Policies and checkpoints
covers the rules, including what --max-iterations must be.