# Antigravity Python SDK: The First 30 Minutes

> A guided onboarding path to the Antigravity SDK, focusing on rapid orientation, core abstractions, and the safety-first execution model.

## Context Links

- [Agent index](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/llms.txt)
- [Human interactive wiki](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867)
- [GitHub repository](https://github.com/google-antigravity/antigravity-sdk-python)

## Repository Metadata

- Repository: google-antigravity/antigravity-sdk-python

- Generated: 2026-05-19T20:42:20.250Z
- Updated: 2026-05-21T21:35:20.879Z
- Runtime: Antigravity CLI
- Format: First 30 Minutes
- Pages: 12

## Page Index

- 01. [Start Here](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/01-start-here.md) - What this repo is, the fastest read order, the entry points to open first, and the vocabulary (Agent, Conversation, Hook, Trigger) a new reader needs.
- 02. [Rapid Setup & First Run](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/02-rapid-setup-first-run.md) - Installation nuances (PyPI wheels vs source clones), environment variables, and the hello_world.py entry point for immediate verification.
- 03. [The Safety Model: Policies vs Capabilities](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/03-the-safety-model-policies-vs-capabilities.md) - Hidden constraints: why the SDK raises ValueError for write tools without policies, and how to optimize tokens by disabling tools vs denying them.
- 04. [Understanding the Agentic Loop](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/04-understanding-the-agentic-loop.md) - The three-layer architecture: Layer 1 (Simplified Agent), Layer 2 (Stateful Session), and Layer 3 (Transport Adapters).
- 05. [Agent Lifecycle & Context](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/05-agent-lifecycle-context.md) - How the Agent class manages resource cleanup via AsyncExitStack and provides high-level streaming interfaces for thoughts and tool calls.
- 06. [Stateful Conversations & History](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/06-stateful-conversations-history.md) - Deep dive into Conversation state, step history accumulation, and the low-level send/receive_steps API for granular interaction control.
- 07. [Tooling & MCP Integration](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/07-tooling-mcp-integration.md) - Extending agent capabilities via native Python functions and the Model Context Protocol (MCP) bridge for stdio and SSE servers.
- 08. [Hooks & Policy Precedence](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/08-hooks-policy-precedence.md) - The priority-based policy model (Specific > Wildcard) and how to implement custom middleware using pre/post-step hooks.
- 09. [Interactive & Human-in-the-Loop](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/09-interactive-human-in-the-loop.md) - Implementing interactive flows using run_interactive_loop and ask_user policy handlers for manual tool call approval.
- 10. [Event-Driven Triggers](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/10-event-driven-triggers.md) - Running background tasks that react to external events (e.g., timers via every()) and push asynchronous messages into the agent session.
- 11. [Multimodal & Content Ingestion](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/11-multimodal-content-ingestion.md) - Handling rich media: using from_file for automatic MIME resolution and direct constructor instantiation for in-memory bytes (Image, Video, Document).
- 12. [Beyond 30 Minutes: Next Steps](https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/12-beyond-30-minutes-next-steps.md) - Synthesis of the core model, pointers to deep-dive examples (Middleware, Subagents), and how to contribute to the SDK.

## Source File Index

- `CONTRIBUTING.md`
- `examples/deep_dives/async_chat.py`
- `examples/deep_dives/interactive_cli.py`
- `examples/deep_dives/multimodal_pipeline.py`
- `examples/deep_dives/README.md`
- `examples/getting_started/custom_tools.py`
- `examples/getting_started/hello_world.py`
- `examples/getting_started/hooks.py`
- `examples/getting_started/human_in_the_loop.py`
- `examples/getting_started/multimodal.py`
- `examples/getting_started/policies.py`
- `examples/getting_started/streaming.py`
- `examples/getting_started/subagents.py`
- `examples/getting_started/triggers.py`
- `examples/README.md`
- `examples/resources/sample_doc.txt`
- `google/antigravity/agent.py`
- `google/antigravity/connections/connection.py`
- `google/antigravity/conversation/conversation.py`
- `google/antigravity/conversation/README.md`
- `google/antigravity/hooks/hook_runner.py`
- `google/antigravity/hooks/hooks.py`
- `google/antigravity/hooks/policy.py`
- `google/antigravity/mcp/bridge.py`
- `google/antigravity/mcp/README.md`
- `google/antigravity/tools/tool_runner.py`
- `google/antigravity/triggers/README.md`
- `google/antigravity/triggers/trigger_runner.py`
- `google/antigravity/triggers/triggers.py`
- `google/antigravity/types.py`
- `google/antigravity/utils/interactive_test.py`
- `google/antigravity/utils/interactive.py`
- `pyproject.toml`
- `README.md`

---

## 01. Start Here

> What this repo is, the fastest read order, the entry points to open first, and the vocabulary (Agent, Conversation, Hook, Trigger) a new reader needs.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/01-start-here.md
- Generated: 2026-05-19T20:14:17.510Z

### Source Files

- `README.md`
- `pyproject.toml`
- `google/antigravity/agent.py`
- `google/antigravity/types.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [README.md](README.md)
- [pyproject.toml](pyproject.toml)
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [google/antigravity/types.py](google/antigravity/types.py)
- [google/antigravity/conversation/conversation.py](google/antigravity/conversation/conversation.py)
- [google/antigravity/hooks/hooks.py](google/antigravity/hooks/hooks.py)
- [google/antigravity/triggers/triggers.py](google/antigravity/triggers/triggers.py)
</details>

# Start Here

Welcome to the Google Antigravity SDK. This Python SDK provides a secure, scalable, and stateful infrastructure layer for building AI agents powered by Antigravity and Gemini. By abstracting the complex "agentic loop," the SDK allows developers to focus on defining agent behavior rather than managing the underlying execution runtime or transport logic.

This page provides an orientation for new readers, defining the core vocabulary, outlining the architectural layers, and recommending a sequence for exploring the codebase. Whether you are building a simple chatbot or a complex autonomous system, understanding these primitives is essential for effective development.

## Core Vocabulary

The Antigravity SDK uses a specific set of terms to describe its components and their interactions. Familiarizing yourself with these concepts is the first step toward mastering the SDK.

### Agent
The **Agent** is the primary, high-level entry point for most applications (Layer 1). It provides a "batteries-included" interface that manages the full lifecycle of an agent session—including binary discovery, tool wiring, hook registration, and policy enforcement—behind a single asynchronous context manager.
Sources: [google/antigravity/agent.py:36-39](), [README.md:32-36]()

### Conversation
A **Conversation** represents a stateful session (Layer 2). While the `Agent` handles higher-level orchestration, the `Conversation` specifically manages the accumulation of step history, tracks turn indices, and provides convenience methods for sending prompts and receiving streaming responses.
Sources: [google/antigravity/conversation/conversation.py:59-64](), [google/antigravity/types.py:763-765]()

### Hook
**Hooks** are interceptors that allow you to inject logic into the agent's lifecycle. They are categorized into three types: `InspectHook` (observability), `DecideHook` (policies/blocking), and `TransformHook` (data modification). Common hook points include turn start/end, tool call dispatch, and context compaction events.
Sources: [google/antigravity/hooks/hooks.py:65-115]()

### Trigger
A **Trigger** is a long-lived asynchronous function that runs alongside an agent session. Triggers react to external events—such as timers, filesystem changes, or webhooks—and push messages into the agent's context, allowing the agent to react to its environment proactively.
Sources: [google/antigravity/triggers/triggers.py:21-26](), [README.md:243-246]()

## Entry Points

The SDK is organized into a three-layer architecture to support varying levels of complexity and control.

| Layer | Purpose | Primary Class |
| :--- | :--- | :--- |
| **Layer 1: Simplified** | High-level, batteries-included orchestration. | `Agent` |
| **Layer 2: Session** | Stateful history management and streaming controls. | `Conversation` |
| **Layer 3: Adapter** | Low-level transport and backend abstraction. | `Connection` |

Sources: [README.md:265-272]()

### For Most Users: `google.antigravity.Agent`
Most developers should start with the `Agent` class. It simplifies configuration by using a `LocalAgentConfig` and handles the setup of underlying connections and runners automatically.

```python
from google.antigravity import Agent, LocalAgentConfig

async with Agent(LocalAgentConfig()) as agent:
    response = await agent.chat("Hello!")
    print(await response.text())
```
Sources: [google/antigravity/agent.py:195-204](), [README.md:44-51]()

### For Power Users: `google.antigravity.conversation.Conversation`
If you need direct control over the `ConnectionStrategy` or want to manage session state manually without the `Agent` abstraction, use `Conversation` directly.
Sources: [google/antigravity/conversation/conversation.py:89-93]()

## Architecture Overview

The following diagram illustrates how these components interact within an active session. The `Agent` orchestrates the `Conversation`, while `Hooks` and `Triggers` provide the extensibility points for custom logic and environmental reactivity.

```mermaid
graph TD
    User([User Application]) -->|Layer 1| Agent[Agent Class]
    Agent -->|Layer 2| Conv[Conversation Session]
    Conv -->|Layer 3| Strategy[Connection Strategy]
    
    subgraph Extensibility
        Agent -.->|Registers| Hook[Hooks / Policies]
        Agent -.->|Starts| Trigger[Triggers]
    end
    
    Trigger -->|Push Notifications| Strategy
    Strategy -->|Intercept Events| Hook
    Strategy -->|Transport| Runtime((Local Harness Binary))
```

## Recommended Read Order

To quickly understand the SDK's implementation, follow this reading path:

1.  **[README.md](README.md)**: Orientation and quickstart examples.
2.  **[google/antigravity/agent.py](google/antigravity/agent.py)**: The main entry point for the "Layer 1" API.
3.  **[google/antigravity/types.py](google/antigravity/types.py)**: The canonical Pydantic models used across all boundaries.
4.  **[examples/](examples/)**: Practical implementation patterns for personas, tools, and triggers.

The Google Antigravity SDK is designed to be provider-neutral and portable, utilizing the Model Context Protocol (MCP) and a flexible hook system to integrate with diverse environments and tools.
Sources: [pyproject.toml:19-24](), [README.md:204-207]()

---

## 02. Rapid Setup & First Run

> Installation nuances (PyPI wheels vs source clones), environment variables, and the hello_world.py entry point for immediate verification.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/02-rapid-setup-first-run.md
- Generated: 2026-05-19T19:52:30.519Z

### Source Files

- `README.md`
- `examples/getting_started/hello_world.py`
- `examples/README.md`
- `CONTRIBUTING.md`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [README.md](README.md)
- [examples/getting_started/hello_world.py](examples/getting_started/hello_world.py)
- [examples/README.md](examples/README.md)
- [google/antigravity/connections/local/local_connection.py](google/antigravity/connections/local/local_connection.py)
- [google/antigravity/connections/local/local_connection_config.py](google/antigravity/connections/local/local_connection_config.py)
- [pyproject.toml](pyproject.toml)
- [google/antigravity/types.py](google/antigravity/types.py)
</details>

# Rapid Setup & First Run

Getting started with the Google Antigravity SDK is designed to be a streamlined experience, moving from installation to a functional agentic turn in minutes. This page covers the critical nuances of the SDK's platform-specific distribution, required environment configuration, and the standard verification path using the built-in examples.

The SDK is not just a collection of Python modules; it is an orchestration layer that interfaces with a specialized Go-based runtime binary called the `localharness`. Understanding how this binary is discovered and how to properly authenticate with the Gemini API is essential for a successful first run.

## Installation Nuances

The Google Antigravity SDK requires a compiled runtime binary to function. This binary handles the heavy lifting of tool execution, state management, and communication with the Gemini backend.

### PyPI Wheels vs. Source Clones

There is a critical distinction between installing via `pip` and cloning the repository:

*   **PyPI Installation (Recommended):** When you run `pip install google-antigravity`, you receive a platform-specific wheel that includes the pre-compiled `localharness` binary. This is the only supported way for most users to obtain the SDK.
*   **Source Clones:** Cloning the repository from GitHub provides the Python source code but **does not include the binary**. The SDK will fail to initialize if it cannot find the `localharness` executable.

Sources: [README.md:15-19](README.md#L15-L19), [pyproject.toml:60-64](pyproject.toml#L60-L64)

### Binary Discovery Logic

The SDK attempts to locate the `localharness` binary using the following priority:
1.  **Environment Variable:** The value of `ANTIGRAVITY_HARNESS_PATH` if set.
2.  **Metadata Discovery:** Searching the installed `google-antigravity` package metadata for the path `google/antigravity/bin/localharness`.
3.  **Resource Discovery:** Falling back to `importlib.resources`.

Sources: [google/antigravity/connections/local/local_connection.py:1307-1330](google/antigravity/connections/local/local_connection.py#L1307-L1330)

## Environment Configuration

The SDK relies on a few key environment variables for authentication and advanced configuration.

| Variable | Description | Required |
| :--- | :--- | :--- |
| `GEMINI_API_KEY` | Your Google Gemini API key used for model inference. | **Yes** |
| `ANTIGRAVITY_HARNESS_PATH` | Explicit path to the `localharness` binary (primarily for development). | No |

Alternatively, the API key can be passed explicitly in the configuration:
```python
config = LocalAgentConfig(api_key="your_api_key_here")
```

Sources: [examples/README.md:10](examples/README.md#L10), [google/antigravity/connections/local/local_connection_config.py:62](google/antigravity/connections/local/local_connection_config.py#L62)

## First Run Verification

Once installed, the `hello_world.py` example is the gold standard for verifying your environment is correctly configured.

### Running Hello World

Navigate to the `examples/getting_started/` directory and execute the script:

```bash
export GEMINI_API_KEY="your_api_key_here"
python hello_world.py
```

### What Happens Internally

When you initialize an `Agent`, the SDK starts the `localharness` binary as a subprocess and establishes a WebSocket connection for real-time communication.

```mermaid
sequenceDiagram
    participant App as Python Application
    participant SDK as Antigravity SDK
    participant Bin as localharness (Binary)
    participant API as Gemini API

    App->>SDK: Agent(config)
    SDK->>Bin: Start Process (subprocess.Popen)
    Bin->>SDK: Port & API Key (stdout)
    SDK->>Bin: Connect (WebSocket)
    App->>SDK: agent.chat("Say 'Hello World!'")
    SDK->>Bin: Forward Prompt (WS)
    Bin->>API: Inference Request
    API-->>Bin: Tokens
    Bin-->>SDK: Tokens (WS)
    SDK-->>App: ChatResponse (Stream)
```

Sources: [examples/getting_started/hello_world.py:34-45](examples/getting_started/hello_world.py#L34-L45), [google/antigravity/connections/local/local_connection.py:1552-1575](google/antigravity/connections/local/local_connection.py#L1552-L1575)

## Requirements & Dependencies

The SDK requires **Python 3.10 or higher**. Core dependencies include `pydantic`, `google-genai`, `mcp`, and `websockets`.

Sources: [pyproject.toml:23-34](pyproject.toml#L23-L34)

Summary: Successful setup of the Google Antigravity SDK depends on installing from PyPI to obtain the mandatory `localharness` binary and providing a valid `GEMINI_API_KEY`. Verification can be performed using the [hello_world.py](examples/getting_started/hello_world.py) script.
Sources: [README.md:15-19](README.md#L15-L19)

---

## 03. The Safety Model: Policies vs Capabilities

> Hidden constraints: why the SDK raises ValueError for write tools without policies, and how to optimize tokens by disabling tools vs denying them.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/03-the-safety-model-policies-vs-capabilities.md
- Generated: 2026-05-19T19:50:01.706Z

### Source Files

- `google/antigravity/hooks/policy.py`
- `google/antigravity/agent.py`
- `google/antigravity/types.py`
- `examples/getting_started/policies.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/hooks/policy.py](google/antigravity/hooks/policy.py)
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [google/antigravity/types.py](google/antigravity/types.py)
- [examples/getting_started/policies.py](examples/getting_started/policies.py)
</details>

