FastSim 0.1.0a36 is an alpha release. This repository is the clean vNext implementation: it intentionally does not accept legacy FastSim configuration or provide legacy import aliases.

Why FastSim?

Isaac Lab, MuJoCo, and PyBullet are simulation engines or simulator frameworks. UniRoboSim normalizes their scene, entity, sensor, debug, and control capabilities. FastSim solves a different problem: it turns assets, runtime policy, a Scenario, and installed plugins into one inspectable and repeatable simulation application.

Layer Responsibility
Simulator backend Native physics, rendering, devices, and backend-specific features
UniRoboSim Backend discovery and a portable simulator contract
FastSim Core Configuration, registry resolution, execution plans, locks, lifecycle, scoped services, and control arbitration
FastSim plugins Rule-based, model, teleoperation, Agent, recording, replay, debug, TUI, Web, or server behavior

Use UniRoboSim directly when an application only needs a thin, portable simulator API. Use FastSim when a run must be described as data, inspected before startup, locked to exact resources, extended without modifying the runtime, and driven by multiple kinds of control producers.

FastSim does not own task semantics. Concepts such as pick, place, grasp poses, action lists, planners, model inference, and teleoperation devices belong to plugins. Core only supplies the lifecycle, data, planning-read, and control boundaries those plugins share.

Architecture

FastSim platform architecture

The CLI is part of FastSim Core, not a plugin. Feature interfaces such as a TUI, browser console, interactive debugger, or HTTP server are plugins so their code and runtime cost are absent unless installed and selected.

Installation

Version matrix

FastSim itself supports Python 3.11 and 3.12. Use the Python required by the selected backend provider.

Package Current compatible version Python Notes
fastsim 0.1.0a36 3.11, 3.12 Pins unirobosim==0.10.5; kinematics remains optional
unirobosim 0.10.5 3.11, 3.12 Portable core; no simulator is bundled
unirobosim-isaaclab 0.10.16 3.12 Requires a compatible Isaac Lab 3.0 / Isaac Sim 6.0 installation
unirobosim-mujoco 0.9.4 3.12 Provider currently pins MuJoCo 3.11.0
unirobosim-pybullet 0.9.4 3.11 Provider currently pins PyBullet 3.2.7
fastsim-kinematics-solver-spi 0.1.0 3.11, 3.12 Optional provider contract
fastsim-kinematics-solver-portable 0.1.0 3.11, 3.12 Optional deterministic URDF provider

FastSim 0.1.0a36 retains the opt-in, independently stamped observation-channel stream introduced in 0.1.0a12 and used for camera recording. Pure numeric Record capture is snapshot-atomic, so one simulation tick creates one queue item regardless of channel count. The existing snapshot query and subscription API is preserved, while direct application state reads now return the WorldState and Observation pair atomically from one committed tick. Live channel delivery and ordered capture use separate sequences: channel_sequence orders every due live item, while optional capture_sequence orders only recorded items. Record 0.2.3 targets FastSim 0.1.0a8; the current Record 0.3.12 and managed Replay 0.2.17 use the current FastSim >=0.1.0a36,<0.2 release train. Do not combine packages from different release trains. In ordered capture, a Run uses exactly one observation lane. A data_consumer does not become a recorder merely by reading observations: the installed Manifest must explicitly declare semantics.plugin.recording_sources, and Core accepts at most one enabled capture owner. Other data consumers keep ordinary live subscriptions and add no global sequencing or recording-history overhead. Selecting observations requires a non-empty compiled observation demand.

Primary recording publication now defaults to structural integrity, avoiding payload SHA-256 work while retaining FSR validation, pinned file identity, durability, atomic publication, and cleanup. Deployments that need same-size post-validation tamper detection can opt into strict SHA-256 integrity. See Run output integrity.

The repositories are currently installed from source; the commands below do not assume that packages are available from PyPI. For a PyBullet development setup:

bash
git clone https://github.com/GitHofee/UniRoboSim.git
git clone https://github.com/GitHofee/UniRoboSim-pybullet.git
git clone https://github.com/FastSim-Benchmark/FastSim.git

python3.11 -m venv fastsim-dev
source fastsim-dev/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ./UniRoboSim
python -m pip install -e ./UniRoboSim-pybullet
python -m pip install -e './FastSim[dev]'

