VOMPECCC: A Modular Completion Framework for Emacs

VOMPECCC: A Modular Completion Framework for Emacs

1. About   emacs completion modularity

vompeccc-banner.jpeg

Figure 1: JPEG produced with DALL-E 3

Completion is not a feature or UI, but instead it is a system composed of at least half a dozen orthogonal concerns that most users never think about separately. The previous post in this series argued that Emacs uniquely exposes completion as a programmable substrate rather than a sealed UI, and that this substrate is what makes Incremental Completing Read (ICR) viable as a primary interaction pattern in Emacs. This post is about the packages that build on that substrate in practice.

VOMPECCC is a loose acronym for eight of them that, together, form a complete, modular, Unix-philosophy-aligned completion framework for Emacs: V​ertico, O​rderless, M​arginalia, P​rescient, E​mbark, C​onsult, C​orfu, and C​ape. Each package does one thing, and the key attribute of all eight is that they compose through Emacs's standard completion APIs, meaning any subset works without the others.

I'm writing this post because these packages have recently taken the Emacs community by storm, but I rarely see discussions on how they relate or how they compose together to provide a feature complete ICR system in emacs. These packages implement concretely what the antecedent post argues in the abstract: completion is a substrate, or set of primitives, on top of which users can build rich interfaces for effortlessly interacting with your machine to do almost anything.

2. The Hidden Complexity of Completion   complexity design

Even if you've only used Emacs once, you've likely seen it's completion features in action. When you press M-x and start typing, a list appears, you pick something, and it runs. But beneath that interaction lies a system of surprising depth. Consider what a fully featured completion experience actually requires:

Candidate display. Where do completion candidates appear? In the minibuffer, vertically? Horizontally? In a separate buffer? In a popup at point? The display layer determines how you scan and navigate candidates, and of course the optimal display is context dependent. Switching buffers might want a vertical list; completing a symbol in code might want a popup near the cursor.

Filtering. You can also think of this as 'matching': how does your input match against candidates? Literal prefix matching is the simplest: find-f matches find-file. But if we want to add some flexibilty (or 'fuzzy matching'), where for examplke ff matches find-file? What about splitting your input into multiple components and matching all of them in any order? What about mixing strategies, for example, where one component matches as a regexp, and another matches as an initialism? Candidate lists can be huge, so we need this set of features as a sort of query language for filtering the candidate list to find what we're looking for.

Sorting. Once you have your filtered candidates, in what order do you see them? Alphabetically? By string length? By how recently you selected them? By frequency of use? A good sorting strategy means the candidate you want is almost always within the first few results. A bad one means scrolling every time.

Annotation. A bare list of candidate names is often insufficient or unhelpful. Often, candidates are of a certain 'type' or 'category' and have rich metadata associated with them. In the M-x example, when selecting a command, you likely want to see its keybinding and docstring. When selecting a file, you likely want to see its size and modification date. When selecting a buffer, you want to see its major mode and file path. Annotations transform a list of strings into a list of informed choices.

Actions. Selecting a candidate (and running some default action) is the most common interaction, but not the only one. In the find-file example, what if you want to delete the file instead of opening it? In the M-x example, what if you want to describe the function instead of running it? A completion system without contextual actions forces you out of the flow: complete, exit, invoke a separate command, etc….

In-buffer completion. Everything above applies to the minibuffer (the prompt at the bottom of the screen). But completion also happens inside buffers: symbol completion while writing code, dictionary words while writing prose, file paths while editing configuration. In-buffer completion has its own display requirements (a popup near the cursor, not the minibuffer) and its own backend requirements (language servers, dynamic abbreviations, file system paths). A truly complete completion system must handle both contexts well.

Completion is not one problem. It is at least six, and most frameworks pretend otherwise.

These six concerns are orthogonal. The way you display candidates has nothing to do with how you filter them; the way you sort them has nothing to do with what actions you can take, etc…. It's actually a useful thought exercise to go through each of the six concerns and appreciate how each is independent from the others. A single-package system can deliver an excellent out-of-the-box experience across all of these, and many have (see Ivy and Helm below). The trade-off is usually that the boundaries between concerns become harder to see, and harder to swap one concern's implementation without disturbing the others.

3. The Monolith Era: Helm and Ivy   helm ivy legacy

For the better part of a decade, two incredible frameworks dominated Emacs completion: Helm and Ivy. Both were genuinely transformative, because in my opinion, they proved that Emacs's built-in completion experience was inadequate, and they inspired everything that followed. But both, in retrospect, made the same architectural trade-off: they bundled every concern into a single package with a single API. I have used both packages extensively, as both a package author and a consumer. The benefits were immediate for me, but the costs emerged over time.

3.1. Helm: The Kitchen Sink

Helm traces its lineage to anything.el, created by Tamas Patrovics in 2007. Thierry Volpiatto, a French alpine guide who taught himself programming after discovering Linux in 20061, forked it as Helm in 2011 and contributed nearly 7,000 commits over the following decade. Helm became the most downloaded package on MELPA2 and the default completion framework in Spacemacs, which drove massive adoption during 2013–2018.

