Skip to content

feat(agent): add Antigravity (agy) CLI agent#1287

Open
peyton-alt wants to merge 8 commits into
mainfrom
feat/antigravity-agent
Open

feat(agent): add Antigravity (agy) CLI agent#1287
peyton-alt wants to merge 8 commits into
mainfrom
feat/antigravity-agent

Conversation

@peyton-alt
Copy link
Copy Markdown
Contributor

@peyton-alt peyton-alt commented May 28, 2026

https://entire.io/gh/entireio/cli/trails/444

Summary

  • Adds first-class support for Antigravity CLI (agy), Google's successor to Gemini CLI as of 2026-05, as a new agent in the Entire CLI. Mirrors the Gemini/Claude integration model: agent package implements Agent + HookSupport, installs hooks into .agents/hooks.json, and routes pre-tool-use / post-tool-use / pre-invocation / post-invocation / stop hooks through entire hooks antigravity <verb>.
  • Verified end-to-end against the real agy binary: shadow branch creation, files_touched capture, Entire-Checkpoint: <hex> trailer on user commits, and matching Checkpoint: <hex> entry on entire/checkpoints/v1.
  • Registered for the E2E suite (E2E_AGENT=antigravity) and covered by integration tests at cmd/entire/cli/integration_test/antigravity_test.go.

Notable real-agy quirks (all hardened in code + tests)

  • invocationNum is 0-indexed despite docs reading like 1-based — parsePreInvocation gates TurnStart on invocationNum == 0, dropping per-invocation follow-ups so the framework's pre-prompt state isn't clobbered after tool calls.
  • agy writes its transcript AFTER Stop fires. Implements TranscriptPreparer to materialize an empty placeholder, so the framework's fileExists check in handleLifecycleTurnEnd doesn't abort.
  • Stop maps to TurnEnd, not SessionEnd, so SaveStep runs (shadow branch commit + step_count++) and the eventual git commit actually condenses.
  • agy 1.0.0 double-encodes tool args ("TargetFile":"\"foo.txt\"", "Overwrite":"true"). decodeAgyString / decodeAgyBool tolerate both the docs shape and the actual wire shape.
  • macOS /tmp/private/tmp symlink would filter agy-supplied paths as "outside repo"; resolveAgySymlinks resolves parent-dir symlinks.

Known v1 gaps (documented inline)

  • Resume sessions (agy --continue, agy --conversation <id>) start with invocationNum > 0, so they don't fire TurnStart. Tracking only works on fresh conversations until we add a state-existence check.
  • No "tracked by entire" banner in the agy UI. Other agents that expose a SessionStart-equivalent hook (Claude Code, Gemini CLI) print a one-line banner inside the agent terminal confirming that the session is being checkpointed. agy does not expose a session-start hook, so we cannot inject that banner — entire still tracks the session (entire status lists it, checkpoints land, commits get the trailer), it's just silent in the agy UI. Matches the existing pattern for Cursor / OpenCode / Copilot CLI / Pi, which also lack the hook. Will be addressed if Google adds a session-start hook surface.
  • Transcript field-aware decoding (token counts, prompt-line attribution) is deferred — prompt_attributions lands with zero line counts in v1.

Test plan

  • mise run check (fmt + lint + unit + integration + canary E2E) is green locally
  • CI passes
  • Reviewer can install via entire agent add antigravity in a test repo and run a real agy session, then confirm Entire-Checkpoint: <hex> lands on the commit
  • Vogon canary E2E still green (no regression in the deterministic E2E path)
  • Optional: real-agy E2E (mise run test:e2e --agent antigravity) — note costs real API tokens

🤖 Generated with Claude Code


Note

Medium Risk
New agent code paths affect session lifecycle, hook-installed repo files, and checkpoint condensation; risk is mitigated by extensive tests but behavior depends on undocumented agy wire formats.

