DEV Community

jamilxt
jamilxt

Posted on

GitHub's Copilot SDK for Java: Run AI Agents in Spring Boot Without Spring AI or LangChain4j

Every Java team adding AI to a backend right now faces the same fork in the road. If you are on Spring Boot, you reach for Spring AI. If you are not, you reach for LangChain4j. Both are good libraries. But both also come with a commitment: you adopt their abstractions, their release cadence, and their opinion of what an agent loop looks like. And if you are on Jakarta EE, Micronaut, or Quarkus, the Spring path is simply closed to you.

On August 10, 2026, GitHub quietly published a third option. Edward Burns, the principal engineer who led the Java binding and was the release coordinator for Jakarta EE 11, walked through the Copilot SDK for Java in an engineering post on the GitHub blog. The short version: the same agent runtime that powers Copilot CLI is now a Maven dependency you can embed in any server-side Java application, Spring or not, IDE or not. And with its BYOK mode, it runs against OpenAI, Anthropic, Azure, or any OpenAI-compatible endpoint with your own API key, no Copilot subscription required.

That last sentence is the part that matters for architecture decisions. Let me explain what the SDK actually is, what the code looks like, and where it fits next to Spring AI and LangChain4j if you run Spring Boot services in production.

Full disclosure: I have not shipped the Copilot SDK in production yet. I run my own small AI agent infrastructure on Spring Boot, and everything below comes from GitHub's official documentation, the SDK README, and Burns's engineering post. Treat this as a grounded evaluation with real code, not a war story.

What the SDK Actually Is

It is not a model API client. Most Java AI libraries give you a thin wrapper over a provider's HTTP endpoint: send messages, get a completion. The Copilot SDK exposes something bigger. Per the repository README, it embeds "the same engine behind Copilot CLI: a production-tested agent runtime you can invoke programmatically." Your code defines agent behavior and tools; the runtime handles planning, tool invocation, the model loop, and even file edits.

It speaks idiomatic Java, not a ported DSL. The API surface is CompletableFuture, annotations, lambdas, and virtual threads. Burns's summary highlights five capabilities: a Java-native API, three tool-definition styles (annotations, lambdas, JSON Schema), section-level system message customization, a one-line agentic loop via sendAndWait(...), and real-time event streaming via session.on(...).

It is genuinely framework-agnostic. The sample application in Burns's post runs on Jakarta EE 11 with Open Liberty 26, using CDI, JPA, and WebSocket. The Spring integration point is deliberately low-level: you hand the SDK an Executor, and it runs its agent work on your threads. There is no Spring Boot starter to install and no framework plugin. The same library works on Jakarta EE, Spring, Quarkus, or a plain main method.

It is a real, versioned product. The SDK family (Python, TypeScript, Go, .NET, Java, Rust) is generally available and follows semantic versioning. The Java artifact is com.github:copilot-sdk-java, at version 1.0.12-preview.0 at the time of writing, and the repo sits at over 10,000 stars.

The Prerequisites, Honestly Stated

Before you get excited, know what the SDK assumes.

Java 17 minimum, JDK 25 recommended. The jar is a multi-release JAR compiled on JDK 25 with maven.compiler.release set to 17. Run it on JDK 25 or later and the SDK automatically uses virtual threads for its default internal executor. On Java 17 it still works, you just do not get the virtual thread default.

The Copilot CLI must be installed. The Java SDK (like the Go and Rust bindings) does not bundle the runtime as a dependency. You need Copilot CLI version 1.0.55-5 or later on your PATH, or you configure a custom cliPath. Every SDK in the family talks to the CLI over JSON-RPC, and the client manages the process lifecycle. This is the deployment detail most likely to bite you in a container image: your Dockerfile needs the CLI present.

There is an experimental escape hatch. If shipping a Node-based CLI alongside your JVM feels wrong, an experimental in-process mode runs the Copilot runtime as a native library instead of spawning a CLI process. It is currently limited to linux-x64 and requires an extra copilot-sdk-java-runtime dependency plus JNA. Interesting for lean containers, not something to bet a production service on yet.

Your First Agent in About 30 Lines

Here is the verified Quick Start from the Java SDK README, lightly trimmed:

import com.github.copilot.CopilotClient;
import com.github.copilot.generated.AssistantMessageEvent;
import com.github.copilot.generated.SessionUsageInfoEvent;
import com.github.copilot.rpc.MessageOptions;
import com.github.copilot.rpc.PermissionHandler;
import com.github.copilot.rpc.SessionConfig;

