How to Use GitHub Copilot SDK with Python: Complete Implementation Guide
The GitHub Copilot SDK for Python provides an asynchronous wrapper around the Copilot CLI runtime, enabling you to programmatically interact with AI models through CopilotClient and CopilotSession objects using JSON-RPC communication.
The github/copilot-sdk repository offers a thin, official Python interface that manages the Copilot CLI process lifecycle rather than embedding LLM logic directly. By using this SDK, developers can create AI-powered applications that leverage custom tool definitions, permission handling, and streaming responses. This article demonstrates how to use GitHub Copilot SDK with Python, covering everything from basic setup to advanced architectural patterns.
Core Architecture
The SDK architecture rests on three fundamental abstractions that handle process management, protocol communication, and conversation state.
CopilotClient: The Entry Point
Located in python/copilot/client.py, the CopilotClient class serves as the primary async context manager. It launches or connects to a Copilot CLI process and owns the JSON-RPC channel. The client handles connection setup, protocol version negotiation, and lifecycle management across different transport methods.
CopilotSession: Conversation State
Each CopilotSession represents a single conversation thread with the model, created via client.create_session() in python/copilot/session.py. Sessions expose high-level methods including send() for prompts, on() for event handlers, and ui.* helpers for interactive dialogs. Internally, sessions map to RPC endpoints defined in python/copilot/generated/rpc.py.
RuntimeConnection: Transport Layer
The RuntimeConnection abstraction in python/copilot/client.py (lines 98-119) supports three transport modes without requiring code changes elsewhere:
- STDIO: Spawns CLI as child process via stdin/stdout
- TCP: Connects via TCP sockets
- URI: Attaches to an already-running server endpoint
Data Flow
The SDK implements a strict request-response pipeline:
- CopilotClient establishes the transport via
RuntimeConnectionfactories (for_stdio,for_tcp,for_uri) - JSON-RPC channel (
python/copilot/_jsonrpc.py) handles non-blocking message serialization - ServerRpc (
python/copilot/generated/rpc.py) maps to CLI protocol endpoints - CopilotSession dispatches events to user code through handlers
This architecture ensures the SDK remains thin—it forwards all requests to the CLI runtime without embedding model logic.
Installation and Basic Setup
To begin using the GitHub Copilot SDK with Python, install the package from the repository and ensure the Copilot CLI is available in your environment.
pip install git+https://github.com/github/copilot-sdk.git#subdirectory=python
The SDK requires Python 3.8+ and an active GitHub Copilot CLI installation. All interactions are asynchronous, requiring asyncio for execution.
Practical Implementation Patterns
Pattern 1: Basic Async Usage
The most common pattern involves creating a client, spawning a session with auto-approved permissions, sending a prompt, and waiting for completion. This example uses PermissionHandler.approve_all to automatically authorize tool calls:
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler
async def main():
async with CopilotClient() as client:
async with await client.create_session(
on_permission_request=PermissionHandler.approve_all,
model="gpt-4"
) as session:
def on_event(ev):
print(f"Event: {ev.type}")
session.on(on_event)
await session.send("What is the capital of France?")
await session.wait_idle()
asyncio.run(main())
The wait_idle() helper blocks until the session receives SessionIdleData, indicating all processing—including tool execution—has completed.
Pattern 2: Defining Custom Tools with Pydantic
Custom tools extend model capabilities by allowing the CLI to execute Python functions. Define tools using the @define_tool decorator from python/copilot/tools.py, which automatically generates JSON schemas from Pydantic models:
from pydantic import BaseModel, Field
from copilot import CopilotClient, define_tool
from copilot.session import PermissionHandler
class SearchParams(BaseModel):
query: str = Field(description="Search query string")
@define_tool(description="Search documentation")
async def search_docs(params: SearchParams) -> str:
# Implementation: query your documentation database
return f"Results for: {params.query}"
async def main():
async with CopilotClient() as client:
async with await client.create_session(
on_permission_request=PermissionHandler.approve_all,
model="gpt-4",
tools=[search_docs]
) as session:
await session.send("Search for authentication methods")
await session.wait_idle()
asyncio.run(main())
When the model requests a tool call, the SDK routes the tool.call RPC to your decorated function, handles schema validation via Pydantic, and returns results to the conversation.
Pattern 3: Streaming Real-Time Responses
For interactive applications, enable streaming to receive token-by-token updates. Set streaming=True during session creation and handle AssistantMessageDeltaData events:
import asyncio
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.session_events import (
AssistantMessageDeltaData, AssistantMessageData, SessionIdleData
)
async def main():
async with CopilotClient() as client:
async with await client.create_session(
on_permission_request=PermissionHandler.approve_all,
model="gpt-4",
streaming=True
) as session:
complete = asyncio.Event()
def handler(ev):
match ev.data:
case AssistantMessageDeltaData() as d:
print(d.delta_content or "", end="", flush=True)
case AssistantMessageData() as m:
print("\n[Complete]")
case SessionIdleData():
complete.set()
session.on(handler)
await session.send("Explain quantum computing")
await complete.wait()
asyncio.run(main())
The streaming flag instructs the CLI to emit assistant.message_delta events, which the SDK forwards as AssistantMessageDeltaData objects containing incremental content.
Advanced Features and Configuration
Permission Handling
The PermissionHandler class in python/copilot/session.py controls tool execution authorization. Beyond approve_all, you can implement custom logic:
def custom_permission_handler(request):
if request.tool_name == "safe_tool":
return True
return False # Denies by default
UI Elicitation
Sessions expose ui.confirm(), ui.select(), and ui.input() methods that surface native Copilot-CLI dialogs when the runtime supports them, enabling interactive clarification without breaking the JSON-RPC flow.
Telemetry and Tracing
The SDK supports OpenTelemetry via configuration in python/copilot/client.py and python/copilot/_telemetry.py. Trace context propagates automatically across RPC boundaries when telemetry is enabled.
Session Persistence
Configure InfiniteSessionConfig in python/copilot/session.py for background token-window management and persistent workspace states, enabled by default for long-running applications.
Key Source Files Reference
Understanding the SDK layout accelerates debugging and extension:
python/copilot/client.py: MainCopilotClientclass,RuntimeConnectionfactories, telemetry initializationpython/copilot/session.py:CopilotSessionimplementation, permission handling, UI helpers, tool execution routingpython/copilot/tools.py:@define_tooldecorator, low-levelToolclass, schema generationpython/copilot/_jsonrpc.py: Async JSON-RPC client over stdin/stdout or TCPpython/copilot/generated/rpc.py: Auto-generated RPC endpoint definitions matching CLI protocolpython/copilot/generated/session_events.py: Event dataclasses (AssistantMessageDeltaData,SessionIdleData, etc.)
Summary
- The GitHub Copilot SDK for Python wraps the Copilot CLI in an async interface using
CopilotClientand JSON-RPC channels. - Sessions manage conversation state through
CopilotSessionobjects, supporting tools, permissions, and UI interactions. - Transport flexibility allows STDIO, TCP, or URI connections without changing application code.
- Custom tools use the
@define_tooldecorator with Pydantic models for automatic schema generation. - Streaming responses require
streaming=Trueand handlingAssistantMessageDeltaDataevents for real-time output. - All LLM logic resides in the CLI runtime; the SDK acts as a thin, type-safe bridge.
Frequently Asked Questions
What Python version is required for the GitHub Copilot SDK?
The SDK requires Python 3.8 or higher due to its reliance on async/await syntax and modern type hints. All core functionality is implemented using asyncio patterns found in python/copilot/client.py.
Can I use the SDK without installing the Copilot CLI separately?
No. The SDK in github/copilot-sdk is explicitly a thin wrapper that communicates via JSON-RPC with the Copilot CLI process. You must have the CLI binary installed and accessible in your system PATH, as the CopilotClient class spawns or connects to this runtime.
How do I handle tool permissions programmatically?
Pass a handler function to on_permission_request when calling client.create_session() in python/copilot/session.py. Use PermissionHandler.approve_all for automation during development, or implement custom logic that inspects the request object to approve specific tools while rejecting others.
Is streaming supported for all models?
Streaming support depends on the Copilot CLI runtime capabilities rather than the SDK itself. When streaming=True is passed to create_session(), the SDK forwards assistant.message_delta events from python/copilot/generated/session_events.py as they arrive, but the underlying model and CLI version must support streaming tokens.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →