Created: 2026-09-10 Thu 12:17
Emacs is the main software I use since 2002. You never feel you understand it enough and every time I tried something different I really couldn't perceive the advantage and went back to emacs.
I even asked claude/cursor what would be the best tool for writing software with interactive sessions, organize your workflow as per org mode, coordinate the agents and act on the system at the same time and the bot responded: keep using emacs. LLMs helped me to improve the way I use it and now it's hard to exit it since all the agents, programs and news are integrated here and the different outputs get piped together.
My current configuration is .emacs.el. emacs.el is a thin core (STYLE, environment, PACKAGES, INTERFACE, language-modes, BACKUP,
WELCOME, SPELLING); the per-topic config lives in sibling modules in
~/.emacs.d/ loaded after the bootstrap:
org-mode.el (org-roam/md-roam/org-capture), coding.el (corfu/eglot/minuet,
python, node, platformio), llm.el (ollama-buddy/gptel/ellama),
multimedia.el (lilypond).
Emacs grows with you. IDEs have many configuration options but they don't give you the freedom to adapt to your workflow and many options are limited. Especially the UI doesn't let you create a really readable interface were you just focus on what information is needed. Some useful examples.
Emacs is the most versatile text editor, it has an overwhelming option of integration and configuration. It takes time to configure it but the productivity speed is unbeatable. I tried IDEs but I find the UI too confusing to concentrate and they force you to work in a single manner. Emacs is the best option for .org too:
More on emacs
There are multiple configurations to include LLMs in emacs:
More on agent_call-emacs and emacs and LLMs.
variables and functions don't share the same namespace (they can have the same name) You can evaluate the lisp code by hitting [C-x C-e] at the end of the last parenthesis.
(defun sing-fun () ;;(interactive) (insert "ciccia")
(run-hooks 'fun-hook))
(add-hook 'fun-hook (lambda () (insert "3")))
define (defun insert-numbers () "insert a sequence of numbers" (interactive) (insert "\n 1 2 3")) and execute function (insert-numbers)
(insert "\nciccia " "ciccio") ciccia ciccio
(eq :foo ':foo)
(defun test-fun (arg) (+ arg 2))
(defun make-odd (arg) (if (% arg 2) (+ arg 1) arg))
(advice-add 'test-fun :filter-return #'make-odd)
(test-fun 4)
(defun insert-code-block ()
(insert "\n#+begin_src :exports both :results output replace \n\n#+end_src"))
(keymap-set c-mode-map "C-M-b" 'insert-code-block)
import re
None
find keymap associated to lisp command: [C-h w] (command-name)
(describe-key (kbd "M-:"))
(global-set-key (kbd "C-Alt-d") 'delete-region)
(keymap-global-set "C-Alt-d" 'delete-region) ;; newer version
Check all key mapping in org-mode
(describe-keymap 'org-mode-map)
(describe-keymap magit-mode-map)
KEYMAP\ OBJECT\ \(no\ variable\)\ 42
Edit variable definition [C-h v]
(describe-function 'package-install)
(custom-set-variables
'(ansi-color-faces-vector
[default default default italic underline success warning error])
'(ansi-color-names-vector
["#000044" "#d55e00" "#009e73" "#f8ec59" "#0072b2" "#cc79a7" "#56b4e9" "white"])
'(custom-enabled-themes '(misterioso))
'(custom-safe-themes
'("43b0db785fc313b52a42f8e5e88d12e6bd6ff9cee5ffb3591acf51bbd465b3f4" "47aaf1021bdd742a2f91448f089ad6fe95028c9557638d4333452ce85da980de" default)))
You can change the theme by hitting [C-x C-e] after the last parenthesis
(load-theme 'misterioso) (load-theme 'tango-dark) (load-theme 'wheatgrass) (load-theme 'whiteboard) (load-theme 'light-blue) (load-theme 'deeper-blue) (load-theme 'modus-vivendi) (load-theme 'leuven-dark)
(org-modern-mode 1)
(set-frame-parameter (selected-frame) 'alpha 100) (set-frame-parameter (selected-frame) 'alpha 80)
full screen [f11]
We can use icons as we write (all-the-icons-wicon "tornado" :face 'all-the-icons-blue)
(use-package all-the-icons
:if (display-graphic-p))
(all-the-icons-install-fonts)
(all-the-icons-insert-material "account-balance")
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
Prettify symbols
(setq prettify-symbol-alist
(mapcan (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
'(("bug" . ?)
("lambda" . ?λ)
("software" . ?)
))
)
(defconst lisp--prettify-symbols-alist
'(("lambda" . ?λ)))
(add-hook 'emacs-lisp-mode-hook
(lambda ()
(push '(">=" . ?≥) prettify-symbols-alist)))
(prettify-symbols-mode 1)
A bug is a when a software fails.
To use the packages listed here open this org file in emacs and set straight.el to test the experimental packages
;; If you're using straight.el, keep package.el from auto-loading.
(add-to-list 'load-path (expand-file-name "~/.emacs.d/lisp/"))
(setq package-enable-at-startup nil)
;; Bootstrap straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el"
user-emacs-directory))
(bootstrap-version 7))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)
(use-package package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
(setq package-archive-priorities
'(("melpa-stable" . 10)
("gnu" . 7)
("melpa" . 5)))
(setq package-check-signature 'allow-unsigned)
(setq package-archive-contents nil)
(package-initialize)
(advice-add 'package-refresh-contents :override
(lambda (&rest _)
(message "Package refresh skipped (run M-x list-packages to refresh archives)"))
'((name . no-refresh-on-init)))
(setq byte-compile-warnings '(cl-functions))
(use-package cl-lib)
(let ((default-directory "~/.emacs.d/"))
(normal-top-level-add-subdirs-to-load-path))
(add-to-list 'load-path "~/.emacs.d/lisp/")
There is a rich collections of software which can be added to emacs.
explain what the package `org-roam` does in emacs
(add-to-list 'load-path "~/.emacs.d/lisp/econky")
(require 'econky)
(defun my/setup-econky-frame (frame)
"Configura o layout 80/20 ao abrir um novo frame via emacsclient."
(with-selected-frame frame
(let ((econky-buffer (get-buffer-create "*econky*")))
(econky-start)
(let ((window-side (split-window-right (- (window-total-width)
(/ (window-total-width) 5)))))
(switch-to-buffer "*scratch*")
(set-window-buffer window-side econky-buffer)
(set-window-dedicated-p window-side t)))))
(add-hook 'after-make-frame-functions #'my/setup-econky-frame)
deft is a package for browsing plain test notes. It is useful to rename variables
(use-package deft ;;for quickly browsing, filtering, and editing directories of plain text notes
:after org
:bind
("C-c n d" . deft)
:custom
(deft-recursive t)
(deft-use-filter-string-for-filename t)
(deft-default-extension "org")
(deft-directory org-roam-directory))
denote is a note taking package easing the naming of files and linked sources doc.
(use-package denote ;;namespace and metadata for files
:ensure t
:hook (dired-mode . denote-dired-mode)
:bind
(("C-c n n" . denote)
("C-c n r" . denote-rename-file)
("C-c n l" . denote-link)
("C-c n b" . denote-backlinks)
("C-c n d" . denote-dired)
("C-c n g" . denote-grep))
:config
(setq denote-directory (expand-file-name "~/lav/src/spiega/project/"))
(denote-rename-buffer-mode 1))
sudo apt install aspell-fr aspell-de aspell-it
(cond
((executable-find "hunspell")
(setq ispell-program-name "hunspell")
(ispell-set-spellchecker-params)
(setq ispell-local-dictionary "en_US,it_IT")
(ispell-hunspell-add-multi-dic "en_GB,it_IT")
(setq ispell-local-dictionary-alist
'(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8))))
((executable-find "aspell")
(setq ispell-program-name "aspell")
(setq ispell-extra-args '("--sug-mode=ultra" "--lang=en_US"))))
(add-hook 'text-mode-hook 'flyspell-mode)
;; For markdown, use flyspell but skip code blocks and URLs
(add-hook 'markdown-mode-hook
(lambda ()
(setq flyspell-generic-check-word-predicate
(lambda ()
(not (or (markdown-code-block-at-point-p)
(markdown-inline-code-at-point-p)
(markdown-link-p)))))
(flyspell-mode 1)))
[M-x] opens minibuffer [M-|] shell command on region [M-:] eval eval-region
Registers and bookmarks in emacs are temporary information you can save in your session.
The useful commands for registers and bookmarks are:
A bookmark is persistent
(set-register ?h '(file . "~/lav/src/spiega/template/header_org.org"))
(file . ~/lav/src/spiega/template/header_org.org)
#+name : keybindings
(describe-key "C-a")
C - a is undefined
(use-package emms)
Shell in a buffer
Insert a shell command elisp:(org-insert-structure-template%20%22s%22) [C-c C-x s s]
(("n" . "notes") ("a" . "export ascii") ("c" . "center")("C" . "comment") ("e" . "example") ("E" . "export")("h" . "export html") ("l" . "export latex") ("q" . "quote")("s" . "src") ("v" . "verse"))
You can start a web browser elisp:(eww%20'%22intertino.it%22)
Retrieve the news feed elisp:(elfeed)
(use-package elfeed)
(setq elfeed-feeds
'(("https://nullprogram.com/feed/" blog )
("https://planet.emacslife.com/atom.xml" )
("https://www.rainews.it/rss" rai)
("https://yhetil.org/emacs-devel/new.atom" emacs lists devel)
("https://yhetil.org/emacs-bugs/new.atom" emacs lists bugs)
("https://sachachua.com/blog/category/emacs-news/feed/" emacs news)))
(setf url-queue-timeout 30)
30
We can use mu4e package.
(use-package mu4e)
Voice assistant and dictation
;; https://git.sr.ht/~lepisma/emacs-speech-input
(use-package esi-dictate
:straight (:host github :type git :repo "lepisma/emacs-speech-input")
:custom
(esi-dictate-dg-api-key "<DEEPGRAM-API-KEY>")
(esi-dictate-llm-provider <llm-provider-using-llm.el>)
; (esi-dictate-llm-prompt )
; Here is an example configuration for using OpenAI's
; (esi-dictate-llm-provider (make-llm-openai :key "<OPENAI-API-KEY>" :chat-model "gpt-4o-mini"))
:bind (:map esi-dictate-mode-map
("C-g" . esi-dictate-stop))
:config
(setq llm-warn-on-nonfree nil)
:hook (esi-dictate-speech-final . esi-dictate-fix-context))
Could not install
(use-package voicemacs
:straight (:host github :type git :repo "jcaw/voicemacs" )
)
t
(when (use-package 'dbus nil t)
(defun inkscape-test ()
"Test Inkscape D-Bus integration - creates a new desktop with a rectangle."
(interactive)
(let* ((desktop (dbus-call-method
:session "org.inkscape" "/org/inkscape/application"
"org.inkscape.application" "desktop_new"))
(rect (dbus-call-method
:session "org.inkscape" desktop
"org.inkscape.document" "rectangle"
:int32 100 :int32 100 :int32 100 :int32 100)))
(message "Created desktop: %s, rectangle: %s" desktop rect))))
(require 'lilypond-mode)
(autoload 'LilyPond-mode "lilypond-mode" "LilyPond Editing Mode" t)
(add-to-list 'auto-mode-alist '("\\.ly$" . LilyPond-mode))
(add-to-list 'auto-mode-alist '("\\.ily$" . LilyPond-mode))
(add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
(add-hook 'LilyPond-mode-hook (function (lambda () (add-to-list 'LilyPond-command-alist '("OpenPDF" "open '%f'")))))
(defvar ac-lilypond-identifiers
'((candidates . (lambda () (all-completions ac-target LilyPond-identifiers)))))
(defvar ni-LilyPond-keywords
(mapcar (lambda (x) (concat "\\" x)) LilyPond-keywords))
(defvar ac-lilypond-keywords
'((candidates . (lambda () (all-completions ac-target ni-LilyPond-keywords)))))
(defvar ac-lilypond-Creserved-words
'((candidates . (lambda () (all-completions ac-target LilyPond-Capitalized-Reserved-Words)))))
(defvar ac-lilypond-ncreserved-words
'((candidates . (lambda () (all-completions ac-target LilyPond-non-capitalized-reserved-words)))))
(provide 'init-lilypond)
How can we configure emacs for coding.
We can connect emacs to a language server (LSP) which runs externally checks on the code
(use-package lsp-mode
:commands (lsp lsp-deferred)
:hook ((prog-mode . lsp-deferred)
(python-mode . lsp)
(lsp-mode . lsp-enable-which-key-integration))
:custom (read-process-output-max (* 1024 1024))
:init
(setq lsp-completion-provider :none)
(setq lsp-keymap-prefix "C-c l")
(setq lsp-diagostic-provider :flycheck)
)
(use-package lsp-ui
:hook (lsp-mode . flycheck-mode)
;; :bind (:map flycheck-mode-map
;; ("M-n" flycheck-previous-error)
;; ("M-p" flycheck-next-error))
:custom (flycheck-display-error-delay .3))
| flycheck-mode | lsp-enable-which-key-integration |
The live emacs.el builds coding assistance from three layers that do not collide because each owns a different moment of the interaction (see the autocompletion guide below):
The legacy Python completer stack (company, company-jedi, elpy, flymake+pylint) has been removed from emacs.el; only eglot + corfu + minuet remain active. Flycheck is still used for graphviz (dot) files.
Few references: gavinok
minuet talks to whatever LLM serving backend is up. Because the backend
can change over time (unsloth, LM Studio, llama.cpp, vLLM, ollama…), the
relevant knobs in emacs.el are the three minuet-openai-fim-compatible-options
plists and the model name:
:end-point:api-key"UNSLOTH_TOKEN" (minuet
resolves the env var at request time), or a placeholder like "TERM" for
backends that ignore auth.:model| Backend | Typical endpoint | Auth | Notes |
|---|---|---|---|
| unsloth | http://localhost:8889/api/inference/completions |
Bearer UNSLOTH_TOKEN |
GGUF served via llama.cpp proxy; chat models give weak FIM output |
| LM Studio | http://localhost:1234/v1/completions |
none (placeholder) | OpenAI-compatible server UI |
| llama.cpp | http://localhost:8080/v1/completions |
none (placeholder) | llama-server / llama-cli --server |
| vLLM | http://localhost:8000/v1/completions |
depends on config | needs a server image with FIM support |
| ollama | http://localhost:11434/v1/completions |
none (placeholder) | OpenAI-compat layer; models like qwen2.5-coder |
| lemonade | http://localhost:13305/v1/completions |
none (placeholder) | OpenAI-compat layer; models like qwen2.5-coder |
Any switch is a one-line :end-point change (plus re-pulling/reloading the
model on the serving side) — the rest of minuet's config stays identical.
This is the same "bring your own backend" idea that ellama and ollama-buddy
use (local LLM clients).
This config is meant to run on laptops of very different power (a gaming laptop with a GPU, an old thin client, …). emacs.el detects the machine and reports the recommended stack, but never applies it automatically — the same emacs.el runs everywhere.
packages-recommended-for-hardware(:tier full|lite :packages (...) :auto-suggest t|nil :eglot-auto t|nil
:reason string).packages-report-hardwareM-x to re-show).packages-apply-recommendedM-x to apply the recommended tier.
Heuristic: >= 8 CPUs and >= 16 GB RAM => full, else lite. Override per
machine with machine/ai-stack (below) or the env var EMACS_AI_STACK=full|lite.
| tier | auto-suggest | eglot | packages | when |
|---|---|---|---|---|
| full | yes | auto | eglot corfu minuet | gaming/workstation or any box with a local LLM running |
| lite | no (manual) | manual | corfu dabbrev | old/thin laptop, visible UI lag, or no LLM available |
emacs.el stays identical on every laptop. A git-ignored
~/.emacs.d/machine.el (sibling of ellama_setup.el / gptel_tools.el, in
the repo under emacs/.emacs.d/) is loaded if present and overrides the
fallbacks. Copy the shipped template and set only what differs on this host:
machine/ai-stack"full" or "lite" (nil = auto from hardware).machine/minuet-host / machine/minuet-port / machine/minuet-model /
machine/minuet-api-key / machine/minuet-endpoint :: the minuet LLM
backend — host, port, model, auth, and the actual OpenAI-compatible FIM
route (different servers expose it at different paths).machine/ollama-url / machine/unsloth-urlellama_setup.el model
discovery.Because the end-point host/port/model now come from machine.el, switching backends on a given machine is a one-line edit in that file.
minuet never blocks Emacs or spams errors when the LLM is absent:
my/minuet-probe-backend TCP-probes the minuet endpoint (1s
timeout, asynchronous). Only if the server answers and the tier is full
does auto-suggest turn on.M-i stays quick and harmless); a
dead backend just yields a one-line message instead of a freeze.org-mode-hook and text-mode-hook (same gate: backend up and tier
full), so ghost-text works when writing notes/markdown too, and stays off
on the lite tier.M-x packages-apply-recommended.To keep a cold boot snappy the heavy / asynchronous work is deferred:
org-roamorg-roam-db-autosync-mode and md-roam-mode are
enabled on the first actual roam command (or M-x org-roam-db-sync), so the
DB is (re)built on demand instead of blocking cold boot.minuetellamastraight*straight-process* buffer is killed once
straight.el finishes (my/kill-straight-process-buffer on a 1-second start
timer), so it no longer lingers in the buffer list.
Instead of the default disabled splash screen you get a small custom
welcome buffer (*welcome*, M-x my/welcome-buffer) with the date, quick
commands, and clickable recent files (recentf, now enabled).
The previous session's buffers return lazily via desktop mode:
desktop-restore-eager is 0 so heavy modes load without blocking — the welcome
splash stays as the landing screen while buffers restore in the background.
Built-in:
Extensions (active):
(company and company-jedi were the older Python completer; removed from emacs.el.)
Minibuffer completion
(use-package vertico ;;minibuffer completion
:ensure t
:init (vertico-mode)
:bind (:map minibuffer-local-map
("<next>" . vertico-next-group)
("<prior>" . vertico-previous-group)))
vertico-previous-group
This is the autocompletion stack configured in the live emacs.el. It layers three tools that do not collide because each activates in a different context:
The key rule that keeps them from colliding: TAB means one thing at a time. When a minuet ghost is on screen, minuet-active-mode-map owns TAB (accept the AI suggestion); otherwise TAB goes to corfu; with no candidate at all, TAB just indents (tab-always-indent set to 'complete).
| key | context | action |
|---|---|---|
| TAB | corfu popup visible | corfu-insert (accept completion) |
| TAB | minuet ghost visible | minuet-accept-suggestion-line (accept first AI line) |
| M-a | minuet ghost visible | accept AI suggestion line |
| M-A | minuet ghost visible | accept whole AI suggestion |
| M-e | minuet ghost visible | dismiss AI suggestion |
| M-n / M-p | minuet ghost visible | next / previous AI suggestion |
| M-i | anywhere | minuet-show-suggestion (request AI completion now) |
| M-y | anywhere | minuet-complete-with-minibuffer (pick a completion) |
| M-x eglot | python / ts / js buffer | (re)start the language server manually |
The mouse also works: middle-click / mouse-2 on a corfu candidate inserts it. eglot adds its own context menu (mouse-3) with "Go to definition", "Rename", etc.
pyright (real LSP completion -> corfu)typescript-language-server for .ts/.tsx/.js/.jsx and web-modepython-mode-hook eglot-ensure) and offers candidates.corfu pops up the candidates. TAB or middle-click accepts one.minuet-active-mode-map takes over and TAB accepts the AI line instead.corfu-auto is deliberately OFF so corfu does not pop up competing suggestions while minuet is generating. corfu appears on demand (TAB), minuet appears automatically.
# Python LSPs (see requirements.txt)
pip install -r requirements.txt
# TypeScript LSP (global pnpm so node_modules stays out of this repo)
pnpm add -g typescript typescript-language-server
The binaries must be on exec-path; emacs.el already adds the pnpm global bin dir.
Legacy minibuffer-completion framework. Kept as an optional heavy fallback; currently commented out in emacs.el (see preferred setup).
(use-package helm ;;display completion
:straight t
:config
)
Lighter minibuffer-completion framework (companion of helm). Optional alternate; commented out in emacs.el.
Org-babel kernel support: run Jupyter notebooks / languages from Org source
blocks (where the jupyter executable is present).
(when (executable-find "jupyter")
(org-babel-do-load-languages
'org-babel-load-languages
'((jupyter . t)))
(define-key jupyter-org-interaction-mode-map (kbd "C-s-c h") #'jupyter-org-hydra/body)
(define-key jupyter-org-interaction-mode-map (kbd "C-c h") nil))
eglot snippet ement
Flexible, order-independent minibuffer/completion matching (space-separated substrings match in any order). Complements vertico/consult.
(use-package orderless)
C language formatter
(use-package clang-format
:commands (clang-format-buffer clang-format-on-save-mode))
(add-hook 'c-mode-hook 'clang-format-on-save-mode)
(add-hook 'c++-mode-hook 'clang-format-on-save-mode)
(add-hook 'glsl-mode-hook 'clang-format-on-save-mode)
Corfu basic
(use-package corfu ;; autocompletion
:hook ((prog-mode . (lambda () (setq-local corfu-auto))
(shell-mode . corfu-mode)
(eshell-mode . corfu-mode))
:init
(global-corfu-mode)
)
| corfu-mode |
More advanced options
(use-package corfu
;; :disabled
:ensure t
;; Optional customization
:custom
(corfu-cycle t) ; Allows cycling through candidates
(corfu-auto t) ; Enable auto completion
(corfu-auto-prefix 10)
(corfu-auto-trigger ".")
(corfu-auto-delay 0.1)
(corfu-popupinfo-delay '(0.5 . 0.2))
(corfu-preview-current 'insert) ; insert previewed candidate
(corfu-preselect 'prompt)
(corfu-on-exact-match nil) ; Don't auto expand tempel snippets
;; Optionally use TAB for cycling, default is `corfu-complete'.
:bind (:map corfu-map
("M-SPC" . corfu-insert-separator)
("TAB" . corfu-next)
([tab] . corfu-next)
("S-TAB" . corfu-previous)
([backtab] . corfu-previous)
("S-<return>" . corfu-insert)
("RET" . nil))
:init
(global-corfu-mode)
(corfu-history-mode)
(corfu-popupinfo-mode)) ; Popup completion info
Enable key bindings
(global-set-key (kbd "M-/") 'dabbrev-expand)
(global-set-key (kbd "M-C-/") 'dabbrev-completion)
dabbrev-completion
Completion-at-point functions (capf) that compose and enrich the completion sources corfu displays (file/history/pcomplete wrappers, eglot wiring).
(use-package cape
:ensure t
:defer 10
:bind ("C-c f" . cape-file)
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(defun my/add-shell-completion ()
(interactive)
(add-to-list 'completion-at-point-functions 'cape-history)
(add-to-list 'completion-at-point-functions 'pcomplete-completions-at-point))
(add-hook 'shell-mode-hook #'my/add-shell-completion nil t)
:config
;; Make capfs composable
(advice-add #'eglot-completion-at-point :around #'cape-wrap-nonexclusive)
(advice-add #'comint-completion-at-point :around #'cape-wrap-nonexclusive)
;; Silence then pcomplete capf, no errors or messages!
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent))
cape-file
Heuristic dabbrev-style expansion (tries many sources: dabbrev, kill-ring, file names, Lisp symbols…). Fast, offline, always available.
(use-package hippie-exp
:bind ([remap dabbrev-expand] . hippie-expand)
:commands (hippie-expand)
:custom
(dabbrev-ignored-buffer-regexps '("\\.\\(?:pdf\\|jpe?g\\|png\\)\\'"))
(dabbrev-upcase-means-case-search t)
:config
(setopt hippie-expand-try-functions-list
'(tempel-expand
try-expand-all-abbrevs
try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-complete-lisp-symbol-partially
try-complete-lisp-symbol
try-complete-file-name-partially
try-complete-file-name)))
The alternates above (helm, ivy, orderless, the extra corfu options) are historical or optional. The preferred configuration for the machine you are on is decided by packages-recommended-for-hardware and applied manually with
packages-apply-recommended (see the subsections under code assistant):
full → eglot + corfu + minuet auto-suggest.lite → corfu + dabbrev, auto-suggest off (manual M-i only).Pick one tier and forget the rest; the others exist so the same emacs.el keeps working on every machine without edits.
Language models without IDE capabilities have limited added value. We can in principle build a coding assistant within emacs but I prefer by now to use different coding assistant with different capabilities. My workflow:
Well configured coding assistants don't need extreme performant models
More on
;; Ollama client helpers
(defun my/ollama-chat (prompt)
"Send PROMPT to Ollama and show the response in a temp buffer."
(interactive "sPrompt: ")
(let* ((url-request-method "POST")
(url-request-extra-headers
'(("Content-Type" . "application/json")))
(url-request-data
(encode-coding-string
(json-encode
`(("model" . "llama3.2")
("stream" . :json-false)
("prompt" . ,prompt)))
'utf-8))
(buf (url-retrieve-synchronously "http://localhost:11434/api/generate")))
(with-current-buffer buf
(goto-char (point-min))
(re-search-forward "^$")
(forward-char 1)
(let ((json-object-type 'alist))
(message "%s" (alist-get 'response (json-read)))))
(kill-buffer buf)))
;; Example command for Blender prompts
(defun my/blender-prompt (task)
"Prepare a Blender instruction from TASK."
(interactive "sBlender task: ")
(my/ollama-chat
(concat
"Rewrite this as a concise Blender instruction: "
task)))
(global-set-key (kbd "C-c o") #'my/ollama-chat)
(global-set-key (kbd "C-c b") #'my/blender-prompt)
;; Meta bindings for convenience
(global-set-key (kbd "M-a") #'save-buffer)
(global-set-key (kbd "M-s") #'save-buffer)
;; (unless (package-installed-p 'blender-mode)
;; (package-install 'blender-mode))
;; (use-package 'blender-mode)
Three Emacs clients talk to LLM backends; they are configured in
~/.emacs.d/llm.el (the LLM module) and ~/.emacs.d/.
gptel (code)~/.emacs.d/gptel_tools.el. Lazy-loaded.ellama (reasoning/docs)~/.emacs.d/ellama_setup.el, lazy-loaded by ellama-load-and-call.ollama-buddy (Unsloth)Key bindings (llm.el):
| Key | Command | Description |
|---|---|---|
C-c g |
gptel-load-and-call |
Load gptel+tools then run gptel |
C-c C-g |
gptel-send |
Send region/buffer to gptel |
C-c C-b |
my/gptel-blender-prompt |
Blender prompt helper (org-mode) |
gptel-load-and-call (llm.el) adds user-emacs-directory to the
load path, loads gptel_tools, binds C-c C-g, then invokes gptel. Tools
live in ~/.emacs.d/gptel_tools.el and allowed shell commands in
~/.emacs.d/gptel-allowed-commands.txt.
Lazy-loaded by ellama-load-and-call (llm.el) from
~/.emacs.d/ellama_setup.el. Supports dynamic provider discovery (defaults
to Unsloth's /api/inference/models, needs UNSLOTH_TOKEN) and a C-c e
prefix keymap. C-x e is left for macro-execute. See agent_call for
the full provider/command breakdown.
Configured in llm.el (the LLM module).
unsloth/gemma-4-E2B-it-GGUFlocalhost:~8889~ (the local Unsloth server)UNSLOTH_TOKEN (API key)t), streaming (t), auto-scroll (t),
max file size 10MB.| Key | Command | Description |
|---|---|---|
C-c o |
ollama-buddy-role-transient-menu |
Role-based chat menu |
C-c O |
ollama-buddy-transient-menu |
Full ollama-buddy menu |
Note: a very old ollama chat helper above historically bound C-c o to a
hardcoded llama3.2 call; that binding is superseded by ollama-buddy.
(use-package aidermacs
:ensure t
:bind (("C-c f x" . aidermacs-transient-menu))
:config (setenv "OLLAMA_API_BASE" "http://127.0.0.1:11434")
:custom
(aidermacs-default-chat-model 'code)
(aidermacs-default-model "ollama_chat/qwen3.5:9b"))
(defun my-aider-add-related (query)
(interactive "sSearch context: ")
(let* ((cmd (format "rg -l \"%s\"" query))
(files (split-string (shell-command-to-string cmd) "\n" t))
(aider-cmd
(concat "aider " (mapconcat #'identity files " "))))
(vterm)
(vterm-send-string aider-cmd)
(vterm-send-return)))
(defun elmo-python-code ()
"Function to integrate ELMo-like functionality using Python."
(interactive)
;; Assuming you have a Python script that interacts with ELMo and
returns results.
(let ((python-eldoc-buffer (make-temp-file "elmocode" nil t)))
(with-current-buffer python-eldoc-buffer
(insert "#!/usr/bin/env python3\n"
"import json\n"
"\n"
"def elmo_functionality(text):\n"
f" # Dummy ELMo function that returns a JSON
object. Replace with actual ELMo call.\n"
f" return {json.dumps({'result': 'processed
text'})}\n"
"\n"
"result = elmo_functionality('"'"'Your input text
here'"'"')\n")
(write-region nil nil python-eldoc-buffer)
(shell-command (concat "chmod +x " python-eldoc-buffer))
(call-process-shell-command
python-eldoc-buffer
:stderr nil
:read-only t
:treat-piped-output-as-errors nil))
;; Now you can access the result in your current buffer.
(message "ELMo function call completed. Result is accessible via `M-x elmo-python-code`")
))
(global-set-key (kbd "<f12>") 'elmo-python-code)
Emacs has many code REPL features were you can send lines of code and test the execution and the data transformation. I mainly use REPL with:
Source code into syntax tree
(use-package treesit-auto)
(use-package tree-sitter)
(use-package tree-sitter-org
:straight (:host github :type git :repo "Idorobots/tree-sitter-org" )
)
t
The provided Emacs configuration file demonstrates a comprehensive setup tailored for efficient coding and development. The work encompasses various features that enhance productivity, code management, and collaboration within the software lifecycle.
Overall, this configuration represents a robust setup for modern software development using Emacs. It integrates various features that cater to different aspects of the software lifecycle, from initial planning and coding to deployment and documentation, making it an essential tool for developers seeking an efficient and flexible development environment.
Entered on [2026-07-24 Fri 14:09]
file:///home/sabeiro/lav/src/spiega/emacs/emacs.el#MissingReference
Entered on [2026-07-24 Fri 14:18]
file:///home/sabeiro/lav/src/spiega/emacs/emacs.el#MissingReference
Entered on [2026-07-24 Fri 14:18]
file:///home/sabeiro/lav/src/spiega/emacs/emacs.el#MissingReference
Entered on [2026-07-24 Fri 14:18]
file:///home/sabeiro/lav/src/spiega/emacs/emacs.el#MissingReference
Entered on [2026-07-24 Fri 14:18]
file:///home/sabeiro/lav/src/spiega/emacs/emacs.el#MissingReference
Entered on [2026-07-24 Fri 14:19]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_org.el#MissingReference
Entered on [2026-07-24 Fri 14:19]
Entered on [2026-07-24 Fri 14:21]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_coding.el#MissingReference
Entered on [2026-07-24 Fri 14:23]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_coding.el#MissingReference
Entered on [2026-07-24 Fri 14:23]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_coding.el#MissingReference
Entered on [2026-07-24 Fri 14:25]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_llm.el#MissingReference
Entered on [2026-07-24 Fri 14:26]
file:///home/sabeiro/lav/src/spiega/emacs/.emacs.d/dauvi_multimedia.el#MissingReference
The provided Emacs configuration file demonstrates a comprehensive setup tailored for efficient coding and development. The work encompasses various features that enhance productivity, code management, and collaboration within the software lifecycle.
### Key Features:
Overall, this configuration represents a robust setup for modern software development using Emacs. It integrates various features that cater to different aspects of the software lifecycle, from initial planning and coding to deployment and documentation, making it an essential tool for developers seeking an efficient and flexible development environment.