patchmarks.nvim is a file-oriented Git review plugin for Neovim.
It starts a review session for the current Git change set and lets you attach freeform line or line-range annotations in normal file buffers. Those annotations can be exported back to an LLM coding agent.
Patchmarks does not render diffs itself. It is designed to coexist with your
existing diff workflow, whether that is gitsigns.nvim, mini.diff, or
plain Git commands.
- Neovim
>= 0.10 - Git on
$PATH
MIT. See LICENSE.
With lazy.nvim:
{
"emmanuelchucks/patchmarks.nvim",
config = function()
require("patchmarks").setup({
preview = {
trigger = "manual", -- or "cursorhold"
},
})
end,
}For local development:
{
dir = "/absolute/path/to/patchmarks.nvim",
name = "patchmarks.nvim",
config = function()
require("patchmarks").setup()
end,
}require("patchmarks").setup({
preview = {
trigger = "manual", -- "manual" | "cursorhold"
width = 72,
height = 6,
},
export = {
handoff = nil, -- optional function(ctx) return true/false end
stop_after_handoff = true,
},
})Defaults:
preview.trigger = "manual"preview.width = 72preview.height = 6export.handoff = nilexport.stop_after_handoff = true
:PatchmarksStartStart or resume a Patchmarks session for the current Git worktree.:PatchmarksFilesOpen a native quickfix list for the active session's changed files.:PatchmarksRefreshExplicitly refresh changed-file metadata without discarding annotations.:PatchmarksNewStart a fresh round and discard existing annotations.:PatchmarksExportExport annotations to registers and clipboard when available.:PatchmarksHandoffExport annotations and run the configured handoff callback.:PatchmarksStopStop Patchmarks UI state but keep the session persisted.:PatchmarksDiscardDelete the persisted session and clear in-memory state.
These mappings exist only in normal file buffers that belong to the active Patchmarks session.
<localleader>aAdd an annotation on the current line, or on the current visual line range.<localleader>eEdit the annotation under the cursor.<localleader>dDelete the annotation under the cursor.<localleader>pPreview the annotation under the cursor.<localleader>xExport the current review.<localleader>XHand off the current review.<localleader>rRefresh the session.<localleader>RStart a new round.[aJump to the previous annotation in the current file, wrapping to the last.]aJump to the next annotation in the current file, wrapping to the first.
- Open a changed source file normally.
- Run
:PatchmarksStartinside the Git worktree. - Add annotations with
<localleader>a. - Edit or preview them as needed.
- Optionally run
:PatchmarksFilesif you want a native quickfix list of changed files. - Run
:PatchmarksExportto copy a compact review block for your agent. - After the agent makes more Git changes, run
:PatchmarksStartto start a fresh round automatically if the last review was already exported. - Use
:PatchmarksNewwhen you want to force a fresh round yourself.
Patchmarks does not make source buffers read-only. Session files remain normal
editable file buffers, so you can keep using tools like gitsigns.nvim,
mini.diff, or Fugitive for hunk navigation and staging. Patchmarks stays
inactive in non-file buffers such as quickfix, help, terminal, prompt,
nofile, acwrite, and plugin-owned buffers.
PatchmarksHandoff exports the current review, passes it to
export.handoff(ctx), and stops the Patchmarks UI when the callback succeeds.
The callback receives ctx.text, ctx.session, ctx.repo_root, and
ctx.repo_name.
Example tmux handoff for a review window opened from an agent window:
require("patchmarks").setup({
export = {
handoff = function(ctx)
return require("patchmarks.integrations.tmux").paste_to_pane(ctx.text, {
target = "{last}", -- previously current tmux window
submit = true,
focus = true,
repo_root = ctx.repo_root,
})
end,
},
})With submit = true, the tmux helper writes .git/patchmarks/handoff.md, pastes
address review: .git/patchmarks/handoff.md into the target pane, sends Enter,
and can switch focus to the target. Pass any tmux target accepted by -t via
target.
Example cmux handoff:
require("patchmarks").setup({
export = {
handoff = function(ctx)
return require("patchmarks.integrations.cmux").paste_to_other_pane(ctx.text, {
submit = true,
})
end,
},
})With submit = true, the cmux helper writes .git/patchmarks/handoff.md and
submits address review: .git/patchmarks/handoff.md. Pass surface = "surface:N"
to target a specific surface.
The annotation editor is a normal writable floating buffer, not a form.
Escreturns to normal mode.:wsaves and keeps the editor open.:wqandZZsave and close.:q!andZQdiscard.
Empty-body behavior:
- New annotation:
empty
:q,:w, and:wqare all no-ops. - Existing annotation:
empty
:qkeeps the original annotation unchanged. empty:wor:wqasks whether to delete the annotation.
Patchmarks persists the active session under the repo Git dir:
.git/patchmarks/current.json
This lets :PatchmarksStart restore a session after restarting Neovim.
If the session was already exported and Git has changed since that export,
PatchmarksStart starts a fresh round automatically instead of restoring the
old annotations.
Supported in v1:
- modified tracked files
- added tracked files
- renamed and copied files
- untracked files
- single-line annotations
- line-range annotations
Not supported in v1:
- deleted tracked files
- overlapping annotations
- multiple annotations covering the same range
- automatic carry-forward into a new review round
- agent-specific CLI integration
Headless test suite:
nvim --headless -u NONE -i NONE -c "lua dofile('tests/run.lua')" -c qall!Local development commands:
make format
make lint
make test
make checkTooling:
StyLuafor Lua formattingSelenefor Lua linting.luarc.jsonfor LuaLS project diagnostics
The Makefile first uses stylua and selene from $PATH. If they are not
available, it falls back to Mason's default bin directory:
~/.local/share/nvim/mason/bin
With Emmanuel's Neovim config, Mason installs both tools automatically. You can still override either binary explicitly when needed:
STYLUA=/path/to/stylua SELENE=/path/to/selene make checkTest layout:
tests/specs/feature-oriented specstests/support/helpers.luashared test helperstests/run.luasingle test entrypoint
Keep changes aligned with the project boundary:
- Patchmarks owns review-session orchestration and annotation UX.
- Diff rendering and hunk UX belong to the user's existing diff tools.
- Favor Neovim and Git built-ins over extra abstraction.
- Run
make checkbefore sending changes upstream.
After installing locally, generate helptags if needed:
:helptags ./docThen see:
:help patchmarks