Helm's ambition was impressive but all-encompassing. It provided its own candidate display, filtering, action system, source API (via EIEIO classes), and dozens of built-in commands for things like file finding, buffer switching, grep, and more…. The actions system was comprehensive too — it offered 44+ file actions alone.

Helm showed what great completion could feel like. Its architecture showed what happens when a single maintainer carries every concern alone.

The cost was proportional to Thierry's ambition. Users reported multi-second delays on basic operations after extended use, 100–500ms lag on window popups, and CPU-intensive fuzzy matching that required disabling for large projects. Samuel Barreto's widely cited "From Helm to Ivy" essay called Helm "a big behemoth size package" and reported using only a third of its capabilities.

Most critically, Helm replaced Emacs's completing-read entirely with its own proprietary helm-source API. Every Helm extension was written against this API. None of them could be reused with any other completion system. That was the helm killer for me: if Helm's development stalled — and it did, twice, in 2018 and 20203 — every downstream package would be stranded.

3.2. Ivy: The Lighter Monolith

Ivy emerged in 2015 as Oleh Krehel's direct reaction to Helm's complexity. Where Helm tried to do everything, Oleh aimed to be more minimalist or at least better factored. The package split its concerns into three logical components: Ivy (the completion UI), Swiper (an isearch replacement), and Counsel (enhanced commands).

In practice, the split was cosmetic. All three lived in a single repository. Counsel was coupled to Ivy's internals. And the core architectural choice was the same as Helm's: Ivy defined its own completion API, ivy-read, and Counsel commands called ivy-read directly rather than completing-read. Code written for Ivy worked only with Ivy.

The ivy-read function grew organically to accept roughly 20 arguments with multiple special cases4. As the Selectrum developers noted: "When Ivy became a more general-purpose interactive selection package, more and more special cases were added to make various commands work properly." Users reported performance degradation after extended use, and Ivy broke with Emacs 28 and again with Emacs 30, forcing compatibility polyfills. This is stressful for not only the consumers of Ivy, but also for the maintainers.

When Ivy's original maintainer stepped back, the project entered a period of reduced maintenance. A new maintainer has since taken over and released version 0.15.1, but active feature development has slowed considerably from the 2016–2020 peak.

3.3. The Unix Philosophy Lens

The Unix philosophy, as articulated by Doug McIlroy5, is straightforward: "Write programs that do one thing and do it well. Write programs to work together." Viewed through this lens, both Helm and Ivy bundle too many concerns into packages that communicate through proprietary APIs (helm-source, ivy-read) rather than Emacs's native completing-read contract. The result is that extensions and backends written for one framework cannot be reused with another, making an investment in either tool non-transferable.

None of this diminishes what they achieved, by the way. I'm personally a huge Helm and Ivy fan and I've build with them and consumed them directly for years. In my opinion, the legacy of Helm and Ivy is that they showed the community what great completion felt like, and gave a taste of what a fully featured completion system built on the Emacs substrate could be. The question is whether the architecture that delivered those features is the one we want to build on going forward.

The irony is that Emacs already provides the right abstraction.

  • completing-read is a stable, well-specified API that any UI can render6.
  • completion-styles is a pluggable system for controlling how input matches candidates7.
  • completion-at-point-functions is a standard hook for in-buffer completion backends.

The infrastructure for composable completion has existed for years. It just needed packages that actually used it.

4. The VOMPECCC Framework   vompeccc framework

VOMPECCC is not a framework in the traditional sense. There is no single repository, no shared dependency, and no coordinating package. It is eight independent packages, maintained by three different developers, that compose through Emacs's standard APIs to cover every concern of a complete completion system.

Package Concern Author
Vertico Minibuffer display Daniel Mendler
Orderless Filtering / matching Omar Antolin Camarena & Daniel Mendler
Marginalia Candidate annotations Omar Antolin Camarena & Daniel Mendler
Prescient Sorting / ranking Radon Rosborough
Embark Contextual actions Omar Antolin Camarena
Consult Enhanced commands Daniel Mendler
Corfu In-buffer display Daniel Mendler
Cape In-buffer backends Daniel Mendler

The architecture maps cleanly onto the six concerns identified earlier:

                Minibuffer                     Buffer
                ----------                     ------
Display:        Vertico                        Corfu
Filtering:      Orderless          (shared across both)
Sorting:        Prescient          (shared across both)
Annotations:    Marginalia         (shared across both)
Actions:        Embark             (shared across both)
Backends:       Consult                        Cape

Each package targets a single layer, and they all communicate through standard Emacs APIs: completing-read, completion-styles, completion-at-point-functions, annotation functions, and keymaps. No package knows about the others' internals ‼️, and because of this all of them can be replaced without affecting the rest.

5. Vertico: The Display Layer   vertico display

Vertico (VERTical Interactive COmpletion) provides a vertical candidate list in the minibuffer. It is roughly 600 lines of code, excluding its extensions.

Vertico's defining characteristic is strict adherence to the completing-read contract. It doesn't filter candidates (that's your completion style's job). It doesn't sort them (that's your sorting function's job). It doesn't annotate them (that's your annotation function's job). It just displays them. Any command that calls completing-read, whether built-in or third-party, automatically gets Vertico's UI with zero configuration.

