# Copilot Instructions for copilot-sdk-java A Java SDK for programmatic control of GitHub Copilot CLI. This is a community-driven port of the official .NET SDK, targeting Java 17+. ## About These Instructions These instructions guide GitHub Copilot when assisting with this repository. They cover: - **Tech Stack**: Java 17+, Maven, Jackson for JSON, JUnit for testing - **Purpose**: Provide a Java SDK for programmatic control of GitHub Copilot CLI - **Architecture**: JSON-RPC client communicating with Copilot CLI over stdio - **Key Goals**: Maintain parity with upstream .NET SDK while following Java idioms ## Build & Test Commands ```bash # Build and run all tests mvn clean verify # Run a single test class mvn test -Dtest=CopilotClientTest # Run a single test method mvn test -Dtest=ToolsTest#testToolInvocation # Format code (required before commit) mvn spotless:apply # Check formatting only mvn spotless:check # Build without tests mvn clean package -DskipTests # Run tests with debug logging mvn test -Pdebug ``` ## Architecture ### Core Components - **CopilotClient** - Main entry point. Manages connection to Copilot CLI server via JSON-RPC over stdio. Spawns CLI process or connects to existing server. - **CopilotSession** - Represents a conversation session. Handles event subscriptions, tool registration, permissions, and message sending. - **JsonRpcClient** - Low-level JSON-RPC protocol implementation using Jackson for serialization. ### Package Structure - `com.github.copilot.sdk` - Core classes (CopilotClient, CopilotSession, JsonRpcClient) - `com.github.copilot.sdk.json` - DTOs, request/response types, handler interfaces (SessionConfig, MessageOptions, ToolDefinition, etc.) - `com.github.copilot.sdk.events` - Event types for session streaming (AssistantMessageEvent, SessionIdleEvent, ToolExecutionStartEvent, etc.) ### Test Infrastructure 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/`. - **E2ETestContext** - Manages test environment with CapiProxy for deterministic API responses - **CapiProxy** - Node.js-based replaying proxy using YAML snapshots from `test/snapshots/` - Test snapshots are stored in the upstream repo's `test/snapshots/` directory ## Key Conventions ### Upstream Merging 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. When porting from .NET: - Adapt to Java idioms, don't copy C# patterns directly - Convert `async/await` → `CompletableFuture` - Convert C# properties → Java getters/setters or fluent setters - Use Jackson for JSON (`ObjectMapper`, `@JsonProperty`) ### Code Style - 4-space indentation (enforced by Spotless with Eclipse formatter) - Fluent setter pattern for configuration classes (e.g., `new SessionConfig().setModel("gpt-5").setTools(tools)`) - Public APIs require Javadoc (enforced by Checkstyle, except `json` and `events` packages) - Pre-commit hook runs `mvn spotless:check` - enable with: `git config core.hooksPath .githooks` ### Handler Pattern Handlers use functional interfaces with `CompletableFuture` returns: ```java session.createSession(new SessionConfig() .setOnPermissionRequest((request, invocation) -> CompletableFuture.completedFuture(new PermissionRequestResult().setKind("allow"))) .setOnUserInput((request, invocation) -> CompletableFuture.completedFuture(new UserInputResponse().setResponse("user input"))) ); ``` ### Event Handling Sessions emit typed events via `session.on()`: ```java session.on(AssistantMessageEvent.class, msg -> System.out.println(msg.getData().getContent())); session.on(SessionIdleEvent.class, idle -> done.complete(null)); ``` ### Sealed Event Hierarchy `AbstractSessionEvent` is a sealed class permitting specific event types. Use pattern matching: ```java switch (event) { case AssistantMessageEvent msg -> handleMessage(msg); case ToolExecutionStartEvent tool -> handleToolStart(tool); case SessionIdleEvent idle -> handleIdle(); default -> { } } ``` ### Tool Definition Pattern Custom tools use `ToolDefinition.create()` with JSON Schema parameters and a `ToolHandler`: ```java var tool = ToolDefinition.create( "get_weather", "Get weather for a location", Map.of( "type", "object", "properties", Map.of("location", Map.of("type", "string")), "required", List.of("location") ), invocation -> { // Type-safe: invocation.getArgumentsAs(WeatherArgs.class) // Or Map-based: invocation.getArguments().get("location") return CompletableFuture.completedFuture(result); } ); ``` ## Testing Conventions ### E2E Test Structure Tests extend the shared context pattern: ```java private static E2ETestContext ctx; @BeforeAll static void setup() throws Exception { ctx = E2ETestContext.create(); } @AfterAll static void teardown() throws Exception { if (ctx != null) ctx.close(); } @Test void testFeature() throws Exception { ctx.configureForTest("category", "test_name"); // Loads test/snapshots/category/test_name.yaml try (CopilotClient client = ctx.createClient()) { // Test logic } } ``` ### Snapshot Naming Test method names are converted to lowercase snake_case for snapshot filenames to avoid case collisions on macOS/Windows. ## JSON Serialization - Uses Jackson with `@JsonProperty` annotations - `@JsonInclude(JsonInclude.Include.NON_NULL)` on DTOs to omit null fields - `ObjectMapper` configured via `JsonRpcClient.getObjectMapper()` with: - `JavaTimeModule` for date/time handling - `FAIL_ON_UNKNOWN_PROPERTIES = false` for forward compatibility ## Documentation - Site docs in `src/site/markdown/` (filtered for `${project.version}` substitution) - Update `src/site/site.xml` when adding new documentation pages - Javadoc required for public APIs except `json` and `events` packages (self-documenting DTOs) - **Copilot CLI Version**: When updating the required Copilot CLI version in `README.md`, also update it in `src/site/markdown/index.md` to keep them in sync ## Boundaries and Restrictions ### What NOT to Modify - **DO NOT** edit `.github/agents/` directory - these contain instructions for other agents - **DO NOT** modify `target/` directory - this contains build artifacts - **DO NOT** edit `pom.xml` dependencies without careful consideration - this SDK has minimal dependencies by design - **DO NOT** change the Jackson version without testing against all serialization patterns - **DO NOT** modify test snapshots in `target/copilot-sdk/test/snapshots/` - these come from upstream - **DO NOT** alter the Eclipse formatter configuration in `pom.xml` without team consensus - **DO NOT** remove or skip Checkstyle or Spotless checks ### Security Guidelines - **NEVER** commit secrets, API keys, tokens, or credentials to the repository - **NEVER** commit `.env` files or any files containing sensitive configuration - **NEVER** log sensitive data in code (API keys, tokens, user data) - Always use `try-with-resources` for streams and readers to prevent resource leaks - Always use `StandardCharsets.UTF_8` when creating InputStreamReader/OutputStreamWriter - Review any new dependencies for known security vulnerabilities before adding them - When handling user input in tools or handlers, consider injection risks ## Dependency Management This SDK is designed to be **lightweight with minimal dependencies**: - Core dependencies: Jackson (JSON), JUnit (tests only) - Before adding new dependencies: 1. Consider if the functionality can be implemented without a new dependency 2. Check if Jackson already provides the needed functionality 3. Ensure the dependency is actively maintained and widely used 4. Verify compatibility with Java 17+ 5. Check for security vulnerabilities 6. Get team approval for non-trivial additions ## Commit and PR Guidelines ### Commit Messages - Use clear, descriptive commit messages - Start with a verb in present tense (e.g., "Add", "Fix", "Update", "Refactor") - Keep the first line under 72 characters - Add details in the body if needed - Examples: - `Add support for streaming responses` - `Fix resource leak in JsonRpcClient` - `Update documentation for tool handlers` - `Refactor event handling to use sealed classes` ### Pull Requests - Keep PRs focused and minimal - one feature/fix per PR - Ensure all tests pass before requesting review - Run `mvn spotless:apply` before committing - Include tests for new functionality - Update documentation if adding/changing public APIs - Reference related issues using `#issue-number` - For upstream merges, follow the `agentic-merge-upstream` skill workflow ## Development Workflow 1. **Setup**: Enable git hooks with `git config core.hooksPath .githooks` 2. **Branch**: Create feature branches from `main` 3. **Code**: Write code following the conventions above 4. **Format**: Run `mvn spotless:apply` to format code 5. **Test**: Run `mvn clean verify` to ensure all tests pass 6. **Commit**: Make focused commits with clear messages 7. **Push**: Push your branch and create a PR 8. **Review**: Address review feedback and iterate