Audience

Verification level

Configuration only. The example resolves a real local Registry, verifies the manifest and asset digests, and builds an immutable ExecutionPlan. It does not start PyBullet or claim a native simulation pass.

What you will learn

One short use: reference travels through this exact chain:

text
use in run.yaml
  -> nearest .fastsim/project.yaml
  -> named Registry index
  -> stable release 1.0.0
  -> digest-verified component manifest
  -> pybullet variant
  -> digest-resolved URDF resource
  -> immutable ExecutionPlan

Files

  • run.yaml asks for one reusable cube component.
  • main.py compiles the Run and asserts every important link in the chain.
  • Component manifest declares the component and its backend variants.
  • Registry index maps the identity to a stable version and a digest-pinned manifest.
  • ../.fastsim/project.yaml registers that index and defines trusted asset roots.

Read the component manifest

The linked manifest contains:

yaml
schema: fastsim-component/1              # Component document contract.
id: object://fastsim/component-demo-cube # Stable, human-facing identity.
version: 1.0.0                           # Immutable release version.
kind: object                             # Legal under scene.objects.
semantics:
  category: primitive                    # Portable descriptive metadata.
variants:
  pybullet:                              # Selected because run.yaml chooses PyBullet.
    resources:
      model:                             # Resource name inside this component.
        uri: assets/cube.urdf             # Relative to this manifest.
        format: model/vnd.urdf+xml       # Machine-readable asset format.
        role: simulation                 # This resource builds the simulated entity.
        sha256: 29d00308...              # Expected bytes, checked before compilation succeeds.

The real manifest also provides MuJoCo and Isaac Lab variants. A component identity therefore stays unchanged when an application changes backend; its variant chooses the compatible representation.

The Registry index supplies two facts that do not belong in a Run:

yaml
stable: 1.0.0                            # Version chosen when @version is omitted.
releases:
  1.0.0:
    manifest: object_cube.yaml           # Location relative to the index.
    sha256: df81158b...                  # Exact file-content integrity gate.

The index SHA-256 covers the manifest file bytes. The plan's manifest_sha256 covers the validated, canonical manifest meaning, so those two digests intentionally serve different layers and do not need to be equal.

Read run.yaml

yaml
schema: fastsim/2                        # FastSim vNext Run schema.
name: component-loading-pipeline         # Human-readable run name.
backend: pybullet                        # Select the pybullet manifest variant.

runtime:
  physics_hz: 60                         # Intended physics frequency.
  control_hz: 30                         # Intended control admission frequency.
  seed: 101                              # Deterministic run seed.

scenario:
  scene:
    objects:
      cube:                              # Local alias: objects.cube.
        use: object://fastsim/component-demo-cube
        pose:
          xyz_m: [0.0, 0.0, 0.5]        # Position in world metres.
          quat_xyzw: [0.0, 0.0, 0.0, 1.0] # Identity rotation, XYZW order.

cube is only this Run's alias. object://fastsim/component-demo-cube is the portable catalog identity. The compiler rewrites the unversioned request to the exact release object://fastsim/component-demo-cube@1.0.0 in the plan.

What enabled means

Every scene entity supports enabled: true or enabled: false. Omitting the field, as this Run does, means true.

yaml
objects:
  optional_cube:
    use: object://fastsim/component-demo-cube
    enabled: false

With enabled: false, FastSim still resolves and validates the component and keeps the complete entity declaration in the Scenario, ExecutionPlan, and Run Lock. A Scenario-reading plugin can therefore see that the entity was declared and disabled. At Runtime, however, FastSim excludes it from the UniRoboSim physical projection:

  • no native object, articulation, robot, environment, fluid, or sensor is created;
  • it has no live physics/render/sensor state and is not a control target;
  • it is absent from live planning geometry and cannot be a default robot or mount target that requires an enabled entity.

This is a compile-time scene switch, not a dynamic visibility or pause command. Changing it requires compiling a new Plan and starting a new application composition; an ordinary Runtime reset continues to use the existing Plan. It also does not skip Manifest/resource resolution during configuration compilation. Use it when one reusable Scenario needs optional entities; remove the entity entirely when even its component and resources should not be resolved.

Read main.py

  1. Path(__file__).with_name("run.yaml") locates the sibling Run from any current working directory.
  2. load_project(RUN_FILE) walks upward to ../.fastsim/project.yaml.
  3. project.compiler().compile_file(RUN_FILE) loads the index, verifies the manifest digest, selects pybullet, resolves the URDF, and freezes the plan.
  4. The assertions prove the selected identity, version, manifest digest, variant, resource format, resource digest, and plan digest.

Only public fastsim.config API is used.

Run it

bash
cd demo/components/01_loading_pipeline
fastsim config validate run.yaml --json
fastsim config expand run.yaml
fastsim config explain run.yaml scenario.scene.objects.cube.component.identity
fastsim config lock run.yaml --output run.lock.yaml
fastsim config verify-lock run.lock.yaml --json
python main.py

config explain queries the compiled effective plan. The authoring-only use field has already been resolved there, so its effective path is component.identity; the selected version and variant are available beside it under component.

What run.lock.yaml is

run.yaml is the human-written intent. It may select a Registry's stable component, inherit Manifest defaults, and use resource URIs. fastsim config lock compiles that intent and writes a generated snapshot of the exact result:

  • the complete immutable ExecutionPlan, including backend, runtime values, seed, entities, plugins, and the Plan digest;
  • each selected component's exact identity, version, backend Variant, and Manifest digest;
  • every resolved resource location and its SHA-256 digest;
  • a lock_digest protecting the canonical Plan and resource-location list.

fastsim config verify-lock checks the Lock structure and digests, then reads every listed local resource and confirms that its bytes still match. Starting with fastsim run run.yaml --lock run.lock.yaml also recompiles run.yaml and refuses to start if the current effective Plan differs from the accepted Lock. A changed stable release, edited pose, different backend Variant, or modified asset therefore fails explicitly instead of silently changing an experiment.

A Run Lock does not freeze the native simulator, Provider package, GPU driver, operating system, or behavior of an external model/device service. Record those versions separately with production evidence.

Treat the Lock as generated evidence, not a second configuration to edit. Regenerate it only after deliberately accepting a configuration change. This tutorial ignores run.lock.yaml, so it is safe to delete after the exercise. For an accepted data run, archive it with that Run's outputs and provenance; review local resource paths before publishing it outside your environment.

Case 12 shows a multi-file component and verifies all of its locked resources.

Expected output

validate reports "ok": true. main.py prints a chain like:

text
use       -> object://fastsim/component-demo-cube
release   -> object://fastsim/component-demo-cube@1.0.0
variant   -> pybullet
resource  -> model (model/vnd.urdf+xml)
plan      -> sha256:...

Digest prefixes may change when the manifest or effective Run changes; their full values remain 64 hexadecimal characters.

Common errors

  • PROJECT_CONFIG_NOT_FOUND: keep the Run inside this demo tree or pass its project explicitly. Copying only run.yaml removes its Registry context.
  • COMPONENT_NOT_FOUND: compare the use identity with catalog/index.yaml.
  • MANIFEST_DIGEST_MISMATCH: the manifest changed without updating its release digest. Treat this as an integrity failure, not as a warning to bypass.
  • RESOURCE_OUTSIDE_TRUSTED_ROOT: register the intended asset root in the project; do not broadly trust unrelated directories.

Next

Continue with 02 — Object component.