Building autonomous agents with tools like Google Antigravity opens up huge possibilities for modern software engineering. Paired with state-of-the-art foundation models, these harnesses provide the scaffolding agents need to reason, navigate multi-step workflows, and execute tools autonomously.
When everything runs smoothly, the experience feels like pure magic. If you are satisfied with that illusion and only care about the final output regardless of how the agent got there, this post is probably not for you.
That magic starts to wear thin the moment you need to debug unexpected behavior, justify infrastructure costs, or explain an agent decision to stakeholders. Engineering reliable systems requires visibility into every step of the execution loop. You need to know which tools your agent selected, track runaway token consumption, and preserve an audit trail when things go sideways.
That is where hooks in Antigravity come into play. By tapping into these lifecycle events, you can lift the curtain and stream runtime telemetry straight into Google Cloud Observability tools like Cloud Logging, Cloud Trace, and Cloud Monitoring. Let’s walk through how to build this integration step by step.

What are hooks in Antigravity?
Antigravity hooks allow you to tap into specific lifecycle events and execute scripts or commands at critical moments:
- PreInvocation: Before the agent begins processing a turn or invocation.
- PreToolUse: Before the agent executes a specific tool call (can allow or block actions).
- PostToolUse: Immediately after a tool completes execution, capturing duration, results, or errors.
- PostInvocation: After an invocation turn finishes.
- Stop: When the conversation or interaction concludes.
They can be created either at a global level or at a workspace level:
- ~/.gemini/config/hooks.json: These hooks will apply to all workspaces.
- .agents/hooks.json: These hooks only apply to the current workspace that contains the .agents folder.
Hooks are commonly used to judge tool usage and potentially decline a tool because it can be used to run destructive operations or leak sensitive data. They are also very useful in creating telemetry and audit trails as you will see in the examples below.
If you want to dive deeper into hooks, I highly recommend this thorough walk-through by Tanaike-san:
A Developer’s Guide to Agent Hooks in Antigravity CLI
How is this different from enabling Gemini Enterprise Compliance Logging?
Antigravity in Gemini Enterprise comes with a built-in feature that allows you to optionally enable either Metadata logging or Prompts and Responses Logging at the inference endpoint on the server side. These provide good insights into how agents are used across the organization, but won’t provide the same granular visibility into harness behavior as the hooks described in this post.
If you’re interested in learning more about the Gemini Enterprise logging capabilities for Antigravity, check out my previous post:
Stop Flying Blind: Enterprise Observability for Antigravity with Gemini Enterprise
The Example Repo
The examples in this post are available on GitHub. To use them in your own Antigravity adventures, clone the repo and copy the .agents folder content into your global config or local repository-scoped .agents folder.
The hooks.json file contains all three hooks that are enabled by default but contain an enabled flag that lets you turn hooks on or off.
{
"Log": {
"enabled": true,
...
},
"Trace": {
"enabled": true,
...
},
"Metrics": {
"enabled": true,
...
}
}
By default, logs and trace spans are written to local files, but all the hooks can be configured via environment variables to send information to the respective Google Cloud services:
export GOOGLE_CLOUD_PROJECT="$(gcloud config get-value project)"
export AGY_LOG_EXPORTER="gcp" # Log to Cloud Logging
export AGY_OTEL_EXPORTER="gcp" # Export Traces to Cloud Tracing
Note that this repo serves primarily as an illustration and the specific payloads have not been optimized for storage cost. Before deploying these hooks at scale, you should evaluate the additional log and metric volume they generate.
The “Log Everything” Hook
The first hook that we want to explore serves two purposes:
- We want to log all lifecycle events.
- We want to understand which data fields are logged for which events so we can use them in hooks to capture metrics and traces.
If you inspect the Log hook in hooks.json, you can see that it triggers on all available lifecycle events and calls the log_hook.py command.
{
"Log": {
"enabled": true,
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "./log_hook.py PreToolUse",
"timeout": 15
}
]
}
],
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "./log_hook.py PostToolUse",
"timeout": 15
}
]
}
],
"PreInvocation": [
{
"type": "command",
"command": "./log_hook.py PreInvocation",
"timeout": 15
}
],
"PostInvocation": [
{
"type": "command",
"command": "./log_hook.py PostInvocation",
"timeout": 15
}
],
"Stop": [
{
"type": "command",
"command": "./log_hook.py Stop",
"timeout": 15
}
]
},
}
With this configuration in place, all tool calls and model turns can now be logged directly to Cloud Logging.

