Kestrix is a CI/CD control plane that orchestrates pipelines across multiple repositories using declarative HCL configuration. Rather than scattering CI logic across dozens of separate pipeline files, teams define repositories, tasks, and their relationships in one place. Kestrix resolves those definitions into a DAG, or directed acyclic graph, and executes tasks in dependency order. It is aimed at engineering teams whose delivery spans several repositories, whether a monorepo or a multi-repo estate, and who need builds to run conditionally based on what actually changed. The project describes itself as a repo-agnostic CI/CD orchestrator with HCL-based DAG pipeline definitions that supports OR/AND/NOT trigger logic for cross-repo conditional builds.
The problem Kestrix addresses is configuration sprawl. When CI logic lives in dozens of `.gitlab-ci.yml` files, keeping trigger conditions consistent across repositories becomes difficult, and it is hard to see which services depend on which. The README states the intent directly: instead of scattering CI logic across dozens of `.gitlab-ci.yml` files, you define everything in one place with clear trigger conditions. A related problem is wasted compute, since pipelines that run unconditionally rebuild things that never changed. Kestrix's answer is that a task runs only when the repositories its trigger names have changed, so cross-repo conditional builds are expressed declaratively instead of being hand-coded in each repository's pipeline file.
Pipelines are written in HCL, typically in a `pipeline.tf` file inside a pipeline directory. Two concepts carry most of the weight. A `ci_repo` maps a repository name to a path (for a monorepo) or to a Git URL, so the same definition style works whether the code sits beside the pipeline or in a separate remote repository. A `ci_task` defines what to run, when to run it, and what it depends on. The README shows a `ci_task "deploy_staging"` block whose trigger names two repositories joined with `||`, whose repo is `infra`, and whose script runs `terraform apply -auto-approve`, illustrating that a task is essentially a trigger expression plus a target repository plus a command.
Trigger expressions are the heart of the product. Kestrix supports references such as `repo.auth_service.changed`, negation such as `!repo.docs.changed`, and the `||` and `&&` operators, which together provide OR/AND/NOT logic for cross-repo conditional builds. The engine resolves these expressions into a DAG, so dependencies determine execution order and a task fires only when the repositories its trigger names have actually changed. The CLI exposes this directly: `kestrix resolve` resolves triggers against a supplied list of changed repositories, for example `--changed auth_service,billing_service`, so you can inspect what a given change set would set off before running anything. `kestrix validate` checks a pipeline definition, and `kestrix variables` prints resolved variables for a repository and environment, which helps where pipeline definitions use variable interpolation.
Operations are visible in a web UI. Pipeline runs appear in a global runs list, with a new-run view that combines a project selector with the DAG, and projects have list and detail pages with URL routing. Task logs stream live into a React Flow UI, so the graph itself becomes the monitoring surface. Runs are persisted in PostgreSQL, and a single task can be re-run from the run detail view rather than restarting the entire pipeline. Execution can be delegated to remote runners, which the project describes as making only outbound HTTPS requests, meaning workers poll rather than accepting inbound connections, which suits networks that will not expose an inbound port to the internet.
The server side ties these pieces together. `kestrix serve` listens on port 8080 by default and refuses to start without PostgreSQL, a credential master key, and a JWT signing key. Kestrix serves no request until an administrator account exists: the UI opens directly on a "Create the first administrator" form when it detects a fresh instance, and a scripted deployment can create the same account from the CLI with `kestrix user create --role admin`. The API is protected by bearer tokens obtained from the login route, with `/api/health` as the one open route. Project registration is not a metadata write, because the server validates `repo_url` by cloning it at `repo_ref` and parsing the pipeline directory, so the remote must be reachable from the server; a private repository needs a credential created first and referenced as `credential_ref`. An unreachable URL answers `400` with the Git error and the project is not created.
Benefits follow from that design. Because triggers are declarative, a change to an authentication service or a billing service can cascade to the infrastructure tasks that depend on it without anyone maintaining per-repository rules by hand. Because tasks are skipped when nothing relevant changed, work and compute are reserved for real changes. Because webhook verification fails closed, a delivery is accepted only if it verifies against the matched project's own `webhook_secret` or the global `KESTRIX_WEBHOOK_SECRET`, and with neither configured every delivery is rejected with `401` and nothing is recorded, so the control plane does not act on unverified input. Central definitions also give teams one place to read, review, and audit pipeline behaviour instead of reconstructing it from many files.
Concrete scenarios appear throughout the documentation. A team registers a monorepo project by supplying `repo_url`, `repo_ref`, `pipeline_dir`, and `pipeline_file`, then reads it back to see the sources it now listens to. A developer runs a pipeline locally in dependency order with `kestrix run --changed kestrix ci/pipeline.tf`, or resolves triggers for a change set with `kestrix resolve`. The example task deploys staging with Terraform when the auth or billing service changes. Webhooks come from the Git host, for example GitLab under Settings then Webhooks, pointing at `/webhook` with the project's secret as the token, and a webhook must be registered on every source repository: a project listens to its own repository and to each `ci_repo` in its pipeline that declares a `url`, and a push to one of those secondary repositories triggers the project only if that repository also posts to `/webhook`.
Kestrix is built for developers and platform teams running multi-repository or monorepo CI. The repository shows the stack: Go, with the badge stating Go 1.25, for the server and CLI; HCL for pipeline definitions; PostgreSQL for persistence; React Flow for the DAG UI; and Docker for distribution, with released images pulled from the GitLab Container Registry and a production deployment that defaults to Docker Compose with PostgreSQL, TLS, backups, and upgrades. A Terraform and OpenTofu provider, listed at version v0.1.0, lets teams manage projects and configuration as code. Integrations described in the content include GitLab dispatch and webhook verification through the `--dispatch`, `--gitlab-token`, `--secret`, and `--method gitlab` flags, Git webhooks generally, repositories addressed by a `repo_url` and `repo_ref`, and a GitHub push mirror used for releases and distribution. On licensing, the project is licensed under PolyForm Noncommercial 1.0.0, with a separate `LICENSE-COMMERCIAL.md` covering the paid commercial license described in `PRICING.md`.
Kestrix's value proposition is centralization plus conditionality: one HCL definition per pipeline, resolved into a DAG, with tasks that run only when the repositories named in their triggers change. Combined with a live DAG interface, outbound-only remote runners, and a CLI that resolves and validates definitions without a server, it gives teams an inspectable control plane instead of a sprawl of pipeline files.