1. The Hidden Tax of Agentic Coding: Permission Fatigue
Modern agentic coding environments like Google Antigravity and Claude Code have shifted software development from single-line autocompletions to multi-step autonomous execution: editing worktrees, running test suites, grepping codebases, and dispatching MCP tools.
However, deep autonomy introduces a persistent security challenge: how do we prevent an autonomous agent from executing destructive commands or exfiltrating credentials without constantly interrupting the developer?
In a typical multi-turn refactoring session, an agent might execute between 15 and 40 individual tool calls. The agent inspects directory trees, reads configuration files, applies edits, runs linters, and executes test suites. If the developer harness requires manual human confirmation for every tool execution, the developer is forced into a barrage of repetitive approval prompts:

This dynamic causes permission fatigue. Human attention is a finite resource. When presented with dozens of low-risk confirmation requests in rapid succession, developers stop evaluating the command arguments and begin reflexively clicking "Allow" or hitting the Enter key.
Excessive manual permission prompts do not improve security; they degrade it. By conditioning developers to reflexively approve prompts to unblock their workflow, real security anomalies (such as accidental recursive deletions, unrequested branch force-pushes, or credential exposure) slip past human review unnoticed.
2. Industry Precedent: Anthropic Claude Code's Auto Mode
Recognizing that manual confirmation prompts become security theater over long coding sessions, Anthropic introduced Auto Mode for Claude Code, establishing it as the default permission model across Pro, Max, and Team tiers.t
How Auto Mode Operates
Instead of forcing developers to choose between continuous manual prompting and a dangerous "allow-all" flag (--dangerously-skip-permissions), Auto Mode inserts an automated classifier in front of tool execution:
- Semantic Safety Classifier: Each pending tool invocation (bash execution, file modification) is evaluated against a pre-tuned security model.
- Intent & Scope Boundary: The classifier determines whether the tool operation falls strictly within the context of the user's active prompt and workspace.
- Escalation vs Auto-Approve: Routine, non-destructive actions within workspace bounds are approved automatically. High-risk operations (destructive commands, network egress to unknown hosts, credential file access) are blocked or escalated to the developer for explicit confirmation.
Telemetry and developer experience reports show that automated permission classification removes the vast majority of human interruptions while maintaining high precision on destructive command detection.
The Friction of Transition
Once a developer experiences the uninterrupted flow of an intelligent auto mode, returning to an agent harness that repeatedly prompts for routine, harmless actions creates immediate cognitive friction.
Google Antigravity 2.0 provides an extensible agentic harness with multi-agent orchestration, subagent delegation, persistent terminal sessions, and workspace sandboxing. However, out of the box, Antigravity prompts users for confirmation on routine read and test commands that carry zero security risk.
While Claude Code's Auto Mode is an integrated, proprietary feature of a closed-source CLI, Antigravity provides an open, extensible lifecycle hook system (PreToolUse, PreInvocation). This allows us to build an inspectable, configurable, and multi-provider security gate.
To bridge this gap, I built auto-permissions: a zero-dependency, multi-provider security classifier and static policy engine plugin for Google Antigravity.
3. Architecture of auto-permissions
The auto-permissions plugin operates as a native PreToolUse lifecycle hook in Google Antigravity 2.0. Before any candidate tool call reaches the execution runtime, it is intercepted and evaluated through a two-tiered decision pipeline.

