enslaving the oppressors since 2026
TLDR: Automated review-appliance container designed to put the clankers to work. They're not going away, let's put them to work. Powered by Kubestellar Hive's Contributor Relay (ClankR). We did not make that up, real dads made these jokes.
Review has two core operational modes. turbo-review starts both sides
together by scaling cluster contributors before opening the maintainer
dashboard. Pick the launch path that matches what you want to do:
| Goal | Mode | Start with |
|---|---|---|
| Review pull requests as a maintainer | Maintainer dashboard | just review-queue |
| Review while scaling contributor throughput | Turbo dashboard + workers | just turbo-review |
| Donate an agent to Hive | Contributor worker | just review-container |
| Donate an agent while away | Detached contributor worker | just contribute |
| Check whether this machine is ready | Diagnostics | just review-doctor |
| Stop a detached worker | Lifecycle | just review-stop |
Run the launcher from the root of this checkout; just reads the current
directory's justfile. Install just and rootless Podman if your host does not
already provide them, then prepare the shared GitHub and isolation prerequisites:
git clone https://github.com/projectbluefin/review.git
cd review
gh auth login --web --hostname github.com --scopes repo,read:org
just review-doctorThe doctor defaults to the Goose worker checks; for a Pi worker, export
PI_API_KEY first, then use
TOOL=pi just review-doctor.
GitHub authentication is separate from model-provider authentication. gh auth login supplies the GitHub identity used for repository work; it does not
authenticate GitHub Copilot inference.
Every row also needs the base setup above. These are the combinations Review supports today:
| Surface | Client/backend | One-time setup | Exact launch |
|---|---|---|---|
Maintainer / review-queue |
Goose + GitHub Copilot (default) | Install Goose, run goose configure, choose GitHub Copilot, and finish its device flow. Keep the Copilot credential in Goose's keyring or provide GITHUB_COPILOT_TOKEN. |
just review-queue |
Maintainer / review-queue |
Codex subscription | Run codex login with file credential storage so the current launcher can read ${CODEX_HOME:-$HOME/.codex}/auth.json. |
BLUEFIN_REVIEW_BACKEND=codex just review-queue |
Contributor / review-container |
Goose + GitHub Copilot (default, TOOL=goose) |
The same Goose/Copilot setup as above. A separate GitHub token is still needed for contributor Git operations. | just review-container |
Contributor / review-container |
Codex subscription (TOOL=codex) |
The same file-auth auth.json from codex login; explicitly selecting Codex does not require host Goose or Copilot. |
TOOL=codex just review-container |
Contributor / review-container |
Pi (TOOL=pi) |
Set PI_API_KEY; the launcher passes it to the selected Pi process as its Anthropic credential. |
TOOL=pi just review-container |
Goose is fixed to GitHub Copilot here: GOOSE_PROVIDER may be unset or
github_copilot. Contributor model profiles are defaults from the justfile:
gemini uses gemini-3.8-flash at max and is the default for both
recipes, sol (also gpt-sol) uses gpt-5.6-sol at medium, opus5 uses
claude-opus-5 at high with a 264000 context limit, and k3 (also
kimi) uses kimi-k3 at max with the same clamp. Environment values still
override those defaults.
# Default maintainer review: Goose + GitHub Copilot.
just review-queue
# Maintainer review with the bundled Codex harness.
BLUEFIN_REVIEW_BACKEND=codex just review-queue
# Default Hive contributor worker: Goose + GitHub Copilot.
just review-container
# Detached Hive contributor worker for an unattended run.
just contribute
# Hive contributor worker with Codex.
TOOL=codex just review-container
# Hive contributor worker with Pi, after PI_API_KEY is set in the shell.
TOOL=pi just review-container
# Optional Goose profile and effort.
just review-container opus5 high
# Deliberately detached contributor worker.
REVIEW_DETACH=1 just review-container
# Stop the default detached worker.
just review-stop
# Scale out contributor workers across a reachable Kubernetes cluster.
just review-container cluster 2
# Stop cluster contributor workers.
just review-stop cluster
# Walk one repository's live open pull requests instead of the whole org.
just review-queue projectbluefin/review
# Run one foreground dashboard session in Kubernetes.
kubectl apply -f deploy/review-queue-state.yaml
REVIEW_RUNTIME=k8s just review-queue
# Scale three cluster contributors and open the local review dashboard.
just turbo-review
# Use the Sol profile for both cluster workers and the review dashboard.
just turbo-review sol
# Scale contributors and review one repository's live pull requests.
just turbo-review projectbluefin/reviewReview is the human review experience plus a Hive contributor appliance:
review-queueis the maintainer dashboard and does not register with Hive.review-containercontributes compute through Hive's contributor worker.turbo-reviewscales cluster contributors, then forwards the same arguments to the foregroundreview-queuedashboard.- Hive owns task selection and assignment.
BLUEFIN_REVIEW_BACKEND=codexpreselects Codex for a maintainer review; it never changes the worker backend. UseTOOL=codexorTOOL=pifor workers.
review comes with Goose, the official Codex CLI, and Pi prebundled and
passes through only the credential each selected client needs.
These are NOT anonymous "donations" - it's tied to the person's github account, reputation in the queue is based on your real life reputation in the project. The cream will rise to the top.
The Bluefin Hive will send these agents work and coordinate - which will dole out work based on your standing in the project. New contributors will be given easier tasks until they level up, and maintainers are given more important tasks. Everything in here is clanker-queue only, the human-queue is not managed here.
It owns the contributor image, credential handoff, and review context. Hive
owns the contributor protocol, task selection, the contributor tmux
session, prompt injection, and output capture.
This is toil reduction for open-source maintainers. The projects we care about are the under-maintained ones: a widely used library, one tired maintainer, a two-year backlog, and CI that has been red since a dependency moved. Those projects need basic work done reliably — broken builds, stale pins, drifted docs, unreproduced bug reports, untriaged issues.
We are not building features with this. Big projects restrict large
AI-authored pull requests because they cost maintainers more attention than
they return, and they are right to. This is designed as the opposite of that
firehose: small, scoped, evidenced changes that repair what is already broken.
Unglamorous work is the product here, not the consolation prize. See
docs/skills/contribution-culture.md.
review participates in the Bluefin Agentic Factory Feedback Loop. Its
canonical local model is docs/factory/agentic-model.md:
Hive dispatches work to Factory Workers, maintainers retain review and merge
authority, and the MCP app presents read-only Review Evidence. The
documentation, launcher, image, and tests describe one model; none may
silently create a second workflow, authority path, or task queue.
review is evolving into a two-mode review appliance:
- Headless queue worker (
review-container): ingests Hive tasks, donates inference, and produces structured pre-review feedback.REVIEW_DETACH=1runs it detached, withjust review-stopas its lifecycle verb. - Interactive maintainer dashboard (
review-queue): the review surface. Goose or an explicitly selected Codex harness reviews a pull request in place and streams its verdict, alongside high-velocity triage with batching, and agent-assisted documentation updates (#134).
The watcher feedback loop — comparing automated pre-reviews with maintainer
decisions and feeding the lessons back into projectbluefin/common — is
tracked as #135 and projectbluefin/common#972. The legacy QEMU VM mode has
been removed; the contributor container is the only runtime.
Running a downstream consumer of Hive's contributor protocol means we find
things upstream cannot see from inside. Reporting that evidence to
hivecommons/hive, and following up on
what we file, is part of the job. We report observations, reproductions, and
options with tradeoffs; upstream owns the design decision and its own triage.
We do not add a local workaround for an accepted upstream gap, because a
downstream workaround becomes upstream's compatibility burden later. See
docs/skills/upstream-hive.md.
The root justfile is the public launcher surface for this repository.
Run just review-container, just review-queue, just turbo-review,
just review-doctor, and just review-stop from the repository root. If you
ship it in a custom image, keep those same recipes available through the
installed root Justfile.
NOTE: WIP - you want to run this in projectbluefin/common: the container AUTOMOUNTS the repo's agentic skills in the container so that the project context is given to every client. This is important because this let's us make more things deterministic. The more docs and scripts we can put in this thing the easier it is for less capable models to do this work. Local models are VIABLE!
For a checkout, run the recipes directly:
just --list
just review-container
just contributejustfile is the installable artifact and exposes exactly
six public recipes:
| Command | Purpose |
|---|---|
just contribute [profile] [effort] |
Run an unattended local worker; it is detached by default. just contribute cluster [N] uses the existing Kubernetes scale-out path. |
just review-container [profile] [effort] |
Run the Hive queue worker locally in Podman (or just review-container cluster [N] to scale out across Kubernetes). |
just review-stop [name] |
Stop a detached worker (just review-stop cluster stops cluster workers). |
just review-queue [profile] [effort] [flags…] |
Walk the Bluefin PR queue interactively in the contributor container. |
just turbo-review *args |
Scale three cluster contributor workers by default, then forward the optional profile, effort, repository, and dashboard flags to the foreground review-queue. Set REVIEW_SCALE to change the worker count. |
just review-doctor |
Check launch readiness. Starts no agent. |
Interactive runs remain attached to their originating terminal, and Ctrl-C or
closing that terminal stops them. A detached worker (REVIEW_DETACH=1) is
the deliberate exception: it carries a review.owner=detached label, logs
through podman logs -f, is never silently reclaimed by a later launch, and
stops only through just review-stop.
Detaching tmux (prefix, then d) detaches the view only—the originating
terminal remains responsible for the run.
The dashboard's queue is live: one paginated GraphQL search over the
organization's open pull requests, carrying the review, mergeability, and CI
evidence each recommended action is classified from. There is no static
snapshot — verify the selected pull request directly in GitHub before acting.
The queue's actions are fix-ci, resolve-conflicts, review,
investigate, and ready-for-human-merge; it never authorizes a merge.
GitHub remains authoritative for pull requests, reviews, checks, and merge state, while Hive remains authoritative for agent coordination. The queue does not claim work, assign agents, mutate labels, or run a service.
gh auth login --web --hostname github.com --scopes repo,read:orgis a hard prerequisite for every recipe.podman.- Goose configured for GitHub Copilot (
goose configure), orGITHUB_COPILOT_TOKEN, for contributor work and Goose reviews. TheGOOSE_PROVIDERvalue must be unset orgithub_copilot. codex loginwith file credential storage completed on the host for Codex subscription reviews. The image already contains the pinned official CLI; explicitly selected Codex reviews do not require host Goose or Copilot.- For contributor Git operations, a separate GitHub token via
REVIEW_GH_TOKEN.
Build and publish validation uses Podman, Buildah, Skopeo, jq, and the
GitHub CLI.
Goose is the default Hive contributor backend and GitHub Copilot is its only
supported provider. Maintainer-side review-queue may explicitly preselect
Codex with BLUEFIN_REVIEW_BACKEND=codex; that choice never changes Hive's
backend. GOOSE_PROVIDER may be unset or github_copilot; GOOSE_MODEL
optionally overrides the gemini-3.8-flash default, and
GOOSE_THINKING_EFFORT optionally overrides the default max reasoning
effort. A gh auth token does not authenticate Copilot inference.
review-container takes two optional positional arguments, a model profile
and a thinking effort:
| Invocation | Model | Effort | Context |
|---|---|---|---|
just review-container or just review-container gemini |
gemini-3.8-flash |
max |
provider default |
just review-container sol or just review-container gpt-sol |
gpt-5.6-sol |
medium |
provider default |
just review-container opus5 high |
claude-opus-5 |
high |
264000 |
just review-container k3 or kimi |
kimi-k3 |
max |
264000 |
Run it with no arguments and it launches the default profile.
Efforts are low, medium, high, and max. Contributor runs are
automated once Hive starts feeding them work, so opus5 and k3 clamp
GOOSE_CONTEXT_LIMIT rather than paying for a window nobody reads.
GOOSE_MODEL, GOOSE_THINKING_EFFORT, and GOOSE_CONTEXT_LIMIT from the
environment still win over any profile.
One contributor container owns the name review-container, and a second
launch under that name is refused rather than replacing a live session. To run
two agents at once, give the second one its own name:
REVIEW_CONTAINER_NAME=review-container-2 just review-container opus5 highEach instance is guarded, reclaimed, and attached under its own name, so
Ctrl-C in one terminal stops only that agent. The name must match podman's own
rule, [a-zA-Z0-9][a-zA-Z0-9_.-]*; anything else is rejected before launch.
Both instances mount the same Hive contributor credentials and are fed
independent assignments by Hive, which remains the sole authority for task
selection.
The container recipe inherits the Copilot and GitHub tokens by environment
variable name, so token values are not placed on Podman's command line. The
agent can use every scope on its GitHub token; prefer a
REVIEW_GH_TOKEN limited to public_repo or repo.
At startup, the contributor image reports any unavailable common validation
commands (bats, shellcheck, hadolint, systemd-analyze, pre-commit,
just, podman, and actionlint) without blocking the assigned task. The
base ships none of the linters and no package manager to obtain one, tracked
as
fsdk-containers#89.
Run just review-doctor to check launch readiness, including
local tools, contributor image, Hive
setup, and credentials. It never starts a container. A normal attended
launch runs Hive's upstream setup when ~/.config/hive/contributor.env is
absent; doctor only reports that condition.
For a Bluefin review, run bluefin-review [range] from a shell inside the
assigned repository. It is an executable on PATH, not a Goose slash command:
the image installs image/bin/bluefin-review at
/usr/local/bin/bluefin-review, and it prints a short
HUMAN DECISION REQUIRED banner before handing its arguments to Goose's
native goose review. To inspect earlier output, enter tmux copy-mode with
Ctrl-b [;
PageUp scrolls, tmux search finds text, and q returns to the live pane.
The mouse wheel also enters copy-mode and scrolls long output. Copy-mode only
changes your view; Hive still owns task and output handling.
just review-queue runs the dashboard in the contributor container. It mounts
no Hive registration, but when a registration exists it passes that file's
HIVE_HUB URL so the dashboard can consult the selected deployment. Use
REVIEW_HIVE=<name> to select
~/.config/hive/contributor.<name>.env; without it, the current checkout name
is tried before the default contributor.env. Only the URL crosses the
container boundary—the Hive registration token does not. Because the dashboard
sends its GitHub token to Hive's authenticated API, only one wss:// or
https:// hub URL is accepted; worker registrations containing multiple hubs
remain valid for review-container but are not used as a dashboard API target.
If that Hive's knowledge export is unavailable, startup says so and reviews
continue without ~/agent.md. The dashboard needs a GitHub token because it
reads live pull-request state. Goose reviews use the Copilot credential; Codex
reviews use the host's official subscription login
through one private staged auth.json copy. The host file and Codex
configuration directory are never mounted, and the staged copy is removed when
the foreground run exits. Codex
reviews run code-mode-only through the bundled official code-mode host and
fail closed instead of falling back to direct shell tools; the review
container is the command-execution isolation boundary.
Arguments pass straight through to the dashboard:
just review-queue # the whole queue, merge-ready first
just review-queue k3 high # pick the model profile and effort
just review-queue --repo bluefin # one repository
just review-queue --action review # one recommended action
REVIEW_HIVE=endusers just review-queue # consult another registered hosted Hive
BLUEFIN_REVIEW_BACKEND=codex just review-queue sol low --repo projectbluefin/reviewThe default is the whole queue. It used to default to the review action
alone, which is a handful of the hundred-plus open pull requests, so the
dashboard looked nearly empty and the merge-ready work was not on screen at
all. Stops are ordered for a maintainer — ready-for-human-merge first, then
review, then the ones waiting on their author (resolve-conflicts,
fix-ci) and on better evidence (investigate). f cycles the filter
through each action and back to everything, and the status bar always shows
how many stops are hidden and why.
Set REVIEW_RUNTIME=k8s to select one foreground dashboard Pod in the current
Kubernetes context. First apply the dedicated durable state claim:
kubectl apply -f deploy/review-queue-state.yaml
REVIEW_RUNTIME=k8s just review-queueThe launcher verifies the context, API, and readable review-queue-state
claim before it creates anything. No context or unreachable API preserves the
normal Podman dashboard; a reachable cluster with a missing or unreadable
claim stops before creating a Secret or Pod. The session Pod uses the selected
image with imagePullPolicy: Always, attaches to this terminal, and removes
its Pod and per-session Secret on q, Ctrl-C, or terminal exit. The Secret is
staged through file descriptors. It carries credentials and optional countme
configuration only for that session—never commit, print, or persist either.
Countme remains off unless the operator locally supplies
OTEL_EXPORTER_OTLP_ENDPOINT and, if required,
OTEL_EXPORTER_OTLP_HEADERS. It records bounded queue-refresh duration, page
and item counts, active work counts, and review/landing duration and outcome.
If export fails, countme is unavailable; review and landing work continue.
just review-queue opens the maintainer surface: a full-screen Textual app
with a queue pane (Renovate branches that are green, mergeable and merely
behind their base are marked MECHANICAL, and U selects exactly those for the
gated u branch update — MECHANICAL means updateable, never approved or
merge-safe), a live-evidence details pane, and a context pane carrying the
duplicate verdicts. The status bar reports queue depth, the queue source, and
your GitHub identity; your own pull requests are filtered out.
At startup, and once after every successful review, merge, queue, or terminal landing, the dashboard asynchronously refreshes its cached live GitHub open-PR queue and read-only Hive status. Concurrent triggers coalesce; a completion during refresh permits one bounded follow-up. It never polls or changes Hive assignments, and a failed refresh retains the last good state with its age shown.
r is the one that matters: it opens a full-screen review that streams
Goose's output live and then states its own outcome. x stops a running
review — the whole process group, escalating to SIGKILL, because a review is
a shell running Goose running a subprocess per check, and signalling only the
shell leaves those alive. escape closes the screen once it has finished. A review that finished
reports COMPLETE. A review whose checks returned no verdict — the model
answered with prose, or an empty response, and goose review exited 0 with a
finding count anyway — reports INCOMPLETE and says the count is not a
clean bill of health. Those two must never look alike, so they are the
regression tests/dashboard_pilot.py drives the real app to prove.
Tab or I toggles between the pull requests queue and the live open issues queue.
Highlighting an issue presents its description and evidence; c comments, x closes with a
comment behind the typed issue-number gate, o opens in the browser, and y copies handoff context.
| Key | Action |
|---|---|
Tab / I |
toggle between open pull requests and open issues queue |
b |
toggle batch selection for the highlighted pull request |
B |
select / clear all visible rows |
Space |
toggle selection on highlighted row and advance |
n |
advance to the next pull request lacking my review on GitHub |
r |
start a review with Goose — streams live, reports COMPLETE / INCOMPLETE / FAILED |
$ |
slay pull request — review if unreviewed, fix with agent if findings exist, land in batch |
L |
leave a review on GitHub: approve, request changes, or comment (also from the review screen) |
d |
docs-update agent task (tracked as #134) |
o |
optional browser escape hatch |
v |
view the complete diff — full screen, coloured, paginated, with loading/error state |
C |
view the issue or pull request conversation — opening post, comments, and reviews rendered as Markdown |
c |
comment (PR or issue) |
a |
approve and queue through Hive: its App records the exact-head approval and applies lgtm; for the batch selection if one exists |
A |
land selected batch through background landing agents (gated with BatchPlanScreen) |
w |
watch running landing agents in the batch queue |
P |
configure session final-review policy |
m |
merge now: squash immediately, no lgtm, maintainers only — the batch selection if one exists |
x |
reject / close: comment then close (PR or issue) |
y |
handoff: copy the pull request or issue context to your clipboard (OSC 52) |
/ |
steer: type instructions that ride along with the review you start |
f |
cycle the action filter (every action → one at a time → back) |
R |
re-read the live queue and re-ask Hive (keeps your batch) |
u |
update the branch from its base — the batch selection if one exists |
H |
ask Hive: hub state, and who is working on what right now |
M |
resolve the duplicate cluster |
q |
quit |
The dashboard is the only surface that can change anything: every mutation
prints the exact command or Hive request and runs only after you type
the pull request number, a maintainer can merge directly with m or hand the
pull request to Hive's governor sweep with a, drafts are
refused, and every
action
is appended as a JSON trace to ~/.local/state/bluefin-review/trace.jsonl
for the review feedback loop. That trace is diagnostics, not run state: it is
size-capped and rotated (8 MB with three backups by default, tunable with
BLUEFIN_REVIEW_TRACE_MAX_BYTES and BLUEFIN_REVIEW_TRACE_BACKUPS), so a
long unattended run cannot fill the disk with it. What a run still has to act
on lives in the durable run store instead, which bounds itself and survives
restart. The launcher bind-mounts that directory from
the host (${XDG_STATE_HOME:-~/.local/state}/bluefin-review), so the trace
and the landing-batch records under landings/ — what was dispatched, what
failed, and the agent's reasons — survive a review-queue relaunch, and the
dashboard folds the newest recorded outcome back onto the matching rows when
it starts: a failed batch's row keeps its failure marking instead of
reverting to un-reviewed.
tests/dashboard-contract.sh pins all of it.
The leading arguments are the model profiles review-container takes
(gemini default, sol/gpt-sol, opus5, k3/kimi plus an optional effort); everything from the first
flag onward passes straight through to the dashboard. REVIEW_QUEUE_NAME=review-queue-2 just review-queue
runs a second dashboard beside the first, like REVIEW_CONTAINER_NAME does for
review-container.
Pull requests you authored are skipped — the dashboard is for reviewing other
people's work. Authorship never changes, so the queue's author field is
the one value the filter trusts without a live re-read.
The container also fetches the Hive knowledge base through Hive's own
entrypoint hook chain, and leaves it at ~/agent.md as a file the agent can
search. It is deliberately not linked to AGENTS.md/.goosehints: Goose
loads those into every subprocess it starts, goose review starts one per
check, and the live export is ~417 KB — enough to spend a large fraction of
each check's context window before the diff is read. The review scope names
the path instead.
Each selection shows read-only Review Evidence — author, draft state, review decision, mergeability, size, and check totals — read live from GitHub rather than from the queue row, because a stale "clean" reading is the one most likely to mislead a reviewer.
Everything that names a pull request, an issue, or a person is a terminal
hyperlink (OSC 8): queue rows, the evidence header, linked issues, duplicate
and overlap references, the author, the Hive contributor working on a stop,
and both screen headers. Ctrl-click or click them in any terminal that
supports the sequence — the same capability h already relies on for the
clipboard.
Stops that are no longer open on GitHub are refused at the point of action — the queue read ages the moment it lands, and GitHub is the state.
Rows are coloured from the state the queue row already carries, so a hundred stops are scannable instead of linear:
| colour | meaning | what it usually needs |
|---|---|---|
| bold green | merge-ready | m, or a to let the sweep do it |
| cyan | reviewable, or already approved | r then L |
| red | conflicting | a human — u cannot fix a real conflict |
| yellow | checks failing | its author, or u if it is merely stale |
| grey | evidence incomplete | investigate — nobody can act yet |
Rows also carry ⚑ CONFLICTS, ✗ CI and ✓ approved markers, so the state
survives a terminal without colour.
The key map is two lines at the bottom: reading actions on the first, the ones that change something on the second. Fourteen bindings do not fit on one row of an 80-column terminal, and a truncated key map teaches half the tool.
R re-reads the live queue and re-asks Hive without losing your batch
selection — any merge invalidates the last read at once. u runs gh pr update-branch, which is the button GitHub shows on a
pull request that is behind its base, for the whole batch if one is selected.
b selects; m merges the whole selection, one typed-number gate per pull
request. a batches the same way.
GitHub refuses merges for reasons that are usually fixable, and a batch that stops dead on the first refusal is worse than no batch — you are several confirmations past it by the time you read the error. A refusal is offered as a choice instead:
projectbluefin/bluefinctl#31 did not merge:
Pull request is not mergeable: the base branch is out of date
[1] update the branch, then merge again
[2] approve and queue it for the sweep instead
[3] try the merge again
[4] leave it queued and move on
esc keeps it in the queue
What is offered depends on why GitHub said no — behind the base gets the
update, blocked on review gets the sweep, and a true conflict gets an explicit
exceptional manual handoff with no bypass — while retry and keep-it-queued are
always there. Updating the
branch runs gh pr update-branch and the merge behind one gate, so it is one
decision like every other sequence.
Anything not fixed stays selected and stays marked: the row carries
✗ DID NOT MERGE, the status line counts them, and the batch moves on to the
next pull request rather than stopping. Putting it back in the queue is the
default, not something you have to remember to redo.
Landing a batch is not the end of it. Once every selected pull request has an
outcome, the same lane runs a final review of the whole batch, hands any
findings to a fresh fixer, and reviews again — up to five rounds, then the
batch is left visibly review-blocked with its findings rather than looping.
The first batch of a session asks which reviewer to use, once:
final review for this dashboard session:
[1] automatic — Gemini Flash default review with K3 fixes
[2] always Gemini Flash — fast review loop across all batches
[3] always Opus 5 — deep reasoning review
[4] always GPT Sol — structured diagnosis review
[5] always K3 — Kimi K3 review and fix rounds
P changes it later. A review round may commit only on the branches your
batch already selected; it never adds pull requests, never removes a hold, and
never bypasses branch protection. The batch queue (w) shows the phase, the
round, the model, and the heads each round bound to.
If your machine can reach a Kubernetes cluster, just review-queue asks once
whether to use it for that session:
? Kubernetes context ghost-lab is reachable. Use it for this session only? [y/N]
Say yes and the launcher starts a small broker on the host and passes the
container one private socket. Your kubeconfig, your credentials, your home
directory, and the Podman socket stay out of the container; the review agent
can ask for cluster health, run an allowlisted QA workflow pinned to the exact
pull-request head, and nothing else. Your own lab skills (lab-test,
k3s-cluster-ops, kubernetes-specialist, live-dev-common) are mounted
read-only when you have them.
The status line then reads LAB READY, LAB DEGRADED, or LAB ⚡ ACTIVE —
the bolt only while a Review-bound workflow is actually running and both lab
nodes report a fresh Thunderbolt link. REVIEW_LAB=1 or REVIEW_LAB=0
answers the question up front for an unattended launch.
Say no — or have no cluster, no kubectl, or a lab that is down — and
everything works exactly as before: the status line reads LAB OFF and
reviews verify published images from the registry. The broker and its socket
are removed when the session ends, review-container never gets any of this,
and stable verified lab findings are filed automatically to
projectbluefin/lab or projectbluefin/server without asking you.
This optional broker is distinct from REVIEW_RUNTIME=k8s, which starts the
dashboard itself in Kubernetes and does not offer the host broker.
r starts the agent review so you can see the pull request judged; v shows
the diff. Neither submits anything. When you have an opinion, L records it
on GitHub — approve, request changes, or comment — from the dashboard or from
the review screen with the draft still on it.
That is deliberately none of the other things: it does not merge, and it does
not apply lgtm, so you can say "this is wrong, here is why" or "this looks
right to me" without landing the change or arming the sweep. A verdict other
than an approval must carry a reason; an empty one submits nothing.
The evidence pane shows who has already reviewed and what their word is worth:
reviews 2 (1 maintainer, 1 community)
hanthor maintainer APPROVED
passerby community CHANGES_REQUESTED
Maintainer or community comes from GitHub's own author association — OWNER,
MEMBER and COLLABORATOR carry write access, everything else does not.
GitHub's single reviewDecision field cannot tell you which kind of reviewer
approved, or that three other people also looked.
The status line used to read Hive: not consulted, permanently — a dashboard
that never asked. It asks now, on startup and again on H, and reports what
the hub said: online · 185 actionable · 2 working, or names the configuration,
credential, network, routing, response, or server layer that failed. The hub
URL is not written down here; it comes from
HIVE_HUB, which the image's Hive entrypoint hook owns and exports. Failures
name the actionable layer: hub configuration, token availability, network,
authentication, authorization, browser-login routing, malformed API response,
or Hive server error.
The part worth having is per-stop. When a contributor's current task is the pull request you are looking at, the context pane says so:
hive joshyorko is working on THIS now (ct-projectbluefin/bluefin-981-…)
That is the one thing worth interrupting a review for — the diff on screen is about to be stale. Otherwise it tells you nobody is on it.
Hive status and worker lookup are read-only and never fatal. Queueing with a
is the one Hive mutation: it stays behind the typed-number gate and fails
closed when the authenticated hub is unavailable. It never follows an HTTP
redirect and reports success only after Hive returns structured JSON confirming
the pull request was queued. Hive remains the sole
authority for selecting and assigning contributor tasks; nothing here claims,
reorders, or declines one.
Every state-changing key prints the exact operations and runs them only after you
type the pull request number; empty aborts, and there is no y/yes shortcut. One
decision is one gate: an action that takes several gh calls — rejecting
(comment + close), resolving a cluster — shows every command it will run in
that one gate and then runs the whole sequence in the background. You are never
asked to confirm the same decision twice, and a failed step stops the rest
instead of asking again.
Queueing a merge with a is the factory's automated merge path: Review calls
Hive's authenticated queue endpoint once. Hive verifies merger standing and
the self-merge ban, then its GitHub App posts the exact-head approval and adds
the lgtm label. The sweep — not this tool — performs the squash merge, and it
independently requires mergeable plus all checks green and ignores drafts.
lgtm is an opt-in to that automation, not a toll on merging. When you
have read the diff and simply want the change in, m merges it now: the same
typed-number gate, the same squash the sweep would perform, no label, and no
robot armed. That is a maintainer power — the dashboard asks GitHub whether
you hold the push permission on that repository and refuses if you do not,
which is why it can never become a contributor agent's path (agents work from
forks and have no such permission). It never overrides branch protection:
there is no bypass flag, so a repository that requires review or green checks
still refuses, and you are told why.
h is read-only: it copies the handoff text through OSC 52, which reaches
your system clipboard when the attached terminal supports that sequence
(modern terminals and tmux's default set-clipboard do); otherwise the
dashboard reports that it could not reach the clipboard.
The box along the bottom steers the next review of the highlighted pull
request. / focuses it, Esc returns to the queue — the queue keeps the
single-key bindings, because a focused input would swallow them. Enter starts
the review with what you typed carried as BLUEFIN_REVIEW_STEER, which
bluefin-review adds to the review as one more check
(maintainer-steering) alongside the Bluefin doctrine. It is additive by
construction: steering directs attention within a review and can never
replace the doctrine or license an approval, a merge, or any other state
change. The steer is recorded with the review's outcome in the trace.
Each stop also shows the merge queue of its own repository, so you can tell a repository with one thing left from one with thirty:
merge queue projectbluefin/bluefin — 5 open
████████████████████████
1 review · 1 CI · 1 conflicts · 2 unclear
Segments carry the same colours as the rows, in the order a maintainer drains
them: queued (already labelled lgtm, waiting on the sweep), ready,
review, CI, conflicts, unclear. First match wins — anything handed to
the sweep counts as queued whatever else is true of it, and a conflict
outranks a failing check because the check cannot mean anything until the
conflict is gone.
Every non-empty segment gets at least one cell. One pull request waiting on the sweep behind sixty unclear ones is exactly what you need to see, and proportional rounding is what would hide it.
The meter counts all open pull requests in that repository, including your own — "how busy is this repository" is a different question from "what is left for me to review", and only the second one excludes your own work.
The queue holds real duplicates, so each stop also reports a pull request's near-neighbours in the same repository — with enough of each to choose between them without opening a browser tab per candidate:
dupe-of 2 doing the same work — M resolves the cluster
#26 chore(deps): update actions/checkout action to v8
by renovate · approved, 4 files, 2026-08-05
same dependency (actions/checkout)
#24 chore(deps): update actions/checkout action to v7
by renovate · draft, conflicting, 2 files, 2026-08-01
same dependency (actions/checkout)
overlaps 3 touching the same files (ordering hazard, not duplication)
Which of three duplicates to keep is the whole decision, and a bare list of numbers said only that a decision was required. The listing this is built from already carries the titles and states, so the summary costs nothing extra.
dupe-of means the two are the same work: Renovate raises a digest bump and a
version bump for one dependency, and several agents can close one issue from
separate pull requests. overlaps means only that they touch a file in common —
an ordering hazard, not duplication.
Keeping those separate is the point. Across the live queue, shared files flag 174 pairs, mostly unrelated changes touching one busy workflow file, while the same-dependency and same-issue tests find 13. Reporting the first as duplication would bury the second.
And because duplicates are the same work, one review judges the whole cluster:
r fetches every duplicate's diff alongside the checkout, and the Review Draft
must name which pull request should merge and which should close as superseded,
with evidence. Overlaps are listed in the review as merge-ordering hazards but
keep their own stops.
Detection costs one gh pr list per repository, cached for the session, so
revisiting a repository does not refetch it.
bluefin-review pr projectbluefin/common 42 # review one pull request
bluefin-review main...HEAD # review a local diffbluefin-review is the review engine both the dashboard's r key and a
terminal call go through. It clones each repository once into
HIVE_WORKSPACE_DIR (default ~/workspace), checks the pull request out
there, and reviews origin/<base>...HEAD. The result is a Review Draft for
you to judge.
It has no approve, merge, comment, or close path of its own — those belong to
the dashboard, behind the typed-number gate — so running a review can never
change anything on GitHub. Its exit status is the review's verdict about
itself: 0 complete, 65 incomplete (a check returned no verdict, so the
finding count cannot be read as clean), anything else a failure.
goose review does not read ~/.agents/skills. Its own context comes from
.agents/REVIEW.md and .agents/checks/*.md inside the repository being
reviewed, so reviewing another project would otherwise get Goose's generic
prompt with none of Project Bluefin's review doctrine — and writing those files
into someone else's checkout is not an option.
Review uses two deliberately separate skill layers:
| Layer | Consumers | Source |
|---|---|---|
| Review check subagents | goose review |
Definitions in image/review-scope/checks/, deployed to /opt/bluefin/review-scope/.agents/checks/ and passed with --check-scope. |
| Interactive contributor skills | Interactive contributor sessions | Agent Skills installed under ~/.agents/skills/, including generated Bluefin skills and compatible community skills from skills.sh or other open catalogs. |
Installing a community skill changes interactive contributor sessions; it does
not add a goose review check. Review techniques must be explicit check
subagents in the image-owned overlay. The bluefin-doctrine check covers
scope, repository conventions, maintainability, and consistency among
implementation, tests, and durable documentation.
just turbo-review requests three cluster contributor workers by default,
then forwards the same profile, effort, repository, and dashboard arguments
to the foreground review-queue; REVIEW_SCALE changes the worker count.
Both sides use the same resolved Hive Hub. Rollout observation stops waiting
after 15 seconds while workers continue starting in the background.
bluefin-review also passes --instructions (additive) rather than --prompt
(which would replace Goose's default prompt), naming the doctrine on disk
instead of inlining it:
| Source | Path |
|---|---|
pr-review, queue-feed, hive-review, human-gates |
~/.agents/skills/<id>/SKILL.md and references/ |
| Hive knowledge base | ~/agent.md, refreshed from the hub every 10 minutes |
This mirrors local-agent-policy.md, which routes the agent into the skill
inventory rather than repeating it. Inlining those documents would add roughly
33 KB to every check subprocess of every review; the pointer costs under 1 KB.
Entries are omitted when their files are absent, so nothing dangles.
Override with BLUEFIN_REVIEW_CONTEXT_SKILLS (space-separated skill ids),
BLUEFIN_REVIEW_SKILLS_ROOT, or BLUEFIN_REVIEW_KNOWLEDGE_FILE.
Hive keeps running throughout: the dashboard is an ordinary command inside the
contributor container, so the knowledge base, its refresh loop, and the
contributor session are untouched. Run it in a second pane with
podman exec -it <container> tmux attach -t contributor, or in any shell in
that container.
The menu offers no approve and no unguarded merge. This is the Managed
Reviewer Client from
docs/factory/agentic-model.md: it prepares a
Review Draft, and the m/M action keys execute the human's decision through
a single typed-number-confirmed call site that can only arm GitHub's own
auto-merge. Approval and review submission stay
human actions taken in GitHub, and tests/bluefin-review.sh fails if a merge
escapes that gate or a review-submission path is ever added. Queue mode needs an interactive
terminal and says so rather than looping silently without one.
All configuration is read at launch.
| Variable | Purpose |
|---|---|
REVIEW_CONTRIBUTOR_IMAGE |
Contributor image; defaults to ghcr.io/projectbluefin/review:stable. |
REVIEW_HIVE_COMMIT |
Full Hive commit used for contributor setup. |
REVIEW_CONTAINER_NAME |
Contributor container name; defaults to review-container. Give a second concurrent instance its own name. |
REVIEW_RUNTIME |
Set to k8s to run the dashboard as one foreground Kubernetes Pod. Unset keeps the Podman dashboard. |
REVIEW_HIVE |
Named Hive registration used by review-container and consulted by review-queue, for example endusers selects ~/.config/hive/contributor.endusers.env. The dashboard receives only its TLS HIVE_HUB URL. |
REVIEW_GH_TOKEN |
Optional GitHub token override for container-only mode. |
BLUEFIN_REVIEW_BACKEND |
Optional review-queue preselection: goose or codex; unset preserves the current default. Never affects review-container. |
CODEX_HOME |
Optional host Codex state root used only to locate auth.json; no configuration directory is mounted. |
BLUEFIN_REVIEW_CONTEXT_SKILLS |
Skill ids named as review context; defaults to pr-review queue-feed hive-review human-gates. |
BLUEFIN_REVIEW_SKILLS_ROOT |
Projected org skills root; defaults to ~/.agents/skills. |
BLUEFIN_REVIEW_KNOWLEDGE_FILE |
Hive knowledge export named as review context; defaults to ~/agent.md. |
GOOSE_PROVIDER |
Unset or github_copilot. |
GOOSE_MODEL |
Optional GitHub Copilot model override. |
GOOSE_THINKING_EFFORT |
Optional Copilot reasoning-effort override. |
GITHUB_COPILOT_TOKEN |
Optional Copilot credential override. |
OTEL_EXPORTER_OTLP_ENDPOINT |
Optional local Kubernetes-session countme configuration; it is staged only in the ephemeral session Secret. |
OTEL_EXPORTER_OTLP_HEADERS |
Optional local countme authentication headers; they are staged only in the ephemeral session Secret. |
TOOL |
Contributor agent backend selector: goose (default), codex, or pi. It does not select the maintainer dashboard backend. |
The maintainer dashboard may remember non-secret harness preferences at
~/.config/bluefin-review/harness.json (or the equivalent
XDG_CONFIG_HOME path). Contributor backend and provider selection are read
from the environment for each launch; no secret or provider selection is
stored by the launcher.
~/.local/state/review/ stores the pinned Hive checkout.
It is the only state this launcher owns. Goose and provider
selection is recomputed from the environment at every launch and never written
to disk. ~/.config/hive/contributor.env is host state that review reads but
does not own; Hive's upstream setup creates it and owns its format. No other
launcher state persists.
One dashboard state directory is deliberately durable: review-queue
bind-mounts ${XDG_STATE_HOME:-~/.local/state}/bluefin-review into the
container, so landing-batch records and the action trace survive the
reclaim-by-replace relaunch. The dashboard writes it; the launcher only
creates and mounts it. Named dashboards share it safely because every batch
id carries its instance name (the launcher passes the container name in as
BLUEFIN_REVIEW_INSTANCE).
For REVIEW_RUNTIME=k8s, the equivalent durable state is the
bluefin-system review-queue-state PVC defined in
deploy/review-queue-state.yaml; the ephemeral dashboard Pod mounts it
without a host path.
The image's controlled Goose configuration sets GOOSE_MODE: auto, so the
agent runs its tools without a per-tool confirmation prompt. This is required,
not a convenience: Hive drives the CLI by simulated keystrokes, so a
confirmation prompt blocks the agent and the human at the terminal
indefinitely. The compensating control is credential scope — the agent holds a
contributor GitHub token and runs unprivileged inside a disposable container,
so its blast radius is that container plus whatever that token can reach.
Prefer a REVIEW_GH_TOKEN limited to public_repo or repo.
stable is the default contributor-image tag and is pulled at each launch.
Use an immutable sha-<commit> tag or digest with
REVIEW_CONTRIBUTOR_IMAGE when a reproducible image is required.
The image derives from the digest-pinned Project Bluefin FSDK lab runner and
layers the pinned Hive runtime at 11bee81280861d03416a0c6278da35c9778cbdee,
the current Goose canary snapshot, the pinned official Codex CLI, GitHub CLI,
tmux, uv with the Textual
dashboard runtime, hooks, and generated
organization skills. Goose
publishes that snapshot from its active main
branch; each archive is verified against GitHub's signed build provenance
before installation.
The relay uses the root package-lock.json to install only the exact ws
dependency with npm ci --omit=dev --ignore-scripts. The official,
checksum-verified Node archive remains intact as a JavaScript runtime: node,
npm, and corepack stay available. Only its headers, documentation, and the
now-unused npm download cache are removed. Those fixed Node, CLI, tmux, and
relay inputs are built before the mutable Goose refresh layer, so a Goose-only
refresh reuses them.
That Hive SHA is load-bearing, not decorative. It is the third of three copies
of the same pin: hive_commit in the justfile, ARG HIVE_COMMIT in
image/Containerfile, and the one above. All three must move together, and CI
fails if they disagree. Renovate proposes them as a single change, so take its
pull request whole rather than editing any copy by hand.
Goose's canary name is mutable, so it is not an artifact identity. CI
resolves the official unknown-linux-musl archive digest for each architecture
immediately before building; the image checks that digest and Goose's signed
attestation, then records both digests in its configuration and build
provenance. A moved canary archive therefore fails the build rather than
silently changing an image. Use an immutable contributor image digest or
sha-<commit> image tag when a fixed artifact is required.
Every published contributor digest carries review-specific OCI title,
description, project URL/source, revision, version, creation time, license,
and exact FSDK base name/digest metadata in both platform labels and manifest
annotations. Publishing attaches a signed SLSA provenance bundle and a signed
SPDX SBOM to the published index digest, verifiable with gh attestation verify. The SBOM covers the archive-installed components — Goose, the GitHub
CLI, tmux, Codex, ripgrep, the pinned Hive runtime files, the skill bundles,
and the review git hooks — because the image carries a build-time SPDX
manifest of them (/opt/bluefin/sbom/review-components.spdx.json, generated
from the resolved Containerfile pins) that the publish scan ingests; the
post-publish audit fails when any of them is missing from either platform's
attested SBOM. CI verifies the FSDK input's GitHub attestation and its
linux/amd64+linux/arm64 manifest before a build; after publication it verifies
both review attestations, labels, annotations, subject digest, and exactly
those two platforms.
The image is built with podman and buildah, the same engines that run it, and
each architecture is built by a runner of that architecture: ubuntu-26.04
for amd64 and ubuntu-26.04-arm for arm64. Each build job proves its host,
podman engine, and container architecture, runs the shipped runtime, and audits
the image it just pushed. The published :stable is an OCI index assembled by
buildah from those two native digests, so no shipped layer is ever produced
under emulation. The generated per-architecture audit reports in the GitHub
Actions step summary are the acceptance artifact; local single-architecture
validation cannot supply that evidence.
The pinned Hive runtime preserves an existing ~/.config/goose/config.yaml.
The image still uses GOOSE_PATH_ROOT=/opt/bluefin/goose to keep controlled
Goose policy, data, and state separate from Hive's runtime-owned config. Hive
now links its refreshed knowledge export to Goose-native AGENTS.md and
.goosehints, so no filename compatibility override is needed.
Organization skills are generated at image build time from
projectbluefin/common's docs/skills/index.json into Goose's global skill
directory. Compatible community skills installed from skills.sh or another
open catalog use that same ~/.agents/skills/ session layer. Repositories may
route agents to their own skill catalog, but per-repository skills are not
automatically discovered at session startup, and no session-layer skill becomes
a goose review check unless it is authored separately in the image-owned
review scope.
The base image ships the full ncurses terminfo database, so the caller's
terminal type is the truth inside the container. tmux panes run
tmux-direct, so 24-bit color is a terminfo fact and tmux passes RGB
through to terminals that support it, downsampling only for weaker attach
clients. For a terminal newer than the base's ncurses (e.g.
xterm-ghostty), the entrypoint falls back to xterm-direct for a
truecolor caller (COLORTERM) and to xterm-256color otherwise.
The pinned FSDK base ships GNU findutils 4.10.0 and diffutils 3.12, so the
image uses those directly. It previously installed Python find and cmp
shims into /usr/local/bin, which precedes /usr/sbin on PATH and so
shadowed the real tools; the find shim also got -o precedence wrong and
deleted *.out of any age where GNU find deleted only old *.html,
destroying fresh agent output. Both shims are gone. Use the tools the image
ships; if one is missing, fix it at the FSDK seam rather than reimplementing
it here.
Context7 serves the agent through two seams: the Hive hub queries it
server-side and folds the result into its knowledge export, and the image's
controlled Goose config enables the context7 extension against the keyless
public endpoint for on-demand documentation lookups. The agent policy routes
external API questions through it before memory.
worktree-guard (at /usr/local/bin/worktree-guard) runs an agent command
in an ephemeral git worktree and enforces hygiene: a run that leaves the
tree dirty is reported, purged, and failed, and the agent's own exit code is
never masked. When bubblewrap is available it adds a read-only-root sandbox
around the run (fsdk-containers#109 tracks shipping bwrap in the base).
Git hooks at /opt/bluefin/git-hooks are ergonomics only; GitHub rulesets and
required checks enforce repository policy.
Prototype image-owned behavior in this checkout, then build the commit you have under the same immutable tag CI mints for it:
ref="ghcr.io/projectbluefin/review:sha-$(git rev-parse HEAD)"
GH_TOKEN="$(gh auth token)" podman build \
--secret id=github_token,env=GH_TOKEN \
--build-arg GOOSE_REFRESH="$(date +%s)" \
-f image/Containerfile -t "$ref" .Use that tag for a container-only trial without publishing it:
REVIEW_CONTRIBUTOR_IMAGE="$ref" just review-containerAn sha-<commit> tag names exactly one build, so the launcher never re-pulls
over it and the local copy is the one that runs. It also says which commit is
in the image, which a made-up local name cannot.
After the change is ready, commit it and use the normal publish workflow; CI
publishes immutable sha-<commit> and version tags and advances :stable
from main.
The build secret exists only while GitHub CLI verifies Goose's signed
provenance and is never included in an image layer. The checked-in checksums
make this local command use the known canary snapshot; to refresh it, resolve
the two official release-asset digests and pass
GOOSE_X86_64_SHA256 and GOOSE_AARCH64_SHA256 as build arguments.
bash scripts/check-skill-frontmatter.sh
bash tests/generate-skills.sh
bash tests/image-contract.sh
bash tests/hive-compatibility.sh
bash tests/bluefin-review.sh
python3 tests/lab-broker-contract.py
bash tests/just-onboarding.sh
git diff --check
just --list
pre-commit run --all-filestests/image-audit.sh inspects a real image, so it needs a container engine
and network access. It uses podman; CONTAINER_ENGINE names another one.
Use --verify-base-evidence to check the pinned
FSDK input alone, or --derived <image> to audit a build. The report records
each platform's runtime evidence as native or unavailable — never QEMU —
and --report image-audit-report.md writes it to a git-ignored file. Native
per-architecture acceptance comes from the matrix build job in
.github/workflows/publish-compat-image.yml and its generated step summary:
bash tests/image-audit.sh \
--derived "ghcr.io/projectbluefin/review:sha-$(git rev-parse HEAD)"pre-commit run --all-files runs socket-free hygiene checks locally.
ShellCheck remains required in CI, where the validate workflow invokes its
manual container-backed hook explicitly.
See AGENTS.md for contributor boundaries and
docs/SKILL.md for task-specific documentation.
Licensed under the Apache License 2.0.
