Skip to content

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

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

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

Conversation

@peyton-alt

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

Copy link
Copy Markdown
Contributor

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

Summary

Status: Preview. The integration ships with IsPreview() == true — users see a "(Preview)" label in the agent selector, entire agent list, and the hook-install message. Known limitations are listed below and in docs/architecture/agent-guide.md ("Antigravity status: Preview").

First-class support for Antigravity CLI (agy), Google's successor to Gemini CLI, as a new Entire agent — the complete integration: lifecycle hooks, transcript decoding, native token counts, review-skill discovery, resume tracking, docs, and E2E wiring. Consolidates the previously stacked PRs #1356 (tokens) and #1381 (transcript decode) plus the gap-fix and review-fix rounds into this single parent.

Scope map (~7.2k insertions; ~60% tests):

Area What
cmd/entire/cli/agent/antigravity/ agent package: 3 lifecycle hooks (pre-tool-use, pre-invocation, stop), transcript analyzers (prompts, positions, modified files), async-transcript handling, token tee (statusline.go/title_install.go), review-skill discovery
cmd/entire/cli/lifecycle.go, state.go, event.go conditional TurnStart (resume tracking), out-of-band token baseline/delta, committed-state filtering for mid-turn commits
cmd/entire/cli/strategy/ empty-transcript degrade (agy-scoped), late-flush prompt recovery, checkpoint-scoped token resolution, agy summary/count cases
agent/skilldiscovery/ shared SKILL.md scanner (claude-code rewired onto it)
e2e + CI agy runner with ADC plumbing and fatal-vs-transient classification; dispatch-only in workflows (see limitations)
docs CLAUDE/AGENTS, architecture guide quirks section, checklist, e2e README

Real-agy quirks (all hardened in code + tests)

  • invocationNum is 0-indexed; PreInvocation fires per model invocation. invocationNum > 0 emits a conditional TurnStart (Event.SuppressIfSessionActive) the dispatcher drops only when a turn is genuinely mid-flight — so resumes (agy --conversation) are tracked and follow-up invocations don't clobber the pre-prompt baseline.
  • agy writes its transcript AFTER Stop. PrepareTranscript briefly waits then materializes a placeholder; condensation degrades to a files/prompt-only checkpoint (agy-scoped) and prompts are re-extracted late (resolvePromptsFromLateFlushedTranscript).
  • Tokens have exactly one surface — the title/statusline JSON. The global title slot is claimed by entire hooks antigravity title-tee (wrap-preserving, doctor-checked); TurnStart snapshots a baseline, TurnEnd computes the delta (OutOfBandTokenSource).
  • Tool args are double-encoded; decodeAgyString/decodeAgyBool tolerate both shapes. macOS /tmp symlinks resolved.
  • No SessionStart hook surface → silent tracking (same as Cursor/OpenCode/Copilot/Pi). agy's PostToolUse/PostInvocation hooks are deliberately not installed — no lifecycle mapping, and they'd spawn a no-op subprocess per tool call.

Review & verification

  • Three-dimension agent review (correctness / over-engineering / hooks-and-docs-vs-agy-1.0.15) followed by a 28-agent adversarially-verified full-implementation review; all 10 verified findings fixed (token double-counting, tokens lost on fully-committed turns, deletion-filter regression, cross-worktree title-tee uninstall, e2e retry masking, degrade scoping, hook-prefix matching, + 3 cleanups).
  • Hook contract verified byte-for-byte against agy's official docs (1.0.15 changed no hook behavior).
  • Analyzer methods validated against 385 real captured agy transcripts: 0 errors, 0 offset mismatches; full-pipeline replay of a real transcript reproduces prompts/files/checkpoint contents.
  • Live smoke on this tip: entire agent add antigravity → real hook wiring → mid-turn commit with unwritten transcript → checkpoint + trailer + scoped tokens + entire status all correct. Real agy fired PreInvocation live (session state created); the model call itself is quota-gated (below).
  • 2026-07-13 review round (3-reviewer pass + live testing on real agy): TestSingleSessionManualCommit passed live with real token counts; fresh-repo smoke verified install → live turn → commit → condensation → resume (agy --conversation) → token scoping across two commits. agy auto-updated 1.0.16→1.1.1 mid-session; hook wire contract re-verified unchanged, but agy 1.1 moved the skill-discovery directories — fixed, along with the ADC-mode quota-log peek, a doctor false-positive for non-agy teammates, an explicit Stop-hook timeout, and an agent remove warning about the global title-tee. Deferred minors are tracked as findings on trail 444.

Behavior note (all agents): the ghost-session fix intentionally changes shadow-branch preservation — a read-only ACTIVE session (no tracked files) no longer keeps its shadow branch alive on commit (phase_postcommit_test.go updated accordingly). Both checkpoint writers skip zero-file writes, so nothing such a session wrote can be stranded.

Known limitations (preview)

  • Live agy E2E is quota/entitlement-gated: agy has no API-key auth; consumer OAuth quota is small and its cloudcode-pa backend can't be enabled on arbitrary GCP projects (subject 110002 — needs a Gemini Code Assist subscription). Hence agy is a workflow_dispatch-only E2E leg, with fail-fast classification so quota/entitlement walls read as clear errors, not retry storms. Details in e2e/README.md.
  • Mid-turn-commit checkpoints record zero tokens (the turn's delta lands on the next condensation — totals stay correct; documented at the fallback).
  • No in-agy banner (no SessionStart hook surface) — tracking is silent inside the agy UI; entire status is the visibility surface.
  • First-turn mid-turn commits can produce a files/prompt-only checkpoint (agy's transcript lands after Stop); prompts recover on the next condensation.
  • Token capture depends on entire hooks antigravity title-tee owning/wrapping agy's global title slot (doctor-checked, setup-repaired).
  • Wire format captured on agy 1.0.14/1.0.15 and re-verified unchanged on agy 1.1.1 (2026-07-13); agy is fast-moving — 1.1 already moved the skill directories (handled).

Test plan

  • mise run check green locally (fmt, lint 0 issues, unit + integration + canary)
  • CI green on this tip (all 12 checks)
  • Analyzer validation against 385 real transcripts + real-transcript pipeline replay
  • Live smoke of install → hooks → commit → checkpoint → status on this tip
  • mise run test:e2e --agent antigravity TestSingleSessionManualCommit — passed live 2026-07-13 (real agy, real tokens in the condensed checkpoint)
  • Live fresh-repo smoke 2026-07-13: enable → live agy turn → commit/trailer/condensation → resume via agy --conversation → checkpoint-scoped token deltas across two commits

🤖 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 7 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
Adds two components that let entire capture agy token usage — the only
surface where agy exposes token data is the JSON payload it pipes to the
user-configured title/statusline command on every agent state change.

Task 1 — Snapshot store (statusline.go / statusline_test.go):
- AppendStatusSnapshot() parses the agy state JSON, deduplicates against
  the last persisted line (by compact-remarshaling the context_window),
  and appends a timestamped JSONL line to
  <ENTIRE_ANTIGRAVITY_STATUS_DIR|XDG_CACHE>/entire/antigravity/status/<conv_id>.jsonl.
- Silently ignores malformed/incomplete payloads; only genuine I/O errors
  propagate.
- Dedup reads only the last line of the file (seek-free linear scan) for
  O(file-size) worst-case but O(1) typical-case performance.
- Prunes stale files (>14d) only when a new conversation file is first
  created, keeping the hot path to a single open+write.

Task 2 — title-tee shim (hooks_antigravity_title.go / _test.go):
- `entire hooks antigravity title-tee [--wrap '<cmd>']` reads stdin, calls
  AppendStatusSnapshot (best-effort), then optionally chains the user's
  original title command via sh -c so their window title is preserved.
- Never exits non-zero; never writes noise to stdout (agy renders stdout
  verbatim as the terminal window title).
- Registered on the antigravity hooks subtree, not through
  executeAgentHook, so it works outside git repos and without entire being
  enabled.

Perf numbers (Apple M4 Pro, arm64, macOS 25.3):
- End-to-end shim: 20-run warm avg = 41ms (budget ≤50ms); total = 830ms
  (budget ≤1000ms).
- BenchmarkAppendStatusSnapshot_GrownFile (500-line file, dedup path,
  100x): ~79µs/op (budget ≤2ms/op).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
peyton-alt and others added 12 commits June 4, 2026 10:59
…lDev + comments

Addresses PR #1356 review (Cursor Bugbot + Copilot):
- InstallHooks now runs InstallTitleTee BEFORE the repo-hooks idempotency
  early-return, so re-running setup repairs a missing/stale global title slot
  (upgrade, failed first install, or 'agent add' without --force). Regression
  test added.
- localDev title command bakes the absolute main.go path at install time
  instead of a runtime $(git rev-parse) that would resolve against the wrong
  repo (the title slot is global). Falls back to the PATH form if unresolved.
- Fix shellSingleQuote doc comment (stray curly quote) and the dedup comment
  to accurately describe the whole-file streaming read.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… comments)

- condensation: gate out-of-band token fallback on AsOutOfBandTokenSource
  (purpose-built capability) instead of the !AsTokenCalculator inverse, so
  only OOB agents inherit accumulated SessionState.TokenUsage; add a
  negative-branch test proving a non-OOB agent (Cursor) does not.
- title-tee: log a debug breadcrumb on AppendStatusSnapshot failure instead
  of discarding the error; contract unchanged (no stdout, returns nil).
- comments: correct readLastContextWindow doc (streams the file), reframe
  AsOutOfBandTokenSource exclusion rationale, note sh -c wrap is the user's
  own settings.json command (not an injection surface).
- lifecycle: use slog.String for the OOB warn log to match the file's local
  convention.
- tests: current_usage change is not deduped; --wrap path still captures the
  snapshot; delta is zero (nil) when baseline is the latest snapshot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test-auditor pass:
- Remove TestTitleTee_WrapPipesPayloadThrough — a strict subset of
  TestTitleTee_WrapStillCapturesSnapshot (which makes the same passthrough
  assertion plus the snapshot-capture check). Zero coverage lost.
- Rewrite TestCalculateTokenUsageSince_ClampsWhenTotalsGoBackwards to assert
  usage == nil directly (the actual all-zero path) instead of guarded
  conditionals that never executed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…T steps

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… fixture

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion is implemented

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on for late-flush agents

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…file extraction)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n commit checkpointing