If you think 1 package for display is overkill, like I originally did before migrating to VOMPECCC, keep reading.

Vertico ships with 13 built-in extensions that modify the display behavior:

Extension Effect
vertico-buffer Display in a regular buffer instead of the minibuffer
vertico-directory Ido-like directory navigation (backspace deletes path components)
vertico-flat Horizontal, flat display
vertico-grid Grid layout
vertico-indexed Select candidates by numeric prefix argument
vertico-mouse Mouse scrolling and selection
vertico-multiform Per-command or per-category display configuration
vertico-quick Avy-style quick selection keys
vertico-repeat Repeat last completion session
vertico-reverse Bottom-to-top display
vertico-suspend Suspend and restore completion sessions
vertico-unobtrusive Show only a single candidate

The vertico-multiform extension is particularly worth configuring: it lets you set per-command display modes, so consult-line can open in a full buffer while M-x stays in the minibuffer.

Created: April 2021. Stars: ~1,800. Available on: GNU ELPA.

6. Orderless: The Filtering Layer   orderless filtering

Orderless is a completion style — it plugs into Emacs's completion-styles variable, the standard mechanism for controlling how user input is matched against candidates. Where built-in styles like basic require prefix matching and flex does single-pattern fuzzy matching, Orderless splits your input into space-separated components and matches candidates that contain all components in any order (Orderless reveals its namesake 😜).

Each component can independently use a different matching method:

Style Example Matches
orderless-literal buffer switch-to-buffer
orderless-regexp ^con.*mode$ conf-mode
orderless-initialism stb switch-to-buffer
orderless-flex stbf switch-to-buffer
orderless-prefixes s-t-b switch-to-buffer
orderless-literal-prefix swi switch-to-buffer

Style dispatchers let you select a matching method per component using affix characters: =​= for literal, ~ for flex, , for initialism, ! for negation, & to match annotations. The system is fully extensible.

The typical configuration sets completion-styles to '(orderless basic), with partial-completion for the file category so that ~/d/s expands path components like ~/Documents/src. The fallback to basic is deliberate: some Emacs features (TRAMP hostname completion, dynamic completion tables) require a prefix-matching style.

Let's keep beating the dead horse of this post's theme: because Orderless is a standard completion style, it works with any completion UI that uses Emacs's completing-read API: Vertico, Icomplete, the default *Completions* buffer, and even the minibuffer in Emacs's stock configuration.

Quick timeout: for readers getting to this point thinking "Wow Vertico plus Orderless is a power stack, let's keep stacking", you certainly can see things this way, but instead, I encourage you to consider what it would be like to use each package without the others. That will give you a better understanding of how the consituent stars in the VOMPECCC constellation behave independently. And that's the long term ROI you'll get from VOMPECCC. The independence is what makes stacking safe and fortuitous, but it doesn't make it necessary.

Created: April 2020. Stars: ~979. Available on: GNU ELPA.

7. Marginalia: The Annotation Layer   marginalia annotations

Marginalia adds contextual annotations to minibuffer completion candidates. The name refers to notes written in the margins of books, and here it means metadata displayed alongside each candidate.

Marginalia detects the category of the current completion (files, commands, variables, faces, buffers, bookmarks, packages, etc.) and selects an appropriate annotator function. The detection works through two mechanisms: marginalia-classify-by-command-name (lookup table keyed by calling command) and marginalia-classify-by-prompt (regex matching against the minibuffer prompt text).

Category Annotations shown
Command Keybinding, docstring summary
File Size, modification date, permissions
Variable Current value, docstring
Face Preview of the face styling
Symbol Class indicator (v/f/c), docstring
Buffer Mode, size, file path
Bookmark Type, target location
Package Version, status, description

marginalia-cycle (typically bound to M-A) lets you cycle between annotation levels: detailed, abbreviated, or disabled entirely. This is useful when annotations are consuming screen space during narrow completions.

Marginalia hooks into Emacs's annotation-function and affixation-function properties in completion metadata. Sorry again to the dead horse I've been wailing on, but yes, this means Marginalia works with any completion UI that respects these properties. It is the framework-agnostic successor to ivy-rich8, which provided similar annotations but was Ivy-specific. It's cool to see Oleh and Thierry's visions carry on in these packages!

This was a mind blower to me when I discovered it - one subtle but consequential effect of using Marginalia is that the annotations themselves become searchable. Combined with Orderless's & style dispatcher, your input can match against annotation text as well as candidate names: running M-x and typing window &frame narrows to commands whose name contains "window" and whose docstring contains "frame". The search/matching space extends beyond candidate identifiers into candidate metadata, which is an unusually large leverage gain for what feels like a cosmetic layer. You are no longer constrained to remembering exact names (🤯); you can reach for commands, files, or buffers by properties that were previously invisible to your completion input. This helps to solve for cases where you have a ICR UI, but you don't know exactly what you're looking for. It can also be used to help you 'browse' candidates based on their characteristics as opposed to their names. Honestly my favorite feature of any of the VOMPECCC packages.

