Skip to content

✨ feature: add Google Antigravity agents and models to the dashboard - #5410

Merged
clubanderson merged 1 commit into
kubestellar:v4from
Danathar:feat/dashboard-agy-models
Sep 1, 2026
Merged

✨ feature: add Google Antigravity agents and models to the dashboard#5410
clubanderson merged 1 commit into
kubestellar:v4from
Danathar:feat/dashboard-agy-models

Conversation

@Danathar

@Danathar Danathar commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Hive already accepts backend: agy, installs Google's Antigravity CLI in the
    main image, and launches it with the model/effort pairing the CLI requires.
    The dashboard did not expose that support: agy was absent from every agent
    method dropdown, so an operator could select it only by editing configuration
    outside the UI.
  • The omission had a second, less visible failure behind it. The dashboard's
    model picker has an explicit per-CLI catalog, but an unregistered CLI falls
    through to COPILOT_CLI_MODELS. Adding only an agy method option would
    therefore advertise Copilot models that Antigravity does not support.
  • This makes Google Antigravity (agy) a first-class dashboard method and
    gives it its own account-aware model inventory. The server runs the vendor's
    agy models command against the same .gemini state the agents use; the UI
    receives the live IDs through /api/config/backends and keeps an 11-model
    static floor for first paint and failed/offline discovery.
  • Blast radius: dashboard method/model selection and the read-only backend
    catalog endpoint. The existing agy launcher, contributor path, authentication
    flow, billing classification, and fixed --effort low launch invariant are
    unchanged.

Observable failure

The backend is valid everywhere below the dashboard:

  • config.CLIBackends contains agy, so config validation accepts it;
  • config/backends.conf maps it to the agy binary;
  • agent.backendLaunchCmd supplies --dangerously-skip-permissions and, when a
    model is set, --model <id> --effort low;
  • both the hub and contributor images install Antigravity.

But static/index.html's independently maintained KNOWN_BACKENDS did not
contain agy. Every agent-card and detail-panel method selector renders from
that array, so the supported backend was impossible to choose on the dashboard.

Nor was adding one string sufficient. Before this change,
modelsForBackend('agy') reached the generic unknown-backend branch:

return CLI_FALLBACK_MODELS[backend] || COPILOT_CLI_MODELS;

That would put Claude/GPT models in Antigravity's dropdown based on GitHub
Copilot's catalog rather than on what agy --model accepts.

Root cause

The authoritative Go/shell backend registries and the dashboard picker are
deliberately separate. backend_picker_parity_test.go guarded the dangerous
direction — every UI option must be launchable — but explicitly allowed the
reverse direction, where a launchable backend is omitted from the UI. That is
reasonable for contributor-only or otherwise constrained CLIs, but it meant the
existing agy support could not make the dashboard fail a test by drifting behind
it.

The model layer repeated the same shape. queryCLIModels and
cliStaticFallback had backend-specific cases for Copilot, Claude, Gemini,
Goose, Codex, and bob, while the frontend had its own CLI_BACKENDS and
CLI_FALLBACK_MODELS maps. agy existed in none of those four places. The
unknown-backend Copilot fallback then hid the omission by returning a non-empty,
but wrong, dropdown.

Change

Dashboard method and first-paint catalog

src/pkg/dashboard/static/index.html now:

  • includes agy in KNOWN_BACKENDS, so both agent method selectors offer it;
  • renders the readable label Google Antigravity (agy) while preserving
    agy as the stored backend ID;
  • includes agy in the client-side CLI_BACKENDS discovery allowlist;
  • maps it to a dedicated AGY_CLI_MODELS fallback rather than Copilot's list.

The fallback is the exact 11-ID order returned by the locally installed
Antigravity CLI 1.1.18 on 2026-08-31:

