Sheldon is a fast, configurable, command-line tool to manage your shell plugins.

How does it work?

Plugins are specified in a TOML configuration file and Sheldon renders an install script using user configurable handlebars templates.

A ~/.zshrc or ~/.bashrc that uses Sheldon simply contains the following.

eval "$(sheldon source)"

Sheldon can manage GitHub or Git repositories, Gists, arbitrary remote scripts or binaries, local plugins, and inline plugins. Plugins are installed and updated in parallel and as a result Sheldon is blazingly fast.

Source code

Sheldon is open source and you can find the code on GitHub.

License

Sheldon and its source code is licensed under either of

at your option.

📦 Installation

Pre-built binaries

Pre-built binaries for Linux (x86-64, aarch64, armv7) and macOS (x86-64) are provided. The following script can be used to automatically detect your host system, download the required artefact, and extract the sheldon binary to the given directory.

curl --proto '=https' -fLsS https://rossmacarthur.github.io/install/crate.sh \
    | bash -s -- --repo rossmacarthur/sheldon --to ~/.local/bin

Alternatively, you can download an artifact directly from the the releases page.

Homebrew

Sheldon can be installed using Homebrew.

brew install sheldon

Cargo

Sheldon can be installed from Crates.io using Cargo, the Rust package manager.

cargo install sheldon

Building from source

Sheldon is written in Rust, so to install it from source you will first need to install Rust and Cargo using rustup. Then you can run the following to build Sheldon.

git clone https://github.com/rossmacarthur/sheldon.git
cd sheldon
cargo build --release

The binary will be found at target/release/sheldon.

🚀 Getting started

Initializing

Sheldon works by specifying plugin information in a TOML configuration file, plugins.toml. You can initialize this file by running sheldon init.

sheldon init --shell bash

or

sheldon init --shell zsh

This will create plugins.toml under ~/.sheldon or, if defined, $XDG_CONFIG_HOME/sheldon. You can either edit this file directly or use the provided command line interface to add or remove plugins.

Adding a plugin

To add your first plugin append the following to the Sheldon config file.

# ~/.sheldon/plugins.toml

[plugins.base16]
github = "chriskempson/base16-shell"

Or use the add command to automatically add it.

sheldon add base16 --github chriskempson/base16-shell

The first argument given here base16 is a unique name for the plugin. The --github option specifies that we want Sheldon to manage a clone of the https://github.com/chriskempson/base16-shell repository.

Loading plugins

You can then use sheldon source to install this plugin, generate a lock file, and print out the shell script to source. Simply add the following to your ~/.zshrc or ~/.bashrc file.

# ~/.zshrc or ~/.bashrc

eval "$(sheldon source)"

💻 Command line interface

Sheldon has three different types of commands.

  • init initializes a new config file.
  • lock and source deal with plugin downloading, installation, and generation of shell source code.
  • add, edit, and remove automate editing of the config file.

init

This command initializes a new config file. If a config file exists then this command does nothing.

For example

sheldon init

Or you can specify the shell.

sheldon init --shell bash

or

sheldon init --shell zsh

lock

The lock command installs the plugins sources and generates the lock file (~/.sheldon/plugins.lock). Rerunning this command without any extra options will not reinstall plugin sources, just verify that they are correctly installed. It will always regenerate the lock file.

sheldon lock

To update all plugin sources you can use the --update flag.

sheldon lock --update

To force a reinstall of all plugin sources you can use the --reinstall flag.

sheldon lock --reinstall

source

This command generates the shell script. This command will first check if there is an up to date lock file, if not, then it will first do the equivalent of the lock command above. This command is usually used with the built-in shell eval command.

eval "$(sheldon source)"

But you can also run it directly to inspect the output. The output of this command is highly configurable. You can define your own custom templates to apply to your plugins.

add

This command adds a new plugin to the config file. It does nothing else but edit the config file. In the following command we add a GitHub repository as a source.

sheldon add my-repo --git https://github.com/owner/repo.git

An example usage of this command for each source type is shown in the Configuration section.

edit

This command will open the config file in the default editor and only overwrite the contents if the updated config file is valid. To override the editor that is used you should set the EDITOR environment variable.

For example using vim

EDITOR=vim sheldon edit

Or with Visual Studio Code