- GetSessionDir/ResolveSessionFile compute the real agy brain-dir transcript
  path (~/.gemini/antigravity-cli/brain/<id>/.system_generated/logs/
  transcript_full.jsonl) instead of returning empty, with a test-override env
  for isolation.
- Implement WriteSession (was a no-op) with validation so restore/rewind can
  materialise transcripts.
- Add USER_INPUT prompt extraction and PrepareTranscript to handle agy's
  asynchronous transcript write (briefly wait, then placeholder) before the
  framework's fileExists check, so Stop does not exit 1 and kill the turn.
- Skip the redundant TurnEnd checkpoint when a mid-turn commit already
  condensed all tracked files (agy fires Stop after PostCommit).

Verified offline against 376 real agy transcripts (0 parse errors) plus unit
and integration tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@peyton-alt
peyton-alt force-pushed the feat/antigravity-agent branch from 1b5319f to dd95db0 Compare July 1, 2026 15:52
peyton-alt and others added 5 commits July 2, 2026 15:56
- Tolerate an empty live transcript at condensation instead of hard-erroring:
  agy writes its transcript after the Stop hook, so a first-turn mid-turn
  commit condenses against the empty placeholder. Erroring stranded the
  already-stamped Entire-Checkpoint trailer (commit referencing a checkpoint
  that never got written). Degrade to a files/prompt-only checkpoint like the
  shadow-branch path.
- Replace the agy-specific TurnEnd skip guard with general committed-state
  filtering: relNewFiles now go through filterToUncommittedFiles and deletions
  through a new filterToUncommittedDeletions, so a Stop after a mid-turn
  commit skips naturally (totalChanges==0) while genuinely uncommitted late
  work (e.g. files created via shell after the commit) still gets
  checkpointed instead of being silently dropped.
- Don't suppress the conditional TurnStart for stuck-ACTIVE sessions: a
  crashed conversation (Stop never fired) stayed ACTIVE and suppressed every
  resume, running it untracked. Reuse session.IsStuckActive.
- Align countTranscriptItems with agy's readers (non-blank line counting) so
  CheckpointTranscriptStart offsets can't drift across blank lines.
- Add the missing Antigravity case to generateSummary's agent switch — agy
  checkpoints never got auto-summaries despite agy being a summary provider.
- Document the mid-turn token-scoping limitation at the OOB fallback gate.

Integration pins: mid-turn commit with unwritten transcript still condenses
(trailer references a real checkpoint); Stop after mid-turn commit checkpoints
late shell-created files; the existing no-extra-shadow-branch test still holds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Stop installing PostToolUse/PostInvocation hooks: neither maps to a
  lifecycle event, so every completed tool call and model invocation spawned
  an `entire` subprocess that did nothing. HookNames/ParseHookEvent drop the
  verbs (unknown names still parse to a nil event, so stale hooks.json entries
  cannot fail an agy turn) and InstallHooks replaces the whole "entire" entry,
  so existing installs self-heal on the next enable. The HookConfig struct
  keeps the event fields for round-trip fidelity and idempotency detection.
- Delete never-referenced hook output types (PreToolUseOutput,
  InvocationOutput, InjectStep, StopOutput) — the integration never writes a
  hook response by design.
- Trim payload structs to the fields actually consumed (conversationId,
  transcriptPath, toolCall, invocationNum, fullyIdle); the fixtures still
  carry agy's full documented payloads so unknown-field tolerance stays
  pinned.
- Deduplicate the JSON map writers (hooks.json / global agy settings.json)
  into writeJSONMapFile; AppendStatusSnapshot now uses statusFilePath instead
  of re-joining the path inline.
- Comment accuracy: agy docs now state invocationNum is 0-indexed (drop the
  "despite the docs" claim); fix the transcript.go header to name
  transcript_full.jsonl (what the hook payload actually sends).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- CLAUDE.md (and AGENTS.md symlink): add Antigravity to the agent list and
  the E2E agent enumerations/examples.
- docs/architecture/agent-guide.md: add antigravity to the AgentName/AgentType
  registry lists and a new "Antigravity (agy) Wire-Format Quirks" pitfalls
  section (0-indexed invocationNum, transcript written after Stop,
  double-encoded tool args, title/statusline-only token surface, no
  SessionStart, deliberately-uninstalled post hooks).
- docs/architecture/agent-integration-checklist.md: add agy to the canonical
  export and file-based WriteSession agent lists.
- e2e: register antigravity in the workflow dispatch options with agy install
  + ADC secret plumbing, mise task usage/timeout defaults, and README docs.
  Deliberately NOT in the default all-agents matrix (runs on push to main):
  agy has no API-key auth and its cloudcode-pa backend is entitlement-gated,
  so it would fail every automatic run — dispatch it explicitly. README
  documents the entitlement caveat so the ADC plumbing isn't mistaken for
  working out of the box.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	CLAUDE.md
