Antigravity
Antigravity (`agy`) connector registers all five 2.0 lifecycle hooks in ~/.gemini/config/hooks.json; the empirically verified PreToolUse event provides native ask/deny decisions that override --dangerously-skip-permissions.
The Antigravity connector wires DefenseClaw into Google's Antigravity CLI (binary name agy) via all five Antigravity 2.0 lifecycle hooks installed in ~/.gemini/config/hooks.json using the Claude-Code-compatible nested schema agy v1.0.x evaluates at runtime. DefenseClaw installs the hooks globally so every Antigravity session on the host reports into the same DefenseClaw gateway, while Antigravity continues to talk directly to its configured upstream model provider.
Why ~/.gemini/config/hooks.json and not ~/.gemini/antigravity-cli/hooks.json? The marketing-facing path printed by agy --help (~/.gemini/antigravity-cli/) is silently ignored by agy v1.0.x at runtime — agy actually reads PreToolUse hooks from ~/.gemini/config/hooks.json in a Claude-Code-compatible nested schema. This was determined empirically during the v0.5.0 smoke test: tracer hooks installed at the marketing path never fired; the same entries at the canonical path fired reliably on every tool call. DefenseClaw writes only the canonical path. defenseclaw doctor will surface a migration warning if a stale entry is left behind from a pre-v0.5.0 install at the legacy path.
Setup
defenseclaw setup antigravity # observe (default) - record only
defenseclaw setup antigravity --mode action # block on policy hits via hook denyThis connector is global/user-scoped only. DefenseClaw writes a single Antigravity hook entry into ~/.gemini/config/hooks.json and installs the shared hook script at ~/.defenseclaw/hooks/antigravity-hook.sh. Antigravity merges every discovered hooks.json it finds (the canonical ~/.gemini/config/hooks.json, project-local <workspace>/.antigravitycli/hooks.json, and the legacy ~/.gemini/hooks.json), so writing to more than one location causes the same hook to fire multiple times per tool call. To keep the audit trail clean and to avoid double-billing policy evaluations, DefenseClaw deliberately writes only the global file.
There is no proxy-enforcement path for Antigravity — blocking happens hook-side using Antigravity's documented JSON deny response.
The Antigravity connector is hook-only. defenseclaw setup antigravity defaults to observability-only mode=observe, and defenseclaw setup antigravity --mode action enables hook-native blocking. Antigravity still talks directly to its configured upstream model provider in both modes; DefenseClaw never inserts an LLM proxy.
What setup antigravity actually does
The wrapper accepts the same hook-alias flags as the other hook connectors. The underlying guardrail config falls back to the values DefenseClaw ships with — schema-defined in internal/config/config.go and documented on the Defaults page.
| Flag | Default | What it does |
|---|---|---|
--yes / -y | off | Skip the confirmation prompt. |
--mode observe|action | observe | observe records only; action returns Antigravity's documented deny response on policy hits. |
--restart / --no-restart | --restart | Bounce defenseclaw-gateway after applying changes so the new hooks wire in. |
--with-local-stack / --no-local-stack | --no-local-stack | Also bring up the bundled Prom/Loki/Tempo/Grafana stack via setup local-observability up. |
setup antigravity is shorthand for setup guardrail --connector antigravity: it adds or reconfigures Antigravity, defaults the connector to observe mode, and can join an existing hook-connector roster when you choose Add. claw.workspace_dir is always cleared — Antigravity setup is global by design. guardrail.mode changes to action only when --mode action is passed. To tune Antigravity after install, keep using defenseclaw setup guardrail --connector antigravity.
Version contract
DefenseClaw validates the installed Antigravity CLI version during setup using the trusted agy --version probe. The Antigravity connector pins a minimum-inclusive version of 1.0.0 and intentionally leaves the upper bound open: agy auto-updates in the background, so a strict ceiling would create a brittle compatibility window. The agy --version output is a bare semver string (e.g. 1.0.1) parsed with the standard semver range matcher.
The current contract is antigravity-hooks-v2 (hook script v7), which expanded coverage from the v1 PreToolUse-only baseline to the full Antigravity 2.0 lifecycle (PreInvocation, PreToolUse, PostToolUse, PostInvocation, Stop). PreToolUse is the only event empirically verified to fire on agy v1.0.1; the other four event branches are spec-conformant but gated on upstream agy implementation parity. Registering all five up front is intentional: when agy starts emitting a previously-quiet event, DefenseClaw handles it with zero redeploy.
Lifecycle events
DefenseClaw registers the full Antigravity 2.0 hook lifecycle. Only PreToolUse is currently advertised through the runtime capability gate as block/ask-capable; the remaining registrations preserve spec parity and telemetry without claiming enforcement that has not been verified.
| Event | When it fires | DefenseClaw role | Action verdict → wire shape |
|---|---|---|---|
PreInvocation | Just before the agent calls the LLM | Registered for spec parity and telemetry; not currently advertised as block/ask-capable | Non-blocking until upstream event behavior is empirically verified |
PreToolUse | Right before a tool (run_command, replace_file_content, etc.) executes | Validate tool args; intercept risky commands | block → {decision: "deny"}, confirm → {decision: "ask"}, alert → {systemMessage}; empirically verified on agy v1.0.1 |
PostToolUse | Immediately after a tool finishes execution | Capture diagnostics; flag PII / secrets in tool output. Cannot block — tool already ran. | alert → {additionalContext: "..."} for next-turn ingestion |
PostInvocation | After the LLM call + all associated tool calls finish | Post-process model output; flag policy violations in the response. Cannot block — response already generated. | alert → {additionalContext: "..."} |
Stop | When the agent's main execution loop is about to terminate | Registered for spec parity and telemetry | Non-blocking until upstream Stop behavior is empirically verified |
Post* events never emit deny or ask because the inspected action has already executed at the agent layer. If agy emits those registered events, DefenseClaw's response shaper uses additionalContext for the next turn.
Hook schema
DefenseClaw writes the Claude-Code-compatible nested schema agy v1.0.x evaluates at runtime. The file is a JSON object whose top-level keys are stable, DefenseClaw-owned hook identifiers — one per lifecycle event. Each value is an object keyed by event name, mapping to a list of (matcher, hooks[]) tuples, and each hook in the inner list is a {type, command} record:
{
"defenseclaw-antigravity-preinvocation": {
"PreInvocation": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "/Users/<you>/.defenseclaw/hooks/antigravity-hook.sh" } ] }
]
},
"defenseclaw-antigravity-pretooluse": {
"PreToolUse": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "/Users/<you>/.defenseclaw/hooks/antigravity-hook.sh" } ] }
]
},
"defenseclaw-antigravity-posttooluse": {
"PostToolUse": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "/Users/<you>/.defenseclaw/hooks/antigravity-hook.sh" } ] }
]
},
"defenseclaw-antigravity-postinvocation": {
"PostInvocation": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "/Users/<you>/.defenseclaw/hooks/antigravity-hook.sh" } ] }
]
},
"defenseclaw-antigravity-stop": {
"Stop": [
{ "matcher": "*", "hooks": [ { "type": "command", "command": "/Users/<you>/.defenseclaw/hooks/antigravity-hook.sh" } ] }
]
}
}The command field is a bare absolute path — agy v1.0.x invokes hooks via direct exec() (not through a shell), so any embedded quote characters would be interpreted as literal path bytes and the hook would silently no-fire. Operators with whitespace in their home path should set DEFENSECLAW_HOME to a whitespace-free directory before setup.
When DefenseClaw blocks on the verified PreToolUse event, the hook script returns a flat JSON envelope on stdout:
{ "decision": "deny", "reason": "policy denied" }On the verified PreToolUse surface, Antigravity recognizes a native "ask" decision that pauses the agent and prompts the operator. A returned "ask" decision bypasses --dangerously-skip-permissions. DefenseClaw maps eligible confirm verdicts to {"decision":"ask"} on that event. The literal string "force_ask" is intentionally not emitted because agy v1.0.0 does not recognize it; the conceptual distinction is preserved in internal raw_action telemetry only.
The response shaper contains the spec-conformant Stop {"decision":"block"} form, but the current capability gate does not classify Stop as blockable. That keeps the docs and advertised enforcement contract pinned to empirically verified behavior.
Local surfaces
Antigravity now publishes MCP, skills, rules, and plugin customization surfaces in addition to hooks. DefenseClaw writes hooks only to the global ~/.gemini/config/hooks.json path, reads and writes MCP servers from ~/.gemini/config/mcp_config.json and <workspace>/.agents/mcp_config.json, and supports the AgentSkills folder form under skills/<skill>/SKILL.md. CLI direct-markdown skills, rules, plugins, and plugin-contained agents are treated as discovery/scan surfaces until Google publishes enough install and lifecycle semantics for DefenseClaw to mutate them safely.
claw.workspace_dir is intentionally not honored by Antigravity hook setup. Antigravity merges discovered hooks.json files from the global, project, and legacy locations, so layering DefenseClaw hooks across multiple files would cause duplicate hook firings. Workspace MCP and asset discovery still use the workspace paths above when a workspace is explicitly selected.
The resolved paths are captured in ~/.defenseclaw/hook_contract_lock.json under locations, so defenseclaw doctor can report both the hook contract and the concrete hook location it is using.
Hook capabilities
Block events
- PreToolUse
Native ask events
- PreToolUse
Antigravity's verified PreToolUse event has a native unbypassable ask primitive. Returning decision=ask there overrides --dangerously-skip-permissions, so eligible confirm verdicts cannot be silently auto-approved. Do not assume that guarantee for the other four registered lifecycle events until their upstream behavior is verified.
Disable
defenseclaw setup guardrail --disableTeardown removes all DefenseClaw-owned defenseclaw-antigravity-* entries (one per lifecycle event) from ~/.gemini/config/hooks.json and leaves unrelated hooks untouched. If the file becomes empty after teardown, it is deleted. Teardown does not modify the legacy ~/.gemini/antigravity-cli/hooks.json — defenseclaw doctor will surface a separate migration warning if a stale entry from a pre-v0.5.0 install is detected there, prompting the operator to remove the file or the obsolete keys manually.
OpenHands
OpenHands connector wires DefenseClaw into global ~/.openhands/hooks.json command hooks by default, with MCP discovery through ~/.openhands/mcp.json and optional workspace-local skills.
Windsurf
Windsurf connector wires Cascade hooks across pre_user_prompt, pre_read_code, pre_write_code, pre_run_command, and pre_mcp_tool_use.