Overview
Adds preview first-class support for Antigravity CLI (agy): a new antigravity agent package that registers with Entire, installs five workspace hooks into .agents/hooks.json (entire entry → entire hooks antigravity <verb>), and maps hook stdin to lifecycle events (TurnStart, ToolUse, TurnEnd).

Lifecycle behavior is tailored to real agy quirks: TurnStart only when invocationNum == 0 (follow-up pre-invocations are ignored so baselines aren’t reset); Stop with fullyIdleTurnEnd (so SaveStep/checkpoints run); post-invocation is a no-op because transcripts aren’t ready yet; PrepareTranscript creates an empty placeholder when the transcript file is still missing after stop. Pre-tool-use records touched files from mutating tools, including double-encoded args and parent-dir symlink normalization (macOS /tmp).

Also wires non-interactive GenerateText via agy -p, JSONL transcript chunk/reassemble (passthrough v1), registry/hooks CLI imports, integration tests over subprocess hooks, and optional E2E registration when agy is on PATH.

Reviewed by Cursor Bugbot for commit f141838. Configure here.

peyton-alt and others added 5 commits May 20, 2026 18:29
Adds AntigravityAgent (Agent + HookSupport surface), registry constants,
camelCase stdin/stdout types for the five Antigravity hook events
(PreToolUse, PostToolUse, PreInvocation, PostInvocation, Stop), transcript
JSONL passthrough via shared agent.ChunkJSONL helpers, GenerateText for
summary-provider integration, and a DiscoverReviewSkills stub. Layout
matches docs/architecture/agent-guide.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: b1371f1a4c7c
Writes .agents/hooks.json with five event handlers and translates
Antigravity's PreToolUse/PostToolUse/PreInvocation/PostInvocation/Stop
into Entire's normalized lifecycle events. PreInvocation always emits
TurnStart; the framework's idempotent strategy.InitializeSession
(cli/lifecycle.go:406) handles first-arrival state creation. Stop with
fullyIdle=false returns nil to avoid finalizing while background
tasks run.

Also restores two //nolint:ireturn directives removed in Chunk 1 that
were blocking golangci-lint on NewCommittedReader and committedCheckpointStore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 6e0dacb51f81
End-to-end integration test drives the five Antigravity hook events
(pre-invocation, pre-tool-use, post-tool-use, post-invocation, stop) via
synthetic stdin payloads against a real git repo. Verifies session state
lazy-inits on first PreInvocation, write_to_file PreToolUse populates
state.FilesTouched, and stop with fullyIdle=true completes the SessionEnd
flow cleanly.

Documents the real Antigravity 2.0 transcript layout in transcript.go
(~/.gemini/antigravity-cli/brain/<conv-id>/.system_generated/logs/transcript.jsonl
with a step_index/source/type/status/created_at/content/tool_calls schema)
based on a captured fixture. The on-disk decoder remains deferred per the
deferred-table; v1 ships only the JSONL passthrough.

Drops the dead .gemini/jetski/ branch from DetectPresence since agy stores
runtime data user-scope, not workspace-scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: a422980bd082
Adds the e2e/agents/Antigravity runner so the existing agent-agnostic
test suite (clean, disable, doctor, attach, resume, rewind, explain,
interactive, multi_session, edge_cases) automatically parameterizes
over antigravity via ForEachAgent when E2E_AGENT=antigravity. Mirrors
the droid/gemini patterns: -p prompt flag, --dangerously-skip-permissions,
tmux-backed StartSession.

PromptPattern is a placeholder (`>`); the real interactive prompt
pattern will be observed and refined once `agy --print` is reliable.
Antigravity-specific test cases (hook-config-location, first-prompt
checkpoint, rewind) are deferred to the same follow-up since they
require a working interactive agy session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 3b02d2cbf01a
Real-agy smoke testing showed our PreInvocation gate inverted: agy 1.0.0
ships invocationNum 0-indexed, so the actual first model call carries
invocationNum=0 and the follow-up carries invocationNum=1. The old
`!= 1` gate dropped the real turn-start and re-fired TurnStart on the
follow-up, clobbering preState after tool calls had already mutated
files — surfacing as "no files modified during session, skipping
checkpoint" at commit time.

Captured wire format:
  PreInvocation #1: {"invocationNum":0,"initialNumSteps":1,...}  ← turn start
  PreInvocation #2: {"invocationNum":1,"initialNumSteps":5,...}  ← follow-up

The gate is now `invocationNum != 0`. Test fixtures (synthesized payload
in lifecycle_test, captured fixture in testdata, integration test in
integration_test) all updated to mirror the real wire shape so the test
pyramid no longer agrees with the wrong invariant. transcript.go has a
gofmt-only reformat of an existing doc comment.

Verified end-to-end against real agy: shadow branch created, files_touched
captured, `Entire-Checkpoint: <hex>` trailer appears on `git commit`,
matching `Checkpoint: <hex>` lands on entire/checkpoints/v1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Entire-Checkpoint: 7bfaeb05bf4d
Copilot AI review requested due to automatic review settings May 28, 2026 09:06
@peyton-alt peyton-alt requested a review from a team as a code owner May 28, 2026 09:06
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class preview support for the Antigravity (agy) CLI agent, wiring it into Entire’s agent registry, hook handling, transcript lifecycle, text generation, integration tests, and optional E2E coverage.

Changes:

  • Introduces a new agent/antigravity package with identity, hook install/uninstall, lifecycle parsing, transcript handling, text generation, and discovery stubs.
  • Registers Antigravity in hook routing, agent constants, tests, and E2E agent support.
  • Adds fixtures and unit/integration coverage for Antigravity hook payloads, lifecycle behavior, hook config management, and transcript preparation.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
e2e/agents/antigravity.go Adds E2E runner support for agy.
e2e/agents/antigravity_test.go Adds basic E2E agent identity tests.
cmd/entire/cli/integration_test/antigravity_test.go Adds integration coverage for Antigravity hook flow.
cmd/entire/cli/hooks_cmd.go Registers Antigravity hooks command package.
cmd/entire/cli/agent/registry.go Adds Antigravity agent name/type constants.
cmd/entire/cli/agent/generate_external_test.go Adds Antigravity text generation test coverage.
cmd/entire/cli/agent/antigravity/antigravity.go Defines Antigravity agent identity and core methods.
cmd/entire/cli/agent/antigravity/antigravity_test.go Tests agent registration, interfaces, and presence detection.
cmd/entire/cli/agent/antigravity/discovery.go Adds review skill discovery stub.
cmd/entire/cli/agent/antigravity/generate.go Adds non-interactive agy text generation.
cmd/entire/cli/agent/antigravity/hooks.go Adds .agents/hooks.json install/uninstall/status handling.
cmd/entire/cli/agent/antigravity/hooks_test.go Tests hook config installation behavior.
cmd/entire/cli/agent/antigravity/lifecycle.go Maps Antigravity hook payloads to Entire lifecycle events.
cmd/entire/cli/agent/antigravity/lifecycle_test.go Tests lifecycle parsing and file extraction edge cases.
cmd/entire/cli/agent/antigravity/transcript.go Adds JSONL transcript read/chunk/reassemble and preparation.
cmd/entire/cli/agent/antigravity/transcript_test.go Tests transcript round-trip and placeholder creation.
cmd/entire/cli/agent/antigravity/types.go Defines Antigravity hook payload/config types.
cmd/entire/cli/agent/antigravity/types_test.go Tests fixture decoding for hook payload types.
cmd/entire/cli/agent/antigravity/testdata/hook_stdin_pre_invocation.json Adds PreInvocation fixture.
cmd/entire/cli/agent/antigravity/testdata/hook_stdin_post_invocation.json Adds PostInvocation fixture.
cmd/entire/cli/agent/antigravity/testdata/hook_stdin_pre_tool_use.json Adds PreToolUse fixture.
cmd/entire/cli/agent/antigravity/testdata/hook_stdin_post_tool_use.json Adds PostToolUse fixture.
cmd/entire/cli/agent/antigravity/testdata/hook_stdin_stop.json Adds Stop fixture.
cmd/entire/cli/agent/antigravity/testdata/transcript_sample.jsonl Adds sample Antigravity JSONL transcript fixture.