# The Safety Model: Policies vs Capabilities

The Google Antigravity SDK implements a multi-layered safety model designed to prevent autonomous agents from performing unintended or dangerous actions. This model separates tool **visibility** (Capabilities) from tool **execution** (Policies), allowing developers to fine-tune both the agent's efficiency and its security posture.

By default, the SDK adopts a "safe-by-default" stance: any agent configured with tools capable of modifying the environment (write tools) or external services (MCP servers) must have an explicit safety policy defined. Failure to provide one results in a `ValueError` during initialization, forcing developers to make an intentional decision about the agent's autonomy.

## Safety by Default: The Policy Requirement

When an agent session starts, the SDK inspects the list of enabled tools. If any "write tools" (non-read-only tools) or Model Context Protocol (MCP) servers are active, the SDK requires at least one policy or a custom tool-decision hook to be registered.

Sources: [google/antigravity/agent.py:123-133]()

The check specifically identifies "write tools" by subtracting the `read_only()` toolset from the active tools list. Read-only tools include safe operations like `list_directory`, `search_directory`, and `view_file`.

```python
# google/antigravity/agent.py:119-125
has_write_tools = bool(active_tools - read_only_tools)
has_mcp_servers = bool(self._config.mcp_servers)
has_tool_decide_hook = bool(self._hook_runner.pre_tool_call_decide_hooks)

if (has_write_tools or has_mcp_servers) and not active_policies and not has_tool_decide_hook:
    raise ValueError("Write tools or MCP servers are enabled without a safety policy.")
```

## Capabilities vs. Policies: A Token Strategy

The SDK distinguishes between **Disabling** a tool and **Denying** a tool call. Choosing the right mechanism is critical for both security and token optimization.

### Disabling Tools (Capabilities)
Configuring `CapabilitiesConfig.disabled_tools` (or `enabled_tools`) removes the tool from the model's context entirely. The model never sees the tool's definition, meaning it cannot even consider calling it.
- **When to use**: When a tool is irrelevant to the agent's task.
- **Benefit**: Saves tokens by keeping the system prompt lean and preventing the model from wasting cycles on irrelevant capabilities.

Sources: [google/antigravity/types.py:311-343](), [google/antigravity/hooks/policy.py:40-49]()

### Denying Tool Calls (Policies)
A policy-denied tool remains **visible** in the model's tool list. If the model attempts to call it, the SDK rejects the call and returns a denial message (optionally with an explanation).
- **When to use**: For conditional or context-dependent restrictions (e.g., denying `run_command` only for `rm` operations).
- **Benefit**: Allows the model to understand the boundary and "learn" why an action was refused, potentially choosing a safer alternative. Note that retries cost additional tokens.

Sources: [google/antigravity/hooks/policy.py:33-46]()

## Policy Precedence

Policies are evaluated using a priority-based model where specificity and safety determine precedence. This prevents general "allow-all" rules from accidentally overriding targeted safety guards.

| Priority | Bucket | Example Builder |
| :--- | :--- | :--- |
| 0 | Specific Deny | `policy.deny("run_command", when=...)` |
| 1 | Specific Ask | `policy.ask_user("edit_file", handler=...)` |
| 2 | Specific Allow | `policy.allow("list_directory")` |
| 3 | Wildcard Deny | `policy.deny("*")` |
| 4 | Wildcard Ask | `policy.ask_user("*", ...)` |
| 5 | Wildcard Allow | `policy.allow_all()` |

Sources: [google/antigravity/hooks/policy.py:329-347](), [google/antigravity/hooks/policy.py:21-23]()

## Runtime Architecture

The following diagram illustrates how tools flow through the Capabilities and Policy layers:

```mermaid
graph TD
    A[Agent Config] --> B{CapabilitiesConfig}
    B -- "Disabled" --> C[Hidden from Model]
    B -- "Enabled" --> D[Tool in Model Context]
    D --> E[Model generates Tool Call]
    E --> F{Policy Hook Layer}
    F -- "APPROVE" --> G[Execute Tool]
    F -- "DENY" --> H[Denial Message to Model]
    F -- "ASK_USER" --> I[Prompt User Approval]
    I -- "Approve" --> G
    I -- "Deny" --> H
```

## Summary

The safety model ensures that agents remain bounded by developer intent. By combining `CapabilitiesConfig` for broad architectural constraints and `policy` hooks for runtime enforcement, developers can build agents that are both efficient and secure. Always prefer `disabled_tools` to optimize tokens for tools the agent will never need.

Sources: [google/antigravity/hooks/policy.py:33-49]()

---

## 04. Understanding the Agentic Loop

> The three-layer architecture: Layer 1 (Simplified Agent), Layer 2 (Stateful Session), and Layer 3 (Transport Adapters).

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/04-understanding-the-agentic-loop.md
- Generated: 2026-05-19T20:22:04.698Z

### Source Files

- `README.md`
- `google/antigravity/agent.py`
- `google/antigravity/conversation/conversation.py`
- `google/antigravity/connections/connection.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [google/antigravity/conversation/conversation.py](google/antigravity/conversation/conversation.py)
- [google/antigravity/connections/connection.py](google/antigravity/connections/connection.py)
- [google/antigravity/connections/local/local_connection.py](google/antigravity/connections/local/local_connection.py)
- [google/antigravity/conversation/README.md](google/antigravity/conversation/README.md)
- [README.md](README.md)
</details>

# Understanding the Agentic Loop

The Google Antigravity SDK is built on a modular, three-layer architecture designed to decouple agent logic from session state and transport mechanics. This separation of concerns ensures that the "Agentic Loop"—the iterative cycle of reasoning, tool execution, and state management—remains robust, testable, and portable across different backends.

By organizing the SDK into three distinct layers, developers can choose the level of abstraction that fits their needs, from a "batteries-included" high-level Agent to low-level transport control. This architecture also facilitates the implementation of advanced features like session resumption, history compaction, and platform-agnostic safety policies.

## Architectural Blueprint

The architecture follows a nested dependency model where higher layers wrap lower ones to add specialized functionality.

```mermaid
graph TD
    subgraph Layer1["Layer 1: Agent (Lifecycle & Config)"]
        A[Agent Class] --> B[Hook Runner]
        A --> C[Tool Runner]
        A --> D[Trigger Runner]
        A --> L2
    end

    subgraph L2["Layer 2: Conversation (Stateful Session)"]
        E[Conversation Class] --> F[History Management]
        E --> G[Turn Tracking]
        E --> H[Usage Tracking]
        E --> L3
    end

    subgraph L3["Layer 3: Connection (Transport Adapters)"]
        I[Connection Interface] --> J[LocalConnection]
        I --> K[Wire Protocol]
    end

    style Layer1 fill:#f9f,stroke:#333,stroke-width:2px
    style L2 fill:#bbf,stroke:#333,stroke-width:2px
    style L3 fill:#dfd,stroke:#333,stroke-width:2px
```

Sources: [google/antigravity/conversation/README.md:16-35](), [google/antigravity/agent.py:15-31]()

## Layer 1: Simplified Agent (Lifecycle & Config)

The **Agent** layer is the primary entry point for most developers. It manages the declarative setup of the agent, including its tools, hooks, and safety policies. It is responsible for the overall lifecycle of a session, ensuring that all components (transports, tool runners, and triggers) are correctly initialized and torn down.

### Key Responsibilities
- **Lifecycle Management**: Uses async context managers (`__aenter__`/`__aexit__`) to manage resource initialization and cleanup.
- **Declarative Configuration**: Consolidates tools, policies, and MCP servers into a single `AgentConfig`.
- **Convenience API**: Exposes the `chat()` method, which abstracts away the complexity of the underlying loops.

```python
# google/antigravity/agent.py:195-204
async def chat(self, prompt: types.Content) -> types.ChatResponse:
  """Sends a prompt and returns the final response."""
  return await self.conversation.chat(prompt)
```

Sources: [google/antigravity/agent.py:36-183](), [README.md:32-36]()

## Layer 2: Stateful Session (Conversation)

The **Conversation** layer manages the "memory" of the agentic loop. It is decoupled from the transport layer, allowing it to focus purely on session state, token usage, and history management.

### Key Responsibilities
- **History Accumulation**: Automatically records every step (text, tool calls, thinking) into a persistent history.
- **Turn & Compaction Tracking**: Tracks where individual turns start and where history has been compacted to optimize context windows.
- **Usage Monitoring**: Aggregates token counts across multiple turns for cost and performance analysis.

### Layer Comparison

| Concern | Owner | Implementation Detail |
|:---|:---|:---|
| **Config & Policies** | Layer 1 (Agent) | Declarative setup; defines *capabilities*. |
| **History & Turns** | Layer 2 (Conversation) | Stateful session; tracks *interactions*. |
| **Wire Protocol** | Layer 3 (Connection) | Transport plumbing; moves *bytes*. |

Sources: [google/antigravity/conversation/conversation.py:59-87](), [google/antigravity/conversation/README.md:37-43]()

## Layer 3: Transport Adapters (Connection)

The **Connection** layer is the lowest level of the SDK, providing a platform-agnostic interface for interacting with agent backends. It abstracts the wire protocol and binary execution details.

### Key Responsibilities
- **Wire Protocol**: Handles the serialization and deserialization of messages (e.g., Protobuf over WebSockets for local execution).
- **Process Management**: In the case of `LocalConnection`, it manages the lifecycle of the underlying `localharness` binary.
- **Backend Abstraction**: Provides a unified `Connection` interface that Layer 2 APIs depend on, ensuring portability between local and hosted backends.

```python
# google/antigravity/connections/connection.py:15-23
"""Base interfaces for connections in the Google Antigravity SDK.
A Connection is the SDK's public interface for interacting with an agent
backend... Layer 2 APIs depend ONLY on this interface."""
```

Sources: [google/antigravity/connections/connection.py:15-38](), [google/antigravity/connections/local/local_connection.py:785-830]()

## Summary

The three-layer architecture of the Google Antigravity SDK ensures that concerns are strictly isolated: the **Agent** handles "who" the agent is (config), the **Conversation** handles "what" happened (state), and the **Connection** handles "how" they talk (transport). This design allows the SDK to scale from simple scripts to complex, multi-modal applications while maintaining a consistent and reliable agentic loop.

Sources: [google/antigravity/conversation/README.md:12-35]()

---

## 05. Agent Lifecycle & Context

> How the Agent class manages resource cleanup via AsyncExitStack and provides high-level streaming interfaces for thoughts and tool calls.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/05-agent-lifecycle-context.md
- Generated: 2026-05-19T19:50:09.379Z

### Source Files

- `google/antigravity/agent.py`
- `google/antigravity/types.py`
- `examples/getting_started/streaming.py`
- `google/antigravity/hooks/hook_runner.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [google/antigravity/conversation/conversation.py](google/antigravity/conversation/conversation.py)
- [google/antigravity/types.py](google/antigravity/types.py)
- [examples/getting_started/streaming.py](examples/getting_started/streaming.py)
- [google/antigravity/hooks/hook_runner.py](google/antigravity/hooks/hook_runner.py)
- [google/antigravity/hooks/hooks.py](google/antigravity/hooks/hooks.py)
</details>

# Agent Lifecycle & Context

The `Agent` class serves as the primary entry point for the Antigravity SDK, orchestrating the complex interactions between model connections, conversation history, tool execution, and lifecycle management. It provides a high-level, asynchronous interface that simplifies session handling while exposing powerful streaming capabilities for real-time thoughts and content.

## Lifecycle Management with AsyncExitStack

The SDK utilizes `contextlib.AsyncExitStack` to manage the cleanup of various asynchronous resources. This ensures that even in the event of errors, resources like MCP server connections, conversation sessions, and trigger runners are gracefully terminated.

### Session Initialization and Cleanup
An `Agent` session is started using the `async with` statement, which triggers the `__aenter__` and `__aexit__` methods. During startup, the agent:
1.  **Initializes Runners**: Sets up `HookRunner`, `ToolRunner`, and optionally `TriggerRunner`.
2.  **Connects MCP Servers**: Establishes connections to any configured Model Context Protocol (MCP) servers and adds their tools to the `ToolRunner`.
3.  **Creates Conversation**: Establishes the stateful Layer 2 session.
4.  **Automatic Cleanup**: Registers callback such as `mcp_bridge.stop` and enters sub-contexts like `Conversation.create` within the `_exit_stack`.

```python
# google/antigravity/agent.py:92-182
async def __aenter__(self) -> "Agent":
  try:
    # ... initialization logic ...
    self._mcp_bridge = bridge.McpBridge()
    self._exit_stack.push_async_callback(self._mcp_bridge.stop)
    # ...
    self._conversation = await self._exit_stack.enter_async_context(
        conversation.Conversation.create(self._strategy)
    )
    return self
  except Exception:
    await self._exit_stack.aclose()
    raise
```
Sources: [google/antigravity/agent.py:92-182](), [google/antigravity/agent.py:184-193]()

## Streaming Interfaces

The `Agent.chat()` method returns a `ChatResponse` object, which is a sophisticated wrapper around an async generator of `StreamChunk` objects. This allows for real-time consumption of different types of output.

### The ChatResponse Model
`ChatResponse` provides multiple independent cursors over a shared internal buffer. This means you can iterate over thoughts, text deltas, and tool calls simultaneously or sequentially without losing data.

*   **`async for token in response`**: Directly yields text token strings (the primary response).
*   **`.thoughts`**: An async iterator yielding internal model reasoning deltas.
*   **`.tool_calls`**: An async iterator yielding `ToolCall` objects as they are dispatched.
*   **`.chunks`**: The raw stream of all `StreamChunk` derivatives (`Thought`, `Text`, `ToolCall`).

```python
# examples/getting_started/streaming.py:43-55
response = await my_agent.chat(prompt)

print("Agent (Streaming thoughts):")
async for thought in response.thoughts:
  print(thought, end="", flush=True)

print("Agent (Streaming final answer):")
async for token in response:
  print(token, end="", flush=True)
```
Sources: [google/antigravity/types.py:763-860](), [google/antigravity/conversation/conversation.py:160-226](), [examples/getting_started/streaming.py:43-55]()

## Context Hierarchy

The SDK manages state across different scopes using a hierarchical context system, primarily used within the Hook system but also reflected in how the Agent manages its internal state.

| Context Type | Scope | Persistence |
| :--- | :--- | :--- |
| `SessionContext` | Entire `Agent` session | Lifetime of the `Agent` instance. |
| `TurnContext` | Single `chat()` turn | Reset at the start of each user message. |
| `OperationContext` | Specific tool call or hook | Lifetime of the individual operation. |

These contexts allow hooks and internal logic to share state (via `.get()` and `.set()`) across different layers of the execution loop while maintaining clear boundaries.

Sources: [google/antigravity/hooks/hooks.py:34-86](), [google/antigravity/hooks/hook_runner.py:67]()

## State and History
The underlying `Conversation` object tracks the full transcript of steps. The `Agent` provides properties to access this state after the session has started:
*   **`conversation_id`**: The identifier used to resume sessions.
*   **`history`**: The full list of `Step` objects (model turns, tool results, compactions).
*   **`usage_metadata`**: Accumulated token counts for the session.

Sources: [google/antigravity/agent.py:211-238](), [google/antigravity/conversation/conversation.py:231-262]()

The `Agent` class effectively bridges high-level user intent with low-level resource and stream management, ensuring a robust and responsive developer experience.
Sources: [google/antigravity/agent.py:36-62]()

---

## 06. Stateful Conversations & History

> Deep dive into Conversation state, step history accumulation, and the low-level send/receive_steps API for granular interaction control.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/06-stateful-conversations-history.md
- Generated: 2026-05-19T20:36:27.695Z

### Source Files

- `google/antigravity/conversation/conversation.py`
- `google/antigravity/conversation/README.md`
- `examples/deep_dives/async_chat.py`
- `google/antigravity/types.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/conversation/conversation.py](google/antigravity/conversation/conversation.py)
- [google/antigravity/conversation/README.md](google/antigravity/conversation/README.md)
- [google/antigravity/conversation/conversation_test.py](google/antigravity/conversation/conversation_test.py)
- [google/antigravity/types.py](google/antigravity/types.py)
- [examples/deep_dives/host_tool_hooks.py](examples/deep_dives/host_tool_hooks.py)
</details>

# Stateful Conversations & History

The `Conversation` class serves as the **Layer 2 Session API** within the Google Antigravity SDK, bridging the gap between high-level Agent logic and low-level transport protocols. While the `Agent` (Layer 1) manages configuration, tools, and hooks, the `Conversation` owns the live session state, including the accumulation of step history, turn tracking, and context window compaction indices.

By wrapping a `Connection` (Layer 3), a `Conversation` provides a stateful container that ensures continuity across multiple model interactions. It maintains a chronologically ordered transcript of `Step` objects, allowing developers to inspect the agent's trajectory, monitor token usage in real-time, and implement advanced memory management strategies like history trimming.

Sources: [google/antigravity/conversation/conversation.py:15-24](), [google/antigravity/conversation/README.md:11-35]()

## Session State & History Accumulation

At its core, a `Conversation` is a collector of `Step` objects received from the underlying connection. Each step represents a discrete event in the agent's reasoning or execution path, such as generating text, calling a tool, or finishing a turn.

### The History Transcript
The full transcript is exposed via the `history` property, which returns a copy of the internal step list. This list is uncompacted by default, preserving every model thought and environment interaction for debugging or logging purposes.

```python
# google/antigravity/conversation/conversation.py:231-238
@property
def history(self) -> list[types.Step]:
  """Returns all steps received across all turns."""
  return list(self._steps)
```

### Memory Management
To prevent unbounded memory growth in long-running sessions, the `Conversation` supports a `max_history_size` parameter. When the step count exceeds this limit, the oldest steps are discarded, and internal turn/compaction indices are automatically adjusted to reflect the new window.

| Property | Description | Source |
| :--- | :--- | :--- |
| `max_history_size` | Maximum steps to retain (default: 10,000). | `conversation.py:34` |
| `turn_count` | Number of user turns (send calls) in the session. | `conversation.py:249` |
| `clear_history()` | Resets the history list and all tracking indices. | `conversation.py:264` |

Sources: [google/antigravity/conversation/conversation.py:59-86](), [google/antigravity/conversation/conversation_test.py:718-777]()

## Turn & Compaction Tracking

Unlike a raw connection, a `Conversation` understands the concept of a "turn" and a "compacted context." It maintains specific indices to help the SDK and developers navigate the history.

*   **Turn Start Indices**: Every time `send()` is called, the current history length is recorded. This allows the SDK to group steps by user interaction.
*   **Compaction Indices**: When the backend model compacts its context window (often triggered by token limits), a `StepType.COMPACTION` step is yielded. The `Conversation` records the index of these steps, indicating that steps preceding the index may no longer be in the model's active memory.

```mermaid
stateDiagram-v2
    direction LR
    state "Turn 1" as T1
    state "Turn 2" as T2
    state "History List" as HL {
        s0: User Prompt
        s1: Model Thought
        s2: Model Response
        s3: Compaction Step
        s4: User Prompt 2
    }
    T1 --> s0
    T2 --> s4
    note right of s3: Recorded in compaction_indices
```

Sources: [google/antigravity/conversation/conversation.py:135-157](), [google/antigravity/conversation/conversation.py:254-263]()

## Low-Level Interaction: send() and receive_steps()

While `chat()` is the preferred method for most users, power users can utilize the granular `send()` and `receive_steps()` API for precise control over the interaction loop. This is particularly useful for building custom UIs or implementing complex agent-to-agent communication.

### Granular Step Iteration
The `receive_steps()` method is an async iterator that yields `Step` objects as they arrive. It blocks until the connection signals it is idle, marking the end of the turn.

```python
# Low-level interaction pattern
await conversation.send("Perform a complex task.")
async for step in conversation.receive_steps():
    if step.type == types.StepType.TOOL_CALL:
        print(f"Agent is calling: {step.tool_calls[0].name}")
    elif step.is_complete_response:
        print(f"Final: {step.content}")
