ANTIGRAVITY LABJP
Articles/Antigravity Basics
Antigravity Basics/2026-07-27Advanced

Who Approved the Right Side of &&? Splitting Shell Commands Before Matching Allow Rules

The approval dialog showed part of what actually ran. Here is a harness that splits compound shell commands without breaking quotes or command substitution, matches allow rules per segment, and the numbers from running it over 45 real commands.

Antigravity CLI18permissions2security19shell2automation87

Premium Article

The approval dialog read python3 scripts/redirect_integrity.py . --fix. My own gate script. I approved it without hesitating.

Days later I noticed there were no .bak files left in the repository and went back through the history. What actually ran was python3 scripts/redirect_integrity.py . --fix && rm -f content/*.bak. I had approved the first half. The deletion went through without me ever reading it.

Nothing was lost that I had not intended to delete anyway. What stayed with me was the gap itself: what I approved and what executed were not the same string.

Working as an indie developer, the approval dialog has exactly one reader. Whatever I wave through runs unopposed.

Reading the Antigravity changelog, I found that v1.1.7 addresses the display side — when only part of a compound shell command requires approval, the prompt now shows the full command. The display gets fixed. The question I could not answer was whether my own allow rules were written against the full command in the first place.

The dialog showed a fragment of what would run

Two separate layers are at work here.

The first is presentation: what the approval prompt puts in front of you. That is the part v1.1.7 improves.

The second is adjudication: the unit at which permit-or-prompt is decided for a command joined with && or ;. That lives in my configuration, and no upstream release fixes it for me.

My allow rules looked like this.

Bash(git add:*)
Bash(git commit:*)
Bash(python3:*)
Bash(npm run:*)

Read plainly, that means "permit commands beginning with python3." And python3 ... --fix && rm -f content/*.bak does begin with python3.

Matching on the leading token lets anything on the right side of && ride along. The rules were not underpowered; the unit of matching was wrong.

Questioning the head-token assumption

The fix is to move adjudication from "one command" to "one segment," where a segment is an individual command the shell will execute in sequence.

a && b || c ; d | e is five segments. git commit -m "a && b" is one, because the operator sits inside quotes. Getting this wrong breaks in both directions: split inside quotes and legitimate commits stop; fail to split outside them and a delete slips past.

So the splitter came first, as its own module. Anything built on a splitter that is wrong is decoration.

One clarification before the code: this is not a reimplementation of how Antigravity CLI adjudicates internally. It is a bench harness for checking whether my own allow rules behave as intended against the full command text. Whatever the tool decides upstream, the shape of my own configuration is something I can measure myself.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A quote-aware, substitution-aware command splitter with a five-case test suite you can drop into your own tooling
Measured difference between head-token matching and segment matching over the same command set, and how four extra rules restore the approval rate while still blocking the dangerous cases
Why command substitution belongs in a fail-closed bucket, and where splitting genuinely fails to help
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Integrations2026-07-18
Turning Silent Auto-Approvals into Allow Rules, One Soft-Deny at a Time
In Antigravity CLI 1.1.3, headless -p stops silently auto-approving confirmation-required tools and instead soft-denies them, printing the required allow-rule name to stderr. This piece uses that output as a discovery source to build least privilege from an empty allow set upward, with a working harness and real numbers from a personal automation.
Antigravity2026-06-16
Does the New CLI Do the Same Job? An Output-Parity Gate Before Switching to Antigravity CLI
With Gemini CLI shutting down on June 18, here is how I froze the old CLI's artifacts as a golden baseline and built a parity harness to catch regressions before cutting over to Antigravity CLI — with normalization and a go/no-go gate, in code.
Antigravity2026-07-11
Are You Actually Using Every Permission You Granted? Tightening Antigravity's Unified Permissions from Real Usage Logs
Once you flip a unified permission policy to 'allow everything,' unused grants quietly pile up. This is the grant-to-usage reconciliation loop: match granted permissions against your action logs, revoke what was never exercised, and narrow what's too broad — with working TypeScript and real numbers from solo operation.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →