Zinit

Zinit is a flexible and fast Zsh plugin manager.

Zinit installs Zsh plugins, snippets and completions from GitHub and other forges, cloning each into $ZINIT[PLUGINS_DIR]. Packages are identified by the user/repo slug Zinit both reports and accepts, which is the id mpm keys them on. A plugin the user renamed through the id-as ice reports under that alias instead, and feeds back into every operation just the same.

Caution

zinit is a shell function, not a standalone binary, so every invocation is wrapped in zsh -c 'source <zinit.zsh> && zinit <args>'. Zsh is therefore the manager’s CLI, and Zinit’s own presence is established by the version probe: a host with Zsh but no Zinit fails to source and reports no version, which leaves the manager unavailable.

Caution

Zinit.installed() is the one operation that cannot use that wrapper. Zinit tracks plugins in shell state populated by the zinit load calls of the user’s .zshrc, so a freshly sourced non-interactive shell knows of none. That query therefore runs zsh --interactive, paying a full shell startup to inventory what the user’s Zsh actually loads. Plugins deferred with the wait ice (Zinit’s turbo mode) load asynchronously after the prompt would have been drawn, so a non-interactive run may miss them.

Note

No outdated: Zinit’s only “what would change” command is zinit status --all, which unconditionally runs .zinit-self-update first, pulling and recompiling Zinit itself. A query that mutates the manager is not a query, so mpm auto-skips the operation and upgrade --all still works.

Note

No search: Zinit resolves plugins straight from forge URLs and indexes no registry to search.

What mpm adds to zinit

mpm reaches across every manager at once, not zinit alone: mpm installed and mpm outdated cover zinit alongside every other manager you run in one table, mpm upgrade --all updates them together, and mpm sbom exports the whole machine as one bill of materials.

Every mpm command also gains --dry-run and --plan previews, cross-scheme version comparison and purl identifiers. See manager augmentations for how each one is built.

Your zinit commands, in mpm

You already know zinit: each operation maps one-to-one onto mpm, in an interface shared by every manager.

To…

With zinit

With mpm

List what’s installed

zsh --interactive -c 'zinit plugins'

mpm --zinit installed

Install a package

zinit load zdharma-continuum/null

mpm install pkg:zinit/zdharma-continuum/null

Upgrade one package

zinit update zdharma-continuum/null

mpm --zinit upgrade zdharma-continuum/null

Upgrade everything

zinit update --all

mpm --zinit upgrade --all

Remove a package

zinit delete --yes zdharma-continuum/null

mpm remove pkg:zinit/zdharma-continuum/null

Prefix any command above with --dry-run to simulate the underlying manager calls without touching the system: the safe way to watch what mpm would do before trusting it.

Platforms

  • 🐧 Linux

  • 🍎 macOS

Operations

Operation

Supported

installed

outdated

orphans

search

install

upgrade

upgrade_all

remove

sync

cleanup

doctor

Ecosystem

  • Accepted purl types: pkg:zinit

Selecting and configuring zinit

Deselect zinit for a single run with --no-zinit, or persist the choice in your configuration:

[mpm]
zinit = false

Keep it enabled but tune how mpm drives it with a per-manager override:

[mpm.managers.zinit]
timeout = 900

mpm config-template zinit prints every overridable attribute as a ready-to-paste block.

Recipes

A few jobs you would otherwise script around zinit, one mpm command each:

  • Snapshot and clone a machine: mpm --zinit dump zinit.toml, then mpm restore zinit.toml on the next one.

  • Export a compliance SBOM: mpm --zinit sbom (CycloneDX by default, --spdx for SPDX).

How mpm drives zinit

  • CLI names, in lookup order: zsh

  • Environment forced on each call:

    • SHELL_SESSIONS_DISABLE=1

mpm forces those arguments and variables on every call, so runs stay quiet, non-interactive and reproducible: the defaults you would set in CI anyway.

The version is probed by running:

$ zsh version
zinit v3.15.0 (darwin25.4.0_arm64)

and extracted with:

r"zinit\s+v(?P<version>\S+)"

Privilege escalation

mpm runs this manager as the current user and never prepends sudo by default. Flip the policy for its privileged operations with --sudo or the per-manager sudo override.

See privilege escalation for the full policy.

Cooldown

State of Zinit’s release-age gating, from the cooldown support table:

  • Status: ❌ None

A cooldown only pays off where a compromised release can be withdrawn while the clock runs, and can only be emulated where the registry dates its releases. From the retraction table:

  • Registry: Upstream Git clones

  • Retraction: None: a plugin is cloned straight from its upstream repository, so withdrawing a bad revision is its author force-pushing, retagging or deleting it themselves. No index sits in between

  • Publish date: ❌ a commit or tag date is set by the author and freely rewritable

With --cooldown set, mpm skips this manager’s install and upgrade operations rather than run them unguarded (fail-closed); --allow-unsupported-managers opts back in.

Reference traces

Raw native outputs captured in the manager source: the reference mpm’s parsers were written against. If you know Zinit well and a transcript below looks wrong, or a newer release changed its output format, report it.

$ zsh --interactive -c 'zinit plugins'
==> 3 Plugins

 1 L ~zinit/zinit.git

 2 L zdharma-continuum/fast-syntax-highlighting

 3 U zsh-users/zsh-completions


Loaded: L | Unloaded: U

Feed any of these through mpm and the raw output becomes one uniform table, the same shape for every manager: filter it, project columns, or export it (mpm --zinit installed --output json, or csv, toml, yaml), each package carrying a purl and a version comparable across managers.