For MuJoCo, use Python 3.12 and install UniRoboSim-mujoco instead. For Isaac Lab, run pip through the Python environment that owns the compatible Isaac Lab installation, then install UniRoboSim-isaaclab and FastSim into that same environment. Do not create a second Isaac installation only for FastSim.

Confirm which FastSim installation is active:

bash
fastsim --version
fastsim doctor --json

doctor reports package and Python information. Its backend_integration field is currently conservative (unverified); it is not a native backend health check.

Quick start

The repository contains a minimal lifecycle Run at examples/quickstart/run.yaml. It resolves one small red cube from a local Registry, so configuration, resource integrity, and backend startup can be checked without downloading a robot or installing a plugin.

yaml
schema: fastsim/2
name: quickstart
backend: pybullet

runtime:
  launch_profile: headless
  physics_hz: 60
  control_hz: 30
  seed: 7

scenario:
  scene:
    objects:
      cube:
        use: object://fastsim/quickstart-cube
        pose:
          xyz_m: [0.0, 0.0, 0.5]
          quat_xyzw: [0.0, 0.0, 0.0, 1.0]

Validate and inspect it without opening a simulator:

bash
fastsim config validate examples/quickstart/run.yaml --json
fastsim config expand examples/quickstart/run.yaml
fastsim config explain examples/quickstart/run.yaml runtime.physics_hz

Create and verify a content-addressed lock:

bash
fastsim config lock examples/quickstart/run.yaml --output quickstart.lock --json
fastsim config verify-lock quickstart.lock --json

With the PyBullet provider installed, run the application for two wall-clock seconds:

bash
fastsim run examples/quickstart/run.yaml --duration 2 --json

The top-level fields are intentionally small:

Field Meaning
schema The clean authoring contract; currently fastsim/2
name Stable human-readable Run name
backend UniRoboSim provider ID selected for this compilation
runtime Physics, control, sensor-rate, and seed policy
scenario Required scene and optional plugin-owned behavior/evaluation payloads
control Default actor and precedence between control-producing plugin instances
plugins Installed plugin instances selected for this Run
overrides Explicit authoring-time overrides compiled with provenance

Demo library

demo/fundamentals is the guided API course. Each numbered case is self-contained and includes a Python program, a Run configuration, an English README, and a Chinese README. The sequence begins with configuration-only checks, then introduces lifecycle, control, sensors, scene and planning queries, reproducibility, and advanced physical tracks. Start with 01_config_validation_and_compilation if this is your first FastSim application.

demo/components is the component authoring course for simulation users. It follows the real Project and Registry resolution chain and gives copyable examples for environments, objects, articulations, robots, sensors, lights, deformables, fluids, Scenarios, version selection, backend variants, defaults, and resource integrity.

demo/official_plugins is reserved for configuration-first application pipelines built from released official plugins. Plugin demos are added only after their packages and native acceptance gates are public; placeholders are not presented as working products.

Direct application API

Developers building a complete simulation application can use the asynchronous FastSimApplication facade without implementing a plugin:

python
import asyncio
import fastsim


async def main() -> None:
    async with fastsim.app("run.yaml") as simulation:
        await simulation.start()
        targets = await simulation.control.targets()
        print([(item.entity_id, item.resource_group) for item in targets])

        operation = await simulation.control.submit_joints(
            actor="droid",
            group="arm",
            path=[
                [0.0, -0.4, 0.0, -2.0, 0.0, 1.6, 0.8],
                [0.2, -0.2, 0.1, -1.8, 0.1, 1.4, 0.6],
            ],
            dt=1.0 / 60.0,
            timeout=10.0,
        )
        print(await operation.status())
        result = await operation.result()
        await operation.release()
        print(result.status)

        moved = await simulation.scene.set_pose(
            "objects.red_cube",
            xyz_m=(0.55, -0.15, 0.72),
        )
        print(moved.status)


asyncio.run(main())

The facade provides async lifecycle operations, coherent world and observation state, opt-in scene/frame/planning-geometry reads, rigid-object pose and drag commands, packed RGB and particle-fluid queries, control-target discovery, joint paths, generic multi-resource physical tracks, and explicit operation status/result/cancel/release. It exposes no simulator-native handle and does not add task semantics such as pick, place, or planning.

The optional solve-only simulation.kinematics client resolves an end-effector pose to ordered joints without executing them. It loads a verified URDF from the compiled robot component, captures current joint state in the active generation, and runs an installed provider off the Application loop. See the bilingual Application kinematics guide.

Planning publication can be expensive and requires a complete collision scene. Use fastsim.app("run.yaml", planning_reads=True) only when scene, frame, or planning geometry APIs are needed. The default keeps planning disabled for control and sensor runs; a planning call then fails explicitly instead of returning partial geometry.

The optional fastsim-plugin-server package exposes the same facade through fastsim-http/1:

bash
pip install fastsim-plugin-server
fastsim-server run.yaml --host 127.0.0.1 --port 8000

Control routes return 202 Accepted with an operation ID, so HTTP remains asynchronous as well. Non-loopback listeners require both HTTPS and bearer-token authentication. See the package's OpenAPI document at /api/v1/docs for the exact transport schema.

For a persistent remote control plane, start an empty Server and authorize one trusted Project tree. The independent Web Client can then upload one standalone config or select a config below the named root and ask the Server to launch it:

bash
fastsim-server \
  --launch-root runs=/srv/fastsim-runs \
  --browser-origin http://127.0.0.1:8080

Configuration model

Files and project discovery

Run and project documents can be YAML, JSON, or TOML. FastSim searches upward from the Run file for exactly one .fastsim/project.yaml, .json, or .toml. The project declares registry indexes, trusted resource roots, cache policy, offline mode, and optional deployment ceilings for plugin access.

The quick-start project points at the component index shipped beside the example:

yaml
schema: fastsim-project/1
installed_packages: false
registries:
  - name: quickstart
    path: components/index.yaml

A larger project can discover installed component catalogs and layer additional indexes in a deterministic order:

yaml
schema: fastsim-project/1
installed_packages: true
registries:
  - name: project-assets
    path: assets/index.yaml

use values such as robot://franka, object://kitchen/cup, scenario://house/heat-food, and plugin://example/controller are resolved by the project's registries. Omitting a version selects the registry's stable release; an exact version can be requested with @, for example robot://franka@1.4.0. Compilation records the exact manifest and resource digests, and a lock preserves them for a later run.

FastSim deliberately has no recursive include, $ref, or inherited configuration language. Reusable products live in versioned registry components; a Run remains a short description of what is selected and what is overridden.

Scenario

Every standalone Run has one Scenario. scene is required. behavior and evaluation are optional opaque mappings: FastSim preserves them and only grants them to plugins whose manifest requests those sections.

yaml
scenario:
  scene:
    environment:
      use: scene://example/apartment
      static: true
    robots:
      mobile_manipulator:
        use: robot://example/mobile-manipulator
        pose:
          xyz_m: [0.0, 0.0, 0.0]
          quat_xyzw: [0.0, 0.0, 0.0, 1.0]
        scale: [1.0, 1.0, 1.0]
    objects:
      cup:
        use: object://example/cup
        pose:
          xyz_m: [0.7, -0.2, 0.85]
          quat_xyzw: [0.0, 0.0, 0.0, 1.0]
  behavior:
    program: heat-and-deliver
  evaluation:
    profile: household-success

environment.static defaults to true: the environment remains a collidable static support world, while undeclared internal actors are not dynamically solved. Set it to false when authored mechanisms inside the environment itself must remain interactive. Explicit robots, objects, and articulations are unaffected.

The authoring schema has groups for environments, rigid objects, general articulations, robots, deformables, fluids, sensors, and lights. The current UniRoboSim runtime lowering runs enabled environment, object, articulation, robot, procedural surface-deformable, fluid, and supported sensor entities. Enabled lights and unsupported deformable forms fail closed at runtime composition; provider support alone is not sufficient.

Scene placement is physical data. A semantic relation such as inside: refrigerator is not used as a substitute for a pose; the food and refrigerator are authored with concrete transforms. A task plugin may interpret its own semantic annotations in behavior, but Core does not turn them into scene state.

Instead of an inline Scenario, a Run may select one registry component:

yaml
scenario:
  use: scenario://example/heat-food

fastsim config materialize expands a referenced Scenario back into portable, runnable authoring.

Runtime rates and backend selection

yaml
backend: isaaclab
runtime:
  launch_profile: headless
  physics_hz: 60
  control_hz: 30
  sensor_hz: {}
  rate_policy: exact
  seed: 7

The launch profile is one of visible, headless, or headless-physics:

Launch profile Native window Camera sensor rendering
visible Enabled Enabled
headless Disabled Available on demand
headless-physics Disabled Disabled

The default is headless; existing Run files therefore keep their current no-window, camera-capable behavior. The remaining defaults are 60 Hz physics, 30 Hz control, exact rate policy, and seed 0. With exact, physics frequency must be an integer multiple of every control or sensor frequency. accumulate permits non-integer ratios.

Named sensor_hz entries are accepted by the configuration compiler, but the current UniRoboSim runtime lowering requires this mapping to remain empty. Every physical entity that can be scaled accepts a positive XYZ scale. Rigid objects and static scenes may use non-uniform values; standalone articulations require uniform values. Isaac Lab composite USD scenes may use uniform scale with embedded dynamic entities, while non-uniform scale is admitted only when the authored result is static and its collision representation supports it. Unsupported asset/scale combinations fail before simulation starts instead of silently ignoring the configured value.

The author selects the backend in the Run. During unlocked inspection it can be overridden without editing the file:

bash
fastsim config validate examples/quickstart/run.yaml --backend mujoco --json
fastsim run examples/quickstart/run.yaml --backend mujoco --launch-profile visible --duration 2 --json

--backend and --launch-profile are compilation overrides. Neither may be used with --lock, because changing either value changes the execution plan and requires a regenerated lock.

Backend switching is not format conversion by itself. The same Run is portable only when every selected component provides a compatible variant or resource and the provider reports the required capabilities. Native rendering, contacts, soft matter, fluids, sensor output, and controller behavior may differ between engines; FastSim does not claim numerical identity merely because the provider ID changed.

For the current physical runtime slice, a PyBullet or MuJoCo entity must resolve to exactly one simulation resource in model/vnd.urdf+xml; an Isaac Lab entity must resolve to exactly one simulation resource in model/vnd.usd. MuJoCo's native provider can expose additional formats, but FastSim's current locked profile still admits URDF only. Asset conversion is an explicit preprocessing step, not an automatic side effect of changing backend.

An articulation component may carry a backend-specific articulation_drive profile in the matching variant defaults. This is physical calibration owned by the component, not a Run-level tuning knob: MuJoCo accepts per-joint position stiffness and damping, while PyBullet accepts position and optional velocity gains. FastSim validates the profile against the selected backend and the component's declared stable joints, preserves it in the lock, and projects only this typed field to the adapter. Omission preserves the adapter's previous behavior. Backend-native drive calibration is excluded from the portable Replay compatibility digest only after this exact validation succeeds.

Plugins: simple by default, explicit when needed

One plugin instance has five authoring blocks:

yaml
plugins:
  controller:
    use: plugin://example/controller
    bindings:
      robot: mobile_manipulator
    access: all
    session:
      freshness:
        max_observation_age_sim_s: 0.25
      lease:
        timeout_s: 5.0
      heartbeat:
        timeout_s: 2.0
    config:
      model_endpoint: http://model.example.test/v1/action
Block Owner and purpose May be omitted?
use Registry identity of the installed plugin No
bindings Maps plugin-local actor names to Scenario entities Yes; compatible Scenario entities are derived deterministically
access Narrows services, observations, and control groups Yes; omission and all both mean the exact manifest/Run/deployment intersection
session Core-enforced freshness, lease, and heartbeat timeouts Yes; manifest defaults apply
config Plugin-private settings validated by its manifest Yes when its schema/defaults permit it

The plugin manifest is the complete declaration of role, runtime entry point, Scenario inputs, service dependencies, binding policy, control capability, session defaults, and private configuration schema. Normal users therefore usually write only use and config. Deployment owners may add a project-level plugin_access_limits allowlist; this is a compile-time capability ceiling, not an operating-system sandbox.

The four plugin roles are control_producer, data_consumer, extension, and interface. Rule-based, model, teleoperation, and Agent controllers are all ordinary control_producer plugins. Recording/replay are data consumers; debug and external interfaces use the appropriate extension or interface role. These names do not add behavior to Core—the corresponding distribution must be installed and selected.

Control precedence contains plugin instance names, not package identities:

yaml
control:
  default_robot: mobile_manipulator
  precedence: [teleop, model]

Precedence resolves authority between overlapping resources. It does not invoke a task or decide which action should happen next. default_robot is derived when the Scenario has one enabled robot and may be authored for a multi-robot Run; plugin actors are still selected by bindings, not silently redirected by that default.

Control and planning-data flow

FastSim uses one control path regardless of where commands originate:

text
plugin capture/query -> plugin computation -> ControlChunk
    -> Control service -> ControlChunkExecutor -> UniRoboSim -> simulator
  • A rule-based plugin reads its private behavior program, captures a coherent robot state and world geometry, runs IK or a planner in its own thread/process, then submits a joint trajectory.
  • A model plugin reads observations, requests inference locally or remotely, and submits the next joint or end-effector-derived chunk.
  • A teleoperation plugin samples a device or network stream and submits short, replaceable chunks.
  • An Agent plugin uses the same scoped query and control services; it has no hidden simulator access.

The beginner-facing plugin facade is fastsim.plugins.easy.PluginClient. It is not a second simulator EasyAPI. It combines public scoped services into a coherent planning capture and a joint-path submission:

python
import asyncio

from fastsim.plugins.easy import PluginClient


async def run_rulebased_step(context, planner):
    async with PluginClient(context) as client:
        source = await client.capture(
            actor="robot",
            group="arm",
            ee="tool0",
            geometry=True,
            timeout=5.0,
        )

        # The planner belongs to the plugin. CPU/GPU work must not block the
        # FastSim application loop.
        joint_path = await asyncio.to_thread(planner.solve, source.view)

        result = await client.control.joints(
            joint_path,
            source=source,
            dt=1.0 / 30.0,
            timeout=30.0,
        )
        if not result.ok:
            raise RuntimeError(f"control failed: {result.status}: {result.message}")

The capture contains the selected control target, ordered joint IDs, positions, velocities, units, limits, optional end-effector transform, scene/frame snapshots, and optionally a geometry catalog. Mesh/SDF resources are resolved on demand under a bounded lease. Heavy world geometry is not copied into every observation frame. Before control admission, FastSim revalidates the capture against the current world generation and declared expected motion.

Advanced rule-based planners may submit already projected physical tracks without constructing a ControlChunk:

python
async def submit_projected_trajectory(client, source, planner_trajectory):
    base_capability = source.projection_capabilities.resolve_projection(base_resource)
    embedded_base = base_capability.embedded_base_joints[0]

    projection = VirtualJointProjection(
        ProjectionBinding(
            virtual_base=virtual_axes,
            arm_joint_names=arm_joint_names,
            arm_joint_units=arm_joint_units,
            base_resource=base_resource,
            arm_resource=arm_resource,
            embedded_base_joints=embedded_base,
        ),
        capabilities=source.projection_capabilities,
    )
    tracks = projection.project(planner_trajectory)
    return await client.control.physical_tracks(
        (tracks.base_track, tracks.arm_track),
        source=source,
        timeout=30.0,
    )

The capability comes from the capture's immutable, authorized target catalog. An embedded base is available only when its component manifest declares the exact physical x/y/yaw joints, (m, m, rad) units, controller and supported kinematic models. physical_tracks() rejects caller-only capability claims and unadvertised base-pose command spaces before consuming the capture. The exact manifest and admission contract is recorded in Embedded base-joint capabilities.

PluginControlClient.joints() waits until its chunk reaches a terminal state. A rule-based producer gets sequential behavior by awaiting each result before submitting the next chunk. The underlying ChunkExecutionPolicy defaults to all_frames_applied, hold at the terminal frame, and preemption allowed. A servo producer can submit a newer overlapping chunk through the low-level control service; the executor terminates the displaced chunk as PREEMPTED and starts the admitted successor at a control-tick boundary. Plugins that need stricter behavior can use the public low-level contracts in fastsim.control.

physical_tracks() is the sequential rule-based path: concurrent calls are admitted in FIFO order and overlapping physical resources cannot preempt the earlier call. The simpler joints()/joints_many() path retains preemptive servo behavior.

Planner or model latency does not implicitly block physics. The plugin decides what to do while computing—pause the Run through an operator workflow, hold the previous valid target, or let the world continue under the configured idle policy. Recording plugins should use control and lifecycle events to omit or label idle intervals instead of assuming every physics tick is training data.

Public Python APIs

Application lifecycle

The stable synchronous application facade is exported from fastsim and fastsim.api:

python
import fastsim

with fastsim.open("examples/quickstart/run.yaml", launch_profile="visible") as run:
    running = run.start(timeout=30.0)
    paused = run.pause(timeout=30.0)
    stepped = run.single_step(timeout=30.0)
    resumed = run.resume(timeout=30.0)
    status = run.snapshot()
    plugins = run.plugin_status()
    run.stop(timeout=30.0)

FastSimRun also exposes prepare, reset, and idempotent close. One Run owns one application-loop thread and one UniRoboSim runtime. Plugins must not call this facade; they receive asynchronous scoped services in PluginRuntimeContext.

The asynchronous path API accepts the same compilation override:

python
import fastsim

app = fastsim.app(
    "examples/quickstart/run.yaml",
    launch_profile="headless-physics",
)

fastsim.open_plan(plan) and fastsim.application_plan(plan) intentionally have no launch-profile argument. An immutable ExecutionPlan is the sole authority at that boundary. When using a lock, author the desired profile before creating the lock; path APIs reject a second launch_profile override.

Compilation and plans

python
from fastsim.config import load_project

context = load_project("examples/quickstart/run.yaml")
compiled = context.compiler().compile_file("examples/quickstart/run.yaml")
plan = compiled.execution_plan
print(plan.backend, plan.digest)

fastsim.config exports the strict codecs, project/registry/compiler contracts, and structured diagnostics. fastsim.plan exports immutable ExecutionPlan, ScenarioPlan, lock verification, diff/explanation, and freeze/thaw helpers.

Plugin SPI and scoped runtime services

fastsim.plugins exports the plugin factory/runtime protocols, immutable binding, lifecycle states, installed-plugin discovery, and conformance runner. A plugin only sees services granted in its compiled binding. Current public service keys are:

Service key Purpose
run.info Run identity and immutable runtime metadata
scenario.read Manifest-declared Scenario sections
scene.query Entity catalogs and coherent scene state
frame.query Frame catalogs, transforms, and deltas
scene.geometry Planning geometry catalogs, transforms, deltas, and leased resources
scene.command Revocable scene pose, drag, attach, and detach commands when the selected backend declares a matching public command capability
planning.capture Coherent scene/frame/geometry/control-target capture plus revalidation
observations Authorized observation snapshots and subscriptions
fluid.emitters Live particle-fluid reservoir and emitter control
fluid.audit Compact post-acceptance emission batches for a data_consumer recorder
fluid.replay Startup-only immutable emission schedule loading for a control_producer replay plugin
control.targets Authorized actors, resource groups, axes, command spaces, and controllers
control Sessions, chunk submission, cancellation, and status
artifact.read Bounded reads of manifest-declared plugin artifacts
event.publish Bounded plugin events

Direct backend handles, Runtime authority objects, and another plugin's private configuration are deliberately not exposed.

CLI reference

There is no fastsim config compile command. Compilation occurs inside the commands below.

Command Purpose
fastsim doctor [--json] Inspect this installation
fastsim config validate RUN Resolve and validate a Run
fastsim config expand RUN Print canonical effective configuration
fastsim config materialize RUN --output PATH Write authoring with an inline Scenario
fastsim config explain RUN PATH Explain the origin of one effective field
fastsim config diff BEFORE AFTER Compare two effective configurations
fastsim config lock RUN [--output PATH] Write a content-addressed lock
fastsim config verify-lock LOCK Verify lock structure and every local resource digest
fastsim config convert INPUT --to yaml|json|toml [--output PATH] Convert portable authoring syntax
fastsim plugins list RUN List compiled plugin metadata without importing plugin code
fastsim plugins inspect RUN INSTANCE Inspect one compiled instance without importing it
fastsim plugins diagnose RUN Import and verify only the factories selected by the Run
fastsim settings path|list|get|describe|set|unset|validate|export|import|reset Manage optional workstation preferences
fastsim outputs root|list|stats|inspect|verify|open|remove|clean Manage bounded Run output artifacts
fastsim server status [--url URL] Check liveness and readiness of a separate FastSim Server
fastsim run RUN Compile and execute one application

All compile-based commands accept --project PATH, repeatable --registry PATH, --offline or --online, --cache-root PATH, --network-timeout SECONDS, --backend ID, --launch-profile {visible,headless,headless-physics}, and --json, except that verify-lock has no compilation overrides and convert only converts syntax. run additionally accepts:

  • --lock PATH — verify and use a previously written lock;
  • --duration SECONDS — stop after a non-negative wall-clock duration;
  • --timeout SECONDS — positive lifecycle-operation timeout, default 30 seconds;
  • --output-root PATH — trusted local root for output-producing plugins;
  • --gpus IDS — comma-separated visible GPU IDs for this Run.

User settings are deliberately absent by default and are never part of a Run or lock. See user settings for precedence and the complete key catalog. See outputs CLI for FSR discovery, validation, Viewer launch and bounded cleanup.

Examples:

bash
fastsim config convert run.yaml --to json --output run.json
fastsim plugins list run.yaml --json
fastsim plugins inspect run.yaml controller --json
fastsim plugins diagnose run.yaml --json
fastsim settings list --effective --json
fastsim outputs list --status complete --json
fastsim server status --url http://127.0.0.1:8010 --json
fastsim run run.yaml --launch-profile headless-physics --duration 60 --timeout 30 --json
fastsim run run.yaml --lock run.lock --duration 60 --timeout 30 --json

Developing plugins

Official and shared plugin packages live in the separate FastSim-Plugins repository. It contains packaging conventions, a minimal plugin template, producer utilities, and conformance tooling. A plugin is a normal Python distribution with:

  1. a fastsim-component/2 manifest and registry index;
  2. a factory registered in the fastsim.plugins entry-point group, with the exact name and module:attribute value declared by that manifest;
  3. lifecycle hooks implementing the fastsim-plugin-runtime/1 SPI;
  4. focused tests plus FastSim conformance checks.

Start with the repository's Adding a plugin guide and copy its minimal template rather than creating packaging metadata by hand.

The standalone FastSim-RuleBased-TestRepo contains the three-level Chinese developer guide, the general Agent skill for plugin authoring, a real installable reference plugin, and Rule-based acceptance code. It demonstrates coherent geometry/joint capture, plugin-owned planning, and joint-chunk submission; it is not the production Rule-based task implementation.

Development and verification

bash
python -m pip install -e '.[dev]'
python -m pytest
python -m ruff check src tests
python -m ruff format --check src tests
python -m build

Useful focused checks while editing configuration or documentation:

bash
python -m pytest tests/unit/config tests/unit/test_cli.py tests/architecture/test_readme.py
fastsim config validate examples/quickstart/run.yaml --json

Real-backend tests are separate from SDK-only tests and require the corresponding provider, native simulator, GPU/display when applicable, and explicit opt-in. A unit test passing does not imply that every backend capability has been exercised.

Release checklist

Before publishing an alpha revision:

  1. Run the full source test suite on supported Python versions.
  2. Build wheel and source distribution, install the wheel in a clean environment, and rerun package/CLI smoke tests.
  3. Run the relevant real backend gates visibly unless the gate is explicitly a headless performance test.
  4. Verify lock/resource integrity and plugin conformance for release candidates.
  5. Record exact FastSim, UniRoboSim core, provider, simulator, driver, asset, and seed versions with the evidence.

Current limitations

  • This is an alpha contract, not a stable 1.0 API.
  • Legacy FastSim configuration and imports are intentionally unsupported.
  • FastSim Core does not include task/action semantics, a planner, model inference, teleoperation device drivers, recording/replay, TUI, Web, debug, HTTP, or MCP implementations. Each requires an installed plugin; consult that plugin's own release status rather than inferring it from Core support.
  • The current application facade owns one world per process. Environment-level vectorization is not a Core feature.
  • Backend selection is unified; asset support, physics fidelity, rendering, sensors, fluids, deformables, and performance remain provider capabilities.
  • Current Runtime lowering accepts environment, rigid-object, articulation, robot, procedural surface-deformable, particle-fluid, and supported camera-sensor entities. Volume-deformable and light lowering, plus named sensor rates, are not implemented yet; scale constraints depend on the entity kind, asset form, and provider capability.
  • fastsim doctor does not yet probe native backend health.
  • License metadata is currently LicenseRef-Pending; public source availability is not a declaration of an open-source license.