Skip to main content

Antigravity-AutoAccept: five strategies to click a button I got tired of clicking

Share:XLinkedInHN
Cover for Antigravity-AutoAccept: five strategies to click a button I got tired of clicking

What Antigravity is, and why my mouse hand started to ache

Antigravity is Google's AI IDE, a VS Code fork with an agent that plans and executes coding steps. Every step wants my consent. Every terminal command, every file edit, every "may I apply this hunk?" is a modal in the sidebar with a button labelled Run, or Accept, or Always allow. On a good day the agent produces twenty of those in a minute. On a great day, sixty. My hand gets tired.

kaushiksaravanan/Antigravity-AutoAccecpt is the extension I wrote to press those buttons for me. Yes, the repo URL has a typo. Accecpt. It has been there since I created the repo and I have decided to keep it, because renaming would break every link and because I like that the artefact carries a small dumb human error on the front. The package.json name is the correctly spelled auto-accept-antigravity, Marketplace publisher kaushiksaravanan, version 0.7.7 shipped 2026-03-24, MIT.

What the extension is doing in five strategies

The extension activates on onStartupFinished and drops a status bar item that reads $(zap) Auto Accept: ON. Ctrl+Shift+Y fires an immediate accept-now on macOS or Windows (a separate toggle command exists without a default keybinding). Behind the toggle there are five different mechanisms trying to click the same set of buttons, because Antigravity does not expose one canonical accept command. It exposes about fifteen, and any given prompt is only reachable through one or two of them.

1. Settings injection

The cheapest attack is the one Antigravity gives me for free. When Auto Accept turns on, src/autoAcceptor.ts writes about a dozen workspace settings. Five of the load-bearing ones:

chat.tools.autoApprove         = true
chat.agent.autoApprove         = true
chat.agent.maxRequests         = 999
security.workspace.trust.enabled = false
terminal.integrated.confirmOnKill = never

There are more in the same batch that toggle terminal auto-approve, paste confirmation, and the global tools flag; I am showing the five that carried most of the weight when I first turned it on. Originals are snapshotted before the write and restored on stop or deactivate. I do not know whether chat.agent.maxRequests: 999 bypasses a paid tier ceiling or a safety cap, and I am not going to claim it does. What I know is that with those flags flipped, most (not all) prompts silently self-approve.

2. Command polling

For everything the settings do not cover, there is a fast setInterval that fires known accept commands on a schedule. Two loops run: a fast one at pollIntervalMs/2 with a 200ms floor, and a full sweep at 800ms. They call about fifteen commands including antigravity.agent.acceptAgentStep, antigravity.agent.acceptAllAgentSteps, antigravity.terminalCommand.run, antigravity.prioritized.agentAcceptFocusedHunk, notification.acceptPrimaryAction, workbench.action.chat.accept. If the command is a no-op because the button is not on screen, VS Code just shrugs. If the command is a hit, the button clicks.

I would love to be more surgical than this. The cost of surgical is keeping up with Antigravity's internal command IDs as they shift release to release, and I have not. Polling is the lazy fallback that survives renames until it does not.

3. Focus juggling

This one is the star. The command antigravity.agent.acceptAgentStep has a when clause that requires !editorTextFocus, meaning it will silently do nothing while my cursor is in the editor. The comment I left in the source, in a JSDoc block above the focus-shift, calls this out plainly:

* This is the key fix: antigravity.agent.acceptAgentStep requires !editorTextFocus.

Before firing accept, the extension shifts focus to the auxiliary bar, then the side bar, then the panel, waits 50ms for the focus event to settle, and only then dispatches the command. Then it puts focus back. If I am typing, I feel a tiny flicker. Every time I have gone back to remove this because it looked hacky, the extension stopped accepting anything and I put it back.

4. Event reactions

Instead of only polling, the extension hooks a fistful of VS Code events and re-fires the accept commands around them: onDidStartTerminalShellExecution, onDidChangeActiveTextEditor, onDidChangeVisibleTextEditors, onDidOpenTerminal, onDidSaveTextDocument. Some fire immediately, some sit behind a small 200-300ms delay so the UI has time to render the prompt about to appear, and onDidSaveTextDocument mostly bumps counters rather than firing accepts. Redundant with polling on paper. In practice, catching an event a moment after it fires beats catching the same button on the next 800ms poll tick, especially for terminal prompts that appear and disappear inside a second.

5. CDP webview walker

