Skip to content

Reference

Python

Author robotics controls, record observations, and replay evidence with the tinyrobot Python SDK.

View as Markdown

The Python SDK supplies author controls, bounded execution, recording, and replay. External libraries still own inference, planning, and robot dynamics. This reference tracks the repository's main branch, not a particular PyPI release.

Install

uv add tinyrobot

Native Rerun recording requires the optional recording extra:

uv add 'tinyrobot[recording]'

Author an app

from tinyrobot import App, Number

app = App("example", title="Example", source="simulation")


@app.command(inputs={"steps": Number(default=10, min=1, max=100, integer=True)})
def run(recording, steps):
    for step in range(steps):
        recording.checkpoint()

An App declares controls and streams; a Run is supplied to each callback by the runner. Declaring an app does not start a web server or authorize hosted execution.

API reference

Signatures and descriptions below are extracted from SDK source with Griffe. They are rendered by the same TypeScript pipeline as these guides and are available through View as Markdown, site search, and /llms.txt.

tinyrobot.App

from tinyrobot import App
tinyrobot.App(id: str, *, title: str, source: str, description: str = '', limits: Limits | None = None, blueprint: Any = None)

A trusted Python author with typed commands, not a script-rerun web server.

Callbacks receive Run then keyword arguments matching their controls. Each invocation must initialize its own simulator/model state. External libraries own inference, IK, planning and dynamics. No callback or import path is sent to clients; hosted execution needs a separately reviewed, pinned recipe.

View source

tinyrobot.App.command

tinyrobot.App.command(*, inputs: Mapping[str, Control] | None = None, id: str | None = None, label: str = '', description: str = '') -> Callable[[Callable[..., None]], Callable[..., None]]

Register a button and its bounded controls. Missing values use defaults.

View source

tinyrobot.App.descriptor

tinyrobot.App.descriptor() -> dict[str, Any]

View source

tinyrobot.App.descriptor_bytes

tinyrobot.App.descriptor_bytes() -> bytes

Freeze declarations and return exact bytes used for descriptorSha256.

View source

tinyrobot.App.digest

tinyrobot.App.digest: str

View source

tinyrobot.App.invoke

tinyrobot.App.invoke(request: object, *, output: str | Path, cancel: threading.Event | None = None) -> dict[str, Any]

Single-flight execution; reject concurrent calls, never queue/retry.

Cancellation is cooperative inside Python. Hosts must terminate hung processes; hosted jobs additionally require provider-confirmed cleanup. Use requestId to ignore stale UI responses after reset/cancel/navigation.

View source

tinyrobot.App.request

tinyrobot.App.request(command: str, *, request_id: str | None = None, **values: Value) -> dict[str, Any]

Make an invocation with validated defaults (no execution).

View source

tinyrobot.App.run

tinyrobot.App.run(command: str, *, output: str | Path, **values: Value) -> dict[str, Any]

Run locally into a NEW directory; never upload or publish anything.

View source

tinyrobot.App.stream

tinyrobot.App.stream(path: str, *, kind: Literal['scalar', 'visual'] = 'visual', role: Role = 'diagnostic', source: str | None = None, unit: str = '', timeline: str = 'step', time_kind: Literal['sequence', 'duration'] = 'sequence') -> Stream

Declare one output; chart-only apps need no robot, camera or geometry.

View source

tinyrobot.app.Role

from tinyrobot.app import Role
type tinyrobot.app.Role = Literal['observed', 'simulated', 'predicted', 'diagnostic', 'action']

View source

tinyrobot.Capture

from tinyrobot import Capture
tinyrobot.Capture(output: str | Path, *, title: str, source: str, target: str = 'unknown', question: str = '', limits: Limits | None = None, kind: str = 'capture', source_format: str = 'native-rerun', source_version: str | None = None, adapter: str | None = None, source_files: list[dict[str, Any]] | None = None, notes: str = '', config: dict[str, Any] | None = None)

Local capture only. Closing stops recording, NEVER the external hardware.

Use as a context manager. Declare clocks/streams before the first log. Native archetypes own data; metadata describes clocks/semantics, not a scene graph. Bounds are cooperative: one native log can allocate before a checkpoint. No App, executable author, inferred action interval, or execution attestation.

View source

tinyrobot.Capture.enter

tinyrobot.Capture.__enter__() -> Capture

View source

tinyrobot.Capture.exit

tinyrobot.Capture.__exit__(exc_type: type[BaseException] | None, exc: BaseException | None, tb: TracebackType | None) -> None

View source

tinyrobot.Capture.checkpoint

tinyrobot.Capture.checkpoint() -> None

View source

tinyrobot.Capture.clock

tinyrobot.Capture.clock(id: str, *, kind: str = 'duration', unit: str = 's', origin: str = 'unknown', source: str | None = None, derivation: str | None = None, synchronization: str = 'unknown', uncertainty_seconds: float | None = None) -> str

View source

tinyrobot.Capture.diagnostic

tinyrobot.Capture.diagnostic(code: str, message: str, *, severity: str = 'warning') -> None

View source

tinyrobot.Capture.finish

tinyrobot.Capture.finish() -> dict[str, Any]

Commit evidence.json last; failed captures are removed, not replayable.

View source

tinyrobot.Capture.log

tinyrobot.Capture.log(stream: str, *archetypes: Any, times: dict[str, float]) -> None

View source

tinyrobot.Capture.metric

tinyrobot.Capture.metric(id: str, value: float | None, *, unit: str | None, method: str, source: str, reason: str | None = None) -> None

View source

tinyrobot.Capture.scalar

tinyrobot.Capture.scalar(stream: str, value: float | None, *, times: dict[str, float]) -> None

None is a native Clear (never zero or a forward-filled measurement).

View source

tinyrobot.Capture.stream

tinyrobot.Capture.stream(path: str, *, role: str = 'unknown', meaning: str = 'unknown', unit: str | None = None, clock: str | None = None, source: str | None = None) -> str

View source

tinyrobot.Choice

from tinyrobot import Choice
tinyrobot.Choice(*, options: tuple[str, ...], default: str, label: str = '', description: str = '')

One value from a fixed allowlist, never a path, model URL or code selector.

View source

tinyrobot.Choice.default

tinyrobot.Choice.default: str

View source

tinyrobot.Choice.description

tinyrobot.Choice.description: str = ''

View source

tinyrobot.Choice.label

tinyrobot.Choice.label: str = ''

View source

tinyrobot.Choice.options

tinyrobot.Choice.options: tuple[str, ...]

View source

tinyrobot.controls.Control

from tinyrobot.controls import Control
type tinyrobot.controls.Control = Number | Choice | MultiChoice | Toggle

View source

tinyrobot.controls.Value

from tinyrobot.controls import Value
type tinyrobot.controls.Value = float | int | str | bool | list[str]

View source

tinyrobot.evidence_request

from tinyrobot import evidence_request
tinyrobot.evidence_request(directory: str | Path, namespace_id: str) -> dict[str, Any]

Build a bounded HTTP import body locally; never upload or claim server trust.

View source

tinyrobot.geometry.depth_points

from tinyrobot.geometry import depth_points
tinyrobot.geometry.depth_points(depth: npt.ArrayLike, image_from_camera: npt.ArrayLike, *, units_per_meter: float = 1000, stride: int = 1) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.int64]]

Project calibrated depth to camera-frame meters and matching (row, col).

Uses integer pixel centers and a 3x3 pinhole intrinsic matrix. Invalid/zero depth is omitted. Coordinates are right/down/forward (RDF); log native Rerun ViewCoordinates/Pinhole/Transform3D when relating this to a world frame. This does not infer calibration, undistort a lens or estimate a camera pose. Native rr.DepthImage(meter=units_per_meter) + rr.Pinhole is preferable when callers only need depth visualization, rather than explicit point arrays.

View source

tinyrobot.geometry.meters

from tinyrobot.geometry import meters
tinyrobot.geometry.meters(value: Any, *, unit: Literal['m', 'cm', 'mm']) -> Any

Convert scalar/array visualization positions once at the boundary.

View source

tinyrobot.lerobot.import_lerobot

from tinyrobot.lerobot import import_lerobot
tinyrobot.lerobot.import_lerobot(directory: str | Path, *, episode: int, output: str | Path, timestamp_policy: str = 'source', title: str = 'LeRobot numeric episode') -> dict[str, Any]

Import one explicit offline episode, never a new hardware trial.

source preserves the source-reported display timeline; nominal_fps uses a separate derived display clock. Both retain source timestamps/indices and nulls in native RRD. Neither proves timing, execution or policy quality.

View source

tinyrobot.Limits

from tinyrobot import Limits
tinyrobot.Limits(*, seconds: float = 60, max_samples: int = 10000, max_bytes: int = 16 * 1024 * 1024)

Cooperative bounds; runner process/provider deadlines are the hard backstop.

View source

tinyrobot.Limits.descriptor

tinyrobot.Limits.descriptor() -> dict[str, Any]

View source

tinyrobot.Limits.max_bytes

tinyrobot.Limits.max_bytes: int = 16 * 1024 * 1024

View source

tinyrobot.Limits.max_samples

tinyrobot.Limits.max_samples: int = 10000

View source

tinyrobot.Limits.seconds

tinyrobot.Limits.seconds: float = 60

View source

tinyrobot.MultiChoice

from tinyrobot import MultiChoice
tinyrobot.MultiChoice(*, options: tuple[str, ...], default: tuple[str, ...], min: int = 1, max: int = 64, label: str = '', description: str = '')

A bounded subset of a fixed allowlist; selection order is meaningful.

View source

tinyrobot.MultiChoice.default

tinyrobot.MultiChoice.default: tuple[str, ...]

View source

tinyrobot.MultiChoice.description

tinyrobot.MultiChoice.description: str = ''

View source

tinyrobot.MultiChoice.label

tinyrobot.MultiChoice.label: str = ''

View source

tinyrobot.MultiChoice.max

tinyrobot.MultiChoice.max: int = 64

View source