EDITOR="code --wait" sheldon edit

remove

This command removes a plugin from the config file. It does nothing else but edit the config file. In the following command we remove the plugin with name my-repo.

sheldon remove my-repo

Flags

Sheldon accepts the following global command line flags.

FlagDescription
-q, --quietSuppress any informational output
-v, --verboseUse verbose output
-h, --helpShow the help message and exit
-V, --versionShow the version and exit

Options

Sheldon accepts the following global command line options.

OptionEnvironment variableDescription
--color <when>Output coloring: always, auto, never. (default: auto)
--home <path>HOMESet the home directory. (default: auto)
--config-dir <path>SHELDON_CONFIG_DIRSet the config directory. (default: <home>/.sheldon)
--data-dir <path>SHELDON_DATA_DIRSet the data directory. (default: <home>/.sheldon)
--config-file <path>SHELDON_CONFIG_FILESet the config file. (default: <config_dir>/plugins.toml)
--lock-file <path>SHELDON_LOCK_FILESet the lock file. (default: <data_dir>/plugins.lock)
--clone-dir <path>SHELDON_CLONE_DIRSet the clone directory. (default: <data_dir>/repos)
--download-dir <path>SHELDON_DOWNLOAD_DIRSet the download directory. (default: <data_dir>/downloads)

The priority order for setting these values is the following

  1. Command line option.
  2. Environment variable.
  3. Default value.

⚙️ Configuration

Plugin sources

A plugin is defined by adding a new unique name to the plugins table in the TOML config file. This can be done by either editing the file directly or using the provided Sheldon commands. A plugin must provide the location of the source. There are three types of sources, each kind is described in this section. A plugin may only specify one source type.

# ~/.sheldon/plugins.toml

#           ┌─ Unique name for the plugin
#        ┌──┴─┐
[plugins.base16]
github = "chriskempson/base16-shell"
#         └─────┬────┘ └─────┬────┘
#               │            └─ GitHub repository name
#               └─ GitHub user or organization

Git

Git sources specify a remote Git repository that will be cloned to the Sheldon data directory. There are three flavors of Git sources.

github

A GitHub source must set the github field and specify the repository. This should be the username or organization and the repository name separated by a forward slash. Add the following to the Sheldon config file.

[plugins.example]
github = "owner/repo"

Or run add with the --github option.

sheldon add example --github owner/repo

gist

A Gist source must set the gist field and specify the repository. This should be the hash or username and hash of the Gist. Add the following to the Sheldon config file.

[plugins.example]
gist = "579d02802b1cc17baed07753d09f5009"

Or run add with the --gist option.

sheldon add example --gist 579d02802b1cc17baed07753d09f5009

git

A Git source must set the git field and specify the URL to clone. Add the following to the Sheldon config file.

[plugins.example]
git = "https://github.com/owner/repo"

Or run add with the --git option.

sheldon add example --git https://github.com/owner/repo

Specifying a branch, tag, or commit

All Git sources also allow setting of one of the branch, tag or rev fields. Sheldon will then checkout the repository at this reference.

[plugins.example]
github = "owner/repo"
tag = "v0.1.0"

Or run add with the --tag, --branch, or --rev option.

sheldon add example --github owner/repo --tag v0.1.0

Cloning with Git or SSH protocols

GitHub and Gist sources are cloned using HTTPS by default. You can specify that Git or SSH should be used by setting the proto field to the protocol type. This must be one of git, https, or ssh.

[plugins.example]
github = "owner/repo"
proto = "ssh"

For a plain Git source you should specify the URL with a git:// or ssh://. For SSH you will need to specify the username as well (it is git for GitHub).

[plugins.example]
git = "ssh://git@github.com/owner/repo"

Private Git repositories

Currently Sheldon only supports authentication when cloning using SSH and requires an SSH agent to provide credentials. This means if you have a plugin source that is a private repository you will have to use the SSH protocol for cloning.

Remote

Remote sources specify a remote file that will be downloaded by Sheldon. A remote source must set the remote field and specify the URL. Add the following to the Sheldon config file.

[plugins.example]
remote = "https://github.com/owner/repo/raw/branch/plugin.zsh"

Or run add with the --remote option.

sheldon add example --remote https://github.com/owner/repo/raw/branch/plugin.zsh

