znative

July 18, 2026 · View on GitHub

znative is a built-in command for installing shell plugins. It handles both zsh script plugins (the oh-my-zsh / zinit kind — functions, aliases, ZLE widgets, completions) and native Rust plugins (cdylibs loaded through the znative ABI — see PLUGINS.md).

It is global only: one content-addressed store under $ZSHRS_HOME/pkg/, no per-project manifest or lockfile. The whole workflow is one line per plugin in your .zshrc:

znative load owner/repo

On the first shell start that installs the plugin and loads it; on every start after, the same line loads it from the store with no network. There is no separate install step. znative needs git on PATH for remote sources, and cargo for native plugins that ship as source.

Commands

Command (aliases)ArgumentsWhat it does
load (source)[NAME_or_SOURCE…]The one you need. With no argument, load every installed plugin. Given an installed name or a source already in the store, load it — zero network. Given a source not yet in the store (owner/repo, github:…, git+URL, path:…), install it first, then load. This is what a .zshrc calls.
add (install, i)SOURCE…Resolve, install into the store, record in the index, and load. (load self-installs, so this is mostly for installing without a .zshrc line.) Multiple sources allowed.
remove (rm, uninstall)NAME…Unload (native), delete the store copy, drop the index row.
list (ls)One line per installed plugin: name version kind source.
info (show)NAMEFull record: name, version, kind, source, store path, integrity, lib / files / fpath.
update (upgrade, up)[NAME]Re-resolve and reinstall from the recorded source (one, or all) — pulls the latest upstream and rebuilds.
gc[--dry-run]Remove store/<name>@<version>/ directories not pinned by the index (orphans from old versions / upgrades) plus the git/ clone cache. --dry-run (-n) lists without deleting.
cleanClear the scratch directories (git/, cache/, bin/); the store and index are untouched.
help (-h, --help)Usage.

After an update/upgrade installs a newer version, the previous store/<name>@<old>/ directory is left behind; znative gc reclaims it.

Errors print as znative: <reason> on stderr and the command returns non-zero.

Sources

The add/update spec is auto-classified:

FormExampleResolves to
owner/repozsh-users/zsh-autosuggestionsgit clone https://github.com/owner/repo
github:owner/repogithub:zdharma-continuum/fast-syntax-highlightingGitHub clone (explicit)
git+URLgit+https://gitlab.com/team/plug.gitgit clone URL
a URL ending .git or with ://https://example.com/x.gitgit clone URL
path:DIRpath:examples/plugin-revolverlocal directory (no network)
an absolute / ./ / ../ / ~ path~/src/my-pluginlocal directory (no network)

Install by version — any remote form may carry an @ref suffix (split after the last /) to pin a tag, branch, or commit: owner/repo@v1.2.0, git+https://host/x.git@main. The pin is recorded in the index (source = github:owner/repo@v1.2.0), so list shows it, update re-fetches that exact ref (not HEAD), and load owner/repo@v1.2.0 matches only that pin. Clones are shallow (git clone --depth 1 [--branch REF]); an arbitrary commit sha a shallow --branch clone can't reach falls back to a full clone + git checkout. The official plugin repos are tagged per release (e.g. MenkeTechnologies/zshrs-revolver@v0.2.1).

Plugin kinds

KindLoaded byBuilt with
nativezmodload -R (the plugin host)cargo build --release when no prebuilt lib*.{dylib,so} is present
scriptfpath=(DIR $fpath) + source *.plugin.zshnothing — sourced as-is

When there is no explicit znative.toml, the kind is auto-detected:

  1. a prebuilt lib*.{dylib,so} at the repo root, or a Cargo.toml whose [lib] crate-type includes cdylibnative;
  2. otherwise any *.plugin.zsh, a functions/ directory, or *.zsh files → script;
  3. otherwise znative reports it cannot determine the kind.

The store

Everything lives under $ZSHRS_HOME/pkg/ (default ~/.zshrs/pkg/):

$ZSHRS_HOME/pkg/
  store/<name>@<version>/   # the installed plugin (content-addressed)
  installed.toml            # the global index — the source of truth
  git/                      # scratch: remote clones land here, then copy to store/
  cache/  bin/              # internal scratch

The copy into store/ excludes .git/ and target/, so the store holds only loadable content. Each install is SHA-256 pinned as sha256-<hex> in installed.toml. A record looks like:

[[package]]
name = "revolver"
version = "0.2.0"
source = "github:MenkeTechnologies/zshrs-revolver"
kind = "native"
integrity = "sha256-…"
lib = "librevolver.dylib"          # native: the cdylib to zmodload -R
# script plugins record instead:
# source_files = ["…​.plugin.zsh"]
# fpath = ["functions"]

znative.toml (optional manifest)

A plugin repo may ship a znative.toml at its root to declare metadata and the load recipe explicitly (it overrides auto-detection):

[plugin]
name = "git-fuzzy"
version = "0.1.0"
description = "git-fuzzy ported to a native zshrs plugin"

# Native (Rust cdylib) plugin — dlopened via `zmodload -R`:
[native]
lib = "git_fuzzy"        # produces lib<lib>.{dylib,so}
# build = true           # run `cargo build --release`; defaults to true
                         # when a Cargo.toml is present

# …or a script plugin:
# [script]
# source = ["git-fuzzy.plugin.zsh"]   # files to `source`, in order
# fpath  = ["functions"]              # dirs to prepend to $fpath

Standard oh-my-zsh / zinit *.plugin.zsh repos need no znative.toml at all.

In your .zshrc

List the plugins you want with znative load owner/repo, one per line, in load order. First start installs each; later starts load from the store with no network:

znative load zdharma-continuum/history-search-multi-word
znative load zsh-users/zsh-autosuggestions
znative load MenkeTechnologies/zshrs-forgit
znative load zsh-users/zsh-syntax-highlighting   # keep highlighting last

A bare znative load (no argument) loads everything already in the store — handy if you prefer to znative add interactively and keep just one line in .zshrc. A complete example startup file is at examples/zshrc.

Examples

# In .zshrc — self-installing on first use, zero-network after.
znative load zdharma-continuum/history-search-multi-word  # script: Ctrl-R multi-word search
znative load MenkeTechnologies/zshrs-forgit               # native: git+fzf
znative load MenkeTechnologies/zshrs-revolver             # native: progress spinner
znative load MenkeTechnologies/zshrs-fasd                 # native: file+dir frecency
znative load MenkeTechnologies/zshrs-reveal               # native: open repo in browser
znative load path:examples/plugin-revolver                # local checkout
znative load zsh-users/zsh-syntax-highlighting@0.8.0      # pinned ref
znative load git+https://gitlab.com/team/plugin.git       # non-GitHub URL

# Interactive store management.
znative add zsh-users/zsh-autosuggestions   # install without a .zshrc line
znative list                                # what's installed
znative info forgit                         # details for one
znative update                              # reinstall everything from source
znative remove forgit                       # unload + delete