| description | Install Pair: what it needs, the daemon and the Neovim plugin, a check with pair doctor, and a working session in herdr or Rex. |
|---|
- Node.js 22.19 or newer
- Neovim 0.11 or newer
- herdr, the best home for Pair: the chat pane beside Neovim, your terminals watched with their output, Scout's pane below the chat. The older herdr (panes) and herdr-core with the Herdr window (terminals) both work, told apart by themselves (herdr.md). Rex is another terminal backend. Without either, all of Pair still works inside Neovim (neovim.md).
- For Scout:
bashand ripgrep (rg); optionally bubblewrap (bwrap), to run Pair's commands in a sandbox - Optional, for the context card, the goal and
your other agents: the work board, Shepherdr (
shepherdron the daemon's PATH), and GitHub'sghfor the pull request - Optional, for search by meaning: Python 3.10 or newer with its venv module (
python3-venvon Debian and Ubuntu), on Linux x86-64 or ARM64 or macOS on Apple silicon;:Pair find onfetches the model and its runtime itself. The word search needs nothing - A model: any OpenAI-compatible local server (for example llama.cpp or Ollama), an Anthropic-compatible API, or any provider pi-ai supports, with an API key or a subscription login (models.md).
Or let your AI agent do it: tell your coding agent "follow
https://github.com/makefunstuff/pairing-buddy/blob/main/INSTALL.md". That guide
takes it from a fresh machine to a passing pair doctor: the prerequisites, the service, your model, the plugin in
your plugin manager, upgrade and uninstall, and it asks you where only you can answer.
Once, in two parts: the daemon as an npm package, and the Neovim plugin with lazy.nvim. Both come from this GitHub repository.
npm install -g github:makefunstuff/pairing-buddy # puts `pair` on your PATH
pair setuppair setup:
- Writes a commented config to
~/.config/pairing-buddy/config.jsonif there is none yet. Set your models there (config.md). - In a terminal, offers to log in to a model provider (a subscription or an API key; see Logins and keys). Enter skips it.
- Stores the environment variables your model entries take keys from (
apiKeyEnv) for the service, which does not get your shell's environment (models.md). - Installs the daemon as a service that starts at login and restarts when it fails: a systemd user service,
pairing-buddy.service, on Linux, and a launchd agent,io.github.makefunstuff.pairing-buddy, on macOS. Without either, see below. - Where the Herdr window is installed (unless
"herdrPanel": false), installs Pair's panel into its mods (~/.config/herdr-app/mods/pair); an upgrade'spair setupupdates it. It also adds a key to the window'skeys.json(Alt-p, else the first of Alt-Shift-p and Ctrl-Alt-p that no section binds) and Pair to its + menu (programs.json), both opening the panel beside the focused terminal; each file is merged and backed up first (<file>.pair-bak-<time>). - Starts the daemon, and prints the next steps.
Then add the plugin to your lazy.nvim specs:
{
'makefunstuff/pairing-buddy',
dependencies = {'makefunstuff/semantic-grep.nvim'}, -- its picker for search by meaning (Alt-s)
main = 'pair',
lazy = false,
opts = {auto_connect = true},
}With auto_connect, every Neovim connects to the daemon at startup. Without a plugin manager:
vim.opt.rtp:append('/path/to/pairing-buddy') and require('pair').setup({auto_connect = true}) in your config.
The plugin's options are in neovim-plugin.md.
The plugin needs semantic-grep.nvim for search by meaning: its
picker is the one Alt-s opens, with Pair's daemon as its source (meaning.md). The spec above installs
it as a dependency; without a plugin manager, append its clone to the runtimepath too. Without it, Alt-s and
:Pair find say so, and the rest of Pair works.
Upgrading. Run npm install -g github:makefunstuff/pairing-buddy and pair setup again, also after upgrading
Node.js: the service names the Node.js binary it runs, and setup rewrites it and restarts the daemon. Without a
service, stop the running daemon first (pkill -f 'pair[.]mjs supervise'); pair setup or pair then starts the new
one.
Uninstalling. pair uninstall stops and removes the service and Pair's panel in the Herdr window (with the key
and the + menu entry setup added, unless you changed them), and keeps the
config and data.
From a clone. npm ci && npm link in it, then pair setup (the service then runs the clone's code), and
dir = '/path/to/clone' in place of the GitHub name in the lazy.nvim spec.
Without systemd or launchd. pair setup then installs no service: pair starts the daemon in the background
when it is not running, under a supervisor (pair supervise) that restarts it 2 s after it crashes or fails, and
gives up after 5 failures in a minute. A clean stop (kill with SIGTERM) stops both. Nothing starts it at login; to
have that, run pair supervise from your init system as your user, or pair daemon under a supervisor of its own
that restarts it on failure, for example a runit user service (exec pair daemon in its run file) or an OpenRC
user service with supervisor=supervise-daemon. Set PAIR_CONFIG there if your config is not in the default place.
pair doctor checks every part and says what is wrong in plain words, one line each, with the fix. What each line
looks at, and the usual fixes, are in Troubleshooting.
- In the herdr pane next to your Neovim, run
pair. It opens a narrow chat pane on the right (and starts the daemon if it is not running). - Neovim is connected already with
auto_connect; otherwise run:Pair startthere. - Pair shows the note of the last session in this project, if there was one ("Last time: …"), and the goal: the
title of the work board's (Shepherdr's) task for this branch, else the words of the branch name. Only without either does
it ask; type the goal, or
laterto skip it (/goal <text>sets one any time). - Work as usual. Pair stays quiet unless a remark clears the bar. Tell it whether a remark helped:
+or-in the chat,Alt-uorAlt-nin Neovim. - Stop when you are done. The session ends by itself, with a short note kept for the next one, after 45 minutes
without you or a minute after its last Neovim and chat pane closed.
/endin the chat (or:Pair end) ends it at once (memory.md).
The chat pane is optional: a Neovim alone is a whole session.
Chat commands. /goal, /level, /scout, /navigate, /drive, + and - for your verdict, /why,
/mute, /undo, /end and the rest are in the command reference; / in the chat lists
them as you type. Anything else you type is a question for Pair, and "you take it" or "your turn" hands it the
wheel. What the pane shows and its keys (? lists them) are in the chat pane.
The shell hook. Optional, for exact command boundaries and exit codes in your own panes: add it to your shell's rc file. Pair then catches every command however short and looks at the pane's processes only for an editor while a command runs. In zsh the hook also reports your keys at the prompt, so the pane is not read there at all; bash and fish report no keys, so the pane with focus is still read twice a second at its prompt, for typing (herdr.md):
eval "$(pair shell-hook bash)" # or zsh
pair shell-hook fish | source # fish, in config.fishIt runs pair report in the background before and after each command, so the prompt never waits; zsh's keys go
straight to the daemon's socket, at most twice a second, and never the keys themselves. It also emits OSC 133 marks
(prompt, output, end with the exit code) for a terminal that reads them. It names the shell by its process id, which
tells Pair the :terminal buffer or tmux pane the command ran in.
Without herdr or Rex, run :Pair chat in Neovim (or pair chat in any terminal). Scout's pane and the tests on save
run in a :terminal along the bottom of Neovim, and the Driver's type goes to your own :terminal buffers
(neovim.md). Pair reads your own :terminal buffers in Neovim, and the panes of the tmux
session Neovim or the chat runs in: which one you are in, the commands you run there and their output, and with the
shell hook their exit codes. Terminals in neither (another window of your terminal emulator) send only the shell
hook's exit codes, without output.
Several projects work at once: each project has its own session, chat pane and goal, and the daemon serves them
all. A project is the git root of the folder Neovim and pair start in, so each git worktree is a project of its
own: two pieces of work in one repository each get their own session in their own worktree. In a monorepo, where
the git root is too coarse, sessionRoots makes smaller folders projects.
Several Neovims in one project share its session. Pair shows points, suggestions and edits in the Neovim you are in: the one with focus, which Neovim learns from the terminal's focus reports and Pair from herdr's focused pane; when none has it (you are in the chat pane, or the browser), the one you were in last. A Neovim's own doings, such as its LSP's diagnostics or a file it reloads while you are elsewhere, never make it the one. Pair reads a file from whichever Neovim has it loaded, the one you are in first.
Restarts. If the daemon restarts, the chat pane's status says so, the pane waits for it and carries on, without showing the history twice. Neovim reconnects by itself too (neovim-plugin.md). If you had asked something the restart cut off, Pair finishes that answer and shows it marked as late, in the chat and in Neovim, also when they reconnect after it. A remark Pair was making unasked, or a hand-over, is dropped instead.
The chat pane's colours. It uses the terminal's own colours and Pair's accent from Neovim, in true colour, so
the two read as one (colours). Until a Neovim with termguicolors connects it uses the terminal's
cyan, and with NO_COLOR set it prints no colours.
Open Neovim in a project in a Rex terminal, then run pair in a Rex terminal beside Neovim. Pair opens the chat beside that terminal. Neovim
connects with auto_connect; otherwise run :Pair start. Pair watches the Rex session's terminals. pair chat runs
in place, and :Pair chat opens in a Neovim terminal buffer. What Pair gets from Rex explains the gaps
and the shell hook.
pair authlogs in to model providers and lists what is set (models.md).pair statsshows how often Pair spoke unasked and what you made of it (memory.md).pair daemonruns the daemon in the foreground;pair supervisetoo, restarting it when it fails.pair --versionprints the version of this install; the daemon's log names its own when it starts.- The daemon's log goes to the journal under systemd (
journalctl --user -u pairing-buddy), to~/Library/Logs/pairing-buddy.logunder launchd, and todaemon.login the data directory whenpairstarted it.