Uploads are immutable, so a malformed archive cannot be replaced at its version path. verify-package checks the zip has one top-level directory, carries lua/, plugin/, doc/ and README.md, and leaks no dev or CI files.
arti-pack
A Neovim plugin manager that installs plugins from an artifact store instead of
git. It downloads tagged upstream source archives through
artifactapi and unpacks them into
Neovim's native package path — see :h packages.
No git, no submodules, no network access to GitHub from the editor: every plugin arrives as a cached, immutable, tagged artifact from the same proxy that serves RPMs, containers and Terraform providers.
Requirements
- Neovim 0.10+
curl, andunzip(ortarwhen usingext = 'tar.gz')
Install
Each tag is published as a source zip to the nvim-plugins artifactapi repo,
so arti-pack installs the same way as everything it manages:
curl -fsSL -o /tmp/arti-pack.zip \
https://artifactapi.k8s.syd1.au.unkin.net/api/v2/remotes/nvim-plugins/files/unkin/arti-pack/archive/refs/tags/v0.1.0.zip
mkdir -p "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack/arti-pack/start"
unzip -q /tmp/arti-pack.zip -d /tmp/arti-pack
mv /tmp/arti-pack/arti-pack-0.1.0 \
"${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/pack/arti-pack/start/arti-pack"
Once installed it can carry itself, since url bypasses the registry:
{
'unkin/arti-pack',
tag = 'v0.1.0',
url = 'https://artifactapi.k8s.syd1.au.unkin.net/api/v2/remotes/nvim-plugins/files/unkin/arti-pack/archive/refs/tags/v0.1.0.zip',
}
Usage
require('arti-pack').setup({
registry = 'https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github',
plugins = {
{ 'nvim-lua/plenary.nvim', tag = 'v0.1.4' },
{ 'folke/which-key.nvim', tag = 'v3.13.3', opt = true },
{ 'folke/tokyonight.nvim', tag = 'v4.10.0', as = 'tokyonight' },
{ 'tpope/vim-fugitive', tag = 'v3.7', ext = 'tar.gz' },
},
})
Every plugin needs an explicit tag — that is the point. Plugins install to
stdpath('data')/site/pack/arti-pack/start/<name>, or .../opt/<name> when
opt = true.
Spec fields
| Field | Default | Meaning |
|---|---|---|
[1] |
required | owner/repo |
tag |
required | Upstream tag, used verbatim in the archive path |
opt |
false |
Install under opt/ for :packadd instead of start/ |
as |
repo name | Directory name to install as |
ext |
'zip' |
zip or tar.gz |
url |
— | Full archive URL, bypassing the registry |
Options
| Option | Default | Meaning |
|---|---|---|
registry |
the estate artifactapi github remote | Proxy prefix placed in front of owner/repo |
auto_sync |
true |
Sync missing and changed plugins on startup |
concurrency |
4 |
Plugins downloaded in parallel |
timeout |
120 |
Per-download timeout in seconds |
Commands
| Command | Effect |
|---|---|
:ArtiPackSync |
Install missing plugins and update ones whose tag changed |
:ArtiPackSync! |
Reinstall everything, ignoring recorded state |
:ArtiPackClean |
Remove installed plugins no longer in the spec |
:ArtiPackList |
Show every configured plugin and its state |
How it resolves an archive
<registry>/<owner>/<repo>/archive/refs/tags/<tag>.<ext>
which for the defaults is
https://artifactapi.k8s.syd1.au.unkin.net/api/v1/remote/github/nvim-lua/plenary.nvim/archive/refs/tags/v0.1.4.zip
Archives are cached under stdpath('cache')/arti-pack, checked for a real zip
or gzip magic header before being trusted, and unpacked into a staging
directory. Tag archives wrap their contents in a single <repo>-<version>
directory, which is stripped on the way in. Installed tags are recorded in
stdpath('data')/arti-pack/lock.json, so a sync with nothing to do costs
nothing. Helptags are regenerated per plugin after install.
A failed plugin is reported and skipped; the rest of the run continues.
Tests
make test