tinyrobot.MultiChoice.min

tinyrobot.MultiChoice.min: int = 1

View source

tinyrobot.MultiChoice.options

tinyrobot.MultiChoice.options: tuple[str, ...]

View source

tinyrobot.Number

from tinyrobot import Number
tinyrobot.Number(*, default: float, min: float, max: float, step: float = 1, integer: bool = False, unit: str = '', label: str = '', description: str = '')

A finite bounded slider/number input; integer=True preserves Python ints.

View source

tinyrobot.Number.default

tinyrobot.Number.default: float

View source

tinyrobot.Number.description

tinyrobot.Number.description: str = ''

View source

tinyrobot.Number.integer

tinyrobot.Number.integer: bool = False

View source

tinyrobot.Number.label

tinyrobot.Number.label: str = ''

View source

tinyrobot.Number.max

tinyrobot.Number.max: float

View source

tinyrobot.Number.min

tinyrobot.Number.min: float

View source

tinyrobot.Number.step

tinyrobot.Number.step: float = 1

View source

tinyrobot.Number.unit

tinyrobot.Number.unit: str = ''

View source

tinyrobot.replay

from tinyrobot import replay
tinyrobot.replay(directory: str | Path) -> dict[str, Any]

Verify an immutable local bundle without importing the author or Rerun.

Return data only. No callbacks, compute, publication or network access. The returned recording filename is relative to the already trusted directory.

View source

tinyrobot.replay_evidence

from tinyrobot import replay_evidence
tinyrobot.replay_evidence(directory: str | Path) -> dict[str, Any]

Verify a headless bundle, without loading Rerun, an author or a reader.

View source

tinyrobot.Run

from tinyrobot import Run
tinyrobot.Run(app: App, request: dict[str, Any], output: Path, cancel: threading.Event)

One independent command/recording, owned by its callback thread.

with run.at(step): synchronizes outputs without repeating clocks. Stream declarations supply roles/units/source. Out-of-order samples are valid. Every native log resets clocks so independent sensors/predictions never inherit time. checkpoint() should also be called inside long inference/simulation loops.

View source

tinyrobot.Run.at

tinyrobot.Run.at(step: float | None = None, **times: float) -> Iterator[None]

Use step by default, or named sensor clocks: at(elapsed=0.1).

Nested contexts replace rather than inherit clocks. Sequence streams require integers; duration streams use seconds. No wall-clock inference.

View source

tinyrobot.Run.checkpoint

tinyrobot.Run.checkpoint() -> None

Check cancellation, timeout, sample and flushed RRD byte budgets.

View source

tinyrobot.Run.clear

tinyrobot.Run.clear(stream: Stream, *, at: float | None = None) -> None

Explicitly clear stale geometry at a sample time (recursive native Clear).

View source

tinyrobot.Run.log

tinyrobot.Run.log(stream: Stream, *archetypes: Any, at: float | None = None, static: bool = False, interval: tuple[float, float] | None = None) -> None

Log native Rerun geometry/images/transforms/plots. No scene graph DSL.

Actions require the application interval, in the stream's time units. Predicted streams require a prediction context and target time; geometry is never silently relabeled as observed or simulated.

View source

tinyrobot.Run.prediction

tinyrobot.Run.prediction(*, origin: float, candidate: str) -> Iterator[None]

Retain forecast origin and horizon separately from target/sample time.

View source

tinyrobot.Run.scalar

tinyrobot.Run.scalar(stream: Stream, value: float, *, at: float | None = None, interval: tuple[float, float] | None = None) -> None

Convenient finite scalar; units, role and source live on the stream.

View source

tinyrobot.Stream

from tinyrobot import Stream
tinyrobot.Stream(path: str, kind: Literal['scalar', 'visual'], role: Role, source: str, unit: str, timeline: str, time_kind: Literal['sequence', 'duration'])

Semantics declared once. Native Rerun archetypes still own visual data.

View source

tinyrobot.Stream.descriptor

tinyrobot.Stream.descriptor() -> dict[str, Any]

View source

tinyrobot.Stream.kind

tinyrobot.Stream.kind: Literal['scalar', 'visual']

View source

tinyrobot.Stream.path

tinyrobot.Stream.path: str

View source

tinyrobot.Stream.role

tinyrobot.Stream.role: Role

View source

tinyrobot.Stream.source

tinyrobot.Stream.source: str

View source

tinyrobot.Stream.time_kind

tinyrobot.Stream.time_kind: Literal['sequence', 'duration']

View source

tinyrobot.Stream.timeline

tinyrobot.Stream.timeline: str

View source

tinyrobot.Stream.unit

tinyrobot.Stream.unit: str

View source

tinyrobot.Toggle

from tinyrobot import Toggle
tinyrobot.Toggle(*, default: bool = False, label: str = '', description: str = '')

View source

tinyrobot.Toggle.default

tinyrobot.Toggle.default: bool = False

View source

tinyrobot.Toggle.description

tinyrobot.Toggle.description: str = ''

View source

tinyrobot.Toggle.label

tinyrobot.Toggle.label: str = ''

View source