Local

Local sources reference local directories. A local source must set the local field and specify a directory. Tildes may be used and will be expanded to the current user's home directory. Add the following to the Sheldon config file.

[plugins.example]
local = "~/Downloads/plugin"

Or run add with the --local option.

sheldon add example --local '~/Downloads/plugin'

Plugin options

These are options that are common to all the above plugins.

use

A list of files / globs to use in the plugin's source directory. If this field is not given then the first pattern in the global match field that matches any files will be used. Add the following to the Sheldon config file.

[plugins.example]
github = "owner/repo"
use = ["*.zsh"]

Or run add with the --use option when adding the plugin.

sheldon add example --github owner/repo --use '*.zsh'

apply

A list of template names to apply to this plugin. This defaults to the global apply.

[plugins.example]
github = "owner/repo"
apply = ["source", "PATH"]

Or run add with the --apply option when adding the plugin.

sheldon add example --github owner/repo --apply source PATH

You can define your own custom templates to apply to your plugins.

Inline plugins

For convenience it also possible to define Inline plugins. An Inline plugin must set the inline field and specify the raw source.

[plugins.example]
inline = 'example() { echo "Just an example of inline shell code" }'

Templates

A template defines how the shell source for a particular plugin is generated. For example the PATH template adds the plugin directory to the shell PATH variable. A template will be applied to a plugin if you add the template name to the apply field on a plugin.

Available built-in templates are different depending on what shell you are using. The following are available for both Bash and Zsh.

  • source: source each file in a plugin.
  • PATH: add the plugin directory to the PATH variable.

If you are using Zsh then the following are also available.

  • path: add the plugin directory to the path variable.
  • fpath: add the plugin directory to the fpath variable.

As template strings in the config file they could be represented like the following.

[templates]
source = { value = 'source "{{ file }}"', each = true }
PATH = 'export PATH="{{ dir }}:$PATH"'
path = 'path=( "{{ dir }}" $path )'
fpath = 'fpath=( "{{ dir }}" $fpath )'

For example if we change the apply field for the below plugin, it will only add the plugin directory to the PATH and append it to the fpath. The plugin will not be sourced.

[plugins.example]
github = "owner/repo"
apply = ["PATH", "fpath"]

The each value, as used in the source template above, specifies that the template should be applied to each matched file for the plugin. This defaults to false.

Custom templates

It is possible to create your own custom templates, and you can even override the built-in ones.

Plugins all have the following information that can be used in templates.

  • A unique name. This is completely arbitrary, and it is the value specified for the plugin in the plugins table. However, it is often the name of the plugin, so it can be useful to use this name in templates with {{ name }}.

  • A directory. For Git sources this is the location of the cloned repository, for local sources, it is the directory specified. This directory can be used in templates with {{ dir }}.

  • One or more files. These are the matched files in the plugin directory either discovered using the the global match field or specified as a plugin option with use. These can be used in templates using {{ file }}. This information only makes sense in templates with each set to true.

  • The Sheldon data directory. This directory can be used as {{ data_dir }}.

To add or update a template add a new key to the [templates] table in the config file. Take a look at the examples for some interesting applications of this.

Global options

shell

Indicates the shell that you are using. This setting will affect the default values for several global config settings. This includes the global match setting and the available templates. This defaults to zsh.

shell = "bash"

or

shell = "zsh"

match

A list of glob patterns to match against a plugin's contents. The first pattern that matches any files will be used by default as a plugin's use field. This defaults to

match = [
    "{{ name }}.plugin.zsh",
    "{{ name }}.zsh",
    "{{ name }}.sh",
    "{{ name }}.zsh-theme",
    "*.plugin.zsh",
    "*.zsh",
    "*.sh",
    "*.zsh-theme"
]

If the shell is Bash then this defaults to

match = [
    "{{ name }}.plugin.bash",
    "{{ name }}.plugin.sh",
    "{{ name }}.bash",
    "{{ name }}.sh",
    "*.plugin.bash",
    "*.plugin.sh",
    "*.bash",
    "*.sh"
]

apply

A list of template names to apply to all plugins by default (see apply). This defaults to

apply = ["source"]

💡 Examples

This section demonstrates the configuration file contents for some common installation practices as well how to configure popular plugins and themes.

Deferred loading of plugins in Zsh

A commonly desired feature of shell plugin managers is deferred loading of plugins because of the massive increase in speed that it provides. Because Sheldon is not written in a shell language it cannot provide the level of integration that other plugin managers can. However, it is pretty easy to get deferred loading working with Sheldon using romkatv/zsh-defer.

Firstly, you should add zsh-defer as a plugin.

[plugins.zsh-defer]
github = "romkatv/zsh-defer"

Important: the zsh-defer plugin definition should be placed before any plugins that will use the defer template. Sheldon always processes plugins in the order they are defined in the config file.

Then add a template that calls zsh-defer source instead of just source.

[templates]
defer = { value = 'zsh-defer source "{{ file }}"', each = true }

Now any plugin that you want to defer you can apply the defer template. For example if you wanted to defer loading of zsh-syntax-highlighting.

[plugins.zsh-syntax-highlighting]
github = "zsh-users/zsh-syntax-highlighting"
apply = ["defer"]

Overriding the PATH template

The built-in PATH template adds the directory path to the beginning of the PATH variable, we might want to change it to the be added at the end. We could do this like this

[templates]
PATH = 'export PATH="$PATH:{{ dir }}"'

You can then apply it to the plugin like this

[plugins.example]
github = "owner/repo"
apply = ["source", "PATH"]

Note: this would change the behavior of PATH for all plugins using it.

Zsh frameworks

ohmyzsh

Add the following to the Sheldon config file.

[plugins.oh-my-zsh]
github = "ohmyzsh/ohmyzsh"

Or run the following to automatically add it.

sheldon add oh-my-zsh --github "ohmyzsh/ohmyzsh"

Add the following to your ~/.zshrc file.

# ~/.zshrc

export ZSH="$HOME/.sheldon/repos/github.com/ohmyzsh/ohmyzsh"

# Oh My Zsh settings here

eval "$(sheldon source)"

Zsh plugins

autosuggestions

Add the following to the Sheldon config file.

[plugins.zsh-autosuggestions]
github = "zsh-users/zsh-autosuggestions"
use = ["{{ name }}.zsh"]

Or run the following to automatically add it.

sheldon add zsh-autosuggestions --github zsh-users/zsh-autosuggestions --use '{{ name }}.zsh'

autojump

Add the following to the Sheldon config file.

[plugins.autojump]
github = "wting/autojump"
dir = "bin"
apply = ["PATH", "source"]

Or run the following to automatically add it.

sheldon add autojump --github wting/autojump --dir bin --apply PATH source

syntax-highlighting

Add the following to the Sheldon config file.

[plugins.zsh-syntax-highlighting]
github = "zsh-users/zsh-syntax-highlighting"

Or run the following to automatically add it.

sheldon add zsh-syntax-highlighting --github zsh-users/zsh-syntax-highlighting

blackbox

Add the following to the Sheldon config file.

[plugins.blackbox]
github = "StackExchange/blackbox"

Or run the following to automatically add it.

sheldon add blackbox --github StackExchange/blackbox

z.lua

Add the following to the Sheldon config file.

[plugins."z.lua"]
github = "skywind3000/z.lua"

Or run the following to automatically add it.

sheldon add z.lua --github skywind3000/z.lua

enhancd

Add the following to the Sheldon config file.

[plugins.enhancd]
github = "b4b4r07/enhancd"

Or run the following to automatically add it.

sheldon add enhancd --github b4b4r07/enhancd

base16

Add the following to the Sheldon config file.

[plugins.base16]
github = "chriskempson/base16-shell"

Or run the following to automatically add it.

sheldon add base16 --github chriskempson/base16-shell

Zsh themes

powerlevel10k

Add the following to the Sheldon config file.

[plugins.powerlevel10k]
github = "romkatv/powerlevel10k"

Or run the following to automatically add it.

sheldon add powerlevel10k --github romkatv/powerlevel10k

spaceship

Add the following to the Sheldon config file.

[plugins.spaceship]
github = "spaceship-prompt/spaceship-prompt"

Or run the following to automatically add it.

sheldon add spaceship --github spaceship-prompt/spaceship-prompt

pure

Add the following to the Sheldon config file.

[plugins.pure]
github = "sindresorhus/pure"
use = ["async.zsh", "pure.zsh"]

Or run the following to automatically add it.

sheldon add pure --github sindresorhus/pure --use async.zsh pure.zsh

📝 Release notes

0.6.4

July 14th, 2021

0.6.3

March 27th, 2021

0.6.2

March 13th, 2021

0.6.1

February 12th, 2021

0.6.0

October 16th, 2020

Breaking changes

  • Support XDG directory structure. If any XDG environment variable is set then Sheldon will adopt the XDG directory structure by default. The config file will be located at $XDG_CONFIG_HOME/sheldon/plugins.toml and downloaded data will be located in $XDG_CONFIG_DATA/sheldon. (Contributed by @tapeinosyne.)

  • Change the default lock file location. For non-XDG directory structures the lock file now always defaults to $SHELDON_DATA_DIR/plugins.lock. It previously was the config file path with a .lock extension.

  • Remove the Sheldon root. The root directory has been replaced by individual directories for configuration and data: config_dir and data_dir. Both default to $HOME/.sheldon, the old default root. (Contributed by @tapeinosyne.)

    If you used Sheldon's defaults, everything will just keep working as it did; no action needs to be taken. Otherwise, you may refer to this migration table:

    OldNew
    Config paths<root>/plugins.toml<config_dir>/plugins.toml
    Data paths<root>/plugins.lock<data_dir>/plugins.lock
    <root>/repos<data_dir>/repos
    <root>/downloads<data_dir>/downloads
    Env variablesSHELDON_ROOTSHELDON_CONFIG_DIR
    SHELDON_DATA_DIR
    CLI options--root--config-dir
    --data-dir
    Template variables{{ root }}{{ data_dir }}
  • Auto-detect whether to use colored output. A new --color option was added with three values always, auto, or never. By default Sheldon will now automatically whether to use colored output or not (auto). But you can still force Sheldon to always use color or never use color with the --color always option or --color never. The previous --no-color option has been removed.

Fixes

0.5.4

August 14th, 2020

Features

  • Support extended glob syntax. This means that {a,b} and ! glob patterns can now be used. For example, the following is now valid.

    [plugins.ohmyzsh]
    github = "ohmyzsh/ohmyzsh"
    dir = "lib"
    use = ["{!git,!nvm,*}.zsh]
    

Fixes

0.5.3

July 28th, 2020

Features

0.5.2

June 4th, 2020

Fixes

Other

0.5.1

May 11th, 2020

0.5.0

May 2nd, 2020

Features

  • Add add and remove commands to edit config. These commands will edit the config file for you.

    For example

    sheldon add example --github owner/repo --tag v0.1.0
    

    will add the following to the config file

    [plugins.example]
    github = "owner/repo"
    tag = "v0.1.0"
    

    The following will remove it again.

    sheldon remove example
    
  • Add edit command. Adds a new command to Sheldon which allows you to open the config file in the default editor. Simply run sheldon edit.

  • Add initial config file. When running add or edit Sheldon will attempt to initialize a new config file at ~/.sheldon/plugins.toml.

  • Warn about unused config keys. Anytime Sheldon loads the config file it will log warnings when there are unused config keys. Great for catching typos!

Breaking changes

  • Update default root directory and clone directory. The root directory now defaults to ~/.sheldon and the clone directory now defaults to {root}/repos. To migrate you should do the following:

    mv ~/.zsh ~/.sheldon
    mv ~/.sheldon/repositories ~/.sheldon/repos
    

    Or to preserve the old behavior you should export the following before running Sheldon.

    export SHELDON_ROOT="$HOME/.zsh"
    export SHELDON_CLONE_DIR="$SHELDON_ROOT/repositories"
    

Fixes

Deprecations

Most of these are still supported, however Sheldon will log a deprecation warning if you use them.

0.4.8

November 3rd, 2019

0.4.7

October 22nd, 2019

0.4.6

August 18th, 2019

0.4.5

July 19th, 2019

0.4.4

July 7th, 2019

0.4.3

July 3rd, 2019

0.4.2

June 27th, 2019

0.4.1

June 2nd, 2019

0.4.0

May 26th, 2019

Complete refactor including breaking changes to the configuration file from prior versions.