apt for Vim: the story of vim-apthogen (2012-2016)
Somewhere between 2012 and 2016, my Vim setup looked like a Debian system from the package manager’s point of view: a pile of bundle/ directories installed by hand and vim-pathogen
doing the loading. Pathogen is honest about its role: it is dpkg, the dumb loader. Nobody had written the apt on top of it. So I did.
The result: vim-apthogen
, published on vim.org on April 12, 2016 (Vim 7.0, 1136 downloads, a karma of 19/6, all numbers I am unreasonably proud of). The README line I still like: Like apt for dpkg, vim-apthogen is a frontend to vim-pathogen.
The metaphor, taken seriously
Once you commit to apt, the rest writes itself:
.apthogen.list: the package index, onename@https://github.com/author/repoline per plugin, exactly like a sources list..required.list,.minimal.list,.recomended.list: dependency tiers, straight from the Debian task-selection playbook.bundle-availlable/(typo included, it is authentic) holds every downloaded plugin; enabling one is a symlink intobundle/, disabling is removing the link. Apache admins will recognizea2enmod/a2dismodmore than apt and I stand by that borrowing.
Two scripts, 291 lines of bash
apthogen (225 lines) speaks the verbs you expect: install, remove, enable, disable, update, upgrade, list, search, show. netinstall (66 lines) is the bootstrap: a curl | bash that builds a fresh ~/.vimnew, infects it with the required modules and asks which profile you want:
[S]lim (Only Required Modules)
[M]inimal (Default)
[H]ighly Recomended
[R]ecomended
[W]hynot
[A]ll (Not Recomended For Testing Purpose)
[C]ancel
Enter your choice and press [Enter]: R
And because a 2016 script could not just say “cloning”, the output is a biology lesson: Apthogen::Incubate, Apthogen::Infection, Apthogen::Propagate::required, Apthogen::Phagocyte::https://github.com/tpope/vim-pathogen, Apthogen::Evolve::nerdtree on upgrades. Infection as a feature. 2016 was a simpler time.
What it actually did well
The enable/disable symlink split was the good idea. It gave me “installed but off” for free, years before pack/plugins/opt became a thing in Vim 8. The show command was a nice parlor trick too: it fetched the plugin’s README from raw.githubusercontent.com and piped it to less, a proto-:help for plugins you had not installed yet.
What it did wrong (the honest list)
- The module index was rebuilt by grepping
.git/configwith awk. It worked until it did not. installwas actually an alias for the undocumentedimportand the case statement’s*)arm swallows everything, including its own typos.- The usage line says
./aptogen(onehshort). Published. For years. showdownloaded remote content and piped it tolessin your editor. A tiny remote-code-adjacent footgun nobody exploited because nobody used it.- Everything is
cd-based. Every script failure leaves you inbundle-availlable.
It is period-accurate bash: [[ ... ]]&&{ ... }||{ ... } chains, &>>$LOGS swallowed errors, date-stamped log files. I keep the zip (still on vim.org
) like a museum piece and it is a bigger one than I remembered: alongside the two scripts it ships a complete environment, .vimrc included (opening with runtime! debian.vim), file templates for bash/C/Perl/PHP/Python/XHTML, French and English spell files, extra syntax files and six plugin/*.vim config files. It was never just a plugin manager; it was a distribution with apt attached. The GitHub repo is dead, the script_id is the tombstone; the zip is the mausoleum.
The ladder, so far
This was rung one. A few years later the plugins moved into git submodules with a second bash script (see the next episode ), then the whole thing got rewritten in VimScript as vim-plugin-manager and hardened for years after that. Every generation kept one idea from the previous one:
- apthogen: apt verbs, on/off split, declarative lists.
- the submodule era: the repo itself becomes the state, no local index needed.
- vim-plugin-manager: parallel installs, pinning re-asserted from the vimrc, lazy loading.
The design did not change as much as the plumbing did. Which is, I think, the actual lesson: get the metaphor right early, then spend a decade making it boring.
[edit: 2026] The Ansible implementation of all this: the vim role .