❯ Guillaume Laforge

The Unofficial Antigravity SDK for Java

The Unofficial Antigravity SDK for Java

Before heading for well-deserved vacations, I wanted to share something I’ve been cooking on and off for the past few weeks: an unofficial Java SDK for Antigravity.

If you’re familiar with Antigravity, you’ll know it’s available across different surfaces:

  • Antigravity 2.0: an agent manager for the Antigravity harness, where you can work across multiple projects and sessions from a rich UI,
  • Antigravity CLI: a CLI coding agent, where you can interleave running terminal commands, with active agent coding actions,
  • Antigravity IDE: a VSCode fork, with an integrated Antigravity chat assistant, when you want to be deep into the code,
  • Antigravity SDK: which is actually a toolkit you can integrate and manage yourself, to create your own Antigravity harness.

Antigravity surfaces
Antigravity surfaces

The first three are pretty natural surface areas, but I was more curious about the latter one, the SDK. With an SDK, I can run my custom agents powered by the Antigravity harness brain, but I can control exactly how it works, I can integrate it however I like, or I could even create my own custom IDE or some crazy other surface.

However, as you know, I’m a Java developer, and I’d rather use the SDK in a language I’m more familiar with, and I can more easily integrate in my work. So I decided to, somehow, reverse engineer the Python SDK, with the help of Antigravity 2.0, to create my own (unofficial) Antigravity SDK for Java.

What’s interesting is that the Antigravity SDK for Python is actually a Python framework wrapping… a Go binary! Yes, the heart of the SDK is actually built in Go, not Python. This means I can also interact with the localharness Go binary with Java’s process builder. The Python SDK comes in the form of a python wheel which contains the binary, so I have to download them (for all platforms) and bundled them in my own artifact.

Note

You can find the unofficial Antigravity Java SDK on GitHub. The README.md details the features supported by the SDK.

Example Use Cases

Why would you use an agent SDK in Java? Here are a few concrete scenarios:

  • GitHub Actions & CI/CD Pipelines: Run custom Java tools or scripts inside GitHub Actions to automate pull request reviews, perform automatic bug triaging, generate release notes, or audit incoming issue reports.
  • Enterprise Applications: Integrate an AI agent into an existing Spring Boot, Quarkus, or Micronaut application to automate backend workflows or internal assistant logic.
  • Internal Java Tools & CLIs: Build command-line utilities that combine standard Java libraries with agent capabilities like code generation, refactoring, or documentation processing.
  • Background Monitoring Agents: Run background services that periodically inspect databases, server logs, or APIs, and run agent turns when specific conditions occur.
  • Custom Interfaces: Build custom desktop or web user interfaces in Java that interact directly with the Antigravity engine (for example a document authoring assistant, a blog drafter).

Getting Started: Hello Java World

It had to start with a Hello World example, right? 😃

To start using the Antigravity Java SDK in your project, add the antigravity-sdk-wrapper dependency. (You only need to declare antigravity-sdk-wrapper because Maven and Gradle will transitively fetch antigravity-sdk-protocol which contains the generated Protobuf classes).

Maven

<dependency>
    <groupId>io.github.glaforge.antigravity</groupId>
    <artifactId>antigravity-sdk-wrapper</artifactId>
    <version>0.2.5</version>
</dependency>

Gradle

implementation 'io.github.glaforge.antigravity:antigravity-sdk-wrapper:0.2.5'

Basic Agent Turn

Here is a minimal example creating an agent with system instructions and sending a prompt testing its Java knowledge:

import io.github.glaforge.antigravity.Agent;
import io.github.glaforge.antigravity.AgentConfig;
import io.github.glaforge.antigravity.AgentResponse;

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) throws Exception {
        AgentConfig config = AgentConfig.builder()
            .instructions(
                "You are a helpful software architecture assistant.")
            .build();

        try (Agent agent = new Agent(config)) {
            AgentResponse response = agent.chat(
                "What are the main benefits of using Java records?")
                .get(60, TimeUnit.SECONDS);

            System.out.println(response.text());
        }
    }
}

