emacs

sabeiro

2026-06-22 Mon 00:00

Created: 2026-09-10 Thu 12:17

emacs

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).

software
software section
coding
coding tools

adaptability

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.

.org and emacs

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:

export
many emacs packages export the files into blog posts and slides
babel
you can link system programs to the execution of code blocks
roam
in the background all the information you work on are linked together
integration
.org connects with all the tools like agenda, web-search, journal …
tools
emacs allows agent to use tools

More on emacs

emacs and LLMs

There are multiple configurations to include LLMs in emacs:

ellama
for reasoning and structuring the project and for code examples in any buffer
gptel
for the integration with mcp
gptel base
base package
mcp.el
start the hub
custom gptel tools
user defined tools
gptel-mcp
integration between the packages
mcp
for adding my own tools and external mcp

More on agent_call-emacs and emacs and LLMs.

edit

lisp

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.

symbols
begin with :
quote
a way to prevent evaluation (+ 1 2) vs '(+ 1 2)
hash
#' to access the function namespace
quasiquote
de-quote `(1 2 , (+ 1 2)) with comma ,
operators
(and ) (or ) (eq ) (not )
conditional
(if when unless) (cond )
setq
set a variable (setq markdown-marginalize-headers t)
setopt
type checking (setopt markdown-marginalize-headers "ciccia")
loop
(cl-loop for i from 0 to 10 collect (* i i)) (while …)
dotimes
(setq total nil)(dotimes (i 3)(setq total (cons total i)))
dolist
(setq total 0)(dolist (i '(1 2 3))(setq total (+ total i)))
mapcar
apply a function to each element of a list (mapcar #'1+ '(1 2 3))
hook
list of functions in a particular situation (add-hook ) (run-hook )
(defun sing-fun () ;;(interactive) (insert "ciccia")
       (run-hooks 'fun-hook))
(add-hook 'fun-hook (lambda () (insert "3")))

variables

string
"ciccia"
symbol
'ciccia'
keyword
:ciccia
temp
with let (defun cucco () (let ((cic (+ 2 3))(cioc (+ 4 5)))(- cic cioc))) (cucco)
chars
?h (output hex)
bool
true -> t, false -> nil
plist
'(key "value" key2 value) or '(:key value :key2 value)

lists

pairs
(cons 1 2) -> (1 . 2)
list
(list 1 3 4 5) -> (1 3 4 5)
car
first value of a list (car '(1 3 4 5))
cdr
the rest of a list (cdr '(3 94 85 8))
symbol_plist
with symbolic links (check if a function is interactive only, class type…) (symbol_plist #'magit-dispatch)
linked lists
(cons 1 (cons 2 nil))

functions

define (defun insert-numbers () "insert a sequence of numbers" (interactive) (insert "\n 1 2 3")) and execute function (insert-numbers)

defun
(defun test-fun (arg) (+ arg 2)) (defun foo () 5)
output
(message "1 2 3") -> minibuffer (insert "1 2 3") -> buffer
interactive
makes the function listed in [M-x]
advice
a decorator
cl_defun
(cl-defun fun-with-kwargs (&key foo bar) (format "%s %s" foo bar))
setf
progn
execute functions in sequence

(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

keybinding

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

cheatsheet

elisp:(keymap-global-lookup) elisp::(describe-keymap)

reference

docs

Edit variable definition [C-h v]

(describe-function 'package-install)

search

isearch
elisp:(isearch)

configuration

font and faces

(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]

icons

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.

packages

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/")

software

There is a rich collections of software which can be added to emacs.

explain what the package `org-roam` does in emacs

econky

(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)

browsing

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))

note taking

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))

spelling

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)))

commands

[M-x] opens minibuffer [M-|] shell command on region [M-:] eval eval-region

register and bookmarks

Registers and bookmarks in emacs are temporary information you can save in your session.

The useful commands for registers and bookmarks are:

[M-x]
insert bookmark
[C-x r SPC]
to save register in buffer (give it a name)
[C-x r s]
store text into a register
[C-x r +]
append to register
[C-x r i]
insert text from register
[C-u C-x r i]
insert and replace
[C-x r c]
copy to clipboard
[C-x y j]
jump to register
[C-x b]
to save the current bookmark
[C-x r b]
To add bookmark, mark position
[C-x]
to save bookmark
[C-x f]
To list all bookmark

A bookmark is persistent

[C-x r m]
create a bookmark
(no term)
elisp:(bookmark-save)
(set-register ?h '(file . "~/lav/src/spiega/template/header_org.org"))
(file . ~/lav/src/spiega/template/header_org.org)

keybindings

#+name : keybindings

(describe-key "C-a")
C - a is undefined

edit

region
[SPC ->] [SPC <-] select region [M-w] copy region [C-y] paste region [M-y] cycle copied regions [M-@] add a word to region [M-h] select paragraph/function [C-x h] [C-x C-p] mark buffer/page [C-x C-x] mark till previous location
navigate
[C-u C-SPC] cursor back to previous location

file manager

open
[C-x C-j] to open dired [C-x C-q] W-dired mode [C-c C-c] finished [o] opens in a new buffer [C-o] temporarly opens in a new buffer
navigate
[i] opens a subdirectory in the same buffer [C-u C-SPC] move the cursor back [C-M-n] next subdirectory [C-M-p] previous subdirectory [C-M-u] up a level [C-M-d] down a level [<] [>] move between directories [$] toggle directory [M-g] header line [A] search within marked files
deletion
[d] mark for deletion -> [x] delete flagged files [D] delete marked files [u] unmark for deletion [% d] deletion with regexp
select
[* /] select directories [* s] select files [* c] [u] unmark [* %] regexp [M {] [M }] navigate marked [e] open marked file
copy/move
[+] new directory [c] copy marked files into new directory [H] [S] [Y] links (hard, symbolic, relative) [M] [G] [O] chmod/chgrp/chown
edit
[Q] sed in the marked files [&] asychrounous job [?] iterate once per each file [*] expand the file name [% R] rename files with regexp (old_\(.*\) -> new_\&) [% l] [% u] uppercase lowercase
search
elisp:(find-grep-dired) search file content

elisp:(dired)

media player

elisp:(emms) elisp:(eradio)

(use-package emms)

shell

Shell in a buffer

shell
[C-e s] elisp:(eshell)

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"))

web browser

You can start a web browser elisp:(eww%20'%22intertino.it%22)

media player

news feed

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

email

We can use mu4e package.

(use-package mu4e)

voice assistant

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

multimedia

inkscape

(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))))

lilypond

(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)

coding

How can we configure emacs for coding.

language server

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

linters

flycheck
flymake
blacken

code assistant

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):

eglot
language-server protocol (pyright for Python, typescript-language-server for TS/JS). Feeds real code completions.
corfu
popup UI that shows candidates from any completion-at-point source.
minuet
AI ghost-text suggestions ("inline copilot"), generated by a local LLM.

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

eglot

[M .]
find definition [M ,] return
[M ?]
find references [M ,] return
[M /]
go to next diagnostics [M ,] return
[C M i]
complete
(no term)
[M ;]
toggle comment

company-mode

[C M o]
[C M f]
find file

corfu

[C M x]
show candidates

The AI/ghost-text backend is swappable

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
the URL of the OpenAI-compatible completions endpoint.
:api-key
a token, an env-var name such as "UNSLOTH_TOKEN" (minuet resolves the env var at request time), or a placeholder like "TERM" for backends that ignore auth.
:model
the model identifier; coder/FIM-aware models give the best ghost-text quality.
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).

  • Hardware-aware recommendation (recommend, never auto-switch)

    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
    returns the recommendation plist (:tier full|lite :packages (...) :auto-suggest t|nil :eglot-auto t|nil :reason string).
    packages-report-hardware
    prints CPU/RAM/recommendation at startup (M-x to re-show).
    packages-apply-recommended
    manual M-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
             
  • Per-machine overlay: .emacs.d/machine.el

    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).
    (no term)
    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-url
    feed ellama_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 resilience (missing local LLM)

    minuet never blocks Emacs or spams errors when the LLM is absent:

    • At startup 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.
    • With no backend, auto-suggest stays off (M-i stays quick and harmless); a dead backend just yields a one-line message instead of a freeze.
    • Plain-English: minuet also suggests in prose buffers — it is hooked into 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.
    • When the UI lags, apply the lighter stack at any time with M-x packages-apply-recommended.

Startup behavior (fast boot, splash, session restore)

To keep a cold boot snappy the heavy / asynchronous work is deferred:

org-roam
is fully lazy: it registers its hooks at load but never builds the DB at boot (a large vault of hundreds of org+md files would otherwise make startup appear to hang). org-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.
minuet
probes its backend in the background (see above).
ellama
refreshes its provider list on a 3-second idle timer.
straight
the transient *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.

auto-completion

Built-in:

dabbrev
expand: [M-/] complete: [M-C-/]
hippie-expand
cape
completion at point

Extensions (active):

minuet
elisp:(minuet-next-suggestion) AI ghost-text (local LLM)
corfu
elisp:(corfu-mode) popup UI for completion-at-point
eglot
language-server completions (pyright, typescript-language-server)
helm
ivy
devdocs

(company and company-jedi were the older Python completer; removed from emacs.el.)

Minibuffer completion

vertico
elisp:(use-package%20vertico) drop down menu
orderless
elisp:(use-package%20orderless)
consult
marginalia
embark
(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

autocompletion guide (current setup)

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:

corfu
popup UI that shows candidates from any completion-at-point source
eglot
language-server protocol; feeds corfu real code completions
minuet
AI ghost-text suggestions from the local LLM

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).

bindings

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.

languages supported

python
eglot auto-starts pyright (real LSP completion -> corfu)
typescript / javascript
eglot auto-starts typescript-language-server for .ts/.tsx/.js/.jsx and web-mode
R / web / org
ESS, web-mode and org-native features provide their own completion sources

what runs when, and why no collision

  1. You type in a .py file. eglot connects to pyright (auto via python-mode-hook eglot-ensure) and offers candidates.
  2. corfu pops up the candidates. TAB or middle-click accepts one.
  3. If a minuet ghost appears after the 0.5s debounce, 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.

installing the backends

# 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.

helm

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
    )

ivy

Lighter minibuffer-completion framework (companion of helm). Optional alternate; commented out in emacs.el.

jupyter

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))

additional

eglot snippet ement

orderless

Flexible, order-independent minibuffer/completion matching (space-separated substrings match in any order). Complements vertico/consult.

(use-package orderless)

clang-format

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

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

dabbrev

Enable key bindings

(global-set-key (kbd "M-/") 'dabbrev-expand)
(global-set-key (kbd "M-C-/") 'dabbrev-completion)
dabbrev-completion

cape

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

hippie-exp

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)))

what to actually run (preferred setup)

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):

  • On a capable machine (gaming laptop / workstation, local LLM running): full → eglot + corfu + minuet auto-suggest.
  • When the UI lags, on an old/thin laptop, or with no local LLM available: 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.

LLM coding assistant

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:

simple tasks
and test every progress. Agents taking too many autonomous decisions are difficult to oversee
little interpretation
agents need to understand and wait for agreement

Well configured coding assistants don't need extreme performant models

pi agent
pi-coding-agent the one I'm currently use the most
aideremacs
aider too many interactions
opencode
opencode in emacs

More on

ollama chat

;; 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)

local LLM clients in emacs

Three Emacs clients talk to LLM backends; they are configured in ~/.emacs.d/llm.el (the LLM module) and ~/.emacs.d/.

gptel (code)
full-featured chat + tool/MCP integration, routed through the gptel tools in ~/.emacs.d/gptel_tools.el. Lazy-loaded.
ellama (reasoning/docs)
lightweight chat everywhere, providers + helpers in ~/.emacs.d/ellama_setup.el, lazy-loaded by ellama-load-and-call.
ollama-buddy (Unsloth)
the direct client for the local Unsloth server (GGUF models) with a role/transient menu.

gptel

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.

ellama

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.

ollama-buddy

Configured in llm.el (the LLM module).

  • Default model: unsloth/gemma-4-E2B-it-GGUF
  • Host/port: localhost:~8889~ (the local Unsloth server)
  • Auth: UNSLOTH_TOKEN (API key)
  • Convert markdown replies to Org (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.

aider emacs

(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)))

elmo

(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)

interactive programming

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:

python
I can access all the methods and help in the panel
IoT
I can open a serial terminal
nodejs
I can test promises too
R
visualize on the fly the results
octave
for more complex mathematical functions
lisp
elisp:(ieml)

other packages

treesit

Source code into syntax tree

activate
elisp:(tree-sitter-mode)
(use-package treesit-auto)
(use-package tree-sitter)
(use-package tree-sitter-org
  :straight (:host github :type git :repo "Idorobots/tree-sitter-org" )
  )
t

ido-mode

bot review

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:

  1. Customization and Personalization:
    • Themes: Uses the 'misterioso' theme with custom colors to improve visual comfort.
    • Font Settings: Adjustable font size through global shortcuts for better readability.
    • Transparency Control: Toggle transparency settings with `C-c l`.
  2. Package Management:
    • Extensive Package List: Includes packages like `gptel`, `eradio`, `ess-R-data-view`, and more, tailored for development needs.
    • Auto-Install and Update: Packages are managed using MELPA, ensuring up-to-date features and tools.
  3. Code Mode Enhancements:
    • Multiple Language Support: Extensive support for languages including R, Python, JavaScript, CSS, HTML, PHP, etc., with mode-specific functionalities like indentation and beautification.
    • Interactive Code Execution: Features like running code snippets directly from Emacs buffers for quick testing and prototyping.
  4. Development Tools:
    • Version Control Integration: Basic backup settings to prevent data loss.
    • Desktop Mode: Restores open buffers across sessions, enhancing productivity.
    • Shell Interactions: Enhanced shell modes for better integration with Node.js and Python.
  5. Project Management:
    • Projectile Integration: For managing projects efficiently, particularly useful with `platformio-mode`.
    • Keybindings for common project tasks like building, uploading, serial communication, and cleaning.
  6. AI and LLM Integration:
    • Ellama (formerly gptel) for AI-driven coding assistance, enabling features like code review, summarization, translation, and more.
    • Minuet for inline code suggestions using AI models.
  7. Spelling and Documentation:
    • Flyspell integration for on-the-fly spelling correction in text and markdown modes.
    • ESS (Emacs Speaks Statistics) for R development with enhanced interactivity.
  8. Custom Functions and Commands:
    • Various custom functions like `my-python-auto-run`, `toggle-transparency`, and more, tailored to specific workflows.
    • Keybindings for quick access to features like running Python code snippets or toggling transparency.

Usage and Importance:

  • Enhanced Productivity: Features like auto-completion, inline suggestions, and AI-driven assistance significantly reduce the time spent on repetitive tasks and improve overall coding efficiency.
  • Collaboration: Tools like `gptel` facilitate real-time collaboration with developers and stakeholders, enabling quick feedback and discussions.
  • Learning and Development: Comprehensive language support and documentation tools encourage continuous learning and skill development.
  • Error Prevention: Features like flyspell help catch spelling errors early in the coding process, reducing bugs.

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.

2026

2026-07 July

2026-07-24 Friday

bot review

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:

  1. Customization and Personalization:
    • Themes: Uses the 'misterioso' theme with custom colors to improve visual comfort.
    • Font Settings: Adjustable font size through global shortcuts for better readability.
    • Transparency Control: Toggle transparency settings with `C-c l`.
  2. Package Management:
    • Extensive Package List: Includes packages like `gptel`, `eradio`, `ess-R-data-view`, and more, tailored for development needs.
    • Auto-Install and Update: Packages are managed using MELPA, ensuring up-to-date features and tools.
  3. Code Mode Enhancements:
    • Multiple Language Support: Extensive support for languages including R, Python, JavaScript, CSS, HTML, PHP, etc., with mode-specific functionalities like indentation and beautification.
    • Interactive Code Execution: Features like running code snippets directly from Emacs buffers for quick testing and prototyping.
  4. Development Tools:
    • Version Control Integration: Basic backup settings to prevent data loss.
    • Desktop Mode: Restores open buffers across sessions, enhancing productivity.
    • Shell Interactions: Enhanced shell modes for better integration with Node.js and Python.
  5. Project Management:
    • Projectile Integration: For managing projects efficiently, particularly useful with `platformio-mode`.
    • Keybindings for common project tasks like building, uploading, serial communication, and cleaning.
  6. AI and LLM Integration:
    • Ellama (formerly gptel) for AI-driven coding assistance, enabling features like code review, summarization, translation, and more.
    • Minuet for inline code suggestions using AI models.
  7. Spelling and Documentation:
    • Flyspell integration for on-the-fly spelling correction in text and markdown modes.
    • ESS (Emacs Speaks Statistics) for R development with enhanced interactivity.
  8. Custom Functions and Commands:
    • Various custom functions like `my-python-auto-run`, `toggle-transparency`, and more, tailored to specific workflows.
    • Keybindings for quick access to features like running Python code snippets or toggling transparency.

Usage and Importance:

  • Enhanced Productivity: Features like auto-completion, inline suggestions, and AI-driven assistance significantly reduce the time spent on repetitive tasks and improve overall coding efficiency.
  • Collaboration: Tools like `gptel` facilitate real-time collaboration with developers and stakeholders, enabling quick feedback and discussions.
  • Learning and Development: Comprehensive language support and documentation tools encourage continuous learning and skill development.
  • Error Prevention: Features like flyspell help catch spelling errors early in the coding process, reducing bugs.

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.