```

### Automatic Draining
A key safety feature of the `send()` method is **automatic draining**. If a developer calls `send()` while a previous turn is still yielding steps, the `Conversation` will automatically drain and record the remaining steps of the active turn into history before initiating the new message.

Sources: [google/antigravity/conversation/conversation.py:109-158](), [examples/deep_dives/host_tool_hooks.py:193-210]()

## Token Usage Monitoring

The `Conversation` aggregates `UsageMetadata` from every step that reports token counts. This provides a unified view of the session's resource consumption.

*   **`total_usage`**: Cumulative token counts (prompt, candidates, thoughts) across the entire session.
*   **`last_turn_usage`**: Token counts specific to the most recent completed turn.

The usage metadata includes `prompt_token_count`, `candidates_token_count`, and `thoughts_token_count` (for reasoning models), allowing for detailed cost and performance analysis.

Sources: [google/antigravity/conversation/conversation.py:315-335](), [google/antigravity/types.py:472-500]()

## Summary

The `Conversation` class provides the stateful backbone for the Antigravity SDK, transforming a stateless transport into a coherent session. By managing step accumulation, turn boundaries, and memory limits, it enables sophisticated agentic workflows while shielding developers from the complexities of wire-protocol management.

Sources: [google/antigravity/conversation/conversation.py:15-24]()

---

## 07. Tooling & MCP Integration

> Extending agent capabilities via native Python functions and the Model Context Protocol (MCP) bridge for stdio and SSE servers.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/07-tooling-mcp-integration.md
- Generated: 2026-05-19T20:39:28.880Z

### Source Files

- `google/antigravity/tools/tool_runner.py`
- `google/antigravity/mcp/bridge.py`
- `google/antigravity/mcp/README.md`
- `examples/getting_started/custom_tools.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/tools/tool_runner.py](google/antigravity/tools/tool_runner.py)
- [google/antigravity/mcp/bridge.py](google/antigravity/mcp/bridge.py)
- [google/antigravity/mcp/README.md](google/antigravity/mcp/README.md)
- [examples/getting_started/custom_tools.py](examples/getting_started/custom_tools.py)
- [google/antigravity/tools/tool_context.py](google/antigravity/tools/tool_context.py)
</details>

# Tooling & MCP Integration

The Antigravity SDK provides a robust and flexible system for extending agent capabilities through tools. Tools allow agents to perform actions, retrieve data, and interact with external systems. The SDK supports two primary methods for tool integration: native Python functions and the Model Context Protocol (MCP).

By using the `ToolRunner`, the SDK manages the registration, schema generation, and execution of tools, including automatic dependency injection for stateful operations. The `McpBridge` further extends this by allowing the agent to consume tools hosted on external MCP servers over various transport protocols.

## Tool Runner

The `ToolRunner` is the central registry and executor for all Python-based tools within the SDK. It maintains a mapping of tool names to their corresponding callables and handles the complexities of invoking them, whether they are synchronous or asynchronous.

Sources: [google/antigravity/tools/tool_runner.py:123-129]()

### Key Features
- **Sync and Async Support**: Tools can be defined as standard Python functions or `async` coroutines. Synchronous tools are automatically executed in a separate thread to avoid blocking the main event loop.
- **Concurrent Execution**: The `process_tool_calls` method allows for the parallel execution of multiple tool calls using `asyncio.gather`, improving performance during complex multi-tool reasoning steps.
- **Signature Proxying**: To ensure models only see relevant parameters, the `ToolRunner` uses `get_public_callable` to generate a proxy signature that hides internal-only parameters like `ToolContext`.

Sources: [google/antigravity/tools/tool_runner.py:221-230](), [google/antigravity/tools/tool_runner.py:276-294]()

## Native Python Tools

Native tools are Python callables registered directly with the agent. They are ideal for tight integration with local logic, database access, or existing Python libraries.

### Tool Context & State Management
Stateful tools can opt-in to receiving a `ToolContext` by declaring it as a typed parameter. The `ToolRunner` automatically injects this context at execution time.

Sources: [google/antigravity/tools/tool_context.py:42-51]()

The `ToolContext` provides:
- **State Persistence**: `get_state(key)` and `set_state(key, value)` allow tools to maintain information across multiple conversational turns.
- **Asynchronous Messaging**: The `send(message)` method allows tools to inject notifications or follow-up messages back into the conversation asynchronously.
- **Identity**: Access to the `conversation_id` for tracking and logging.

Sources: [google/antigravity/tools/tool_context.py:66-105]()

### Example: Stateful Fruit Tracker
```python
from google.antigravity import ToolContext

def record_fruit(sku: str, count: int, ctx: ToolContext) -> str:
    """Records the count of fruits by SKU."""
    current_counts = ctx.get_state("fruit_counts", {})
    current_counts[sku] = current_counts.get(sku, 0) + count
    ctx.set_state("fruit_counts", current_counts)
    
    return f"Recorded {count} units for {sku}. Total is {current_counts[sku]}."
```
Sources: [examples/getting_started/custom_tools.py:67-87]()

## MCP Integration

The Model Context Protocol (MCP) bridge allows the Antigravity SDK to connect to external tool providers. This enables the use of a wide ecosystem of pre-built tools without writing custom Python wrappers for every service.

Sources: [google/antigravity/mcp/README.md:1-15]()

### McpBridge
The `McpBridge` class manages the lifecycle of MCP client sessions. It discovers tools from connected servers and converts them into `ToolWithSchema` objects compatible with the `ToolRunner`.

Sources: [google/antigravity/mcp/bridge.py:59-69]()

### Supported Transports
| Transport Type | Description |
| :--- | :--- |
| **stdio** | Connects to local MCP servers running as subprocesses (e.g., via `npx`). |
| **SSE** | Connects to remote MCP servers using Server-Sent Events over HTTP. |
| **Streamable HTTP** | Advanced remote connection with fine-grained timeout and lifecycle management. |

Sources: [google/antigravity/mcp/bridge.py:80-91](), [google/antigravity/mcp/bridge.py:115-139]()

### Integration Architecture
The following diagram illustrates how the `McpBridge` interacts with the SDK's core tooling system:

```mermaid
graph TD
    Agent[Agent] --> TR[ToolRunner]
    TR --> NT[Native Python Tools]
    TR --> Bridge[McpBridge]
    Bridge --> Stdio[stdio Subprocess]
    Bridge --> SSE[SSE / HTTP Server]
    
    subgraph "External MCP Servers"
        Stdio
        SSE
    end
```

## Summary

The Antigravity SDK's tooling system provides a unified interface for both local Python execution and remote MCP-based capability extension. By centralizing tool management in the `ToolRunner` and providing a dedicated `McpBridge`, the SDK ensures that agents can seamlessly leverage a diverse set of tools while maintaining clean separation between tool implementation and agent logic.

Sources: [google/antigravity/tools/tool_runner.py:15-29]()

---

## 08. Hooks & Policy Precedence

> The priority-based policy model (Specific > Wildcard) and how to implement custom middleware using pre/post-step hooks.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/08-hooks-policy-precedence.md
- Generated: 2026-05-19T19:50:08.089Z

### Source Files

- `google/antigravity/hooks/hooks.py`
- `google/antigravity/hooks/hook_runner.py`
- `google/antigravity/hooks/policy.py`
- `examples/getting_started/hooks.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/hooks/hooks.py](google/antigravity/hooks/hooks.py)
- [google/antigravity/hooks/hook_runner.py](google/antigravity/hooks/hook_runner.py)
- [google/antigravity/hooks/policy.py](google/antigravity/hooks/policy.py)
- [examples/getting_started/hooks.py](examples/getting_started/hooks.py)
- [google/antigravity/types.py](google/antigravity/types.py)
</details>

# Hooks & Policy Precedence

The Google Antigravity SDK provides a sophisticated lifecycle management system through **Hooks** and a declarative **Policy** engine. Hooks allow developers to inject custom logic for observability, enforcement, and data transformation at various stages of an agent's execution. The Policy system builds on these hooks to provide a granular, priority-based mechanism for controlling tool usage.

Understanding the precedence model is critical for designing safe, autonomous agents that can navigate complex tool environments while maintaining strict security boundaries.

## Policy Precedence Model

Antigravity employs a "Specificity-First" priority model. Policies are evaluated in discrete buckets, where the most specific rules always override general wildcard rules. Within a specificity level, safety is prioritized (Deny > Ask > Allow).

### Priority Buckets
When multiple policies are registered, they are sorted into six priority levels (0-5), with lower numbers taking absolute precedence. Evaluation short-circuits at the first matching policy in the highest available bucket.

| Priority | Level Name | Target | Decision |
| :--- | :--- | :--- | :--- |
| **0** | Specific Deny | Named Tool | `DENY` |
| **1** | Specific Ask | Named Tool | `ASK_USER` |
| **2** | Specific Allow | Named Tool | `APPROVE` |
| **3** | Wildcard Deny | `*` | `DENY` |
| **4** | Wildcard Ask | `*` | `ASK_USER` |
| **5** | Wildcard Allow | `*` | `APPROVE` |

> [!IMPORTANT]
> Within a single bucket, the **first registered match wins**. This allows for sequential evaluation of complex predicates for the same tool.
> Sources: [google/antigravity/hooks/policy.py:326-347]()

### Predicates and Context
Policies can be constrained by `when` predicates, which receive the tool call arguments and can perform synchronous or asynchronous checks. This enables context-aware security, such as blocking `run_command` only when it contains dangerous strings like `rm -rf`.

```python
# Specific Deny (Level 0) takes priority over Wildcard Allow (Level 5)
policies = [
    policy.deny("run_command", when=lambda args: "sudo" in args.get("CommandLine", "")),
    policy.allow_all() 
]
```
Sources: [google/antigravity/hooks/policy.py:51-65]()

## Hook Architecture

The SDK distinguishes between three fundamental hook types, each serving a different architectural role in the Blueprint of an agent session.

1.  **InspectHook (Observability)**: Read-only and non-blocking. Used for logging, metrics, and UI updates (e.g., `on_session_start`, `post_turn`).
2.  **DecideHook (Enforcement)**: Read-only but **blocking**. Returns a `HookResult` that can stop execution (e.g., `pre_turn`, `pre_tool_call_decide`).
3.  **TransformHook (Modification)**: Modifying and blocking. Allows the SDK to recover from errors or handle interactive flows (e.g., `on_tool_error`, `on_interaction`).

### Hook Lifecycle
Hooks are managed by the `HookRunner`, which maintains isolated registries for each event type and handles context propagation through `HookContext` hierarchies.

```mermaid
sequenceDiagram
    participant A as Agent
    participant HR as HookRunner
    participant H as Hooks/Policies
    participant T as Tool/Model

    A->>HR: dispatch_pre_tool_call(tool_call)
    HR->>H: Evaluate Policies (Levels 0-5)
    H-->>HR: HookResult(allow=True/False)
    
    alt Denied
        HR-->>A: Denial Message
    else Allowed
        HR->>T: Execute Tool
        T-->>HR: ToolResult
        HR->>H: dispatch_post_tool_call(result)
        HR-->>A: Final Result
    end
