---
title: "6. Keep it running"
description: "Hand both streams to the runtime with tatolab run -d, so they keep running after you close the terminals and come back after a restart."
type: "docs-page"
url: "https://tatolab.com/docs/tutorial/keep-running"
site: "Tatolab"
section: "Tutorial"
---

# 6. Keep it running

> Hand both streams to the runtime with tatolab run -d, so they keep running after you close the terminals and come back after a restart.

So far each stream has lived only as long as its `tatolab dev`. That's what you want while you're editing. Once they work, you want them to keep running on their own: after you close the terminals, after you log out, after the machine restarts.

## Keep the stream

Stop both `tatolab dev` commands (Ctrl-C in each terminal). Then, in the `motion-watcher` folder:

```sh
tatolab run -d
```

```txt title="Output"
motion_watcher kept (project /home/you/motion-watcher)
```

And in the `motion-log` folder:

```sh
tatolab run -d
```

```txt title="Output"
motion_log kept (project /home/you/motion-log)
```

Each command returns at once, and the window stays open. The runtime has recorded both streams and now owns them. Close the terminals; they keep running, and `motion-events.jsonl` keeps growing.

```sh
tatolab streams
```

```txt title="Output"
NAME            STATE  NODES  PROJECT
motion_watcher  kept   3      /home/you/motion-watcher
motion_log      kept   1      /home/you/motion-log
```

The motion watcher has 4 nodes if you added the tint in step 5.

## What "kept" means

A kept stream is part of the machine's setup. The runtime records it in its state folder: the graph your stream function built, the project's Python environment, and the exposure of its ports. Every time the runtime starts, it loads the stream again: when you log in, when the machine boots, and when the runtime restarts after a crash. Both streams come back, and `motion_log`'s link connects once `motion_watcher` is running, whichever loads first.

If a kept stream keeps taking the runtime down, the runtime stops loading it: after it's involved in two crashes in a row, it's marked **failed**, and the runtime starts every other stream without it. The same happens to a kept stream that can't load at all, say because you deleted its `.venv`. `tatolab streams` shows why:

```txt title="Output"
NAME            STATE   NODES  PROJECT
motion_watcher  failed  -      /home/you/motion-watcher

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

## Manage it

```sh
tatolab logs --stream motion_watcher -f   # follow its log
tatolab stop motion_watcher               # stop it; it stays stopped, even across restarts
tatolab start motion_watcher              # start it again (or retry a failed one)
tatolab rm motion_watcher                 # stop it and forget it
```

`stop` is how you pause a kept stream without losing it. `rm` is the only command that forgets one.

## Change it

The runtime keeps the graph from the moment you ran `tatolab run -d`. Editing `stream.py` or a node afterwards doesn't change the running stream. To pick up your changes, run it again from the project folder:

```sh
tatolab run -d
```

Running `run -d` again for the same project and function replaces the record with the new version.

To go back to editing with `tatolab dev`, remove the kept stream first. A kept stream holds its name even while it's stopped, so `stop` isn't enough:

```sh
tatolab rm motion_watcher
tatolab dev
```

When you're done, `tatolab run -d` keeps the new version. Then check that `motion_log` is reading again: `tatolab graph --stream motion_log` should show its link as `wired`. If it isn't, reload it with `tatolab stop motion_log` and `tatolab start motion_log`.

Running a development copy under another name, next to the kept one (`tatolab dev --name motion_watcher_dev`), works only if the copy doesn't open the camera too: on Linux, only one stream at a time can open a camera.

## Where it runs

> **Caution: Built from source?**
>
> Nothing starts the runtime for you. Kept streams keep running after you close the terminal you ran `tatolab run -d` in, but not the one running `tatolabd`. After a reboot or a logout, start `tatolabd` again and your kept streams load with it.


The kept stream runs in the machine's runtime, which the installer set up as a service: a login item on macOS, a systemd user service on Linux. On a Linux machine you reach over `ssh`, turn on lingering (`loginctl enable-linger`) so the runtime, and your stream, keep running when nobody is logged in. [Deploy to a machine](https://tatolab.com/docs/run/deploy) covers servers and other machines without a screen.

## Next

Last step: let an AI agent see and change the running streams. [Let an agent watch](https://tatolab.com/docs/tutorial/agents).
