How to Implement Session Persistence and Resume Sessions in the Copilot SDK
To implement session persistence with the Copilot SDK, create a session with a deterministic session_id and call disconnect() before exiting; later, use resumeSession() with the same ID to restore conversation history and state from ~/.copilot/session-state/.
The Copilot SDK treats a session as a first-class object that holds conversation history, tool call results, and planning state. By default, this state exists only in memory, but the SDK provides automatic disk persistence when you supply a custom session identifier. This guide demonstrates how to implement resumable sessions across process restarts and container deployments using the official github/copilot-sdk repository.
Understanding Session Persistence Architecture
The SDK’s persistence mechanism centers on deterministic identifiers and JSON checkpoints. When you create a session with a specific ID, the SDK automatically serializes conversation turns to disk after each interaction.
Core Components
CopilotClient ([go/client.go](https://github.com/github/copilot-sdk/blob/main/go/client.go)) serves as the entry point, providing CreateSession and ResumeSession methods. When calling CreateSession, the client initializes a storage directory under ~/.copilot/session-state/<session_id>/.
Session ([go/session.go](https://github.com/github/copilot-sdk/blob/main/go/session.go)) manages the live conversation loop and implements two critical methods:
Disconnect()releases in-memory resources while preserving on-disk stateDeleteSession()permanently erases the storage directory and all checkpoints
ResumeSessionConfig ([go/types.go](https://github.com/github/copilot-sdk/blob/main/go/types.go#L1640)) allows you to override configuration when resuming, including model selection and provider credentials for BYOK (Bring Your Own Key) scenarios.
Persistence Layer ([session-persistence.md](https://github.com/github/copilot-sdk/blob/main/docs/features/session-persistence.md)) handles serialization of conversation turns into numbered JSON checkpoints (001.json, 002.json, etc.) alongside plan files and generated artifacts.
Implementing Resumable Sessions
To survive process restarts, you must create sessions with deterministic IDs rather than auto-generated UUIDs. The following examples demonstrate the pattern across all supported languages.
TypeScript (Node.js)
import { CopilotClient } from "@github/copilot-sdk";
const client = new CopilotClient();
// Create with deterministic ID
const session = await client.createSession({
sessionId: "alice-code-review-1706932800000",
model: "gpt-5.2-codex",
});
await session.sendAndWait({ prompt: "Review this pull request" });
await session.disconnect(); // Persists to disk
// Later: resume exactly where you left off
const resumed = await client.resumeSession("alice-code-review-1706932800000");
await resumed.sendAndWait({ prompt: "Continue the review" });
Python
from copilot import CopilotClient
from copilot.session import PermissionHandler
client = CopilotClient()
await client.start()
# Create resumable session
session = await client.create_session(
session_id="bob-deploy-1706932800",
model="gpt-5.2-codex",
on_permission_request=PermissionHandler.approve_all,
)
await session.send_and_wait("Deploy the new version")
await session.disconnect() # State saved to ~/.copilot/session-state/
# Resume across restarts
session = await client.resume_session(
"bob-deploy-1706932800",
on_permission_request=PermissionHandler.approve_all,
)
await session.send_and_wait("Check deployment status")
Go
package main
import (
"context"
copilot "github.com/github/copilot-sdk/go"
)
func main() {
ctx := context.Background()
client := copilot.NewClient(nil)
// Create with custom ID
sess, _ := client.CreateSession(ctx, &copilot.SessionConfig{
SessionID: "carol-analysis-1706932800",
Model: "gpt-5.2-codex",
})
sess.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Analyze repository"})
sess.Disconnect() // Keeps state for resumption
// Resume later
resumed, _ := client.ResumeSession(ctx, "carol-analysis-1706932800", nil)
resumed.SendAndWait(ctx, copilot.MessageOptions{Prompt: "Continue analysis"})
}
C# (.NET)
using GitHub.Copilot;
var client = new CopilotClient();
// Create persistent session
var session = await client.CreateSessionAsync(new SessionConfig {
SessionId = "dave-codegen-1706932800",
Model = "gpt-5.2-codex",
});
await session.SendAndWaitAsync(new MessageOptions { Prompt = "Generate CRUD API" });
await session.DisconnectAsync(); // Persist to disk
// Resume in new process
var resumed = await client.ResumeSessionAsync("dave-codegen-1706932800");
await resumed.SendAndWaitAsync(new MessageOptions { Prompt = "Add unit tests" });
Session Lifecycle Management
Effective session persistence requires understanding the distinction between pausing and terminating sessions, plus handling authentication secrets correctly.
Creating Deterministic Session IDs
Without an explicit session_id, the SDK generates random UUIDs that cannot be recovered after a restart. Use a structured pattern encoding user identity and task context, such as user-{uid}-{task}-{timestamp}, to ensure you can reconstruct the identifier in future processes.
Disconnect vs Delete
Call Disconnect() when you want to pause work while preserving state for later resumption. This method releases memory and network resources but leaves the ~/.copilot/session-state/<session_id>/ directory intact.
Call DeleteSession() only when the workflow is complete and you want to free disk space. This operation permanently removes all checkpoints and artifacts, making the session unrecoverable.
Handling Secrets and BYOK
Secrets are never persisted to disk. API keys and provider credentials are explicitly excluded from serialization as a security measure. When resuming a session created with a custom provider, you must re-provide the credentials via ResumeSessionConfig:
const resumed = await client.resumeSession("alice-task-456", {
model: "claude-sonnet-4",
provider: {
type: "azure",
apiKey: process.env.AZURE_OPENAI_KEY, // Required again
endpoint: "https://my-resource.openai.azure.com",
deploymentId: "my-deployment",
},
});
Deployment Patterns for Containerized Environments
For containerized or serverless deployments, mount ~/.copilot/session-state/ to a persistent volume (Azure File Share, AWS EFS, or persistent volume claims in Kubernetes) so that state survives pod restarts or migrations.
Configure idle timeout handling via CopilotClientOptions.sessionIdleTimeoutSeconds to automatically clean up inactive sessions. A value of 0 disables automatic deletion, while positive values trigger server-side cleanup after the specified seconds of inactivity.
For multi-tenant SaaS applications, implement one CLI server per user with isolated storage mounts to prevent session ID collisions. Alternatively, a shared CLI server requires application-level access control to validate session ownership before resumption.
Summary
- Deterministic IDs: Always supply a custom
session_idwhen callingcreateSession()to enable future resumption. - Automatic checkpoints: The SDK writes JSON checkpoints after each conversation turn to
~/.copilot/session-state/<session_id>/without requiring explicit save calls. - Pause with disconnect: Use
disconnect()to preserve state on disk while releasing memory resources. - Re-authenticate on resume: BYOK credentials and API keys must be provided again via
ResumeSessionConfigas they are never written to disk. - Persistent volumes: Mount the session state directory to external storage for containerized deployments to survive restarts.
Frequently Asked Questions
How does the Copilot SDK store session data?
The SDK serializes conversation history, tool results, and planning state into numbered JSON checkpoint files (001.json, 002.json, etc.) stored in ~/.copilot/session-state/<session_id>/. This occurs automatically after each interaction when you provide a deterministic session_id during session creation.
Can multiple processes resume the same session simultaneously?
No, the SDK does not implement file locking for session directories. If multiple processes might access the same session, your application must implement distributed locking (e.g., using Redis or database locks) to prevent corruption of the checkpoint files.
What happens to API keys when a session is persisted?
API keys and provider credentials are never written to disk. When you resume a session using resumeSession(), you must provide the provider configuration and secrets again through the ResumeSessionConfig object, even if they were present during the original session creation.
How do I clean up old sessions permanently?
Use the deleteSession() method (or language-specific equivalent) and pass the session_id. This removes the entire directory under ~/.copilot/session-state/ and all associated checkpoints, plan files, and artifacts, freeing disk space and preventing future resumption of that specific session.
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 →