Created: December 2020. Stars: ~919. Available on: GNU ELPA.

8. Prescient: The Sorting Layer   prescient sorting

Prescient provides intelligent sorting and filtering of completion candidates based on recency and frequency of use. The portmanteau frecency captures the combined metric that drives the ranking.

Orderless and Prescient are often confused with one another: the difference is that while Orderless answers "which candidates match?", Prescient answers "in what order should they appear?"

The sorting is hierarchical:

  1. Recency — most recently selected candidates appear first
  2. Frequency — frequently selected candidates next, with scores that decay over time
  3. Length — remaining candidates sorted by string length (shorter first)

Usage statistics persist across Emacs sessions via prescient-persist-mode, which writes to a save file. This means Prescient learns your habits: if you frequently run magit-status from M-x, it surfaces near the top after a few uses, regardless of where it falls alphabetically.

Prescient ships as a core library plus framework-specific adapters — vertico-prescient and corfu-prescient being the relevant ones for VOMPECCC. A key architectural insight is that both Vertico and Corfu work seamlessly with Prescient.

A common and powerful configuration combines Orderless for filtering with Prescient for sorting. Among the candidates filtered by Orderless, the most recent and frequent ones get promoted to the top.

Prescient also provides its own filtering methods (literal, regexp, initialism, fuzzy, prefix, anchored) with on-the-fly toggling via M-s prefix commands. However, I personally prefer Orderless for filtering and use Prescient purely for its sorting intelligence. I sort of act as if Prescient was cohesive in this way, rather than giving it responsibility for 2 orthogonal features.

Created: August 2017. Stars: ~695. Available on: MELPA.

9. Embark: The Action Layer   embark actions

Embark provides a framework for performing context-aware actions on "targets" — the thing at point or the current completion candidate. Think of it as a keyboard-driven right-click context menu that works everywhere in Emacs: in the minibuffer and in normal buffers.

The core command is embark-act. When invoked, Embark determines the type of the target (file, buffer, URL, symbol, command, etc.) and opens a keymap of single-letter actions appropriate to that type:

Target Example actions
File Open, delete, copy, rename, byte-compile, open as root
Buffer Switch to, kill, bury, open in other window
URL Browse, download, copy
Symbol Describe, find definition, find references
Package Install, delete, describe, browse homepage

There are over 100 preconfigured actions across all target types.

Beyond embark-act, Embark provides several other capabilities:

  • embark-dwim runs the default action without showing the menu
  • embark-act-all applies the same action to every current candidate (e.g., kill all matching buffers)
  • embark-collect snapshots current candidates into a persistent buffer
  • embark-live creates a live-updating collection that refreshes as you type
  • embark-export exports candidates into the appropriate Emacs major mode: file candidates become a Dired buffer, grep results become a grep-mode buffer (editable with wgrep), buffer candidates become an Ibuffer buffer
  • embark-become switches to a different command mid-stream, transferring your input

Two of these deserve special attention, because they change what a completion session is.

embark-collect freezes the current candidate set into a standalone buffer that persists after the minibuffer exits. This converts an ephemeral interaction (browse, pick, leave) into something durable (collect, hand off, revisit later). The collected buffer remains an Embark target, so the same keymap of actions applies to each entry. It is the right tool when the candidate list itself is the useful artifact: a shortlist of files to process, a set of buffers you want to act on later, a reference you want to keep open on the side.

embark-export goes one step further: instead of a generic candidate buffer, it materializes a buffer in the native major mode appropriate to the candidate type. File candidates become a Dired buffer, with Dired's decades of filesystem operations available. Grep-style candidates become a grep-mode buffer that wgrep can turn into a multi-file editing session, buffer candidates become Ibuffer, package candidates become the package menu, etc…. Each export targets a major mode purpose-built for the candidate type, so you end up inside the tool that was already the best one for the job, arrived at on demand, from a completion prompt, with no navigation overhead. Few interaction patterns in computing convert generic into specialized this cleanly.

Embark is a difference of kind, not quantity, compared to Helm and Ivy's action systems — because it works everywhere, across all types of objects9.

Using embark and consult together we can see a canonical example of this pattern: exporting consult-ripgrep results gives you a wgrep-editable grep buffer, so the workflow — search with Consult, export with Embark, edit with wgrep — compounds three independent packages into a multi-file refactor tool without any of them knowing about the others.

Created: May 2020. Stars: ~1,200. Available on: GNU ELPA.

10. Consult: The Command Layer   consult commands

Consult provides 50+ enhanced commands built on completing-read. It is the spiritual successor to Counsel (from the Ivy ecosystem) but designed to work with any completion UI. Where Counsel called ivy-read directly, Consult uses the native contract, which means its commands work with Vertico, Icomplete, fido-mode, or even Emacs's default completion buffer.

Consult's commands span several categories:

Search:

Command Purpose Replaces
consult-line Search lines in current buffer Swiper
consult-line-multi Search across multiple buffers Swiper-all
consult-ripgrep Async ripgrep search counsel-rg
consult-grep Async grep search counsel-grep
consult-git-grep Git-aware grep counsel-git-grep
consult-find Async file finding counsel-find

Navigation:

