README.md
July 28, 2026 · View on GitHub
Tripbot loves you :robot: :heart:
This is the source code to whereisdana.today, a 24/7 interactive slow-tv art project streaming on Twitch and YouTube.
If you like it, please consider subscribing to my channel on Twitch.tv. Thanks for watching!
-Dana (dana.lol)
How it all works
There are two main components built from this repo, each running in its own container: the chatbot itself, which listens for user commands, and an overlay server for on-screen graphics. The dashcam video playback lives in its own repo (adanalife/playout); the chatbot controls it over NATS and reads the currently-playing clip over HTTP. The scene compositing and streaming to the platforms (Twitch and YouTube) is handled by OBS, which lives in its own repo (adanalife/obs) and pulls the playback output over RTSP — so the bot and video server can still be split across machines. The chatbot still controls that OBS over its WebSocket (start/stop, health watchdog). The admin UI lives in a separate private repo (adanalife/tripbot-console), and platform API calls route through a private adanalife/platform-gateway service.
The general flow of information looks like this:

For more detail, check out Tripbot, the Adventure Robot.
Developing on the host (quick start)
Day-to-day Go work happens directly on the host. You'll need:
- mise — provides the Go toolchain pinned in
.tool-versions - go-task — the task runner (
task --listshows everything)
# run the unit tests in docker (postgres included, so the DB-backed tests run)
task test
# or call go directly through mise — the repo is pure Go, so the tests run on
# the host with no extra setup; the DB-backed ones skip without postgres
mise exec -- go test ./...
mise exec -- go build ./cmd/tripbot
Running the full stack locally
The full application stack (bot + dependencies) runs on the local k3d dev
cluster managed from the infra repo —
task k8s:dev:cluster:up brings it up. See that repo's README for the cluster
lifecycle targets.
For DB-backed tests you only need postgres, which task test spins up on demand
via the docker-compose testing stack (infra/docker/docker-compose.testing.yml) — no manual setup required.
Changelog
Changelog entries are managed with towncrier. Every PR into main adds a fragment describing its user-facing change — a changelog CI check enforces this (label a PR skip-changelog for dependabot bumps, CI-only tweaks, or pure refactors that warrant no entry).
A fragment is a small markdown file in changelog.d/ named <PR-number>.<type>.md, e.g. 889.fix.md. Its contents are the entry prose (bold lead-in sentence, then detail — match the existing CHANGELOG.md style); the PR link is added automatically.
You won't know the PR number when branching, so run task changelog:add TYPE=<type> — it drops a +-prefixed placeholder (towncrier's issue-less convention, e.g. +fix.fix.md), and the changelog-number workflow renames it to <PR-number>.<type>.md on first push. No SKIP_CHANGELOG dance needed.
# scaffold one (opens $EDITOR); or just create the file by hand
task changelog:add PR=889 TYPE=fix
# preview the assembled notes
task changelog:preview
Types map to the changelog's component sections: gateway, chatbot, onscreens, playout, console, fix, deploy, ci, cleanup, misc, plus summary (a lead paragraph for the release, named +summary.summary.md — no PR number).
Releases
Releases are trunk-based: release-please maintains a standing release PR on main with the next version, computed from the conventional commits since the last release. The release PR also carries the collated changelog (built from the changelog.d/ fragments) and the bumped + re-synthed prod deploy manifests. Merging the release PR is the release: it tags vX.Y.Z, publishes the GitHub Release, kicks off the multi-arch image builds, and deploys prod (prod-1 autosyncs from main).