Emacs Lisp coding conventions and elpaca rebuild patterns. Use when writing, reviewing, or testing Elisp code.
Elisp changes propagate to the running Emacs in two phases. Understanding both is critical to avoid testing stale code.
A PostToolUse hook () fires on edits to files under or . It triggers + . However, (), which is a separate git checkout from the canonical . Pre-commit, the elpaca clone has the old code, so this rebuild may load stale definitions. This is expected and harmless.
load-elisp-after-edit.sh.elelpaca/sources/dotfiles/emacs/extras/elpaca-rebuildelpaca-extras-reloadelpaca-rebuild compiles from the elpaca source cloneelpaca/sources/dotfiles/~/My Drive/dotfiles/A git post-commit hook (sync-elpaca-clone.sh) runs after every commit. It fetches from the local gitdir into the elpaca source clone, resets it to FETCH_HEAD, then runs elpaca-rebuild + elpaca-extras-reload for each changed package. Only after committing does the running Emacs have the latest code.
~/My Drive/dotfiles/emacs/extras/batch-test.sh to verify compilation (this uses the canonical source, not the elpaca clone)emacsclient -e expressionsYou must never use load-file, eval-buffer, eval-defun, or manual byte-compile commands to reload Elisp. If you find yourself reaching for these, the correct action is to commit so the post-commit hook propagates the changes.
A PreToolUse hook (block-elpaca-rebuild-uncommitted.sh) blocks manual elpaca-rebuild calls when there are uncommitted .el changes, to prevent accidentally testing stale code.
See emacs/extras/doc/elisp-development-workflow.org for the full design rationale.
Do these proactively to avoid being blocked by pre-commit hooks:
emacs --batch before committing (details below).emacs/extras/doc/<package>.org manual update alongside .el files. Use /doc-elisp to generate or update documentation.A PreToolUse hook blocks git commit when .el files are staged until an emacs --batch test has run. Use the helper script:
~/My\ Drive/dotfiles/claude/bin/batch-test.sh YOUR-PACKAGE
~/My\ Drive/dotfiles/claude/bin/batch-test.sh YOUR-PACKAGE '(message "Result: %S" (YOUR-TEST-EXPRESSION))'
The script handles profile resolution, load-path setup, and stale .elc cleanup automatically.
ert-run-tests-batch, etc.) in the active Emacs session via emacsclient. Use a separate emacs --batch process. The active session is for loading code and interactive testing, not test suites.emacsclient -e to print large Emacs objects (hash tables, EIEIO objects, etc.). Serializing them freezes Emacs. Always extract specific slots or counts instead (e.g. (hash-table-count ht) instead of ht).emacsclient -e: no font-lock-ensure, no interactive commands, no unbounded loops, no operations whose runtime is unpredictable. A hung emacsclient blocks the Emacs server queue and makes Emacs unresponsive.next-single-property-change for O(regions) jumps, or skip the diagnostic entirely and reason from the code.sed or other Bash commands are used to edit .el files (bypassing the Edit tool), manually call emacsclient --eval '(load-file "...")' afterward — the PostToolUse hook only fires on Edit/Write..el files simultaneously — the elpaca rebuild hook fires on each save, flooding Emacs with concurrent rebuilds. Serialize edits or batch into a single agent.After adding or modifying a transient-define-prefix, verify that every suffix symbol is an interactive command. Transient defers suffix validation to invocation time, so byte-compilation and commandp on the prefix itself will not catch non-interactive suffixes. Before committing, check every suffix via emacsclient -e '(interactive-form (quote SYMBOL))' — any that return nil need an (interactive) spec added to their defun.
If you need to understand what the script does (e.g., for debugging), the key details:
elpaca/builds/*/ directories are added to load-path via file-expand-wildcards.emacs/extras is pushed to the front so edited .el sources take precedence over stale .elc in elpaca builds.load-prefer-newer (causes version mismatches) or append (puts extras at the end where elpaca builds take precedence).