Antigravity
Antigravity (`agy`) connector registers all five 2.0 lifecycle hooks. PreInvocation and PreToolUse are ask-capable; PreInvocation, PreToolUse, and Stop are block-capable in the current contract.
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 denyAntigravity setup is supported on macOS and Linux. The DefenseClaw connector is not certified on native Windows x64, so setup rejects it there.
This connector is global/user-scoped only. DefenseClaw writes five owned
entries—one per lifecycle event—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 global file, project-local
<workspace>/.antigravitycli/hooks.json, and legacy
~/.gemini/hooks.json), so writing the same handlers to more than one
location causes duplicate firings. 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 the event's declared native deny/block 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 run setup local-observability up; follow the command's printed gateway-restart step after it writes the export destination. |
setup antigravity is the dedicated Antigravity alias. It uses the shared
guardrail setup backend, defaults to observe mode, and can join an existing
hook-connector roster when you choose Add. claw.workspace_dir is cleared
because Antigravity hook setup is global by design. See the
quick-alias reference for the common options
and full guardrail setup for advanced scanner and
judge configuration.
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. After setup
selects antigravity-hooks-v2, that pinned runtime profile advertises
PreInvocation and PreToolUse as ask-capable, and PreInvocation,
PreToolUse, and Stop as block-capable. Only
PreToolUse has been empirically verified against agy v1.0.1; the other four
branches follow the published contract but still depend on upstream agy
implementation parity.
Use hook_contract_lock.json or defenseclaw doctor to identify the contract
actually pinned on a host.
| Event | When it fires | DefenseClaw role | Action verdict → wire shape |
|---|---|---|---|
PreInvocation | Just before the agent calls the LLM | Inspect the prompt before the model call | block → {decision: "deny"}, eligible confirm → {decision: "ask"}; spec-conformant, not yet 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 | Record the stop reason and honor a block verdict | block → {decision: "block"}; spec-conformant, not yet 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 a pre-action event, the hook script returns a flat JSON envelope on stdout:
{ "decision": "deny", "reason": "policy denied" }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 PreInvocation and PreToolUse; only the latter
has been empirically verified against agy v1.0.1. The literal string
"force_ask" is intentionally not emitted because agy v1.0.0 does not
recognize it; the conceptual distinction is preserved in raw_action
telemetry.
Stop uses the spec-conformant {"decision":"block"} form rather than the
"deny" verb used by pre-action events. PostToolUse and PostInvocation
never block.
Local surfaces
Antigravity 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 read/write installation of
the AgentSkills folder form under skills/<skill>/SKILL.md. Rules and plugins
are discovery/scan-only: DefenseClaw reads plugin roots under
~/.gemini/config/plugins/, <workspace>/.agents/plugins/, and the
CLI-managed ~/.gemini/antigravity-cli/plugins/, but does not install or
disable Antigravity plugins. CLI direct-markdown skills and plugin-contained
agents are also discovery/scan-only.
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
The authoritative contract is antigravity-hooks-v2: ask on
PreInvocation and PreToolUse; block on PreInvocation, PreToolUse, and
Stop; fail-closed transport is not supported. PostToolUse and
PostInvocation are observe/context-only.
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. PreInvocation has the same advertised ask shape but
has not yet been empirically verified against agy v1.0.1.
Disable
defenseclaw guardrail disable --connector antigravity --yesTeardown 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.