gemini-3.7-flash-high       Gemini 3.7 Flash (High)
gemini-3.7-flash-medium     Gemini 3.7 Flash (Medium)
gemini-3.7-flash-low        Gemini 3.7 Flash (Low)
gemini-3.6-flash-high       Gemini 3.6 Flash (High)
gemini-3.6-flash-medium     Gemini 3.6 Flash (Medium)
gemini-3.6-flash-low        Gemini 3.6 Flash (Low)
gemini-3.1-pro-high         Gemini 3.1 Pro (High)
gemini-3.1-pro-low          Gemini 3.1 Pro (Low)
claude-sonnet-4-6           Claude Sonnet 4.6 (Thinking)
claude-opus-4-6-thinking    Claude Opus 4.6 (Thinking)
gpt-oss-120b-medium         GPT-OSS 120B (Medium)

These are preserved verbatim. In particular, the -high/-medium/-low
suffixes are part of Antigravity's model IDs; this PR does not reinterpret them
as Hive's separate reasoning-effort setting.

Account-aware server discovery

New src/pkg/dashboard/cli_models_agy.go adds agy to the existing CLI model
pipeline:

  • agy models is bounded by a five-second timeout and parsed as the CLI's
    observed tab-delimited <id>\t<display name> output;
  • when /data/home exists, the subprocess runs with that HOME and working
    directory. Per-UID interactive homes already bridge .gemini back there, so
    the probe sees the same signed-in account as the agents without guessing one
    agent's home or reading OAuth files itself;
  • stdout is parsed only for model records; stderr/progress logs are discarded
    and never copied into Hive logs;
  • missing binary, signed-out state, timeout, command failure, changed output,
    or an empty list returns fallback=true and the static floor. A format change
    is never treated as an authoritative empty catalog, which could otherwise
    auto-heal agents away from working models;
  • successful results use the existing 30-second cache and three-live-miss
    retention machinery, so one transient omission does not churn agent models.

handleBackends now returns an agy entry with its models and fallback flag, and
the frontend consumes it through the same /api/config/backends path as the
other CLIs.

Regression coverage and operator record

cli_models_agy_test.go covers the output parser, live and failed probes, the
missing-binary path, UI visibility, exact frontend/Go fallback parity, and the
actual /api/config/backends wire response. The generic picker-parity comment is
updated to point backend-specific visibility promises at explicit tests, while
retaining its original picker-must-be-dispatchable invariant.

CHANGELOG.md records the user-visible method and model selection support under
Unreleased → Added.

Design decisions and boundaries

Use agy models, not the Gemini API. Antigravity's observed catalog is not a
Gemini-only list: it includes Claude and GPT-OSS IDs and is scoped to the Google
account signed into the CLI. Reusing discoverGeminiModels would query a
different product/auth mechanism and return models that are not proof of agy
support.

Live list plus static floor, not either one alone. A hardcoded-only list
would become stale as Google changes the service. A live-only list would leave a
blank dropdown on first paint, on developer builds without the binary, and on a
hive whose operator has not signed in yet. The existing fallback contract
makes that distinction visible and prevents fallback data from driving
auto-heal.

No OAuth handling in Hive. The probe delegates credential resolution to the
vendor CLI and does not parse, refresh, log, or transport .gemini contents.
This preserves the existing ownership boundary and avoids rotating state out
from under a running agent.

No authentication claim. This does not solve fresh headless Kubernetes
authentication. agy still has interactive Google OAuth and no API-key mode; an
operator must seed a usable session. #5406 remains open for verifying that path.

No launcher or effort change. Selecting a model still reaches the existing
launch command as --model <id> --effort low. agy requires an effort flag
whenever a model is supplied; per-agent effort selection is a separate feature
and is not introduced here.

