Use when the user needs guidance on copilot-sdk-go. GitHub Copilot instruction from the awesome-copilot collection.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill ghcopilot-instr-copilot-sdk-go --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Ghcopilot Instr Copilot Sdk Go?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-ghcopilot-instr-copilot-sdk-go)More formats (shields.io, HTML) on the badges page.
---
name: ghcopilot-instr-copilot-sdk-go
description: "Use when the user needs guidance on copilot-sdk-go. GitHub Copilot instruction from the awesome-copilot collection."
license: CC-BY-NC-SA-4.0
metadata:
version: "1.0.0"
tags: [copilot-instruction, community, copilot-sdk-go]
applyTo: "**.go, go.mod"
source: "awesome-copilot"
---
## Core Principles
- The SDK is in technical preview and may have breaking changes
- Requires Go 1.21 or later
- Requires GitHub Copilot CLI installed and in PATH
- Uses goroutines and channels for concurrent operations
- No external dependencies beyond the standard library
## Installation
Always install via Go modules:
```bash
go get github.com/github/copilot-sdk/go
```
## Client Initialization
### Basic Client Setup
```go
import "github.com/github/copilot-sdk/go"
client := copilot.NewClient(nil)
if err := client.Start(); err != nil {
log.Fatal(err)
}
defer client.Stop()
```
### Client Configuration Options
When creating a CopilotClient, use `ClientOptions`:
- `CLIPath` - Path to CLI executable (default: "copilot" from PATH)
- `CLIUrl` - URL of existing CLI server (e.g., "localhost:8080"). When provided, client won't spawn a process
- `Port` - Server port (default: 0 for random)
- `UseStdio` - Use stdio transport instead of TCP (default: true)
- `LogLevel` - Log level (default: "info")
- `AutoStart` - Auto-start server (default: true, use pointer: `boolPtr(true)`)
- `AutoRestart` - Auto-restart on crash (default: true, use pointer: `boolPtr(true)`)
- `Cwd` - Working directory for the CLI process
- `Env` - Environment variables for the CLI process ([]string)
### Manual Server Control
For explicit control:
```go
autoStart := false
client := copilot.NewClient(&copilot.ClientOptions{AutoStart: &autoStart})
if err := client.Start(); err != nil {
log.Fatal(err)
}
// Use client...
client.Stop()
```
Use `ForceStop()` when `Stop()` takes too long.
## Session Management
### Creating Sessions
Use `SessionConfig` for configuration:
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
Streaming: true,
Tools: []copilot.Tool{...},
SystemMessage: &copilot.SystemMessageConfig{ ... },
AvailableTools: []string{"tool1", "tool2"},
ExcludedTools: []string{"tool3"},
Provider: &copilot.ProviderConfig{ ... },
})
if err != nil {
log.Fatal(err)
}
```
### Session Config Options
- `SessionID` - Custom session ID
- `Model` - Model name ("gpt-5", "claude-sonnet-4.5", etc.)
- `Tools` - Custom tools exposed to the CLI ([]Tool)
- `SystemMessage` - System message customization (\*SystemMessageConfig)
- `AvailableTools` - Allowlist of tool names ([]string)
- `ExcludedTools` - Blocklist of tool names ([]string)
- `Provider` - Custom API provider configuration (BYOK) (\*ProviderConfig)
- `Streaming` - Enable streaming response chunks (bool)
- `MCPServers` - MCP server configurations
- `CustomAgents` - Custom agent configurations
- `ConfigDir` - Config directory override
- `SkillDirectories` - Skill directories ([]string)
- `DisabledSkills` - Disabled skills ([]string)
### Resuming Sessions
```go
session, err := client.ResumeSession("session-id", &copilot.ResumeSessionConfig{OnPermissionRequest: copilot.PermissionHandler.ApproveAll})
// Or with options:
session, err := client.ResumeSessionWithOptions("session-id", &copilot.ResumeSessionConfig{ ... })
```
### Session Operations
- `session.SessionID` - Get session identifier (string)
- `session.Send(copilot.MessageOptions{Prompt: "...", Attachments: []copilot.Attachment{...}})` - Send message, returns (messageID string, error)
- `session.SendAndWait(options, timeout)` - Send and wait for idle, returns (\*SessionEvent, error)
- `session.Abort()` - Abort current processing, returns error
- `session.GetMessages()` - Get all events/messages, returns ([]SessionEvent, error)
- `session.Destroy()` - Clean up session, returns error
## Event Handling
### Event Subscription Pattern
ALWAYS use channels or done signals to wait for session events:
```go
done := make(chan struct{})
unsubscribe := session.On(func(evt copilot.SessionEvent) {
switch evt.Type {
case copilot.AssistantMessage:
fmt.Println(*evt.Data.Content)
case copilot.SessionIdle:
close(done)
}
})
defer unsubscribe()
session.Send(copilot.MessageOptions{Prompt: "..."})
<-done
```
### Unsubscribing from Events
The `On()` method returns a function that unsubscribes:
```go
unsubscribe := session.On(func(evt copilot.SessionEvent) {
// handler
})
// Later...
unsubscribe()
```
### Event Types
Use type switches for event handling:
```go
session.On(func(evt copilot.SessionEvent) {
switch evt.Type {
case copilot.UserMessage:
// Handle user message
case copilot.AssistantMessage:
if evt.Data.Content != nil {
fmt.Println(*evt.Data.Content)
}
case copilot.ToolExecutionStart:
// Tool execution started
case copilot.ToolExecutionComplete:
// Tool execution completed
case copilot.SessionStart:
// Session started
case copilot.SessionIdle:
// Session is idle (processing complete)
case copilot.SessionError:
if evt.Data.Message != nil {
fmt.Println("Error:", *evt.Data.Message)
}
}
})
```
## Streaming Responses
### Enabling Streaming
Set `Streaming: true` in SessionConfig:
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
Streaming: true,
})
```
### Handling Streaming Events
Handle both delta events (incremental) and final events:
```go
done := make(chan struct{})
session.On(func(evt copilot.SessionEvent) {
switch evt.Type {
case copilot.AssistantMessageDelta:
// Incremental text chunk
if evt.Data.DeltaContent != nil {
fmt.Print(*evt.Data.DeltaContent)
}
case copilot.AssistantReasoningDelta:
// Incremental reasoning chunk (model-dependent)
if evt.Data.DeltaContent != nil {
fmt.Print(*evt.Data.DeltaContent)
}
case copilot.AssistantMessage:
// Final complete message
fmt.Println("\n--- Final ---")
if evt.Data.Content != nil {
fmt.Println(*evt.Data.Content)
}
case copilot.AssistantReasoning:
// Final reasoning content
fmt.Println("--- Reasoning ---")
if evt.Data.Content != nil {
fmt.Println(*evt.Data.Content)
}
case copilot.SessionIdle:
close(done)
}
})
session.Send(copilot.MessageOptions{Prompt: "Tell me a story"})
<-done
```
Note: Final events (`AssistantMessage`, `AssistantReasoning`) are ALWAYS sent regardless of streaming setting.
## Custom Tools
### Defining Tools
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
Tools: []copilot.Tool{
{
Name: "lookup_issue",
Description: "Fetch issue details from tracker",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"id": map[string]interface{}{
"type": "string",
"description": "Issue ID",
},
},
"required": []string{"id"},
},
Handler: func(inv copilot.ToolInvocation) (copilot.ToolResult, error) {
args := inv.Arguments.(map[string]interface{})
issueID := args["id"].(string)
issue, err := fetchIssue(issueID)
if err != nil {
return copilot.ToolResult{}, err
}
return copilot.ToolResult{
TextResultForLLM: fmt.Sprintf("Issue: %v", issue),
ResultType: "success",
ToolTelemetry: map[string]interface{}{},
}, nil
},
},
},
})
```
### Tool Return Types
- Return `ToolResult` struct with fields:
- `TextResultForLLM` (string) - Result text for the LLM
- `ResultType` (string) - "success" or "failure"
- `Error` (string, optional) - Internal error message (not shown to LLM)
- `ToolTelemetry` (map[string]interface{}) - Telemetry data
### Tool Execution Flow
When Copilot invokes a tool, the client automatically:
1. Runs your handler function
2. Returns the ToolResult
3. Responds to the CLI
## System Message Customization
### Append Mode (Default - Preserves Guardrails)
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
SystemMessage: &copilot.SystemMessageConfig{
Mode: "append",
Content: `
<workflow_rules>
- Always check for security vulnerabilities
- Suggest performance improvements when applicable
</workflow_rules>
`,
},
})
```
### Replace Mode (Full Control - Removes Guardrails)
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
SystemMessage: &copilot.SystemMessageConfig{
Mode: "replace",
Content: "You are a helpful assistant.",
},
})
```
## File Attachments
Attach files to messages using `Attachment`:
```go
messageID, err := session.Send(copilot.MessageOptions{
Prompt: "Analyze this file",
Attachments: []copilot.Attachment{
{
Type: "file",
Path: "/path/to/file.go",
DisplayName: "My File",
},
},
})
```
## Message Delivery Modes
Use the `Mode` field in `MessageOptions`:
- `"enqueue"` - Queue message for processing
- `"immediate"` - Process message immediately
```go
session.Send(copilot.MessageOptions{
Prompt: "...",
Mode: "enqueue",
})
```
## Multiple Sessions
Sessions are independent and can run concurrently:
```go
session1, _ := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
})
session2, _ := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "claude-sonnet-4.5",
})
session1.Send(copilot.MessageOptions{Prompt: "Hello from session 1"})
session2.Send(copilot.MessageOptions{Prompt: "Hello from session 2"})
```
## Bring Your Own Key (BYOK)
Use custom API providers by configuring `ProviderConfig`:
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Provider: &copilot.ProviderConfig{
Type: "openai",
BaseURL: "https://api.openai.com/v1",
APIKey: "your-api-key",
},
})
```
## Session Lifecycle Management
### Checking Connection State
```go
state := client.GetState()
// Returns: "disconnected", "connecting", "connected", or "error"
```
## Error Handling
### Standard Exception Handling
```go
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
log.Fatalf("Failed to create session: %v", err)
}
_, err = session.Send(copilot.MessageOptions{Prompt: "Hello"})
if err != nil {
log.Printf("Failed to send: %v", err)
}
```
### Session Error Events
Monitor `SessionError` type for runtime errors:
```go
session.On(func(evt copilot.SessionEvent) {
if evt.Type == copilot.SessionError {
if evt.Data.Message != nil {
fmt.Fprintf(os.Stderr, "Session Error: %s\n", *evt.Data.Message)
}
}
})
```
## Connectivity Testing
Use `Ping` to verify server connectivity:
```go
resp, err := client.Ping("test message")
if err != nil {
log.Printf("Server unreachable: %v", err)
} else {
log.Printf("Server responded at %d", resp.Timestamp)
}
```
## Resource Cleanup
### Cleanup with Defer
ALWAYS use `defer` for cleanup:
```go
client := copilot.NewClient(nil)
if err := client.Start(); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(&copilot.SessionConfig{OnPermissionRequest: copilot.PermissionHandler.ApproveAll})
if err != nil {
log.Fatal(err)
}
defer session.Destroy()
```
### Manual Cleanup
If not using defer:
```go
client := copilot.NewClient(nil)
err := client.Start()
if err != nil {
log.Fatal(err)
}
session, err := client.CreateSession(&copilot.SessionConfig{OnPermissionRequest: copilot.PermissionHandler.ApproveAll})
if err != nil {
client.Stop()
log.Fatal(err)
}
// Use session...
session.Destroy()
errors := client.Stop()
for _, err := range errors {
log.Printf("Cleanup error: %v", err)
}
```
## Best Practices
1. **Always use `defer`** for cleanup of clients and sessions
2. **Use channels** to wait for SessionIdle event
3. **Handle SessionError** events for robust error handling
4. **Use type switches** for event handling
5. **Enable streaming** for better UX in interactive scenarios
6. **Provide descriptive tool names and descriptions** for better model understanding
7. **Call unsubscribe functions** when no longer needed
8. **Use SystemMessageConfig with Mode: "append"** to preserve safety guardrails
9. **Handle both delta and final events** when streaming is enabled
10. **Check nil pointers** in event data (Content, Message, etc. are pointers)
## Common Patterns
### Simple Query-Response
```go
client := copilot.NewClient(nil)
if err := client.Start(); err != nil {
log.Fatal(err)
}
defer client.Stop()
session, err := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Model: "gpt-5",
})
if err != nil {
log.Fatal(err)
}
defer session.Destroy()
done := make(chan struct{})
session.On(func(evt copilot.SessionEvent) {
if evt.Type == copilot.AssistantMessage && evt.Data.Content != nil {
fmt.Println(*evt.Data.Content)
} else if evt.Type == copilot.SessionIdle {
close(done)
}
})
session.Send(copilot.MessageOptions{Prompt: "What is 2+2?"})
<-done
```
### Multi-Turn Conversation
```go
session, _ := client.CreateSession(&copilot.SessionConfig{OnPermissionRequest: copilot.PermissionHandler.ApproveAll})
defer session.Destroy()
sendAndWait := func(prompt string) error {
done := make(chan struct{})
var eventErr error
unsubscribe := session.On(func(evt copilot.SessionEvent) {
switch evt.Type {
case copilot.AssistantMessage:
if evt.Data.Content != nil {
fmt.Println(*evt.Data.Content)
}
case copilot.SessionIdle:
close(done)
case copilot.SessionError:
if evt.Data.Message != nil {
eventErr = fmt.Errorf(*evt.Data.Message)
}
}
})
defer unsubscribe()
if _, err := session.Send(copilot.MessageOptions{Prompt: prompt}); err != nil {
return err
}
<-done
return eventErr
}
sendAndWait("What is the capital of France?")
sendAndWait("What is its population?")
```
### SendAndWait Helper
```go
// Use built-in SendAndWait for simpler synchronous interaction
response, err := session.SendAndWait(copilot.MessageOptions{
Prompt: "What is 2+2?",
}, 0) // 0 uses default 60s timeout
if err != nil {
log.Printf("Error: %v", err)
}
if response != nil && response.Data.Content != nil {
fmt.Println(*response.Data.Content)
}
```
### Tool with Struct Return Type
```go
type UserInfo struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Role string `json:"role"`
}
session, _ := client.CreateSession(&copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
Tools: []copilot.Tool{
{
Name: "get_user",
Description: "Retrieve user information",
Parameters: map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"user_id": map[string]interface{}{
"type": "string",
"description": "User ID",
},
},
"required": []string{"user_id"},
},
Handler: func(inv copilot.ToolInvocation) (copilot.ToolResult, error) {
args := inv.Arguments.(map[string]interface{})
userID := args["user_id"].(string)
user := UserInfo{
ID: userID,
Name: "John Doe",
Email: "john@example.com",
Role: "Developer",
}
jsonBytes, _ := json.Marshal(user)
return copilot.ToolResult{
TextResultForLLM: string(jsonBytes),
ResultType: "success",
ToolTelemetry: map[string]interface{}{},
}, nil
},
},
},
})
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!