Terminal development environment
The Keystone terminal module (keystone.terminal) provides an opinionated, batteries-included command-line development environment. It delivers a consistent experience across NixOS systems, macOS, and other Linux distributions via Home Manager, ensuring that the same tools and configuration are available regardless of where development occurs.
Enabling the module
The terminal environment is enabled per-user through the keystone.os.users option. When a user has terminal.enable = true, the module installs and configures the full terminal toolchain automatically.
keystone.os.users.alice = {
fullName = "Alice Smith";
email = "alice@example.com";
terminal.enable = true;
};For standalone Home Manager usage outside of Keystone OS, the module can be imported directly:
{
inputs = {
keystone.url = "github:ncrmro/keystone";
home-manager.url = "github:nix-community/home-manager";
};
outputs = { keystone, home-manager, nixpkgs, ... }: {
homeConfigurations."alice" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
modules = [
keystone.homeModules.terminal
{
home.username = "alice";
home.homeDirectory = "/home/alice";
home.stateVersion = "25.05";
keystone.terminal = {
enable = true;
git.userName = "Alice Smith";
git.userEmail = "alice@example.com";
};
}
];
};
};
}Design philosophy
The terminal module embraces a TUI-first development philosophy. Terminal user interface tools provide a consistent, efficient environment that works identically whether one is on a local machine or connected to a remote server.
- Consistency: The same tools behave the same way everywhere -- on a laptop, a server, a VM, or a container.
- Efficiency: Keyboard-driven workflows are faster once mastered. There is no context switching between mouse and keyboard.
- Low bandwidth: TUI applications transmit text, not pixels, enabling effective work over slow or intermittent connections.
- Resumable sessions: With Zellij, the entire workspace persists across disconnections. One can detach and reattach without losing state.
- Reproducibility: Nix manages the entire environment declaratively. A new machine receives the same setup in minutes.
Included tools
The following tools are installed and configured when the terminal module is enabled:
| Tool | Purpose |
| :------------------- | :------------------------------------------------------------- |
| Helix | Modal text editor with built-in LSP support |
| Zsh | Interactive shell with autosuggestions and syntax highlighting |
| Starship | Minimal, fast cross-shell prompt |
| Zellij | Terminal multiplexer with session persistence |
| Git | Version control with LFS and sensible defaults |
| Lazygit | Terminal UI for Git operations |
| Ghostty terminfo | Proper terminal handling for SSH connections from Ghostty |
| eza | Modern replacement for ls with color and Git integration |
| ripgrep | Fast recursive content search |
| yazi | Keyboard-driven terminal file manager |
| zoxide | Smart directory navigation that learns usage patterns |
| direnv | Per-directory environment variable management |
| htop | Interactive process viewer |
| zesh | Zellij session manager with zoxide integration |
Helix editor
Keystone configures Helix as the default editor. The EDITOR and VISUAL environment variables are set to hx.
Editor settings
The module applies the following defaults:
- Theme:
kinda_nvim(when the theme input is available; otherwise the Helix default). - Line numbers: Absolute.
- Soft wrap: Enabled with a text width of 120 columns.
- Clipboard: Wayland provider.
- Cursor shapes: Block in normal mode, bar in insert mode, underline in select mode.
Keybindings
| Key | Action |
| :--------------------- | :-------------------------------------------------------------------- |
| Return (normal mode) | Save the current buffer (:write) |
| F6 | Preview the current buffer as rendered Markdown in the system browser |
| F7 | Toggle soft wrapping |
The Markdown preview feature (F6) pipes the full buffer content through Pandoc, renders it to HTML, opens the result in the default browser via xdg-open, and copies the file URL to the clipboard for convenience.
Language servers
The module installs and configures language servers for the following languages:
| Language | Server(s) |
| :------------- | :------------------------------------------------------------- |
| Markdown | marksman, harper-ls (grammar checking) |
| Nix | nixfmt (auto-format on save) |
| Bash | bash-language-server |
| TypeScript | typescript-language-server, prettier (auto-format on save) |
| Dockerfile | dockerfile-language-server |
| Docker Compose | docker-compose-language-service, yaml-language-server |
| YAML | yaml-language-server |
| JSON | vscode-json-language-server |
| CSS | vscode-css-language-server |
| HTML | vscode-html-language-server |
| Helm | helm-ls |
| Ruby | ruby-lsp, solargraph |
The harper-ls grammar checker is additionally attached to many languages including Go, Python, Rust, Java, C, C++, and others, providing inline prose linting across the codebase.
Zsh shell
Zsh is configured with Oh My Zsh using the robbyrussell theme, along with the git and colored-man-pages plugins. The following features are enabled by default:
- Autosuggestion: Suggests commands from history as one types.
- Syntax highlighting: Colors valid and invalid commands in real time.
- Completion: Tab completion for commands, paths, and arguments.
- History: Retains up to 100,000 entries.
Shell aliases
| Alias | Expansion | Description |
| :-------- | :------------------------- | :------------------------------------------------ |
| ls, l | eza -1l | Modern ls replacement with color and Git status |
| grep | rg | Ripgrep for fast content search |
| g | git | Shortened Git invocation |
| lg | lazygit | Launch the Lazygit TUI |
| ztab | zellij action rename-tab | Rename the current Zellij tab |
| zs | zesh connect | Zellij session manager with zoxide integration |
| y | yazi | Launch the yazi file manager |
Starship prompt
Starship provides a minimal, informative prompt that displays Git branch and status, active language versions, command execution time, and other contextual information without configuration overhead.
Zoxide
Zoxide replaces cd with a smarter alternative that tracks frequently visited directories. After navigating to a directory once, subsequent visits require only a partial match:
z proj # Jumps to ~/code/projects if that is the most-visited match
zi # Interactive fuzzy selection of tracked directoriesDirenv
Direnv automatically loads and unloads environment variables based on the current directory. With nix-direnv integration enabled, it provides seamless Nix dev shell activation when entering a project directory containing a flake.nix or .envrc.
Zellij terminal multiplexer
Zellij manages terminal sessions, panes, and tabs. It is configured with the following defaults:
- Theme: Inherits the current system theme.
- Pane frames: Disabled for a cleaner appearance.
- Startup tips: Disabled.
Keybindings
The module customizes Zellij keybindings to avoid conflicts with common development tools (such as Claude Code and Lazygit):
| Key | Action |
| :-------------------------------- | :----------------------------------------------- |
| Ctrl+T | Create a new tab |
| Ctrl+W | Close the current tab |
| Ctrl+PageUp or Ctrl+Shift+Tab | Switch to previous tab |
| Ctrl+PageDown or Ctrl+Tab | Switch to next tab |
| Ctrl+Shift+G | Enter lock mode (default Ctrl+G is unbound) |
| Ctrl+Shift+O | Enter session mode (default Ctrl+O is unbound) |
Session management
Zellij sessions persist across disconnections. Common session operations:
zellij # Start a new session
zellij -s myproject # Start a named session
zellij attach myproject # Reattach to an existing session
zellij list-sessions # List all active sessions
zesh connect # Use zesh for session management with zoxide integrationGhostty terminal emulator
When the desktop module is enabled, Ghostty is configured as the default terminal emulator. The terminal module installs Ghostty terminfo data so that SSH connections from Ghostty-based terminals are handled correctly on remote machines. Without this, remote systems would not recognize TERM="xterm-ghostty" and ncurses applications would fail.
Git configuration
Git is enabled by default when the terminal module is active. The git.userName and git.userEmail options are required and are automatically populated from the user's fullName and email fields when configured through keystone.os.users.
Defaults
- LFS: Enabled.
- Default branch:
main. - Auto setup remote: Enabled (
push.autoSetupRemote = true).
Aliases
| Alias | Command |
| :---- | :----------- |
| s | switch |
| f | fetch |
| p | pull |
| b | branch |
| st | status -sb |
| co | checkout |
| c | commit |
Lazygit is also installed and available via the lg shell alias for a full terminal UI over Git operations.
Module options reference
The terminal module exposes the following options under keystone.terminal:
| Option | Type | Default | Description |
| :-------------- | :------ | :------- | :------------------------------------------------ |
| enable | boolean | false | Enable the terminal development environment |
| editor | string | "hx" | Default editor command (EDITOR and VISUAL) |
| devTools | boolean | false | Install additional development tools (csview, jq) |
| git.enable | boolean | true | Enable Git with Keystone defaults |
| git.userName | string | required | Full name for Git commits |
| git.userEmail | string | required | Email address for Git commits |
See also
- User management -- enabling the terminal module per user via
keystone.os.users - Desktop environment -- the Hyprland desktop that builds on top of the terminal module
- Remote development -- using the terminal tools over SSH with session resumption
- Architecture -- how the terminal module fits into the Keystone module system