```
Sources: [google/antigravity/hooks/hook_runner.py:181-204](), [google/antigravity/hooks/hooks.py:95-143]()

## Implementing Custom Middleware

Developers can implement custom middleware by decorating async functions with the appropriate hook decorator. This is a common Page Shape for adding cross-cutting concerns like authentication or sensitive data masking.

### Hook Contexts
Hooks receive a `context` object (e.g., `TurnContext`, `OperationContext`) which allows sharing state between hooks in the same lifecycle scope. Contexts follow a parent-child inheritance model.

```python
@hooks.pre_turn
async def audit_log_prompt(context: hooks.TurnContext, data: str) -> types.HookResult:
    # Access session-level state
    user_id = context.get("user_id")
    print(f"User {user_id} prompted: {data}")
    return types.HookResult(allow=True)
```
Sources: [google/antigravity/hooks/hooks.py:34-87]()

## Policy vs. CapabilitiesConfig

A common design decision is choosing between the Policy system and `CapabilitiesConfig`.

*   **CapabilitiesConfig**: Controls tool **visibility**. If a tool is disabled here, the model never sees it in its tool list, saving tokens and preventing hallucinations.
*   **Policy (Hooks)**: Controls tool **execution**. The model sees the tool but the call is rejected at runtime. Use this for conditional restrictions where the model needs to understand *why* a specific action was refused.

Sources: [google/antigravity/types.py:311-349](), [google/antigravity/hooks/policy.py:33-49]()

In summary, the Antigravity SDK's priority-based policy model (Specific > Wildcard) ensures that security rules are applied predictably, while the extensible hook system provides the necessary flexibility for implementing complex agent middleware and observability.
Sources: [google/antigravity/hooks/policy.py:17-25]()

---

## 09. Interactive & Human-in-the-Loop

> Implementing interactive flows using run_interactive_loop and ask_user policy handlers for manual tool call approval.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/09-interactive-human-in-the-loop.md
- Generated: 2026-05-19T19:50:04.594Z

### Source Files

- `google/antigravity/utils/interactive.py`
- `examples/getting_started/human_in_the_loop.py`
- `examples/deep_dives/interactive_cli.py`
- `google/antigravity/utils/interactive_test.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/utils/interactive.py](google/antigravity/utils/interactive.py)
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [examples/getting_started/human_in_the_loop.py](examples/getting_started/human_in_the_loop.py)
- [examples/deep_dives/interactive_cli.py](examples/deep_dives/interactive_cli.py)
- [google/antigravity/utils/interactive_test.py](google/antigravity/utils/interactive_test.py)
</details>

# Interactive & Human-in-the-Loop

The Google Antigravity SDK provides robust support for interactive workflows, allowing developers to keep a "human-in-the-loop" (HITL) for critical operations. This is achieved through a combination of policy handlers for tool approval and specialized hooks for direct agent-to-user communication. These utilities are primarily housed in the `google.antigravity.utils.interactive` module and are designed to facilitate local development, debugging, and safe execution of autonomous agents.

Interactivity in Antigravity typically takes two forms: **Tool Call Approval**, where a user must explicitly permit the agent to execute a specific tool (like running a shell command), and **Active Questioning**, where the agent pauses its execution to request clarification or missing information from the user via the `ask_question` tool.

## Core Interactive Utilities

The SDK provides several pre-built components to enable interactive CLI sessions without requiring custom logic for stdin/stdout handling.

### Interactive Loop REPL
The `run_interactive_loop` function is the primary entry point for creating a terminal-based REPL. It manages the conversation lifecycle, handles user input via an asynchronous wrapper for `input()`, and automatically wires up interactive hooks.

Sources: [google/antigravity/utils/interactive.py:244-292]()

### Tool Confirmation Handlers
For tool-level safety, the SDK offers two primary ways to prompt the user:
1.  **`ask_user_handler`**: A convenient handler designed for the policy system. When a tool call matches a policy configured with `policy.ask_user`, this handler prints the tool arguments and waits for a `y/n` response.
2.  **`ToolConfirmationHook`**: A lower-level `PreToolCallDecideHook` that can be registered directly with an agent to intercept and confirm tool calls.

Sources: [google/antigravity/utils/interactive.py:80-129]()

### Active Questioning with `AskQuestionHook`
The `AskQuestionHook` enables the `ask_question` capability. When an agent invokes this tool, the hook intercepts the request, presents the questions (and any multiple-choice options) to the user, and returns the user's answers back to the agent as tool output.

Sources: [google/antigravity/utils/interactive.py:132-190]()

## Implementing Human-in-the-Loop

Implementing HITL involves configuring the agent's policies and hooks during initialization. The following table summarizes the typical configuration options:

| Component | Usage | Description |
| :--- | :--- | :--- |
| `policy.ask_user` | `policies=[policy.ask_user("*", handler=ask_user_handler)]` | Prompts for confirmation on every tool call. |
| `AskQuestionHook` | `hooks=[AskQuestionHook()]` | Enables the agent to ask the user questions. |
| `run_interactive_loop` | `await run_interactive_loop(agent)` | Starts a full CLI REPL with automatic policy "upgrades". |

### Policy-Based Tool Approval
By default, sensitive tools like `run_command` may be denied in certain configurations. `run_interactive_loop` automatically "upgrades" these denials to `ASK_USER` prompts, ensuring a smooth developer experience without compromising the underlying safety model.

```python
# From examples/deep_dives/interactive_cli.py:130-142
config = LocalAgentConfig(
    tools=[read_file_upside_down],
    mcp_servers=[mcp_server],
    # Wire all tool calls to the interactive CLI handler
    policies=[policy.ask_user("*", handler=interactive.ask_user_handler)],
    hooks=[interactive.AskQuestionHook()],
)
```

### Interactive Flow Sequence
The following diagram illustrates the sequence of an interactive tool call approval using the policy system:

```mermaid
sequenceDiagram
    participant User
    participant Agent
    participant PolicyHook as Policy (ask_user_handler)
    participant Tool as Tool Implementation

    Agent->>PolicyHook: Request Tool Call (e.g. run_command)
    Note over PolicyHook: Display arguments to User
    PolicyHook->>User: "Allow execution? (y/n)"
    User-->>PolicyHook: "y"
    PolicyHook-->>Agent: Allow: True
    Agent->>Tool: Execute Tool
    Tool-->>Agent: Tool Result
    Agent->>User: Final Response
```

## Practical Examples

### Basic HITL Questioning
In a simple script, you can register the `AskQuestionHook` to allow the agent to clarify ambiguous prompts.

```python
# From examples/getting_started/human_in_the_loop.py:41-43
async with Agent(config) as my_agent:
    # Register the hook to handle questions from the agent.
    my_agent.register_hook(interactive.AskQuestionHook())
```

### Full Interactive CLI
For a complete debugging environment, use `run_interactive_loop` which handles the REPL logic and automatically configures standard interactive hooks and policy upgrades.

```python
# From google/antigravity/utils/interactive.py:269-270
agent.register_hook(AskQuestionHook())
_upgrade_to_interactive_confirmation(agent)
```

Interactive utilities in Antigravity ensure that autonomous agents remain transparent and controllable, providing a seamless bridge between automated execution and human oversight.

