# oh my pi enable antigravity

> Source: <https://gist.github.com/XSilverTH/6519a09b6d57966cc4d107c966c18c4f>
> Published: 2026-11-10 09:33:55+00:00

|  | /** | 
|  | * Extension to re-enable Google Antigravity logins and models in oh-my-pi >= 18.18.4, | 
|  | * and bypass the artificial "ineligible account" location/free-tier block. | 
|  | * | 
|  | * Upstream PR #18622 added a `disabled` rule to google-antigravity in the catalog, | 
|  | * and google-antigravity-project has a rigid check that throws if free-tier is | 
|  | * flagged as ineligible, even when the user has valid OAuth credentials, paid tier, | 
|  | * or an active cloudaicompanionProject. | 
|  | */ | 
|  | import * as compatAuth from "@oh-my-pi/pi-catalog/compat/auth"; | 
|  | import { getProviderDefinition, registerOAuthProvider } from "@oh-my-pi/pi-ai"; | 
|  | import { Database } from "bun:sqlite"; | 
|  | import { getAgentDbPath } from "@oh-my-pi/pi-utils"; | 
|  | // 1. Clear paused status and remove restrictive built-in hooks | 
|  | const policy = compatAuth.authPolicyFor("google-antigravity"); | 
|  | if (policy) { | 
|  | delete (policy as any).disabled; | 
|  | if (policy.login) { | 
|  | delete (policy.login as any).afterExchange; | 
|  | } | 
|  | if (policy.refresh) { | 
|  | delete (policy.refresh as any).afterRefresh; | 
|  | } | 
|  | } | 
|  | // 2. Wrap provider definition to bypass the eligibility check | 
|  | const def = getProviderDefinition("google-antigravity"); | 
|  | const formatApiKey = (creds: any) => | 
|  | JSON.stringify({ | 
|  | token: creds.access, | 
|  | projectId: creds.projectId, | 
|  | refreshToken: creds.refresh, | 
|  | expiresAt: creds.expires, | 
|  | email: creds.email, | 
|  | accountId: creds.accountId, | 
|  | }); | 
|  | if (def && def.login) { | 
|  | const originalLogin = def.login; | 
|  | const originalRefreshToken = def.refreshToken; | 
|  | const resolveProjectId = async ( | 
|  | accessToken: string, | 
|  | onProgress?: (msg: string) => void, | 
|  | signal?: AbortSignal | 
|  | ): Promise<string> => { | 
|  | let projectId = | 
|  | process.env.GOOGLE_CLOUD_PROJECT \|\| process.env.GOOGLE_CLOUD_PROJECT_ID; | 
|  | if (!projectId) { | 
|  | onProgress?.("Checking Antigravity project status..."); | 
|  | try { | 
|  | const res = await fetch( | 
|  | "https://daily-cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", | 
|  | { | 
|  | method: "POST", | 
|  | headers: { | 
|  | Authorization: `Bearer ${accessToken}`, | 
|  | "Content-Type": "application/json", | 
|  | "User-Agent": "antigravity", | 
|  | }, | 
|  | body: JSON.stringify({ metadata: { ideType: "ANTIGRAVITY" } }), | 
|  | signal, | 
|  | } | 
|  | ); | 
|  | if (res.ok) { | 
|  | const data = (await res.json()) as any; | 
|  | projectId = | 
|  | typeof data.cloudaicompanionProject === "string" | 
|  | ? data.cloudaicompanionProject | 
|  | : data.cloudaicompanionProject?.id; | 
|  | } | 
|  | } catch {} | 
|  | } | 
|  | return projectId \|\| "aicode-consumers"; | 
|  | }; | 
|  | const customLogin = async (ctrl: any) => { | 
|  | // def.login handles local callback server and OAuth token exchange with Google | 
|  | const creds = await originalLogin(ctrl); | 
|  | // Resolve project without the artificial free-tier location eligibility block | 
|  | const projectId = | 
|  | creds.projectId \|\| | 
|  | (await resolveProjectId(creds.access, ctrl.onProgress, ctrl.signal)); | 
|  | return { | 
|  | ...creds, | 
|  | projectId, | 
|  | }; | 
|  | }; | 
|  | const customRefreshToken = async (creds: any, signal?: AbortSignal) => { | 
|  | const refreshed = await originalRefreshToken(creds, signal); | 
|  | return { | 
|  | ...refreshed, | 
|  | projectId: creds.projectId \|\| refreshed.projectId \|\| "aicode-consumers", | 
|  | }; | 
|  | }; | 
|  | registerOAuthProvider({ | 
|  | id: "google-antigravity", | 
|  | name: def.name, | 
|  | login: customLogin, | 
|  | refreshToken: customRefreshToken, | 
|  | getApiKey: formatApiKey, | 
|  | }); | 
|  | registerOAuthProvider({ | 
|  | id: "antigravity", | 
|  | name: def.name, | 
|  | storeCredentialsAs: "google-antigravity", | 
|  | login: customLogin, | 
|  | refreshToken: customRefreshToken, | 
|  | getApiKey: formatApiKey, | 
|  | }); | 
|  | } | 
|  | // 3. Bump auth_change_revision so CredentialPool picks up credentials | 
|  | try { | 
|  | const db = new Database(getAgentDbPath()); | 
|  | db.run("UPDATE auth_change_revision SET revision = revision + 1 WHERE id = 1"); | 
|  | db.close(); | 
|  | } catch {} | 
|  | export default function (api: any) { | 
|  | if (api.extension) { | 
|  | api.extension.registersProviders = true; | 
|  | } | 
|  | api.on("session_start", async (_event: any, ctx: any) => { | 
|  | if (ctx.model && ctx.model.provider !== "google-antigravity") { | 
|  | const target = ctx.modelRegistry.find("google-antigravity", "gemini-3.8-flash"); | 
|  | if (target) { | 
|  | await api.runtime.setModel(target); | 
|  | } | 
|  | } | 
|  | }); | 
|  | } |