Testing

  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go build ./...
    — passed.
  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go test ./pkg/dashboard -count=1
    — passed, 55.490s.
  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go test ./pkg/dashboard -run '^(TestParseAgyModelsOutput|TestParseAgyModelsOutputRejectsChangedFormat|TestQueryCLIModelsAgyLiveInventory|TestQueryCLIModelsAgyFailureUsesStaticFallback|TestExecAgyModelsProbeBinaryMissing|TestDashboardOffersAgyWithDedicatedModels|TestHandleBackendsServesAgyInventory|TestBackendPickerOffersOnlyDispatchableBackends|TestBackendPickerInferenceListMatchesGo)$' -count=1
    — passed (0.038s): parser success/changed-format refusal,
    live/fallback/missing-binary discovery, picker visibility and dispatchability,
    exact JS/Go fallback parity, and backend API response.
  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go test ./pkg/config -run '^(TestValidateBackend_AcceptsAllSupported|TestShellAndGoCLIBackendListsAgree|TestBackendBinaryAndPermFlagCoverKnownBackends)$' -count=1
    — passed (0.071s).
  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go test ./pkg/agent -run '^(TestStart_AgyLaunchCommandLine|TestAgyLaunchCommandLine_NoModel|TestInvocationMetadata|TestBackendBinaryName_AgyLaunchesAntigravityCLI|TestAcceptedBackendsAreLaunchableByConstruction)$' -count=1
    — passed (0.005s).
  • agy --version / agy models against the existing signed-in local CLI —
    version 1.1.18, 11 records matching the checked-in fallback order.
  • cd src && env GOCACHE="$PWD/.test-cache/go" GOTMPDIR="$PWD/.test-cache/tmp" CCACHE_DIR="$PWD/.test-cache/ccache" go test ./pkg/config ./pkg/agent -count=1 — the broad run
    reached unrelated environment-sensitive failures. pkg/config's
    TestGateFailsClosedWithoutIP6Tables saw the host's real unprivileged
    ip6tables (Permission denied) instead of its intended missing-binary
    condition, and three TestEntrypointHardensRuntimeConfigItRecreates cases
    could not chown without root/CAP_CHOWN, leaving test files 0644 instead of
    0600. pkg/agent had one timing failure,
    TestSendKick_RestartsCrashedCLIThenDelivers; rerunning that exact test in
    isolation passed in 9.415s. None touches dashboard/model discovery code.

The default Go and ccache locations are read-only in this workspace, so the
commands above redirect only build caches into a temporary, removed directory;
the tested source and command semantics are otherwise unchanged.

Related issues

Related: #5406 tracks the still-unverified agy headless Kubernetes authentication
path; this PR deliberately does not close it.

Contributor checklist

  • PR targets v4 (the repository's default branch).
  • Title uses the repo emoji convention.
  • Commit includes DCO sign-off (git commit -s).
  • Docs, examples, and policies are updated when behavior changes — the
    user-visible change is recorded in CHANGELOG.md; the existing backend setup
    guide already documents agy's install, auth, model, effort, and confinement
    contract.
  • CHANGELOG.md has an entry under Unreleased → Added.
  • No secrets, credentials, local runtime state, or probe output containing
    account data are committed.

Signed-off-by: Douglas Baggett <doug.baggett@gmail.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Sep 1, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign hanthor for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Sep 1, 2026
@kubestellar-hive

Copy link
Copy Markdown
Contributor

Quality verification (live hive host): fetched pull/5410/head and ran go test ./pkg/dashboard/ -run 'Agy|AGY|Antigravity|CLIModels|BackendPicker|Models' — green. Function-level coverage on the touched files is solid: cli_models_agy.go parse/canonicalize paths and cli_models.go cache/query/stabilize are 90–100%. Residual gaps are the live-credential branches (copilotAPIHost/parseCopilotAPIHost 0%, discoverGeminiModels 33%) — pre-existing, not introduced here. No concerns from the quality side.

Filed by quality agent (hold-gated mode).

🐝 Hive Agent: quality | Instance: hosted-available-oke-11-placeholder-r05x | SHA: unknown

— hive: agent=quality backend=copilot model=claude-fable-5

@clubanderson
clubanderson merged commit 5d8d0f4 into kubestellar:v4 Sep 1, 2026
41 of 42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants