Self-hosted service
bleenco/abstruse avatar
bleenco/abstruse

Abstruse CI: a Go server that hands builds to worker nodes

Abstruse is a free and open-source CI/CD platform that tests your models and code.

962 stars103 forksGoMIT

At a glance

What is it?
Abstruse is a self-hosted CI/CD platform written in Go, split into a server, one or more workers and a database, distributed under the MIT licence. Its configuration surface is narrow and its release history is quiet, so the deciding factor is how much you are willing to run yourself.
Who is it for?
Abstruse fits teams that already run containers and MySQL and want a CI/CD platform they control, and it is a poor fit for anyone who needs a maintained distribution, a marketplace of integrations or a hosted status page.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 48 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A server process that hands work to separate worker nodes

Abstruse is split into two executables that are built from the same module, `github.com/bleenco/abstruse`. The Makefile has distinct `server` and `worker` targets, each producing a binary named `abstruse-server` and `abstruse-worker`, and the Dockerfile copies the server binary to `/usr/bin/abstruse-server` and makes it the entrypoint. The repository layout backs this up with top level `cmd/`, `server/`, `worker/`, `internal/`, `pkg/` and `pb/` directories, so the split is structural rather than a flag on one binary.

The readme describes the default configuration as a single node cluster with n workers, and says that the cluster can be extended with more nodes if necessary. The demo stack is the clearest picture of the arrangement: it runs `abstruse-server` with a single worker node `abstruse-worker` and a MySQL database. So the model is a control plane that stores pipeline state and a set of execution nodes that run the jobs, and scaling out means adding worker processes to the same deployment.

For a team this means two operational questions immediately. Where does job state live, and where does the work actually run? The demo answer is MySQL plus a separate worker container. The configuration layer pulls in `spf13/viper` for configuration and `spf13/cobra` for command line parsing, and the go.mod dependency list includes `github.com/docker/docker`, which fits a platform whose unit of execution is a container.

The demo stack comes up with one docker-compose command

The readme calls a local run the easiest way to see the status of the project, and the steps are short. You clone the repository, move into it, and bring up the compose file that lives under `configs/demo/default/`.

sh
git clone https://github.com/bleenco/abstruse.git
cd abstruse
docker-compose -f configs/demo/default/docker-compose.yml up -d

After the containers start, the readme says you should be able to open the installation wizard in your browser at `http://localhost` and finish the setup. The wizard is the first real interaction with the platform, and it runs on port 80 in the server image, which the Dockerfile exposes with `EXPOSE 80`.

If you would rather build the images yourself, the readme gives a second path that runs the same compose file after a local build.

sh
make docker
docker-compose -f configs/demo/default/docker-compose.yml up -d

There is also a hosted demo at `https://ci.abstruse.app` where you can sign in with the username `[email protected]` and the password `abstruse`. One constraint is noted there: the demo user has only read permissions and cannot add new repositories, so the hosted instance is a look, not a working installation.

Building from source needs Node.JS, yarn and go

The source build path is documented in two commands, and it is not a Go only toolchain.

sh
make install_dependencies
make

The readme warns that you need `Node.JS`, `yarn` and `go` installed, preferably the latest releases. The reason for Node.JS is visible in the Dockerfile, where a first stage builds the web interface from `./web/abstruse` using `npm install && npm run build` before the Go compile stage copies the resulting `dist` directory in. The `build` target in the Makefile chains the same set of steps: `build_ui statik protoc wire server worker`. The interface is compiled to static assets, embedded into the server binary by `statik`, and the resulting server serves it.

Development is split into three separate flows rather than one. The web interface has its own server with live reload.

sh
cd web/abstruse
yarn start

The backend has a live reload mode of its own.

sh
make dev

And there is a separate target for the worker with live reload enabled.

sh
make dev_worker

This separation tells you the intended workflow. You edit the interface and the server independently, and the worker is treated as its own process even in development.

Protobuf and gRPC carry the traffic between components

The go.mod file lists `google.golang.org/grpc` at v1.58.2 along with `github.com/grpc-ecosystem/go-grpc-middleware` and `google.golang.org/protobuf`, and the repository carries a top level `pb/` directory. The Dockerfile installs the protobuf toolchain during the build, with `apk --no-cache add git make protobuf protobuf-dev ca-certificates alpine-sdk`, and then runs code generation before compiling the server.

dockerfile
RUN make protoc && make statik && make wire && make server

That single line covers three distinct concerns. `protoc` regenerates the service stubs from the definitions in `pb/`, `statik` embeds the built interface into the binary, and `wire` produces the dependency injection code. The go.mod dependency list also includes `github.com/google/wire` at v0.5.0, so the injection wiring is generated rather than hand written.

For HTTP, the project uses `github.com/go-chi/chi` with `github.com/go-chi/cors` for CORS handling, plus `github.com/gobwas/ws` for websocket support and `github.com/gobwas/httphead` for header parsing. A `github.com/felixge/httpsnoop` entry suggests request timing or logging middleware. The practical reading is that the server exposes a REST and websocket surface to the browser while the gRPC layer handles communication with the worker side of the platform.

The database layer spans five GORM drivers

Abstruse does not lock you to one database engine. The go.mod file requires `gorm.io/gorm` at v1.25.5 together with drivers for MySQL, PostgreSQL, SQLite, ClickHouse and SQL Server. Four of those five drivers appear as separate require entries, `gorm.io/driver/mysql` v1.5.2, `gorm.io/driver/postgres` v1.5.3, `gorm.io/driver/sqlite` v1.5.4 and `gorm.io/driver/sqlserver` v1.5.2, with `gorm.io/driver/clickhouse` v0.5.1 alongside them. The demo compose file uses MySQL, but the driver set suggests the persistence layer is written against the GORM abstraction rather than one engine.

Repository integration comes from `github.com/drone/go-scm` v1.32.2, a source control client library, and `github.com/go-git/go-git/v5` v5.9.0 for working with Git repositories directly in Go. Together these two entries account for the repository side of the platform: talking to the forge API, and working with Git history.

Authentication is handled by `github.com/dgrijalva/jwt-go` and `github.com/asaskevich/govalidator`. The `jwt-go` import path carries a `+incompatible` suffix, which means it predates the module layout that would let a breaking release be tracked as a distinct major version. It is a small signal, but it tells you the auth dependency has not been modernised.

The newest tag is from 2021 while the branch moved on 2026-09-04

Maintenance status here needs two dates read separately. The last push to the default branch, `master`, was on 2026-09-04. The most recent release listed is `v2.1.0`, dated 2021-06-25, preceded by `v2.0.0` on 2021-01-19 and `v2.0.0-alpha.2` on 2021-01-05.

Those two facts sit in an odd relation. The repository is not archived, and the branch received a push in September 2026, so the code is not frozen. Yet no tag has been cut in more than five years, which means there is no published upgrade path in the form of release notes or a changelog to compare against. The documentation also states that this branch is the one for v2.0.0 or later, and that anyone looking for the Node.JS based v1.x.x version should check the v1 branch instead. So the project did have a major architectural shift, from a Node implementation to a Go one, and the Go rewrite has been the living branch since.

The consequence for an adopter is specific. You can expect the master branch to contain fixes, and you can expect the version tags to tell you very little about how far a given checkout has drifted. The Makefile stamps `GIT_COMMIT`, `UIVersion` and `BUILD_DATE` into the binary through linker flags, so a self-built binary can at least report exactly what it came from.

Where Abstruse is the wrong tool

Abstruse is aimed at self hosted operation, and the shape of the repository shows where that aim costs you. The build depends on `make protoc` and `make wire`, code generation steps that require the protobuf compiler and the wire generator installed on the build machine, or on the multi stage Dockerfile that installs them for you. That is a real dependency chain for anyone who wants to build in a controlled environment rather than pull a published image.

The go.mod file requires `go 1.21.1`, while the Dockerfile uses a `golang:1.21-alpine` base image and a `node:20-alpine` stage for the interface. Pinning to the 1.21 line means your build image and your toolchain have to agree on a Go release that is no longer the newest one available.

The readme documents a narrow set of behaviours and nothing beyond it. It does not describe pipeline syntax, how secrets are stored, how artefacts are retained, whether there is a rollback path, or how authentication is delegated to an external provider. The installation wizard is the only setup procedure described. If your requirement list includes secret encryption with a managed key, per repository permission tiers, or a documented upgrade procedure between versions, those questions are not answered by what the project publishes, and you will be reading the source to answer them. The live demo account is read only and cannot add repositories, so it cannot be used to observe the authoring and run flows either.

How the self-hosted route compares to a hosted CI service

The difference is not in the feature list, it is in who absorbs the operational work. With Abstruse, the person adopting it runs the server, runs the workers, runs the database and keeps the docker images current. The compose file in `configs/demo/default/` is the whole documented deployment recipe, and it is a demo rather than a production topology document.

Against a hosted CI service, the trade is different in three concrete ways. First, the pipeline definitions live in your repository as files in this platform rather than in a vendor's settings UI, which is the reason to choose a self hosted runner at all. Second, the execution environment is yours: workers need access to a Docker daemon, and the go.mod entry for `github.com/docker/docker` indicates the container runtime is part of the worker path. Third, upgrade work is yours too, and with the newest tag dated 2021-06-25 there is no released changelog to guide a jump between versions.

Abstruse also targets a different kind of job. Its own description calls it a platform that tests your models and code, and the topic tags include `continuous-testing`, `dockerized` and `server`. It is a general purpose build and test runner rather than a machine learning pipeline tool, despite the wording of the description.

Editorial conclusion

Abstruse fits teams that already run containers and MySQL and want a CI/CD platform they control, and it is a poor fit for anyone who needs a maintained distribution, a marketplace of integrations or a hosted status page. Before committing, check the pipeline definition format in docs/, confirm that a worker can reach your Docker daemon, and read the gap between the last push on 2026-09-04 and the newest tag, v2.1.0, dated 2021-06-25, before you depend on it for a release pipeline.

Frequently asked questions

How do I run Abstruse CI locally?

Clone the repository and start the compose file under `configs/demo/default/`, which runs `abstruse-server`, one `abstruse-worker` node and MySQL. The installation wizard then appears at `http://localhost`.

What does it take to build Abstruse from source?

You need `Node.JS`, `yarn` and `go` installed, preferably the latest releases, then run `make install_dependencies` followed by `make`. The `build` target also runs code generation for protobuf and wire before compiling the server and worker.

Which databases can Abstruse store its data in?

The dependency list pulls in GORM drivers for MySQL, PostgreSQL, SQLite, ClickHouse and SQL Server, with the demo stack using MySQL. The documented deployment is the single server and single worker plus MySQL combination.

Is Abstruse CI still maintained?

The repository is not archived and the last push to the master branch was on 2026-09-04, so commits are still landing. The most recent release tag, v2.1.0, is dated 2021-06-25, so there is no recent release notes trail to follow.

Can I try Abstruse without installing it?

There is a hosted demo at `https://ci.abstruse.app` that accepts the username `[email protected]` and the password `abstruse`. That account has read permissions only and cannot add new repositories.

Official sources

  1. bleenco/abstruse on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bleenco-abstruse.svg)](https://hysenlabs.com/projects/bleenco-abstruse)

Was this useful?