Awesome Open Source
Awesome Open Source


Build Status img img img


alt tag

An interactive .files and environment configuration tool created with node

Inspired by Zach Holmans popular dotfiles, stripped down and written in node

  • One command
  • No restrictions on where you run from or store your dotfiles
  • Easy to configure, extend and tweak
  • Interactive CLI that prompts which tasks you want to run
  • Just needs node and your dotfiles!

alt tag


What is kody

kody is more than a dotfiles installer. Out of the box, it can handle symlinking your version controlled files to a desired directory. It will also backup your originals if you wish 👍

But it can do much more! And it's up to you how creative you want to get 🐻

You create some tasks to set up your machine, run kody, and kody will go ahead and run the tasks you tell it to!

What else would I use it for

You can use kody to automate most things.

For example, fed up of installing a bunch of apps when you set up a machine? Create a small task to install homebrew, configure a list of apps you want and tell kody to do it for you! 😉

Or how about automating your shell configuration or IDE set up! They can be time consuming 😅

You can see some examples in the examples section below 👍


You'll need to install node/npm first as this is a dependency of kody. Then, install kody globally 👍

npm i -g kody


Installing Dotfiles

Out of the box, kody comes with dotfile installation. kody will symlink your version controlled dotfiles to a directory of your choosing. The default is $HOME.

kody needs to know which files to symlink. So any files or directories you wish to symlink should have the suffix .link.

For example; I want to install a dotfile for a .gitignore file. Rename your version controlled .gitignore to and then run kody in that directory. The same works for directories if you want to symlink the contents of a directory.

/my/version/controlled/dotfiles/repo/ -> $HOME/.gitignore

kody will also prompt you to see if you'd like to backup your original dotfiles. It will backup the original to the same destination with the .bak suffix.

That's all you need to manage and install your dotfiles 💪


Now the fun starts! 😉

You can also use kody to automate various defined tasks.

Let's start with the basics.

By default, all tasks live inside a kody.tasks directory. You can configure this (we will get to that). kody will search the directory for all the JavaScript files it can find. You can nest tasks.

Each task file exposes an object that must consist of at least a name and an exec function. The description property is metadata to give a friendly description of tasks. description will be rendered when choosing which tasks to run.

module.exports = {
  name: '🦄',
  description: 'A truly magical task',
  exec: (resolve, reject, shell, config, log, ora) => {}

The exec function is what gets run by kody. You can do whatever you like inside this function but the arguments passed in are important. This is how kody exposes various things to the user. You are of course free to name the parameters however you wish 😄

Let's run through them 👍

  • resolve/reject - kody uses Promises so the first two arguments enable you to inform kody of when to move on. If your task is complete, invoke resolve. If your task stumbles, make use of reject 🛑
  • shell - one of the main things when automating set up etc. is running various shell commands. kody exposes the shelljs API to your tasks. We will use this in the Hello World example
  • config - a major thing with set ups is being able to keep everything in one config file. This way you won't have to hard code values into your tasks. kody will search for a .kodyrc file on start and pass that configuration object to your tasks. In here you can define any JSON you want. For example, a list of apps to install, editor plugins to install etc. Define under keys and access them in your tasks 👊
  • log - kody exposes a simple color logging utility that uses chalk. It's a function that takes three parameters. The first is the message you want to display. The second and third are the text color and background color respectively. The function expects color represented by a hexidecimal value 👍 You use this log function inside your standard console invocation.
  • ora - kody exposes the ora API so you can fire up a terminal spinner when needed too!

Hello World

For our first task, why not "Hello World!"? 😅

We will use shelljs to invoke say.

const task = {
  name: 'Hello World 👋',
  description: 'Hey from kody 🐻',
  exec: (resolve, reject, shell) => {
    shell.exec('say hello world!')
module.exports = task

That's it! Run kody in the parent of your tasks directory and choose the Hello World task. Depending on your OS, you should hear Hello World! 🎉

.kodyrc file

The .kodyrc file was mentioned briefly above. It's used to define values and configuration for your tasks. It also has two special keys. Both are optional

  • task_directory - this specifies the location of your tasks relative to your current working directory
  • running_order - this specifies a running order for your tasks

An example .kodyrc

  "task_directory": "./awesome-tasks",
  "running_order": [
  "brewInstalls": [

In this .kodyrc file we specify that tasks are under ./awesome-tasks. We also state that tasks run in any order but b must run before a. It's important to note that running order entries are task file names and not the name of the task. The extension is not necessary.

Any other keys in the .kodyrc file are user defined and made available in any tasks you write/use. In this example, we have brewInstalls which could be an array of homebrew casks to install.

A real task

For a real task example, let's install Homebrew.

const { info } = console
const task = {
  name: 'Homebrew',
  description: 'Install and set up Homebrew',
  exec: function(resolve, reject, shell, config, log) {
    const { brew_installs: packages } = config
    const brewInstalled = shell.which('brew') !== null
    if (!brewInstalled) {
      try {
        info(log('Installing Homebrew'))
        const result = shell.exec(`ruby -e "$(curl -fsSL ${PROPS.URL})"`)
        if (result.code !== 0) throw new Error(result.stderr)
        else info(log('Homebrew installed'))
      } catch (err) {
        throw new Error(err)
    } else info(log('Homebrew already installed'))
    info(log('Running brew doctor'))
    shell.exec('brew doctor')
        `NOTE: Any info from brew doctor may account for any issues with package installs`
    if (packages && packages.length > 0) {
      info(log(`Installing ${packages.join(' ')}`))
      shell.exec(`brew install ${packages.join(' ')}`)
      info(log('Brew packages installed'))
    } else {
      info(log('No brew packages to install'))

module.exports = task

It may look like there's a lot going on here. But the majority of this is actually logging to the console 😅

Tasks that have already been created

  • Set up git
  • Write OSX defaults
  • Install and set up Homebrew
  • Install programs supported by brew cask such as Spotify, Chrome, etc.
  • Set up fish shell
  • Set up oh-my-zsh
  • Install Atom IDE packages
  • Install and set up Visual Studio Code
  • Remove unwanted default system applications


  • Jhey's .files - My personal kody set up. Sets up IDE, installs programs, configures shell etc.


kody is easy to work on. It uses a self-documented Makefile.

Just run make to see what tasks are available.

First things first is to pull in dependencies with make setup.

Then you'll be wanting to use make develop to start work. Use npm link to get a global instance of what you're working on available in the shell. You can test this by running kody --version.

It's best to create a dummy folder that you can test things out in. This reduces the risk of breaking your $HOME setup.

Enjoy! 😎

Under the hood

kody is written using es6 with babel and is developed using a self-documented Makefile.


I've only used kody on OSX. I'm not responsible if you bork your machine configuration 😅 However, I'm happy to try and help you out if you get stuck!


Any problems or questions, feel free to post an issue or tweet me, @jh3yyy! 🐦

Made with 🐻s by @jh3y 2018

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
javascript (70,924
nodejs (3,865
osx (333
dotfiles (317
utility (227
cli-app (108
dotfile (16