A PreToolUse log entry for a view_file tool for expample looks like this:
{
"insertId": "1dpcibaf6kj3j4",
"jsonPayload": {
"timestamp": "2026-09-23T14:10:31.237814+00:00",
"payload": {
"transcriptPath": "/home/user/.gemini/antigravity-cli/brain/6beeecbd-b2c5-40ca-973f-05960ec4e5f4/.system_generated/logs/transcript_full.jsonl",
"stepIdx": 4,
"modelName": "gemini-3.8-flash-low",
"toolCall": {
"args": {
"toolSummary": "Read README.md",
"toolAction": "Viewing README.md",
"EndLine": 200,
"StartLine": 1,
"AbsolutePath": "/home/user/experiments/agy-hooks/README.md"
},
"name": "view_file"
},
"artifactDirectoryPath": "/home/user/.gemini/antigravity-cli/brain/6beeecbd-b2c5-40ca-973f-05960ec4e5f4",
"workspacePaths": [
"/home/user/experiments/agy-hooks"
],
"conversationId": "6beeecbd-b2c5-40ca-973f-05960ec4e5f4"
},
"event": "PreToolUse"
},
"resource": {
"type": "gce_instance",
"labels": {
"project_id": "my-project",
"instance_id": "2690103350977809706",
"zone": "projects/1111111111111111/zones/europe-west1-b"
}
},
"timestamp": "2026-09-23T14:10:33.108410674Z",
"severity": "INFO",
"labels": {
"model": "gemini-3.8-flash-low",
"event": "PreToolUse",
"conversation_id": "6beeecbd-b2c5-40ca-973f-05960ec4e5f4"
},
"logName": "projects/my-project/logs/antigravity-hooks",
"receiveTimestamp": "2026-09-23T14:10:33.108410674Z"
}
Note that here we’re only looking at the logs capturing lifecycle hook context. If you want insights into the user’s initial prompt and the model’s full thinking process, check the built-in session transcript logging that Antigravity creates in either of these locations depending on the surface:
- antigravity-cli/brain/<CONVERSATION_ID>/.system_generated/logs/transcript_full.jsonl
- antigravity/brain/<CONVERSATION_ID>/.system_generated/logs/transcript_full.jsonl
Of course, you can also use a logging agent to stream these logs to Cloud Logging or upload them to a Cloud Storage bucket for analytics or archiving.
The “Stream Raw Metrics” hook
Now that we have logs in Cloud Logging, we could use log-based metrics to create metrics in Cloud Monitoring. However, since we already have hooks in place, we can emit metrics directly with full scripting flexibility using a dedicated hook.
Unlike the previous hook where we explored all available hook contexts, here we are only interested in PostToolUse and PostInvocation events to record metrics for tool calls and turns:
{
"Metrics": {
"enabled": true,
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "./metrics_hook.py PostToolUse",
"timeout": 15
}
]
}
],
"PostInvocation": [
{
"type": "command",
"command": "./metrics_hook.py PostInvocation",
"timeout": 15
}
]
}
}
Our metrics_hook.py takes care of creating metrics entries for each turn and tool call. With that hook in place and the environment variable set to record metrics in Cloud Monitoring, we can see metrics streaming in and available in Metrics Explorer:

The “Trace the Flow” Hook
With logs and metrics in place, we can also generate OpenTelemetry spans for tracing. These trace graphs are invaluable for visualizing the sequence of agent actions and analyzing latency breakdowns.
The hook configuration looks very similar to the other two, but this time we need all signals to calculate span durations:
{ "Trace": {
"enabled": true,
"PreInvocation": [
{
"type": "command",
"command": "./trace_hook.py PreInvocation",
"timeout": 15
}
],
"PreToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "./trace_hook.py PreToolUse",
"timeout": 15
}
]
}
],
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "./trace_hook.py PostToolUse",
"timeout": 15
}
]
}
],
"PostInvocation": [
{
"type": "command",
"command": "./trace_hook.py PostInvocation",
"timeout": 15
}
],
"Stop": [
{
"type": "command",
"command": "./trace_hook.py Stop",
"timeout": 15
}
]
}
}
The hook script in trace_hook.py creates spans that can either be viewed locally by logging them to the console:
Conversation: a8d6df1d-7991-4ae4-8149-9d05901972f4 | Model: gemini-3.8-flash-medium | Total: 34.98s
------------------------------------------------------------------------
[12:52:49] Invoc #0 (Turn #0) (4.37s)
└─ run_command (498ms): Workspace listing
[12:52:53] Invoc #1 (Turn #1) (3.51s)
└─ run_command (448ms): Find hooks.json
[12:52:57] Invoc #2 (Turn #2) (4.00s)
└─ view_file (454ms): View hooks.json
[12:53:02] Invoc #3 (Turn #3) (3.85s)
└─ view_file (431ms): View README.md
[12:53:06] Invoc #4 (Turn #4) (9.91s)
└─ run_command (517ms): List .agents directory
[12:53:16] Invoc #5 (Turn #5) (7.37s)
├─ Direct response (7.37s)
└─ Stop: NO_TOOL_CALL
Or they can be ingested into Cloud Trace:

Interesting side note: Cloud Trace now supports specific highlighting for “GenAI” events. But that’s a rabbit hole for another day.
Next Steps
The examples in this post are primarily designed to demonstrate hook capabilities and inner harness behavior. They are not intended for production use out of the box, as they have not been optimized to minimize cloud costs or execution overhead. For instance, the hooks currently send telemetry to Google Cloud synchronously within hook execution. In production, you would want to decouple capture from ingestion to avoid introducing latency to the Antigravity agent.
If you’re curious about what your agent is doing under the hood, clone the example repo and start exploring!
Hooking into the Antigravity Harness with Google Cloud Observability was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/hooking-into-the-antigravity-harness-with-google-cloud-observability-18de38bd6667?source=rss—-e52cf94d98af—4
