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 comes with Goose and the official Codex CLI 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, agent-assisted documentation updates (#134), and Ghost Cluster build dispatch (#133).
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
kubestellar/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, and just review-doctor
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-containerjustfile is the installable artifact and exposes exactly
four public recipes:
| Command | Purpose |
|---|---|
just review-container [profile] [effort] |
Run the Hive queue worker: the contributor container that receives assigned tasks and donates inference. REVIEW_DETACH=1 runs it as a detached background worker. |
just review-stop [name] |
Stop a detached worker. Refuses attended runs and containers this launcher did not start. |
just review-queue [profile] [effort] [flags…] |
Walk the Bluefin PR queue interactively in the contributor container. |
just review-doctor |
Perform read-only launch diagnostics. |
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 generated public PR queue is a small, static review backlog:
/serves the Markdown overview;/queue.mdserves the Markdown artifact;/queue.jsonserves the machine-readable artifact.
Every artifact carries generated_at. Treat it as a recommendation snapshot:
check its freshness and 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, include private repositories, or
run a service. The queue.projectbluefin.io custom-domain and DNS mapping are
an operations task outside this repository automation.
gh auth login --web --hostname github.com --scopes repo,read:orgis a hard prerequisite for every recipe.podman.- Goose configured for GitHub Copilot, or
GITHUB_COPILOT_TOKEN, for contributor work and Goose reviews. 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.
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 gpt-5.6-luna 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 |
gpt-5.6-luna |
max |
provider default |
just review-container luna |
gpt-5.6-luna |
max |
provider default |
just review-container opus5 high |
claude-opus-5 |
high |
264000 |
just review-container 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 kimi 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 — no Hive
registration. It needs a GitHub token because the dashboard 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 kimi high # pick the model profile and effort
just review-queue --repo bluefin # one repository
just review-queue --action review # one recommended action
BLUEFIN_REVIEW_BACKEND=codex just review-queue luna 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.
just review-queue opens the maintainer surface: a full-screen Textual app
with a queue pane (Renovate-style dependency bumps are marked BATCHABLE), a
live-evidence details pane, and a context pane carrying the duplicate
verdicts. The status bar reports queue depth, snapshot freshness, and your
GitHub identity; your own pull requests are filtered out.
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.
| Key | Action |
|---|---|
b |
toggle batch selection for the highlighted pull request |
r |
start a review with Goose — streams live, reports COMPLETE / INCOMPLETE / FAILED |
L |
leave a review on GitHub: approve, request changes, or comment (also from the review screen) |
d |
docs-update agent task (tracked as #134) |
g |
Ghost Cluster build dispatch (tracked as #133) |
o |
open in browser |
v |
view the diff — full screen, coloured, scrollable |
c |
comment |
a |
approve and queue: approval + lgtm, opting in to Hive auto-merge; for the batch selection if one exists |
m |
merge now: squash immediately, no lgtm, maintainers only — the batch selection if one exists |
x |
reject: comment, then close |
h |
handoff: copy the pull request's 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 |
refresh the queue snapshot 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 gh command 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 (approval + lgtm), drafts are
refused, and every
action
is appended as a JSON trace to ~/.local/state/bluefin-review/trace.jsonl
inside the container for the review feedback loop.
tests/dashboard-contract.sh pins all of it.
The leading arguments are the same model profiles review-container takes
(luna, opus5, 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 snapshot'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 snapshot, 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 snapshot can be hours old, and GitHub is the state.
Rows are coloured from the state the snapshot 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 snapshot and re-asks Hive without losing your batch selection
— the snapshot regenerates every 15 minutes and any merge invalidates it 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, a conflict gets handed to a human in
the browser — and 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.
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 plainly unreachable
or not configured. The hub URL is not written down here; it comes from
HIVE_HUB, which the image's Hive entrypoint hook owns and exports.
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.
Consulting Hive is strictly read-only and never fatal: an unreachable or unauthenticated hub is reported as unreachable, not raised, and the queue still works. 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 commands 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 — queueing
(approval + lgtm), 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: it posts the
exact approval Hive's governor sweep re-verifies (Approved by @<you> for Hive auto-merge on green CI.) and adds the lgtm label the sweep scans for. The
sweep — not this tool — performs the squash merge, and it independently
enforces the self-merge ban, 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.
bluefin-review therefore 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_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_QUEUE_URL |
Queue snapshot the dashboard reads; defaults to the published queue.json. |
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. |
TOOL |
Agent backend selector; only goose is accepted. |
~/.config/review/last-selections.env stores launcher configuration
state such as the last Goose/provider selection between runs.
~/.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.
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 98781c252cefb2f2193832a701abd8d0728ea18b,
the current Goose canary snapshot, the pinned official Codex CLI, GitHub CLI,
tmux, uv with the Textual
dashboard runtime, hooks, generated
organization skills, and the pinned projectbluefin/lab skills (projected as
lab-<id> so the Ghost Cluster operating knowledge rides along). 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. 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-24.04
for amd64 and ubuntu-24.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. Repositories may route agents to their own skill catalog, but
per-repository skills are not automatically discovered at session startup.
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
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.