#	cmd/entire/cli/agent/agent.go
#	cmd/entire/cli/agent/text_generator_cli.go
#	cmd/entire/cli/doctor_test.go
#	cmd/entire/cli/strategy/manual_commit_condensation_test.go
#	mise-tasks/test/e2e/_default
Post-merge adjustments after merging origin/main (1,549 commits):
- main renamed checkpoint.CommittedMetadata to checkpoint.Metadata (persistent
  vocabulary, api/checkpoint extraction) — update the merged antigravity token
  metadata tests.
- Extract resolveCondensedTokenUsage from CondenseSession: the merge pushed
  the function over the maintidx threshold; the token fallback chain (out-of-
  band -> transcript backfill -> accumulated per-checkpoint) is now a named,
  documented helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
peyton-alt and others added 13 commits July 2, 2026 23:11
Token accounting:
- Drop the out-of-band fallback that copied session-cumulative
  state.TokenUsage into per-checkpoint metadata — it double-counted earlier
  turns on every checkpoint after the first and preempted the correct
  checkpoint-scoped state.CheckpointTokenUsage fallback (which SaveStep
  already feeds with the same out-of-band delta). The pinning test now sets a
  deliberately larger cumulative total so any regression re-inheriting it
  fails.
- Record the out-of-band token delta even when a turn ends with no
  uncommitted changes (agy committing all its work mid-turn — its normal
  flow): the totalChanges==0 early return skipped SaveStep and then deleted
  the baseline, losing the turn's tokens permanently. New
  strategy.AccumulateSessionTokenUsage mirrors SaveStep's accounting.

Committed-state filtering:
- Remove filterToUncommittedDeletions and the relNewFiles filtering entirely:
  git status cannot report a committed deletion and untracked files are never
  in HEAD, so both filters were no-ops for their intended case while the
  deletion filter actively dropped uncommitted deletions of files created
  within the session — making checkpoint rewind resurrect deliberately
  deleted files. Only relModifiedFiles (which merges transcript-extracted
  paths) needs committed-state filtering.

Scoping and matching:
- Scope the empty-live-transcript degrade to Antigravity: other agents keep
  the error/retry-next-commit invariant for transient empty-file races.
- UninstallTitleTee now matches the bare localDev tee by shape instead of
  re-resolving the repo path at uninstall time — uninstalling from a
  different worktree no longer orphans the global title entry (which kept
  spawning a failing `go run` after the original worktree was deleted).
- entireHookPrefixes uses the full canonical localDev prefix (matching
  cursor/claudecode) instead of bare "go run ", which misclassified any
  user-authored go-run command as Entire-managed.
- e2e WaitFor surfaces exhausted raw-tool-call retries as an error instead of
  returning malformed content with nil.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eline

- Extract forEachNonBlankLine as the single owner of the transcript-offset
  metric: ExtractPrompts, GetTranscriptPosition, and
  ExtractModifiedFilesFromOffset each hand-rolled the same skip-blank-before-
  counting loop, kept in sync only by comments — a drift in any copy would
  silently shift offsets and attribute prompts/files to the wrong checkpoint.
- SnapshotTokenBaseline reuses the streaming last-line reader (generalized
  from the dedup path) instead of JSON-decoding the entire per-conversation
  snapshot history on every TurnStart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ment antigravity limitations

- The interactive agent selector and `entire agent list` now show a
  "(Preview)"/"(preview)" label for agents whose IsPreview() is true — the
  hook-install message already did; the selection surfaces users see first
  did not. Extracted the shared previewLabel constant.
- docs/architecture/agent-guide.md gains an "Antigravity status: Preview"
  section listing the known limitations (silent tracking, coarse mid-turn
  token scoping, transcript-less first-turn mid-turn checkpoints, title-slot
  dependency for token capture, quota/entitlement-gated live E2E, wire format
  pinned to agy 1.0.14/1.0.15).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sweep of every agent enumeration outside the architecture guide (which
already documents agy): README (feature line, --agent flag values, hooks-file
table with .agents/hooks.json), first-time-contributors, security-and-privacy,
sessions-and-checkpoints, .github/copilot-instructions, and the
--summarize-agent flag help (agy is a summary provider).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follows the codex/copilotcli/cursor pattern: verdict (COMPATIBLE, Preview),
binary/auth notes, hook mechanism + event mapping (3 installed hooks,
0-indexed invocationNum, conditional TurnStart for resumes), captured payload
schemas, transcript layout and the after-Stop write with its handling,
TranscriptAnalyzer offset contract, the out-of-band token tee design,
config preservation, and the preview gaps & limitations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…des it

