Review loop

Paste text or a diff on /review — a writer and a critic iterate (bounded), then a classifier judge delivers the verdict. Text is the default tab (no code literacy needed, and classifier judges are most accurate on prose); code is the second tab.

Where this sits (plugin, not layer)

The scope taxonomy has no "layer" axis — the directory is the layer (features/ = product) and the annotation is the removal class. In those terms: review is a feature (terminal user surface, trim it and /review is gone) and genkit is a plugin capability (serves the feature; nothing user-facing disappears without it, but review stops working). Genkit is not a framework (proven by cmd/check-flatdeps), not a second LLM client (zero provider plugins; generation reaches providers only through llm.Client), and not core (trim + go mod tidy removes it from the build).

How it runs

Synchronous in the request scope: one POST streams phased progress over ephemeral SSE and patches a single verdict fragment. Disconnect cancels the run; MaxRunDuration (90s) bounds it either way. A 15s heartbeat holds the stream open between phases so proxies never kill it idle (a dead stream used to leave the Run button disabled with no error). Nothing persists — no queue jobs, no DagNats runs, no database writes. The billing ledger is the only write (generative calls via llm.Client's meter when wired; the judge call is recorded once when a judge meter is wired).

The loop needs a real LLM (GOAI_API_KEY): without one the page shows a setup hint and the run API answers 503. There is deliberately no simulated path — the template's AI surface is real-LLM only.

The three roles

Pointing at another jev-compatible API

The flow never names a provider — endpoint and model ride env, and the contract is just POST {state,model,questions}:

EnvDefault (keyless SimpleJev demo)Custom example
JEV_API_URLhttps://simple-jev-demo-api.featherless.ai/v1/classifierhttps://api.typesafe.ai/v1/systemone, http://127.0.0.1:8000/v1/classifier (self-hosted), bare host:port (expands to /v1/systemone)
JEV_MODELfeatherless-ai/Qwen3.6-35B-A3B-classifierjev-latest, any served ID
JEV_API_KEYempty (no Authorization header)operator key in the age-encrypted secrets file
JEV_TIMEOUT10sper-attempt HTTP timeout
JEV_CONFIDENCE_THRESHOLD0.7recalibrate (below) when changing backends

The demo endpoint is rate-limited (2k context, 2 RPS) — fine for trying, not for production. Production wants a featherless.ai account (or the open-source self-host) plus the calibration below.

Calibrating the confidence threshold

Before trusting auto-accept on a new backend: label ~20 cases by hand (10 publish / 10 revise), run the judge, measure agreement (target ≥70% on the binary decision), freeze the threshold in JEV_CONFIDENCE_THRESHOLD. Re-run when the backend, model, or rubric changes. An uncalibrated judge is noise with confidence attached.

Removal

gogogo trim review (dropped by the minimal and no-ai presets), or by hand: delete features/review/ + the bootReview helper, reviewH lines and /review mounts in internal/server/chi.go (+ the newReviewHandlerForTest fixture in its test) + go mod tidy.

Why no LLM gateway (Bifrost) yet

An LLM gateway (Bifrost, Apache-2.0) was evaluated and deferred — not rejected, and not implemented. One provider, provider-aware retry already in goai, budgets already in ai-credits: a gateway would add a control plane, its own log store, and a large dependency for zero current need.

Verified facts (scratch probe + upstream docs, 2026-10-13; core v1.12.0 — do not confuse with the host's bifrost-stdio service, which is BB's MCP gateway, a different project sharing the name):

Reconsider when: a second provider/key needs failover (e.g. OpenRouter free quota killing the demo), the first tool-using feature arrives, or measured cache-hit savings justify the weight. Next step then is a one-day spike with real calls (usage mapping, streaming, fallback with one bad key) — not a blind integration.