Inline AI pair programming for Neovim.
🔺 Breaking Changes in v4.0 🔺
This version removes the overlay system, sessions, RPC, and marker-based suggestions to focus on one thing: simple inline editing with
cc:/uu:markers. See v4-architecture.md for details.Why? Less complexity, more reliability. Claude edits files directly — no parsing, no overlays, no state management. Just write
cc:, save, and Claude handles it.Need the old features? Use
git checkout legacy-v3orgit checkout v3.0.0.
Write cc: markers anywhere in your code, save, and Claude edits the file directly.
-- cc: add error handling here
-- uu: Should I use pcall or assert?
function process(data)
return data.value
endSave → Claude reads the file → executes the instruction → removes the marker.
See prompt.md for the full prompt.
Use gC to insert cc: markers with proper comment syntax for any filetype:
| Keybinding | Action | Scope Hint | Captures Text |
|---|---|---|---|
gCC |
Insert marker above current line | <line> |
No |
gCip/gCap |
Insert marker for paragraph | <paragraph> |
No |
gCiw/gCaw |
Insert marker for word | <word> |
Yes |
gCis/gCas |
Insert marker for sentence | <sentence> |
Yes |
gCi}/gCa} |
Insert marker for block | <block> |
No |
gCif/gCaf |
Insert marker for function | <function> |
No |
gC (visual) |
Insert marker with selected text | <selection> |
Yes |
Scope hints tell Claude what the instruction applies to:
-- cc: <paragraph> refactor this section
-- cc: <line> add error handling
-- cc: <selection> some_variable <- rename to camelCaseExample: Select “controller configuration” and press gC:
// cc: <selection> controller configuration <-
// Config holds the controller configurationMarkers show in the gutter:
- (yellow) —
cc:command marker - (blue) —
uu:question marker
When Claude needs more information, it adds uu: and you can continue discussion by appending cc: in response.
-- cc: add error handling here
-- uu: Should I use pcall or assert?
function process(data)
return data.value
endKey bindings are optional — the plugin works with :Pairup commands alone.
-- lazy.nvim
{
"Piotr1215/pairup.nvim",
cmd = { "Pairup" },
keys = {
{ "<leader>cc", "<cmd>Pairup start<cr>", desc = "Start Claude" },
{ "<leader>ct", "<cmd>Pairup toggle<cr>", desc = "Toggle terminal" },
{ "<leader>cq", "<cmd>Pairup questions<cr>", desc = "Show questions" },
{ "<leader>cx", "<cmd>Pairup stop<cr>", desc = "Stop Claude" },
},
config = function()
require("pairup").setup()
-- Default works out of the box. Override only if needed:
-- require("pairup").setup({
-- providers = {
-- claude = { cmd = "claude --permission-mode plan" },
-- },
-- })
end,
}:Pairup <subcommand>
| Command | Description |
|---|---|
start |
Start Claude (hidden terminal) |
stop |
Stop Claude |
toggle |
Show/hide terminal |
say <msg> |
Send message to Claude |
questions |
Show uu: in quickfix |
inline |
Manual cc: trigger |
diff |
Send git diff to Claude |
lsp |
Send LSP diagnostics to Claude |
Automatically injected into lualine (or native statusline if no lualine). No config needed.
[C]— Claude running[C:pending]— Waiting for Claude[C:██░░░░░░░░]— Progress bar[C:ready]— Task complete
Manual setup (only if you disable auto-inject or use a custom statusline plugin):
-- Disable auto-inject
require("pairup").setup({ statusline = { auto_inject = false } })
-- Add to native statusline manually
vim.o.statusline = '%f %m%=%{g:pairup_indicator} %l:%c'Default: The --permission-mode acceptEdits flag is included by default. This allows Claude to edit files without prompting for confirmation on each change, which is required for the inline editing workflow to function smoothly.
All settings below are defaults. You only need to include values you want to change:
require("pairup").setup({
provider = "claude",
providers = {
claude = {
-- Full command with flags (default includes acceptEdits)
cmd = "claude --permission-mode acceptEdits",
},
},
terminal = {
split_position = "left",
split_width = 0.4,
auto_insert = false, -- Enter insert mode when opening terminal
},
auto_refresh = {
enabled = true,
interval_ms = 500,
},
inline = {
markers = {
command = "cc:",
question = "uu:",
},
quickfix = true,
},
statusline = {
auto_inject = true, -- auto-inject into lualine/native statusline
},
-- Progress bar (optional, disabled by default)
-- NOTE: When enabled, YOU must grant Claude write access to the progress file directory.
-- Add to your claude command: --add-dir /tmp (or your custom path)
progress = {
enabled = false,
file = "/tmp/claude_progress", -- Default path, change if needed
},
operator = {
key = "gC", -- change to override default
},
})Customizable highlight groups (respects light/dark background by default):
-- In your colorscheme or after/plugin/colors.lua:
vim.api.nvim_set_hl(0, 'PairupMarkerCC', { bg = '#your_color' }) -- cc: marker line
vim.api.nvim_set_hl(0, 'PairupMarkerUU', { bg = '#your_color' }) -- uu: marker line
vim.api.nvim_set_hl(0, 'PairupFlash', { bg = '#your_color' }) -- changed lines flashAvailable <Plug> mappings for custom keybindings:
vim.keymap.set('n', '<leader>cc', '<Plug>(pairup-toggle-session)') -- start/stop
vim.keymap.set('n', '<leader>ct', '<Plug>(pairup-toggle)') -- show/hide terminal
vim.keymap.set('n', '<leader>cl', '<Plug>(pairup-lsp)') -- send LSP diagnostics
vim.keymap.set('n', '<leader>cd', '<Plug>(pairup-diff)') -- send git diff
vim.keymap.set('n', '<leader>cq', '<Plug>(pairup-questions)') -- show uu: in quickfix
vim.keymap.set('n', '<leader>ci', '<Plug>(pairup-inline)') -- process cc: markers
vim.keymap.set('n', ']C', '<Plug>(pairup-next-marker)') -- next marker
vim.keymap.set('n', '[C', '<Plug>(pairup-prev-marker)') -- prev marker- Neovim 0.11+
- Claude Code CLI
MIT