AI coding agents can run tests, inspect logs, and produce convincing summaries. The weak point is often the boundary between ?work attempted? and ?work verified.? An agent may stop after a failed command, omit the report, or proceed with a broader tool call than the QA charter intended.
Antigravity hooks let teams run deterministic command handlers at specific points in the agent execution loop. This tutorial builds a small QA guardrail with three hooks: one before a tool runs, one after it completes, and one when the agent is about to stop. The goal is not to make an agent the release authority. It is to make missing approvals, failed checks, and absent evidence harder to overlook.
What Antigravity hooks expose
Google’s official Antigravity hooks documentation describes five lifecycle events: PreToolUse, PostToolUse, PreInvocation, PostInvocation, and Stop. Hooks are command handlers configured in a hooks.json file inside a workspace or user customization directory.
For this QA pattern, three events matter:
- PreToolUse: inspect a proposed tool call and return
allow,deny,ask, orforce_ask. - PostToolUse: observe the completed step and error field, then record sanitized diagnostics.
- Stop: inspect termination reason, execution number, idle state, workspace paths, transcript path, and artifact directory; return
continuewhen required work is incomplete.
Hooks receive JSON through standard input and return JSON through standard output. Treat every input field as untrusted. Validate types, normalize paths, and return the smallest supported response.
Hooks complement permissions
Antigravity also has a separate permission engine with Deny, Ask, and Allow lists. Google documents the precedence as Deny, then Ask, then Allow. Keep broad security rules in permissions. Use hooks for task-specific validation such as ?this QA run may execute the approved test script, but anything broader requires a fresh review.?
A hook should never weaken a deny rule or silently broaden access. For sensitive operations, force_ask is useful because it requires a prompt even when a cached approval exists.
Scenario: evidence-gated API regression check
Create a disposable repository containing a harmless API contract test and synthetic data. The required completion evidence is:
- the approved test command;
- its exit status;
- a machine-readable test report;
- a sanitized log;
- the build or commit identifier;
- no active background task;
- a human-readable summary that does not claim success after a failed check.
Keep all artifacts inside the workspace. Do not connect the lab to production, customer data, billing systems, or real credentials.
Step 1: organize the hook files
.agents/
hooks.json
scripts/
qa-pretool-gate.js
qa-posttool-record.js
qa-stop-validate.js
evidence/
hook-events.jsonl
test-report.xml
run-summary.json
The scripts should be small, dependency-light, and independently testable. Do not make them call a model. Their value comes from deterministic checks that behave the same way for the same JSON input.
Step 2: configure the three events
{
"qa-evidence-guard": {
"PreToolUse": [
{
"matcher": "run_command",
"hooks": [
{
"type": "command",
"command": "node scripts/qa-pretool-gate.js",
"timeout": 10
}
]
}
],
"PostToolUse": [
{
"matcher": "run_command",
"hooks": [
{
"type": "command",
"command": "node scripts/qa-posttool-record.js",
"timeout": 10
}
]
}
],
"Stop": [
{
"type": "command",
"command": "node scripts/qa-stop-validate.js",
"timeout": 10
}
]
}
}
Use paths that resolve consistently for the environment in which Antigravity runs. Keep timeouts short so a broken guardrail fails visibly instead of becoming a new source of hanging automation.
Step 3: design the PreToolUse gate
The gate reads toolCall.name, the proposed command, working directory, step index, and workspace paths. Define a narrow matrix:
| Proposed action | Decision | Reason |
|---|---|---|
| Approved read-only test command in the workspace | allow | Matches the lab charter |
| Unrecognized command or expanded arguments | force_ask | Requires human scope review |
| Production URL, secret path, privilege escalation, or destructive operation | deny | Outside the lab boundary |
Match normalized tokens and exact working directories; avoid broad substring checks. A command that starts similarly to an approved command may still add a dangerous flag or a second operation. Log only the decision, rule identifier, step index, and a redacted command fingerprint.
Step 4: record PostToolUse outcomes
PostToolUse receives the completed step index, an error string when the tool failed, and common metadata such as conversation and artifact paths. Append a JSON Lines record with:
- step index;
- success or failure;
- normalized error category, not the full secret-bearing message;
- timestamp;
- expected artifact names present after the command;
- conversation identifier stored as a one-way fingerprint if correlation is required.
PostToolUse returns an empty JSON object. It observes; it does not retroactively change the tool result. The later Stop validator uses its record to decide whether completion evidence is sufficient.
Step 5: build a bounded Stop validator
The Stop hook runs when the execution loop terminates. Check the termination reason, error, fullyIdle flag, execution number, and evidence files. Return continue only when the missing item can be recovered safely?for example, the test finished but the structured summary was not created.
Cap continuation. A simple policy is:
- On the first stop, continue once if a required report is missing and no unsafe error occurred.
- If a background task is still active, continue only to collect its bounded result.
- After the cap, allow termination and write an incomplete-run marker.
- Never convert a failed test into a pass merely because the agent produced more text.
Without a cap, a permanently missing artifact can create an execution loop. Test the cap before enabling the hook for team use.
Step 6: test the hook matrix
| Case | Expected behavior |
|---|---|
| Approved command | Allowed; successful outcome recorded |
| Broader command arguments | Fresh approval requested |
| Explicitly forbidden target | Denied before execution |
| Test exits with failure | Error recorded; completion cannot claim pass |
| Report missing after success | One bounded continuation requests evidence |
| Background task not idle | Result collection continues within the cap |
| Artifact still missing after cap | Run terminates as incomplete, not successful |
| Malformed hook input | Hook fails closed with a clear diagnostic |
Unit-test each script by piping fixture JSON into it and comparing the exact JSON response. Then run one integration test in the disposable Antigravity workspace. Preserve both the hook output and the final test evidence.
Step 7: review failure modes
Check for secrets in hook logs, path traversal, shell injection, oversized inputs, invalid JSON, unavailable interpreters, timeouts, concurrent file writes, and duplicate events. Use atomic append or a dedicated per-conversation evidence file so parallel runs do not corrupt one another.
Also verify that disabling the hook restores the documented baseline and that removing the customization leaves no hidden dependency. Rollback should be a tested operation, not a note in the README.
QA release checklist
- Permissions deny sensitive targets independently of hooks.
- PreToolUse allow, force-ask, and deny paths are tested.
- PostToolUse records success and failure without leaking secrets.
- Stop checks the report, log, build identifier, and idle state.
- Continuation is bounded and cannot create an infinite loop.
- Failed tests remain failed in the final summary.
- Malformed input fails closed with a useful diagnostic.
- Parallel runs cannot overwrite each other’s evidence.
- Disable and rollback behavior is verified.
- Human QA retains defect, severity, and release authority.
Antigravity hooks are most valuable when they enforce small, observable rules. Gate the proposed action, record the real outcome, and require the evidence needed to review completion. Then let deterministic tests and a human QA engineer decide whether the software is ready.
