{"_id":"@agenticcontrolplane/antigravity","name":"@agenticcontrolplane/antigravity","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agenticcontrolplane/antigravity","version":"0.1.0","description":"Agentic Control Plane hook for Google Antigravity (agy) — identity, audit, and policy enforcement on every tool call, with a native force_ask mapping for approvals","type":"module","main":"hook.mjs","scripts":{"test":"node --test test/*.test.mjs"},"engines":{"node":">=20"},"keywords":["antigravity","agy","google","agent-governance","hooks","policy","audit","agentic-control-plane"],"homepage":"https://agenticcontrolplane.com/controls/antigravity","repository":{"type":"git","url":"git+https://github.com/agentic-control-plane/antigravity-acp-plugin.git"},"license":"MIT","_id":"@agenticcontrolplane/antigravity@0.1.0","gitHead":"ea8a749e415abb9fc7cf943a6b7e353d45cfe458","bugs":{"url":"https://github.com/agentic-control-plane/antigravity-acp-plugin/issues"},"_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-IT7bKVgf2HRL0pZoK6kWxVcja9Ujx8akA3yd+cC3WSm6ugLoAkOtbv3g3wwLafm5N7d21RlK02W8740Dtm8QTg==","shasum":"45668ef2ebd7ca3f48f9b461f1f1aac411b3ee74","tarball":"https://registry.npmjs.org/@agenticcontrolplane/antigravity/-/antigravity-0.1.0.tgz","fileCount":5,"unpackedSize":24715,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDFMExwC/BAxt2JUvVe7ZzMPQ0DXDClfej8T5blTTuDQAIhAMeUzhjNn9GI1uuj7/gWN7sVCJaLKGy5KA22fd1hgUuZ"}]},"_npmUser":{"name":"davidcrowe","email":"reducibl@gmail.com"},"directories":{},"maintainers":[{"name":"davidcrowe","email":"reducibl@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/antigravity_0.1.0_1787773816667_0.0071212508917724016"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-26T19:50:16.541Z","0.1.0":"2026-08-26T19:50:16.786Z","modified":"2026-08-26T19:50:17.007Z"},"maintainers":[{"name":"davidcrowe","email":"reducibl@gmail.com"}],"description":"Agentic Control Plane hook for Google Antigravity (agy) — identity, audit, and policy enforcement on every tool call, with a native force_ask mapping for approvals","homepage":"https://agenticcontrolplane.com/controls/antigravity","keywords":["antigravity","agy","google","agent-governance","hooks","policy","audit","agentic-control-plane"],"repository":{"type":"git","url":"git+https://github.com/agentic-control-plane/antigravity-acp-plugin.git"},"bugs":{"url":"https://github.com/agentic-control-plane/antigravity-acp-plugin/issues"},"license":"MIT","readme":"# @agenticcontrolplane/antigravity\n\n![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen) ![license](https://img.shields.io/badge/license-MIT-blue)\n\n[Agentic Control Plane](https://agenticcontrolplane.com) hook for **Google Antigravity** (`agy` — the CLI, the IDE, and the app share one hook registration). Every tool call is checked against your workspace policy before it runs, and ACP approvals surface as **native Antigravity prompt cards** via `force_ask` — the first harness whose hook vocabulary carries a first-class ask.\n\nBefore any tool runs, ACP is consulted via `/govern/tool-use`; after it runs, an audit/completion record goes to `/govern/tool-output`. Session end emits a receipt with a review link.\n\n## Install\n\n~~~bash\ncurl -fsSL https://agenticcontrolplane.com/install.sh | bash\n~~~\n\nThe installer detects Antigravity, places the hook at `~/.acp/hooks/antigravity/hook.mjs`, and **merges** the registration into `~/.gemini/config/hooks.json` under its own `acp` key — the file is shared by the CLI, IDE, and app, so it is never overwritten. Manual install:\n\n~~~bash\nmkdir -p ~/.acp/hooks/antigravity ~/.gemini/config\ncurl -fsSL https://raw.githubusercontent.com/agentic-control-plane/antigravity-acp-plugin/main/hook.mjs \\\n  -o ~/.acp/hooks/antigravity/hook.mjs\ncurl -fsSL https://raw.githubusercontent.com/agentic-control-plane/antigravity-acp-plugin/main/hooks/acp.json \\\n  -o ~/.acp/hooks/antigravity/acp.json\nnode -e 'const fs=require(\"fs\");const p=process.env.HOME+\"/.gemini/config/hooks.json\";let cur={};try{cur=JSON.parse(fs.readFileSync(p,\"utf8\"))}catch{};const add=JSON.parse(fs.readFileSync(process.env.HOME+\"/.acp/hooks/antigravity/acp.json\",\"utf8\"));fs.writeFileSync(p,JSON.stringify({...cur,...add},null,2))'\n~~~\n\nCredentials live at `~/.acp/credentials` (the installer provisions them; or paste a workspace key from [cloud.agenticcontrolplane.com](https://cloud.agenticcontrolplane.com)). Verify with `/hooks` inside Antigravity.\n\n## What it does\n\n| Antigravity event | ACP call | Effect |\n|---|---|---|\n| `PreToolUse` (matcher `*`) | `POST /govern/tool-use` | `deny` blocks; `ask` becomes native `force_ask`; `allow` proceeds |\n| `PostToolUse` | `POST /govern/tool-output` | Audit/completion record — the payload carries the call and error status, **not the tool's output**, so this is not a content scan |\n| `Stop` | — | Session receipt in the scrollback with a console review link |\n\n**Tool-name mapping.** Antigravity's native names (`run_command`, `view_file`, `replace_file_content`, …) map to the canonical vocabulary before the policy check so content floors fire; the native name is preserved as `client_tool_name` in the audit record. Unknown and MCP tool names pass through.\n\n## The ask decision\n\nAn ACP `ask` maps to Antigravity's **`force_ask`**: the human gets a native prompt card, and cached \"Always Allow\" grants deliberately do not pre-empt it. Headless (`-p`), Antigravity itself soft-denies unobtainable approvals (run continues, exit 0, stderr notice) — the correct unattended resolution, natively.\n\n## Failure posture\n\nAntigravity's hook core is **fail-closed**: a crashed, timed-out, or non-zero-exiting hook blocks the tool call. This hook therefore always answers in JSON with exit 0 — including its own crash handling — and carries its own posture for gateway trouble:\n\n- **Interactive sessions**: gateway unreachable → fail **open**, loudly — `[ACP] ⚠ UNGOVERNED` on stderr and a durable line in `~/.acp/lapse.log`. An ACP outage must never brick your session.\n- **Unattended tiers**: fail **closed** — nobody is watching, so the block is the safety net.\n- One retry on transport failure; HTTP error statuses are the server answering — never retried.\n- Internal 4s decision budget ≪ the registered 30s timeout, so the hook always answers before the harness's error path.\n\nAntigravity runs hooks with a **sanitized environment** — configuration rides in `~/.acp/config.json` (snake_case keys), not env vars. Unattended fleets should pin `\"agent_tier\": \"background\"` there.\n\n## Configuration\n\n| Env (when it reaches the hook) | Config key | Default |\n|---|---|---|\n| `ACP_BEARER_TOKEN` | — | `~/.acp/credentials` |\n| `ACP_GOVERN_BASE` | `govern_base` | `https://govern.agenticcontrolplane.com` |\n| `ACP_CONSOLE_BASE` | `console_base` | `https://cloud.agenticcontrolplane.com` |\n| `ACP_AGENT_TIER` | `agent_tier` | `interactive` |\n| `ACP_CHECK_TIMEOUT_MS` | `check_timeout_ms` | `4000` |\n| `ACP_SHADOW` | `shadow` | shadow-mode notices on |\n\n## Verified vs. pending\n\nLive-verified end to end (agy 1.1.21, 2026-08-26): the hook fires in real turns **before** the native permission layer; `run_command`'s arg key is **`CommandLine`** (normalized to the canonical `{command}` shape — the production hardline floor denied `rm -rf /` under the native tool name); headless soft-deny and session receipts behave as documented. Known limit, verified by A/B: **`--dangerously-skip-permissions` bypasses Antigravity's hook layer entirely** — no hook (this one included) is consulted under that flag. Still pending: `force_ask` rendering in the interactive TUI (offline-verified against the documented contract).\n\n## Tests\n\n~~~bash\nnode --test test/*.test.mjs\n~~~\n\n15 offline tests against a mock gateway: payload parsing, canonical mapping, deny/force_ask/allow, both fail postures, config-file tier resolution, retry discipline, PostToolUse noise filtering, receipts.\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-932c156f9dfdc2ae85ce3578c920ba31"}