Native Emacs Lisp client library for GitHub Copilot via the Agent Client Protocol (ACP).
This is the SDK — the protocol layer. For the full AI OS experience (chat UI, built-in tools, workflows, metaprogramming), see copilot-emacs.
This is NOT a completion plugin. For inline code completion, use copilot.el.
The Elisp equivalent of the official Copilot SDKs (Node.js, Python, .NET, Go, Java):
- ACP transport — NDJSON (newline-delimited JSON-RPC 2.0) over stdio
- Client lifecycle —
initialize, capability negotiation, version checking - Session management —
session/new,session/prompt,session/cancel,session/load - Event streaming —
session/updatenotifications (text chunks, tool calls, plans) - Permissions —
session/request_permissionhandling - FS/Terminal handlers —
fs/read_text_file,fs/write_text_file,terminal/* - Tool framework — register, unregister, dispatch, JSON Schema helpers, usage stats
copilot-sdk-deftoolmacro — one-expression tool definition with auto-generated schema- Model intelligence — model selection, reasoning effort, reasoning summaries
- Unix citizen tools — sandboxed shell pipelines and system tool discovery
- Settings persistence — model/effort/summaries saved to
~/.copilot/emacs-settings.el - Session resume — list and resume previous CLI sessions
.planfile injection — Unix-tradition context bridge into every prompt- Per-project plan context — org-roam nodes as per-project plans, injected via
<project_plan>tags - BYOK local providers — use Ollama, direct Anthropic/OpenAI, or any OpenAI-compatible endpoint
Looking for tool nursery, skills, and model routing? These application-level features live in copilot-emacs.
- Emacs 27.1+
- Copilot CLI v1.0+ installed and authenticated
git clone https://github.com/lqdev/copilot-sdk-elisp.git(add-to-list 'load-path "/path/to/copilot-sdk-elisp")
(require 'copilot-sdk)
(require 'copilot-sdk-tools) ; tool framework + deftool macro;; Create a client and session
(copilot-sdk-ensure-client)
(let ((session (copilot-sdk-create-session nil)))
;; Send a message and wait for the response
(copilot-sdk-send-and-wait session "What is Emacs?" 30))
;; Async with streaming callbacks
(copilot-sdk-send session "Explain this code"
:on-text (lambda (text) (princ text))
:on-turn-end (lambda (reason) (message "Done: %s" reason)))(copilot-sdk-tools-register
"get-weather"
"Get current weather for a city"
(copilot-sdk-tools--make-schema
`((city . ,(copilot-sdk-tools--string-prop "City name")))
'("city"))
(lambda (args)
(format "Weather in %s: Sunny, 72°F" (alist-get 'city args))))(copilot-sdk-deftool weather
"Get weather for a city"
((city string "City name"))
(format "Weather in %s: Sunny, 72°F" city))One expression creates the function, JSON Schema, and registration.
;; Browse ALL registered tools
M-x copilot-sdk-tools-list-ui
;; In the tools browser:
;; RET — inspect tool details
;; g — refresh;; List available sessions
(copilot-sdk-list-sessions)
;; → (((id . "abc123") (title . "My Plan") (modified . "2025-01-15 10:30")) ...)
;; Resume a session programmatically
(copilot-sdk-load-session "session-id")The SDK reads ~/.plan (configurable) and injects its content into
every prompt as <user_plan> context:
(setq copilot-sdk-plan-file "~/.plan") ; defaultWrite your current goals, projects, or focus areas in this file and the agent will always know what you're working on.
Projects can have their own plan context via org-roam nodes. Set the
project name and the SDK will look up a matching org-roam node to inject
as <project_plan> tags alongside the global .plan:
(setq copilot-sdk--project-name "my-project")The function copilot-sdk--read-project-plan resolves the org-roam node
by title (matching copilot-sdk--project-name) and returns its content.
If no matching node is found, it falls back to ~/.plan.
copilot-sdk-send automatically wraps the project plan in <project_plan>
tags when sending prompts to the agent, giving per-project context without
manual copy-paste.
(setq copilot-sdk-cli-path "/path/to/copilot") ; Custom CLI path
(setq copilot-sdk-log-level "warning") ; CLI log level
(setq copilot-sdk-auto-approve nil) ; Auto-approve permissions (default: nil)Select models, control reasoning effort, and enable reasoning summaries:
;; Set via customize or interactively
(setq copilot-sdk-default-model "claude-sonnet-4") ; nil = agent default
(setq copilot-sdk-reasoning-effort "high") ; nil, "low", "medium", "high", "xhigh"
(setq copilot-sdk-reasoning-summaries t) ; For OpenAI models
;; Interactive commands
M-x copilot-sdk-select-model ; completing-read with available models
M-x copilot-sdk-select-effort ; set reasoning effort
M-x copilot-sdk-toggle-reasoning-summaries ; toggle summaries on/offAll three settings auto-persist to ~/.copilot/emacs-settings.el and are
restored on startup via copilot-sdk-load-settings.
Two built-in tools (registered via copilot-sdk-deftool) let the agent
interact with the host system safely:
Execute shell pipelines with guardrails:
;; The agent can run commands like:
;; ["rg" "pattern", "sort", "uniq -c", "head -20"]
;; Configuration
(setq copilot-sdk-unix-pipe-allowlist '("rg" "sort" "uniq" ...)) ; permitted commands
(setq copilot-sdk-unix-pipe-timeout 30) ; max seconds per pipelineSafety features:
- Allowlist — only commands in
copilot-sdk-unix-pipe-allowlistmay execute - Dangerous pattern rejection —
rm -rf /, fork bombs,dd,mkfsare blocked - Timeout — pipelines killed after
copilot-sdk-unix-pipe-timeoutseconds - Output truncation — capped at 100K characters
Discovers available CLI tools on the host and returns JSON with tool names
and versions. Checks for rg, fd, jq, curl, git, python3,
node, gcc, docker, kubectl, and more.
copilot-sdk.el Core: ACP client, NDJSON transport, JSON-RPC, sessions,
permissions, FS/terminal handlers, event system, native tool
registration, model intelligence, settings persistence
copilot-sdk-tools.el Tool framework: register, dispatch, schema helpers, deftool macro,
usage tracking, tools browser UI, unix-pipe, system-tools
copilot-sdk-local.el BYOK local providers: Ollama, Anthropic, OpenAI, Azure, custom
Emacs ──── NDJSON JSON-RPC 2.0 ────▶ Copilot CLI (--acp --stdio) ──▶ GitHub Copilot
◀─── tool.call ──────────────┘
Tools are registered natively via the tools parameter in session.create.
The CLI invokes them via tool.call JSON-RPC requests over the same connection.
Key methods: initialize, session/new, session/prompt, session/cancel, session/load
Agent→Client: session/update, session/request_permission, fs/*, terminal/*
Full spec: agentclientprotocol.com
| Project | Relationship |
|---|---|
| copilot-emacs | AI OS app built ON this SDK (chat, tools, workflows) |
| copilot.el | Inline completion (different protocol, complementary) |
| copilot-sdk | Official SDKs (Node/Python/Go/.NET) — same scope, different language |
make compile # Byte-compile
make test # Run 132 ERT tests
make lint # Checkdoc linting
make clean # Remove .elc filesThe SDK supports Bring Your Own Key — use local models (Ollama), direct API keys
(Anthropic, OpenAI), or any OpenAI-compatible endpoint. The Copilot CLI handles all
provider connections natively via the provider field in session.create.
# Install and start Ollama
ollama serve
ollama pull qwen2.5-coder:7b(require 'copilot-sdk-local)
;; Create a session with a local model
(let ((session (copilot-sdk-local-create-session
:model "qwen2.5-coder:7b")))
(copilot-sdk-local-send session "Write fizzbuzz in Elisp"
:on-text #'insert))| Provider | Function | Notes |
|---|---|---|
| Ollama | (copilot-sdk-local-ollama-provider) |
Local, no API key needed |
| Anthropic | (copilot-sdk-local-anthropic-provider KEY) |
Direct Claude access |
| OpenAI | (copilot-sdk-local-openai-provider KEY) |
Direct GPT access |
| Azure | (copilot-sdk-local-azure-provider URL KEY) |
Azure OpenAI |
| Foundry Local | (copilot-sdk-local-foundry-provider) |
Microsoft Foundry |
| Custom | (copilot-sdk-local-custom-provider URL) |
Any OpenAI-compatible |
M-x copilot-sdk-local-status— check Ollama server statusM-x copilot-sdk-local-select-model— pick from available Ollama models
See samples/local-providers.el for more examples.
MIT — see LICENSE.