# GitHub Copilot SDK for Java
[](https://github.com/github/copilot-sdk/actions/workflows/sdk.yml)
[](https://openjdk.org/)
[](https://opensource.org/licenses/MIT)
#### Latest release
[](https://github.com/github/copilot-sdk/releases)
[](https://github.com/github/copilot-sdk/releases)
[](https://central.sonatype.com/artifact/com.github/copilot-sdk-java)
[](https://javadoc.io/doc/com.github/copilot-sdk-java/latest/index.html)
## Background
Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. The Java SDK tracks the official GitHub Copilot SDK family (TypeScript, Python, Go, .NET, and Rust).
## Prerequisites
To use the SDK, you'll need:
- Java 17 or later. **JDK 25 recommended**. The distributed jar is a multi-release jar (MR-JAR) and is compiled on JDK 25 with `maven.compiler.release` set to 17. This means, when run on JDK 25 and later, the SDK automatically uses virtual threads for its default internal executor.
Managed stdio and TCP connections materialize the platform classifier's
`copilot-runtime[.exe]` and adjacent `runtime.node` by default. An explicit
`cliPath` or `COPILOT_CLI_PATH` environment variable overrides the bundled
runtime.
## Installation
### Maven
```xml
com.githubcopilot-sdk-java1.0.14-preview.1
```
### Gradle
```groovy
implementation 'com.github:copilot-sdk-java:1.0.14-preview.1'
```
### Snapshot builds
Snapshot builds of the next development version are published to Maven Central Snapshots. To use them, add the snapshot repository and depend on the development version:
#### Maven
```xml
central-snapshotshttps://central.sonatype.com/repository/maven-snapshots/truecom.githubcopilot-sdk-java1.0.15-preview.1-SNAPSHOT
```
#### Gradle
```groovy
implementation 'com.github:copilot-sdk-java:1.0.15-preview.1-SNAPSHOT'
```
## In-process mode (experimental)
The SDK supports running the Copilot runtime **in-process** as a native library instead of spawning a separate CLI process. This eliminates process management overhead and simplifies deployment. In-process mode is currently experimental and supported on **linux-x64** (glibc), **linux-arm64** (glibc), **linuxmusl-x64**, **win32-x64**, **win32-arm64**, **darwin-x64**, and **darwin-arm64**.
Because in-process mode is experimental, see the [Using experimental APIs](#using-experimental-apis) section for how to opt in.
### Additional dependency
Add both the SDK and the platform-specific native runtime to your project:
```xml
com.githubcopilot-sdk-java${copilot.version}com.githubcopilot-sdk-java-runtime${copilot.version}linux-x64net.java.dev.jnajna5.19.1
```
### Usage
Configure the client to use the in-process connection:
```java
CopilotClientOptions options = new CopilotClientOptions()
.setConnection(RuntimeConnection.forInProcess());
CopilotClient client = new CopilotClient(options);
client.start().get();
```
## Quick Start
For experimental in-process AHP hosting, select a transport explicitly:
`client.startAhpHost(new AhpHostOptions().setLocalServer(new HostLocalServerOptions(null, null, null, null)))`.
The transport types are in `com.github.copilot.generated.rpc`. For GitHub Mission
Control, use `.setGithubEnvironment(new HostGitHubEnvironmentOptions("My host", "compute-id"))`
instead, or configure both transports. GitHub environment name and compute ID are
required; there is no implicit local listener. The host's `getUrl()`, `getToken()`,
and `getPid()` may return `null`; `getEnvironmentId()` returns the GitHub environment
ID when configured. Environment list/get/delete operations are available only
through the generated RPC API.
See [runtime-supervised AHP hosting](../docs/runtime-supervised-host.md) for creation
and resume callbacks, resident-session publication, ownership, and shared-snapshot E2Es.
```java
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};
// Create and start client
try (var client = new CopilotClient()) {
client.start().get();
// Create a session
var session = client.createSession(
new SessionConfig().setOnPermissionRequest(PermissionHandler.APPROVE_ALL).setModel("claude-sonnet-4.5")).get();
// Handle assistant message events
session.on(AssistantMessageEvent.class, msg -> {
lastMessage[0] = msg.getData().content();
System.out.println(lastMessage[0]);
});
// Handle session usage info events
session.on(SessionUsageInfoEvent.class, usage -> {
var data = usage.getData();
System.out.println("\n--- Usage Metrics ---");
System.out.println("Current tokens: " + data.currentTokens().intValue());
System.out.println("Token limit: " + data.tokenLimit().intValue());
System.out.println("Messages count: " + data.messagesLength().intValue());
});
// Send a message
var completable = session.sendAndWait(new MessageOptions().setPrompt("What is 2+2?"));
// and wait for completion
completable.get();
}
boolean success = lastMessage[0] != null && lastMessage[0].contains("4");
System.exit(success ? 0 : -1);
}
}
```
When targeting MCP tools configured through `setMcpServers(...)`, remember the
runtime tool name is `-`. For `setAvailableTools(...)`
and `setExcludedTools(...)`, prefer the source-qualified filter form
`mcp:-`. For `CustomAgentConfig.setTools(...)` and
`DefaultAgentConfig.setExcludedTools(...)`, use `-`
directly.
`CopilotClientOptions.setCwd(...)` sets the runtime process working directory, which otherwise inherits the current process working directory. `SessionConfig.setWorkingDirectory(...)` sets the session working directory, which otherwise defaults to the runtime process working directory.
`CopilotClientOptions.setExtensionLaunchProvider(...)` configures an experimental
connection-level resolver for extension launch profiles. The client installs the
reverse-RPC handler and registers the provider during startup before sessions can
be created.
### Installation confirmation (experimental)
`CopilotClientOptions.setInstallationConfirmationHandler(...)` configures the
connection-global `installations.confirm` receiver. The handler receives the
generated `InstallationConfirmationRequest` and an
`InstallationConfirmationContext`, then returns only an explicit
generated `InstallationDecision.CONFIRM`, `InstallationDecision.DECLINE` or
`InstallationDecision.CANCEL`. The SDK echoes the original challenge and review
fingerprint; it never infers approval and does not enable installation
capabilities or call a runtime registration RPC.
Match `operationId` and `policySessionId` against the original action on this
exact connection before presenting the complete review. Missing legacy session
metadata does not select a default session. Refuse unknown operations or
incomplete reviews.
Concurrent reviews are independent and do not block other client-global RPCs.
`context.getCancelled()` returns the single cancellation signal for the review.
It completes when the runtime's numeric `$/cancelRequest`, runtime-enforced
expiry, or loss of the original connection retires the review. Separately
spawned UI work should observe this signal and retire itself when it completes.
Dropping an outbound installation or OAuth future does not cancel that
operation.
`SessionConfig.setAskUserVariant(AskUserVariant.ELICITATION)` selects the
structured form-based `ask_user` tool when an elicitation handler is also set.
The default is `AskUserVariant.LEGACY`. Re-supply the option and handler through
`ResumeSessionConfig` on a cold resume.
To continue a pending turn after resuming a session, pass
`new ResumeSessionConfig().setContinuePendingWork(true)` to `resumeSession`.
Set it to `false` to opt out explicitly, or leave it unset to use the runtime
default.
For rotating per-session GitHub credentials, use
`SessionConfig.setGitHubTokenProvider(...)` (or the equivalent
`ResumeSessionConfig` setter) instead of `setGitHubToken(...)`:
```java
var config = new SessionConfig()
.setGitHubTokenProvider(args ->
acquireForHost(args.host()).thenApply(token ->
GitHubTokenProviderResult.token(token, 8 * 60 * 60)))
.setOnPermissionRequest(PermissionHandler.APPROVE_ALL);
```
The remaining lifetime is required and must be positive when the callback
completes; production GitHub tokens typically last eight hours. A static token
and a provider are mutually exclusive.
Initial acquisition runs during session creation or resume. Cancellation,
provider errors, and invalid token responses reject that operation instead of
falling back to ambient authentication. Idle sessions refresh only before their
next credential-consuming operation; there is no background refresh timer.
### Typed MCP installation and removal payloads (breaking change)
Three payloads in the experimental MCP installation and removal workflow are now sealed
interfaces with one record per variant, instead of `Object`, which brings Java into line
with the other SDKs. No other generated type changes.
| Field | Before | After |
| --- | --- | --- |
| `InstallationConfirmationRequest.review()` | `Object` | `InstallationReview` sealed interface (`InstallationReviewMcp` / `InstallationReviewSkill`, by `resource`); the MCP variant carries `McpInstallationReview` (`McpInstallationReviewInstall` / `McpInstallationReviewUninstall`, by `action`) and the Skill variant carries `SkillInstallationReview` |
| `McpInstallPlan.transportChoices()` | `List