Skip to content

Volumes & Assets

A job reads its inputs and writes its files through three kinds of handle:

Writable What it names Use it for
Volume Yes A named folder on the GPU machine Scratch files a job writes while it runs.
Asset No A catalog reference, pinned to one version Validated robots, worlds, and props.
AssetSource No A file path, with no catalog identity A USD or URDF file that isn’t published.

What a training job produces does not go in any of these. Its checkpoints are saved to its policy automatically; see Policies and checkpoints.

Volumes: writable folders on the GPU machine

Section titled “Volumes: writable folders on the GPU machine”

Declare a volume, mount it on the app, and write to its path inside the job:

scratch = simulo.Volume.from_name("scratch", create_if_missing=True)
app = simulo.App("my-app", mounts={"scratch": scratch})
@app.job(type="train", system=simulo.SystemType.TIER_1)
def train() -> dict:
with open(f"{scratch.path}/notes.txt", "w") as f:
...

Constructing a Volume only declares it. scratch.path exists only inside a running job; reading it while simulo run imports your file raises an error instead of pretending the folder exists on your machine.

A volume lives on the disk of the GPU machine that runs the job. It belongs to your organization, and a later job from your organization sees its contents only if it runs on that same machine. GPU machines are started and replaced as demand changes, so a volume’s contents can disappear between jobs. Treat a volume as scratch space for one run, and keep anything you need later in one of the ways below.

To keep a file after the job ends:

  • register it with simulo.save_output. When the job completes, Simulo uploads it and simulo outputs can download it. A job that fails, is cancelled, or times out does not deliver these files. See Retrieve job outputs.
  • or return small values in the job’s result dict.

An MCAP file a job writes into a mounted volume during the run is uploaded as one of the job’s recordings; see Recordings & live view.

simulo.Asset.from_registry(ref) declares a catalog input:

cartpole = simulo.Asset.from_registry("simulo/robot/cartpole:v1")
my_arm = simulo.Asset.from_registry("robot/my-arm:v3")

A reference is [publisher/]kind/name[:vN]. With no publisher it names your organization’s catalog; simulo/ names the Simulo catalog. Leaving out :vN picks the latest published version at submit, and the job records that exact version.

Pass a robot handle straight to Robot:

self.robot = simulo.Robot(asset=my_arm, initial_pose=simulo.Pose.identity())

Create handles at module level so simulo run sees them and pins them. On the GPU machine the handle becomes a read-only folder holding the exact, digest-checked package. Its .path works only inside a running job.

Asset catalogs & version pinning covers publishing, the two catalogs, --frozen, --strict-assets, and deleting.

simulo.AssetSource is a model file named by its path, with no catalog identity, no version, and no validation:

source = simulo.AssetSource.usd("/models/gripper.usd") # a simulo.USDAsset
arm = simulo.AssetSource.urdf("/models/arm.urdf") # a simulo.URDFAsset
source.path # "/models/gripper.usd"
simulo.Asset.from_registry(ref) simulo.AssetSource.usd(path)
What it names A catalog entry, by reference A file, by path
Version pinned with the job Yes No
Validated when published Yes No
Checks the kind (robot or world) Yes No
Reading .path Only inside a running job Always; it is the path you passed

Use Asset.from_registry(...) in job code. It pins a version, records the exact input with the job, and refuses a world where a robot belongs instead of loading the wrong thing.

Use AssetSource when you need the model-file value itself: a type annotation on a helper, an isinstance check against simulo.USDAsset or simulo.URDFAsset, or plain library code with no job around it.

If you have a file and want it versioned and reproducible, publish it and use Asset.from_registry(...).

simulo.Asset also has .usd(path) and .urdf(path). Inside a running job they return the same simulo.USDAsset or simulo.URDFAsset that AssetSource does. The difference is only on your machine during simulo run, where Asset.usd() returns an inert placeholder so the import stays fast. That is why it is typed as returning Any, while AssetSource.usd() returns a simulo.USDAsset everywhere. Neither pins or validates the file.