Command Purpose Replaces
consult-buffer Enhanced buffer switching helm-mini
consult-imenu Flat imenu with grouping helm-imenu
consult-outline Navigate headings with preview Built-in
consult-goto-line Goto line with live preview Built-in
consult-bookmark Enhanced bookmark selection Built-in
consult-recent-file Recent file selection with preview counsel-recentf

Editing and miscellaneous:

Command Purpose
consult-yank-from-kill-ring Browse kill ring interactively
consult-theme Preview themes before applying
consult-man Async man page lookup
consult-flymake Navigate Flymake diagnostics
consult-org-heading Navigate org headings

Three features make Consult particularly powerful:

Live preview: Most commands show a real-time preview as you navigate candidates. consult-line highlights the matching line in the buffer. consult-theme applies the theme before you select it. consult-goto-line scrolls to the line as you type the number.

Narrowing and grouping: consult-buffer combines buffers, recent files, bookmarks, and project items into a single unified list. Narrowing keys filter to a single source: b SPC for buffers, f SPC for files, m SPC for bookmarks. Custom sources can be added via consult-buffer-sources.

Two-level async filtering: Commands like consult-ripgrep split input at #: everything before it goes to the external tool as the search pattern, everything after it filters the results locally with your completion style. error#handler searches for "error" with ripgrep, then narrows to results containing "handler" using Orderless. Async support is an enormously important feature, because it makes the cognitive cost of search roughly constant with respect to the size of the search space.

Created: November 2020. Stars: ~1,600. Available on: GNU ELPA.

11. Corfu: The In-Buffer Display Layer   corfu completion

Corfu (COmpletion in Region FUnction) is simply the in-buffer counterpart to Vertico. Where Vertico handles minibuffer completion display, Corfu handles the popup that appears at point when you complete a symbol while writing code or text. It is roughly 1,220 lines of code.

Corfu's defining architectural choice mirrors Vertico's: it hooks into Emacs's built-in completion-in-region mechanism rather than inventing its own backend system. Any mode that provides a completion-at-point-function (Eglot, Tree-sitter, elisp-mode, etc.) works with Corfu automatically. Any completion-style (basic, partial-completion, orderless) can be used for filtering.

This is the fundamental difference from Company, the incumbent in-buffer completion framework10. Company uses its own proprietary company-backends API. Company backends don't work with completion-at-point, and Capfs don't work with Company (without an adapter). Anecdotally, I've had many wrestling matches with Company and always found it incredibly difficult to set up properly. Corfu eliminates this split. Doom Emacs recognized this: Company is now deprecated in Doom in favor of Corfu, with plans to remove it post-v311.

Aspect Company Corfu
Backend system Proprietary Emacs-native Capfs
Popup technology Overlays Child frames
Completion styles Limited Any Emacs style
Codebase size Many files, 3,900+ LOC in main file Single file, ~1,220 LOC
Created 2009 2021

Corfu ships with seven built-in extensions:

Extension Purpose
corfu-echo Brief candidate documentation in the echo area
corfu-history Sort by selection history/frequency
corfu-indexed Select candidates by numeric prefix argument
corfu-info Access candidate location and documentation
corfu-popupinfo Documentation popup adjacent to the completion menu
corfu-quick Avy-style quick key selection

Created: April 2021. Stars: ~1,400. Available on: GNU ELPA.

12. Cape: The In-Buffer Backend Layer   cape backends

Cape (Completion At Point Extensions) provides a collection of modular completion backends (Capfs) and a powerful set of Capf transformers for composing and adapting them. If Corfu is the frontend (how completions are displayed), Cape is the backend toolkit (what completions are available).

Cape provides 13 completion backends, here are some highlights:

Capf Purpose
cape-dabbrev Dynamic abbreviation from current buffers
cape-file File path completion
cape-elisp-block Elisp completion inside Org/Markdown blocks
cape-keyword Programming language keyword completion
cape-history History completion in Eshell/Comint

The remaining backends cover dictionary words, emoji, abbreviations, line completion, and Unicode input via TeX, SGML, and RFC 1345 mnemonics.

Cape's Capf transformers are higher-order functions that wrap and modify backends:

  • cape-capf-super merges multiple Capfs into a single unified source
  • cape-capf-case-fold adds case-insensitive matching
  • cape-capf-inside-code / cape-capf-inside-string / cape-capf-inside-comment restrict activation to specific syntactic regions
  • cape-capf-prefix-length requires a minimum prefix before activating
  • cape-capf-predicate filters candidates with a custom predicate
  • cape-capf-sort applies custom sorting

The cape-company-to-capf adapter converts any Company backend into a standard Capf, without requiring Company to be installed. This bridges the two ecosystems: you can use Company-era backends (like company-yasnippet) with Corfu. I don't personally do this, but you can if you want!

Created: November 2021. Stars: ~760. Available on: GNU ELPA.

13. The Subset Property: Use What You Want   modularity flexibility

The most important property of VOMPECCC is that you don't need to buy into all eight packages. You can start with one, add another when you feel a gap, and swap any component for an alternative without breaking anything else.

If you're into inverting dependencies, VOMPECCC is your bag, man.

This works because every package communicates through the native Emacs APIs rather than depending on each other's internals. There are no hard dependencies between any of the eight packages. Here is a map of what each package can be replaced with — or simply omitted:

Package Alternative Or simply…
Vertico Icomplete-vertical, Mct, Ido, fido-mode Default *Completions* buffer
Orderless Hotfuzz, Fussy, Prescient (filtering mode) Built-in flex or substring
Marginalia (none equivalent) No annotations (still works)
Prescient savehist-mode + vertico-sort-override Alphabetical sorting
Embark (none equivalent) Direct command invocation
Consult Built-in switch-to-buffer, grep, etc. Standard Emacs commands
Corfu Company, completion-preview-mode Default *Completions* buffer
Cape Company backends, hippie-expand Mode-provided Capfs

Some practical subset configurations:

Minimal (2 packages): Vertico + Orderless. You get a vertical candidate list with multi-component matching. No annotations, no actions, no enhanced commands — but a dramatically better M-x and find-file experience than stock Emacs.

Comfortable (4 packages): Vertico + Orderless + Marginalia + Consult. Now you have annotations on every candidate and enhanced commands with live preview. This is probably the sweet spot for most users.

Full stack (8 packages): All of VOMPECCC. Complete coverage of both minibuffer and in-buffer completion, with intelligent sorting, contextual actions, and modular backends.

For concrete configuration, the most reliable starting point is each package's own repository — every package linked in the opener ships a comprehensive README with example use-package snippets, and most also provide wikis or info manuals covering more specialized use cases (Vertico's per-command vertico-multiform patterns, Cape's Capf transformer recipes, Embark's keymap customization examples, Consult's custom sources, and so on). Reading those directly is faster than copying a consolidated configuration and then reverse-engineering what each line does, and it scales better as the packages themselves evolve.

14. Growth and Adoption Timeline   timeline adoption

The history of Emacs completion frameworks is a progression from monolithic solutions toward composable ones.

Year Event
1996 Kim F. Storm begins Ido
2007 Ido included in Emacs 22; anything.el created (Helm's ancestor)
2011 Volpiatto forks anything.el as Helm
2013–2018 Helm's golden era: most-downloaded MELPA package, default in Spacemacs
2015 Krehel creates Ivy/Swiper/Counsel
2016 "From Helm to Ivy" blog post sparks migration; Ivy peaks ~2016–2020
2017 Rosborough creates Prescient
2018 Helm enters bug-fix-only mode (maintainer burnout)
2019 Rosborough creates Selectrum (first completing-read​-native UI)
2020 Apr Antolin Camarena creates Orderless
2020 May Antolin Camarena creates Embark
2020 Sep Helm development officially stopped
2020 Nov Mendler creates Consult
2020 Dec Antolin Camarena & Mendler create Marginalia
2021 Apr Mendler creates Vertico and Corfu
2021 May "Replacing Ivy and Counsel with Vertico and Consult" (System Crafters)
2021 Selectrum deprecated in favor of Vertico; Doom Emacs adds Vertico module
2021 Nov Mendler creates Cape
2022 Doom Emacs switches default completion from Ivy to Vertico
2024 Ivy breaks with Emacs 30; Company deprecated in Doom in favor of Corfu

Helm and Ivy accumulated stars over a longer period; the newer packages are growing faster relative to their age (counts as of early 2026):

Package Stars Created Approx. age
Helm ~3,500 2011 15 years
Ivy/Swiper ~2,400 2015 11 years
Vertico ~1,800 April 2021 5 years
Consult ~1,600 Nov 2020 5 years
Corfu ~1,400 April 2021 5 years
Embark ~1,200 May 2020 6 years
Orderless ~979 April 2020 6 years
Marginalia ~919 Dec 2020 5 years
Cape ~760 Nov 2021 4 years
Prescient ~695 Aug 2017 9 years

The community momentum is clear. Doom Emacs, one of the most popular Emacs distributions, has moved to Vertico + Corfu as its defaults12. Modern configuration guides almost universally recommend the modular stack13. And the upstream Emacs project itself has been integrating ideas from this ecosystem: Emacs 30 added completion-preview-mode, and Emacs 31 is incorporating Mct-inspired features (they love Prot, and for good reason, lol).

15. The Trade-Off: Monolith vs. Composition   tradeoffs analysis

Engineering is about trade-offs. The modular approach has real advantages, but it does have costs, so I want to be honest about them:

15.1. Advantages of VOMPECCC

No vendor lock-in. Every package builds on the same native contracts. If any one of the eight packages is abandoned, you replace it. Your other packages continue to work. Contrast this with Helm, where the maintainer's burnout announcement stranded an entire ecosystem of downstream packages.

Independent maintenance. Three different developers maintain the eight packages. Daniel Mendler maintains five (Vertico, Consult, Corfu, Cape, and co-maintains Marginalia), so the overall bus factor is not dramatically higher than a monolith. But the key difference is structural: if Mendler stepped away, the remaining packages would continue to function independently. Omar Antolin Camarena's Embark and Orderless would keep working. Radon Rosborough's Prescient would keep working. Nobody's contribution is stranded by someone else's absence.

Incremental adoption. You start with one package and add more as you discover needs. There is no cliff of initial configuration. You never need to understand all eight before getting value from any one.

Smaller, auditable codebases. Vertico is ~600 lines. Corfu is ~1,220 lines. These are packages you can actually read end to end. Bugs are easier to find and fix in small, focused codebases.

Automatic ecosystem benefits. Because everything uses the native completion protocol, third-party packages benefit for free. Any command that calls completing-read gets your chosen UI, filtering, sorting, annotations, and actions without any integration code.

Future compatibility. Emacs itself continues to improve its built-in completion system. Packages built on the native protocol benefit from those improvements automatically. Packages built on proprietary APIs do not.

15.2. Disadvantages of VOMPECCC

Higher initial discovery cost. A newcomer searching "Emacs completion" finds eight packages instead of one. Understanding the role of each, and which subset to start with, requires more research than "install Helm" or "install Ivy." The conceptual overhead is non-trivial.

Configuration across packages. Eight packages means eight use-package declarations, eight sets of configuration variables, and eight places where something could be misconfigured. Helm's all-in-one approach means one declaration, one set of variables, one source of truth.

Interaction effects. While the packages are independent, some combinations require awareness of how they interact. Combining Orderless with Prescient requires understanding that Orderless handles filtering while Prescient handles sorting. The embark-consult integration package exists because the two packages benefit from knowing about each other in specific workflows.

Less out-of-the-box polish. Helm ships with dozens of purpose-built commands. With VOMPECCC, you compose those workflows yourself. The result is often more powerful, but you build it rather than unwrap it.

Documentation is distributed. Each package has its own README, its own issue tracker, its own wiki. There is no single "VOMPECCC manual." Cross-cutting workflows (search with Consult, export with Embark, edit with wgrep) are documented across multiple repositories.

15.3. When to Choose What

Choose VOMPECCC if:

  • You value understanding your tools and want to read the source code
  • You want completion that works identically with built-in and third-party commands
  • You want to invest incrementally rather than all at once
  • You care about long-term maintainability and Emacs version compatibility
  • You want to mix and match components as your needs evolve

Consider Helm if:

  • You want maximum out-of-the-box functionality with minimal configuration
  • You prefer a single point of documentation and support
  • You are comfortable depending on a single package and its API
  • You need one of Helm's highly specific, purpose-built features (like helm-top or helm-colors) and don't want to replicate them
  • You think Thierry is a cool dude (he is)

Consider Ivy if:

  • You are already invested in the Ivy ecosystem with custom ivy-read code
  • You prefer Ivy's action selection UX
  • You need Spacemacs's Ivy layer specifically
  • You think Oleh is a cool dude (he is)

For new configurations today, the community consensus points strongly toward the modular stack. Doom Emacs's switch to Vertico and Corfu, the deprecation of Selectrum, and the ongoing maintenance challenges of both Helm and Ivy have made the direction clear. The question is no longer whether to use the modular approach, but which subset to start with.

16. Conclusion   conclusion

I came to this stack the way most people probably do: one package at a time, over the course of a year or so. I started with Vertico and Orderless because my Ivy config had started fighting with Emacs 28 upgrades and I was tired of debugging someone else's ivy-read edge cases. Two packages, ten minutes of configuration, and M-x already felt better. Marginalia came next for me. Once you've seen keybindings and docstrings next to every command, you can't unsee their absence. Consult replaced Counsel, Embark replaced the "type search string, exit completion, run a different command" waltz, and Corfu replaced Company when I realized the same Orderless filtering I'd grown to depend on in the minibuffer wasn't available in my code buffers.

The whole migration happened very incrementally, which was incidental for me, but is the point of this post. I never sat down to "install VOMPECCC." I solved one friction at a time, and each solution composed with the ones I already had. That's the experience the architecture is designed to produce.

Nobody really calls it VOMPECCC in Emacs circles, it is a mnemonic used here for the sake of an article rather than an established term. But the packages it describes have quietly become the default recommendation for modern Emacs completion, adopted by Doom Emacs, recommended by Protesilaos Stavrou14, documented by System Crafters15, and built on by a growing ecosystem of third-party packages.

The shift from Helm to Ivy to the modular stack follows a familiar pattern in software: monoliths are convenient until they aren't. Composable tools with clear interfaces outlast the frameworks that try to be everything16. Emacs figured this out forty years ago, and the modular stack described here is what completion looks like once you treat it as a substrate, the raw material on top of which you build Incremental Completing Read interactions, rather than as a finished product the vendor hands you. Its completion ecosystem just needed a few years to catch up.

17. TLDR   tldr

Emacs completion is not one problem but at least six orthogonal concerns: display, filtering, sorting, annotation, actions, and in-buffer completion. For a decade, Helm and Ivy delivered excellent experiences but bundled everything behind proprietary APIs, creating vendor lock-in and maintenance fragility. VOMPECCC names eight independent packagesVertico, Orderless, Marginalia, Prescient, Embark, Consult, Corfu, and Cape — that each address a single concern and compose through Emacs's native completing-read contract rather than custom APIs. Because no package depends on another's internals, any subset works on its own and any component can be replaced without breaking the rest. The community has moved decisively toward this modular stack, with Doom Emacs switching its defaults to Vertico and Corfu. There are real trade-offs — higher discovery cost and distributed configuration — but the architecture pays off in durability, auditability, and incremental adoption.

Footnotes:

1

Sacha Chua's interview with Thierry Volpiatto (2018) provides a candid account of Helm's history. Volpiatto describes being a mountain guide with no programming background, discovering Linux in 2006, and gradually becoming Helm's sole maintainer. He also discusses the financial unsustainability of maintaining a package used by hundreds of thousands of users as a volunteer.

2

Helm accumulated over 640,000 downloads on MELPA, making it the most downloaded package on the archive at its peak. MELPA download counts are visible on the MELPA package page. The figure is cumulative since MELPA began tracking downloads in 2013.

3

Volpiatto's 2020 announcement (GitHub Issue #2386) was definitive: "Helm development is now stopped, please don't send bug reports or feature request, you will have no answers." The issue was locked to collaborators. The Hacker News discussion that followed highlights the difficulty of sustaining large open-source projects without institutional support.

4

The ivy-read signature can be inspected in ivy.el on GitHub. The Selectrum README (radian-software/selectrum) provides a detailed comparison of ivy-read with completing-read and explains why the deviation from the standard API created long-term maintainability problems.

5

McIlroy's articulation of the Unix philosophy appears in the Bell System Technical Journal's 1978 special issue on Unix (available at archive.org). The full quote is: "Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new 'features'." See also Eric S. Raymond's The Art of Unix Programming, Chapter 1, which elaborates on the philosophy's implications for software design.

6

The completing-read API is documented in the Emacs Lisp Reference Manual. The key design insight is that completing-read supports programmatic completion tables — functions that can compute candidates lazily based on the current input — which is essential for large or dynamic candidate sets like TRAMP hosts or LSP symbols.

7

Emacs's completion styles system is documented in the GNU Emacs Manual. The variable completion-styles controls which matching strategies are tried, in order, until one produces results. The completion-category-overrides variable allows per-category customization, so file completion can use partial-completion while M-x uses orderless.

8

ivy-rich (Yevgnen/ivy-rich) was a popular Ivy extension that added columns of information to Ivy completion candidates — essentially the same concept as Marginalia. The key limitation was that it was structurally coupled to Ivy: if you switched away from Ivy, you lost your annotations. Marginalia solves the same problem through the standard annotation-function API, making it framework-agnostic.

9

This characterization comes from Karthinks's "Fifteen Ways to Use Embark", one of the most comprehensive third-party guides to the package. The post demonstrates workflows that were impossible or impractical before Embark: acting on multiple candidates simultaneously, exporting completion results into native Emacs modes, and switching commands mid-stream without losing context.

10

Company-mode (company-mode/company-mode) was created by Nikolaj Schumacher in 2009 and has been maintained by Dmitry Gutov since 2013. It remains actively maintained with ~2,300 GitHub stars. The architectural critique here is specific to the backend API: company-backends is a separate protocol from completion-at-point-functions, which means backends written for Company don't work with other completion UIs, and vice versa.

11

The Doom Emacs Corfu module was merged in PR #7002 in March 2024. The Discourse discussion explains the rationale: Corfu aligns with Emacs's native completion infrastructure, while Company's proprietary API creates friction with the rest of the modern completion stack.

12

Doom Emacs's completion modules are documented at docs.doomemacs.org. The Vertico module includes pre-configured integration with Orderless, Marginalia, Consult, and Embark. The older Ivy and Helm modules remain available but are no longer the recommended default.

13

Notable guides recommending the modular stack include: Martin Fowler's "Improving my Emacs experience with completion" (2024), which documents his switch to the Vertico ecosystem; the "Guide to Modern Emacs Completion" by Jonathan Neidel, which walks through the full Vertico/Corfu stack; and Kristoffer Balintona's multi-part "Vertico, Marginalia, All-the-icons-completion, and Orderless" series (2022).

14

Protesilaos Stavrou's "Emacs: modern minibuffer packages (Vertico, Consult, etc.)" is a ~44 minute video demonstrating the full stack. Stavrou is also the author of Mct (Minibuffer and Completions in Tandem), an alternative approach that reuses the built-in *Completions* buffer with automatic updates. His recommendation of Vertico despite having written a competing package speaks to the strength of the ecosystem.

15

System Crafters' "Streamline Your Emacs Completions with Vertico" and the companion video "Replacing Ivy and Counsel with Vertico and Consult" (May 2021) were early catalysts for community adoption. David Wilson (System Crafters) documented his own migration from Ivy and provided configuration examples that became widely copied.

16

The pattern of monoliths giving way to composable architectures is well-documented in software engineering. Fred Brooks described the "second system effect" in The Mythical Man-Month (1975), where the follow-up to a successful lean system tends to be an overdesigned monolith. More recently, the microservices movement explicitly applies the Unix philosophy to distributed systems — with similar trade-offs around discovery cost, operational complexity, and distributed debugging.