//flake.nix

My current workflow uses NixOS which is my primary Linux distribution on my computers. I also use project-level flakes which let me have specific versions of tools at the project level.

While I go into far more detail on using NixOS in my project layout, here is a high-level of what I use for writing.

Flake

The flake file flake.nix (and it corresponding flake.lock) describe the environment to use. There are two special setups that basically configure a lot of the common files such as automatic formatting while doing a commit, making sure line endings and tabs are correct, and also all of the command line tools that I typically use.

The first one is MfGames Project Setup Flake which adds conventional commits, source code formatting, and a bunch of other common things I use for both writing and software projects.

The second is MfGames Writing Setup Flake which packages all the command-line tools to use MfGames Writing.

Put together, this file sets up everything with just a copy/paste of the file from another writing project. This is also why I don't set the description attribute in the flake since I consider this a copy and forget type of file.

{
  inputs = {
    nixpkgs.url = "nixpkgs/nixos-25.05";
    flake-utils.url = "github:numtide/flake-utils";
    mfgames-project-setup.url = "git+https://src.mfgames.com/nixos-contrib/mfgames-project-setup-flake.git";
    mfgames-writing-setup.url = "git+https://src.mfgames.com/nixos-contrib/mfgames-writing-setup-flake.git";
  };

  outputs = { self, nixpkgs, flake-utils, mfgames-project-setup, mfgames-writing-setup }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};

        project-config = mfgames-project-setup.lib.mkConfig {
          inherit system;
          pkgs = nixpkgs.legacyPackages.${system};
          prettier.proseWrap = "never";
        };

        writing-config = mfgames-writing-setup.lib.mkConfig {
          inherit system;
          pkgs = nixpkgs.legacyPackages.${system};
        };
      in
      {
        devShell = pkgs.mkShell {
          packages = [ ]
            ++ project-config.packages
            ++ writing-config.packages;

          shellHook = project-config.shellHook;
        };
      });
}

Direnv

The flake itself doesn't do much. Instead I use a tool called direnv to automatically configure everything as soon as I change into the directory. This puts various tools on the PATH so most of my Just targets work. (Sadly, markdowny is not one of the things automatically configured, I'm working on that).

$ cd allegro
direnv: loading ~/src/fedran/sources/allegro/.envrc
direnv: using flake
direnv: nix-direnv: Using cached dev shell
nixago: updating repository files
nixago: '.conform.yaml' link is up to date
nixago: '.editorconfig' copy is up to date
nixago: 'lefthook.yml' link is up to date
nixago: '.prettierrc.json' link is up to date
nixago: 'treefmt.toml' link is up to date
sync hooks: ✔️ (pre-commit, commit-msg)
direnv: export +AR +AS +CC +CONFIG_SHELL +CXX +DETERMINISTIC_BUILD +HOST_PATH +IN_NIX_SHELL +LD +NIX_BINTOOLS +NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_BUILD_CORES +NIX_CC +NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +NIX_CFLAGS_COMPILE +NIX_ENFORCE_NO_NATIVE +NIX_HARDENING_ENABLE +NIX_LDFLAGS +NIX_STORE +NM +NODE_PATH +OBJCOPY +OBJDUMP +PYTHONHASHSEED +PYTHONNOUSERSITE +PYTHONPATH +RANLIB +READELF +SIZE +SOURCE_DATE_EPOCH +STRINGS +STRIP +_PYTHON_HOST_PLATFORM +_PYTHON_SYSCONFIGDATA_NAME +__structuredAttrs +buildInputs +buildPhase +builder +cmakeFlags +configureFlags +depsBuildBuild +depsBuildBuildPropagated +depsBuildTarget +depsBuildTargetPropagated +depsHostHost +depsHostHostPropagated +depsTargetTarget +depsTargetTargetPropagated +doCheck +doInstallCheck +dontAddDisableDepTrack +mesonFlags +name +nativeBuildInputs +out +outputs +patches +phases +preferLocalBuild +propagatedBuildInputs +propagatedNativeBuildInputs +shell +shellHook +stdenv +strictDeps +system ~PATH ~XDG_DATA_DIRS

To set this up only requires a small file in //.envrc:

use flake || use nix

dotenv_if_exists

PATH_add node_modules/.bin # NPM
PATH_add .local/bin