nvim plugin to view file edits live, along with .fish command to spawn a tmux claude / nvim window
  • Shell 51%
  • Lua 49%
Find a file
EvilEKo b9caedbfeb Initial commit: claude-nvim + tclaude fish helper
Live tmux/nvim mirror of Claude Code file activity, plus the fish
function to launch claude+nvim side by side with tracking enabled.
2026-07-09 15:31:21 -04:00
fish Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
hook Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
lua/claude-nvim Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
plugin Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
test Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
.luarc.json Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00
README.md Initial commit: claude-nvim + tclaude fish helper 2026-07-09 15:31:21 -04:00

claude-nvim

Run Claude Code in one tmux pane and nvim in the other, and nvim just follows along. Files it reads pop open at the line it read. Files it edits reload with the changed lines lit up. No more alt-tabbing to check what it just did to your code.

Off by default — a plain nvim never opens a socket. You turn it on per-session with tclaude (below) or :ClaudeWatch enable.

How it works

A PostToolUse hook fires on every Read/Edit/Write/MultiEdit/NotebookEdit, ships a small JSON event over a unix socket to nvim, and nvim jumps/highlights accordingly. That's it, no polling, no LSP, no daemon besides nvim itself.

Install

Plugin (lazy.nvim):

{
  dir = "~/projects/nvim-plugins/claude-nvim", -- or wherever you clone this
  lazy = false, -- the socket has to start with nvim, can't be lazy-loaded
  opts = {},
}

Then from inside nvim, once:

:ClaudeWatch install

That patches a PostToolUse hook into ~/.claude/settings.json pointing at hook/claude-nvim-hook.sh. Needs jq. Restart any running claude session after.

tclaude (fish function, optional but recommended): copy fish/tclaude.fish into ~/.config/fish/functions/. It's autoloaded, no source needed.

cp fish/tclaude.fish ~/.config/fish/functions/tclaude.fish

Using it

tclaude is the easy path — run it from any project dir and it opens a tmux split with claude on the left and nvim on the right, tracking already turned on:

tclaude          # just claude + nvim
tclaude -r       # forwards flags straight to claude, e.g. resume picker

If you'd rather wire it up yourself:

  • :ClaudeWatch enable / :ClaudeWatch disable — open/close the socket for this nvim instance. The hook is a silent no-op while disabled.
  • <leader>ct or :ClaudeWatch — toggle tracking on/off without tearing down the socket. Flip it off to browse a file in peace; flip it back on and nvim jumps to whatever Claude did most recently.
  • :ClaudeWatch status — disabled / paused / tracking. Also exposed as vim.g.claude_nvim_enabled, vim.g.claude_nvim_tracking, and require("claude-nvim").status() if you want it in a statusline.
  • Setting CLAUDE_NVIM_TRACK=1 before launching nvim auto-enables tracking without touching your config — this is exactly what tclaude does under the hood.

Some behavior worth knowing:

  • Changed lines get ClaudeNvimChanged highlight (linked to DiffText) until the next event replaces it.
  • If you've got unsaved edits in a buffer Claude also touches, nvim won't clobber them — you get a warning instead of a silent overwrite.
  • Images/binaries Claude reads (png, pdf, zip, etc.) are ignored instead of getting shoved into a buffer as garbage.
  • The socket path is keyed off cwd, so run nvim from the same directory Claude Code is running in.

Options

require("claude-nvim").setup({
  keymap = "<leader>ct",        -- set false or "" to skip the toggle keymap
  hl = "ClaudeNvimChanged",
  sign = "▎",
  max_bytes = 2 * 1024 * 1024,  -- files bigger than this get skipped
  enabled = false,              -- true = auto-enable on every nvim start, not just via tclaude
})

Tests

test/run.sh spins up headless nvim instances and fires fake hook payloads at them — covers the socket lifecycle, offset jumps, highlight ranges, dirty-buffer protection, toggle/pause behavior, and a couple of past regressions (null JSON offsets, double-setup() clobbering its own socket). Run it with:

./test/run.sh