Skip to content

Manage streams

Load streams attached or kept, choose which stream in a project to run, and stop, start and remove them.

Every stream runs inside the machine’s runtime. The tatolab CLI asks the runtime to load, stop and forget streams; it never runs a stream itself. This page covers those commands, and the difference between an attached stream and a kept one.

Command What happens Use it when
tatolab dev Loads the stream attached, and loads it again every time you save a .py file or pyproject.toml in the project You’re writing or changing the stream
tatolab run Loads the stream attached, once You want to run it for a while and watch its log
tatolab run -d Hands the stream to the runtime to keep, and returns It should keep running on its own

All three run from the project folder and use the project’s .venv. The stream’s log records print in your terminal for dev and run.

An attached stream lives as long as the command that loaded it. Press Ctrl-C, close the terminal, or kill the command, and the runtime stops the stream. If the runtime itself goes down, run exits with an error that says so; dev waits for the runtime to come back and loads the stream again.

A kept stream belongs to the machine. The runtime writes a record of it to its state folder: the graph your stream function built, the project’s Python environment, and the exposure of each port. It loads the stream again every time the runtime starts: at login, at boot, and after a crash. If you built from source, the runtime is the tatolabd in your terminal, so kept streams come back when you start it again.

Terminal window
tatolab run -d
Output
motion_watcher kept (project /home/you/motion-watcher)

By default, run and dev load the one function decorated with @stream in the project’s stream.py. To load something else:

You want Run
One of several streams in stream.py tatolab run stream.py:recorder
A stream in another file tatolab run cameras.py:front_door, or tatolab run -f cameras.py if it has only one
A stream from an installed package tatolab run acme_streams.rover:camera_rig
A project in another folder tatolab run --dir ~/projects/motion-watcher
The same stream under another name tatolab run --name motion_watcher_test

--dir sets the project folder, where the runtime looks for .venv. It defaults to the current folder, and doesn’t search parent folders.

A stream’s name is its function’s name, made URL-safe, unless you pass --name. Names are unique on a machine: loading a second stream with a name already in use is refused, and the message says which project has it.

Terminal window
tatolab streams
Output
NAME STATE NODES PROJECT
motion_watcher kept 6 /home/you/motion-watcher
front_door attached 4 /home/you/cameras
garage stopped - /home/you/cameras
State Means
attached Running, and lives as long as the command that loaded it
kept Running, and the runtime loads it again whenever it starts
stopped A kept stream you stopped. It stays stopped, across restarts too, until you start it.
failed A kept stream the runtime stopped loading. The reason is printed below the table.
Terminal window
tatolab stop garage # unload it; a kept stream stays stopped until you start it
tatolab start garage # load a stopped stream again, or retry a failed one
tatolab rm garage # unload it and forget it

stop on an attached stream ends it, the same as pressing Ctrl-C in its terminal. rm is the only command that makes the runtime forget a kept stream.

The runtime keeps the graph from the moment you ran tatolab run -d. Editing the project afterwards doesn’t change the running stream, and neither do changes an agent makes to the live graph: after a restart, the runtime loads the recorded graph.

To pick up changes, run tatolab run -d again from the project folder. For the same project and stream function, that replaces the record with the new version.

A kept stream holds its name even while it’s stopped, so to work on one with tatolab dev, remove it first (tatolab rm motion_watcher), and tatolab run -d again when you’re done. Or run the development copy under another name (tatolab dev --name motion_watcher_dev), as long as the copy doesn’t need a device the kept stream has open, such as a camera.

A kept stream is marked failed, and skipped when the runtime starts, when:

  • it was involved in the runtime’s last two crashes in a row (a clean stop or restart of the runtime resets the count), or
  • it can’t be loaded at all, for example because its project’s .venv was deleted.

Every other stream still starts. tatolab streams shows the reason:

garage failed: <the reason>. `tatolab start garage` retries it, `tatolab rm garage` forgets it.

Fix the cause, then tatolab start garage.

tatolab dev watches the project’s .py files and pyproject.toml. After each save:

  • the runtime runs your stream function again in the project’s .venv;
  • if that works, it replaces the running stream with the new one;
  • if it fails, for example a syntax error in stream.py or a node module, the error prints and the previous version keeps running until a save that works. If no version has run yet, dev prints no stream is loaded — fix it and save again.

Errors that happen once the stream is running, like a GLSL mistake in an effect’s setup, appear in the stream’s log, in the same terminal.

Every command on this page needs the runtime running. Without it, each one stops at once:

error: no runtime is running on this machine: nothing answers at /run/user/1000/streamlib/local-api.sock. Start one by running `tatolabd` in a terminal.

How the runtime starts depends on how you installed it: the Tatolab app on a Mac, a systemd user service on Linux, or tatolabd in a terminal for a source build. See Install.