RiverRoot
A small self-hosted CI server in Go that runs each pipeline step on the host or in a container, and shows the builds in a dashboard.
- Context
- Personal learning project. It started as Mini CI and was renamed and rebuilt as RiverRoot.
- Stack
- Go 1.26, Docker Go SDK, SQLite, YAML pipeline definitions, an embedded HTML dashboard.
- Role
- Sole author
- Repository
- github.com/HeyItWorked/RiverRoot (Public)

At a glance
What it is
RiverRoot is a continuous integration server small enough to read in one sitting. I wrote it to understand what happens between a push and a green check.
You describe the steps in pipeline.yaml. Triggering a build, from the dashboard or with POST /builds, runs each step as a host process or inside a Docker container and saves the result with its output in SQLite.
What is implemented
- Steps run in order; consecutive steps marked
parallelrun together as one batch. - A step with an image runs in a Docker container through the Go SDK, with the repository mounted at
/workspace. Other steps run throughbashon the host. Every step gets a five-minute timeout. - The build stops at the first failure, and a step that could not start is recorded separately from one that ran and failed.
- Builds and their steps are saved in SQLite, one transaction per build.
- A REST API (
GET /builds,GET /builds/{id},POST /builds) and a dashboard embedded in the same binary. Demo mode seeds example builds and turns offPOST /builds. - Built and tested, but not yet started by the server: a Git poller that detects new commits and changed files, and a per-build log store that can follow output as it is written.
Screens

Verification
Checked on 24 Sep 2026 with Go 1.27 on macOS: go vet reports no problems, and 34 of 36 tests pass across the API, Git, pipeline, runner and store packages.
The two failing runner tests compare working directories. The command prints the temporary directory as /var/… and the test expects the resolved /private/var/…, which is the same folder through a macOS symlink. The tests need fixing, not the runner.