Comment thread cmd/entire/cli/agent/antigravity/generate.go
Comment thread cmd/entire/cli/agent/antigravity/hooks.go
Comment thread cmd/entire/cli/agent/antigravity/hooks.go
Comment thread cmd/entire/cli/agent/antigravity/lifecycle.go Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f141838. Configure here.

Comment thread e2e/agents/antigravity.go Outdated
peyton-alt and others added 3 commits May 28, 2026 11:24
Three correctness fixes surfaced by Copilot and Cursor Bugbot review:

1. Register antigravity in summaryProviderBinaries. The GenerateText
   implementation in cmd/entire/cli/agent/antigravity/generate.go was
   dead code because IsSummaryCLIAvailable filtered antigravity out
   even when `agy` was installed on PATH. Adding the map entry makes
   `entire explain` and summary-provider selection see it. Matches the
   pattern for the other five agents that ship a generate.go.

2. resolveAgySymlinks now walks up to the deepest existing ancestor.
   The previous implementation only EvalSymlinks'd the immediate
   parent and silently returned the unresolved path if that parent
   didn't exist — which fires the moment agy creates a file inside a
   new nested directory (e.g. /tmp/repo/newdir/file.txt). The
   unresolved path then gets filtered as "outside repo" on macOS via
   the /tmp → /private/tmp symlink, silently breaking files_touched
   capture. Added two regression tests: one for the new-nested-dir
   case, one pinning the "no resolvable ancestor → return input"
   fallback.

3. Filter HOME before appending the test-home override in
   antigravityPromptEnv. The previous code appended HOME=... to an
   env that already contained HOME, and getenv returns the first
   match — so agy ran under the user's real home, defeating E2E test
   isolation. Mirrors codex.go's filtering of CODEX_HOME and pi.go's
   filtering of PI_CODING_AGENT_DIR.

Two further bot comments about hooks.go install/uninstall over-eagerly
owning the "entire" top-level key in .agents/hooks.json are skipped
intentionally: by convention "entire" IS our bucket name, and the
idempotency comparison in InstallHooks already protects against
clobbering an identical config. Other agents (claude-code, gemini-cli)
use a per-handler `entire-` prefix model because their hook schema is
a flat array; antigravity's nested top-level-bucket schema is
sufficiently different that adopting the prefix dance would add
complexity without a real-world payoff.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Entire-Checkpoint: 58eff1cb1cf5
Three issues prevented `mise run test:e2e --agent antigravity` from
actually exercising the integration:

1. Drop `--model gemini-2.5-flash`. agy 1.0.2 has no --model flag, so
   passing it made agy exit 2 with "flags provided but not defined".
   Model selection lives in settings.json; tests accept agy's default
   for now.

2. Drop HOME isolation. Pointing HOME at a fresh per-test dir stranded
   agy's auth, install id, and onboarding state under HOME/.gemini/,
   causing agy to re-trigger the browser auth flow on every run.
   Selective symlink-seeding chases a moving target as agy adds new
   state files. Sharing the real HOME lets agy authenticate; the test
   repo (cmd.Dir) still scopes workspace mutations. CI will need a
   proper HOME-isolation surface (or a dedicated test account) before
   the real-agy suite is wired into CI — out of scope here.

3. Pass `--add-dir <dir>` in print mode. Without it, agy ignores cwd
   and falls back to ~/.gemini/antigravity-cli/scratch/ — it init'd a
   brand-new git repo there and committed the test file there while
   the actual test repo stayed empty.

Validated locally: a 14.8s real-agy run of
TestSingleSessionAgentCommitInTurn now passes (hooks fire,
files_touched captured, checkpoint advances on user commit).

Entire-Checkpoint: 6a895268cec9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants