My Terminal

August 26, 2026 ยท View on GitHub

The applied terminal varies by the host OS:

Additionally, the ๐Ÿงฉ Extra setup covers what I run on top of the terminal itself: Nerd Fonts, herdr (agent multiplexer) and NeoVim (text editor).

This repo only does not list my IDE: VS Code settings.

๐ŸŽ Warp

Warp - my main terminal for macOS.

๐ŸŽจ Appearance

Warp
  • Theme: Fancy Dracula
  • Prompt: Shell prompt (PS1)
  • Font: JetBrainsMono Nerd Font Mono 12 (see ๐Ÿ”ฃ Nerd Fonts)

โš™๏ธ Zsh settings

  • Framework: Oh My Zsh
  • Prompt: Starship
    • If you have installed conda, I suggest to disable printing environment names, as they will be displayed already by Starship: conda config --set changeps1 False

Plugins

Oh My Zsh plugins:

External plugins:

Shell aliases

Note


Since 2024/01/07, I keep my core text-expansion config in my-espanso-config.

I recommend keeping aliases in the ~/.aliases file, and then source this file in your respective profile file through source ~/.aliases. Keep in mind that a bunch of aliases is already configured through the aforementioned Oh My Zsh plugins, which you can quickly check using the aliases plugin.

general:

  • alias aliases='code ~/.aliases' โ† quickly open ~/.aliases in VS Code
  • alias lisl='eza -hla --icons' โ† better ls with eza
  • alias list='eza -hlas time --icons' โ† better ls with eza (ordered by time)
  • alias treee='br -c :pt' โ† better tree with broot
  • alias path='echo -e ${PATH//:/\\n}' โ† show all directories in the PATH variable, one per line
  • alias ports='netstat -a | grep -i "listen"' โ† show all open ports and the processes using them
  • alias reload='source ~/.zshrc' โ† reload the configuration file for zsh
  • alias zshrc='code ~/.zshrc' โ† quickly open ~/.zshrc in VS Code

kubernetes:

  • alias k8s-get-pods='kubectl get pods --all-namespaces' โ† get the list of all pods
  • alias k8s-get-services='kubectl get services --all-namespaces' โ† get the list of all services

macOS:

  • alias cleanup="find . -type f -name '*.DS_Store' -ls -delete" โ† find and delete all .DS_Store files in the current directory and all subdirectories

functions:

  • check if a website is up or down:

    function website-status(){
      curl -Is "\$1" | head -n 1
    }
    
  • open finder in the current folder:

    function openfinder(){
        open -a Finder "\$1";
    }
    

Shell tools

You can find a list of my recommended shell tools in my other repo.

๐ŸŽ iTerm2

iTerm2 - my alternative terminal for macOS.

๐ŸŽจ Appearance

iTerm2

โœจ Extras

Extra iTerm2 configuration:

  1. Jump between words with โŒฅ + โ†/โ†’
    • Settings > Profiles > Keys > Key Mappings > +
      • Keyboard shortcut: โŒฅ โ†, Action: Send Escape Sequence, Esc+: b
      • Keyboard shortcut: โŒฅ โ†’, Action: Send Escape Sequence, Esc+: f
  2. Delete words with โŒฅ + BACKSPACE
    • Settings > Profiles > Keys > General
      • Left and Right option keys: change from Normal to Esc+

๐Ÿ–ฅ Windows Terminal

Windows Terminal - my main terminal for Windows.

๐ŸŽจ Appearance

Windows Terminal

โš™๏ธ Profiles

Command Prompt

Git Bash

Install Git Bash from here.

Add profile to Windows Terminal:

  • Name: Git Bash
  • Command line: %PROGRAMFILES%/Git/bin/bash.exe -i -l
  • Starting directory: %USERPROFILE%
  • Icon: %PROGRAMFILES%/Git/mingw64/share/git/git-for-windows.ico

Extras:

  • Prompt: Starship
  • To be able to activate conda environments, you may also need to set a system variable: PYTHONIOENCODING=utf8

.bash_profile:

# Set Starship theme
eval "$(starship init bash)"

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
eval "$('/c/Users/pawel/miniconda3/Scripts/conda.exe' 'shell.bash' 'hook')"
# <<< conda initialize <<<

PowerShell 7

I am using PowerShell 7 in addition to the native Windows PowerShell 5.

