Application and service clients
import asyncio
import fastsim
async def main() -> None:
async with fastsim.app("run.yaml") as simulation:
await simulation.start()
snapshot = await simulation.state()
targets = await simulation.control.targets()
print(snapshot, targets)
asyncio.run(main())
The context guarantees final close, but application code still handles start, Operation results, cancellation, and timeout explicitly. Never extract a native backend object and mutate it from another thread.
Capability clients expose stable service boundaries:
scene: catalog, state, and controlled pose/drag/attach operations.frames: frame catalog, lookup, and transforms.geometry: planning-geometry capabilities, catalogs, transforms, and resources.kinematics: queries through an available solver.control: target discovery, joint/track chunks, status, and cancellation.visualization: debug primitives, metrics, and events.- checkpoint, camera, and output clients appear according to Run capabilities.
Discover capabilities and targets before calling optional features. Missing optional capability is explicit—not a reason to catch every exception and continue.
The API is asynchronous, but one authority boundary still serializes backend ownership. A timeout limits caller waiting and does not automatically cancel an Operation. Simple scripts may use synchronous FastSimRun; services and UIs should retain the async Application.
Current signatures are generated in the Python SDK.
Capability-first application code
Lifecycle and Run identity are common, while Scene, Frame, Geometry, Camera, Kinematics, Visualization, Control, and Output depend on the compiled Plan and Provider. Discover descriptors and control targets before starting UI or workers. Treat service-unavailable, invalid request, stale generation, capacity, and Provider failures as different conditions rather than catching every exception as “no data.”
Snapshots and service responses are immutable values carrying run, generation, revision, or tick identity. Scene changes and control commands use service methods; mutating a returned value does not change the backend world.
Operations and structured shutdown
Keep each accepted Operation with its run/generation identity. A wait timeout only ends that wait; decide whether to query again or request cancellation, observe the terminal result, and release it. Subscriptions and workers belong to the Application scope and must stop before close. Never pass the Application or a native backend handle into arbitrary worker threads.
Use CLI for one-shot validation and deployment, Python for in-process composition, and Server for browsers or remote clients. All three should converge on the same Application rather than implementing separate simulation state machines.