An Emacs Lisp AI coding agent with multi-agent architecture, permission-based tool access, and LLM integration via gptel.
Magent now uses a durable child-agent lifecycle for collaborative agent work: spawn, message, wait, list, resume/inspect, and close. The lifecycle is implemented on top of the Magent-owned agent loop while provider integration stays with gptel-request.
The old one-shot delegate tool has been replaced by spawn_agent, send_agent_message, wait_agent, list_agents, and close_agent. Codex sandbox behavior is intentionally out of scope. The final architecture is documented in docs/AGENT_JOBS.md.
- Multi-agent system with specialized agents (build, plan, explore, general)
- Permission-based tool access with fine-grained control per agent
- Custom agent support via
.magent/agent/*.mdfiles - LLM integration via gptel supporting Anthropic Claude, OpenAI GPT, and compatible APIs
- 14 built-in tools: file operations, shell, grep, glob, web search, Emacs eval, durable child-agent jobs, skill invocation
- Skill system for extending agent capabilities (built-in Emacs skill + custom skills from files)
- Single-request lock for serializing concurrent requests
- Project-scoped session management with conversation history and JSON persistence
- Streaming responses with chunk batching and async fontification
- Markdown-to-Org conversion for rendering assistant output in org-mode
- Context-aware prompting via
magent-dwimwith automatic buffer context attachment
Add the project to your Emacs load path:
(add-to-list 'load-path "/path/to/magent")
(require 'magent)(use-package magent
:load-path "/path/to/magent"
:config
(global-magent-mode 1))Magent does not assume Evil by default. Evil-specific state handling and
bindings live in the optional magent-evil feature:
(use-package magent-evil
:after (magent evil)
:config
(magent-evil-mode 1))Magent delegates all LLM communication to gptel. Configure your provider, model, and API key through gptel:
;; gptel handles provider/model/key configuration
(setq gptel-model 'claude-sonnet-4-20250514)
(setq gptel-api-key "sk-ant-...") ; or use ANTHROPIC_API_KEY env varSee gptel documentation for full provider setup (Anthropic, OpenAI, Ollama, etc.).
Customize with M-x customize-group RET magent RET. Key settings:
| Option | Default | Description |
|---|---|---|
magent-system-prompt | (built-in) | Default system prompt for agents |
magent-buffer-name | "*magent*" | Output buffer name |
magent-auto-scroll | t | Auto-scroll output buffer |
magent-enable-tools | default tool set | Globally enabled tool permission groups |
magent-project-root-function | nil | Custom project root finder |
magent-max-history | 100 | Max messages in history |
magent-request-timeout | 120 | Timeout in seconds for LLM requests |
magent-max-sampling-requests | 25 | Max model sampling requests in one user turn; 0 disables the lifecycle guard |
magent-default-agent | "build" | Default agent for new sessions |
magent-load-custom-agents | t | Load custom agents from .magent/agent/*.md |
magent-enable-logging | t | Enable logging to *magent-log* buffer |
magent-log-level | info | Minimum displayed log level; PERM and unprefixed messages count as info |
magent-enable-audit-log | t | Persist compact audit logs for permission and sensitive actions |
magent-assistant-prompt | "ASSISTANT" | Tag text in assistant section headers |
magent-user-prompt | "USER" | Tag text in user section headers |
magent-tool-call-prompt | "tool" | Tag text in tool call lines |
magent-error-prompt | "error" | Tag text in error section headers |
magent-agent-directory | ".magent/agent" | Relative path to custom agent dir |
magent-session-directory | ~/.emacs.d/magent-sessions/ | Base directory for global sessions and per-project session subdirectories |
magent-audit-directory | nil | Override directory for audit JSONL files; defaults to magent-session-directory/audit/ |
magent-grep-program | "rg" | Path to ripgrep binary |
magent-grep-max-matches | 100 | Max matches from grep searches |
magent-bash-timeout | 30 | Timeout in seconds for bash commands |
magent-child-agent-max-depth | 1 | Max recursive child-agent depth; direct children are allowed by default |
magent-emacs-eval-timeout | 10 | Timeout in seconds for emacs_eval |
magent-audit-preview-length | 120 | Max width for persisted audit summaries and previews |
magent-include-reasoning | t | Display (t), keep out of the UI (ignore), or discard (nil) reasoning blocks |
magent-auto-context | t | Auto-attach buffer context in magent-dwim |
magent-ui-batch-insert-delay | 0.05 | Delay in seconds for batching streaming chunks |
magent-ui-fontify-threshold | 500 | Character threshold for async fontification |
| Command | Keybinding | Description |
|---|---|---|
magent-dwim | C-c m p | Smart prompt: opens output buffer or prompts for input with auto-context |
magent-diagnose-emacs | C-c m d | Start a structured diagnosis of the current Emacs session |
magent-doctor | C-c m D | Run Magent self-check and diagnose Magent-specific issues |
magent-prompt-region | C-c m r | Send selected region to AI |
magent-ask-at-point | C-c m a | Ask about symbol at point |
magent-clear-session | C-c m c | Clear current session |
magent-show-log | C-c m l | View API request/response log |
magent-clear-log | C-c m L | Clear the log buffer |
magent-ui-toggle-section | C-c m t | Toggle fold/unfold of section at point |
magent-select-agent | C-c m A | Select an agent for this session |
magent-resume-session | C-c m R | Resume a saved project or global session |
magent-show-agent-transcript | C-c m j | Inspect a persisted child-agent transcript |
magent-show-current-agent | C-c m i | Show current session’s agent |
magent-list-agents | C-c m v | List all available agents |
magent-toggle-by-pass-permission | M-x | Toggle permission bypass for tool filtering and approval prompts |
In the *magent* output buffer: TAB and S-TAB fold sections, ? opens the transient menu outside the editable input area, C-c C-c submits input, and C-g interrupts. Submit @clear as the whole input to clear the current session context, similar to Codex /clear.
The same bypass state is also exposed as the customize option
magent-by-pass-permission under M-x customize-group RET magent RET.
Magent keeps a single *magent* buffer, but session state is scoped by project:
- In a recognized project, prompts, agent selection, clear, and resume operate on that project’s current session.
- Saved project sessions live under
magent-session-directory/projects/<sha1(project-root)>/. - Outside any project, Magent falls back to the global session behavior and saves directly under
magent-session-directory. - Compact audit logs for permission decisions and sensitive tools are written as daily JSONL files under
magent-session-directory/audit/unlessmagent-audit-directoryis set. magent-resume-sessionshows all sessions grouped by project, with date and time in each candidate, the current project’s group first, and global sessions in their own group.
;; Enable the mode
(magent-mode 1)
;; Or globally
(global-magent-mode 1)
;; Send a prompt
M-x magent-dwim
;; Or use keybinding
C-c m pIn the Magent input area, type @skill-name to explicitly activate an
instruction skill for that request. Skills with a default-prompt can also be
used as command-like inputs; for example, submitting @init initializes or
refreshes the project’s root AGENTS.md, similar to Codex /init. Extra text
after the skill token is treated as the request body, so @init focus on tests
runs the same skill with that additional constraint.
Submit @clear as the whole input to clear the current session context without
sending a request to the model, similar to Codex /clear.
Magent uses a multi-agent architecture where different agents have different capabilities and permissions.
| Agent | Mode | Description |
|---|---|---|
build | primary | Default agent for general coding tasks with full tool access |
plan | primary | Planning agent with restricted file edits (only .magent/plan/*.md) |
explore | subagent | Fast codebase exploration (read/grep/glob/bash only) |
general | subagent | General-purpose subagent for child-agent tasks |
compaction | primary (hidden) | Session summarization / conversation compaction |
title | primary (hidden) | Conversation title generation |
summary | primary (hidden) | Pull-request style summary generation |
- primary: User-facing agents that can be selected for sessions
- subagent: Internal agents called by primary agents for subtasks
- all: Can act as either primary or subagent
Primary agents can coordinate child agents through durable jobs. A root turn can call spawn_agent to start work under a subagent profile, use list_agents and wait_agent to monitor results, send follow-up input with send_agent_message, and close work explicitly with close_agent.
Child jobs are stored in the parent session under agent-jobs with status, prompt, metadata, result/error, and transcript state. The parent buffer shows compact #+begin_agent lifecycle blocks, while the full child transcript is available through magent-show-agent-transcript (C-c m j). See docs/AGENT_JOBS.md for the implementation model and boundaries.
Each agent has permission rules controlling tool access:
;; Example permission rules in an agent definition
(
(read_file . allow) ; Allow all file reads
(write_file . ((deny "*.env") ; Deny writing to .env files
(deny "*.key") ; Deny writing to .key files
(allow "*"))) ; Allow writing to other files
(bash . ask) ; Ask user before running bash commands
)Permission actions:
allow: Tool is alloweddeny: Tool is blockedask: Prompt the user for confirmation
Create custom agents by adding markdown files to .magent/agent/.
Example: ~.magent/agent/reviewer.md~
---
description: Code review specialist
mode: primary
hidden: false
temperature: 0.3
permissions:
- (read_file . allow)
- (write_file . deny)
- (bash . deny)
- (grep . allow)
- (glob . allow)
---
You are a code review specialist. Analyze code for:
- Bugs and potential issues
- Code style and best practices
- Performance optimizations
- Security vulnerabilities
Provide constructive feedback with specific examples.The YAML frontmatter supports:
description: Short description of the agentmode:primary,subagent, orallhidden: Hide from agent selection UItemperature: Override default temperaturemodel: Override default modelpermissions: List of permission rules
The AI agent has access to these tools (can be customized per agent):
| Tool | Side-effect | Description |
|---|---|---|
read_file | no | Read file contents from the filesystem |
write_file | yes | Write or create a file (auto-creates parent dirs) |
edit_file | yes | Replace exact text in a file (must match once) |
grep | no | Regex search via ripgrep; returns file:line:content |
glob | no | Find files matching a glob pattern |
bash | yes | Execute shell commands (default timeout 30s) |
emacs_eval | yes | Evaluate Emacs Lisp expressions (default timeout 10s) |
spawn_agent | yes | Start a durable child-agent job |
send_agent_message | yes | Send follow-up input to a live child job |
wait_agent | no | Wait for child jobs and return status/results |
list_agents | no | List child-agent jobs for the current session |
close_agent | yes | Close or cancel a child-agent job |
skill_invoke | no | Invoke tool-type skills |
web_search | no | Search the web via DuckDuckGo |
Tools with side effects prompt the user for confirmation before execution unless permission bypass is enabled with M-x magent-toggle-by-pass-permission or by customizing magent-by-pass-permission.
Tool availability is controlled by:
- Global
magent-enable-toolssetting - Per-agent permission rules
- Entry Point (
magent.el): Definesmagent-modeminor mode with theC-c mkeybinding prefix. Full initialization (agent registry, skills) is lazy – triggered on first command viamagent--ensure-initialized. - Runtime (
magent-runtime.el): Centralizes static initialization and project-local overlay activation for agents, skills, and capabilities. - Agent System: Multi-agent architecture with permission-based tool access:
magent-agent.el: Builds gptel prompts, applies per-agent overrides, callsgptel-requestmagent-agent-registry.el: Agent info struct, built-in agent definitions, and central registrymagent-agent-file.el: Custom agent loader (.magent/agent/*.md)
- Permission System (
magent-permission.el): Rule-based tool access control per agent with file-pattern matching (glob syntax). - Capability System (
magent-capability.el): File-backed capability definitions score each request context and attach matching instruction skills. - Agent Loop:
magent-agent.elstarts the Magent-owned loop inmagent-agent-loop.el.magent-llm.eldefines normalized request/events, andmagent-llm-gptel.elcallsgptel-requestfor one sampling request while hiding gptel callback/FSM details. The loop owns tool dispatch, serial queueing, visible tool rendering, abort cleanup, permission audit hooks, and tool-result session recording;magent-agent-processowns continuation policy across sampling requests. - LLM Integration (via gptel): All LLM communication is handled by gptel. Provider, model, and API key configuration is managed entirely by gptel.
- Tools (
magent-tools.el): 14 tool implementations registered asgptel-toolstructs, filtered per agent based on permission rules. The durable child-agent lifecycle tools arespawn_agent,send_agent_message,wait_agent,list_agents, andclose_agent. - Skills (
magent-skills.el): Two skill types –instruction(markdown injected into the system prompt) andtool(invoked viaskill_invoke). Instruction skills can be explicitly selected with@skill-namein the input area; skills that declaredefault-promptcan be submitted alone, such as@initfor project instruction initialization. The module contains the registry, built-inskill-creatordefinition, file-based skill loading, and interactive inspection commands. Skills load in priority order from: (1) built-inskills/directory bundled with magent, (2) user directory~/.emacs.d/magent-skills/<name>/SKILL.md, (3) project-local.magent/skills/<name>/SKILL.md. - Session (
magent-session.el): Conversation history management with per-project active sessions, global fallback outside projects, and JSON persistence. Thebuffer-contentslot stores raw buffer text for lossless restore. - Audit (
magent-audit.el): Persistent JSONL audit logging for permission prompts and decisions plus sensitive actions such asbash,emacs_eval,write_file,edit_file, and child-agent lifecycle tools. Payloads are redacted to metadata and truncated previews. - UI (
magent-ui.el): The*magent*buffer derives fromorg-mode. It uses in-buffer input with* [USER]sections. Tool calls render as#+begin_tool~/~#+end_toolblocks; reasoning blocks as#+begin_think~/~#+end_think. Single-request serialization now lives here viamagent-ui--processingandmagent-ui--enqueue. - Evil Integration (
magent-evil.el): Optional feature for Evil users. It is not loaded bymagentand is enabled explicitly withmagent-evil-mode. - Markdown-to-Org (
magent-md2org.el): Converts markdown assistant output to org-mode format for rendering. - File Loader (
magent-file-loader.el): Shared definition loader for agent, skill, and capability files. It includes frontmatter parsing and supports booleans, numbers, quoted strings, and comma-separated lists.
magent/
|-- magent.el # Main entry point and mode definition
|-- magent-config.el # Configuration (customize group, defcustom vars)
|-- magent-runtime.el # Static initialization and project overlay activation
|-- magent-session.el # Session and message history (JSON persistence)
|-- magent-agent-job.el # Durable child-agent job state
|-- magent-llm.el # Provider-neutral LLM request/event protocol
|-- magent-llm-gptel.el # gptel-request sampling adapter
|-- magent-agent-loop.el # Magent-owned event loop, tools, guards, aborts
|-- magent-capability.el # Capability registry and prompt-time resolution
|-- magent-audit.el # Audit logging and JSONL persistence
|-- magent-tools.el # Tool implementations (14 gptel-tool structs)
|-- magent-tool-orchestrator.el # Permission, approval, audit, and tool-call orchestration
|-- magent-agent.el # Agent logic (gptel integration)
|-- magent-agent-types.el # Compatibility shim for legacy agent-types feature
|-- magent-agent-registry.el # Agent struct, built-in definitions, and registry
|-- magent-agent-file.el # Custom agent file loader (.magent/agent/*.md)
|-- magent-permission.el # Permission system (allow/deny/ask with glob patterns)
|-- magent-file-loader.el # Shared definition loader and frontmatter parser
|-- magent-md2org.el # Markdown to org-mode converter
|-- magent-skills.el # Skill registry, built-in skills, file loading, and skill commands
|-- magent-ui.el # In-buffer UI and output buffer (org-mode derived)
|-- magent-evil.el # Optional Evil integration
|-- magent-pkg.el # Package descriptor
|-- prompt.org # Default system prompt
|-- Makefile # Build, test, and clean targets
|-- skills/ # Built-in skills (loaded automatically)
| |-- brainstorming/SKILL.md
| |-- systematic-debugging/SKILL.md
| |-- test-driven-development/SKILL.md
| |-- writing-plans/SKILL.md
| |-- executing-plans/SKILL.md
| |-- subagent-driven-development/SKILL.md
| |-- verification-before-completion/SKILL.md
| |-- git-workflow/SKILL.md
| |-- requesting-code-review/SKILL.md
| |-- receiving-code-review/SKILL.md
| |-- finishing-a-development-branch/SKILL.md
| |-- dispatching-parallel-agents/SKILL.md
| |-- research/SKILL.md
| |-- research-add/SKILL.md
| |-- research-batch/SKILL.md
| |-- research-explore/SKILL.md
| `-- research-report/SKILL.md
`-- test/
`-- magent-test.el # ERT test suite
magent-agent-info: Agent configuration struct (name, description, mode, permissions, prompt, temperature, model, and related settings)magent-session: Conversation state with message list, assigned agent, history trimming, raw buffer content, and durable child-agent jobsmagent-agent-job: Child-agent job state with stable id, status, prompt, transcript, result/error, and inheritance metadatamagent-agent-loop: Active turn state for normalized LLM events, tool queueing, guards, aborts, and continuationmagent-skill: Loaded skill definition (name, description, tools, body, dir)
make compile # Byte-compile all Elisp files
make test # Run ERT tests
make clean # Remove compiled .elc filesemacs -Q --batch -L . -L ~/path/to/gptel -f batch-byte-compile magent-foo.elSessions are automatically saved to ~/.emacs.d/magent-sessions/ (configurable). Each session maintains:
- Conversation history
- Assigned agent
- Message metadata
- Raw buffer content for lossless restore
- Durable child-agent job metadata, results, errors, and transcripts
View request and response logs:
(setq magent-enable-logging t
magent-log-level 'debug)
M-x magent-show-log ; C-c m lM-x magent-list-agents ; List all agents
M-x magent-show-current-agent ; Show current session's agentAPI keys are managed by gptel. Check with:
gptel-api-key ; Should return your API keyThis project is licensed under the GNU General Public License v3.0. See LICENSE for details.
- Inspired by: OpenCode
Contributions are welcome. Please ensure:
- Code follows existing style conventions
- All files byte-compile without warnings
- Documentation is updated for new features
- Project Repository: https://github.com/jamie-cui/magent