Disclaimer: This is an unofficial port of the Google Antigravity SDK from Python to Rust. It is not an official Google project.
The Google Antigravity SDK is a Rust SDK for building AI agents powered by Antigravity and Gemini. It provides a secure, scalable, and stateful infrastructure layer that abstracts the agentic loop, letting you focus on what your agent does rather than how it runs.
Add the SDK to your Cargo.toml:
[dependencies]
antigravity-sdk = { path = "path/to/antigravity-sdk" } # Or git repository URL
tokio = { version = "1", features = ["full"] }Important
The Google Antigravity SDK relies on a Go localharness binary communicating via WebSocket and Protobuf. Ensure the harness is correctly set up.
Get started by running one of the examples/, such as the
hello_world example with:
export GEMINI_API_KEY="your_api_key_here"
cargo run --example hello_worldThe Agent struct is the easiest way to get started. It manages the full
lifecycle — tool wiring, hook registration, and policy defaults.
use antigravity_sdk::connections::local::LocalAgentConfig;
use antigravity_sdk::Agent;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error + Send + Sync>> {
let config = LocalAgentConfig::default();
let mut agent = Agent::new(config);
agent.start().await?;
let response = agent.chat("What files are in the current directory?").await?;
println!("{}", response.text().await);
agent.stop().await?;
Ok(())
}To stream agent output in real-time (e.g., for fluid UI or console applications), simply consume the ChatResponse object which implements futures::stream::Stream:
use antigravity_sdk::connections::local::LocalAgentConfig;
use antigravity_sdk::Agent;
use futures::StreamExt;
use std::io::{self, Write};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut agent = Agent::new(LocalAgentConfig::default());
agent.start().await?;
let mut response = agent.chat("Write a short poem about space.").await?;
while let Some(chunk) = response.next().await {
print!("{}", chunk);
io::stdout().flush()?;
}
println!();
agent.stop().await?;
Ok(())
}By default, Agent runs in read-only mode for safety. Pass
capabilities: CapabilitiesConfig::default() to enable all tools (including writes).
use antigravity_sdk::connections::local::{LocalAgentConfig, CapabilitiesConfig};
use antigravity_sdk::Agent;
use antigravity_sdk::utils::interactive::run_interactive_loop;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut config = LocalAgentConfig::default();
config.capabilities = Some(CapabilitiesConfig::default());
let mut agent = Agent::new(config);
agent.start().await?;
run_interactive_loop(&mut agent).await?;
agent.stop().await?;
Ok(())
}For full control over the connection lifecycle, use Conversation directly:
use antigravity_sdk::connections::local::LocalConnectionStrategy;
use antigravity_sdk::conversation::Conversation;
use antigravity_sdk::tools::tool_runner::ToolRunner;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let tool_runner = ToolRunner::new();
let mut strategy = LocalConnectionStrategy::new(
Default::default(),
tool_runner,
None,
None,
);
let mut conversation = Conversation::create(&mut strategy).await?;
let response = conversation.chat("What files are here?").await?;
println!("{}", response.text().await);
println!("Total steps: {}", conversation.history().await.len());
conversation.disconnect().await?;
Ok(())
}The SDK follows a state-of-the-art Functional Programming architecture:
- Railway Oriented Programming (ROP): Pipeline-based error handling with
Pipeline<T>andPipelineError - Functional Core – Imperative Shell: Pure functions in
src/core/, IO at boundaries - Actor Model: Zero-lock concurrency via
StateActorandWriterActor(replacesArc<Mutex<...>>) - Event Sourcing:
AgentPhasestate machine +AgentEventappend-only log
For detailed architecture documentation, see FP Architecture.
Register Rust closures or functions as tools that the agent can call using RegisteredTool:
use antigravity_sdk::connections::local::LocalAgentConfig;
use antigravity_sdk::Agent;
use antigravity_sdk::tools::tool_runner::{RegisteredTool, ToolRunner};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut tool_runner = ToolRunner::new();
let _ = tool_runner.register(RegisteredTool {
name: "get_weather".to_string(),
description: "Returns the current weather for a city.".to_string(),
schema: Some(json!({
"type": "object",
"properties": {
"city": { "type": "string" }
},
"required": ["city"]
})),
handler: Box::new(|args| {
Box::pin(async move {
let city = args.get("city").unwrap().as_str().unwrap();
Ok(json!(format!("It's sunny in {}.", city)))
})
}),
});
let config = LocalAgentConfig::default();
let mut agent = Agent::new(config);
// Note: Tool Runner injection occurs automatically through hooks/config in advanced use
agent.start().await?;
agent.chat("What's the weather in Tokyo?").await?;
agent.stop().await?;
Ok(())
}Connect to external MCP servers and expose their tools to the agent natively using the rmcp crate integration.
Control agent behavior with a declarative policy system inside the HookRunner or via AgentConfig.
For more detailed documentation, see the deep-dive guides:
- Getting Started — Basics and Setup
- Core Concepts — Agent, Conversation, Streaming
- Advanced Usage — Custom Tools, MCP, Policies, Triggers
- Architecture — Under the hood of the Rust implementation
- FP Architecture — Railway Oriented Programming, Actor Model, Event Sourcing