headroom.walls.sh · vim
Vim and Claude Code are both terminal tools. There is no plugin required, no IDE overhead — split your terminal, run Claude Code in one pane, edit in another. This page covers the workflows that work well for Vim users and how to surface usage data in your statusline.
Vim users already work in the terminal and are comfortable switching between shell and editor. Claude Code fits into that workflow without friction: it reads and writes files the same way shell scripts do, and it returns control when done. No GUI, no Electron, no context switching outside the terminal.
The most common setup is a tmux session with two panes:
tmux new-session # Left pane: vim vim src/main.py # Right pane (Ctrl-b then %): claude claude
Ctrl-b + % creates a vertical split. Navigate with Ctrl-b + arrow keys. :w in Vim saves the file; Claude Code reads it on the next tool call.
Vim 8.1+ has a built-in terminal. Open a split terminal with:
:terminal " or vertical split: :vertical terminal
Then run claude in the terminal buffer. Switch between the editor and terminal with Ctrl-w + h/l. Exit terminal mode with Ctrl- Ctrl-n.
For quick one-off Claude Code commands without a persistent session:
:!claude --print "Explain this function: %"
The % expands to the current filename. The output appears in Vim's command output area. Useful for quick questions; for multi-turn debugging sessions, use a proper split.
" Open Claude Code in a vertical split terminal nnoremap <leader>cc :vertical terminal claude<CR> " Open Claude Code in a new tab nnoremap <leader>ct :tabnew | terminal claude<CR> " Quick: run claude --print on current file nnoremap <leader>cq :!claude --print "Summarize what this file does: %"<CR>
Vim's statusline can call shell commands via system(). Read Claude Code's usage JSON from Vim's statusline function:
" Add to your .vimrc
function! ClaudeUsage()
let l:file = expand('~') . '/.claude/headroom-usage.json'
if !filereadable(l:file)
return ''
endif
let l:data = system('jq -r ""CC " + (.sessionUsagePct|floor|tostring) + "%" + "·" + (.weeklyUsagePct|floor|tostring) + "%"" ' . l:file . ' 2>/dev/null')
return substitute(l:data, "\n", "", "g")
endfunction
set statusline+=%{ClaudeUsage()}
This calls jq on each statusline redraw. If you find it slow, wrap it in a timer that updates a global variable every 30 seconds instead.
let g:claude_usage_cache = ''
let g:claude_usage_last = 0
function! ClaudeUsageCached()
let l:now = localtime()
if l:now - g:claude_usage_last > 30
let l:file = expand('~') . '/.claude/headroom-usage.json'
if filereadable(l:file)
let l:raw = system('jq -r ""CC " + (.sessionUsagePct|floor|tostring) + "%·" + (.weeklyUsagePct|floor|tostring) + "%"" ' . l:file . ' 2>/dev/null')
let g:claude_usage_cache = substitute(l:raw, "\n", "", "g")
endif
let g:claude_usage_last = l:now
endif
return g:claude_usage_cache
endfunction
set statusline+=%{ClaudeUsageCached()}
Show usage in your shell prompt, visible before you enter Vim:
# In ~/.bashrc or ~/.zshrc
claude_usage() {
local f="$HOME/.claude/headroom-usage.json"
[ -f "$f" ] && jq -r '"CC " + (.sessionUsagePct|floor|tostring) + "%·" + (.weeklyUsagePct|floor|tostring) + "%" ' "$f" 2>/dev/null || true
}
export PS1='$(claude_usage) w $ '
→ Full shell prompt integration · Starship module · tmux status bar
The statusline integration works when you're looking at Vim. But during a long Claude Code run — debugging a test suite, doing a multi-file refactor — Headroom shows both meters in the macOS menu bar as a persistent ambient display, no vim required:
Reads from ~/.claude/headroom-usage.json — same file your statusline script uses. Zero network calls, no API key. macOS 13+, free.
The Vim statusline tells you your usage when you glance at it. Headroom's color-coded menu bar icon alerts you passively — turns orange at 70%, red at 90% — so a session limit never interrupts you mid-task.
→ Claude Code + Neovim
→ tmux status bar integration
→ Shell prompt integration
→ Debugging with Claude Code
→ Claude Code keyboard shortcuts