docs: add AGENTS.md for agentic coding guidelines
Add comprehensive guide for agents working in this Doom Emacs config: - Build/lint/test commands (doom sync, doom build, doom doctor) - Emacs Lisp code style guidelines - Doom macro reference (use-package!, add-hook!, map!, after!, load!) - Naming conventions and common patterns - Important workflow notes
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
# AGENTS.md — Doom Emacs Configuration
|
||||
|
||||
This is a Doom Emacs 3 personal configuration at `~/.config/doom/`.
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
doom/
|
||||
├── init.el # Module declarations (doom! macro)
|
||||
├── config.el # Main config, loads modular files via load!
|
||||
├── packages.el # Package declarations (package! macro)
|
||||
├── core.el # Core settings and super-save
|
||||
├── custom.el # Emacs custom variables (auto-generated)
|
||||
├── security.el # Security settings
|
||||
├── org.el # Org-mode configuration
|
||||
├── metrics.el # Usage tracking (keyfreq)
|
||||
├── theme.el # Theme configuration
|
||||
├── inbox.el # Quick capture inbox
|
||||
├── ai/
|
||||
│ ├── agents.el # Claude Code & Gemini CLI configuration
|
||||
│ └── gptel.el # GPTel (ChatGPT) configuration
|
||||
├── development/
|
||||
│ ├── lsp.el # LSP/LSP-UI configuration
|
||||
│ ├── cpp.el # C++ development settings
|
||||
│ ├── nix.el # Nix development settings
|
||||
│ └── misc.el # Miscellaneous dev settings
|
||||
├── docs/
|
||||
│ └── doom-macros-reference.md # Doom macro documentation
|
||||
└── snippets/ # Yasnippet snippets
|
||||
```
|
||||
|
||||
## Doom Commands
|
||||
|
||||
### Essential Commands
|
||||
|
||||
```bash
|
||||
# Sync config (run after ANY change to init.el, packages.el, or package configs)
|
||||
doom sync
|
||||
|
||||
# Rebuild all packages
|
||||
doom build
|
||||
|
||||
# Diagnose issues
|
||||
doom doctor
|
||||
|
||||
# Update all packages
|
||||
doom sync -u
|
||||
|
||||
# Show verbose output
|
||||
doom -v sync
|
||||
|
||||
# Run in batch mode (for CI/testing)
|
||||
emacs --batch -l ~/.config/doom/config.el --eval "(message \"test\")"
|
||||
```
|
||||
|
||||
### Package Management
|
||||
|
||||
```bash
|
||||
# Force sync without prompts
|
||||
doom sync -!
|
||||
|
||||
# Clean up orphaned packages
|
||||
doom sync --gc
|
||||
|
||||
# Install packages only (no rebuild)
|
||||
doom install
|
||||
```
|
||||
|
||||
### Testing Individual Config Files
|
||||
|
||||
```bash
|
||||
# Load a specific config file and check for errors
|
||||
emacs --batch -l ~/.config/emacs/bin/doom -l config.el -l ai/agents.el --eval "(message \"Loaded successfully\")"
|
||||
|
||||
# Check Elisp syntax
|
||||
emacs --batch --eval "(setq lexical-binding t)" -l ai/agents.el --eval "(message \"Syntax OK\")"
|
||||
```
|
||||
|
||||
## Code Style Guidelines (Emacs Lisp)
|
||||
|
||||
### File Headers
|
||||
|
||||
Every `.el` file should start with a standard header:
|
||||
|
||||
```elisp
|
||||
;;; filename.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;; Commentary:
|
||||
;;; Description of what this file does
|
||||
|
||||
;;; Code:
|
||||
```
|
||||
|
||||
### Lexical Binding
|
||||
|
||||
Always use `lexical-binding: t` (note the dash, not underscore in the file-local variable).
|
||||
|
||||
```elisp
|
||||
;;; init.el -*- lexical-binding: t; -*-
|
||||
```
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
| Element | Convention | Example |
|
||||
|---------|------------|---------|
|
||||
| Private functions | `+prefix--name` | `+org--restart-mode-h` |
|
||||
| Hook functions | `+module-hook-function-h` | `+org-exclude-agenda-buffers-from-workspace-h` |
|
||||
| Variables | `+module-variable-name` | `+org--restart-mode-h` |
|
||||
| Package hooks | `-module-hook-function-h` | `-org-exclude-agenda-buffers-from-workspace-h` |
|
||||
| Doom modules | `:module` | `:lang`, `:completion` |
|
||||
| Module flags | `+flag` | `+orderless`, `+lsp` |
|
||||
| Constants | `SCREAMING-SNAKE` | `MAX-HEIGHT` |
|
||||
|
||||
### Keybinding Syntax (map!)
|
||||
|
||||
```elisp
|
||||
;; Basic keybindings
|
||||
(map! :n "C-s" #'consult-line)
|
||||
|
||||
;; With lambda
|
||||
(map! :n "M-s" (lambda () (interactive) (consult-line (thing-at-point 'symbol))))
|
||||
|
||||
;; Leader key with prefix
|
||||
(map! :leader
|
||||
(:prefix ("C" . "claude-code")
|
||||
:desc "Start Claude" "c" #'claude-code
|
||||
:desc "Kill Claude" "k" #'claude-code-kill))
|
||||
|
||||
;; State modifiers: :n (normal), :v (visual), :i (insert), :e (emacs)
|
||||
(map! :nv "C-j" #'something)
|
||||
```
|
||||
|
||||
### use-package! vs use-package
|
||||
|
||||
- Use `use-package!` in Doom configs (macro version)
|
||||
- Use `use-package` when referring to the built-in package.el macro
|
||||
|
||||
```elisp
|
||||
;; Doom configuration
|
||||
(use-package! org-roam
|
||||
:after org
|
||||
:custom
|
||||
(org-roam-directory "~/org/roam")
|
||||
:config
|
||||
(org-roam-db-autosync-mode))
|
||||
|
||||
;; Standard Emacs (when needed)
|
||||
(use-package org
|
||||
:init
|
||||
(setq org-todo-keywords '("TODO" "DONE"))
|
||||
:config
|
||||
(org-mode 1))
|
||||
```
|
||||
|
||||
### Hook Registration
|
||||
|
||||
```elisp
|
||||
;; Anonymous function with defun inside
|
||||
(add-hook! 'org-agenda-finalize-hook
|
||||
(defun +org-exclude-agenda-buffers-from-workspace-h ()
|
||||
"Don't associate temporary agenda buffers with current workspace."
|
||||
(when org-agenda-new-buffers
|
||||
(persp-remove-buffer org-agenda-new-buffers
|
||||
(get-current-persp)
|
||||
nil))))
|
||||
|
||||
;; :local makes hook buffer-local
|
||||
(add-hook! :local 'some-mode-hook
|
||||
(defun my-local-hook ()
|
||||
(do-something)))
|
||||
```
|
||||
|
||||
### Conditional Loading
|
||||
|
||||
```elisp
|
||||
;; After package loads (preferred in Doom)
|
||||
(after! lsp-ui
|
||||
(setq lsp-ui-doc-enable t))
|
||||
|
||||
;; With feature check
|
||||
(when (featurep! :system 'macos)
|
||||
(setq mac-command-modifier 'meta))
|
||||
|
||||
;; After multiple packages
|
||||
(after! (org org-roam)
|
||||
(require 'org-roam-protocol))
|
||||
```
|
||||
|
||||
### Defcustom vs Defvar
|
||||
|
||||
- Use `defcustom` for user-configurable settings that belong in `custom.el`
|
||||
- Use `defvar` or `setq` for internal variables
|
||||
|
||||
```elisp
|
||||
;; In packages.el (for user customization)
|
||||
(setq org-directory "~/org/")
|
||||
|
||||
;; Not a defcustom unless it belongs in custom.el
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```elisp
|
||||
;; Use quiet! to suppress output
|
||||
(quiet! (org-mode-restart))
|
||||
|
||||
;; Use fn! or #' for function references
|
||||
(advice-add #'org-capture :around
|
||||
(lambda (fun &rest args)
|
||||
(letf! ((#'+org--restart-mode-h #'ignore))
|
||||
(apply fun args))))
|
||||
|
||||
;; Use ignore when function should do nothing
|
||||
(defalias '+org--restart-mode-h #'ignore)
|
||||
```
|
||||
|
||||
### Package Recipes (packages.el)
|
||||
|
||||
```elisp
|
||||
;; Simple package from Melpa
|
||||
(package! super-save)
|
||||
|
||||
;; GitHub recipe with custom files
|
||||
(package! copilot
|
||||
:recipe (:host github :repo "copilot-emacs/copilot.el" :files ("*.el")))
|
||||
|
||||
;; GitHub with exclusion patterns
|
||||
(package! eat
|
||||
:recipe (:host codeberg
|
||||
:repo "akib/emacs-eat"
|
||||
:files ("*.el" ("term" "term/*.el") "*.texi"
|
||||
"*.ti" ("terminfo/e" "terminfo/e/*")
|
||||
(:exclude ".dir-locals.el" "*-tests.el"))))
|
||||
|
||||
;; Disable a package
|
||||
(package! some-package :disable t)
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Restart/Reload Functions
|
||||
|
||||
```elisp
|
||||
(defun +org--restart-mode-h ()
|
||||
"Restart org-mode on buffer switch."
|
||||
(remove-hook 'doom-switch-buffer-hook #'+org--restart-mode-h 'local)
|
||||
(cl-delete (current-buffer) org-agenda-new-buffers :test 'eq)
|
||||
(quiet! (org-mode-restart))
|
||||
(run-hooks 'find-file-hook))
|
||||
```
|
||||
|
||||
### Advice Around Functions
|
||||
|
||||
```elisp
|
||||
(advice-add #'org-capture :around
|
||||
(lambda (fun &rest args)
|
||||
(letf! ((#'+org--restart-mode-h #'ignore))
|
||||
(apply fun args))))
|
||||
```
|
||||
|
||||
### Buffer Display Configuration
|
||||
|
||||
```elisp
|
||||
(add-to-list 'display-buffer-alist
|
||||
'("^\\*claude"
|
||||
(display-buffer-in-side-window)
|
||||
(side . right)
|
||||
(window-width . 90)))
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```elisp
|
||||
;; Unset for subprocess access
|
||||
(setenv "CLAUDECODE" nil)
|
||||
|
||||
;; Set with path
|
||||
(setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH")))
|
||||
```
|
||||
|
||||
## Doom Module System
|
||||
|
||||
The `init.el` uses the `doom!` macro to declare enabled modules:
|
||||
|
||||
```elisp
|
||||
(doom! :category
|
||||
(module +flag)
|
||||
:another-category)
|
||||
```
|
||||
|
||||
Modules referenced in this config:
|
||||
- `:completion` — Vertico, Corfu
|
||||
- `:ui` — Doom dashboard, treemacs, workspaces
|
||||
- `:editor` — Evil, format+, multiple-cursors
|
||||
- `:emacs` — Dired, ibuffer, undo
|
||||
- `:term` — Eshell, vterm
|
||||
- `:checkers` — Syntax, spell
|
||||
- `:tools` — LSP, magit, direnv, docker
|
||||
- `:lang` — Python, Go, Rust, Org, JavaScript, etc.
|
||||
- `:config` — Default bindings, smartparens
|
||||
|
||||
## Important Notes
|
||||
|
||||
1. Run `doom sync` after ANY change to `init.el`, `packages.el`, or `config.el`
|
||||
2. Use `doom build` to rebuild if byte-compilation errors occur
|
||||
3. This config uses straight.el for package management (via Doom)
|
||||
4. Custom variables are auto-generated to `custom.el` — don't edit manually
|
||||
5. The `load!` macro loads relative to `doom-private-dir` (this config directory)
|
||||
Reference in New Issue
Block a user