Sources: [google/antigravity/agent.py:123-137]()

---

## 10. Event-Driven Triggers

> Running background tasks that react to external events (e.g., timers via every()) and push asynchronous messages into the agent session.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/10-event-driven-triggers.md
- Generated: 2026-05-19T20:40:42.791Z

### Source Files

- `google/antigravity/triggers/triggers.py`
- `google/antigravity/triggers/trigger_runner.py`
- `examples/getting_started/triggers.py`
- `google/antigravity/triggers/README.md`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/triggers/triggers.py](google/antigravity/triggers/triggers.py)
- [google/antigravity/triggers/trigger_runner.py](google/antigravity/triggers/trigger_runner.py)
- [google/antigravity/triggers/helpers.py](google/antigravity/triggers/helpers.py)
- [google/antigravity/triggers/__init__.py](google/antigravity/triggers/__init__.py)
- [google/antigravity/connections/connection.py](google/antigravity/connections/connection.py)
- [google/antigravity/connections/local/local_connection.py](google/antigravity/connections/local/local_connection.py)
- [examples/getting_started/triggers.py](examples/getting_started/triggers.py)
- [google/antigravity/triggers/README.md](google/antigravity/triggers/README.md)
</details>

# Event-Driven Triggers

Event-Driven Triggers are long-lived, asynchronous background tasks that run alongside an agent session. Unlike **Hooks**, which are tied to specific agent lifecycle dispatch points (like `pre_turn` or `post_tool_call`), Triggers react to external stimuli—such as timers, file changes, or webhooks—and push asynchronous notifications into the active agent session.

These notifications are injected into the conversation history, allowing the agent to react to background events during the next user turn or even mid-session depending on the connection implementation. This architecture is essential for building agents that monitor systems, wait for long-running processes, or respond to real-time data feeds.

## Architecture and Control Flow

Triggers operate independently of the main agent loop. They communicate with the agent via a `TriggerContext` which holds a reference to the active `Connection`.

