Neovim + tmux + Claude Code. Solarized dark. Portable.
The notes command creates a tmux session with two windows:
| Window | Name | Contents |
|---|---|---|
| 0 | edit | Neovim, opened in ~/notes. Use keybindings to toggle the file tree and fuzzy search. |
| 1 | claude | Claude Code CLI — full terminal session. |
Switch windows with C-a 0 / C-a 1 (your tmux prefix is Ctrl+a).
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
Leader key is Space. All bindings in normal mode.
| Key | Action |
|---|---|
| Space e | Toggle file tree (current directory) |
| Space E | Toggle file tree rooted at ~/notes |
| Space f | Fuzzy find files in current directory |
| Space F | Fuzzy find files in ~/notes |
| Space g | Live grep (search file contents) |
| Space n | File browser in ~/notes — press c to create a new note |
| Space a | Toggle Claude Code panel (in-editor) |
| Space x | Save file |
| Space ev | Edit nvim settings (settings.lua) |
| Space sv | Reload nvim settings |
| Space li | Toggle invisible characters |
| jj | Exit insert mode (insert mode only) |
Space n — opens the file browser in ~/notesc — prompts for a filenameOr from fuzzy search: Space F, type a name that doesn't match anything, then Space n to create it.
| Key | Action |
|---|---|
| Ctrl+j / Ctrl+k | Move selection down / up |
| Enter | Open selected file |
| Esc | Close telescope |
| Ctrl+q | Send selection to quickfix list |
| Key | Action |
|---|---|
| c | Create new file |
| r | Rename file |
| d | Delete file |
# 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
sudo add-apt-repository ppa:neovim-ppa/unstable && sudo apt install neovimnpm install -g @anthropic-ai/claude-code
# then authenticate:
claude
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.
nvim
# lazy.nvim will bootstrap itself and install all plugins automatically.
# Wait for it to finish (~30s on first run), then restart nvim.
:TSUpdate inside nvim.notes # should create the tmux session and open nvim
-- 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")
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,
})
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 },
},
})
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")
#!/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"
#!/usr/bin/env bash
if [ -z "$TMUX" ]; then
printf '{"systemMessage":"WARNING: Not in a tmux session. Run: tmux attach -t vim"}'
fi
{
"autoMemoryDirectory": "~/.claude/memory",
"hooks": {
"SessionStart": [{
"hooks": [
{ "type": "command", "command": "<passdown command>",
"statusMessage": "Reading passdown..." },
{ "type": "command", "command": "~/.claude/hooks/check-tmux.sh" }
]
}]
}
}
| Problem | Fix |
|---|---|
| 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. |