A pair programmer for Neovim that knows when to speak.
Pair is a Neovim plugin and a daemon that work next to you like a colleague in the second chair: it watches you code,
says one short line under your cursor when it spots something, runs the tests you would skip, and takes the keyboard
only when you hand it over. It is not code completion and not a chat sidebar, and it never writes your files: its
edits land unsaved in your buffer as one undo step, and the disk changes only when you save. When you ask it for
code (/gen), it proposes it where you asked, and you take it with one key, also unsaved; new files it drafts are
buffers to review, and one reaches the disk only when you :w it. A sample you ask for to try out (/gen try) is
written and run in a folder of Pair's own, outside your project, and /keep brings it in as one more buffer to
review. A scaffold of many files (/gen scaffold) is built and run in a copy of your project in Pair's data folder,
and you keep it a file at a time: a new file as a buffer to review, a change to one of yours as suggestions in it.
Docs: makefunstuff.github.io/pairing-buddy (source in
docs/, built from site/).
Watch the tutorial on the site: 25 minutes with a voiceover
and captions, one idea per scene, recorded live with a real model. Chapters: 0:00 what Pair is · 0:59 setup and pair doctor · 2:44 the roles · 4:16 the chat pane · 6:20 exploring code · 7:20 tests · 8:42 notes and the blank page ·
11:11 the hand-over · 12:51 asking for code with /gen · 18:09 the board · 21:41 several worktrees · 22:14 voice ·
23:20 with or without herdr · 23:55 the keys to remember. Its script and how to render it again are in
docs/video.
Version 0.11 (changelog).
Most AI coding tools sit beside your work: you stop, describe the problem, and read a long answer. A good human pair does something else. They notice when you start fixing the wrong file, run the tests you would skip, keep quiet while you think, and take the keyboard only when you hand it over. Pair aims for that:
- It speaks rarely. A small, fast model, the Watcher, scores each moment first, and most moments are not worth a word. On a slow server Pair skips the moments you can see on screen, and still asks about the ones you cannot (watcher). An optional decision model (a classifier such as TypeSafe's Jev or Cloudflare's Clef) can sort the moments first and say, with a probability, whether one is worth interrupting you for. Remarks that can wait are held until your next break.
- It shows, in place. Its words appear under the line you are on, it points at the line it means, and a suggested change is one key to take.
- It runs what you'd skip. Save, and it runs the project's tests and tells you what your fix broke elsewhere.
- You stay in charge. One role at a time: Navigator points and suggests, Scout also runs commands in its own pane,
and the Driver edits only when you hand over, while you watch. Any key takes the wheel back. Ask it for code with
/gen hereorAlt-g, and it lands where you asked, to take with one key and undo as one request;/gen filedrafts new files as buffers you review, which reach the disk only when you:wone;/gen trywrites a sample in a folder outside the project and runs it in a sandbox, for you to read, change and run again, and/keepmoves it in;/gen scaffoldbuilds many files and their wiring in a copy of the project, runs and checks them there, and you keep what you want of it a file at a time. Every request runs against your brief (the goal andNOTES.md, in your words, which Pair never edits): it asks before going against it, and says what its code guessed. Pair knows its own edits from yours, so it never remarks on the code it wrote as if you had. Code you took stays marked┊until you edit it or:Pair ownit, and:Pair todayandpair statssay how much of it is not yours yet (/gen). In the chat pane, what a request made is a card with its keys:kkeep,Enteropen it in Neovim,ddrop,uundo. A request too big to watch goes to your work board, Shepherdr, with/gen board: Pair writes the task's brief from yours (your words, the note's lines withfile:line, the files, the tests, the open questions), lets you edit it, and adds it only as you pick: add only, add and delegate, plan first, research only, or copy the command. A request too big for/gen's limits is offered to the board. When a task is ready,:Pair review <id>(orAlt-ron its line) opens its branch as a review: what its reviewer said,≠ briefon the branch, each file's diff, andkto keep a file or a hunk in yours, unsaved; tell, merge (a tell to its agent) and archive only on your pick. On a task's branch its brief on the board is part of yours, and/brief synctells its agent, on your pick, what changed in your brief since. - Your other agents, in one line. When a board task or another agent needs you, is ready to merge or is done,
Pair says so at your next pause, never while you type;
o,dandtopen what a task left behind (its report or pull request, its branch's diff, a terminal in its worktree), and the chat's header counts the repo's tasks. A file a working task also changes says so in its winbar, and when you edit lines its branch changes, Pair tells you at your next pause (your other agents).
You need Node.js 22.19+, Neovim 0.11+, and a model: a local OpenAI-compatible server, an API key for any provider pi-ai supports, or a subscription login where the provider allows it. herdr (the older herdr, or herdr-core with the Herdr window) is the best home for Pair; Rex is another terminal backend. Without herdr or Rex, everything runs inside Neovim and tmux.
npm install -g github:makefunstuff/pairing-buddy # puts `pair` on your PATH
pair setup # writes the config, offers a login, installs the serviceAdd the plugin with lazy.nvim:
{
'makefunstuff/pairing-buddy',
dependencies = {'makefunstuff/semantic-grep.nvim'}, -- its picker for search by meaning (Alt-s)
main = 'pair',
lazy = false,
opts = {auto_connect = true},
}Set your model in ~/.config/pairing-buddy/config.json (models), run pair doctor to check every
part, then pair in a herdr pane or Rex terminal next to Neovim (in the Herdr window it opens
Pair's panel), or :Pair chat in Neovim, and work. In the
chat pane, ? lists its keys and / its commands.
Getting started walks through it, and the
first ten minutes tutorial does it step by step, with what pair doctor
shows. Optionally add the shell hook (eval "$(pair shell-hook bash)", or zsh, or
fish) to your shell's rc file: Pair then gets every command you run, with its exit code, from the shell itself, and
in zsh your typing too.
Let your AI agent set it up. Tell your coding agent "follow
https://github.com/makefunstuff/pairing-buddy/blob/main/INSTALL.md": INSTALL.md takes it from a fresh
machine to a passing pair doctor, step by step with checks, and asks you where only you can answer (which model,
your keys and logins).
- Getting started and install and daily use
- Tutorials: short how-tos, a few minutes each, from the first ten minutes to /gen, the board, worktrees and voice
- How it works, roles and workflows
- The chat pane: who speaks, what Pair is doing now, wide and narrow panes, a remark's own keys, the gen card, find, calm motion, role colours, its keys and commands
- Your other agents: the board's tasks and herdr's agents in one line at your next pause, what a task left behind (report or pull request, its branch's diff, its worktree) one key away, and the files a working task also changes
- /gen: ask Pair for code at your cursor, as new files to review, as a sample to run outside the
project, or as a scaffold built in a copy of it, against your brief; take it with one key,
:w,/keeporkper file, undo the request as one; Pair's own edits carry their origin, and taken code is marked┊until you own it;/gen boardhands a request to the board as a task, its brief built from yours, and:Pair reviewopens a task's branch as a review to keep pieces of - Search by meaning:
Alt-sis semantic-grep's live picker in Telescope, snacks.picker or fzf-lua that finds code by your words on every key and by what you mean as you pause, from a local index (EmbeddingGemma 2, or an embedding model of your own) Pair keeps up to date in the background, and optionally a small decision model that reranks a settled list's first pieces - Push-to-talk: ask aloud, heard by LFM3-Omni on your CPU (or whisper.cpp, or an OpenRouter model), with answers read aloud when you are away, or always in talk
- Models and providers: local servers, API keys, subscription logins, one model for both roles, and the optional decision model
- Reference: configuration, Neovim plugin, commands
- Troubleshooting and known limitations
- Data and privacy, tests
- Contributing, also on the site, releasing and the changelog
The site is VitePress: cd site && npm ci && npm run dev previews it, and the
Pages workflow builds and deploys it on every push to main that changes docs/ or site/. Its look is pixel art:
the palette (PICO-8's 16 colours) and the fonts (Pixelify Sans for headings and labels, Inter for text) are in
site/.vitepress/theme/tokens.css, and the sprites, the favicon and the PNG icons
(with the web manifest) are drawn as pixel grids in site/sprites/build.mjs
(npm run sprites redraws them).
A shared link shows the page's own title and description: a docs page's description from its frontmatter, or else its
first paragraph, cut to 155 characters (site/.vitepress/meta.mjs). Give a page a
description when it opens with a list, a heading or a code block. The preview image, site/public/og-v2.png
(1200x630), is site/og/card.html: npm run og redraws it with a headless Chrome or Chromium,
and the PNG is committed. X caches card images by URL, so a changed design goes out under a new file name (change it
in site/og/build.mjs and meta.mjs); otherwise X keeps showing the old image.
After npm run build, npm run check checks every built page has the full set of tags with absolute URLs (the Pages
workflow runs it before it deploys), and node og/previews.mjs OUT renders mock X, Slack and Discord previews of the
built pages into OUT/previews.png.
Bug reports, ideas and pull requests are welcome: CONTRIBUTING.md says how to run Pair from a
clone, run the tests, report a bug (with pair doctor output) and open a pull request.
pairing-buddy is under the MIT License. The fonts, a vendored animation library and a colorscheme used by the site and the video keep their own licences: see THIRD_PARTY_NOTICES.md.