Extras:

$PROFILE:

# Set Starship
Invoke-Expression (&starship init powershell)

# Show navigable menu of all options when hitting Tab
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete

# Autocompletion for arrow keys
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward

WSL - Ubuntu 22.04 (LTS)

Install Ubuntu:

  1. Set a default version of WSL: wsl --set-default-version 2.
  2. Install Ubuntu 22.04 LTS.

Setup the environment:

  1. Start with sudo apt update and sudo apt upgrade.
  2. Install Zsh, Oh My Zsh and Starship.
  3. Copy the โš™๏ธ Zsh settings.

Extras:

  • Disable beep sound in Windows Terminal settings for the Ubuntu Profile (Advanced > Bell notification style)
  • If you have installed conda, I suggest to disable printing environment names, as they will be displayed already by Starship: conda config --set changeps1 False.

๐Ÿค– Termux

Termux - my main terminal for Android installed from F-Droid.

๐ŸŽจ Appearance

Termux

UI modified with Termux:Styling (obtained from F-Droid):

  • Theme: Dracula
  • Font: FiraCode (JetBrains Mono does not support icons of eza --icons)
  • Keyboard: Gboard

โš™๏ธ Setup

  1. Install F-Droid, and use it to install Termux with Termux:Styling.
  2. Open up Termux and start with apt update and apt upgrade.
  3. Install extra packages: pkg install git, pkg install python and pkg install vim.
  4. Install Zsh (pkg install zsh), Oh My Zsh and Starship (pkg install starship).
  5. Copy the โš™๏ธ Zsh settings.
  6. Optionally, install further tools such as Tool-X.

๐Ÿงฉ Extra setup

Layers that sit on top of whichever terminal I am in, so they are OS agnostic.

๐Ÿ”ฃ Nerd Fonts

Every terminal here uses JetBrainsMono Nerd Font Mono, which is JetBrains Mono patched by Nerd Fonts. The unpatched font carries no icon glyphs.

It has to be v3 or newer. v3 moved the Material Design icons to U+F0000+, which is where current tools look for them: Neovim's file explorer, eza --icons, yazi, lazygit.

brew install --cask font-jetbrains-mono-nerd-font

Warning

Remove any v2 build you installed earlier, rather than leaving both. v2 files are named ... Nerd Font Complete ....ttf and declare the same family name as v3, so macOS may keep resolving to the old one and the new glyphs never appear:

ls ~/Library/Fonts | grep Complete

Move those out of ~/Library/Fonts, then fully quit and reopen the terminal. Warp is where this bites hardest, since it has no font fallback and draws only what the selected font provides. iTerm2 falls back to another installed font and hides the problem, so check its profile still points at a font that exists.

๐Ÿ‘ herdr

herdr - my agent multiplexer, running inside whichever terminal I am on.

๐ŸŽจ Appearance

herdr
  • Theme: dracula
  • Font: inherited from the host terminal, so JetBrainsMono Nerd Font Mono everywhere

โš™๏ธ Setup

  1. Install herdr:

    # macOS / Linux
    brew install herdr
    
    # or, without Homebrew
    curl -fsSL https://herdr.dev/install.sh | sh
    

    On Windows: irm https://herdr.dev/install.ps1 | iex.

  2. Run herdr to create or attach to the persistent session. CTRL + B is the prefix key, so CTRL + B then ? lists every binding, and CTRL + B then Q detaches while leaving the agents running. Use herdr --session <name> for a second isolated session, and herdr --remote <ssh-target> to attach to a server running on another machine.

  3. Apply the Dracula theme in ~/.config/herdr/config.toml:

    [theme]
    name = "dracula"
    
  4. Install the plugins I use:

    # git-aware, read-only file browser in a split pane
    herdr plugin install smarzban/herdr-file-viewer
    
    # review agent-written diffs in a sidebar and send line comments back to the agent
    herdr plugin install persiyanov/herdr-reviewr
    

    Both are bound in ~/.config/herdr/config.toml:

    [[keys.command]]
    key = "prefix+f"
    type = "plugin_action"
    command = "herdr-file-viewer.open-file-viewer"
    description = "open file viewer in split"
    
    [[keys.command]]
    key = "prefix+shift+f"
    type = "plugin_action"
    command = "herdr-file-viewer.open-file-viewer-tab"
    description = "open file viewer in tab"
    
    [[keys.command]]
    key = "prefix+d"
    type = "plugin_action"
    command = "persiyanov.reviewr.toggle"
    description = "toggle reviewr diff pane"
    

    Config changes are picked up with herdr server reload-config, or CTRL + B then SHIFT + R.

    reviewr keeps its own config in ~/.config/herdr/plugins/config/persiyanov.reviewr/config.toml, which it re-reads on every refresh:

    theme = "dracula"
    default_scope = "branch"
    

    branch diffs against the merge-base with the default branch, so a review still shows the agent's work once it has been committed. The default uncommitted scope only covers the working tree.

  5. Optionally, wire up the agent CLIs you use: herdr integration install claude. Run herdr integration to see the rest (codex, cursor, copilot, opencode, grok, and more).

  6. Optionally, add Zsh completions:

    mkdir -p ~/.zfunc
    herdr completion zsh > ~/.zfunc/_herdr
    

    Then add fpath=(~/.zfunc $fpath) to ~/.zshrc, above the line that sources Oh My Zsh.

๐Ÿง Neovim

Neovim - my main text editor used within the terminal of any OS.

๐ŸŽจ Appearance

Neovim
  • Neovim config: LazyVim
  • Theme: dracula
  • Font: JetBrainsMono Nerd Font Mono 12, and it has to be Nerd Fonts v3 or newer, otherwise the file explorer renders without icons

This setup used to be NvChad with the chadracula theme. I moved to LazyVim because its config layout has stayed stable for years, while NvChad has gone through breaking restructures (v1 โ†’ v2 โ†’ v2.5) that each required rewriting the config from scratch.

โš™๏ธ Setup

  1. Make sure you have set up the local terminal of your OS (ideally as in this repo).

  2. Install Neovim 0.11 or newer (nvim --version).

  3. Back up any existing config and install the LazyVim starter:

    mv ~/.config/nvim{,.bak}
    mv ~/.local/share/nvim{,.bak}
    mv ~/.local/state/nvim{,.bak}
    mv ~/.cache/nvim{,.bak}
    
    git clone https://github.com/LazyVim/starter ~/.config/nvim
    rm -rf ~/.config/nvim/.git
    rm -f ~/.config/nvim/lua/plugins/example.lua
    
  4. Enable the language support I use, by adding these imports to the spec table in ~/.config/nvim/lua/config/lazy.lua:

    { import = "lazyvim.plugins.extras.lang.typescript" },
    { import = "lazyvim.plugins.extras.lang.json" },
    { import = "lazyvim.plugins.extras.lang.markdown" },
    { import = "lazyvim.plugins.extras.lang.clangd" },
    { import = "lazyvim.plugins.extras.formatting.prettier" },
    

    In the same file, set the fallback colourscheme so the first launch does not flash Tokyo Night:

    install = { colorscheme = { "dracula", "habamax" } },
    
  5. Apply the Dracula theme in ~/.config/nvim/lua/plugins/colorscheme.lua:

    return {
      {
        "AndresYague/dracula.nvim",
        lazy = false,
        priority = 1000,
        opts = {
          style = "default", -- "default" | "soft" | "day"
          styles = {
            comments = { italic = true },
          },
        },
      },
      {
        "LazyVim/LazyVim",
        opts = { colorscheme = "dracula" },
      },
    }
    
  6. Add the HTML/CSS language servers in ~/.config/nvim/lua/plugins/lsp.lua (Lua, TypeScript, C and the formatters already come from step 4):

    return {
      {
        "neovim/nvim-lspconfig",
        opts = { servers = { html = {}, cssls = {} } },
      },
      {
        "nvim-treesitter/nvim-treesitter",
        opts = { ensure_installed = { "css" } },
      },
      {
        "mason-org/mason.nvim",
        opts = { ensure_installed = { "html-lsp", "css-lsp" } },
      },
    }
    
  7. Add jk as an escape shortcut in ~/.config/nvim/lua/plugins/editor.lua:

    return {
      {
        "max397574/better-escape.nvim",
        event = "InsertEnter",
        opts = {},
      },
    }
    
  8. Add diffview.nvim in ~/.config/nvim/lua/plugins/git.lua. LazyVim's gitsigns already covers single-file hunks, while this gives a file panel and a side-by-side view over a whole changeset, which is how I review what a coding agent wrote:

    return {
      {
        "sindrets/diffview.nvim",
        cmd = { "DiffviewOpen", "DiffviewClose", "DiffviewFileHistory", "DiffviewToggleFiles" },
        keys = {
          { "<leader>gv", "<cmd>DiffviewOpen<cr>", desc = "Diffview (working tree)" },
          { "<leader>gV", "<cmd>DiffviewFileHistory %<cr>", desc = "Diffview (file history)" },
          {
            -- Everything on this branch, committed work included. The working-tree
            -- view above goes blank once an agent has committed its changes.
            "<leader>gm",
            function()
              local base = vim.trim(vim.fn.system("git symbolic-ref --quiet --short refs/remotes/origin/HEAD"))
              if vim.v.shell_error ~= 0 or base == "" then
                base = "origin/main"
              end
              vim.cmd("DiffviewOpen " .. base .. "...HEAD")
            end,
            desc = "Diffview (vs base branch)",
          },
        },
        opts = {
          enhanced_diff_hl = true,
          view = {
            -- 3-way merge conflicts are easier to read with the base shown.
            merge_tool = { layout = "diff3_mixed" },
          },
          keymaps = {
            view = { { "n", "q", "<cmd>DiffviewClose<cr>", { desc = "Close Diffview" } } },
            file_panel = { { "n", "q", "<cmd>DiffviewClose<cr>", { desc = "Close Diffview" } } },
            file_history_panel = { { "n", "q", "<cmd>DiffviewClose<cr>", { desc = "Close Diffview" } } },
          },
        },
      },
    }
    

    q closes any of the panels. Note that :DiffviewOpen <rev> with a single revision compares the working tree against that revision, so a branch passed on its own shows its additions as removals. The base...branch range is the one that matches what a merge request displays.

  9. Optionally, if you use GitLab, add a :MR <id> command at the top of that same git.lua, above the return. It asks glab for the merge request's branches, fetches them, and opens the range in the right order, so reviewing an MR needs no checkout and no typing out refs:

    vim.api.nvim_create_user_command("MR", function(opts)
      local id = opts.args
      local raw = vim.fn.system({ "glab", "mr", "view", id, "--output", "json" })
      if vim.v.shell_error ~= 0 then
        return vim.notify("glab failed for MR " .. id .. ":\n" .. raw, vim.log.levels.ERROR)
      end
      local ok, mr = pcall(vim.json.decode, raw)
      if not ok or not mr.source_branch then
        return vim.notify("Could not read branches for MR " .. id, vim.log.levels.ERROR)
      end
      vim.notify(("MR !%s: %s <- %s"):format(id, mr.target_branch, mr.source_branch))
      vim.fn.system({ "git", "fetch", "origin", mr.source_branch, mr.target_branch })
      vim.cmd(("DiffviewOpen origin/%s...origin/%s"):format(mr.target_branch, mr.source_branch))
    end, { nargs = 1, desc = "Diffview for a GitLab merge request" })
    
  10. Reload files that changed outside Neovim, in ~/.config/nvim/lua/config/autocmds.lua. LazyVim only does this on FocusGained, which a herdr pane switch does not always produce, so a file an agent rewrote in another pane can stay stale:

    vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI", "BufEnter" }, {
      group = vim.api.nvim_create_augroup("checktime_on_idle", { clear = true }),
      callback = function()
        if vim.o.buftype == "" and vim.fn.mode() == "n" then
          vim.cmd("silent! checktime")
        end
      end,
    })
    
  11. Append my keybindings to ~/.config/nvim/lua/config/keymaps.lua:

    local map = vim.keymap.set
    
    -- Enter command mode without reaching for Shift
    map("n", ";", ":", { desc = "Enter command mode", nowait = true })
    
    -- CTRL+N opens the file explorer (LazyVim ships the snacks explorer, not neo-tree)
    map("n", "<C-n>", function()
      Snacks.explorer({ cwd = LazyVim.root() })
    end, { desc = "Explorer (root dir)" })
    
  12. Start Neovim with nvim. lazy.nvim bootstraps itself and installs everything on the first launch. Use :Lazy to manage plugins, :LazyExtras to browse the other language packs, and :checkhealth to confirm the install.

  13. Optionally, apply Neovim in your IDE, such as in VS Code through the VSCode Neovim extension.