Version 0.4.1
Efrit is an AI coding agent that brings Claude's intelligence directly into Emacs. It can execute natural language commands, explore codebases, run shell commands, and have multi-turn conversations - all while you stay in your editor.
Core principle: Zero client-side intelligence. Claude makes all decisions, Efrit executes.
⚠️ Security Note: Efrit executes AI-generated code in your Emacs. See SECURITY.md for trust model and recommended practices.
Multi-turn conversations with Claude that understand your Emacs context:
- Ask questions about code, get explanations
- Refactor with guidance
- Debug issues interactively
Execute natural language commands that Claude translates to actions:
- "Create a buffer with today's date"
- "List all elisp files in this directory and count them"
- "Search for the function definition of
efrit-execute" - "Run git status and show me the output"
A structured, real-time view of agentic sessions with:
- Session status and elapsed time in header-line
- Task progress tracking (TODOs) updated by Claude
- Conversation view with expandable tool calls
- Interactive input for follow-up commands and mid-session guidance
Agent Buffer Keybindings:
| Key | Action |
|---|---|
n / M-n |
Next tool call |
p / M-p |
Previous tool call |
RET |
Expand/collapse tool at point |
E |
Expand all tool calls |
C |
Collapse all tool calls |
w |
Copy tool output to kill ring |
v |
Cycle verbosity (minimal/normal/verbose) |
i |
Inject guidance mid-session |
r |
Resume paused session |
k |
Cancel session |
g |
Refresh display |
q |
Quit buffer (session continues) |
1-4 |
Select option when Claude asks |
? |
Show help |
Efrit provides Claude with 35+ tools:
| Category | Tools |
|---|---|
| Code Execution | eval_sexp (elisp), shell_exec (shell commands) |
| File Editing | edit_file, create_file, undo_edit, format_file |
| Codebase Exploration | search_content, read_file, project_files, glob_files, file_info |
| Version Control | vcs_status, vcs_diff, vcs_log, vcs_blame |
| Task Management | todo_write, session_complete, request_user_input |
| Safety | confirm_action, checkpoint, restore_checkpoint, show_diff_preview |
| Diagnostics | get_diagnostics, elisp_docs |
| Issue Tracking | beads_ready, beads_create, beads_update, beads_close, beads_list |
| External | web_search, fetch_url, read_image |
| Buffer Management | buffer_create, display_in_buffer |
- Circuit breaker prevents infinite loops
- Automatic error recovery and retry
- Security controls on shell commands
Other AI agents (Claude Code, Cursor, etc.) can interact with Efrit via file-based JSON queue for autonomous development.
- Emacs 28.1+
- Anthropic API key from console.anthropic.com
git clone https://github.com/steveyegge/efrit.git
cd efritAdd to ~/.emacs.d/init.el:
(add-to-list 'load-path "/path/to/efrit/lisp")
(require 'efrit)Option A: Encrypted authinfo (recommended)
Create ~/.authinfo.gpg:
machine api.anthropic.com login personal password YOUR_API_KEY_HERE
Option B: Environment variable
export ANTHROPIC_API_KEY="sk-your-key-here"Option C: Plain authinfo
Create ~/.authinfo:
machine api.anthropic.com login personal password YOUR_API_KEY_HERE
Verify with M-x efrit-doctor.
| Mode | Use When | Tools Available |
|---|---|---|
efrit-chat |
Multi-turn conversations, asking questions, explanations | Buffer-centric (read buffer, search) |
efrit-do |
Quick agentic commands, shows progress in minibuffer | Full suite (35+ tools) |
efrit-agent |
Complex tasks needing visibility and interaction | Full suite + structured UI |
Decision guide:
- Just asking? →
efrit-chat(conversational, no file changes) - Quick command? →
efrit-do(runs in background, shows progress buffer) - Complex task? →
efrit-agent(real-time visibility, can guide mid-session)
Key differences:
efrit-chat: Read-only context, conversational UI, retains historyefrit-do: Fire-and-forget, progress buffer with raw outputefrit-agent: Interactive session buffer with expandable tool calls, TODO tracking, and mid-session guidance (ikey)
| Command | Description |
|---|---|
M-x efrit-chat |
Multi-turn conversational interface |
M-x efrit-do |
Execute natural language command asynchronously with progress buffer |
M-x efrit-agent |
Open the structured agent session buffer |
M-x efrit-do-sync |
Execute natural language command synchronously (blocking) |
M-x efrit-do-silently |
Execute command asynchronously without showing progress buffer |
M-x efrit-do-show-progress |
Show the progress buffer for the active command |
M-x efrit-do-show-queue |
Show commands queued for execution |
M-x efrit-doctor |
Run diagnostics |
M-x efrit-help |
Show help |
Simple queries:
M-x efrit-do RET
> what buffer am I in?
Code exploration:
M-x efrit-do RET
> search for all uses of 'defcustom' in this project and list them
Multi-step tasks:
M-x efrit-do RET
> create a new elisp file with a function that reverses a string, include proper headers
Shell integration:
M-x efrit-do RET
> run git log --oneline -10 and summarize the recent changes
Conversational:
M-x efrit-chat RET
You: Help me understand how the error handling works in this file
Assistant: [analyzes current buffer and explains]
You: Can you refactor it to use condition-case-unless-debug instead?
Bug fix workflow:
M-x efrit-agent RET
> The function `my-parse-data` throws an error on empty input. Find and fix it.
Claude will:
1. Search for the function definition
2. Analyze the code
3. Identify the bug
4. Create the fix with edit_file
5. Show you the diff for review
Refactoring workflow:
M-x efrit-agent RET
> Refactor all uses of deprecated `my-old-api` to use `my-new-api` in this project
Claude will:
1. Find all occurrences with search_content
2. Create a TODO list for each file
3. Edit each file, showing progress
4. Verify changes compile
Mid-session guidance: While Claude is working, you can:
- Press
ito inject guidance: "Focus on the src/ directory only" - Press
kto cancel if going wrong direction - Wait for questions - Claude will ask via
request_user_inputand you can respond directly in the buffer
Providing corrections: When Claude asks a question, you can:
- Type your response after the
>prompt and pressC-c C-sto send - Press
1,2,3, or4to select from offered options - Type "actually, I meant..." to correct course
By default, efrit-do executes asynchronously:
M-x efrit-do RET
> create a buffer with a function to reverse strings
Efrit automatically:
- Displays a progress buffer with real-time updates on Claude's thinking and tool execution
- Supports interruption with
C-g(keyboard-quit) - Queues commands if another command is already running (use
efrit-do-show-queueto view) - Shows session status in the minibuffer and modeline
The progress buffer shows:
- Claude's reasoning and tool calls
- Results from each step
- Time elapsed
For simpler tasks or scripting, use efrit-do-sync for blocking execution:
(efrit-do-sync "list all python files in current directory")This is the older API that waits for completion before returning.
To run a command without showing the progress buffer:
M-x efrit-do-silently RET
> long running task...
Progress is visible in the minibuffer. Show the buffer later with M-x efrit-do-show-progress.
Enable the global keymap:
(efrit-setup-keybindings) ; Binds C-c C-e prefixThen use:
C-c C-e c- Chat interfaceC-c C-e d- Async command with progress bufferC-c C-e D- Async command in backgroundC-c C-e q- Start remote queueC-c C-e Q- Queue status
AI agents can interact with Efrit via the Model Context Protocol:
(efrit-remote-queue-start) ; Start the queueRequest format:
{
"id": "req_001",
"version": "1.0.0",
"type": "eval",
"content": "(buffer-name)",
"timestamp": "2025-11-28T20:00:00Z"
}Types: eval (elisp), command (natural language), chat (conversation), status (health check)
Response format:
{
"id": "req_001",
"version": "1.0.0",
"status": "success",
"result": "*scratch*",
"timestamp": "2025-11-28T20:00:01Z"
}See mcp/README.md for MCP server setup.
If you have existing keybindings or configurations using older Efrit APIs:
Old name → New name | Status
--- | --- | ---
efrit-do (sync) | efrit-do-sync | Deprecated
efrit-do-async | efrit-do | Primary interface
efrit-do-async-legacy | — | Do not use
If you have in your init.el:
;; OLD: sync command (blocking)
(global-set-key (kbd "C-c C-e d") 'efrit-do)
;; NEW: use async command with progress buffer
(global-set-key (kbd "C-c C-e d") 'efrit-do)Or if you have code calling efrit-do-async:
;; OLD: explicit async
(efrit-do-async "your command")
;; NEW: efrit-do is async by default
(efrit-do "your command")The async API is now recommended for all use cases. Use efrit-do-sync only if you need blocking behavior (e.g., in scripts where waiting for completion is required).
;; Model selection (default: claude-sonnet-4-5-20250929)
(setq efrit-default-model "claude-sonnet-4-5-20250929")
;; Max tokens per response
(setq efrit-max-tokens 8192)
;; Data directory
(setq efrit-data-directory "~/.emacs.d/.efrit/")
;; Enable debug logging
(setq efrit-log-level 'debug)
;; Progress buffer configuration
(setq efrit-do-show-progress-buffer t) ; Show progress buffer automatically
(setq efrit-do-queue-max-size 10) ; Max commands to queueEfrit includes safety controls for eval_sexp:
;; Timeout for elisp evaluation (default: 30 seconds)
(setq efrit-tools-eval-timeout 30)
;; Disable elisp evaluation entirely (Claude uses predefined tools only)
(setq efrit-tools-sexp-evaluation-enabled nil)See SECURITY.md for full security configuration.
Efrit restricts which shell commands Claude can execute. By default, a wide range of development tools are allowed (git, npm, cargo, go, python, etc.).
;; Disable all shell security checks (trust Claude completely)
(setq efrit-do-shell-security-enabled nil)
;; OR allow all commands but keep forbidden pattern checks
(setq efrit-do-allowed-shell-commands '("*"))
;; Add additional allowed commands
(add-to-list 'efrit-do-allowed-shell-commands "mycustomtool")
;; Disable forbidden pattern checking
(setq efrit-do-forbidden-shell-patterns nil)The default forbidden patterns block truly dangerous commands like sudo, shutdown, and shell command injection via $(...) or backticks.
All data lives under ~/.emacs.d/.efrit/:
.efrit/
├── cache/ # Temporary cache
├── context/ # Context persistence
├── queues/ # AI communication (requests/responses/processing/archive)
├── logs/ # Debug logs
└── sessions/ # Session data
Check installation:
M-x efrit-doctorAPI issues:
M-: (efrit-common-get-api-key) ; Should return your keyDebug logging:
(setq efrit-log-level 'debug)
M-x efrit-log-showView errors:
M-x efrit-show-errorsmake compile # Byte-compile elisp
make test # Run test suiteSee DEVELOPMENT.md for contributor guidelines.
Efrit follows the Pure Executor principle:
- Claude decides what to do
- Efrit executes those decisions
- No pattern matching or heuristics in the client
See ARCHITECTURE.md for design details.
Apache License 2.0. See LICENSE.