public class CopilotSDK {
    public static void main(String[] args) throws Exception {
        var lastMessage = new String[]{null};

        try (var client = new CopilotClient()) {
            client.start().get();

            var session = client.createSession(
                new SessionConfig()
                    .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
                    .setModel("claude-sonnet-4.5")).get();

            session.on(AssistantMessageEvent.class, msg -> {
                lastMessage[0] = msg.getData().content();
                System.out.println(lastMessage[0]);
            });

            session.on(SessionUsageInfoEvent.class, usage -> {
                var data = usage.getData();
                System.out.println("Current tokens: " + data.currentTokens().intValue());
                System.out.println("Token limit: " + data.tokenLimit().intValue());
            });

            session.sendAndWait(
                new MessageOptions().setPrompt("What is 2+2?")).get();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Three things in this snippet deserve attention, because they differ from what Spring AI and LangChain4j hand you.

sendAndWait is the whole agentic loop. One call. The runtime does the model call, decides whether to invoke tools, executes them, and loops until it has a final answer. In Spring AI you assemble this yourself from ChatClient, tool callbacks, and advisor chains. Here the loop is the runtime's job, which is either a relief or a loss of control depending on your temperament.

Token accounting is a built-in event, not an add-on. SessionUsageInfoEvent streams current tokens, the token limit, and message count as the session runs. Anyone who has been surprised by a provider invoice will appreciate that cost observability is a first-class event rather than something you bolt on with an interceptor.

Permissions are explicit. PermissionHandler.APPROVE_ALL is the demo setting. The real API lets you write a handler that inspects each permission request and decides programmatically, or routes to a human. For a server-side agent that can touch your filesystem, this is the difference between a demo and something your security team signs off on.

Defining Tools: The Part You Will Actually Write

Tools are where your domain logic meets the agent, and the SDK offers three styles. The annotation style is the one enterprise Java teams will recognize instantly:

import com.github.copilot.rpc.ToolInvocation;
import com.github.copilot.tool.CopilotTool;
import com.github.copilot.tool.CopilotToolParam;

class ProgressTools {
    @CopilotTool("Reports the current phase and session")
    public String reportProgress(
            @CopilotToolParam("Current phase") String phase,
            ToolInvocation invocation) {
        return "phase=" + phase + ", sessionId=" + invocation.getSessionId();
    }
}
Enter fullscreen mode Exit fullscreen mode

Note the ToolInvocation parameter. It is injected as runtime context and never appears in the tool schema the model sees, so you get session identity and tool call IDs inside your handler for free. It can sit before, between, or after the schema-visible parameters.

For quick inline tools at session construction, there is a lambda style:

ToolDefinition search = ToolDefinition.from(
    "search_items",
    "Searches indexed items by keyword",
    Param.of(String.class, "keyword", "Search keyword"),
    keyword -> "Searching for: " + keyword)
.skipPermission(true)
.defer(ToolDefer.AUTO);
Enter fullscreen mode Exit fullscreen mode

Optional parameters with defaults, async handlers via fromAsync, and a third JSON Schema style for full control round out the toolkit. The fluent modifiers matter in production: .skipPermission(true) on a read-only search tool is reasonable, while leaving permissions on for anything that writes is the sane default.

BYOK: The Detail That Changes the Decision

Here is the claim from Burns's post, quoted directly because the scope matters: "Even though it's called GitHub Copilot SDK, you can use it with any direct model provider, such as OpenAI, Azure, Anthropic, or OpenAI-compatible endpoints, by passing a provider/ProviderConfig with your own baseUrl + apiKey (or bearer token). No Copilot subscription required."

Read that again from a procurement perspective. The agent runtime GitHub has hardened over years of Copilot CLI usage, the orchestration, the tool loop, the permission model, becomes a portable harness you can point at whichever provider your company already has a contract with. If your organization standardized on Azure OpenAI, you do not need a Copilot seat per service to use this.

There are limits, and they are worth knowing before a design review. BYOK in the current SDK is key-based only. There is no support yet for Entra ID, managed identities, or third-party identity providers. Teams whose security posture requires workload identities rather than raw keys will either wait for that support or authenticate through GitHub OAuth instead.

Running It Inside Spring Boot

Since my day job is Spring Boot services, this is the angle I care about most, and the pattern is clean. The SDK does not want to own your threading model. You hand it an Executor and it hands back CompletableFutures.

The deployment shape that makes sense in a Boot service:

One client, many sessions. Instantiate a single CopilotClient as a singleton bean, call start() once at startup, and create a session per user request or conversation. Sessions are cheap; the client owns the expensive JSON-RPC connection to the runtime.

Virtual threads for agent work. On JDK 25, the SDK's internal executor already uses virtual threads by default. In a Boot 4 service you can additionally pass your own executor so agent work stays off the platform threads serving HTTP traffic. Each sendAndWait call blocks a virtual thread, not a Tomcat worker.

Memory is per-session and explicit. The SDK supports persistent agent memory via MemoryConfiguration on SessionConfig, so an agent can carry context across turns. It is opt-in per session, including on resumeSession, which means you decide per use case whether the agent remembers anything. For stateless request/response endpoints, leave it off. For a support assistant, turn it on and bound it.

The container gotcha. Your image needs the Copilot CLI binary on PATH unless you use the experimental in-process mode. A minimal stage in a multi-stage Docker build that installs the CLI keeps the final image honest. Budget for this in your CI pipeline before you demo.

How It Stacks Up Against Spring AI and LangChain4j

I keep getting asked some version of "does this replace Spring AI," so here is the honest positioning.

Spring AI 2.0 remains the right default if you are all-in on Spring Boot. Its annotation-driven tool model, advisor chains, MCP support, and Spring Boot auto-configuration are unmatched for developer velocity inside the Spring ecosystem. You give up nothing except the ability to leave.

LangChain4j remains the right default if you are not on Spring and want the broadest provider and vector store coverage, 20-plus models and 20-plus stores, with Quarkus and Micronaut integrations.

The Copilot SDK for Java occupies a different slot: it is the option when you want a complete, production-tested agent runtime rather than a framework for assembling your own. You get the loop, the permission model, the memory, the token telemetry, and BYOK provider neutrality, with no framework coupling at all. The trade is that the runtime ships the Copilot CLI process model with it, the version is still in 1.0.x-preview territory, and the ecosystem around it (examples, community answers, battle scars) is young compared to the other two.

A reasonable 2026 architecture: Spring AI for model-facing features inside your Boot services, and the Copilot SDK where you need a full autonomous agent harness that non-Spring teams can also consume. They are not mutually exclusive.

A Pre-Flight Checklist Before You Adopt

If you evaluate this SDK this month, here is the checklist I would run, save it for your next design doc:

  • Confirm the runtime story. Can your container images ship Copilot CLI 1.0.55-5 or later? If not, is experimental linux-x64 in-process mode acceptable for your risk tolerance?
  • Pick your auth mode deliberately. GitHub OAuth for Copilot-subscribed teams, BYOK for provider-neutral deployments. If you need managed identities, BYOK is not ready for you yet.
  • Write a real PermissionHandler. APPROVE_ALL is for demos. Decide per tool kind what auto-approves and what escalates.
  • Verify the JDK story. Java 17 works, JDK 25 gets you virtual thread defaults. If you are still on 21, confirm the executor behavior in your thread dumps.
  • Watch the version. 1.0.12-preview.0 today, semver discipline promised, but pin the version and read the changelog before upgrading. Experimental APIs are gated behind @CopilotExperimental compile errors by default, which is a good sign of API hygiene.
  • Measure tokens from day one. Wire SessionUsageInfoEvent into your metrics pipeline before the first demo, not after the first invoice.

The Takeaway

The Java AI stack consolidated fast this year: Spring AI 2.0, LangChain4j's BDI agents, Jakarta's own Agentic AI spec in milestone. The Copilot SDK for Java adds a genuinely different option, a vendor-neutral agent runtime with an enterprise Java soul, designed by someone who knows exactly how Jakarta EE shops build software. It is young, the CLI process dependency is real friction, and I would not rip out a working Spring AI integration for it. But for teams that want agent capabilities without framework commitment, or that want one harness across Jakarta EE and Spring, this is the first credible answer. I will be prototyping it against my own agent infra and will report back with real numbers.

I write about Java, Spring Boot, and AI every week. Subscribe, it's free.

Have you tried the Copilot SDK for Java, or are you staying with Spring AI or LangChain4j for now? What broke first in production? I read every comment.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev

Running agents directly inside Spring Boot is interesting because it keeps the AI layer close to existing service boundaries. I would be careful to make tool permissions and observability feel like normal backend infrastructure, not a side channel.