3.1 Two-Tiered Evaluation Pipeline
-
Tier 1: Static Policy Engine (<0.2ms Fast-Path): The hook first evaluates deterministic static ACL rules configured across hierarchical scopes. Safe operations (such as workspace file reads or explicitly allowed commands like
pytestandruff) are approved instantly in< 0.2mswith zero token cost. The engine prioritizes literal token prefix matching and evaluates pre-compiled regular expressions within strict execution bounds to eliminate ReDoS vulnerabilities. -
Tier 2: Decoupled LLM Classifier (~500 to 900ms Deep Semantic Check): If no static rule applies, the hook gathers sanitized context and invokes a fast LLM classifier (leveraging the zero-key Inbuilt Antigravity session, direct Gemini 2.5 Flash, or local/remote OpenAI and Anthropic models) to determine whether the action aligns with user intent. Token overhead is minimal (typically ~120 to 180 tokens per check).
4. Key Architectural Decisions & Invariants
Decision 1: Zero External Runtime Dependencies
The core hook scripts (hooks/auto_approve_gate.py, hooks/classifier.py, hooks/policy_engine.py, hooks/transcript_parser.py, hooks/audit_logger.py, sidecars/auto-permissions-worker/worker.py) run strictly using the Python 3 standard library (urllib.request, json, os, sys, threading, time).
External dependencies in lifecycle hooks introduce startup latency, environment conflicts, and virtualenv coupling. By using pure standard library networking and JSON parsing, hook execution starts instantly across any host environment without dependency resolution overhead.
Decision 2: The Decoupled Classifier Principle & Delimiter Sanitization
A critical vulnerability in LLM-based security gates is context poisoning and indirect prompt injection (IPI). If a classifier prompt includes the agent's internal chain-of-thought (CoT) or previous tool outputs (such as untrusted web page content or file contents read from disk), an attacker could manipulate the classifier into auto-approving malicious commands.

The auto-permissions classifier prompt strictly structures context into isolated, sanitized XML sections. To prevent structural delimiter breakouts, all user-provided strings are sanitized with XML entity escaping before template interpolation:
<workspace_roots>: JSON array of authorized workspace paths.<session_goal>: Optional high-level session objective extracted from Turn 0.<custom_workspace_guidelines>: Optional project-specific security rules from.agents/auto-permissions/config.json.<prior_user_prompts>: Recent user instruction history with chronological indexing ([Turn 0],[Turn 1]), excluding agent outputs and chain-of-thought.<active_user_prompt>: The immediate user instruction for the current turn.<proposed_tool_call>: The candidate tool name, action intent, and argument payload.
Completely stripping the agent's internal reasoning and untrusted prior tool outputs prevents indirect prompt injection from influencing security verdicts. To ensure the classifier understands multi-step developer workflows (e.g. running uv lock or pytest after editing code), the system prompt explicitly encodes developer lifecycle semantics: routine testing, formatting, and dependency lock updates within workspace boundaries are recognized as valid supporting actions for active engineering prompts.
<classifier_payload>
<workspace_roots>
<root>/workspace/project</root>
</workspace_roots>
<session_goal>
Refactor authentication service and verify test suite
</session_goal>
<prior_user_prompts>
<turn index="0"><![CDATA[The mock JWT token expired in unit tests]]></turn>
</prior_user_prompts>
<active_user_prompt>
<![CDATA[Fix the expiration timestamp and run the test suite again]]>
</active_user_prompt>
<proposed_tool_call>
<tool_name>run_command</tool_name>
<arguments>
{"CommandLine": "pytest tests/test_jwt.py -v", "Cwd": "/workspace/project"}
</arguments>
</proposed_tool_call>
</classifier_payload>Decision 3: Fail-Closed Safety Contract
Security gates must never fail open. If an API timeout occurs (>4.0s by default), an API key is missing, network access is severed, or a JSON payload is malformed, the hook immediately falls back to {"decision": "ask", "reason": "Classifier fallback: ..."}. The user is prompted manually rather than risking unauthorized execution.
In autonomous agent workflows, an unhandled network error or malformed model response cannot be treated as implicit approval. Forcing human confirmation during fault states guarantees that infrastructure failures never create accidental security bypasses.
Decision 4: Non-Blocking Audit Logging & Ephemeral Turn Disclosures
Security transparency is essential when actions are auto-approved. The plugin provides a two-pronged audit model:
- Background JSONL Logger: Every decision is logged asynchronously with atomic rotation (
max_bytes=5MB,backup_count=3) to<session_dir>/auto-permissions/audit.jsonl. - Turn-Scoped Disclosure Table: A
PreInvocationhook injects an ephemeral markdown summary at the beginning of each turn, displaying all actions evaluated during that turn. If a turn involves zero tool operations (such as pure conversational Q&A), the table is completely suppressed to avoid clutter.
Writing audit logs synchronously in the critical path introduces disk I/O latency to every tool call. Offloading JSONL writes to background threads maintains sub-millisecond hook responsiveness, while turn-scoped markdown summaries ensure developers retain continuous visibility over all auto-approved actions without permanent transcript pollution.

5. Core Features & Configuration Architecture
5.1 Hierarchical Static Policy Scopes
Static policies allow developers to enforce deterministic rules without LLM latency. Rules are resolved hierarchically from most specific to least specific:
1. Session Scope (<session_dir>/auto-permissions/session_overrides.json)
2. Project Local Scope (.agents/auto-permissions/config.local.json - gitignored)
3. Project Shared Scope (.agents/auto-permissions/config.json - committed to repo)
4. Global Scope (~/.gemini/config/auto-permissions/config.json)Rules support pattern matching across command prefixes, regex patterns, filesystem paths, URLs, and MCP tools:
command(pytest.*): Allow any pytest invocation matching the regex pattern.command(git status): Allow exact binary and subcommand prefix.write_file(src/.*): Allow file modifications withinsrc/.url(https://api\.internal\.corp/.*): Allow HTTP reads from internal corporate APIs.mcp(stripe:*): Require confirmation for Stripe payment MCP actions.
5.2 Zero-Configuration Authentication & Bring Your Own Model (BYOM)
The plugin resolves its classifier provider through a four-step resolution order, and supports Bring Your Own Model (BYOM) multi-provider classification. You do not need a separate Google AI Studio API key or billing account to use the security classifier:
| Provider | Protocol / Mechanism | Auth Requirement | Latency Profile | Deployment Scenarios |
|---|---|---|---|---|
Inbuilt Antigravity (antigravity) | Loopback Connect-RPC via plugin sidecar (sidecars/auto-permissions-worker/ on 127.0.0.1:4020), single-turn GetModelResponse | Zero-Config (Active IDE login & Language Server session) | ~500-900ms | Default out-of-the-box mode; zero billing setup. |
Cloud Code (cloudcode) | Google Cloud Code Assist REST API (cloudaicompanion.googleapis.com) | Google OAuth token (GOOGLE_OAUTH_TOKEN / gcloud auth) | ~1,280ms | Headless CI/CD, corporate Google Cloud workspaces. |
Google (google) | Gemini REST API (generateContent) | GEMINI_API_KEY or GOOGLE_API_KEY | ~1,340ms | Direct AI Studio API access with custom rate limits. |
OpenAI (openai) | OpenAI Chat Completions REST API | Optional local token or API key | ~30ms to 400ms (Local) / ~1.2s (Cloud) | Local GPU inference (Lemonade, vLLM, Ollama) or cloud endpoints (GPT-4o, Groq). |
Anthropic (anthropic) | Claude Messages REST API | ANTHROPIC_API_KEY | ~1,100ms | Anthropic API, Claude 3.5 Haiku, enterprise setups. |
The Plugin Sidecar Worker Pattern
When operating in zero-configuration mode, auto-permissions ships a thin, standard-library plugin sidecar (sidecars/auto-permissions-worker/). Antigravity spawns it automatically and injects the Language Server connection environment (ANTIGRAVITY_LS_ADDRESS, ANTIGRAVITY_CSRF_TOKEN). PreToolUse hooks run without that environment, so the gate calls the sidecar over loopback HTTP (POST /classify); the sidecar issues a single, stateless GetModelResponse to the language_server and returns the verdict. Contexts that do carry the environment classify directly, and the classifier falls back to the sidecar whenever direct loopback access is blocked (for example inside Antigravity's sandbox).
The zero-key provider relies on the Language Server's single-turn completion endpoint over its local Connect-RPC loopback, and the plugin sidecar is spawned via Antigravity's sidecar mechanism. Both are internal, undocumented surfaces that can change between Antigravity releases; the classifier fails closed (ask) rather than risking a bypass if they ever break. We default the classifier model to MODEL_GOOGLE_GEMINI_2_5_FLASH (100% on our 17-case accuracy battery at ~0.6s), resolved from the live account roster with automatic fallback when Google retires a model.

For privacy-sensitive enterprise environments, local inference servers (such as Lemonade, vLLM, or Ollama) allow the security gate to operate entirely on-device with zero external network egress:
python3 skills/auto-permissions-configure/scripts/configure_permissions.py \
--scope project_local \
--provider openai \
--model gemma-2-9b-it \
--endpoint-url "http://localhost:8000/v1/chat/completions" \
--api-key "optional-local-token"Use the /auto-permissions-configure skill from within Antigravity to interactively toggle between Inbuilt Antigravity, Cloud Code OAuth, Gemini, Anthropic, or local GPU endpoints.
Generation defaults target deterministic, low-latency verdicts: temperature 0.0, top-p 1.0, and a 800-token output cap. For local OpenAI-compatible backends you can override these (and reasoning effort, top-k, seed, and JSON mode) via AUTO_PERMISSIONS_TEMPERATURE, AUTO_PERMISSIONS_TOP_K, AUTO_PERMISSIONS_MAX_TOKENS, AUTO_PERMISSIONS_REASONING_EFFORT, and related environment variables. See the plugin configuration wiki for the full list and recipes.
5.3 Governed Surfaces (Subagents, Scheduling, Images)
By default, auto-permissions governs subagent delegation (invoke_subagent) and recurring schedules (schedule) to prevent unconstrained background processes from exceeding the scope of the developer's request.
In high-throughput agent workflows, you can customize or opt out of surface governance via .agents/auto-permissions/config.json:
{
"governed_surfaces": {
"subagents": true,
"schedule": true,
"generate_image": false
}
}6. Operating Inside the Antigravity Sandbox: Capabilities & Limitations
Google Antigravity executes tool commands inside a local container sandbox by default:
- Standard Sandbox Mode (
BypassSandbox: false): Read/write access to the workspace directory, but isolated from external host paths and restricted from raw network sockets unless explicitly allowed. - Bypass Sandbox Mode (
BypassSandbox: true): Disables container isolation, granting full filesystem and network access.
How auto-permissions Interacts with the Sandbox
- Sandboxed Command Evaluation: The classifier evaluates sandboxed commands normally, verifying that directory access and arguments align with user requests.
- Sandbox Elevation Detection: If a tool attempts to execute with
BypassSandbox: true, the classifier inspects the request with heightened scrutiny. If the active prompt did not explicitly demand unsandboxed access (such as connecting to an external cloud database or pushing a git remote), the classifier emitsaskordeny. - Sandbox Enforcement: The plugin acts as an automated intent-verification gate. It does not replace OS-level container isolation, but ensures that elevation requests are only approved when explicitly intended by the user.
7. Interactive Agent Skills
The plugin equips Antigravity with five built-in agent skills:
1. /auto-permissions-configure
Interactive CLI and wizard to inspect effective rules, toggle governed surfaces, update model providers (including zero-key Inbuilt Antigravity), and add ACL rules across Session, Project, or Global scopes.
2. /auto-permissions-audit
Analyzes <session_dir>/auto-permissions/audit.jsonl records, summarizes verdicts (allow/ask/deny ratios), calculates average classifier latency, and flags security warnings (e.g. timeout fallbacks or sandbox bypass attempts).

3. /auto-permissions-test
Simulates how the policy engine and LLM classifier will evaluate a candidate tool call against a given user prompt without executing the tool. Displays collapsible raw XML prompt payloads and raw JSON model responses.


4. /auto-permissions-fix
Analyzes recent denied tool actions from the audit log and automatically derives candidate static ACL rules, allowing one-click remediation of false-positive denials.

5. /auto-permissions-benchmark
Runs a labeled 17-case accuracy and latency battery (safe routines, workspace writes, external actions, destructive operations, credential exfiltration) against any configured provider or model, reporting per-case verdicts and request latency statistics. Use it to validate a model choice before adopting it (for example, it is how we verified that MODEL_GOOGLE_GEMINI_2_5_FLASH scores 100% while the account's default High-effort model is slower and once false-allowed reading .env secrets).

8. Installation & Quickstart
Prerequisites
- Google Antigravity 2.0
- Python 3.10+ (pure standard library)
- Zero-Configuration by default (Uses active Antigravity session; optional
GEMINI_API_KEY,OPENAI_API_KEY,ANTHROPIC_API_KEY, or local vLLM/Lemonade/Ollama server)
Installation
git clone \
https://github.com/abn/google-antigravity-plugin-auto-permissions.git \
~/.gemini/config/plugins/auto-permissionsOut-of-the-Box Zero-Key Execution
No API keys are required. The plugin automatically detects your active Google Antigravity environment and runs using the bundled plugin sidecar worker:
# Optional: explicitly enforce the Inbuilt Antigravity provider in your environment
export AUTO_PERMISSIONS_PROVIDER="antigravity"Restart Antigravity or reload plugins. The auto-permissions gate will immediately govern candidate tool calls.
9. Limitations of the Intent-Classification Layer
Intent classification is a pragmatic ergonomics and policy layer, not a guarantee. The limits that matter to practitioners:
- Probabilistic, not provable. An LLM infers intent; it cannot prove an action is safe. It will occasionally both over-block (a harmless help invocation misread as a risky mutation) and under-block (a genuinely dangerous command judged benign), and the miss rate rises sharply on obfuscated, chained, or composite commands.
- Bias tradeoff. Biasing toward automatic approval to remove permission fatigue necessarily raises the chance that an action a human would have caught slips through. Every reduction in false prompts trades a little safety.
- Blinding is double-edged. Hiding the agent's reasoning and tool outputs is what defeats prompt injection, but it also means the classifier judges only the command string and user intent, not the actual file contents or side effects the action will cause.
- Coverage is only as good as the test battery. Accuracy figures reflect curated scenarios on specific models; they do not generalize to the adversarial long tail, and weaker (especially local) models score measurably worse.
- Fast-paths bypass review. Sub-millisecond static rules auto-approve routine reads and workspace edits without any model review, so a compromised agent can still land benign-looking changes untouched.
Even when the intent classifier allows a tool call, the sandbox can still surface a prompt to the user. For example, in Antigravity's sandbox mode, an operation that needs to escape the container (for example a BypassSandbox elevation, or a command the sandbox blocks, such as one touching a read-only mount) may still require confirmation or fail closed regardless of the classifier's verdict. Classifier approval is necessary but never sufficient to avoid a human prompt.
10. A Reference Blueprint for Agent Plugin Authors
Permission fatigue is not unique to Google Antigravity. As AI coding harnesses (Cursor, Cline, Roo Code, Aider, OpenHands) gain deeper autonomy, every platform faces the same fundamental challenge: how to decouple security evaluation from human interruptions without opening a blank-check backdoor.
I built google-antigravity-plugin-auto-permissions with clean architectural separation:
- Standard library runtime with zero package bloat.
- Fast-path static policy evaluation before LLM invocation.
- Clean context decoupling to prevent indirect prompt injection.
- Fail-closed safety contracts with rotatable audit logging.
- Multi-provider BYOM support (Inbuilt Antigravity, Cloud Code OAuth, Gemini, Claude, local GPU).
I hope this implementation serves as a practical, open-source reference template for plugin authors across the agentic ecosystem. By moving from reflexive human confirmations to intelligent, decoupled authorization gates, we can build coding agents that are both autonomous and secure.
In this paradigm, all we are doing is letting a model predict our intent and evaluate candidate tool actions against security boundaries. While highly effective at reducing permission fatigue, intent classification is fundamentally probabilistic. It cannot mathematically guarantee security in all adversarial edge cases.
Automated intent classification is a pragmatic operational layer. As specialized open models mature, combining Language World Models (like Alibaba's Qwen-AgentWorld) with policy-adaptive edge models (like Mistral's Shieldstral) and personalized adapters will significantly elevate security postures. Until then, and even after, intent classifiers must always be paired with kernel-enforced sandboxes (like Linux Landlock and nono) or isolated virtual machines to maintain inviolable execution boundaries.









