Xome: Easy Fancy Dev-Environments Configured with Home-Manager

icon

Ever wanted reproducible shell highlighting/autocomplete etc when running nix develop? Me too, which is why I made Xome (“Zome”): a small flake that combines home-manager and nix develop. Basically makes a fake home (cached), uses home-manager to populate it, then makes use of that home to create a super isolated nix-develop shell.

Note! the sys command makes easy to escape the otherwise super-isolatedness. Want to run a quick git push? Then sys git push will do what you want. Same for sys sudo, sys vim, etc. They will be run using your real home and real path, so they’ll find your home git config, ssh keys, etc.

Example Usage

If you use flake utils you probably have something like this:

{
    description = "My Project";
    inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
        flake-utils.url = "github:numtide/flake-utils";
        xome.url = "github:jeff-hykin/xome";
    };
    outputs = { self, nixpkgs, flake-utils, xome, ... }:
        let
            something = "something";
        in
            flake-utils.lib.eachDefaultSystem (system:
                {
                    packages = { /* your normal stuff */ };
                }
            );
}

You can add Xome like this:

{
    description = "My Project";
    inputs = {
        nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
        flake-utils.url = "github:numtide/flake-utils";
        xome.url = "github:jeff-hykin/xome";
    };
    outputs = { self, nixpkgs, flake-utils, xome, ... }:
        flake-utils.lib.eachDefaultSystem (system:
            let
                pkgs = nixpkgs.legacyPackages.${system};
            in
                {
                    packages = { /* your normal stuff */ };
                    devShells = xome.simpleMakeHomeFor {
                        inherit pkgs;
                        pure = true;
                        homeModule = {
                            # for home-manager examples, see: 
                            # https://deepwiki.com/nix-community/home-manager/5-configuration-examples
                            # all home-manager options: 
                            # https://nix-community.github.io/home-manager/options.xhtml
                            home.homeDirectory = "/tmp/virtual_homes/xome_simple";
                            home.stateVersion = "25.11";
                            home.packages = [
                                # vital stuff
                                pkgs.nix
                                pkgs.coreutils-full
                                
                                # optional stuff
                                pkgs.gnugrep
                                pkgs.findutils
                                pkgs.wget
                                pkgs.curl
                                pkgs.unixtools.locale
                                pkgs.unixtools.more
                                pkgs.unixtools.ps
                                pkgs.unixtools.getopt
                                pkgs.unixtools.ifconfig
                                pkgs.unixtools.hostname
                                pkgs.unixtools.ping
                                pkgs.unixtools.hexdump
                                pkgs.unixtools.killall
                                pkgs.unixtools.mount
                                pkgs.unixtools.sysctl
                                pkgs.unixtools.top
                                pkgs.unixtools.umount
                                pkgs.git
                                pkgs.htop
                                pkgs.ripgrep
                            ];
                            
                            programs = {
                                home-manager = {
                                    enable = true;
                                };
                                zsh = {
                                    enable = true;
                                    enableCompletion = true;
                                    autosuggestion.enable = true;
                                    syntaxHighlighting.enable = true;
                                    shellAliases.ll = "ls -la";
                                    history.size = 100000;
                                    # this is kinda like .zshrc
                                    initContent = ''
                                        # this enables some impure stuff like sudo, comment it out to get FULL purity
                                        export PATH="$PATH:/usr/bin/"
                                    '';
                                };
                                starship = {
                                    enable = true;
                                    enableZshIntegration = true;
                                };
                            };
                        }; 
                    };
                }
        );
}

Run nix develop and you’ll get a fancy starship terminal, autocomplete, highlighting, etc.

Tagging @MattRixman since you mentioned a while ago you might be interested in this kind of thing.

7 Likes

This is really cool @jeff-hykin thanks for sharing. You’re right that I’m interested (although I’ve lost track of where I said that :sweat_smile: ).

I think I may try to use it to set nushell as a project’s devshell and arm it with a bunch of project-specific plugins.

1 Like

So uh, about nushell :sweat_smile: , you definitely can use it and in fact any custom shell, but for this initial release you’ll have to test one of the advanced features: the shellOverride option. Because most shells source a global rc file (like /etc/profile) I have to add an extra shell-specific argument to prevent that behavior (and maintain isolation/reproducibility). I figured 99% of people use bash and zsh so I hardcoded automatic support for them (bash --noprofile and zsh --no-global-rcs). If you let me know the equivalent nushell startup flag(s), I can add automatic nushell support too. I imagine some people want fish support as well.

That all sounds quite reasonable.

Currently I’m just writing those plugins and adding them to home manager in the normal way. The time for distributing this shell experience as part of a repo will come later. Potentially much later… Or never if I can’t convince my co-workers to give nix a try.

Thanks for pointing me at that feature, when the time comes I’ll try it out and iron out any kinks.

Exactly what was on my mind too since devshells is all about a project specific experience :stuck_out_tongue_closed_eyes:

Yup. Please bring custom shell support so that many can use it. Shellhooks are an okayish workaround, but still a better approach can be done I guess.

btw, this project is nice. :clap:

1 Like

Could you explain more about what exactly Xome does? I can kind of make guesses with seeing the home-manager declarations, it seems like it’s creating a fake home environment when using nix develop? What else can it do?

{ Make fake home + activate fake home + no username requirement for homemanger + don’t break stuff + convenience (envPassthrough) } is pretty much all its doing. Took me quite a while to make it work. But once I figured out how, I took the time to boil it down into a pretty small flake. I’ve been using fake home systems for years (similar to devenv), but this is the first one thats really super isolated and simple (no extra CLI tool or extra files).

The idea is to create a whitelist for the dev environment. E.g. git (inside a dev shell) cannot access our personal config, unless we explicitly try to link it. In the future I want to add convenience options. I just added the sys command so that, in the shell sys python --version will be your system python while python --version would be the nix develop python (if there was one). Another example, I want to add an executable-specific passthrough (e.g. allow impure sudo) without adding all the impure executables in /usr/bin. Another example is allowing for a git-config passthrough and a nix-cache while keeping everything isolated (tons of programs read and modify home).

1 Like

It has custom shell support! It requires an extra arg, but it is supported without resorting to shell hooks.

Here, I added a section to the readme for it

1 Like