There are a couple of noteworthy details in this short snippet:

  • Resource Management (try-with-resources): Agent implements AutoCloseable. Instantiating an agent starts the native localharness Go process and establishes the WebSocket connection. Wrapping Agent in a try-with-resources block ensures agent.close() is called automatically, cleanly terminating the Go subprocess and closing network sockets when the block exits.
  • Asynchronous CompletableFuture & Timeouts: The agent.chat(...) method returns a CompletableFuture<AgentResponse>. Calling .get(60, TimeUnit.SECONDS) waits for the turn to complete. Using an explicit timeout is good practice to prevent your application from blocking indefinitely if a network request stalls. You can also use standard CompletableFuture methods like thenApply() or thenAccept().

If you prefer non-blocking reactive patterns or want to process tokens in real-time as they are generated, the SDK also supports streaming responses with callbacks and Flow.Publisher, detailed in the Reactive & Token Streaming section below.

Calling Java Code from the Antigravity Harness

One of the useful capabilities of the SDK is extending the agent with your own custom Java code.

When you configure an agent with a custom tool, the SDK automatically generates a JSON schema for the parameter types. During an agent turn, if the model decides it needs to invoke your tool:

  1. The localharness Go binary sends a tool invocation request over WebSockets to the Java process.
  2. The Java SDK receives the request, parses the JSON arguments into Java parameters, and executes your Java method.
  3. The method result is sent back to the Go harness over WebSockets, allowing the model to continue its reasoning turn.

Here is an example using the @Tool and @Param annotations:

import io.github.glaforge.antigravity.annotations.Param;
import io.github.glaforge.antigravity.annotations.Tool;

public class InventoryService {

    public record StockInfo(String productId, int availableQuantity, String warehouseLocation) {}

    @Tool(name = "check_inventory", description = 
          "Check available stock levels for a given product ID.")
    public StockInfo checkInventory(
        @Param(name = "productId", description = 
        "The unique SKU or product ID") String productId
    ) {
        // Query a DB, call an internal service, 
        // or execute your own business logic
        return new StockInfo(productId, 42, "Warehouse B, Aisle 3");
    }
}

To register this tool with your agent, add it to the AgentConfig:

InventoryService service = new InventoryService();

AgentConfig config = AgentConfig.builder()
    .instructions("""
        You are a helpful logistics assistant. 
        Use the `check_inventory` tool when asked about stock.""")
    .addTool(service)
    .build();

try (Agent agent = new Agent(config)) {
    AgentResponse response = agent.chat(
        "How many units of SKU-1234 do we have in stock?").get(60, TimeUnit.SECONDS);
    System.out.println(response.text());
}

The agent executes checkInventory("SKU-1234") in Java, receives the StockInfo record, and returns a natural language response to the user.

Reactive & Token Streaming

In addition to returning CompletableFuture<AgentResponse>, the SDK provides reactive streaming capabilities so you can process tokens as they are generated by the model.

1. Callback-based Streaming

If you want a simple way to consume tokens as they arrive, use agent.chatStream:

CompletableFuture<AgentResponse> future = agent.chatStream(
    "Tell me a short story.", 
    chunk -> System.out.print(chunk.textDelta())
);
future.get(120, TimeUnit.SECONDS);

2. Reactive Streams (Flow.Publisher)

For modern reactive frameworks (such as Project Reactor, or RxJava 3), agent.chatPublisher returns a standard java.util.concurrent.Flow.Publisher<AgentResponseChunk>:

Flow.Publisher<AgentResponseChunk> publisher = 
    agent.chatPublisher("Explain virtual threads in Java.");

// Integration example with Project Reactor:
// Flux<AgentResponseChunk> flux = Flux.from(publisher);

// Standard Java 9+ Subscriber
publisher.subscribe(new Flow.Subscriber<>() {
    private Flow.Subscription subscription;

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
        subscription.request(Long.MAX_VALUE);
    }

    @Override
    public void onNext(AgentResponseChunk chunk) {
        System.out.print(chunk.textDelta());
    }

    @Override
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
    }

    @Override
    public void onComplete() {
        System.out.println("\nDone!");
    }
});

3. Thought & Tool Event Streams

If you are building rich user interfaces, agent.streamChat(...) returns an AgentStream object allowing you to separate the model’s internal reasoning process (thoughts()) from tool execution events (toolCalls()):

AgentStream stream = agent.streamChat(
    "Think step-by-step and check stock for SKU-1234.");

// Stream model reasoning deltas
stream.thoughts().subscribe(thought -> 
    System.out.println("Thinking: " + thought));

// Intercept tool calls in real-time
stream.toolCalls().subscribe(call -> 
    System.out.println("Executing tool: " + call.name()));

// Wait for the final complete response
AgentResponse response = stream.result().get(60, TimeUnit.SECONDS);

Agent Skill for AI Coding Assistants

To help you build applications with this SDK, the repository includes an official Agent Skill conforming to the open Agent Skills specification.

If you use AI coding tools or CLI coding agents (such as Antigravity CLI, Cursor, Windsurf, or Claude Code), installing this skill gives your assistant native knowledge of the SDK’s API, classes, configuration options, and design patterns.

You can install it directly from the GitHub repository using npx skills or gh skills:

# Using npx skills
npx skills add glaforge/antigravity-java-sdk

# Or using the GitHub CLI skills extension
gh skills add glaforge/antigravity-java-sdk

Once added, your AI coding assistant will automatically know how to configure AgentConfig builders, stream tokens, attach security policies, and write custom Java @Tool implementations.

Supported Features

The Java SDK provides feature parity with the Python SDK:

  • Agent Chat & Session Persistence: Synchronous and asynchronous turns, multi-turn history, and session resumption via conversationId.
  • Streaming Options:
    • Callback-based streaming (chatStream).
    • Reactive Streams integration (Flow.Publisher via chatPublisher).
    • Filtered streams for model thinking process (thoughts()) and tool calls (toolCalls()).
  • Custom Tool Calling: Annotated Java methods (@Tool) and dynamic runtime tool definitions (DynamicTool).
  • Model Context Protocol (MCP): Native connection to external MCP servers over stdio, sse, and streamableHttp transports.
  • Agent Skills: Ability to load file-based skills matching the open Agent Skills specification.
  • Security Policies: Configurable policy chains (Policies.denyAll(), Policies.allowTools(), Policies.askUser()) for tool execution safety.
  • Lifecycle Hooks: Intercept and modify turns, tool calls, and user interactions (PreTurnHook, PreToolCallDecideHook, OnInteractionHook).
  • Background Triggers: Run periodic background tasks to inject context into an active agent session.
  • Multimodal Inputs: Send text, images, audio, and video inputs to the agent.
  • Structured Outputs: Map model responses directly to Java record types using JSON Schema constraints.
  • Subagents: Support for spawning and delegating tasks to subagents.
  • Slash Commands: Send CLI-style commands (like /help or /clear) directly in agent chat turns.
  • Built-in Capabilities: Toggle built-in tools like web search, shell execution, file editing, and image generation.
Tip

Again, be sure to check the README.md which details the features listed above.

Summary

Building this SDK has been a fun exercise, with the help of Antigravity itself, doing some forensics & reverse engineering, and in connecting native Go binaries with modern Java 21 features like records, virtual threads, and Reactive Streams.

If you are a Java developer interested in building AI agents using the Antigravity harness, check out the Antigravity SDK for Java on GitHub.

Feedback, issues, and pull requests are welcome! I’m particularly curious to hear more about use cases you have in mind for your own Antigravity harness based integrations.