# How to Use the GitHub Copilot SDK with Rust: Building Async AI Assistants

> Master the GitHub Copilot SDK with Rust to build async AI assistants. Embed managed sessions, custom tools, and real-time event streaming leveraging the power of Copilot CLI.

- Repository: [GitHub/copilot-sdk](https://github.com/github/copilot-sdk)
- Tags: how-to-guide
- Published: 2026-06-06

---

**The GitHub Copilot SDK for Rust provides an async-first JSON-RPC client that wraps the Copilot CLI, enabling you to embed AI-powered assistants with managed sessions, custom tools, and real-time event streaming.**

The `github/copilot-sdk` repository delivers a high-level Rust crate designed specifically for integrating GitHub Copilot capabilities into native Rust applications. This **GitHub Copilot SDK with Rust** abstracts the complexity of process management and authentication by communicating with the Copilot CLI over JSON-RPC, offering a typed, non-blocking API built on Tokio that handles everything from binary resolution to OpenTelemetry trace propagation.

## Core Architecture

The SDK centers on four primary components that manage the CLI lifecycle and conversation state.

**Client** (`rust/src/lib.rs#L47-L75`)  
The **Client** struct serves as the main entry point, spawning or connecting to the Copilot CLI process and managing JSON-RPC traffic. It is `Clone`-able, allowing shared access across async tasks without restarting the underlying process.

**ClientOptions** (`rust/src/lib.rs#L90-L108`)  
Configuration follows a builder pattern through **ClientOptions**, which specifies the CLI binary resolution strategy (**CliProgram**), transport method (**Transport**), authentication tokens, telemetry settings, and operational mode (**ClientMode**).

**Session** (`rust/src/session.rs#L136-L155`)  
A **Session** represents a single Copilot conversation thread. It exposes methods like `send`, `send_and_wait`, and `subscribe` for event streaming, plus `disconnect` for lifecycle management.

**Handler and Tool Modules**  
The `handler` module ([`rust/src/handler.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/handler.rs)) defines traits for **UserInputHandler** and **PermissionHandler**, letting you inject custom logic for approvals and prompts. The `tool` module ([`rust/src/tool.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/tool.rs)) provides a typed framework for exposing Rust functions as callable tools to the Copilot agent.

## Initializing the Client

To begin, create a **Client** using `Client::start` with default or custom options. The SDK automatically resolves the CLI binary through `COPILOT_CLI_PATH`, embedded binaries (via the `bundled-cli` feature), or development cache paths.

```rust
use github_copilot_sdk::{Client, ClientOptions};

#[tokio::main]
async fn main() -> Result<(), github_copilot_sdk::Error> {
    // Spawns the Copilot CLI process automatically
    let client = Client::start(ClientOptions::default()).await?;
    Ok(())
}

```

**Transport Options**  
The **Transport** enum supports three modes:
- **Stdio** (default): Spawns CLI as a subprocess and communicates over stdin/stdout.
- **Tcp**: Spawns CLI with `--port` and connects via TCP.
- **External**: Connects to a pre-existing server instance.

## Creating and Configuring Sessions

Before spawning a session, build a **SessionConfig** (`rust/src/types.rs#L109-120`) to define behavior handlers and streaming preferences.

```rust
use github_copilot_sdk::types::{SessionConfig, SessionId};
use github_copilot_sdk::handler::{ApproveAllHandler, UserInputHandler};
use std::sync::Arc;

let config = SessionConfig::default()
    .with_permission_handler(Arc::new(ApproveAllHandler))
    .with_streaming(true);

```

Create the session using `client.create_session(config).await?`, which returns a **Session** object containing a unique `SessionId` and event channels.

## Sending Messages and Streaming Responses

The SDK supports both fire-and-forget and blocking message patterns via **MessageOptions**.

**Blocking with Timeout**  
Use `send_and_wait` when you need the complete response before proceeding:

```rust
use github_copilot_sdk::types::MessageOptions;
use std::time::Duration;

session
    .send_and_wait(
        MessageOptions::new("Explain this code")
            .with_wait_timeout(Duration::from_secs(120))
    )
    .await?;

```

**Streaming Events**  
For real-time token streaming, subscribe to the session's event receiver before sending:

```rust
let mut events = session.subscribe();

// Spawn listener task
tokio::spawn(async move {
    while let Ok(event) = events.recv().await {
        if event.event_type == "assistant.message_delta" {
            if let Some(delta) = event.data.get("deltaContent").and_then(|c| c.as_str()) {
                print!("{delta}");
            }
        }
    }
});

```

## Handling User Input and Permissions

Implement the **UserInputHandler** trait to intercept agent prompts and provide responses programmatically or via UI.

```rust
use async_trait::async_trait;
use github_copilot_sdk::handler::{UserInputHandler, UserInputResponse};
use github_copilot_sdk::types::SessionId;

struct StdinHandler;

#[async_trait]
impl UserInputHandler for StdinHandler {
    async fn handle(
        &self,
        _session_id: SessionId,
        question: String,
        _choices: Option<Vec<String>>,
        _allow_freeform: Option<bool>
    ) -> Option<UserInputResponse> {
        println!("[agent asks] {}", question);
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).ok()?;
        Some(UserInputResponse {
            answer: input.trim().to_string(),
            was_freeform: true
        })
    }
}

```

For automated environments, **ApproveAllHandler** automatically grants all permission requests, while **ClientMode::Empty** disables global keychain access for multi-tenant security.

## Implementing Custom Tools

Expose internal Rust functions to the Copilot agent by implementing the **Tool** trait from [`rust/src/tool.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/tool.rs).

```rust
use async_trait::async_trait;
use github_copilot_sdk::tool::{Tool, ToolResult, ToolResultOutput};

struct EchoTool;

#[async_trait]
impl Tool for EchoTool {
    fn name(&self) -> &'static str { "echo" }
    
    fn description(&self) -> &'static str { 
        "Echoes the provided input back to the agent." 
    }
    
    async fn run(&self, input: String) -> ToolResult {
        ToolResult::new(ToolResultOutput::new(input))
    }
}

```

Register tools via `SessionConfig::with_tool_set` before creating the session. See [`rust/examples/tool_server.rs`](https://github.com/github/copilot-sdk/blob/main/rust/examples/tool_server.rs) for a complete implementation including the tool server setup.

## Working with Virtual Filesystems

For sandboxed environments, configure **SessionFS** (`rust/src/session_fs.rs#L60-L85`) to provide a virtual filesystem backed by SQLite instead of host disk access.

```rust
use github_copilot_sdk::session_fs::{SessionFsConfig, SessionFsCapabilities};
use std::path::PathBuf;

let fs_config = SessionFsConfig {
    initial_cwd: PathBuf::from("/workspace"),
    session_state_path: PathBuf::from("/tmp/session_state.sqlite"),
    capabilities: Some(SessionFsCapabilities { sqlite: true }),
    ..Default::default()
};

let client = Client::start(
    ClientOptions::default()
        .with_session_fs(fs_config)
).await?;

```

This pattern is essential for stateful agents or code generation scenarios requiring isolated filesystem contexts.

## Security and Telemetry Considerations

The SDK implements several security-conscious design decisions:

- **Token Redaction**: Authentication tokens display as `<redacted>` in `Debug` output to prevent accidental logging.
- **Environment Isolation**: Telemetry and W3C trace context propagate via environment variables to the CLI process without exposing sensitive data to the application logs.
- **Binary Verification**: Automatic resolution follows a strict precedence: explicit `COPILOT_CLI_PATH`, embedded binary, then development cache.

## Summary

- The **GitHub Copilot SDK with Rust** wraps the CLI via JSON-RPC, providing async methods in [`rust/src/lib.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/lib.rs) and [`rust/src/session.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/session.rs).
- **Client** manages process lifecycle and supports `Clone` for shared access; **Session** handles individual conversation state.
- Configure behavior through **ClientOptions** (transport, auth, telemetry) and **SessionConfig** (handlers, streaming, tools).
- Implement **UserInputHandler** and **PermissionHandler** traits to customize interaction flows.
- Use **Tool** trait implementations to expose Rust functions as callable capabilities to Copilot agents.
- Enable **SessionFS** for sandboxed filesystem operations via SQLite-backed virtual directories.

## Frequently Asked Questions

### How does the SDK communicate with the Copilot service?

The SDK does not communicate directly with GitHub's APIs. Instead, it spawns the official Copilot CLI as a subprocess and exchanges JSON-RPC messages over stdio (or TCP), as implemented in `rust/src/lib.rs#L78-L86`. The CLI handles all upstream authentication and API calls, while the SDK manages the process lifecycle and Rust-side abstractions.

### Can I use the SDK in a multi-tenant or serverless environment?

Yes. Set **ClientMode::Empty** in your **ClientOptions** to disable global keychain access, and use **ApproveAllHandler** for automated permission management. Combine this with **SessionFS** for isolated virtual filesystems per session, ensuring tenants cannot access each other's data or host filesystem.

### What async runtime does the GitHub Copilot SDK require?

The SDK is built exclusively on **Tokio** and requires a Tokio runtime. All I/O operations are non-blocking, and the internal `jsonrpc::JsonRpcClient` uses background tasks to dispatch notifications to subscribers while buffering requests and responses.

### How do I handle authentication tokens securely?

The SDK reads tokens from environment variables or configuration but redacts them in all `Debug` implementations, displaying `<redacted>` instead of the actual value. Never log **ClientOptions** using `{:?}` if you have manually included tokens in custom fields; rely on the built-in redaction mechanisms in [`rust/src/lib.rs`](https://github.com/github/copilot-sdk/blob/main/rust/src/lib.rs).