← All churts

uBix Core 0.38 — A Second Reader on Every Merge Request

uBix Core 0.38 — A Second Reader on Every Merge Request

Why a Second Reader

uBix Core’s quality gate catches everything a machine can check: lint, types, tests. What it can’t see is the kind of mistake that compiles fine. A handler that takes its route parameter the wrong way. A money amount stored as a float. A browser call to a helper that only works on the server. On Sowing.me, each of those has cost us at least once.

Most of us already review with an AI on our own machines. What was missing was a reader that runs in the pipeline, on every merge request, whoever opened it.

What 0.38 Adds

git diff "$CI_MERGE_REQUEST_DIFF_BASE_SHA" HEAD | bin/ubix ci:aiReview --guide=bin/ci/ai-review-guide.md

ci:aiReview sends the MR’s diff to Google’s Gemini with two sets of instructions. The framework’s are generic: real bugs and security first, missing tests next, and no style nits, because the gate already does those. The project’s are its own conventions file: the rules that have bitten that product. The answer goes on the MR as one note, replaced on every push, so a branch pushed ten times still has a single review to read.

It is advisory by design. The job never blocks a merge, and it never approves anything. With no API key it skips green. A rate limit or a refusal shows in the job log, and nothing is posted to the MR.

The Honest Trade-off

The free tier of Gemini’s API costs nothing because Google keeps what you send to improve its models. For a project that keeps credentials in uBix Vault rather than in the repo, that’s a trade I’m comfortable making, and each project chooses which paths leave the building. Sowing.me sends its code and keeps its infrastructure notes out. If your code can’t be shared, pay for the tier that doesn’t train, or don’t wire this up at all.

The full wiring (API key, a Reporter token, two CI variables, one job) is in uBix Core’s docs/standards/ai-review-in-ci.md.

Update: 0.40, and a Human Has the Last Word

A second reader is only half of review. uBix Core 0.40 adds ci:requireApproval, a pipeline job that fails until the merge request carries a human sign-off: the Approve button, or a 👍. With GitLab’s Pipelines must succeed setting turned on, nothing merges without one.

GitLab’s own approval rules would have been the obvious tool, but they need a paid tier. They also can’t cope with how I actually work: the agents I build with open their merge requests under my account, and an author can’t approve their own MR, so with those rules nothing would ever merge. The job lets a named owner sign off on their own MR instead, and writes that into the log so a pushed-through merge is on the record. The agents themselves are told never to click it. It’s a guard against merging in a hurry, not a lock, and the standard says so plainly.

The first release also had a bug the second one fixes: the review shared an HTTP client with a five-second timeout, and no model reads a whole diff in five seconds. The note-to-self is the same one as always: green tests didn’t catch it, a real run did.

Update: 0.42, and the Click Is Enough

0.40 had one rough edge: GitLab doesn’t re-run a pipeline when you approve, so after clicking Approve you also had to click Retry on the sign-off job. uBix Core 0.42 removes that. It ships uBixOps, a small operations app that lives inside the framework. A GitLab webhook tells it when a merge request is approved or un-approved, and it retries just that one job. Not the whole pipeline, which would re-run every check and the AI review for each click.

It’s deliberately not part of any product. One instance serves every project on the GitLab server, it holds tokens that have no business sitting next to a product’s payment data, and it ships as a public image and a Helm chart. Anyone running uBix Core deploys it exactly the way I do.

← All churts