Skip to content

Commit 6cdefd2

Browse files
committed
Add Copilot instructions for the Java SDK
1 parent 52bab0f commit 6cdefd2

1 file changed

Lines changed: 171 additions & 0 deletions

File tree

.github/copilot-instructions.md

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
# Copilot Instructions for copilot-sdk-java
2+
3+
A Java SDK for programmatic control of GitHub Copilot CLI. This is a community-driven port of the official .NET SDK, targeting Java 17+.
4+
5+
## Build & Test Commands
6+
7+
```bash
8+
# Build and run all tests
9+
mvn clean verify
10+
11+
# Run a single test class
12+
mvn test -Dtest=CopilotClientTest
13+
14+
# Run a single test method
15+
mvn test -Dtest=ToolsTest#testToolInvocation
16+
17+
# Format code (required before commit)
18+
mvn spotless:apply
19+
20+
# Check formatting only
21+
mvn spotless:check
22+
23+
# Build without tests
24+
mvn clean package -DskipTests
25+
26+
# Run tests with debug logging
27+
mvn test -Pdebug
28+
```
29+
30+
## Architecture
31+
32+
### Core Components
33+
34+
- **CopilotClient** - Main entry point. Manages connection to Copilot CLI server via JSON-RPC over stdio. Spawns CLI process or connects to existing server.
35+
- **CopilotSession** - Represents a conversation session. Handles event subscriptions, tool registration, permissions, and message sending.
36+
- **JsonRpcClient** - Low-level JSON-RPC protocol implementation using Jackson for serialization.
37+
38+
### Package Structure
39+
40+
- `com.github.copilot.sdk` - Core classes (CopilotClient, CopilotSession, JsonRpcClient)
41+
- `com.github.copilot.sdk.json` - DTOs, request/response types, handler interfaces (SessionConfig, MessageOptions, ToolDefinition, etc.)
42+
- `com.github.copilot.sdk.events` - Event types for session streaming (AssistantMessageEvent, SessionIdleEvent, ToolExecutionStartEvent, etc.)
43+
44+
### Test Infrastructure
45+
46+
Tests use the official copilot-sdk test harness from `https://github.com/github/copilot-sdk`. The harness is automatically cloned during `generate-test-resources` phase to `target/copilot-sdk/`.
47+
48+
- **E2ETestContext** - Manages test environment with CapiProxy for deterministic API responses
49+
- **CapiProxy** - Node.js-based replaying proxy using YAML snapshots from `test/snapshots/`
50+
- Test snapshots are stored in the upstream repo's `test/snapshots/` directory
51+
52+
## Key Conventions
53+
54+
### Upstream Merging
55+
56+
This SDK tracks the official .NET implementation at `github/copilot-sdk`. The `.lastmerge` file contains the last merged upstream commit hash. Use the `agentic-merge-upstream` skill (see `.github/prompts/agentic-merge-upstream.prompt.md`) to port changes.
57+
58+
When porting from .NET:
59+
- Adapt to Java idioms, don't copy C# patterns directly
60+
- Convert `async/await``CompletableFuture`
61+
- Convert C# properties → Java getters/setters or fluent setters
62+
- Use Jackson for JSON (`ObjectMapper`, `@JsonProperty`)
63+
64+
### Code Style
65+
66+
- 4-space indentation (enforced by Spotless with Eclipse formatter)
67+
- Fluent setter pattern for configuration classes (e.g., `new SessionConfig().setModel("gpt-5").setTools(tools)`)
68+
- Public APIs require Javadoc (enforced by Checkstyle, except `json` and `events` packages)
69+
- Pre-commit hook runs `mvn spotless:check` - enable with: `git config core.hooksPath .githooks`
70+
71+
### Handler Pattern
72+
73+
Handlers use functional interfaces with `CompletableFuture` returns:
74+
75+
```java
76+
session.createSession(new SessionConfig()
77+
.setOnPermissionRequest((request, invocation) ->
78+
CompletableFuture.completedFuture(new PermissionRequestResult().setKind("allow")))
79+
.setOnUserInput((request, invocation) ->
80+
CompletableFuture.completedFuture(new UserInputResponse().setResponse("user input")))
81+
);
82+
```
83+
84+
### Event Handling
85+
86+
Sessions emit typed events via `session.on()`:
87+
88+
```java
89+
session.on(AssistantMessageEvent.class, msg -> System.out.println(msg.getData().getContent()));
90+
session.on(SessionIdleEvent.class, idle -> done.complete(null));
91+
```
92+
93+
### Sealed Event Hierarchy
94+
95+
`AbstractSessionEvent` is a sealed class permitting specific event types. Use pattern matching:
96+
97+
```java
98+
switch (event) {
99+
case AssistantMessageEvent msg -> handleMessage(msg);
100+
case ToolExecutionStartEvent tool -> handleToolStart(tool);
101+
case SessionIdleEvent idle -> handleIdle();
102+
default -> { }
103+
}
104+
```
105+
106+
### Tool Definition Pattern
107+
108+
Custom tools use `ToolDefinition.create()` with JSON Schema parameters and a `ToolHandler`:
109+
110+
```java
111+
var tool = ToolDefinition.create(
112+
"get_weather",
113+
"Get weather for a location",
114+
Map.of(
115+
"type", "object",
116+
"properties", Map.of("location", Map.of("type", "string")),
117+
"required", List.of("location")
118+
),
119+
invocation -> {
120+
// Type-safe: invocation.getArgumentsAs(WeatherArgs.class)
121+
// Or Map-based: invocation.getArguments().get("location")
122+
return CompletableFuture.completedFuture(result);
123+
}
124+
);
125+
```
126+
127+
## Testing Conventions
128+
129+
### E2E Test Structure
130+
131+
Tests extend the shared context pattern:
132+
133+
```java
134+
private static E2ETestContext ctx;
135+
136+
@BeforeAll
137+
static void setup() throws Exception {
138+
ctx = E2ETestContext.create();
139+
}
140+
141+
@AfterAll
142+
static void teardown() throws Exception {
143+
if (ctx != null) ctx.close();
144+
}
145+
146+
@Test
147+
void testFeature() throws Exception {
148+
ctx.configureForTest("category", "test_name"); // Loads test/snapshots/category/test_name.yaml
149+
try (CopilotClient client = ctx.createClient()) {
150+
// Test logic
151+
}
152+
}
153+
```
154+
155+
### Snapshot Naming
156+
157+
Test method names are converted to lowercase snake_case for snapshot filenames to avoid case collisions on macOS/Windows.
158+
159+
## JSON Serialization
160+
161+
- Uses Jackson with `@JsonProperty` annotations
162+
- `@JsonInclude(JsonInclude.Include.NON_NULL)` on DTOs to omit null fields
163+
- `ObjectMapper` configured via `JsonRpcClient.getObjectMapper()` with:
164+
- `JavaTimeModule` for date/time handling
165+
- `FAIL_ON_UNKNOWN_PROPERTIES = false` for forward compatibility
166+
167+
## Documentation
168+
169+
- Site docs in `src/site/markdown/` (filtered for `${project.version}` substitution)
170+
- Update `src/site/site.xml` when adding new documentation pages
171+
- Javadoc required for public APIs except `json` and `events` packages (self-documenting DTOs)

0 commit comments

Comments
 (0)