Found by the first full live E2E run (51/59 pass, agy 1.0.16): in headless -p
mode agy's "Individual quota reached" detail lands ONLY in
~/.gemini/antigravity-cli/log/cli-*.log — stderr is empty and the transcript's
ERROR_MESSAGE carries just the generic "overloaded" 429 text — so the harness
classified an exhausted quota as transient and retried scenarios into the
wall.

antigravityFatalFromLogs scans log files modified since the prompt started
(E2E_ANTIGRAVITY_LOG_DIR override for tests); RunPrompt consults it before an
error can be classified transient. antigravityFatalError now also matches its
own generated messages so a folded fatal finding stays fatal on
reclassification.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found by the first full live agy E2E run (TestSubagentCommitFlow): agy runs
subagents as separate conversations with their own hooks. The subagent's
fullyIdle Stop condenses normally at commit, but the parent conversation only
receives fullyIdle=false Stops before the headless process exits — leaving a
"ghost" session that stays ACTIVE with zero tracked files and zero
checkpoints. The post-commit cleanup preserved the shadow branch for ANY
active uncondensed session, so the ghost pinned the branch permanently — a
guaranteed leak, since PostCommit also rebases the ghost's BaseCommit to the
new HEAD, meaning any future work targets a NEW branch name.

Preserve the branch only for active uncondensed sessions that still track
files (their uncondensed checkpoints are the only copy of that work).
Sessions with nothing to lose don't pin: SaveStep recreates shadow branches
on demand. TestPostCommit_ReadOnlyActiveSessionNotCondensed pinned the leak
as intended behavior; its final assertion is flipped with the rationale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolved cmd/entire/cli/setup.go: main extracted the duplicated agent-option
loops into hookAgentOptions; folded this branch's preview-label logic into
that helper so it applies at both call sites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes from the trail 444 agent-review findings, verified against the code:

- Atomic settings write: writeJSONMapFile now goes through
  jsonutil.WriteFileAtomic, so a crash mid-write can no longer truncate
  agy's machine-global settings.json (shared title slot) or .agents/hooks.json.
- Crash-resume tracking: shouldSuppressConditionalTurnStart also fires the
  conditional TurnStart when state.OwnerExited() detects a dead owner PID,
  instead of waiting out the 1h StuckActiveThreshold.
- Cache-path isolation: statusDir resolves via userdirs.Cache() (the mandated
  resolver) so $XDG_CACHE_HOME isolation works on darwin and go-test runs
  fall back to a throwaway dir instead of the real user cache.
- Dangling trailer: the prepare-commit-msg fast path
  (sessionLacksCondensableContent) stats agy's transcript file rather than
  trusting the non-empty path, so no Entire-Checkpoint trailer is stamped for
  a mid-turn commit whose condensation will return Skipped (agy writes the
  transcript only after Stop; shell-only edits leave FilesTouched empty).
- Statusline hot path: readLastStatusSnapshot does a bounded 64KB tail-read
  (O(1) per title fire instead of O(file)); MkdirAll only on first append.
- Wrapped title command failures now leave a Debug breadcrumb and the
  POSIX-only constraint of the sh -c wrap is documented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KWYNWMTR2EHMVWK1FKAKC13J
The origin/main merge brought in claudecode.ClaudeErrorUnknown without a
matching case in formatCheckpointSummaryError's kind switch; golangci-lint's
exhaustive check fails on the tree. Route Unknown through the existing
default handling explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KWYNX0XYRTQ8NPMPPP62JGGV
…set advance

