Explore the architecture, build pipeline, and technical details that make ContainifyCI work.
Here's how dunebot a real ContainifyCI project defines its entire build and CI pipeline.
package main
import (
"os"
"github.com/containifyci/engine-ci/client/pkg/build"
"github.com/containifyci/engine-ci/protos2"
)
func main() {
os.Chdir("../")
opts := build.NewGoServiceBuild("dunebot")
opts.Application = "dunebot"
opts.File = "main.go"
opts.Properties = map[string]*build.ListValue{
"goreleaser": build.NewList("true"),
}
build.Serve(opts)
}
name: Pull Request
on:
pull_request:
branches: [main]
jobs:
build:
name: Build
uses: containifyci/.github/.github/workflows/pull-request.yml@v1
secrets: inherit
name: Release
on:
push:
branches: [main]
paths-ignore: ['.github/**']
jobs:
build-and-release:
uses: containifyci/.github/.github/workflows/release.yml@v1
secrets: inherit
One Go file for your build logic. Two tiny YAML files to
connect it to GitHub Actions. The same engine-ci run command works locally and in
CI. There are no divergence and no surprises.
See the full working example at containifyci/dunebot.
| YAML Pipelines | Go Pipelines (ContainifyCI) | |
|---|---|---|
| Error detection | Runtime fails mid-build | Compile time fails before build starts |
| Testing | Manual / none | Unit tests with go test |
| IDE support | Syntax highlighting only | Full autocomplete, refactoring, go-to-definition |
| Reuse | Copy-paste snippets | Import packages, call functions |
| Debugging | Push and pray | Run locally, set breakpoints |
(.containifyci/containifyci.go)
engine-ci reads your build definition from
.containifyci/containifyci.go, compiles it into a self-contained binary, and
orchestrates containers to execute each build step in isolation. Tool versions are pinned inside
the containersa and not on the host machine.
Language support is modular. engine-java and engine-python are extensions that plug into the core. Adding support for a new language means writing a Go package that implements the build interface.
Every build runs through 7 orchestrated phases. Quality and Publish run concurrently for faster feedback.
Auto-detection picks the available runtime, or
override with the CONTAINER_RUNTIME env var.
engine-ci builds and publishes its own container images to Docker Hub. Each build step runs inside a purpose-built image with pinned tool versions. The images themselves are built by engine-ci.
Each Dockerfile is hashed at compile time. The SHA256 checksum becomes the image tag, so a rebuilt image is only pushed when the Dockerfile actually changes.
Go's go:generate extracts Dockerfile content, base image versions, and
checksums into generated Go code. There are no runtime parsing, errors caught before the
build starts.
All images are built for both linux/amd64 and linux/arm64, so
the same pipeline works on Intel and Apple Silicon machines.
Intermediate build images contain compilers and tooling. Production images are minimal (Alpine-based). Only the compiled binary and a non-root user.
| Image | Purpose | Base |
|---|---|---|
containifyci/golang-* |
Go build with linting (Alpine, Debian, CGO variants) | golang:1.25-alpine / golang:1.25 |
containifyci/maven-* |
Java & Maven builds with TestContainers | eclipse-temurin JDK |
containifyci/python-* |
Python build, lint, and packaging | python:3.14-slim-bookworm |
containifyci/sonar |
SonarCloud scanner (multi-arch) | alpine:3.20 |
All images are hosted at hub.docker.com/u/containifyci. engine-ci pulls or builds them automatically. There is no need for manual image management.
Secrets never touch disk. An in-memory key-value store with a REST API keeps credentials safe throughout the build lifecycle.
HTTP REST API: secrets live only in memory, never written to disk or in the container metadata or logs
Request signing with timestamps and nonces prevents replay attacks
mem: KV store / cmd: shell command / env:
environment variable
Per-session tokens with 1-hour expiry and constant-time comparison
Unix socket bind mounts forward your host SSH agent into build containers. This enables private repository access during builds. Platform-aware for both Linux and macOS, and available across all build types.