# 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.

- Repository: google-antigravity/antigravity-sdk-python
- GitHub: https://github.com/google-antigravity/antigravity-sdk-python
- Human wiki: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867
- Complete Markdown: https://grok-wiki.com/public/wiki/google-antigravity-antigravity-sdk-python-2abd361a7867/llms-full.txt

## 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]()
