Skip to content

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

Merged
Soph merged 135 commits into
mainfrom
feat/antigravity-agent
Sep 24, 2026
Merged

Soph merged 135 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 three auth modes (ADC → GEMINI_API_KEY → OAuth), trusted-workspace seeding, fatal-vs-transient classification, agy-log + hook-probe artifact capture; 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 runs in the default matrix in agy's Gemini API-key mode (no account session; the shared GEMINI_API_KEY secret). agy ≤ 1.1.24 loaded .agents/hooks.json on that route but never executed the hooks (Hooks from .agents/hooks.json are loaded but never executed when authenticated via GEMINI_API_KEY (headless -p, 1.1.22) google-antigravity/antigravity-cli#893, still open upstream); bisecting the release binaries with a probe hook shows agy ≥ 1.1.25 executes them, and CI installs releases/latest (1.2.7 as of 2026-09-21). The optional ANTIGRAVITY_GOOGLE_APPLICATION_CREDENTIALS_JSON secret still switches the leg to ADC; the cloudcode-pa backend remains entitlement-gated (subject 110002). Fail-fast classification covers quota/entitlement walls plus GEMINI_API_KEY … not set / API_KEY_INVALID. Details in e2e/README.md.
  • Transcript-derived file lists can be incomplete when agy persists a step with truncated_fields and drops TargetFile (reported by @ecgang, ~0.8% of replace_file_content calls in their corpus). Now logged as a WARN per dropped call instead of a silent skip; live PreToolUse stdin is never truncated so only the late-flush / first-turn fallbacks are affected. Awaiting a real fixture.
  • 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, re-verified unchanged on agy 1.1.1 (2026-07-13) and 1.1.22 (2026-08-27: still exactly 5 hook types; statusline/title payload unchanged). agy is fast-moving — 1.1 moved the skill directories (handled), 1.1.10 fixed hook ordering so Stop/PostInvocation fire reliably, 1.1.12 answers -p "/hooks" locally (used by entire doctor to verify the workspace hooks actually load, zero quota).