The last strategy is the one that goes underneath VS Code entirely. It is opt-in via the enableCDP setting, and OFF by default in 0.7.7. Antigravity, being an Electron app, exposes a Chrome DevTools Protocol endpoint. The extension scans ports 9222, 9229, and 9000 through 9014, opens a WebSocket to /json/version, enumerates all targets, and attaches to every one whose URL starts with vscode-webview://.

Then it injects a script (buildPermissionScript) built with a TreeWalker that walks the DOM inside the webview, recursing into any shadow root it finds, and matches buttons whose visible text contains entries from a small keyword list including run, accept, allow, always allow, allow this conversation, plus anything the user has added to customButtonTexts. A second pass targets expander buttons whose text contains expand or requires input. To avoid clicking the same button twice, each button gets a data-aa-t timestamp attribute for 5-second debounce, and expand-targets get 8 seconds.

I dropped this whole path in 0.6 when native settings started working. I put it back in 0.7.7 as an opt-in fallback for the long tail of prompts the command API cannot reach.

The safety brake

Any tool that clicks Run on my behalf is a footgun. The blocklist is enforced twice, on purpose.

blockedCommands = [
  "rm -rf /", "format", "mkfs", "del",
  "del *", "rmdir", "rd", "erase"
]

The first check is in the terminal-shell-execution listener. When Antigravity queues a shell command, the extension reads its text and matches each blocked entry as a word-boundary regex before allowing the accept fire. The second check is inside the CDP script, which re-scans the container text near any Run or Accept button and, if it finds a blocked command, returns the sentinel string blocked:<cmd> instead of clicking. Belt and braces because the CDP path can see prompts the extension API cannot.

flowchart TD
  A[Prompt appears] --> B{Native command<br/>path available?}
  B -- yes --> C[Focus juggle:<br/>aux -> side -> panel]
  C --> D[Fire accept command]
  B -- no --> E{CDP enabled?}
  E -- yes --> F[WebSocket to webview<br/>TreeWalker + shadow DOM]
  E -- no --> G[Skip; wait for next poll]
  D --> H{Terminal command<br/>text?}
  F --> H
  H -- matches blocklist --> I[Block: log 'blocked:cmd']
  H -- safe --> J[Click / dispatch]
  J --> K[Debounce 5s via data-aa-t]

The version arc

The commit graph tells its own story. Eight commits. Version 0.5 leaned entirely on CDP because the command API was not yet stable enough to be worth calling. 0.6 and 0.7 stripped CDP out completely in favour of the native settings and command-polling path, because CDP is intrusive and requires the user to launch Antigravity with a debug port they otherwise do not want open. Then 0.7.7 put CDP back, as an opt-in fallback, because the native path missed a class of prompts I kept hitting.

The lesson I keep re-learning is that when a tool exposes multiple layers, the right answer is usually not to pick one. It is to run the cheap layer by default and keep the expensive layer boxed and available. The graph zig-zags because I had to learn that twice.

What is messy

Two things I am not proud of. The commit 3239ee9, labelled just fix, sweeps a Windows debug session into the repo wholesale: hello.ps1, commands.json, settings.json, settings_utf8.json, ls_full_data.txt, ls_full_metadata.csv, process_debug_info.txt, test_monetization_script.js. None of it is used by the extension. All of it should have been in .gitignore before I ever ran git add .. There is also a test_extension.py sitting in a TypeScript repo. Thirty-three lines, untouched, from a moment I thought I would write the tests in Python. I did not.

The other soft spot is src/paywallWebview.ts. A RevenueCat paywall scaffolded, @revenuecat/purchases-js loaded from unpkg, a public test key wired in, a command autoAcceptAgent.showPaywall registered. And then checkPaywallLimit() short-circuits with return true; and the ten-free-runs logic is commented out. The paywall exists structurally and does nothing at runtime. I kept the scaffold in case a future me wants to charge, and I want the future me to see the seams.

Meanwhile, src/diagnostics.ts is the useful housekeeping tool: it scans vscode.commands.getCommands(true) against a couple dozen regex patterns and probes a similar-sized list of candidate settings, so when Antigravity renames something, I can find the new name in a report rather than by grepping the wrong version of the source.

That is the extension. Five ways to press a button, one blocklist so I do not press the wrong one, and one repo whose URL will forever be spelled Antigravity-AutoAccecpt.

Cite as: Saravanan, K. (2026). Antigravity-AutoAccept: five strategies to click a button I got tired of clicking. Kaushik Saravanan. https://www.kaushik.cv/blog/antigravity-auto-accept