{"id":15712345,"url":"https://github.com/olaoluwam/dotfilers","last_synced_at":"2025-10-28T12:06:26.944Z","repository":{"id":39234466,"uuid":"497498930","full_name":"OlaoluwaM/dotfilers","owner":"OlaoluwaM","description":"A minimalist, transparent flexible approach to dotfiles management. Written with fp-ts","archived":false,"fork":false,"pushed_at":"2022-12-31T05:43:03.000Z","size":406,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-12T22:53:53.996Z","etag":null,"topics":["cli","dotfiles","dotfiles-manager","fp-ts","functional-programming","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OlaoluwaM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-29T05:28:50.000Z","updated_at":"2024-05-30T23:36:48.000Z","dependencies_parsed_at":"2023-01-31T18:16:34.405Z","dependency_job_id":null,"html_url":"https://github.com/OlaoluwaM/dotfilers","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlaoluwaM%2Fdotfilers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlaoluwaM%2Fdotfilers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlaoluwaM%2Fdotfilers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OlaoluwaM%2Fdotfilers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OlaoluwaM","download_url":"https://codeload.github.com/OlaoluwaM/dotfilers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253837389,"owners_count":21971981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","dotfiles","dotfiles-manager","fp-ts","functional-programming","typescript"],"created_at":"2024-10-03T21:15:42.442Z","updated_at":"2025-10-28T12:06:21.905Z","avatar_url":"https://github.com/OlaoluwaM.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introduction\n\n\u003c!-- - Add your project logo.\n- Write a short introduction to the project.\n- If you are using badges, add them here. --\u003e\n\nWelcome to Dotfilers! A CLI tool that automates the management of system configuration files (dotfiles) simply and transparently with blazing fast efficiency.\n\n## :ledger: Index\n\n- [Introduction](#introduction)\n  - [:ledger: Index](#ledger-index)\n  - [:beginner: About](#beginner-about)\n  - [:zap: Usage](#zap-usage)\n    - [:electric\\_plug: Installation](#electric_plug-installation)\n    - [🪜 Setup](#-setup)\n    - [:package: Commands](#package-commands)\n    - [🛠️ Configuration](#️-configuration)\n  - [:wrench: Development](#wrench-development)\n    - [:notebook: Pre-Requisites](#notebook-pre-requisites)\n    - [:nut\\_and\\_bolt: Development Environment](#nut_and_bolt-development-environment)\n    - [:hammer: Build](#hammer-build)\n    - [:rocket: Deployment](#rocket-deployment)\n  - [:cherry\\_blossom: Community](#cherry_blossom-community)\n    - [:fire: Contribution](#fire-contribution)\n    - [:cactus: Branches](#cactus-branches)\n  - [:lock: License](#lock-license)\n\n## :beginner: About\n\n\u003c!-- Add a detailed introduction about the project here, everything you want the reader to\nknow. --\u003e\n\nThis project began as a simple script to help keep my dotfiles repository in check with minimal effort (laziness ftw :P). Eventually, as things grew, so did the sophistication of my script, to the point where I felt the idea it leveraged was robust enough to be generalized. Hence this project!\n\nDotfilers helps you manage your system configuration files with ease. It's implementation is also pretty straightforward! Essentially, it's all symbolic links 😃. Symbolic links are very powerful as they allow us keep files up to date with pointers that reference those files from any part of our file system. What's more, paths to these pointers can also be used in place of the path to the actual file being referred to because the pointer's path still resolves to the actual file.\n\nHowever, for all this to work, the CLI imposes a minimal required structure on your dotfiles repository, so certain things can be kept track of.\n\nThe CLI requires that you encapsulate configuration files into special directories known as \"_configuration groups_\" or \"config group\" for short. A config group is a directory of system configuration files (preferably related, but not a hard requirement) with a special association file, called a `destinations.json` file, that maps each configuration file to a destination path.\n\nAlthough, it sounds very simple (because it is), this file is has added capabilities such as:\n\n- The ability to configure a destination for all configuration files at once using the `all` key which also doubles as a value if you wanted to set all configuration files to be excluded with `exclude` key.\n- We can direct sets of configuration files to a single destination path using globs as keys in the file\n- Paths support all available shell variables, even the `~`. Destination paths must be absolute, not relative\n\nConfig groups can have any name, but names that collectively represent the nature or use case of the configuration files housed within them are best. For instance, if you had a config group that contained all your `git` configuration, you wouldn't name it `cherry`. The name `git` is better because it is semantic.\n\nHere is an example of what your dotfiles directory structure might look like\n\n```txt\n.\n├── git/\n│   ├── .gitconfig\n│   ├── destinations.json\n│   └── .gitignore\n├── npm/\n│   ├── destinations.json\n│   └── .npmrc\n├── shell/\n│   ├── .zshrc\n│   ├── destinations.json\n│   └── .bash_aliases\n└── cava/\n    └── .config\n```\n\nThe `git`, `shell`, and `npm` directories are all config groups, but not the `cava` directory since it doesn't have the `destinations.json` file.\n\nYour structure can be flat (recommended), but it can also be nested, that is, you can have config groups within other config groups or regular directories within config groups. In the case of nested directories, you can reference nested files from the top level `destinations.json` file.\n\nHowever, if the nested directory is a config group, then the parent directory's `destinations.json` file cannot reference any files within it. Nested config groups are isolated from their parents and function much like separate directories.\n\n## :zap: Usage\n\n\u003c!-- Write about how to use this project. --\u003e\n\n### :electric_plug: Installation\n\n\u003c!-- - Steps on how to install this project, to use it.\n- Be very detailed here, For example, if you have tools which run on different operating\n  systems, write installation steps for all of them. --\u003e\n\nInstallation is simple. All you need is node and npm.\n\n```bash\nnpm i -g dotfilers\n```\n\n### 🪜 Setup\n\n**The CLI relies on one of two environment variables for the path to your dotfiles directory: `$DOTS` or `$DOTFILES`**. Ideally, either one (or both) of these variables should be defined and available permanently. This can be achieved by defining them in your shell config file (like a .bashrc or .zshrc) or an alias file sourced on shell startup.\n\n\u003e **IMPORTANT**: Either the `$DOTS` or `$DOTFILES` shell variables must be set as the CLI depends on them to function properly.\n\n\u003c!-- Speak on the anatomy of the `destinations.json` file --\u003e\n\n### :package: Commands\n\u003c!-- - Commands to start the project. --\u003e\n\nThe CLI has four commands\n\n- `link`: Receives the names of configuration groups as arguments and, by default, creates symbolic links of the **un-excluded** files within each listed configuration group. The destination path of the ensuing symbolic links are determined by associations listed in the `destinations.json` file of the corresponding configuration group. If the destination path does not exist, it is created, regardless of how nested it is.\n\n- `unlink`: The opposite to `link`. Functions in much of the same way, except rather than placing symbolic links at a destination path, it deletes the symbolic links of the files in the configuration groups, using the corresponding `destinations.json` as lookup reference for where the links are\n\n- `create`: Bootstraps a new configuration group with a default `destinations.json` file\n\n- `sync`: Synchronizes dotfiles directory with corresponding remote repository. **Note,** your dotfiles directory must be a git repository for this command to work.\n\nEach command also has a set of options that augment its behavior. Use the `dfs --help` command to find out more.\n\n### 🛠️ Configuration\n\nBelow is an example of a sample `destinations.json` file for the `shell` directory in the above illustration:\n\n```json\n{\n  \".zshrc\": \"~\",\n  \".bash_aliases\": \"$HOME\"\n}\n```\n\n\u003e Notice how we refer to files by their names and not by some relative path\n\nWhen we invoke the `link` command (`link shell`), we would be creating symbolic links for the `.zshrc` and `.bash_aliases` files in the home directory. We could set a default destination for all files in the `shell` configuration group with the following file disposition:\n\n```json\n{\n  \"all\": \"~\"\n}\n```\n\nThe `all` key is a reserved one that collectively refers to _all_ files within a config group. It can also be used to specify a general default destination for files not explicitly associated with a destination path in the JSON. **Implicitly, though, all files default to having their symbolic links placed in the home directory**\n\nTo keep certain files from having symbolic links created and positioned somewhere in your file system, we can list them as part of the values for the `exclude` key, as so:\n\n```json\n{\n  \"exclude\": [\"example.json\", \"*.toml\", \".xresources\"]\n}\n```\n\nThis is another reserved key that takes either an array of filenames and globs or the string \"`all`\" as values.\n\n```json\n{\n  \"exclude\": \"all\"\n}\n```\n\nIf it has a value of \"`all`\", all config files in the configuration would be skipped over by both the `link` and `unlink` commands.\n\nFinally, here is a full on sample `destinations.json` file\n\n```json\n{\n  \"config-file-name.json\":\"$HOME/.local/app\",\n  \"inner/nested-file.rs\": \"$HOME\",\n  \"*.toml\": \"$CUSTOM_VAR/.local/toml-configs\",\n  \"exclude\": [\"*.js\", \"*.txt\", \".gitconfig\"],\n  \"all\": \"~/default\"\n}\n```\n\n## :wrench: Development\n\n\u003c!-- If you want other people to contribute to this project, this is the section, make sure you\nalways add this. --\u003e\n\n### :notebook: Pre-Requisites\n\nTo work or contribute to the code of this project, you require the following:\n\n- Knowledge of functional programming, beyond purity, array methods, and immutability. Knowledge of things like\n  - Modelling side effects with algebraic data structures\n  - Optics\n- Knowledge of [fp-ts](https://github.com/gcanti/fp-ts)\n- Comfortable with Typescript\n\n### :nut_and_bolt: Development Environment\n\nSetup is easy, it's just like any other node project written in TypeScript with NPM as the package manager\n\n\u003c!-- ### :file_folder: File Structure\n\nAdd a file structure here with the basic details about files, below is an example.\n\n```\n.\n├── assets\n│   ├── css\n│   │   ├── index-ui.css\n│   │   └── rate-ui.css\n│   ├── images\n│   │   ├── icons\n│   │   │   ├── shrink-button.png\n│   │   │   └── umbrella.png\n│   │   ├── logo_144.png\n│   │   └── Untitled-1.psd\n│   └── javascript\n│       ├── index.js\n│       └── rate.js\n├── CNAME\n├── index.html\n├── rate.html\n└── README.md\n```\n\n| No  | File Name | Details     |\n| --- | --------- | ----------- |\n| 1   | index     | Entry point | --\u003e\n\n### :hammer: Build\n\nNothing serious, just run the command:\n\n```bash\nnpm run build\n```\n\n### :rocket: Deployment\n\nDeployments to the NPM registry occur automatically on successful pull requests to the `main` branch. The nature of the commit determines the kind of release that occurs.\n\n## :cherry_blossom: Community\n\n\u003c!-- If it's open-source, talk about the community here, ask social media links and other links. --\u003e\n\n### :fire: Contribution\n\nYour contributions are always welcome and appreciated. Following are the things you can do to contribute to this project.\n\n1. **Report a bug** - If you think you have encountered a bug, and I should know about it, feel free to report it [here](https://github.com/OlaoluwaM/dotfilers/issues) and I will take care of it.\n\n2. **Request a feature** - You can also request for a feature [here](https://github.com/OlaoluwaM/dotfilers/issues), and if it will viable, it will be picked for development.\n\n3. **Create a pull request** - It can't get better then this, your pull request will be appreciated by the community. You can get started by picking up any open issues from [here](https://github.com/OlaoluwaM/dotfilers/issues) and make a pull request.\n\n\u003e If you are new to open-source, make sure to check read more about it [here](https://www.digitalocean.com/community/tutorial_series/an-introduction-to-open-source) and learn more about creating a pull request [here](https://www.digitalocean.com/community/tutorials/how-to-create-a-pull-request-on-github).\n\n### :cactus: Branches\n\nThe main branch is the production/release branch. All other branches are feature branches and should be deleted when no longer needed. I initially had a development branch, but keeping it in sync with the master branch became a bit of a hassle, and it's a relatively small project\n\n\u003c!--\nI use an agile continuous integration methodology, so the version is frequently updated\nand development is really fast.\n\n1. **`stage`** is the development branch.\n\n2. **`master`** is the production branch.\n\n3. No other permanent branches should be created in the main repository, you can create\n   feature branches but they should get merged with the master.\n\n**Steps to work with feature branch**\n\n1. To start working on a new feature, create a new branch prefixed with `feat` and\n   followed by feature name. (ie. `feat-FEATURE-NAME`)\n2. Once you are done with your changes, you can raise PR.\n\n**Steps to create a pull request**\n\n1. Make a PR to `main` branch.\n2. Comply with the best practices and guidelines e.g. where the PR concerns visual\nelements it should have an image showing the effect.\n3. It must pass all continuous integration checks and get positive reviews.\n\nAfter this, changes will be merged. --\u003e\n\n\u003c!-- ### :exclamation: Guideline\n\ncoding guidelines or other things you want people to follow should follow.\n\n## :question: FAQ\n\nYou can optionally add a FAQ section about the project.\n\n## :page_facing_up: Resources\n\nAdd important resources here --\u003e\n\n\u003c!-- ## :camera: Gallery\n\nPictures of your project. --\u003e\n\n\u003c!-- ## :star2: Credit/Acknowledgment\n\nCredit the authors here. --\u003e\n\n## :lock: License\n\n[MIT License](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folaoluwam%2Fdotfilers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folaoluwam%2Fdotfilers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folaoluwam%2Fdotfilers/lists"}