Metadata-Version: 2.4
Name: klein-bt
Version: 0.8.1
Summary: Lightweight CLI telemetry dashboard for BehaviorTree.CPP v4 over ZeroMQ.
Author-email: Johan Ubbink <25775970+johanubbink@users.noreply.github.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/johanubbink/klein-bt
Project-URL: Issues, https://github.com/johanubbink/klein-bt/issues
Project-URL: Changelog, https://github.com/johanubbink/klein-bt/blob/main/CHANGELOG.md
Keywords: behaviortree,behaviortree.cpp,groot,groot2,robotics,zeromq,telemetry,dashboard,visualization
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Software Development :: Debuggers
Classifier: Topic :: Software Development :: Embedded Systems
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyzmq>=25
Requires-Dist: websockets>=14
Requires-Dist: msgpack>=1.0
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: playwright; extra == "dev"
Dynamic: license-file

# klein

klein lets you watch a running BehaviorTree.CPP v4 tree live in your browser.
You see which nodes are running, succeeding or failing, plus the current
blackboard values, as the robot ticks.

![klein showing a live CrossDoor behavior tree: running nodes pulse, the blackboard updates, and the Timeline below draws each node's RUNNING spans as the robot ticks](https://raw.githubusercontent.com/johanubbink/klein-bt/main/assets/klein-demo.gif)

## Install

Install it from [PyPI](https://pypi.org/project/klein-bt/) with
[uv](https://docs.astral.sh/uv/):

```bash
uv tool install klein-bt
```

uv fetches a newer Python by itself if yours is older than the 3.10 klein
needs. [pipx](https://pipx.pypa.io) works too:

```bash
pipx install klein-bt
```

This gives you two commands: `klein-bt` (the dashboard) and `klein-bt-mock`
(a fake robot for trying it out).

## Run it

```bash
klein-bt                                          # robot on 127.0.0.1:1667
klein-bt --robot-host 10.0.0.5 --robot-port 1667  # robot somewhere else
klein-bt --port 8080 --no-browser                 # don't open a browser
klein-bt --host 0.0.0.0                           # let other machines open it
klein-bt --open run.btlog                         # a saved recording, no robot
```

| Flag              | Default     | Meaning                              |
| ----------------- | ----------- | ------------------------------------ |
| `--robot-host`    | `127.0.0.1` | IP address of the robot              |
| `--robot-port`    | `1667`      | Groot2 publisher port on the robot   |
| `--host`          | `127.0.0.1` | interface the dashboard is served on; `0.0.0.0` opens it to the network |
| `--port`          | `8080`      | port the dashboard is served on      |
| `--no-browser`    | off         | don't open the browser automatically |
| `--record-buffer` | `10m`       | how much recent history to record (`90s`, `30m`, `1h`); `0` turns recording off |
| `--open FILE`     |             | show a saved `.btlog` (and `FILE.bb.jsonl` beside it) instead of a robot |

klein opens `http://localhost:8080` for you. You can start it before the robot
is up; it keeps retrying until the robot appears.

By default only this machine can open the dashboard. To watch from another
computer (klein on the robot, the browser on your laptop), pass
`--host 0.0.0.0` and open `http://<this machine's address>:8080` there.
There is no password: anyone who can reach that port sees the live tree and
blackboard values and can download the recording. Do this only on a network
you trust, or use an SSH tunnel instead
(`ssh -L 8080:localhost:8080 robot`, then `http://localhost:8080`).

## Using the dashboard

- Node colours show status: green is SUCCESS, pulsing amber is RUNNING, red is
  FAILURE, grey is IDLE.
- Scroll to zoom and drag to pan. Click a node to fold or unfold its children.
- Press `R` to see the whole tree again, or `F` to jump to whatever is running.
- Hover a node to see its ports.
- **Layout** switches between a vertical and a horizontal tree.
- The **Blackboards** list shows every subtree's values. A value that just
  changed gets a thin amber edge that fades; a key that changes all the time
  (a position, a counter) gets a steady dim edge and a `~` instead. Click a
  row to expand it, or hover a board to find its node in the tree. See
  [docs/blackboards.md](https://github.com/johanubbink/klein-bt/blob/main/docs/blackboards.md) for how values are shown.
- Hover a key to see which nodes use it: writers outlined solid, readers
  dashed. Hover a node to ring its keys. Writers get a small amber dot when
  the key changes.
- Drag the side panel's right edge to make it wider or narrower, or fold it
  away with its `◂` button (or a double-click on the edge) for more room.
  klein remembers both.

If the robot loads a different tree, the dashboard switches to it by itself.

## Record, rewind and replay

klein records everything the robot does (BehaviorTree.CPP 4.3.3 or newer),
blackboard included, and keeps the last 10 minutes. Change that with
`--record-buffer` (`30m`, `1h`, or `0` to turn recording off). Don't log
from Groot2 against the same robot at the same time: each would get only
some of the transitions.

![klein rewinding a live robot: hover the minimap (its scrollbar shows), drag its box back, click a burst, scrub, step, hover a key, play, back to live](https://raw.githubusercontent.com/johanubbink/klein-bt/main/assets/klein-rewind.gif)

The drawer under the tree shows the recording. Its top row works in every
tab, even with the drawer folded:

- |◀ ▶| step to the previous or next transition, and ▶ plays at 1×.
  While live it reads ❚❚: press it to freeze the tree, the blackboard and
  the clock right where they are.
- The green **● Live** says you are live. In the past it turns into
  **Go live**, which takes you back; the tree gets a thin amber edge,
  and the clock beside the bar says which moment you see. Changes are marked
  in the past too: stepping or clicking shows which values just changed.
- The bar is a minimap of the recording, eight of the Timeline's windows
  long (live, now is its right edge): amber columns show how busy the robot
  was, hatched stretches are outages, and a pink dashed line marks where
  the robot started another tree. Click or drag it to go to that moment;
  hover it for the time. On the Timeline tab a box on it is the Timeline's
  window: drag it (or turn the wheel) to pan. While the pointer is over the
  bar, a thin scrollbar for the whole recording shows underneath.
- The keys: ←/→ step, Space plays or pauses, Home goes to the oldest moment
  kept, End or Esc goes live, and `\` zooms the Timeline to fit everything
  kept (also its ⤢ button).

Below it are two tabs, a filter and the recording pill:

- **Log**: every transition. Click a row to see the tree and blackboard at
  that moment.
- **Timeline**: each node's running time as bars, so every retry shows. Drag
  the playhead to go back in time; − and + change the window.
- The **Filter** beside the tabs narrows both tabs, and stepping, to the
  nodes and subtrees you name.
- **Save**, on the recording pill (`● Recording 10 min · 148 kB`),
  downloads one `.zip` with a `.btlog` per tree run (Groot2 opens these)
  and its blackboard in a `.bb.jsonl` beside it.

`klein-bt --open FILE.btlog` shows a saved recording without a robot, in the
same Log and Timeline; **Go to end** takes you to its end. Unzip a saved
`.zip` first; the `.bb.jsonl` beside the file brings its blackboard along.

## Set up your robot

klein talks to the Groot2 publisher that comes with BehaviorTree.CPP v4. If
Groot2 can connect to your robot, klein can too. If not, add a publisher after
you create the tree:

```cpp
#include "behaviortree_cpp/loggers/groot2_publisher.h"

auto tree = factory.createTreeFromFile("my_tree.xml");
BT::Groot2Publisher publisher(tree, 1667);
```

The publisher also uses the next port up (1668), so leave that one free.

## Try it without a robot

```bash
klein-bt-mock --port 1777        # in one terminal
klein-bt --robot-port 1777       # in another
```

Add `--switch-every 200` to the mock to make it swap between two trees every
20 seconds or so.

## Docs

- [docs/blackboards.md](https://github.com/johanubbink/klein-bt/blob/main/docs/blackboards.md): reading blackboard values, and
  adding a renderer for your own message types.
- [docs/architecture.md](https://github.com/johanubbink/klein-bt/blob/main/docs/architecture.md): how klein works inside.
- [docs/protocol.md](https://github.com/johanubbink/klein-bt/blob/main/docs/protocol.md): the Groot2 wire protocol klein speaks.
- [docs/testing.md](https://github.com/johanubbink/klein-bt/blob/main/docs/testing.md): the test tiers and harness, and
  `scripts/make_gifs.py`, which remakes the GIFs above.

## License

klein is released under the MIT License — see [LICENSE](https://github.com/johanubbink/klein-bt/blob/main/LICENSE).

The dashboard bundles [D3.js](https://d3js.org) v7 (ISC License, © Mike
Bostock), served locally so it works on air-gapped networks.

## Disclaimer

klein is an independent tool. It is not affiliated with, endorsed by, or
sponsored by the BehaviorTree.CPP project or the authors of Groot / Groot2.
"BehaviorTree.CPP", "Groot", and "Groot2" are the property of their respective
owners. klein interoperates over the Groot2 publisher wire protocol that is part
of the open-source, MIT-licensed BehaviorTree.CPP library; it contains no code
copied from those projects.
