01 · One pipeline, three forges
Every proposal goes through one router.
Agents produce proposals without knowing the forge. A router picks
the client for each repository from your configuration, and a
proposal is only published to a repository the configuration
positively names. Anything unmatched is refused at emission,
and the GitLab client refuses repositories configured for another
forge.
The same rule holds on every forge: the assistant opens drafts and
never merges them.
02 · The usual way in
A kubeconfig, and a network path to the API server.
A tool that reads a cluster normally needs a kubeconfig with
long-lived credentials, and a route to the API server: a public
endpoint, a VPN, or an allowlisted static egress address on the
tool's side.
For a customer cluster behind a VPN, that is a firewall change and
a credential to rotate, per cluster.
03 · Through the GitLab agent
The cluster dials out. Nothing dials in.
The GitLab agent (agentk) runs inside the cluster and
keeps an outbound connection to GitLab's agent server (KAS). The
assistant talks to KAS's Kubernetes proxy with a GitLab token scoped
to k8s_proxy, and builds its kubeconfig in memory.
No inbound port, no VPN, no kubeconfig file. Access is granted in
the agent's config file in git, to a project or group the bot
belongs to.
04 · What it may do, in git
The bot's cluster role is a file you review.
On GitLab CE every proxied request runs as the agent's service
account, so the agent's RBAC is the assistant's access. It
is read-only by contract, plus a few narrow, separately bound
extras such as requesting a Flux reconcile.
That RBAC file lives in your deployment repo. The assistant checks
it for drift, and any change the assistant itself proposes to it
is escalated to human review before an MR is opened.
05 · Keep the path up
Two agent replicas, two zones, one disruption budget.
If both agent replicas land on one node, a single spot reclaim or
drain takes the whole KAS context down: your CI deploys and the
assistant's reads together. The baseline pins zone and host spread
and a PodDisruptionBudget, which the chart has no value for.
06 · Review the forge itself
Branch protection, CI secrets, the runner fleet.
Three deterministic reviewers read GitLab through a GET-only
client: project access and branch protection, the merged CI
configuration of every project, and the runners each project can
use. No LLM is involved.
When the bot's own role cannot see an endpoint, it files one
"could not review" advisory. A blind review is never reported as a
clean one.
07 · GitHub In development
Draft pull requests, same rules.
The GitHub client reads repositories, pull requests and history,
and writes draft pull requests. Writing needs an explicit write
token, a writable repository row and a positive config match;
without all of them it makes no HTTP call at all.
It is built and tested, and waiting for its first live write.
Known gaps: marking a PR ready and assigning reviewers.
08 · Forgejo In development
Read path proven. Writes next.
A Forgejo repository is read through the same reader as GitHub,
with a thin dialect for Forgejo's API. At the same commit it
returns byte-identical files to a local clone, and a large tree it
cannot page through reads as incomplete, never as complete.
Planned, not built: draft pull requests. Forgejo marks drafts by a
WIP: title prefix, so the writer reads the PR back and
closes it if it did not come out as a draft.
09 · The proposal
A one-line CI fix, found by the forge review.
Most forge findings are issues: a committed secret needs rotating,
not a diff. One is mechanical: CI_DEBUG_TRACE left on,
which prints every masked variable into the job log. When the
setting is verbatim in the project's own
.gitlab-ci.yml, you get a draft MR. The full MR is
below.