CLI tool
b3nj5m1n/xdg-ninja avatar
b3nj5m1n/xdg-ninja

xdg-ninja: find the files that ignore XDG and move them back where they belong

A shell script which checks your $HOME for unwanted files and directories.

3,379 stars189 forksHaskellMIT

At a glance

What is it?
xdg-ninja is a shell script that scans $HOME for dotfiles and directories that programs dumped outside the XDG base directory layout, then tells you whether each one can be moved and how. It is for Linux users who want a tidy home directory without auditing every config path by hand.
Who is it for?
Adopt xdg-ninja if you run Linux, keep a long-lived home directory, and want a concrete list of misplaced config files with per-program instructions rather than a generic cleanup script. Skip it if most of your tooling is already XDG-aware, or if you want something that edits your dotfiles for you: xdg-ninja reports and instructs, it does not rewrite application configuration.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 144 days ago.
What is it written in?
Mainly Haskell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: programs that treat $HOME as their own

The XDG base directory specification defines where user-specific files should live: configuration under XDG_CONFIG_HOME, data under XDG_DATA_HOME, cache under XDG_CACHE_HOME. Plenty of programs ignore it and write straight into $HOME, so a home directory accumulates .gitconfig, .npmrc, .viminfo and dozens of similar entries that exist only because the application picked the easiest path.

xdg-ninja targets exactly that residue. It is a shell script that walks your $HOME looking for files and directories it has a record of. When it finds one, it tells you whether that file can be moved to the appropriate location and how to do the move. The audience is Linux users who care about keeping $HOME readable, and who would rather get a per-program checklist than run a blind cleanup script that deletes things.

How xdg-ninja decides what to report

The mechanism is data-driven, and the data lives in JSON. The programs/ directory holds one file per application, and each file names the program plus a list of paths it is known to write into $HOME. For every path there is a movable flag and, when the answer is yes, a Markdown help string explaining the relocation.

The README's own example is git: the file $HOME/.gitconfig is marked movable, and the help text says the XDG spec is supported by git so the file can be moved to $XDG_CONFIG_HOME/git/config. The script does not perform that move. It finds the file, reports it, and prints the instructions. That separation is the design: detection is automated, remediation stays manual and readable.

Configuration sources are named in the README as the Arch Wiki page on XDG_BASE_DIR, the antidot project (converted with a tool written by a contributor), and entries crowdsourced from other users. The script itself needs a POSIX-compliant shell, jq for parsing the JSON files, and find. glow is optional and renders the Markdown help in the terminal; bat, pygmentize or highlight can substitute, but the README says glow's output is clearer.

The programs directory is expected next to xdg-ninja.sh, and the XN_PROGRAMS_DIR environment variable overrides that location. That variable matters for packaging: a distribution that installs the script into a bin directory has to point the script at wherever it put the JSON files.

Installing xdg-ninja and running a first scan

The manual route is a clone plus the script. Run these three commands and the script executes every test in the default configuration, printing a report of the files it recognizes in your home directory.

bash
git clone https://github.com/b3nj5m1n/xdg-ninja
cd xdg-ninja
./xdg-ninja.sh

If you use Nix with flakes enabled, the README gives a single command instead of a clone:

bash
nix run github:b3nj5m1n/xdg-ninja

Homebrew users need the HEAD flag, and the README is explicit about why: releases are not cut the way Homebrew expects, so the formula ships a stale version. Install and upgrade both go through git HEAD, and a generic brew upgrade will not touch it.

bash
brew install xdg-ninja --HEAD
brew upgrade xdg-ninja --fetch-HEAD

There is also a Makefile for a system-wide install. It installs the script as $(PREFIX)/bin/xdg-ninja, copies programs into $(PREFIX)/share/xdg-ninja/, and places the man page and docs under share/man and share/doc. PREFIX defaults to /usr/local, so a plain make install puts the JSON configs in /usr/local/share/xdg-ninja/programs. If you install that way and the script reports nothing, check XN_PROGRAMS_DIR before assuming your home directory is clean.

Adding your own program configs, and the xdgnj generator

The script only knows what is in programs/. A program that is not covered will never appear in the output, which is the main reason a clean report is not proof of a clean home directory.

Writing a config by hand is a small JSON file. The README's git example, saved as programs/git.json, is the template:

json
{
    "name": "git",
    "files": [
        {
            "path": "$HOME/.gitconfig",
            "movable": true,
            "help": "Luckily, the XDG spec is supported by git, so we can simply move the file to _$XDG_CONFIG_HOME/git/config_.\n"
        }
    ]
}

The help field is Markdown, so newlines and formatting have to be JSON-escaped. The README suggests piping text through jq -aRs . to produce a correctly escaped string, and shows that a two-paragraph help text comes out with embedded \n sequences.

There is a separate Haskell binary, xdgnj, that helps generate these files. The README is careful to say it is only a config generator: you still need the shell script to run the tests. It offers xdgnj add, xdgnj prev programs/FILE.json, xdgnj edit programs/FILE.json and xdgnj run. Prebuilt binaries are published for x86_64 Linux only, and can be fetched with curl and made executable with chmod +x. Building from source uses cabal build or stack build, and a dockerfile is provided under haskell/build/.

Where xdg-ninja stops short

The tool reports; it does not fix. Nothing in the README describes an automatic move, a rollback, or a dry-run mode that undoes changes, because the script never makes changes in the first place. If you want a tool that relocates files for you, this is the wrong one.

Coverage is the second constraint. The programs directory is a curated and crowdsourced list, so an application nobody has written a config for is invisible. A report with no findings means no known paths were found, not that your home directory is XDG-compliant.

The help text is advice, not verification. A config can say a file is movable to a particular path; whether that specific application version actually honors the XDG variable is something you have to confirm. Some entries in the README's own workflow are marked as not fixable at all, with a suggestion to delete the directory instead, which is a reminder that the underlying programs, not the script, set the limits.

Finally, the Homebrew situation is a real packaging wart. The README states plainly that releases are not cut in a way that suits the formula, that the shipped version is stale, and that you must install and upgrade from git HEAD. The most recent tagged release is v0.2.0.2 from 2024-02-04, so anyone relying on tags rather than HEAD is working with older configuration data. The repository itself is not archived and the last push was on 2026-05-10, so the project is still receiving changes even though releases are rare.

xdg-ninja versus antidot

antidot is the closest point of comparison, and the README names it as one of the sources for xdg-ninja's own configuration data. The difference is what each one does with that knowledge.

antidot is built around applying the relocation: it manages the move of files into XDG-compliant locations. xdg-ninja stops at detection and instruction. You get a report and a Markdown explanation per file, and you run the mv or edit the application config yourself.

That makes xdg-ninja the safer choice if you want to review each change before it happens, and the more tedious one if you have a long list. It also means xdg-ninja's JSON schema is a description of a problem plus a suggested fix, while a tool that performs moves needs to encode the mechanics of the relocation itself. If your goal is a one-shot cleanup of a messy home directory, a tool that acts will get you there faster. If your goal is understanding which programs are misbehaving and why, reading a report is the point.

Licence, packaging and what maintenance costs you

xdg-ninja is MIT licensed. That is permissive: you can redistribute it, embed it in a distribution, or ship the JSON configs alongside it, provided the licence text travels with it. The Makefile already installs LICENSE and README.md into share/doc, which handles that for a system install. Nothing here is legal advice, and if you are packaging it commercially you should read the LICENSE file in the repository rather than this summary.

The upgrade story splits by install method. Nix users get the flake and can pin or follow it as they would any other flake. Homebrew users have to remember the --fetch-HEAD flag, because a plain brew upgrade will leave the formula's stale copy in place. Manual cloners just pull. The cost that matters more than any of these is the config data: programs/ grows as contributors add applications, so an old copy produces an old report. If you installed through a distribution package that tracks a tag rather than HEAD, expect the coverage to lag.

Running the script is cheap and read-only, so there is no ongoing operational burden beyond re-running it after you install new software. The maintenance work is in the instructions it prints: each flagged file is a small manual change to an application's configuration.

Editorial conclusion

Adopt xdg-ninja if you run Linux, keep a long-lived home directory, and want a concrete list of misplaced config files with per-program instructions rather than a generic cleanup script. Skip it if most of your tooling is already XDG-aware, or if you want something that edits your dotfiles for you: xdg-ninja reports and instructs, it does not rewrite application configuration. Before trusting it, run it once and check that the programs directory it loaded matches where you installed it, which on a Makefile install means /usr/local/share/xdg-ninja/programs, and confirm jq is present, since the script parses its JSON configs with it.

Frequently asked questions

What does xdg-ninja do?

It is a shell script that checks your $HOME for files and directories it knows about, and for each one tells you whether it can be moved to the appropriate XDG location and how to do it. The configurations come from the Arch Wiki page on XDG_BASE_DIR, from antidot, and from other users.

How do I install xdg-ninja?

Clone the repository and run ./xdg-ninja.sh, or use nix run github:b3nj5m1n/xdg-ninja. Homebrew users must install and upgrade with the HEAD flag, because the README states releases are not cut and the formula otherwise ships a stale version.

Does xdg-ninja move the files for me?

No. It reports the file and prints Markdown instructions for relocating it. The README's git example marks $HOME/.gitconfig as movable and explains that it can be moved to $XDG_CONFIG_HOME/git/config, but the move is left to you.

What does xdg-ninja need to run?

A POSIX-compliant shell, jq for parsing the JSON files, and find. glow is optional and renders the Markdown instructions in the terminal; bat, pygmentize or highlight work as fallbacks, though the README says glow's output is clearer.

What is the xdgnj binary for?

It is a Haskell tool that helps you automatically generate the JSON configuration files, with commands such as xdgnj add, xdgnj prev, xdgnj edit and xdgnj run. The README stresses that it is only a config generator and that you still need your shell to run the tests.

Official sources

  1. b3nj5m1n/xdg-ninja on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/b3nj5m1n-xdg-ninja.svg)](https://hysenlabs.com/projects/b3nj5m1n-xdg-ninja)