Menu
AkurAI-Build
publicLatest change 266a1aa21e346770b48e96f008ab6c2a5a603961 - Complete PR interfaces, isolated CI and crash-safe merge recovery by Ólafur Búi Ólafsson
# AkurAI Build
A small Git-native CI/CD system requiring Rust 1.97 or newer: one Rust binary for repositories, pipelines, Docker/native jobs, configurable Titan build workers, build matrices, logs, artifacts, protected deployments, webhooks, filterable CLI/API queries, and a responsive MiniJinja workbench.
It keeps the useful center of Jenkins, GitLab CI, GoCD, Concourse, and Woodpecker with a minimal authenticated Smart HTTP Git host, but without plugin markets, cluster control planes, or frontend frameworks.
## Foundation
AkurAI Build starts from [Bunfork](https://github.com/olibuijr/bunfork)'s proven shape:
- Rust single binary
- encrypted SQLCipher state and ordered migrations
- bounded Axum/Hyper HTTP serving
- MiniJinja templates and dependency-free Ponytail UI
- strict CSP, constant-time tokens, protected files, and hardened systemd
- digest-recorded artifacts and rollback-oriented deployment
Bunfork remains a supported artifact target; AkurAI Build replaces its unrelated vector/demo application surface with CI/CD.
## Production topology
```text
https://akurai-build.olibuijr.com
│ TLS
▼
EC2 Nginx / AkurAI-VPN
│ private 100.88.0.0/16
▼
Titan 100.88.0.9:3210
├── akurai-build-service (HTTP and execution, AKURAI_WORKERS=1)
├── Docker / BuildKit
├── encrypted SQLite
└── workspaces, cache, artifacts
```
All releases use the MCP-controlled immutable pipeline:
```text
local commit → repo_sync → run_queue(exact SHA) → unattended production deploy → persisted success
```
The self-pipeline consumes the package artifact and stages the packaged binary
for the root-owned host agent, which verifies its checksum, installs it, restarts
the service, and health-gates the result. Any failed step rolls the service back.
## Pipeline
Commit `.akurai.yml`:
```yaml
version: 1
jobs:
- name: test
image: oven/bun:1.3
network: true
run:
- bun install --frozen-lockfile
- bun test
matrix:
platform: [linux/amd64, linux/arm64]
cache: [.bun]
- name: package
needs: [test]
image: oven/bun:1.3
run: bun build src/index.ts --compile --outfile dist/app
artifacts: [dist/**]
- name: deploy
needs: [package]
executor: native
environment: production
approval: true
branches: [main]
secrets: [DEPLOY_TOKEN]
run: $AKURAI_BUILD_HOME/.local/lib/akurai-build/akurai ec2 release --mode publish --yes
```
Jobs default to depending on the previous job; set `needs: []` for an independent root. Caches are isolated by registered repository and shared by its jobs. Matrix axes expand to at most 32 variants and become `AKURAI_MATRIX_<AXIS>` variables. `platform` also selects Docker's `--platform`.
- Docker jobs run with dropped capabilities, no-new-privileges, fixed CPU/memory/PID limits, a read-only root, writable workspace/tmp, host UID/GID, and no network unless `network: true`. Linux `amd64`/`arm64` variants use Titan Docker with pinned `tonistiigi/binfmt:qemu-v10.2.3-68` QEMU registration, rechecked by every deploy. Native jobs require both the controller-wide `AKURAI_ALLOW_NATIVE=1` opt-in and a repository marked trusted by the administrator. Enable native execution only for repositories whose writers are trusted.
Declared secrets resolve only from `AKURAI_SECRET_<NAME>`, are omitted from Docker arguments, and are exact-value-redacted from retained logs. Repository writers with secret-bearing jobs are privileged because build code can intentionally transform or exfiltrate a secret.
### Pipeline build context
Every job — native and Docker — receives these variables. Pipelines **must**
use them instead of hardcoding a worker username or data root, because the
worker host and its user are deployment details that change.
| Variable | Value |
|---|---|
| `AKURAI_BUILD_ROOT` | the worker data root |
| `AKURAI_BUILD_HOSTED` | `$AKURAI_BUILD_ROOT/hosted`, where the bare Git mirrors live |
| `AKURAI_BUILD_WORKSPACE` | the job's workspace (`/workspace` inside Docker) |
| `AKURAI_BUILD_HOME` | the invoking user's home, captured before `HOME` is repointed at the per-job sandbox |
So a sibling mirror is `$AKURAI_BUILD_HOSTED/AkurAI-Framework.git` and a shared
Rust toolchain is `CARGO_HOME=$AKURAI_BUILD_HOME/.cargo`.
## Operator CLI and agent MCP
The `akurai` binary exposes service lifecycle commands (`keygen`, `migrate`, `mcp`, and `serve`) plus the `ec2` host-operations surface. Repository, run, artifact, approval, and deployment operations are exposed through the configured AkurAI Build MCP tools rather than standalone CLI subcommands. Agents use those tools and never substitute raw stdio calls.
### MCP control plane
The configured `akurai-build` stdio server exposes the full MCP-controlled workflow:
- repository registration, hosting, synchronization, rename/update/visibility, branch heads, directory trees, and bounded file blobs;
- immutable-ref pipeline validation, run queueing/querying/waiting/retrying/canceling/logs, protected-environment promotion, delivery metrics, and bounded operation-audit reads;
- cache statistics/pruning with dry-run, worker status/drain control, installation/deployment evidence, community issues/comments, diagnostics, pipeline initialization, artifact retrieval, and semantic releases.
`akurai_repo_branches` returns the exact SHA for every branch head. `akurai_repo_tree` accepts a branch or immutable commit and a directory path; `akurai_repo_blob` reads a bounded UTF-8 file at a ref and path. The maintained launch entrypoint is `deploy.sh mcp`; clients use the configured `mcp__akurai_build_*` tools rather than invoking it directly.
### Hosted Git
Hosted repositories are available at `https://akurai-build.olibuijr.com/git/<name>.git`. Smart HTTP reads and writes require the existing AkurAI Build bearer token; the token must be supplied through a protected credential helper or maintained command, never a URL, command argument, source file, or log. CI uses the local bare mirror directly, so builds do not depend on public DNS or the edge proxy.
## Push-triggered CI and Git webhooks
A successful `git push` to a hosted repository queues a pipeline run for its
default branch automatically when the pushed repository carries `.akurai.yml`;
repositories without a pipeline accept pushes silently. External forges can
additionally deliver webhooks:
Use:
```text
POST https://akurai-build.olibuijr.com/api/hooks/<repository-name>
```
Supported authentication:
- GitHub `X-Hub-Signature-256`
- Gitea `X-Gitea-Signature`
- GitLab `X-Gitlab-Token`
The secret is the protected `webhook.token`; do not expose it in commands or documentation. Push payloads supply `ref` and the immutable commit. Manual/UI/API mutations require the separate bearer API token.
## State and recovery
- A run stores its resolved immutable commit before reading `.akurai.yml`.
- Jobs execute fail-fast in dependency order; all variants of a dependency must succeed.
- Artifacts are bounded, SHA-256 recorded, copied without symlinks/traversal, and served only after authorization.
- A protected deployment records the exact upstream artifact IDs and digests before execution.
- Every Titan worker persists its status, capacity, heartbeat, current run, completed-run count, drain state, and lease expiry; restart recovery marks stale workers offline before registering the configured pool.
- The service runs as one hardened systemd unit that also executes pipelines. The protected `.akurai.yml` deployment stages the packaged binary for the root-owned `akurai-deploy.path` host agent (`deploy/host/`), which checksum-verifies, installs, restarts, health-gates, and rolls back automatically on failure.
Run evidence is the system's operational knowledge. It supports debugging and safe iteration without allowing unreviewed self-modifying code.
## Limits kept intentionally
- Titan currently runs one hardened scheduler/service with `AKURAI_WORKERS=1`; the worker pool remains configurable for deployments that explicitly provision more capacity. Each worker owns one leased run at a time, and jobs inside a run remain dependency-ordered and isolated. Linux container matrices are complete; native Windows/macOS and remote Windows-container builds wait for a signed artifact-streaming agent protocol rather than pretending remote bind mounts are portable. Object storage and provider commit-status adapters remain deferred—not stubbed.
## Development and release
Run `cargo fmt --all -- --check`, Clippy with warnings denied, and `cargo test --workspace` locally. Commit only intended paths and push to hosted Git (`https://akurai-build.olibuijr.com/git/<name>.git` with the bearer token as an `Authorization` extraHeader); the push queues the verification run automatically. Trusted Titan checkouts may alternatively publish with `akurai_repo_sync` + `akurai_run_queue`. AkurAI-Build production changes run only through this repository's `.akurai.yml`; its deploy job runs unattended after verification and packaging, so require persisted success and verify the changed behavior.
## Pull requests
Repository pages link to Pull requests for creation, browsing, bounded diff
inspection, individual reviews and the serialized merge queue. The MCP tools
`akurai_pr_list`, `akurai_pr_get`, `akurai_pr_diff`, `akurai_pr_create`,
`akurai_pr_review`, `akurai_pr_enqueue` and `akurai_merge_queue` expose the same
workflow. Reviews bind to the current head and require an independent
authenticated identity; shared automation tokens cannot supply reviews.
PR refs run through the untrusted Docker execution path. Main-branch native
execution still requires repository trust and controller opt-in.
Run Docker queue acceptance checks on TITAN with
`cargo test --lib merge_queue::tests -- --ignored --test-threads=1`.
The tests cover success, failed/skipped CI and recovery after the final Git
push but before database completion. They use a pinned disposable Debian
container and temporary repositories.