2026-08-27/28 update

  • Merged origin/main (was 3 months behind): ported to local-dev removal, IsManagedHookCommand(cmd), AreHooksInstalled → (bool, error), 4-value RunIsolatedTextGeneratorCLI, main's skilldiscovery extraction.
  • Fixed the CI install step: the agy release tarball ships the binary as antigravity, so the leg had never started in CI.
  • Added GEMINI_API_KEY e2e mode, optional ADC, trusted-workspace seeding, agy-log + hook-probe artifacts (agy emits no log line for hook execution — the probe is how Fix external agents detection #893 was found).
  • entire doctor: "Antigravity hooks: LOADED/NOT LOADED by agy" via agy -p /hooks --add-dir <root> --output-format json (version-gated ≥ 1.1.12), plus the untrusted-workspace trap from the test report.
  • truncated_fields degrade path (above). Docs refreshed for 1.1.22.

2026-09-22 update (trail-444 review rounds after real Windows/macOS testing)

  • Windows (confirmed on Windows 11 ARM64, agy 1.2.7): agy hands hook commands to cmd.exe, so the sh wrapper failed silently and nothing was tracked. Antigravity now installs the bare direct-shell wrapper (agent.WrapWindowsProductionSilentHookCommandDirect) when HookHostIsWindows(). The status store's root-relative names were backslash-joined on Windows and never created; they are slash-separated now and osroot.MkdirAllNoSymlink refuses backslash names.
  • entire doctor: the agy -p /hooks probe was observed to run a full model turn on Windows and only proved agy parsed hooks.json, so it is opt-in (ENTIRE_ANTIGRAVITY_DOCTOR_PROBE=1). By default doctor now checks, at zero cost, that the installed hook entry is the shape this host needs (HooksEntryMatchesHost) and says how to reinstall. An unparseable agy version no longer produces "run agy update".
  • Prompt loss on later-turn manual commits (user-reported, three checkpoints): the last rung of the condensation prompt ladder now extracts from the transcript bytes being stored (agent.TranscriptPromptExtractor) instead of re-reading the live path, and condensation logs which rung supplied the prompts. A new integration test runs two turns in agy's real order and commits each manually.
  • Smaller: uninstall leaves a hooks.json with no Entire entry untouched; readers no longer leave orphan lock files; prune pairs a snapshot file with its lock; --add-dir must be absolute (documented, and the probe refuses a relative root); the merge-gating e2e.yml pins agy to 1.2.7 while nightly keeps latest.
  • Re-test on the fixed head (2026-09-22): live two-turn agy conversation with a manual commit after each turn on entireio/entire-sandbox — both checkpoints carry the right prompt (the later turn at transcript offset 4), tokens recorded, status store under ~/.cache/entire/antigravity/status with no orphan locks, doctor clean without the probe. Full antigravity e2e suite: 48 pass / 3 skipped both locally and in CI; the 5 TestInteractive* failures were the harness, not the CLI — interactive agy in a never-run HOME shows a color-scheme chooser and a Terms consent before the prompt. The isolated HOME now seeds cache/onboarding.json as complete (established by walking onboarding in a scratch HOME and diffing), and the runner clicks through both screens as a fallback.
  • Command smoke matrix (2026-09-22, sandbox, agy session present): agent list/add/remove, status (+--json), session list/current/info/tokens/stop, checkpoint list/explain/tokens/search, search, recap --static, activity, agent-help, doctor (default and with the probe opt-in), configure --summarize-provider antigravity, checkpoint explain --generate, dispatch --local --agent antigravity, clean --dry-run, disable/enable. Two real bugs found and fixed: agy 1.2.x ignores stdin in print mode, so GenerateText now passes the prompt in argv (dispatch --local had handed agy an empty prompt); and the summarizer had no condenser for agy's step JSONL, so explain --generate reported an empty transcript — antigravity.CondenseTranscript now feeds it. Both re-verified live.
  • Shadow-branch pinning (review finding on the smoke-matrix head): the ghost-session fix had narrowed "active session with uncondensed content" to "active session with tracked files", which would let a sibling's condensation delete the only checkpoint of a session whose first step captured a transcript before any edit. The gate now uses the same test condensation uses (sessionHasShadowContent: files, written steps, or task checkpoints); the ghost still has none of those. Table test covers files-only and steps-only.
  • Merged origin/main a third time (session-store tests; no code conflicts).
  • Windows, on a real Windows host (2026-09-22 evening): the antigravity leg is now dispatchable in e2e-windows.yml (agy 1.2.7 from agy_cli_windows_x64.zip, API-key mode; the harness redirects USERPROFILE with HOME so agy and the entire hooks it spawns agree on the isolated home). TestSingleSessionManualCommit passed on windows-latest (run 35803986610): the cmd.exe wrapper fired PreInvocation/PreToolUse/Stop, agy wrote the file through a PreToolUse hook, the Stop hook saved the shadow checkpoint, and the commit carries its Entire-Checkpoint trailer. The first run failed only on the harness's sh -c probe hook, which cmd.exe cannot run and which made agy refuse the tool call; the probe now skips itself on Windows. Runner is x64; ARM64 remains the reviewer's manual evidence. Follow-up: add antigravity to the nightly Windows leg.
  • 2026-09-23: Victor's Windows and review-round fixes landed directly on the branch. On top of them: the title-tee idempotency test stands up an agy on PATH (the tee is now only claimed where agy exists); the summary prompt's [Files Modified] list is bounded like the transcript; the e2e harness removes Antigravity's isolated home with the repo; the commit fast path treats only a missing or store-refused transcript as "no content" (any other stat error fails toward condensing); and the title-tee now preserves a pre-existing user title command on Windows — --wrap-b64 <base64url> where agy runs the slot through cmd.exe, re-run through cmd.exe by the tee, with uninstall restoring either form byte for byte. Previously that case failed on every model call on Windows (no tokens, user title gone); an older finding had deferred it with "revisit if agy ships on Windows". Review round on that head: a TTY mid-turn commit before agy's first Stop lost its trailer because the slow path required transcript growth before looking at hook-captured files (fixed: files carry the decision, growth is the fallback); the summary-prompt bounds had leaked into explain --full (display formatter is unbounded again, LLM callers use FormatCondensedTranscriptForPrompt); the Antigravity install hint used backticks the picker mangles.
  • Merged main again for agent: remove IsPreview from the Agent interface #2554: agent.IsPreview is gone, so Antigravity's preview status is documentation only (AGENT.md, agent-guide.md); this branch's own selector/list preview labels were reverted before that.

2026-09-21 update

  • Merged origin/main again (~905 commits; 14 conflicts). Main deleted e2e-isolated.yml / e2e-checkpoints-v2.yml and gave e2e.yml a test regex input, so the antigravity CI wiring now lives only in e2e.yml. Adapted to main's checks: StepContext.MetadataDirAbs removal, the writeTestFile helper removal, goconst on the hook type literal, the transcript-read ratchet (transcript_read_guard_test.go; antigravity registers one read like every other agent), the e2e prompt-timeout chain (boundPrompt), the userdirs consumer audit (the statusline tee now resolves through userdirs.CacheDirChecked), and the summary-capable provider pin (antigravity has GenerateText, so it joins the list and the README).

  • Fix external agents detection #893 verified fixed upstream in agy 1.1.25 by bisecting real release binaries in an isolated HOME with modelProvider: gemini and a probe hooks.json: 1.1.22/1.1.23/1.1.24 fire nothing, 1.1.25/1.2.0/1.2.7 fire PreInvocation + Stop. The release notes never mention it. The antigravity leg is back in the default e2e.yml matrix and the dispatch-only caveats are rewritten (AGENT.md, agent-guide.md, e2e/README.md).

  • Nightly install smoke (nightly-e2e.yml) gains an antigravity leg on Linux and macOS (agy from the latest release tarball, API-key mode, 25-minute step cap for the 2.5x multiplier). It can only go green once this PR is in a published nightly, since that workflow checks out the nightly tag.

  • Model bump: agy 1.2.x dropped gemini-3.5-flash-low from agy models (both auth modes) and rejects it with invalid model selection; the harness default is now gemini-3.8-flash-low.

  • CI run 35650998214 then passed TestSingleSessionManualCommit for antigravity in API-key mode (no ADC secret present, agy from releases/latest): the org GEMINI_API_KEY is valid and the full hook set, PreToolUse included, executes on that route.

  • Live smoke on entire.io (2026-09-21): entire built from this branch drove real agy 1.2.7 sessions in API-key mode against entireio/entire-sandbox on both checkpoint backends — git-branch session (checkpoint 593b557e273d) and git-refs session (checkpoint 01M33B0YNF2RDS4ANXE7H8PZ2E). Hooks, title-tee, trailer, condensation, push and ingestion all worked; the three trail-444 findings (dedup/append race, bare os.Remove in prune, os.Stat on the transcript path) are fixed in 9f688a8763 by anchoring the status store on userdirs.CacheRoot and locking the dedup-append.

Follow-ups (deliberately out of scope)

  • Record the model: agy's PreInvocation payload carries modelName, but checkpoint metadata leaves model empty today.
  • entire.io's activity view labels these sessions "Unknown" while the search index says Antigravity — a web-side display mapping, not this repo.
  • entire doctor could warn when agy < 1.1.25 runs in API-key mode (hooks load but never execute there).

Test plan

  • mise run check green locally (fmt, lint 0 issues, unit + integration + canary) — re-run 2026-09-21 on the merged tree
  • CI green on the merged tip
  • e2e.yml antigravity leg green in API-key mode on agy latest, no ADC secret — run 35650998214 (TestSingleSessionManualCommit, 2026-09-21)
  • 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 fullyIdle → TurnEnd (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 Outdated
Comment thread cmd/entire/cli/agent/antigravity/hooks.go
Comment thread cmd/entire/cli/agent/antigravity/hooks.go Outdated
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>
gtrrz-victor and others added 27 commits September 23, 2026 15:42
resolvePendingTranscriptOffset logs at Info when it completes a deferred
advance, but returned silently when the phase is not ACTIVE. That is the
branch worth seeing: the checkpoint scope then keeps the previous turn's
already-condensed tail, which reaches the summary as duplicated content.
The doc comment acknowledged the bloat; nothing made an occurrence
observable. Same level as the advance, so the two are equally visible.

Finding: 01M373FQ00E2

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M3782H66PSMH4XF38K8FW3G4
title-tee is attached to the per-agent hooks command, which defined a
PersistentPreRun that loads settings, scans every session state file via
ResolveCallerSession and builds the secret scanners. agy fires its title
command on every state change, unserialized, so that ran roughly once a
second to append one JSON line: a real 35-second turn logged 32
"redaction configured" lines.

Fixed by moving the PersistentPreRun onto the per-verb commands. The
lifecycle verbs keep exactly today's behaviour; title-tee, which is not
one of them, inherits nothing.

Not by re-parenting title-tee, and not by giving it a no-op hook of its
own. The exact string `entire hooks antigravity title-tee` is persisted
in users' agy settings.json by InstallTitleTee and matched by shape on
uninstall, so moving it would leave every installed tee invoking a
command that no longer exists — token capture silently to zero, and
uninstall no longer recognising the old entry. And a no-op cannot shadow
an ancestor: root.go sets cobra.EnableTraverseRunHooks, which in cobra
v1.10.2 runs every ancestor's PersistentPreRun from the root down rather
than only the nearest.

TestTitleTee_InheritsNoPersistentPreRun pins both halves: the command
path, and that no ancestor below the root defines a hook. The two tests
that asserted the hook's old location now assert the new one, keeping
their real invariants.

Finding: 01M376TTRSTZ

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M379E46MGE5S80V5HQHDV6MW
InstallHooks called InstallTitleTee with no check that agy is on PATH.
The title slot lives in agy's machine-global settings.json, so a
repo-local `entire agent add antigravity` — in a teammate's checkout,
say — wrote a shared user-level file on a machine that has never run
agy. `entire doctor` already gates its matching check on the same
lookup.

The call keeps its position ahead of the idempotency early-return: that
ordering is what makes stale-slot repair work, and only the binary check
was missing.

Finding: 01M376Y1T4CG

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M379EMNTA0QRB1QZXZF2GAB4
internal/flock sat in the flat allowedPrefixes list, beside genuinely
shared utilities, so it silently permitted the import for every agent
package. The reason it exists is specific to one: agy fires its title
command on every state change without serializing, so the Antigravity
title-tee takes a per-conversation flock.

scopedPrefixes keys such an exception by agent package, the same
per-path shape unconfinedTranscriptReads and allowedRootBases already
use. A second agent that wants flock now has to say so and give its
reason, instead of inheriting one agent's answer.

Finding: 01M376VAJ85Y

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M379EPQG8C7R49H7XVKBVHRH
The hint named ~/.gemini/skills, which antigravity/discovery.go
documents as a pre-1.1 layout; the current global root is
~/.gemini/config/skills.

Not cosmetic, and the comment now says why: Entire scans all three
layouts, so a skill placed at the old path still reaches Entire's
prompt and looks like it worked — but agy itself will not load it, which
is the half the hint was getting wrong.

Finding: 01M376V84NXJ

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M379ERRNP0W0N7728W2RXS2P
parseHooksProbeOutput decoded the envelope's status and never read it.
agy can exit 0 while reporting a non-success status with an empty
command.data.hooks array, which is byte-identical to a genuine "no hooks
loaded" response — and doctor's remediation for that case tells the user
their hooks are NOT LOADED, the wrong advice for someone whose probe
never ran.

A status agy actually reported and did not set to SUCCESS is now an
error. An absent status is left alone: only a reported status is
evidence about the probe.

Finding: 01M36QMB0KXY

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M379Q4VXA3RBE93C85H7DK63
ead34ed moved the hook-session PersistentPreRun from the shared
per-agent command onto each verb, but executeAgentHook's doc still said
built-in subcommands pass stampSession=false because "their parent
command's PersistentPreRun already did it".

Worth more than tidiness: that sentence teaches the stamping is
inherited, which is the belief that makes the title-tee bug easy to
reintroduce — attach another non-verb command to the agent command and
it would not be stamped, contrary to what the doc promised.

Finding: 01M37AC1240K

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M37ARAK7SMZ7QFZAA57XP4ZB
The snapshot prune stat'd a file, found it older than the retention
window, and unlinked it without taking that conversation's lock — while
the lock-file loop right below it is careful about exactly this. A
dormant conversation resumed between the stat and the unlink is
mid-append, and the file goes out from under its open fd.

The prune now takes the conversation's own lock first, non-blocking: a
held lock means that conversation is alive right now, which is reason
enough to leave its file for the next run.

Scope of the bug, since it is easy to overstate: the recorded token
counts are NOT at risk. agy's totals are cumulative per conversation and
CalculateTokenUsageSince subtracts a baseline held in PrePromptState, so
a lost file is followed by a fresh snapshot carrying the same cumulative
totals and the delta still comes out right. What is lost is the per-line
detail between baseline and now — the cache fields and APICallCount that
the same function already documents as best-effort. A documented
approximation getting more approximate, in a window needing three
coincidences. Taken because the fix is cheap and matches its sibling
loop, not because the consequence is severe.

Finding: 01M37A5Y47WN

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M37AXPNXBX5WEBPTM5NARRQQ
2b193e4 took the conversation's lock before unlinking its snapshot,
which is the right shape, but reached for it unconditionally. The
try-lock is not a free probe: flock opens with O_CREATE|O_EXCL, so
asking for a lock that does not exist creates one — left behind for a
conversation that was just deleted. The orphan-lock loop cannot collect
it in the same pass, since it walks an entries snapshot taken before the
lock existed, and on the next pass it must first age past the retention
cutoff. Each pruned conversation could leak a lock file for another
retention window: the accumulation 01M341AX1V6D removed from the read
path, reintroduced on the prune path.

The lock is now attempted only when the lock file already exists.
Absence is evidence rather than missing evidence: AppendStatusSnapshot
takes the lock BEFORE creating the .jsonl — the ordering the orphan-lock
loop already relies on — so a snapshot with no lock beside it has never
had a tee mid-append, and unlinking it directly is safe.

The decision now lives in pruneStaleSnapshot rather than inline, so the
loop reads as intent and the reasoning has one home.

Finding: 01M37B28RP6R

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M37B6Y0GH68QRZ3N37CNMM8J
The comment here promised the merge gate was protected from third-party
agy regressions. It was not. agy self-updates in place: the updater
replaces the executable at its own path — in CI, the file this step
installs — and is spawned on essentially every launch, ~0.4s in, with
auth not gating it and its only brake a 15-minute check keyed on state a
fresh CI home never has.

So the pin governed only the first agy spawn of the job, and the harness
spawns agy once per prompt, so every prompt after the first already ran
whatever the updater had fetched. Measured on Windows 11 ARM64: 1.2.7
installed, one headless prompt, 1.2.9 at the same path afterwards, with
the original moved aside as agy.exe.<ns>.old. There is no opt-out — not
a flag, a settings key, or an env var.

Dropping the pin changes almost nothing in practice (one prompt out of
many) and stops the tree asserting a guarantee it does not provide. The
exposure is now written down instead: this job's agy version floats, and
an agy regression can redden PRs that never touched Antigravity.

Closing the exposure for real needs the updater blocked — an unwritable
install path, or no egress for this step — and neither is tested, so
neither is adopted here rather than trading a known exposure for an
untested merge-gate hack.

With the pin gone the hand-rolled tarball had no remaining purpose, so
this uses agy's official installer like every other install in the tree.

Finding: 01M37BP8MN8Q

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M37BZMWDMNKNRJT3XYFMFRDR
…ected

InstallHooks now claims agy's global title slot only where `agy` resolves
on PATH (41fdeae). TestInstallHooks_IdempotentStillRepairsTitleTee still
asserted the tee after the first install on a machine with no agy, which is
exactly the case that commit stopped installing it. The test now puts a
stand-in agy on PATH, so it keeps guarding the stale-slot repair it was
written for.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37JE28VJTQNA67KZVXQ6036
boundTranscriptText caps the transcript at 96 KiB so the whole prompt stays
under Linux's 128 KiB single-argument limit, since Antigravity takes the
prompt in argv. The [Files Modified] list appended after it was unbounded,
so a session touching many files could push the prompt back over the limit
and reproduce the E2BIG the bound exists to prevent. The list now keeps
whole lines up to 16 KiB and closes with how many paths were left out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37JE7DHXPK7YYSQ4BYK8105
antigravityTestHomeDir is a sibling of the repo temp dir and held agy's
settings, session and log state; nothing removed it, since PrepareRepo has
no *testing.T. An optional RepoCleaner hook, registered by SetupRepo after
the repo's own cleanup and before artifact capture, now removes it when the
test ends (kept under E2E_KEEP_REPOS, like the repo).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37JEDAQFE9AVCVB382WTRPW
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37JGJPADYJ2470RFSDSPQXR
…n the fast path

sessionLacksCondensableContent classed every stat failure on a late-writer
transcript as "no content", so an EACCES, ENOTDIR or I/O error silently
dropped that session from the commit's trailer. Now only an absent file, or
a path the session store refuses (a symlink at any component, a non-regular
leaf, which the full path refuses too), reads as no content; anything else
fails toward condensing, where the read reports what is wrong.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37K972CZEZGQ44W361569Y0
agy hands its global title slot to cmd.exe on Windows. The tee preserved a
pre-existing user title command as --wrap '<original>' and re-ran it with
`sh -c`, both POSIX-only: cmd.exe reads the single quotes as literal text and
a stock Windows PATH has no sh, so on such a machine the tee failed on every
model call — no token snapshots, and the user's own title gone. An earlier
finding on this code was closed with "revisit if agy ships on Windows"; it
does, and this branch claims Windows support.

On Windows hosts InstallTitleTee now writes --wrap-b64 <base64url(original)>,
an encoding no shell touches, and the tee re-runs the decoded original
through cmd.exe (/d /s /c, the whole line passed verbatim via CmdLine) — the
same shell agy would have used. Unix keeps the quoted form. Uninstall parses
both forms and restores the original byte for byte; the quoted form is tried
first because only its payload can contain either flag's text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37M4XF1BCE823AJQTCR4Z13
… agy's first Stop

sessionHasNewContentFromLiveTranscript required transcript growth before it
looked at FilesTouched. For a late-transcript writer the file is still an
empty placeholder mid-turn — position and CheckpointTranscriptStart are both
zero — so a user committing from a terminal during agy's first turn lost the
Entire-Checkpoint trailer even though PreToolUse had recorded the edit. The
no-TTY fast path never reaches this function, which is why the integration
test for that scenario kept passing.

FilesTouched is cleared by condensation, so anything in it is uncondensed
work; transcript growth is now consulted only when the hooks recorded
nothing. The staged-file overlap check is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37NG3Q2A8WJHTK3FFZD7F0B
boundTranscriptText and the file-list bound exist to keep Antigravity's
single-argv summary prompt under Linux's 128 KiB limit, but they were applied
inside FormatCondensedTranscript, which `entire explain --full` also uses to
show a reader the whole transcript. FormatCondensedTranscript is unbounded
again; the two LLM callers use FormatCondensedTranscriptForPrompt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37NG5HT3F2JFAQ308MQR354
The picker renders these through huh, which treats backtick spans as
markdown and mangles them — the rule stated four lines above the entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Entire-Checkpoint: 01M37NG7DP20JP9KVTWB317288
On the shadow-branch path the whole prompt ladder — the tree's prompt.txt,
the filesystem copy, and the late-flush transcript rung — sat inside
`if fullTranscript != ""`. None of those rungs needs transcript content to
answer: prompt.txt is written at turn start, and resolveCondensationPrompts
falls back to the transcript path when the bytes are empty.

So a checkpoint condensed while the transcript was empty carried no prompt
from ANY source, including the prompt.txt sitting in the very tree being
read. For a LateTranscriptWriter that is not a rare race: agy flushes after
Stop, PrepareTranscript materialises a 0-byte placeholder, SaveStep
checkpoints it, and a commit before the flush lands takes this path.
logCondensationPrompts was inside the same block, so the breadcrumb added to
make an empty prompt diagnosable was absent exactly when it was needed.

The rungs now run regardless; only the transcript assignment stays gated.
This is the shadow-path twin of the live-path fix in 165b0ad, which
already resolves prompts independently of transcript content.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396JCC5EMGD71P29N0Z2RX8
cobra.EnableTraverseRunHooks is on, so root's PersistentPreRunE runs for
every command including `entire hooks antigravity title-tee`, and
paths.RequireEntireDir answers nil only for ErrNotARepository. An
unresolvable repository (git's safe.directory refusal, git absent from PATH)
or a `.entire` that is not a real directory therefore made the tee print the
multi-line remedy to stderr and exit non-zero — once per agy agent state
change, against this command's documented NEVER-exit-non-zero contract, with
token capture silently dead and only agy's own log to show for it.

The tee writes to the per-user cache and never under `.entire`, so it has
nothing the guard protects. The exemption is scoped to this one command
rather than the `hooks` tree: the lifecycle verbs are the checkpoint-writing
path and must keep failing closed.

TestEntireDirCheckExemptions requires every exempt command to carry a written
justification, so the ledger gains one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396JX6BMJH0H5AYE9V2QFZC
…lves

resolvePendingTranscriptOffset cleared TranscriptOffsetPending before
attempting the advance, so every outcome consumed the one-shot flag —
including the one it exists for. An ACTIVE session whose transcript still has
not flushed cannot compute the advance (GetTranscriptPosition fails, or
returns a position no later than the stale offset), and a second commit made
inside that same unflushed window therefore discarded the deferral. Once the
flush landed, the next checkpoint scoped from an offset inside the previous,
already-condensed turn: the previous turn's prompt attributed to it and a
duplicated tail in the stored transcript — precisely the shift the flag was
added to prevent.

The flag now survives only that case, and the unresolved attempt is logged
like the advance and the non-ACTIVE skip already are. Everything else still
consumes it: outside ACTIVE the file may hold the current turn's uncondensed
content, and the capability checks can never come true for the session, so a
flag left set there would be re-read forever. Letting it outlive a successful
condensation is harmless — that rewrites CheckpointTranscriptStart to the
transcript end, so the next pass finds pos <= start and no-ops.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396JYM2XHTVCNZPGBT2DCHQ
…anscript agents

sessionHasNewContentFromLiveTranscript began treating a non-empty
FilesTouched as sufficient evidence of new work, skipping the transcript
growth check. The justification is specific to a LateTranscriptWriter: only
such an agent has an empty transcript mid-turn, where the growth check would
veto genuinely hook-captured edits and drop the trailer from a user's
mid-turn commit.

Applied to every agent, it also removed the growth precondition from the
eight streaming-transcript agents' TTY commit path, where that check is
meaningful evidence rather than a false veto. Adding an agent to the registry
should not change the commit path of the agents already in it, and every
other behavioural change in this integration is gated through
agent.AsLateTranscriptWriter — this one now is too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396KAV831Y7R2EZ8Y7QJXQH
Antigravity's two truncated-step warnings logged through
context.Background(). logging.log resolves its logger from the context and
falls back to slog.Default() when there is none, and nothing outside tests
calls slog.SetDefault — so those warnings went to the stdlib text handler on
stderr, not to .entire/logs/entire.log where the integration says they are
recorded. ExtractModifiedFilesFromOffset runs inside prepare-commit-msg and
post-commit condensation, whose stderr the user sees, so a transcript with
truncated replace_file_content steps (measured at roughly 0.8% of such calls)
printed unstructured `level=WARN msg=...` lines into `git commit` output,
without session_id.

The method had no context to log through, so the interface gains one. The
other ten implementations ignore it; only the call sites, which all had a
context in scope, and the antigravity implementation change behaviour.

Mechanical apart from those two log calls, and separable from the rest of
this branch if it is better carried by the prompt-resolution follow-up.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396KXK11H1DRDMZ9R131KPR
The import guard built its per-package allowlist with
`append(allowedPrefixes, scopedPrefixes[pkgName]...)` inside the loop. That
is safe only because allowedPrefixes is a composite literal whose cap equals
its len, forcing a copy. Build it any other way — make() with spare capacity,
or one more appended entry — and append writes the antigravity-scoped
internal/flock entry into its backing array, handing every package checked
afterwards the exception scopedPrefixes exists to contain, with no test
failure to signal it.

slices.Clone makes that independent of how the slice is built, and hoisting
it out of the inner loop drops a re-allocation per import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M396KYVETYG282B0SZZZ0ZSV
main removed Gemini CLI support while this branch was adding Antigravity, so
every conflict was the same collision: both sides edit the lists of supported
agents. Resolved by taking main's list and restoring Antigravity to it,
keeping main's other additions (Codex, where it had been added alongside).

Substantive resolutions:

- generateSummary: kept this branch's sliceByAgentMetric delegation and took
  main's geminilegacy call inside the fallback switch. The branch's inner
  Gemini case still named the geminicli package, which main deleted, so it
  could not have compiled either way.
- agent/geminicli: accepted main's deletion of the package. This branch had
  only touched it to thread ctx through ExtractModifiedFilesFromOffset.
- e2e/testutil/repo.go: kept RepoPreparer/RepoCleaner, dropped the gemini-cli
  branch — setupGeminiTestHome no longer exists.
- antigravity_test.go: the "wrong agent" sentinel named AgentNameGemini, a
  constant main deleted. Now AgentNameClaudeCode. This one is a semantic
  conflict git resolved cleanly and only vet caught.

Verified on the merged tree: go build, go vet (including GOOS=windows),
gofmt, mise run lint (0 issues) and mise run test:ci, all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M39RV7DGXVXPKTJRE1KGKEZ8
Both comments described the secret as shared with the gemini-cli E2E leg.
That leg no longer exists — main removed Gemini CLI support — so the only
consumer is agy's API-key mode, and "shared" now points a reader at an agent
that is not there.

Comment-only; the secret, the workflow and the fallback behaviour are
unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 01M39S2GZKTWB0KJFM3TQ86THA
@Soph
Soph merged commit 2a9ec4a into main Sep 24, 2026
18 checks passed
@Soph
Soph deleted the feat/antigravity-agent branch September 24, 2026 13:44
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.

5 participants