mkDevShell, mkDocsShell, and mkDevShells
mkDevShell builds one development shell. mkDocsShell builds a dedicated docs/tooling shell with the same base toolchain wiring but with Windows and macOS cross environment variables disabled by default. mkDevShells builds the default four-shell layout used by most downstream workspaces. All generated shells include cargo-sweep and the shared native build tools before project-specific packages are appended.
mkDevShell
Use mkDevShell when you want a single environment with precise control over Windows and macOS helpers.
Important parameters:
pkgscraneLibcrossenableWindowsEnvenableOsxcrossEnvpkgConfigDepspackagesextraEnvextraShellHookcheckscargoConfig: optional override; defaults to the configuration attached bymkToolchain
mkProjectCliShellTools
Use mkProjectCliShellTools when a project wants its flake-built CLI available in direnv or nix develop:
projectCli = harbor-rs.lib.mkProjectCliShellTools {
inherit pkgs;
package = self'.packages.my-cli;
commandName = "my-cli";
hint = "my-cli dev shell - run `my-cli --help`";
versionCheck.expected = version;
};
Append projectCli.packages to the shell packages and projectCli.shellHook to the shell hook. The hook fails if command -v resolves to a different binary than the package output, which prevents stale tools earlier on PATH from shadowing the current flake build.
mkDevShells
mkDevShells wraps mkDevShell and returns:
defaultwindowsmacoscross
That layout works well for workspaces where some crates only need native tools while others need MinGW or osxcross.
mkDocsShell
Use mkDocsShell for CI and local workflows that only need mdBook documentation:
nix develop .#docs -c cargo doc --no-deps --all-featuresnix develop .#docs -c mdbook serve docs
The Plinth-powered project site is intentionally isolated from the reusable
harbor-rs flake so consumers cannot create a dependency cycle. Run its
dedicated nested flake when needed:
nix develop ./site#docs
nix build ./site#site
Example
devShells =
(harbor-rs.lib.mkDevShells {
inherit pkgs cross;
inherit (toolchain) craneLib;
packages = with pkgs; [ just vulkan-loader ];
pkgConfigDeps = with pkgs; [ wayland libxkbcommon udev alsa-lib ];
extraEnv = {
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.vulkan-loader ];
};
extraShellHook = ''
echo "Welcome to my project!"
'';
};
})
// {
docs = harbor-rs.lib.mkDocsShell {
inherit pkgs cross;
inherit (toolchain) craneLib;
packages = with pkgs; [ mdbook ];
};
};
The shell installs the selected configuration in a hash-specific directory
under the user cache and uses it as CARGO_HOME only when the caller has not
already selected one. Pass cargoConfig explicitly only to override the
configuration attached to craneLib by mkToolchain. Prefer
toolchain.cargoConfig over reconstructing the same file with mkCargoConfig.
Activation
Harbor produces shell packages, environment variables, and hooks. It does not activate a repository. Each project chooses its toolchain and direnv policy.
This .envrc pattern requires nix-direnv. Register source watches before
use flake. Disable stale-cache fallback so a failed rebuild is not reported
as success. Do not update lockfiles from direnv.
watch_file flake.nix flake.lock
nix_direnv_disallow_fallback
use flake . --no-update-lock-file || return 1
A nested checkout that must not inherit a parent Harbor shell needs its own
.envrc: either use flake . for that project, or a no-op file such as
true. An absent .envrc inherits the parent.
Harbor’s Cargo hook:
- installs generated config only into Harbor’s hashed cache directory
- leaves an existing
CARGO_HOMEunchanged and reports that generated config is not activated - fails the shell when that install cannot complete
checks.mkDevShells-cargo-home covers repeated, concurrent, user-owned, and
failed-install cases. lib.devShellTests.mkCheck covers executable
availability. Real direnv transitions remain a consumer check.