Addresses the two remaining trail 444 findings:

- New agent.LateTranscriptWriter capability marks agents whose transcript
  is written only after the Stop hook (agy). It replaces the three
  AgentType==Antigravity switches threaded through shared strategy code
  (empty-transcript degrade, offset counting in countTranscriptItems, the
  prepare-commit-msg content guard), and its CountTranscriptPosition method
  makes the agent the single owner of its offset metric — deleting the
  non-blank-line counter the strategy had to keep byte-identical with the
  agent's readers across the package boundary. The remaining generateSummary
  switch is a transcript-format enumeration (agy grouped with the JSONL
  agents), not an agent special-case, and stays.

- Prompt-shift fix for mid-turn commits: HandleTurnEnd's offset advance can
  lose agy's transcript-flush race at Stop, leaving CheckpointTranscriptStart
  inside the previous turn — the next mid-turn commit's checkpoint then
  extracts the previous turn's prompt and re-scopes already-condensed
  transcript. The lost advance is now recorded in a one-shot
  TranscriptOffsetPending state flag and completed at the next mid-turn
  condensation, where a late-flushing agent's file provably contains only
  already-condensed turns. Carry-forward clears the flag (it restarts the
  offset at 0 deliberately). Regression pin covers the exact misattribution.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KWYNX9NHKJ6YT977RW3ZXPRT
@peyton-alt
peyton-alt force-pushed the feat/antigravity-agent branch from d98d9a0 to 42abc77 Compare July 7, 2026 16:18
peyton-alt and others added 7 commits July 7, 2026 18:30
…older

Trail finding asked whether agy reads the prompt from the -p value (which
would make GenerateText summarize a literal space). Verified live against
agy 1.0.16: a prompt piped to stdin with -p " " is what the model receives
and answers — same convention as the Gemini CLI, whose --help documents it
while agy's does not. Record that in the comment so the pattern isn't
re-flagged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Entire-Checkpoint: 01KWYPMYBRJM2STKR93TDYTMAR
agy 1.1 moved skill discovery defaults: workspace skills now live in
<workspace>/.agents/skills (legacy .agent/skills still honored) and global
skills in ~/.gemini/config/skills. The discovery scanned only the pre-1.1
roots, so skills created where agy's own /skills UI puts them never showed
in the entire review picker. Scan new and legacy roots.

Also align the wire-format claims across AGENT.md, agent-guide, and the
integration-test comment: captured on 1.0.14/1.0.15, re-verified unchanged
against agy 1.1.1 (docs + binary + live run, 2026-07-13).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
antigravityFatalFromLogs read agy's CLI logs from the harness process's
real HOME, but in ADC mode the agy subprocess runs with HOME redirected to
the per-repo test home — exactly the CI dispatch mode where the fail-fast
classification matters. A quota wall visible only in agy's CLI log would
be classified transient and retried into. Resolve the log dir through the
same ADC-aware home resolution as the brain dir (new antigravityHomeDir).

Also: create the ADC credentials file with 0600 before writing the secret
in all three workflows, and fix the README's CI-matrix line to match the
actual push-run matrix (antigravity is workflow_dispatch-only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- doctor: skip the title-tee check when no agy binary is on PATH —
  .agents/hooks.json is committable, so a teammate who never uses agy would
  otherwise get a permanent false warning (whose repair writes agy's global
  settings); repair hint now names the agent (entire agent add antigravity).
- hooks: install the Stop handler with an explicit 300s timeout; agy's 30s
  default can kill SaveStep mid-checkpoint on large repos with no trace.
- agent remove: warn that uninstalling the global title-tee disables token
  capture for every other repo still using Antigravity (only when the tee
  was actually claimed).
- docs: document the machine-global title-tee capture surface in
  security-and-privacy.md (conversation ID + token counts only, 14-day
  snapshot retention, removed with agent remove).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Conflict: cmd/entire/cli/agent/agent.go — both sides added a new capability
interface at the same location (LateTranscriptWriter here,
SidecarImageProvider on main); kept both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- AreHooksInstalled parses per-entry: a malformed FOREIGN hook entry in
  .agents/hooks.json (free-form user content) no longer breaks detection of
  the entire entry — install previously succeeded while status/doctor
  permanently reported not-installed.
- InstallHooks respects a user-set "enabled": false on the entire entry
  (agy's documented per-entry disable knob) instead of rewriting the entry
  and silently re-arming tracking; --force remains the explicit override.
- computeOutOfBandTokenUsage treats a missing token baseline mid-session as
  no-data instead of count-from-zero: a lost/corrupt PrePromptState after
  turn 1 would otherwise return session-cumulative totals and double-count
  every earlier turn's tokens.

Resolves trail 444 findings 019f5c22-ef3, 019f5c23-098, 019f5c22-f84.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ecgang

ecgang commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Independent test report — branch b7ac0224 against Antigravity 1.1.10 (macOS, daily-driver corpus)

I run agy daily alongside Claude Code/Codex, so I put this branch through a real workout: fresh build, entire agent add antigravity, and a live agy session in a scratch repo, plus a wire-format check against 12 real sessions from my brain/ history.

What works (end-to-end): clean native build (go build, exit 0); antigravity (preview) appears in entire agent list; enable installs the documented 3 hooks + orphan ref with no login required; a live session produced a commit carrying Entire-Checkpoint with the exact prompt, a 6-step transcript in real agy format, correct files_touched, and agent_percentage=100. entire doctor correctly diagnosed both title-tee states. (One environment note: 3 pre-existing strategy test failures on my machine — checkpoint_remote_test.go expects git@github.com: URLs and my global url.…insteadOf rewrites them to HTTPS; the file is byte-identical to main, so not this PR's doing, but the tests do assume no insteadOf rewrite.)

No format drift 1.1.1 → 1.1.10: all agyStep fields match by name and type against the May testdata, field-for-field. Tool census over a 12-session sample of my brain history: replace_file_content ×119, write_to_file ×19, multi_replace_file_content ×3 — no new mutating tools in the sample (nor in a coarse scan of the full 300+-session corpus). Double-encoded args still present, so decodeAgyString is still needed.

One real bug — silent file loss under truncated_fields: agy sometimes truncates tool_calls in PLANNER_RESPONSE steps, and the truncation can drop TargetFile while keeping every other arg (observed live: 1 of my 119 replace_file_content calls, ~0.8%). grep -ri truncated finds no handling in the integration, and testdata has no such step — so ExtractModifiedFilesFromOffset decodes "" and silently skips a genuinely modified file, no error or log. Scope stated fairly: live PreToolUse stdin isn't truncated, so normal sessions are covered — this bites the transcript-derived fallbacks the PR itself documents (late-flush, first-turn mid-turn). Suggest a WARN or an incomplete-file-list marker rather than a silent skip.

One DX trap worth a doc line: plain agy -p inside a repo that isn't a trusted workspace resolves cwd to agy's own scratch workspace — writes land in ~/.gemini/antigravity-cli/scratch/, no hooks fire, no session is created, and it exits 0 with no warning. Anyone evaluating this integration in a fresh repo will wrongly conclude it's broken. A line in AGENT.md / e2e/README.md would save that.

Small notes: entire agent add antigravity writes the token-capture title slot into Antigravity's global settings.json (verified against an isolated HOME) without mentioning it in the install output — worth a line since it's the one write outside the repo; agent list renders lowercase "(preview)" vs agent-guide.md's "(Preview)"; go.mod wants go 1.26.4, which auto-downloads a toolchain and would fail closed under GOTOOLCHAIN=local.

Happy to re-test after a rebase (branch is ~620 commits behind main as of today) and can share the truncated-step fixture. Thanks for building this — it's the missing piece for my fleet.

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.

4 participants