flk global
Manage a machine-wide (“global”) environment for always-on developer tools like ripgrep, fd, or bat — inspired by Devbox’s global mode. Instead of nix profile install or a system package manager, your daily toolchain lives in one declarative, reproducible flk environment.
The global environment is a regular flk project (slim layout) stored outside any repository. Every flk global subcommand operates on that directory instead of the current one, and otherwise behaves exactly like its project-scoped counterpart.
Location
The global directory is resolved in this order:
FLK_GLOBAL_DIRenvironment variable (override for scripts and tests)$XDG_CONFIG_HOME/flk/global~/.config/flk/global
The directory is created and initialized automatically (generic template) the first time you run any flk global subcommand.
Subcommands
flk global add
Add a package to the global environment.
flk global add ripgrep
flk global add fd --version 10.2.0 # pin a version
flk global add bat --profile cli-tools # target a specific global profile
flk global remove
Remove a package from the global environment.
flk global remove ripgrep
flk global list
List the packages of the global environment.
flk global list
flk global list --profile cli-tools
flk global activate
Enter the global dev shell (same caching behavior as flk activate).
flk global activate
flk global activate --profile cli-tools
The shell opens in the directory you ran the command from, not in the global config directory.
Inside the global shell, the hook’s refresh and switch commands operate on the global environment: the activation exports FLK_ENV_DIR (the global directory) plus FLK_FLAKE_REF/FLK_PROFILE, and the hook functions resolve flake refs, profile caches, and freshness checks against that directory. So flk global add jq followed by refresh picks up the new package without leaving the shell, and switch cli-tools swaps between global profiles — even while your cwd is inside some project.
From a project shell, refresh -g / switch -g <profile> jump to the global environment, and switch -l <profile> jumps back to the cwd project — the new shell always supersedes the current one, shells never stack.
flk global update
Update global packages to the latest version (same behavior as flk update, including automatic lock backups).
flk global update
flk global update --show
flk global path
Print the resolved global environment directory. This is the only subcommand with no side effects — it never creates or initializes the directory.
flk global path
# /home/you/.config/flk/global
Useful for scripting:
nix develop "$(flk global path)#generic"
flk global ref
Print the global flake reference (<dir>#<profile>) — plumbing for the shell hook’s refresh -g/switch -g. Prints nothing but the reference (no banners) and fails if the global environment has not been initialized yet.
flk global ref
# /home/you/.config/flk/global#generic
flk global ref --profile cli-tools
flk global profile
Manage profiles inside the global environment — identical to flk profile, but scoped to the global directory.
flk global profile add cli-tools
flk global profile list
flk global profile set-default cli-tools
flk global profile remove cli-tools
flk global unfree
Manage the global environment’s unfree allow-list — identical to flk unfree, but scoped to the global directory.
flk global unfree add slack # default global profile
flk global unfree add slack -p cli-tools # a specific global profile
flk global unfree add slack --all # every global profile
flk global unfree list
flk global unfree remove slack
flk global shellenv
Print shell code that appends the global environment’s store paths to PATH — Devbox-style ambient integration. Eval it in your rc file and your global tools are available in every shell, including inside project (flk activate) shells:
# .bashrc / .zshrc
eval "$(flk global shellenv zsh)" # or bash
# ~/.config/fish/config.fish
flk global shellenv fish | source
Properties:
- Packages only, never the build toolchain: only the environment’s own packages and their propagated binaries are exported. The stdenv toolchain that
nix developputs onPATH—gcc,binutils,glibc’s tools,make,patch,tar— is filtered out. It would otherwise answer for a missing systemccormakein every shell on the machine, which is not something an rc-file one-liner should be able to do. - Appended, not prepended: system tools and project-shell packages always win; global packages only fill the gaps.
- Idempotent: appends only when
PATHdoesn’t already contain the entry set, so nested shells and re-sourced rc files don’t growPATH— whileexec zshafter a rebuild still picks up new packages. - Fast and offline: reads the profile’s GC root via
nix print-dev-env(no flake evaluation). - rc-safe: degrades to a comment when the global environment isn’t initialized or built yet — run
flk global activateonce to build it. It also degrades to a comment, rather than exporting an unfilteredPATH, if it can’t tell the environment’s packages from the toolchain. - The snippet reflects the environment at eval time: after
flk global add/remove, refresh it with a new shell (orrefresh -ginside a global shell).
Shell startup integration
flk never edits your shell rc files. To make your global tools available:
- Eval
flk global shellenvin your rc file (ambient, Devbox-style), or - Run
flk global activatewhenever you want the full global shell, or - Add an alias yourself, e.g.:
alias gsh='flk global activate'
Behavior notes
- The global environment is fully independent of any project: a project shell’s
FLK_FLAKE_REFis ignored during global profile resolution. - All state (flake.nix,
.flk/, lock backups, activation cache) lives inside the global directory — nothing is written to your current working directory. - Version pins,
flake.lockbackups, and profiles work exactly as in a project.