- Shell 51%
- Lua 49%
Live tmux/nvim mirror of Claude Code file activity, plus the fish function to launch claude+nvim side by side with tracking enabled. |
||
|---|---|---|
| fish | ||
| hook | ||
| lua/claude-nvim | ||
| plugin | ||
| test | ||
| .luarc.json | ||
| README.md | ||
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>ctor: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 asvim.g.claude_nvim_enabled,vim.g.claude_nvim_tracking, andrequire("claude-nvim").status()if you want it in a statusline.- Setting
CLAUDE_NVIM_TRACK=1before launching nvim auto-enables tracking without touching your config — this is exactly whattclaudedoes under the hood.
Some behavior worth knowing:
- Changed lines get
ClaudeNvimChangedhighlight (linked toDiffText) 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