Gemini Code Assist¶
A free, advisory, on-request review pass on marola's PRs, and how to stand it up two ways: by hand in the Google Cloud console, or as a Besom (Pulumi for Scala) program with state in GCS. Everything dated here was checked on 2026-09-21; vendor pages move, so re-check before relying on a number.
Why this tool: h0ffmann/marola is a private repo, so every "free for open source" tier
(CodeRabbit, Qodo's OSS programme, Sourcery's public-repo tier, Codacy) is out. Of what remains,
Gemini Code Assist on GitHub is the only hosted reviewer that is free on a private repo with a
quota marola cannot hit (Google's docs: ≥ 100 PR reviews/day per installation). Greptile's Starter
plan (50 reviews/month, one developer) is the runner-up. MIP-0060's local route (open-code-review
on Ollama) is parked because qwen2.5-coder:7b cannot do the tool calls; this is the hosted
alternative it reserved for a human go-ahead in its §5.5, because private source leaves the
machine. §8 has the survey.
1. What is in the repo (this PR)¶
| File | Does |
|---|---|
.gemini/config.yaml |
Turns off review-on-open, summary-on-open and draft handling; MEDIUM severity floor; at most 10 comments; ignores benchmark outputs, finetune data, test fixtures, flake.lock, native-image metadata, vendored JS. |
.gemini/styleguide.md |
The subset of AGENTS.md/.claude/rules/scala.md a diff reviewer can check. Gemini injects this file into its prompt; it does not read AGENTS.md on its own. |
DEV-FLOW.md §5 |
Route 4: /gemini review, on request only. |
Gemini's default is to review every PR the moment it opens. DEV-FLOW.md §5 says nothing reviews
a PR automatically, and a nine-PR MIP stack would burn nine reviews at once, so
pull_request_opened.code_review: false is the one setting that matters. .github/workflows/**
is skipped by Gemini itself, always.
2. Using it¶
On a PR, comment:
| Comment | Effect |
|---|---|
/gemini review |
One summary comment plus inline comments with a severity and a committable suggestion. Repeat after new commits. |
/gemini summary |
Description only. |
/gemini <question> |
Ask about the diff. |
/gemini help |
The list above. |
Reply to an inline comment to argue with it. Same discipline as a Claude review (superpowers
receiving-code-review): verify the finding before acting on it. Never make it a required check.
3. GCP side, by hand (the fast path)¶
The Feb-2025 "free for individuals, install the GitHub app" path is gone from Google's docs; the only documented install now goes through Google Cloud Developer Connect and needs a GCP project with a billing account attached. Google states there are no charges during Preview, but a card is on file. This is a human's action, never an agent's: it is the moment private source starts going to Google.
- Pick or create a project; confirm billing is linked. You need Owner/Admin on it, or Service
Usage Admin plus
roles/geminicodeassistmanagement.scmConnectionAdmin(grantable only viagcloud projects add-iam-policy-binding, not the console). - Console → Gemini Code Assist → Agents & Tools → Source Code Management → create the
connection. Enable the Developer Connect API and the Gemini Code Assist Management API when
the banners ask. The connection lands in
us-east1; Google says an existing connection made for another feature (code customisation) cannot be reused. - When GitHub asks: Only select repositories →
h0ffmann/marola. Never "All repositories". - Back in Developer Connect → Link repositories → marola.
- Gemini Code Assist privacy settings → turn off "use my data to improve Google products" (the individual edition defaults to sharing). §5 makes this a line of code instead.
Then open any PR and comment /gemini review.
4. GCP side, as Besom (candidate MIP — not built)¶
Every GCP-side piece has a Pulumi resource, and Besom is current: besom-core 0.5.2
(2026-09-18) and besom-gcp 9.0.0-core.0.5 (2025-09-27, wrapping Pulumi GCP provider 9.0.0
of 2025-09-18) on Maven Central. Do not trust search.maven.org's index for these: it lags a
year; read repo1.maven.org/maven2/org/virtuslab/ directly.
| Need | Resource | In pulumi-gcp since |
|---|---|---|
| Enable the two APIs | gcp.projects.Service |
— |
| The role the console cannot grant | gcp.projects.IAMMember |
— |
The connection, in us-east1 |
gcp.developerconnect.Connection |
8.2.0 |
Link h0ffmann/marola |
gcp.developerconnect.GitRepositoryLink |
8.2.0 |
| Data-sharing opt-out, as code | gcp.gemini.DataSharingWithGoogleSetting + …Binding |
8.20.0 |
| Gemini enablement, as code | gcp.gemini.GeminiGcpEnablementSetting + …Binding |
8.20.0 |
Layout: a standalone scala-cli project under infra/gemini/, not an sbt module. The
besom-gcp jar is the whole GCP surface and just build must not pay for it. CLAUDE.md puts
infra/** behind plan mode, and it would be the repo's first IaC, so it is a MIP before it is a
branch.
// infra/gemini/project.scala — sketch, not compiled
//> using scala 3.3
//> using dep "org.virtuslab::besom-core:0.5.2"
//> using dep "org.virtuslab::besom-gcp:9.0.0-core.0.5"
import besom.*
import besom.api.gcp
@main def main = Pulumi.run {
val apis = List("developerconnect.googleapis.com", "cloudaicompanion.googleapis.com")
.map(s => gcp.projects.Service(s, gcp.projects.ServiceArgs(service = s)))
val conn = gcp.developerconnect.Connection("marola-code-assist",
gcp.developerconnect.ConnectionArgs(
location = "us-east1", connectionId = "marola-code-assist",
githubConfig = gcp.developerconnect.inputs.ConnectionGithubConfigArgs(
githubApp = "DEVELOPER_CONNECT",
appInstallationId = config.get("appInstallationId"), // absent on the first `up`
authorizerCredential = config.get("oauthSecretVersion").map(v =>
gcp.developerconnect.inputs.ConnectionGithubConfigAuthorizerCredentialArgs(
oauthTokenSecretVersion = v)))),
opts(dependsOn = apis))
val link = gcp.developerconnect.GitRepositoryLink("marola",
gcp.developerconnect.GitRepositoryLinkArgs(
location = "us-east1", parentConnection = conn.connectionId,
gitRepositoryLinkId = "marola", cloneUri = "https://github.com/h0ffmann/marola.git"))
val noSharing = gcp.gemini.DataSharingWithGoogleSetting("no-sharing",
gcp.gemini.DataSharingWithGoogleSettingArgs(
dataSharingWithGoogleSettingId = "no-sharing", location = "global",
enableDataSharing = false, enablePreviewDataSharing = false))
Stack(link, noSharing).exports(
nextStep = conn.installationStates.map(_.headOption.map(_.actionUri)))
}
Two things Besom does not remove:
- The GitHub app install is a browser step. The first
pulumi upcreates the connection pending and exportsinstallationStates[0].actionUri; open it, install the app on marola only; the flow writes an OAuth token to Secret Manager. SetappInstallationIdandoauthSecretVersionin stack config and runupagain. Two runs, one click: the workflow Pulumi's own docs describe, not a Besom limit. - Whether an API-created connection counts as a "Code Assist" connection is undocumented.
If the console just makes a plain connection in
us-east1, Besom's is identical. If it stamps a label the review bot filters on, Besom's is ignored silently. Verify before writing the MIP: do §3 once,gcloud developer-connect connections describe marola-code-assist --location=us-east1, look atlabels/annotations; copy any marker into the program andpulumi importthe existing connection rather than creating a second one.
Toolchain notes: nixpkgs has pulumi (3.255.0 today) but no Scala language plugin and no
pulumiPackages.pulumi-gcp; both install with pulumi plugin install language scala 0.5.2
--server github://api.github.com/VirtusLab/besom and pulumi plugin install resource gcp 9.0.0
into ~/.pulumi/plugins. Inside just jail-claude HOME is ephemeral, so install them on the
host or the plan has to map the plugin dir in, same trap as gh auth login in the jail.
5. State: GCS self-managed, or Pulumi Cloud¶
Pulumi's CLI, engine and SDKs are Apache-2.0 and run without any account. What is paid is Pulumi Cloud, the hosted state/secrets/deployments service. Its Individual tier is free: one user, unlimited stacks and updates, no resource cap, no card, and marola's one maintainer fits it by definition. There is no separate open-source programme and none is needed.
The choice is therefore not about money but about where the state file lives. The state holds the connection's details and the Secret Manager path of the GitHub OAuth token (not the token). Recommended: a GCS bucket in the same project, one fewer third party holding infra metadata, and consistent with marola's per-integration opt-in stance.
gcloud storage buckets create gs://marola-pulumi-state --location=us-east1 \
--uniform-bucket-level-access --public-access-prevention
gcloud storage buckets update gs://marola-pulumi-state --versioning # undo a bad state write
pulumi login gs://marola-pulumi-state
cd infra/gemini && pulumi stack init prod --secrets-provider=passphrase # $0; or gcpkms://… (~$0.06/key/month)
pulumi login gs://… reads Application Default Credentials (gcloud auth application-default
login once on the host). A passphrase secrets provider costs nothing and is enough for a stack
whose only secret is a config value; Cloud KMS is the upgrade when more than one person runs it.
Switch to Pulumi Cloud the day a second person needs the stack: that is the collaboration
feature it sells, at $40/month (Essentials), not free.
6. A CD layer¶
Pulumi Deployments (Pulumi's own CD: run preview/up on their compute or a self-hosted
agent, triggered by a PR or a git push) is a Pulumi Cloud feature. It needs Pulumi Cloud as the
backend; the Individual tier includes up to 500 workflow minutes/month. With state in GCS (§5) it
is not available: that is the trade.
The equivalent without Pulumi Cloud is a GitHub Actions workflow with pulumi/actions, which
marola can run on its own self-hosted runners (the same ones ci.yml's profile ping and
MIP-0060's OCR job use):
pull_requesttouchinginfra/gemini/**→pulumi preview, diff posted as a PR comment. Read-only; fine to run unattended.workflow_dispatchonly →pulumi up. Never on push, never on merge:AGENTS.md's cost/deployment rule ("never provision without explicit human confirmation") is about paid/irreversible provisioning, and a GitHub-triggeredupis exactly the shape it forbids an agent to run. The human presses the button.- Auth: Workload Identity Federation from the repo's OIDC token to a service account with
roles/developerconnect.admin,roles/storage.objectAdminon the bucket, and the two Gemini roles, no JSON key in a GitHub secret.
Follow-up for the MIP, not this PR: add pulumi up / pulumi destroy to
.claude/settings.json's permissions.deny, so an agent cannot run them directly.
7. What it costs, and what leaves the machine¶
- No paid resource: Developer Connect and Secret Manager are within their free tiers, Gemini Code Assist on GitHub is free during Preview, GCS state is cents at most. The billing account is a prerequisite, not a charge.
- Private source goes to Google on every
/gemini review. §3 step 5 / §4'sDataSharingWithGoogleSettingstop it being used to improve Google's products; it is still processed by Google. This is the go-ahead MIP-0060 §5.5 reserved for a human, and installing the app is that go-ahead. - Pre-GA: "limited support", and the quota, the free status and the install path have all changed once already (2025 → 2026).
8. The alternatives, as of 2026-09-21¶
| Tool | On a private repo | Verdict |
|---|---|---|
| Gemini Code Assist for GitHub | Free, ≥ 100 reviews/day per installation (one source: 33/day individual edition); needs a GCP billing account on file | This doc |
| Greptile Starter | Free, 50 credits/month (1 = one review), unlimited repos, 1 developer; indexes the codebase | Second opinion for the PRs that matter |
| CodeRabbit | Free forever on public repos only; private = 14-day trial then $24/dev/month | No lasting free path |
| Qodo Merge | No permanent free tier any more; 14-day trial then $30/month; OSS programme needs a public repo with 200+ stars | No |
| Sourcery | Free on public repos; private $15/dev/month | No |
| GitHub Copilot code review | Not in Copilot Free; Pro $10/month, and each review also burns Actions minutes since 2026-06 | No |
| PR-Agent (Apache-2.0) / open-code-review (MIP-0060) | $0 software, bring your own model | The model is the cost; GitHub Models — the free-in-Actions inference — was retired 2026-07-30; the Gemini API free tier trains on requests |
Sources¶
- Customize Gemini Code Assist behavior in GitHub:
config.yamlschema - Set up Gemini Code Assist on GitHub
- Use Gemini Code Assist on GitHub: commands
- Gemini for Google Cloud — quotas
- pulumi
gcp.developerconnect.Connection - pulumi
gcp.gemini - pulumi-gcp releases: v8.2.0, v8.20.0, v9.0.0 notes
- Besom ·
org.virtuslabon Maven Central - Pulumi pricing · Pulumi Deployments
- CodeRabbit pricing · Qodo pricing · Greptile pricing · Copilot plans · GitHub Models retirement