#+TITLE: Module Inventory — init.el Load Graph #+AUTHOR: Craig Jennings #+DATE: 2026-05-24 * Purpose Living per-module inventory for the [[file:init-load-graph.org][init.el load-graph refactor]]. The spec's module-category table is the seed; this file is the per-module truth as each module is inspected and classified. A module moves from [[*Pending classification][Pending classification]] into [[*Classified modules][Classified modules]] once its source has been read and its load-graph header written. Phase 1 exit criterion: every module required by =init.el= (103 total) is represented here with a category and target load shape, every eager survivor has a documented reason, and top-level timer/process/network side effects are identified. Classification proceeds in batches; the header-validation test =tests/test-init-module-headers.el= enforces the contract on each classified module. This inventory is independent from the helper inventory owned by =utility-consolidation.org=. * Status - Phase 1 (Inventory and Contracts), in progress. - Batch 1 (Foundation, Layer 1): classified. 7 modules. - Batch 2 (Text/editing command modules, Layer 2): classified. 9 modules. - Batch 3 (Core libraries and command modules): classified. 7 modules. - Batch 4 (UI / core-UX modules, Layer 2): classified. 11 modules. - Batch 5 (Dev entry-points, diff, help, lint, VC, Layer 2): classified. 9 modules. - Batch 6 (Programming modules, Layer 2-4): classified. 10 modules. - Batch 7 (Org modules, Layer 3-4): classified. 13 modules. - Batch 8 (Domain / integration / optional modules, Layer 2-4): classified. 18 modules. - Batch 9 (Remaining domain / integration / optional modules, Layer 2-4): classified. 19 modules. - 103 of 103 modules classified. Phase 1 classification complete. - No load-order changes have been made; =init.el= keeps its current eager order. * Legend Category key (a module may carry two, e.g. =F/S=): - =F= foundation or shared library/config - =C= core eager UX - =P= package configuration (usually hook/command/package loaded) - =D= domain workflow with a possible eager reason - =S= startup side-effect / timer / process owner - =O= optional, entertainment, experimental, rarely used - =L= pure-ish library / command helpers, easy to load directly Load shape: =eager= | =hook= | =mode= | =command= | =after-load=. Direct test load: =yes= | =conditional= | =no= — can the module be loaded directly in batch without first loading the rest of init? * Classified modules ** Batch 1 — Foundation (Layer 1) | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =system-lib= | 1 | F/L | eager | eager | none (auth-source on demand) | none | yes | | =user-constants= | 1 | F | eager | eager | none | file writes: creates configured dirs/files at load | conditional | | =host-environment= | 1 | F/L | eager | eager | none (battery on demand) | none | yes | | =system-defaults= | 1 | F/S | eager | eager | autorevert, server, bookmark, host-environment, user-constants | global setq, display-warning advice, display-buffer-alist entry, one key remap | yes | | =keyboard-compat= | 1 | F/S | eager | eager | host-environment | adds emacs-startup-hook | yes | | =keybindings= | 1 | F/C | eager | eager | user-constants, which-key, free-keys | defines cj/custom-keymap + cj/jump-map, binds global keys, which-key labels | conditional | | =config-utilities= | 1 | C/O | eager | eager | cl-lib, cl-generic, eieio, find-lisp, profiler | defines cj/debug-config-keymap, binds C-c d | yes | Every Batch 1 module stays eager: each satisfies a spec eager-reason condition (shared helpers, path constants, core Emacs behavior, or the global keymap owner). Reasons are recorded in each module's load-graph header. ** Batch 2 — Text/editing command modules (Layer 2) The =custom-*= text-command helpers. Each is eager only to register a =C-;= submap (or direct bindings) at load; none has a necessary eager reason, so all are deferral candidates for Phase 3 (registration API) and Phase 4 (command/autoload). Target load shape is command-driven. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =custom-case= | 2 | L/C | eager | command | keybindings | cj/case-map under C-; c; remaps capitalize-region | yes | | =custom-comments= | 2 | L/C | eager | command | keybindings | cj/comment-map under C-; C | yes | | =custom-datetime= | 2 | L/C | eager | command | keybindings | cj/datetime-map under C-; d | yes | | =custom-buffer-file= | 2 | L/C | eager | command | keybindings, external-open, mm-decode, system-lib | cj/copy-buffer-content-map, cj/buffer-and-file-map; C-; b | yes | | =custom-line-paragraph= | 2 | L/C | eager | command | keybindings (expand-region on demand) | cj/line-and-paragraph-map under C-; l | yes | | =custom-misc= | 2 | L/C | eager | command | keybindings | align-regexp advice; direct C-; bindings | yes | | =custom-ordering= | 2 | L/C | eager | command | cl-lib, keybindings (org-config on demand) | cj/ordering-map under C-; o | yes | | =custom-text-enclose= | 2 | L/C | eager | command | keybindings (change-inner on demand) | cj/enclose-map under C-; s | yes | | =custom-whitespace= | 2 | L/C | eager | command | keybindings | cj/whitespace-map under C-; w | yes | ** Batch 3 — Core libraries and command modules The remainder of init.el's early/core block: shared command libraries and a few eager side-effect owners. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =external-open= | 2 | L/D | eager | command | host-environment, system-lib, external-open-lib, cl-lib | none | yes | | =media-utils= | 3 | D/L | eager | command | system-lib | none | yes | | =auth-config= | 1 | F/D | eager | eager | system-lib, user-constants | auth-source/epa config | yes | | =keyboard-macros= | 2 | C/L | eager | command | subr-x, user-constants | none | yes | | =system-utils= | 2 | L/C/S | eager | eager | system-lib, external-open-lib | 3 global keys, 1 startup hook | yes | | =text-config= | 2 | C/P | eager | eager | none | 3 add-hook, package config | yes | | =undead-buffers= | 2 | C | eager | eager | none | 3 global keys (kill-buffer remap) | yes | ** Batch 4 — UI / core-UX modules (Layer 2) Modules that shape the first interactive frame: theme, font, modeline, window navigation, completion stack, and landing page. Most have a real first-frame eager reason and stay eager. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =auto-dim-config= | 2 | C/O | eager | eager | none (loads ~/code auto-dim fork) | enables global minor mode, edits affected-faces | conditional | | =ui-config= | 2 | C/S | eager | eager | user-constants | UI defaults, post-command hook, display-buffer-alist | yes | | =ui-theme= | 2 | C | eager | eager | none | theme load path, theme key | yes | | =ui-navigation= | 2 | C/P | eager | eager | none | nav keymap, 5 global keys, package config | yes | | =font-config= | 2 | C/P/S | eager | eager | host-environment, keybindings | 5 global font keys, font-install checks | yes | | =selection-framework= | 2 | C/P | eager | eager | none | 1 global key, 15 use-package forms | yes | | =modeline-config= | 2 | C/S | eager | eager | user-constants | 2 add-hook (VC cache) | yes | | =mousetrap-mode= | 2 | C | eager | eager | cl-lib | 3 add-hook, 1 add-to-list, 1 global key | yes | | =popper-config= | 2 | C/P | eager | eager | none | package config (enabled-state open question) | yes | | =dashboard-config= | 2 | C/S | eager | eager | none | builds/opens dashboard buffer at startup | conditional | | =nerd-icons-config= | 2 | C/P | eager | eager | none | package config | yes | ** Batch 5 — Dev entry-points, diff, help, lint, VC (Layer 2) Command entry points and package config for the development workflow: coverage (F7), F-keys (F4/F6), diff, help, lint, the ERT runner, and Magit. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =coverage-core= | 2 | C/L | eager | eager | seq, subr-x, system-lib | 1 global key (F7) | yes | | =coverage-elisp= | 2 | C/P | eager | eager | coverage-core | backend registration | yes | | =dev-fkeys= | 2 | C | eager | eager | cl-lib, system-lib, keybindings | 6 F-key bindings; C-; P | yes | | =diff-config= | 2 | C/P | eager | eager | none | package config | yes | | =help-config= | 2 | C/P | eager | eager | none | 2 global keys, package config | yes | | =help-utils= | 2 | L/D | eager | command | none | 1 global key, package config | yes | | =flycheck-config= | 2 | C/P | eager | hook | keybindings | package config; cj/custom-keymap :map binding | yes | | =test-runner= | 2 | C/L | eager | eager | ert, cl-lib, keybindings | test keymap under cj/custom-keymap | yes | | =vc-config= | 2 | C/P | eager | eager | user-constants, keybindings | 2 keymaps under cj/custom-keymap, package config | yes | ** Batch 6 — Programming modules (Layer 2-4) prog-general owns the shared programming defaults and tree-sitter/LSP policy and stays eager. The language modules are eager only by init order and should load by major mode (Phase 6); prog-training is optional and already autoloads. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =prog-general= | 2 | C/P/S | eager | eager | none | 4 add-hook, package config | yes | | =prog-c= | 3 | D/P | eager | mode | none | 6 add-hook, package config | yes | | =prog-go= | 3 | D/P | eager | mode | none | package config | yes | | =prog-lisp= | 3 | D/P | eager | mode | none | 2 add-hook, package config | yes | | =prog-python= | 3 | D/P | eager | mode | system-lib | package config; warns if pyright missing | yes | | =prog-webdev= | 3 | D/P | eager | mode | system-lib | package config; warns if prettier missing | yes | | =prog-json= | 3 | D/P | eager | mode | none | 1 add-hook, package config | yes | | =prog-yaml= | 3 | D/P | eager | mode | none | 1 add-hook, package config | yes | | =prog-shell= | 3 | D/P/S | eager | mode | none | 5 add-hook (after-save executable hook flagged) | yes | | =prog-training= | 4 | O/D/P | eager | command | none | package config (autoloaded) | yes | ** Batch 7 — Org modules (Layer 3-4) The daily Org workflows (config, agenda, capture, refile, roam) stay eager per the spec's Phase 6 target. Babel and contacts move to after-load; export, reveal, drill, noter, webclipper, and hugo become command-loaded. The agenda and refile idle-timer caches are the side effects the spec tracks separately. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =org-config= | 3 | C/D/P | eager | eager | keybindings | org-protocol, cj/custom-keymap binding, package config | yes | | =org-agenda-config= | 3 | D/S | eager | eager | user-constants, system-lib, cj-cache-lib | add-hook, idle-timer agenda cache | yes | | =org-babel-config= | 3 | D/P | eager | after-load | none | 1 global key, package config | yes | | =org-capture-config= | 3 | D/P | eager | eager | none | capture templates, org-protocol handlers | yes | | =org-contacts-config= | 3 | D/P | eager | after-load | user-constants | 1 global key, package config | yes | | =org-drill-config= | 4 | O/D/P | eager | command | user-constants, keybindings | drill keymap under cj/custom-keymap | yes | | =org-export-config= | 3 | D/P | eager | command | system-lib | package config | yes | | =org-noter-config= | 4 | O/D/P | eager | command | cl-lib, user-constants, keybindings | add-hook, keymap under cj/custom-keymap | yes | | =org-refile-config= | 3 | D/S | eager | eager | system-lib, cj-cache-lib | idle-timer refile cache | yes | | =org-reveal-config= | 4 | O/D/P | eager | command | none | package config | yes | | =org-roam-config= | 3 | D/P/S | eager | eager | user-constants | 1 global key, roam db setup, package config | yes | | =org-webclipper= | 4 | O/D/P | eager | command | none | org-protocol handler | yes | | =hugo-config= | 3 | D/P | eager | command | user-constants, host-environment | package config | yes | ** Batch 8 — Domain / integration / optional modules (Layer 2-4) AI, browser, calendar, ebook, file-manager, shell, IRC, web, games, and other domain workflows. Almost all are eager only by init order and become command-, hook-, or mode-loaded. calendar-sync stays eager when its .local.el is present. flyspell-and-abbrev is the one Core-UX member (text-mode hooks). | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =ai-config= | 3 | D/P | eager | command | keybindings, system-lib | cj/ai-keymap under cj/custom-keymap | yes | | =ai-term= | 3 | D | eager | command | cl-lib, seq, cj-window-geometry-lib, cj-window-toggle-lib, host-environment | 4 global keys | yes | | =browser-config= | 3 | D/P | eager | command | cl-lib | 1 global key | yes | | =calendar-sync= | 3 | D/S | eager (.local.el) | eager (.local.el) | cl-lib, subr-x, system-lib, cj-org-text-lib, keybindings | calendar keymap (C-; g), guarded timer/network | yes | | =calibredb-epub-config= | 4 | O/D/P | eager | command | user-constants, subr-x | add-hook, advice-add, package config | yes | | =chrono-tools= | 3 | D/P | eager | command | user-constants | package config | yes | | =dirvish-config= | 3 | D/P | eager | command | user-constants, system-utils, host-environment, system-lib, external-open-lib | 3 add-hook, package config | yes | | =dwim-shell-config= | 3 | D/P | eager | command | cl-lib | package config | yes | | =elfeed-config= | 4 | O/D/P | eager | command | user-constants, system-lib, media-utils | package config (elfeed bindings) | yes | | =erc-config= | 4 | O/D/P | eager | command | cl-lib, keybindings | ERC keymap under cj/custom-keymap | yes | | =eshell-config= | 3 | D/P | eager | command | system-utils | add-hook, advice-add, package config | yes | | =eww-config= | 3 | D/P | eager | command | cl-lib | package config | yes | | =flyspell-and-abbrev= | 2 | C/P | eager | hook | cl-lib | mode-hook package config | yes | | =games-config= | 4 | O | eager | command | none | package config | yes | | =gloss-config= | 4 | O/D/P | eager | command | none | package config | yes | | =httpd-config= | 4 | O/D/P | eager | command | none | package config | yes | | =jumper= | 4 | O/L | eager | command | cl-lib | jumper keymap | yes | | =latex-config= | 3 | D/P | eager | mode | none | package config | yes | ** Batch 9 — Remaining domain / integration / optional modules (Layer 2-4) The last 19 modules: mail, terminals, chat, media capture, package mirror, and assorted optional tools. mail-config and the daily terminals stay practically eager; the rest are command/mode/package-loaded deferral candidates. wrap-up owns the intentional end-of-startup buffer-bury timer. | Module | Layer | Cat | Current | Target | Runtime requires | Top-level side effects | Direct load | |--------+-------+-----+---------+--------+------------------+------------------------+-------------| | =linear-config= | 3 | D/P | eager | command | system-lib | package config | yes | | =local-repository= | 4 | O/D/P | eager | command | elpa-mirror | none | yes | | =lorem-optimum= | 4 | O/L | eager | command | cl-lib | none | yes | | =mail-config= | 3 | D/P | eager | command | user-constants, system-lib, mu4e-attachments, keybindings | cj/email-map under cj/custom-keymap, add-hook, 2 advice, 1 global key | yes | | =markdown-config= | 3 | D/P | eager | mode | none | package config, org-src lang map | yes | | =music-config= | 4 | O/D/P/S | eager | command | subr-x, user-constants, keybindings | music keymap under cj/custom-keymap, 1 global key | yes | | =pdf-config= | 3 | D/P | eager | mode | none | package config | yes | | =quick-video-capture= | 4 | O/D/S | eager | command | system-lib | org-protocol handler | yes | | =reconcile-open-repos= | 3 | D/S | eager | command | cl-lib, subr-x | 1 global key | yes | | =restclient-config= | 3 | D/P | eager | command | none | package config | yes | | =slack-config= | 4 | O/D/P | eager | command | system-lib, cl-lib | package config | yes | | =system-commands= | 3 | D/S | eager | command | keybindings, rx | system-command keymap under cj/custom-keymap | yes | | =telega-config= | 4 | O/D/P | eager | command | keybindings | telega keymap under cj/custom-keymap | yes | | =tramp-config= | 3 | D/P | eager | package | none | package config | yes | | =transcription-config= | 4 | O/D/P | eager | command | dired, notifications, system-lib, user-constants | 1 add-to-list | yes | | =video-audio-recording= | 4 | O/D/S | eager | command | system-lib, keybindings | cj/record-map under C-; r | yes | | =term-config= | 3 | D/P | eager | command | keybindings, seq, subr-x, cj-window-geometry-lib, cj-window-toggle-lib | 2 keymaps, 1 global key, 2 add-hook | yes | | =weather-config= | 4 | O/D/P | eager | command | none | package config | yes | | =wrap-up= | 2 | S | eager | eager | system-lib | one-shot startup buffer-bury timer | yes | * Hidden dependencies (resolved in Phase 2) Discoveries from classification, all resolved in Phase 2 by making each dependency explicit: requiring the owning module (=host-environment=, =user-constants=, =keybindings=) and dropping the =boundp= / =eval-when-compile= shims. Each consuming module now loads standalone (verified with a fresh =emacs --batch (require 'X)= per module). Kept here as the record of what was found and fixed; the =Phase 2 fix:= notes below describe the change applied. - =system-defaults= reads =env-bsd-p= (host-environment) and =user-home-dir= (user-constants) at *load* time, but declares both only via =eval-when-compile=. The compiled module therefore cannot load standalone — it works at startup only because =init.el= requires host-environment and user-constants earlier. Phase 2 fix: promote the two =eval-when-compile= requires to plain runtime =require=. (Test =test-system-defaults-functions.el= was updated to require host-environment so the unit loads in isolation; the production fix is still pending.) - =custom-buffer-file= registers its =C-; b= submap behind =(when (boundp 'cj/custom-keymap) ...)= and declares =cj/custom-keymap= only via =eval-when-compile=. Loaded standalone without keybindings, the =boundp= guard is nil and the binding silently drops. That guard is the "define-if-not-present" shim the spec warns against. Phase 2/3 fix: require keybindings (or use the registration API once it exists) and drop the guard. - =dev-fkeys= uses the same =(when (boundp 'cj/custom-keymap) ...)= shim plus an =eval-when-compile= declaration for its =C-; P= binding, so the binding silently drops when loaded without keybindings. Same Phase 2/3 fix. - =flycheck-config= binds =(:map cj/custom-keymap ...)= through use-package but does not require keybindings, so the binding fails when the module loads standalone. Phase 2 fix: require keybindings (or move to the registration API). - =calendar-sync= guards its =C-; g= registration with =(when (boundp 'cj/custom-keymap) ...)= and does not require keybindings, so the binding silently drops standalone. Same boundp-shim pattern. Phase 2/3 fix. - =video-audio-recording= uses the same =(when (boundp 'cj/custom-keymap) ...)= shim for its =C-; r= binding without requiring keybindings. Same Phase 2/3 fix. - =mail-config= registers =cj/custom-keymap "e"= directly (no boundp guard) and does not require keybindings, so it errors standalone rather than degrading. Phase 2 fix: require keybindings (or use the registration API). * Deferred classification - None. =elfeed-config= was the last deferred module; its tests were rewritten to build real =elfeed-entry= structs (so they survive byte-compilation) and it is now classified in Batch 8. * Pending classification - None. Every module required by =init.el= is classified (103 of 103).