```mermaid
flowchart TD
    subgraph "Agent Session"
        Runner[TriggerRunner]
        AgentLoop[Agent Main Loop]
    end

    subgraph "External Events"
        Timer((Timer))
        FS[File System]
        WH[Webhook]
    end

    Timer --> T1[Trigger 1]
    FS --> T2[Trigger 2]
    WH --> T3[Trigger 3]

    T1 & T2 & T3 -.-> |async ctx.send| Runner
    Runner --> |automated_trigger| Conn[Connection]
    Conn --> AgentLoop

    style Runner fill:#f9f,stroke:#333,stroke-width:2px
    style AgentLoop fill:#bbf,stroke:#333,stroke-width:2px
```
Sources: [google/antigravity/triggers/README.md:465-475](google/antigravity/triggers/README.md#L465-L475), [google/antigravity/triggers/trigger_runner.py:142-150](google/antigravity/triggers/trigger_runner.py#L142-L150)

## Defining Triggers

A Trigger is any `async` function that accepts a `TriggerContext` as its sole argument. For better validation and discovery, developers should use the `@triggers.trigger` decorator.

### Using the @trigger Decorator
The decorator validates the function signature and marks it for the SDK's internal discovery mechanisms.

```python
from google.antigravity import triggers

@triggers.trigger
async def my_custom_trigger(ctx: triggers.TriggerContext) -> None:
    """A trigger that sends a message every 10 seconds."""
    while True:
        await asyncio.sleep(10)
        await ctx.send("Background check: System status is nominal.")
```
Sources: [google/antigravity/triggers/triggers.py:53-81](google/antigravity/triggers/triggers.py#L53-L81)

### Using Helper Factories
The SDK provides several pre-built factories for common patterns in `google.antigravity.triggers.helpers`.

| Helper | Description | Usage |
| :--- | :--- | :--- |
| `every()` | Runs a callback on a fixed interval. | `every(300, my_callback)` |
| `on_file_change()` | Monitors a path for file system events (requires `watchfiles`). | `on_file_change("./logs", my_callback)` |

Sources: [google/antigravity/triggers/helpers.py:256-340](google/antigravity/triggers/helpers.py#L256-L340)

## Lifecycle Management: TriggerRunner

The `TriggerRunner` is responsible for starting triggers as concurrent `asyncio.Task` instances and ensuring they are cleanly cancelled when the session ends.

- **Isolation**: Each trigger runs in its own task. An unhandled exception in one trigger will be logged but will not affect the agent session or other triggers.
- **Cleanup**: Triggers are expected to handle `asyncio.CancelledError` if they need to perform specific cleanup (e.g., closing sockets or file handles).
- **Session Lifecycle**: Triggers are typically started when the `Agent` session enters an `async with` block and stopped upon exit.

```python
# Internal lifecycle in TriggerRunner
async def start(self) -> None:
    for trigger in self._triggers:
        ctx = TriggerContext(connection=self._connection)
        task = asyncio.create_task(self._run_trigger(trigger, ctx))
        self._tasks.append(task)
```
Sources: [google/antigravity/triggers/trigger_runner.py:130-150](google/antigravity/triggers/trigger_runner.py#L130-L150), [google/antigravity/triggers/trigger_runner.py:209-217](google/antigravity/triggers/trigger_runner.py#L209-L217)

## Pushing Messages to the Session

The `TriggerContext.send(content)` method is the primary way triggers communicate. Under the hood, this calls `connection.send_trigger_notification(content)`.

In the **Local Connection** implementation, these notifications are sent as `automated_trigger` fields within an `InputEvent` proto. This allows the backend to treat the notification as a special system-initiated message that the agent can "see" without requiring a direct user prompt.

```python
# google/antigravity/connections/local/local_connection.py
async def send_trigger_notification(self, content: str) -> None:
    """Sends a trigger message to the agent."""
    event = localharness_pb2.InputEvent(automated_trigger=content)
    await self._ws.send(json_format.MessageToJson(event))
```
Sources: [google/antigravity/triggers/triggers.py:46-50](google/antigravity/triggers/triggers.py#L46-L50), [google/antigravity/connections/local/local_connection.py:1280-1283](google/antigravity/connections/local/local_connection.py#L1280-L1283)

## Example: Monitoring a Pipeline

In this example, a custom trigger simulates a webhook listener for a CI/CD pipeline.

```python
from google.antigravity import Agent, LocalAgentConfig, triggers

@triggers.trigger
async def webhook_listener(ctx: triggers.TriggerContext):
    # Simulate waiting for a webhook event
    await asyncio.sleep(5) 
    await ctx.send("[WEBHOOK ALERT] Pipeline 'Build-123' failed on main.")

config = LocalAgentConfig(
    system_instructions="You monitor CI/CD pipelines.",
    triggers=[webhook_listener]
)

async with Agent(config) as agent:
    # Triggers start here
    await agent.chat("Let me know if any builds fail.")
    # ... later ...
    response = await agent.chat("Any updates?")
    print(await response.text()) # Agent will report the failure found in history
```
Sources: [examples/getting_started/triggers.py:144-174](examples/getting_started/triggers.py#L144-L174)

Triggers provide a robust way to bridge the gap between external real-time events and the agent's conversational session, ensuring the agent remains informed of background changes without blocking user interaction.
Sources: [google/antigravity/triggers/README.md:461-463](google/antigravity/triggers/README.md#L461-L463)

---

## 11. Multimodal & Content Ingestion

> Handling rich media: using from_file for automatic MIME resolution and direct constructor instantiation for in-memory bytes (Image, Video, Document).

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/11-multimodal-content-ingestion.md
- Generated: 2026-05-19T19:50:31.341Z

### Source Files

- `google/antigravity/types.py`
- `examples/getting_started/multimodal.py`
- `examples/deep_dives/multimodal_pipeline.py`
- `examples/resources/sample_doc.txt`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [google/antigravity/types.py](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/google/antigravity/types.py)
- [examples/getting_started/multimodal.py](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/examples/getting_started/multimodal.py)
- [examples/deep_dives/multimodal_pipeline.py](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/examples/deep_dives/multimodal_pipeline.py)
- [examples/resources/sample_doc.txt](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/examples/resources/sample_doc.txt)
</details>

# Multimodal & Content Ingestion

The Google Antigravity SDK provides first-class support for multimodal interactions, allowing agents to process and generate rich media such as images, videos, audio, and documents. By encapsulating raw bytes with semantic metadata, the SDK ensures that models receive content in a format they can accurately interpret without leaking implementation details like file paths or temporary storage locations.

This system is built around a set of immutable media primitives that handle validation and MIME-type resolution automatically. Whether you are loading assets from disk or streaming in-memory bytes, the SDK provides a unified interface for content ingestion that remains portable across different model providers.

## Media Content Primitives

The core of the ingestion system is a hierarchy of media classes derived from a common base. These classes ensure that the data passed to the agent is correctly typed and supported by the underlying model's capabilities.

### Available Media Classes

| Class | Description | Supported Formats (Examples) |
| :--- | :--- | :--- |
| `Image` | Static visual data. | PNG, JPEG, WEBP, BMP |
| `Video` | Motion visual data. | MP4, WEBM, MOV, AVI |
| `Audio` | Sound data. | MP3, WAV, OGG, FLAC |
| `Document` | Structured or unstructured text/data files. | PDF, TXT, JSON, CSV, HTML |

Sources: [google/antigravity/types.py:1007-1053](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/google/antigravity/types.py#L1007-L1053)

### Class Hierarchy

```mermaid
classDiagram
    class _BaseMedia {
        +bytes data
        +str mime_type
        +str description
        +from_file(path, description)
    }
    class Image {
        +validate_mime_type(v)
    }
    class Video {
        +validate_mime_type(v)
    }
    class Audio {
        +validate_mime_type(v)
    }
    class Document {
        +validate_mime_type(v)
    }
    _BaseMedia <|-- Image
    _BaseMedia <|-- Video
    _BaseMedia <|-- Audio
    _BaseMedia <|-- Document
```

## Content Ingestion Methods

There are two primary ways to ingest content: automatic resolution from local files and direct manual instantiation for in-memory data.

### 1. Automatic Resolution with `from_file`

The `types.from_file` function is the recommended way to load local assets. It automatically detects the file's MIME type using standard system utilities and returns the appropriate specialized class instance.

```python
from google.antigravity import types

# The SDK detects this is a PNG and returns an Image object
media = types.from_file("path/to/screenshot.png", description="Application error state")

# You can also call it on the specific class if the type is known
image = types.Image.from_file("path/to/image.jpg")
```

Sources: [google/antigravity/types.py:1072-1103](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/google/antigravity/types.py#L1072-L1103)

### 2. Direct Constructor Instantiation

For in-memory bytes (e.g., from a network request, a database, or a dynamically generated buffer), you can instantiate the classes directly. This requires specifying the MIME type explicitly, which prevents the agent from receiving ambiguous data.

```python
from google.antigravity import types

# Example: Loading bytes from an existing file handle
with open("report.pdf", "rb") as f:
    pdf_bytes = f.read()

# Direct instantiation for in-memory data
doc = types.Document(
    data=pdf_bytes, 
    mime_type="application/pdf", 
    description="Q3 Financial Report"
)
```

Sources: [examples/deep_dives/multimodal_pipeline.py:158-164](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/examples/deep_dives/multimodal_pipeline.py#L158-L164)

## Integrating with the Agent

Multimodal primitives are passed to the `Agent.chat` method as part of a `Content` list or as a single primitive. The agent processes these alongside text prompts to provide contextual responses.

```python
async with Agent(config) as my_agent:
    image = types.Image.from_file("example_image.png")
    doc = types.Document.from_file("sample_doc.txt")
    
    # Passing mixed content types in a single turn
    prompt = ["Analyze the chart in this image based on the data in this doc.", image, doc]
    response = await my_agent.chat(prompt)
    print(await response.text())
```

Sources: [examples/getting_started/multimodal.py:48-62](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/examples/getting_started/multimodal.py#L48-L62)

## Summary

Multimodal ingestion in the Antigravity SDK simplifies complex media handling into a few predictable patterns. By using `from_file` for local assets and direct constructors for buffers, developers can build agents that "see," "hear," and "read" with minimal boilerplate. This architecture maintains provider neutrality by focusing on standard MIME types and raw byte payloads, ensuring that your multimodal logic remains portable across different agent backends.

Sources: [google/antigravity/types.py:1055-1069](file:///var/folders/_h/3ssd63kx3_j7pxq42wmfq5980000gn/T/grok-wiki-local-cli-workspace-7VAz95/repo/google/antigravity/types.py#L1055-L1069)

---

## 12. Beyond 30 Minutes: Next Steps

> Synthesis of the core model, pointers to deep-dive examples (Middleware, Subagents), and how to contribute to the SDK.

- Page Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/pages/12-beyond-30-minutes-next-steps.md
- Generated: 2026-05-19T20:42:20.250Z

### Source Files

- `examples/README.md`
- `examples/deep_dives/README.md`
- `CONTRIBUTING.md`
- `examples/getting_started/subagents.py`

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [examples/README.md](examples/README.md)
- [examples/deep_dives/README.md](examples/deep_dives/README.md)
- [CONTRIBUTING.md](CONTRIBUTING.md)
- [examples/getting_started/subagents.py](examples/getting_started/subagents.py)
- [examples/getting_started/README.md](examples/getting_started/README.md)
- [examples/deep_dives/agent_middleware.py](examples/deep_dives/agent_middleware.py)
- [google/antigravity/agent.py](google/antigravity/agent.py)
- [google/antigravity/types.py](google/antigravity/types.py)
</details>

# Beyond 30 Minutes: Next Steps

Once you have mastered the [Getting Started](examples/getting_started/README.md) basics, the Google Antigravity SDK provides powerful primitives for scaling agents into production-ready compound systems. This page synthesizes the core architectural model and directs you to advanced implementation patterns for middleware, multi-agent orchestration, and autonomous operations.

Understanding how to compose these layers—from transparent lifecycle hooks to independent subagent delegation—is key to building robust, observable, and efficient AI applications.

## Synthesis of the Core Model

The SDK's architecture is built around the `Agent` and its underlying `Conversation` session. While `agent.chat()` provides a simple entry point, the core model is a declarative system where behavior is shaped by the interaction of tools, policies, and hooks.

### The Agent Lifecycle
An `Agent` instance manages the orchestration of several internal runners. When you enter an `async with Agent(config)` context, the SDK initializes the following components:

| Component | Responsibility |
| :--- | :--- |
| `ToolRunner` | Executes both `BuiltinTools` and custom `PythonTool` functions. |
| `HookRunner` | Intercepts lifecycle events to modify data or control execution flow. |
| `TriggerRunner` | Manages background monitoring and proactive event injection. |
| `McpBridge` | Connects the agent to external toolsets via the Model Context Protocol. |

Sources: [google/antigravity/agent.py:100-165](), [google/antigravity/types.py:212-235]()

## Middleware: Hook-Based Interception

Hooks are the agent equivalent of HTTP middleware or gRPC interceptors. They allow you to inject logic at critical points in the agent's turn without modifying the core reasoning prompt or tool implementations.

### Transparent Pattern: agent_middleware.py
The [agent_middleware.py](examples/deep_dives/agent_middleware.py) example demonstrates how "stacked" hooks create emergent behavior. By chaining multiple hooks, you can implement features that are transparent to the agent:

*   **Rate Limiting**: Use `PreToolCallDecideHook` to enforce per-tool quotas.
*   **Audit Logging**: Use `PostToolCallHook` to record every tool result to a persistent trail.
*   **Error Recovery**: Use `OnToolErrorHook` to intercept exceptions and provide recovery guidance to the model.

```python
# Example of a middleware-style error recovery hook
class FallbackHook(hooks.OnToolErrorHook):
  async def run(self, context, data):
    if isinstance(data, ValueError):
      return "[Could not find user. Use lookup_user instead of display name.]"
    return None
```
Sources: [examples/deep_dives/agent_middleware.py:107-135](), [examples/deep_dives/README.md:15-28]()

## Delegation: Orchestrating Subagents

Subagents allow you to break complex tasks into smaller, scoped contexts. This is a critical pattern for managing token usage and ensuring high-quality reasoning on massive datasets.

### Context Scoping with subagents.py
In [subagents.py](examples/getting_started/subagents.py), a main agent delegates a heavy research task to a subagent. This provides two primary benefits:
1.  **Context Hygiene**: The main agent's context window stays clean; it only receives the subagent's final synthesis, not the raw source documents.
2.  **Specialization**: Subagents can be configured with different tools or policies than the parent agent.

Subagent invocations are tracked via the `START_SUBAGENT` builtin tool, allowing parents to monitor and report on sub-task progress.

Sources: [examples/getting_started/subagents.py:34-45](), [google/antigravity/types.py:231]()

## Deep-Dive Examples Index

For specialized use cases, refer to the following advanced implementation patterns in `examples/deep_dives/`:

*   **[interactive_cli.py](examples/deep_dives/interactive_cli.py)**: Implements "Human-in-the-loop" approval flows using `policy.ask_user`.
*   **[round_based_chat.py](examples/deep_dives/round_based_chat.py)**: Orchestrates synchronized parallel agent discussions using `asyncio.gather`.
*   **[async_chat.py](examples/deep_dives/async_chat.py)**: Demonstrates reactive peer-to-peer agent communication using `asyncio.Condition`.
*   **[doc_maintenance_agent.py](examples/deep_dives/doc_maintenance_agent.py)**: An autonomous agent using `policy.allow` and `policy.deny` for fine-grained file-system scoping.

Sources: [examples/deep_dives/README.md:10-95](), [examples/README.md:35-55]()

## Contributing to the SDK

We are not currently accepting external contributions to the project. However, we encourage the community to report issues or request features through our issue tracker.

*   **Reporting Issues**: File a bug report on the project's tracker.
*   **Community Guidelines**: We follow [Google's Open Source Community Guidelines](https://opensource.google/conduct/).

Sources: [CONTRIBUTING.md:1-12]()

The Google Antigravity SDK is designed to be a modular foundation for compound AI engineering, prioritizing provider-neutrality and local-first execution.

---
