`opencode-antigravity-auth`: The Account-Rotation Engine Behind a Shadow AI Access Layer

A TypeScript plugin that treats OAuth, quota, and retry logic as one survival system for staying ahead of model limits, bans, and API drift.

8-10 min read • View on GitHub • More from NoeFabris

Three identity cards spin on a mechanical turntable and feed into a locked gateway. Small gauges above the machine show health, cooldown, and jitter, turning login into a routing problem instead of a one-time handshake. The image explains that the repo manages many accounts as a living access layer.
The core idea is not authentication alone. It is continuous identity management under pressure.
Key Takeaways

The real product is survival

The most interesting thing about opencode-antigravity-auth is that it does not behave like a normal auth plugin. It behaves like an operating system for scarce access: score each identity, route traffic to the healthiest one, cool down the damaged ones, and keep enough entropy in the loop to avoid obvious patterns.

That is why the repo is better read as infrastructure than glue code. The point is not to log in once. The point is to keep a multi-account path usable when quota gets tight, failures cluster, and the backend starts pushing back.

A number of users have reported their Google accounts being banned or shadow-banned (restricted access without explicit notification).

Project README, Repository documentation · NoeFabris/opencode-antigravity-auth README

How a Google login becomes a project ID

The authentication flow is only the first gate. The plugin uses PKCE and a Google-specific scope set, then calls a project-discovery step that resembles an IDE bootstrap rather than a generic OAuth callback. The key move is simple: the client must become the right kind of client before the backend yields the project identity it expects.

The auth path is really a client-shaping path. The project ID is the lock, not just the token.

const token = await authorizeAntigravity({
  scopes: ANTIGRAVITY_SCOPES,
  pkce: true,
});

const projectID = await fetchProjectID(token.accessToken);

return {
  refreshToken: token.refreshToken,
  projectID,
  managedProjectID: projectID,
};

That sequence matters because it turns a generic identity into a managed workspace identity. In other words, the plugin is not just asking for permission. It is negotiating shape.

Rotation is the core algorithm

The heart of the repo is the health scoring loop. Accounts are not treated as equal, and they are not rotated in a simple round robin. Each identity accumulates reward for success and penalties for quota exhaustion, transient failures, and repeated bad outcomes, then waits out a tiered backoff before it is eligible again.

A close-up ledger on a workbench shows success rewards, failure penalties, and a backoff staircase with uneven steps. A hand marks one account as cooling, another as hot, and a third as safe to route, explaining how the rotation system makes identity selection feedback-driven.
The scoring ledger turns account choice into a live feedback problem, not a blind retry loop.
Simple clientThis repoWhy it matters
Retry after failureScore, cool down, and route away before failure repeatsIt avoids turning every error into a stampede
One account at a timeA pool of identities with current health statesAccess survives by distributing risk
Flat retry timingTiered backoff plus jitterRetries do not synchronize into self-inflicted bursts
Stateless authStateful quota awarenessThe system remembers which identities are fragile

The important detail is that the model for selection is not static. A healthy account today can become a bad choice after a few quota hits, and the tracker is built to notice that drift fast enough to matter.

Request shaping is where the model behavior changes

Once a request is in flight, the plugin stops being a passive pipe. It reshapes the body, routes between quota pools, and primes thinking sessions so the downstream model behaves the way the caller expects. That is the boundary where the repo moves from auth into session control.

function buildThinkingWarmupBody(prompt: string) {
  return {
    model: "claude-opus-4.6-thinking",
    thinking: true,
    messages: [{ role: "user", content: prompt }],
  };
}

const route = cliFirst ? "gemini-cli" : "antigravity";
const body = buildThinkingWarmupBody(userPrompt);

This is also why the project feels risky and disciplined at the same time. It does not merely hope the backend cooperates. It actively nudges the request into the shape most likely to succeed, then keeps the session warm enough to keep working.

Storage, concurrency, and the cost of many identities

The more accounts you manage, the more storage stops being a convenience and becomes a correctness problem. The repo packs refresh token, project ID, and managed project ID into a single persisted string, then uses locking to keep concurrent writers from corrupting shared state.

Simple clientThis repoWhy it matters
One process, one tokenMany sessions, one shared account storeConcurrency becomes a data-integrity issue
Plain refresh token storagePacked token plus project metadataCredential state stays portable across flows
Best-effort writesLockfile-protected updatesTwo writers do not race each other into corruption

That design tells you what kind of system this is. It is not a user-facing plugin that caches a few secrets. It is a coordination layer that expects motion, contention, and recovery.

Why this repo feels more like infrastructure than a plugin

Ordinary auth helpers answer a narrow question: can I log in? This repository answers a harder one: can I keep traffic flowing while the backend changes its mind, quota windows close, and identities age out at different speeds?

Ordinary OAuth helperThis repoWhy it matters
Authenticate onceAuthenticate, score, rotate, and recoverAccess is treated as an ongoing system
Pass credentials throughShape requests and warm sessionsBehavior changes, not just permissions
Retry on errorPreemptive routing with jittered backoffThe system avoids predictable failure patterns
Single-account simplicityMulti-account state managementThe architecture resembles a control plane

That is the editorial takeaway. Whatever one thinks of the use case, the engineering pattern is clear: observe, score, route, retry, and adapt. The plugin is built like a control plane because that is what keeping shadow access alive demands.