Pearl is a lightweight package manager for automating reproducible environments between different systems (Linux and OSX). It can be used for dotfiles, plugins, programs and any form of code accessible via git.
Shell Emacs Lisp Vim script
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.


Because only in the best Shells you will find a Pearl...



Project Status Communication
Build status Join the gitter chat at

Table of Contents


Pearl is a lightweight package manager for automating reproducible environments between different systems (Linux and OSX). It can be used for dotfiles, plugins, programs and any form of code accessible via git.

As soon as a package gets installed, its content can be activated out of the box according to certain events, like, for instance, a shell startup (Bash, Zsh or Fish) or an editor startup (Vim or Emacs). This is possible via a smart and simple hook mechanism that integrates the package content within the Pearl ecosystem.

The main advantages on using Pearl are:

  • Create your own Pearl package in seconds (any git repository is already a Pearl package)!
  • Full control and sync of your dotfiles across different systems.
  • Automatic bootstrap of the package content whenever shells or editors get started.
  • Access to a wide range of existing packages via the OPH (Official Pearl Hub).
  • Allows to create your own package repository that can be shared with your friends!
  • Stable codebase with 100+ unit tests and exhaustive integration tests via Travis for Linux and OSX.
  • Small number of dependencies needed in order to ensure compatibility with most of the systems.

Comparison with similar solution: Ansible

You could achieve something similar from what Pearl provide by using Ansible. Ansible is a powerful software for IT automation which can be widely used for many use cases. Despite of this, Ansible has few drawbacks when using it for lightweight forms of automations:

  • Pearl uses bash for writing simple scripts for automation:
    • it makes easier the integration with other programs in the system (without existing Playbooks may be hard to achieve this in Ansible);
    • it is a powerful and well-known language;
  • Ansible requires way more dependencies than Pearl;
  • Ansible requires knowledge about how Ansible Playbooks works;
  • Pearl uses built-in functions and variables which heavily simplify construction of scripts for automation;
  • Pearl makes easier to remove packages and restore the system to an initial state;


The Pearl CLI script allows to: list, search, install, update, emerge, remove the Pearl packages defined according to the configuration located in ~/.config/pearl/pearl.conf



  • List all the available packages:
$ pearl list
    Awesome git dotfiles (
pearl/sesaila [installed]
    Awesome aliases for Bash, Zsh and Fish shells (
pearl/airline [installed]
    Status/tabline for vim (
pearl/trash [installed]
    Smart command to recover files you regretted to delete (


  • Search for vim Pearl packages:
$ pearl search vim
* Updating repository
    Awesome vim dotfiles (


  • Install pearl/dot-vim package (as soon as the package is installed the package is ready out of the box in vim editor!):
$ pearl install dot-vim
* Updating repository
* Installing pearl/dot-vim package
  • Install pearl/trash package:
$ pearl install trash
* Updating repository
* Installing pearl/trash package
$ trash -h
Usage: trash file1 file2 ....
Moves to trash the files
        -s, --show                  Shows the trash
        -e, --empty                 Empties the trash
        -r, --recovery <file ...>   Recovers trashed files
        -c, --count                 Count the trashed files
        -h, --help                  Show this help message


  • Update pearl/dot-vim package:
$ pearl update dot-vim
* Updating repository
* Updating pearl/dot-vim package
  • Update Pearl and all its packages installed:
$ pearl update
* Updating repository
* Updating Pearl script
* Updating pearl/dot-vim package
* Updating pearl/airline package
* Updating pearl/trash package
* Updating pearl/caprica package


Emerge is an idempotent command for either installing or updating a package depending whether the package is already installed or not. This command turns to be particularly useful for establishing dependencies between packages. See the section below for more details.


  • Remove pearl/dot-vim package:
$ pearl remove dot-vim
* Updating repository
* Removing pearl/dot-vim package
  • Remove Pearl and all its packages installed:
$ pearl remove
Are you sure to REMOVE all the Pearl packages in $PEARL_HOME folder? (N/y)
* Updating repository
* Removing pearl/dot-vim package
* Removing pearl/airline package
* Removing pearl/trash package
* Removing pearl/caprica package

Recommended Pearl Hub packages to install:

For dotfiles packages take a look here.

Check out the OPH (Official Pearl Hub) for more packages you might be interested.



Before installing Pearl be sure that all dependencies are properly installed in your system. The Pearl dependencies are the following:

The following are optional dependencies in case you are using a different shell from bash:


Assuming all Pearl dependencies are properly installed in the system, to install Pearl run the following:

# or
curl -LO


In order to install all Pearl dependencies, you first need to install Homebrew.

To install all the needed dependencies via Homebrew:

brew update
brew install bash git coreutils

Once all Pearl dependencies are properly installed in the system, to install Pearl run the following:

# or
curl -LO

Create your own Pearl package in seconds!

Any git repository is already a Pearl package. For instance, in order to see a dotfiles repository in Pearl, you just need to change the Pearl configuration file located in $HOME/.config/pearl/pearl.conf.

Add the following line to pearl.conf file:


In other words, update the PEARL_PACKAGES array with a new entry containing the name of the package (i.e. joe-dotfiles) and the git url (i.e.

That's it! The package will be ready to be installed, updated, emerged and removed via the Pearl system.

Also, an optional description of the package can be defined via PEARL_PACKAGES_DESCR array:

PEARL_PACKAGES_DESCR["joe-dotfiles"]="The Joe's dotfiles"

Structure of a Pearl package

Your own git repository can contain an optional directory named pearl-config used by Pearl to integrate the package with the Pearl environment.

/ (package root)
├── pearl-config (optional directory)
│   │
│   ├──
│   ├──
│   ├── config.bash
│   ├── config.zsh
│   ├──
│   ├── config.vim
│   └── config.el
└── (additional package content)

The files inside pearl-config are also optional scripts:

  • - contains the hooks functions executed during the install, update and remove events.
  • - will be sourced whenever a new Bash/Zsh shell is starting up.
  • config.bash - will be sourced whenever a new Bash shell is starting up.
  • config.zsh - will be sourced whenever a new Zsh shell is starting up.
  • - will be sourced whenever a new Fish shell is starting up.
  • config.vim - will be executed whenever Vim editor is starting up.
  • config.el - will be sourced whenever Emacs editor is starting up.

The following variables can be used in any of the previous scripts:

  • PEARL_HOME - Pearl location (default: $HOME/.config/pearl)
  • PEARL_ROOT - Pearl script location
  • PEARL_PKGDIR - Pearl package location
  • PEARL_PKGVARDIR - Pearl package location containing data needed for package
  • PEARL_PKGNAME - Pearl package name
  • PEARL_PKGREPONAME - Pearl package repo name (useful to detect and interact with packages within the same repo)

Additionally, the script can use the utility functions available in Buava and Pearl utils directory that make easier the integration with Pearl ecosystem.

Useful examples of Pearl packages can be checked in the Official Pearl Hub.

Note: Legacy Pearl versions were using a different directory named pearl-metadata. This directory is meant to be deprecated in the upcoming Pearl version.

The script

Hook functions

  • post_install - Called after an installation of the package occurs.
  • pre_update - Called before an update of the package occurs.
  • post_update - Called after an update of the package occurs.
  • pre_remove - Called before a removal of the package occurs.
  • post_remove - Called after a removal of the package occurs.

An script example

post_install() {
    info "Awesome - new package installed!"
    warn "Remember to setup your config located in: ~/.dotfiles"
    link tmux "$PEARL_PKGDIR/mytmux.conf"
post_update() {
pre_remove() {
    info "dotfiles package removed"
    unlink tmux "$PEARL_PKGDIR/mytmux.conf"

The info and warn are functions that print a message using different colors (namely cyan and yellow).

The link unlink are idempotent functions (the result will not change if the function will be called multiple times) that are able to link/unlink a config file in order to be loaded at startup by a certain program.

All these functions belong to the Buava package in and to the Pearl script.

Create a Pearl package from a local directory

Pearl package system will work even for local directories. This is particularly useful whenever a Pearl package needs to be tested before pushing to a git repository.

For instance, the following lines in pearl.conf file will add a package located in /home/joe/dotfiles:

PEARL_PACKAGES_DESCR["joe-dotfiles"]="The Joe's dotfiles"

The directory path must be an absolute path.

The package will be ready to be installed, updated, emerged and removed via the Pearl system.

The directory content can be structured in the exact way as described in the previous section.

Define dependencies between Pearl packages

Suppose you have a package mypack which depends on another package mydep, you can update the mypack file in this way:

post_install() {
    # Install/update the dependency here:
    pearl emerge ${PEARL_PKGREPONAME}/mydep
post_update() {
pre_remove() {
    # Uncomment below to strictly remove the dependency
    # during the removal of the current package:
    #pearl remove ${PEARL_PKGREPONAME}/mydep

The PEARL_PKGREPONAME variable will make sure to define dependencies only between packages of the same repository. To see a real example in Pearl Hub, take a look at the Kyrat

Use third-party git repository not available in Pearl Hub

If you want to use a third-party git repository that is not available in the Official Pearl Hub, you can:

  • Create your own git repository and use the PEARL_PKGVARDIR directory (recommended)
  • Create your own git repository and use git submodule
  • Point directly to the third-party git repository

To see examples of Pearl packages from third-party git repos take a look at the Official Pearl Hub.

Create your own git repository and use the PEARL_PKGVARDIR directory (recommended)

You can use the PEARL_PKGVARDIR directory during the installation phase to install the third-party git repository. This is the best way to incorporate third-party project into Pearl ecosystem.

Here it is an example of file which install the ranger file manager into the directory ${PEARL_PKGVARDIR}/ranger:

function post_install(){
    install_or_update_git_repo "${PEARL_PKGVARDIR}/ranger" master

function post_update(){

function pre_remove(){
    rm -rf ${PEARL_PKGVARDIR}/ranger

The function install_or_update_git_repo comes from the Buava library in which is natively available in Pearl during the installation. You can even use the functions install_git_repo or update_git_repo which respectively install or update the git repository.

For a full example take a look at the ranger Pearl Hub package.

Create your own git repository and use git submodule

Inside your git repository, you just need to add the third-party git repo as a git submodule. For instance, to add the powerline in your Pearl package, you can introduce a submodule in the module directory:

git submodule add module

The filesystem structure of the package will become something like this:

/ (package root)
├── pearl-config   (optional directory)
├── module/        (contains third-party code)
└── (additional package content)

Then, you just need to modify the config scripts in order to integrate the third-party project inside Pearl environment.

Point directly to the third-party git repository

Let's suppose you want to install the vim-rails plugin. In your Pearl configuration (~/.config/pearl/pearl.conf), add your new Pearl package:

PEARL_PACKAGES_DESCR["vim-rails"]="Ruby on Rails power tools"

Install the package:

pearl install vim-rails

Voila', your new vim plugin is ready to be used!

This approach is particularly useful whenever you do not need to specify any pearl config to "enrich" the third-party project inside the Pearl environment.

Create your own Pearl repository in seconds!

A Pearl repository is just a git repository containing a file located in pearl-config/pearl.conf with a list of packages. For instance, the OPH repository is available here.

In order to use the new repository (i.e. ""), update the pearl.conf file by adding the following line:



Corrupted Pearl Home directory

Q: What should I do if I accidentally removed files/packages in $PEARL_HOME?

A: You can recover the structure of the $PEARL_HOME by running:

$> pearl init

The command will create all the essential directories and symlinks in $PEARL_HOME. It is harmless to run the init command multiple times since it is idempotent.

Corrupted package

Q: Why I can no longer update/remove a package?

A: This is probably because either one of the hook functions is failing or the package content is corrupted. You can forcely delete a package by simply removing its directory:

$> rm -rf $PEARL_HOME/packages/pearl/<packagename>

After that, you can reinstall the package again. The Pearl packages contain a dedicated directory var for storing data needed for the package itself. The var data are always managed by the package and they never gets deleted by Pearl during the package removal. If you want to delete the content in var package:

$> rm -rf $PEARL_HOME/var/pearl/<packagename>

Package shell variables/functions not visible in current shell after installation

Q: Why are not package's environment variables/functions visible in my current shell after installing/updating the package?

A: After package install/update, the variables or functions related to the current shell and defined in pearl-config/config.* may not be available because a reload of Pearl configuration file is required. You can fix this by simply run the function pearl-source which reloads the configuration. The use of such function is not always required but depends whether the variables/functions involve the current shell where the package install/update occurred (i.e. a new variable defined in and the current shell is a bash or zsh). Alternatively, user can always create a new shell and the package resources will be available as expected.


You could help improving Pearl and the OPH in the following ways: