Notes Environment — Setup & Reference

Neovim + tmux + Claude Code. Solarized dark. Portable.

Layout

The notes command creates a tmux session with two windows:

WindowNameContents
0editNeovim, opened in ~/notes. Use keybindings to toggle the file tree and fuzzy search.
1claudeClaude Code CLI — full terminal session.

Switch windows with C-a 0 / C-a 1 (your tmux prefix is Ctrl+a).

Daily Use

Starting a session

notes                  # open ~/notes (creates session or reattaches)
notes ~/some/other/dir # open any directory instead

If you're already in tmux and just want nvim:

nvim

Neovim keybindings

Leader key is Space. All bindings in normal mode.

KeyAction
Space eToggle file tree (current directory)
Space EToggle file tree rooted at ~/notes
Space fFuzzy find files in current directory
Space FFuzzy find files in ~/notes
Space gLive grep (search file contents)
Space nFile browser in ~/notes — press c to create a new note
Space aToggle Claude Code panel (in-editor)
Space xSave file
Space evEdit nvim settings (settings.lua)
Space svReload nvim settings
Space liToggle invisible characters
jjExit insert mode (insert mode only)

Creating a new note

  1. Press Space n — opens the file browser in ~/notes
  2. Press c — prompts for a filename
  3. Type the name and press Enter — file is created and opened

Or from fuzzy search: Space F, type a name that doesn't match anything, then Space n to create it.

Telescope navigation

KeyAction
Ctrl+j / Ctrl+kMove selection down / up
EnterOpen selected file
EscClose telescope
Ctrl+qSend selection to quickfix list

File browser actions (Space n)

KeyAction
cCreate new file
rRename file
dDelete file

Files on Disk

~/.config/nvim/
├── init.lua # plugin manager (lazy.nvim) + plugin list
└── lua/user/
    ├── settings.lua # options, leader key, all keybindings
    ├── neo-tree.lua # file tree sidebar config
    └── telescope.lua # fuzzy finder + file browser config

~/.claude/
├── settings.json # Claude Code hooks (passdown + tmux check)
├── hooks/
│   └── check-tmux.sh # warns if not inside tmux
└── memory/ # persistent memory (all projects)

~/.local/bin/
└── notes # session launcher script

~/notes/ # your notes live here

Installing on a New Server

Step 1 — Install prerequisites

# Debian/Ubuntu
sudo apt update
sudo apt install -y neovim tmux git curl

# Verify versions (nvim >=0.8 required, >=0.10 recommended)
nvim --version
tmux -V
Note: If the distro ships an old nvim, install via AppImage or the official PPA:
sudo add-apt-repository ppa:neovim-ppa/unstable && sudo apt install neovim

Step 2 — Install Claude Code

npm install -g @anthropic-ai/claude-code
# then authenticate:
claude

Step 3 — Copy config files

The fastest approach is to tar the relevant directories from the existing machine and extract on the new one:

# On the source machine — pack everything
tar -czf notes-env.tar.gz \
  ~/.config/nvim \
  ~/.claude/settings.json \
  ~/.claude/hooks \
  ~/.local/bin/notes

# Transfer to new server
scp notes-env.tar.gz user@newserver:~

# On the new server — extract
cd ~
tar -xzf notes-env.tar.gz
chmod +x ~/.claude/hooks/check-tmux.sh ~/.local/bin/notes
mkdir -p ~/notes

Or copy file by file. The full contents are in the sections below.

Step 4 — First nvim launch (auto-installs plugins)

nvim
# lazy.nvim will bootstrap itself and install all plugins automatically.
# Wait for it to finish (~30s on first run), then restart nvim.
Note: Treesitter parsers also compile on first launch. If you see errors, run :TSUpdate inside nvim.

Step 5 — Verify

notes          # should create the tmux session and open nvim

Full File Contents for manual install

~/.config/nvim/init.lua

-- Bootstrap lazy.nvim plugin manager if not installed
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
  vim.fn.system({
    "git", "clone", "--filter=blob:none",
    "https://github.com/folke/lazy.nvim.git",
    "--branch=stable", lazypath,
  })
end
vim.opt.rtp:prepend(lazypath)

require("lazy").setup({
  spec = {
    { "ishan9299/nvim-solarized-lua", lazy = false,
      config = function()
        vim.o.termguicolors = true
        vim.o.background = "dark"
        vim.cmd("colorscheme solarized")
      end },
    { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate",
      config = function()
        require"nvim-treesitter.configs".setup {
          ensure_installed = { "lua", "javascript", "python", "c", "cpp", "bash" },
          highlight = { enable = true },
        }
      end },
    { "greggh/claude-code.nvim",
      dependencies = { "nvim-lua/plenary.nvim" },
      config = function() require("claude-code").setup() end },
    { "nvim-telescope/telescope.nvim",
      dependencies = { "nvim-lua/plenary.nvim",
        "nvim-telescope/telescope-file-browser.nvim",
        "nvim-tree/nvim-web-devicons" },
      config = function() require("user.telescope") end },
    { "nvim-neo-tree/neo-tree.nvim", branch = "v3.x",
      dependencies = { "nvim-lua/plenary.nvim",
        "nvim-tree/nvim-web-devicons", "MunifTanjim/nui.nvim" },
      config = function() require("user.neo-tree") end },
  }
})

require("user.settings")

~/.config/nvim/lua/user/settings.lua

vim.o.number = true
vim.o.relativenumber = true
vim.o.termguicolors = true
vim.o.mouse = "a"
vim.cmd([[syntax on]])

vim.g.mapleader = " "

vim.api.nvim_set_keymap("i", "jj", "<Esc>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("n", "<leader>x", ":w<CR>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("n", "<leader>a", "<cmd>ClaudeCodeToggle<CR>", { noremap = true, silent = true })
vim.api.nvim_set_keymap("n", "<leader>ev", ":e ~/.config/nvim/lua/user/settings.lua<CR>", { noremap = true, silent = true })

vim.keymap.set("n", "<leader>e", "<cmd>Neotree toggle<CR>")
vim.keymap.set("n", "<leader>E", "<cmd>Neotree dir=~/notes toggle<CR>")
vim.keymap.set("n", "<leader>f", "<cmd>Telescope find_files<CR>")
vim.keymap.set("n", "<leader>F", function()
  require("telescope.builtin").find_files({ cwd = vim.fn.expand("~/notes") })
end)
vim.keymap.set("n", "<leader>g", "<cmd>Telescope live_grep<CR>")
vim.keymap.set("n", "<leader>n", function()
  require("telescope").extensions.file_browser.file_browser({ path = vim.fn.expand("~/notes") })
end)

vim.api.nvim_create_autocmd("BufWritePre", {
  pattern = "*",
  callback = function() vim.cmd([[ %s/\s\+$//e ]]) end,
})

~/.config/nvim/lua/user/neo-tree.lua

require("neo-tree").setup({
  close_if_last_window = false,
  window = { position = "left", width = 32,
    mappings = { ["<space>"] = "none" } },
  filesystem = {
    follow_current_file = { enabled = true },
    use_libuv_file_watcher = true,
    filtered_items = { hide_dotfiles = false, hide_gitignored = true },
  },
})

~/.config/nvim/lua/user/telescope.lua

local telescope = require("telescope")
local actions = require("telescope.actions")
local fb_actions = require("telescope").extensions.file_browser.actions

telescope.setup({
  defaults = {
    prompt_prefix = " ",
    path_display = { "truncate" },
    mappings = { i = {
      ["<C-j>"] = actions.move_selection_next,
      ["<C-k>"] = actions.move_selection_previous,
      ["<esc>"] = actions.close,
    }},
  },
  extensions = {
    file_browser = {
      create_from_prompt = true, hijack_netrw = true,
      grouped = true, initial_mode = "normal",
      mappings = { n = {
        ["c"] = fb_actions.create,
        ["r"] = fb_actions.rename,
        ["d"] = fb_actions.remove,
      }},
    },
  },
})
telescope.load_extension("file_browser")

~/.local/bin/notes

#!/usr/bin/env bash
NOTES_DIR="${1:-$HOME/notes}"
SESSION="notes"
mkdir -p "$NOTES_DIR"

if tmux has-session -t "$SESSION" 2>/dev/null; then
  exec tmux attach-session -t "$SESSION"
fi

tmux new-session -d -s "$SESSION" -c "$NOTES_DIR"
tmux rename-window -t "$SESSION:0" "edit"
tmux send-keys -t "$SESSION:0" "nvim" Enter
tmux new-window -t "$SESSION:1" -n "claude" -c "$NOTES_DIR"
tmux send-keys -t "$SESSION:1" "claude" Enter
tmux select-window -t "$SESSION:0"
exec tmux attach-session -t "$SESSION"

~/.claude/hooks/check-tmux.sh

#!/usr/bin/env bash
if [ -z "$TMUX" ]; then
  printf '{"systemMessage":"WARNING: Not in a tmux session. Run: tmux attach -t vim"}'
fi

~/.claude/settings.json (relevant section)

{
  "autoMemoryDirectory": "~/.claude/memory",
  "hooks": {
    "SessionStart": [{
      "hooks": [
        { "type": "command", "command": "<passdown command>",
          "statusMessage": "Reading passdown..." },
        { "type": "command", "command": "~/.claude/hooks/check-tmux.sh" }
      ]
    }]
  }
}

Troubleshooting

ProblemFix
Plugins not loading on first launch Wait for lazy.nvim to finish, then restart nvim. Run :Lazy to check status.
Telescope or neo-tree errors :Lazy sync inside nvim to force reinstall all plugins.
No icons / boxes showing instead of icons Install a Nerd Font and set it in your terminal. Recommended: JetBrainsMono Nerd Font.
Colors look wrong Terminal must support 24-bit color. Check with echo $COLORTERM — should show truecolor.
notes command not found Check ~/.local/bin is in your $PATH. Add export PATH="$HOME/.local/bin:$PATH" to ~/.zshrc.
Claude Code hook not firing Open /hooks in Claude Code UI to reload config, or restart the session.