ANTIGRAVITY LABJP
Articles/Integrations
Integrations/2026-07-11Advanced

Nobody Is There to Say Yes: Writing Unified Permissions as an Unattended Contract

The v2.2.1 unified permission system assumes a person is watching. On a 3 a.m. scheduled run, that assumption quietly breaks. Here is how I declared the policy up front as an allow / deny / queue contract so an unattended agent never stalls on a prompt no one can answer.

Antigravity355unified permissionsscheduled runs4unattended operationpermission design3

Premium Article

A scheduled run I had kicked off at 3 a.m. was still not finished by morning. I opened the log and it stopped on a single line: "Allow writing to this file?" There was no one there to answer.

The unified permission system that landed in v2.2.1 is a refreshingly plain mechanism for controlling what an agent is allowed to do. But that plainness rests on an assumption: that someone is sitting in front of the screen, ready to press allow or deny. The more you run agents overnight or before dawn as a solo developer, the more quietly that assumption slips away. Today I want to walk through the design I actually built to close that gap.

What happens when you carry an interactive mechanism into unattended hours

The default behavior of unified permissions is to ask when it meets an operation it has not seen before. In an interactive session that is correct. Returning judgment to a human is the foundation of safe design.

The trouble is that this same behavior runs unchanged during hours when there is no human to ask. When an agent running headless or on a schedule raises a prompt, no response comes back. It times out, or worse, it sits there holding the run open. In my case, a stalled process kept a lock and dragged the next scheduled start into the jam, chaining two nights of jobs together. The failure was in one place; the damage spread sideways.

Flipping everything to "allow" is the easy escape, but that throws away the reason you enabled unified permissions in the first place. Precisely because it is unattended, I want the permitted surface to stay narrow — and yet not stall. The only way to have both is to decide the answers before execution instead of asking during it.

The unattended contract: an allow / deny / queue trichotomy

The key was to stop treating the decision as a binary. Interactively, allow-or-deny is enough, because a person can think on the spot. Unattended, both ends hurt. Lean toward allow and dangerous operations slip through; lean toward deny and legitimate work is dropped.

So I added a third exit: queue.

DecisionRuntime behaviorMeaning
allowExecute as-isReversible, contained operations you can call safe in advance
denyRefuse, stop, and recordThings you never want touched unattended: destructive production changes, secret reads
queueHold execution for a morning decisionNeither clearly safe nor clearly dangerous — worth one human glance

An unattended contract is the promise that every operation that could arise is mapped, ahead of time, to one of these three. At runtime the agent consults the contract instead of asking. No prompt appears. So nothing stalls.

I set the axis of judgment on reversibility and blast radius, not on the name of a permission. Reads and changes inside the worktree are allow; side effects over the network or writes to shared resources are queue; destructive operations and secrets are deny. That line maps cleanly onto the operation categories unified permissions already enumerates.

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 manifest that maps unified permissions to allow / deny / queue before the agent runs
An audit log of the prompts that would have appeared, plus a morning re-entry digest
Measured numbers from 30 nights of scheduled runs: deadlocks, queue volume, and what deny actually stopped
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 $15 for lifetime access
View Membership →

Related Articles

Integrations2026-07-19
The One File That Stops Startup: Guarding config.json Integrity Before Scheduled Runs
Antigravity 2.3.1 fixed a bug where an empty or corrupt config.json blocked startup. The symptom was fixed; the causes of corruption still live in your environment. Here is a three-layer guard — validate, snapshot, restore — that runs before a scheduled job, with working code and notes from running it nightly.
Integrations2026-08-03
I Measured Before Writing a Number: MCP Connect and Tool Calls Differed by 486x
Antigravity 2.4.3 lets you set a timeout per MCP server. To find a defensible number I built a stdio server, measured each boundary separately, and found why a single value cannot cover both.
Integrations2026-07-28
Three Tools Named read_file: Catching MCP Name Collisions Before Startup
Bundle enough MCP servers and tool names collide quietly. Here is what a real 5-server, 21-tool setup measured at 43% collision, plus a Python preflight that catches them before startup and assigns deterministic aliases.
📚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 →