Tutorial: Setting Up the dev-session Workflow

nvim and an AI agent editing the same buffer

tutorial · 80% AI

Post 2026-A-0127

Abstract. dev-session is a tmux workflow that puts nvim in the top pane and an AI coding agent in the bottom pane, with both editing the same live buffer. The agent reaches nvim through a msgpack-rpc socket (nvim --listen /tmp/nvim-dev.pipe) using pynvim – no terminal injection, no fake keypresses, and no fighting over the keyboard. This tutorial walks through the full setup: tmux configuration, the dev-session launcher, the nvim keymaps, and the agent-side skills that drive nvim over the socket.

Prerequisites

Step 1: Install the tmux configuration

Create ~/.tmux.conf:

set -g mouse on
set -g prefix C-a
bind C-a send-prefix

# Prefix-free pane navigation
bind -n C-k select-pane -U
bind -n C-j select-pane -D

Reload it:

tmux source-file ~/.tmux.conf

Why these choices: mouse on lets you click any pane to focus it. The prefix is Ctrl-a instead of the default Ctrl-b because nvim captures Ctrl-b. And Ctrl-j/Ctrl-k are bound without a prefix so you can switch panes from anywhere, including from inside nvim normal mode or the agent’s prompt.

Step 2: Add the nvim split-navigation keymaps

In ~/.config/nvim/init.lua, add keymaps for nvim’s own splits, plus a fallback that opens the agent in a nvim terminal split when you are not in dev-session:

vim.keymap.set("n", "<C-h>", "<C-w>h")
vim.keymap.set("n", "<C-j>", "<C-w>j")
vim.keymap.set("n", "<C-k>", "<C-w>k")
vim.keymap.set("n", "<C-l>", "<C-w>l")
vim.keymap.set("t", "<C-h>", "<C-\\><C-n><C-w>h")
vim.keymap.set("t", "<C-j>", "<C-\\><C-n><C-w>j")
vim.keymap.set("t", "<C-k>", "<C-\\><C-n><C-w>k")
vim.keymap.set("t", "<C-l>", "<C-\\><C-n><C-w>l")

vim.keymap.set("n", "<leader>cl", function()
  vim.cmd("belowright split | terminal hermes")
  vim.cmd("startinsert")
end)

Note: inside dev-session, Ctrl-j/Ctrl-k are claimed by tmux and switch panes; inside a plain nvim window they navigate nvim splits.

Step 3: Install the dev-session launcher

Create ~/av/bin/dev-session (or any bin directory on PATH):

#!/bin/bash
# Launch a tmux dev session: nvim (top) + agent (bottom).
# nvim listens on /tmp/nvim-dev.pipe so the agent can interact via pynvim.
#
# Usage:
#   dev-session              # start or attach to "dev" session
#   dev-session [file]       # open nvim on a specific file
#   dev-session -k           # kill the session
#
# The bottom pane runs `hermes` by default. To use another agent
# (e.g. claude), override: AGENT=claude dev-session

SESSION="dev"
NVIM_SOCKET="/tmp/nvim-dev.pipe"
AGENT="${AGENT:-hermes}"

if [[ "$1" == "-k" ]]; then
    tmux kill-session -t "$SESSION" 2>/dev/null && echo "Session '$SESSION' killed." || echo "No session '$SESSION' running."
    exit 0
fi

FILE="${1:-}"

if tmux has-session -t "$SESSION" 2>/dev/null; then
    tmux attach-session -t "$SESSION"
    exit 0
fi

# Create session -- top pane: nvim
tmux new-session -d -s "$SESSION" -n "main" -x "$(tput cols)" -y "$(tput lines)"

if [[ -n "$FILE" ]]; then
    tmux send-keys -t "${SESSION}:0.0" "nvim --listen ${NVIM_SOCKET} $(printf '%q' "$FILE")" Enter
else
    tmux send-keys -t "${SESSION}:0.0" "nvim --listen ${NVIM_SOCKET}" Enter
fi

# Bottom pane: $AGENT (30% height)
tmux split-window -t "${SESSION}:0.0" -v -p 30
tmux send-keys -t "${SESSION}:0.1" "$AGENT" Enter

# Focus nvim
tmux select-pane -t "${SESSION}:0.0"

tmux attach-session -t "$SESSION"

Make it executable and link it onto PATH:

chmod +x ~/av/bin/dev-session
ln -s ~/av/bin/dev-session ~/.local/bin/dev-session

Step 4: Install the agent-side skill

For Hermes, install the nvim-send skill. It ships a single driver script that talks to the socket; operations are check, read, open, ex, append, and goto. The skill’s script is pinned to ~/Miniforge3/bin/python3 because that is the only python with pynvim installed on this machine:

~/Miniforge3/bin/python3 -m pip install pynvim

For Claude Code, install ~/.claude/commands/nvim-send.md following the reference implementation in the repo tutorial (the socket protocol is identical; only the invocation differs).

Step 5: Start the session

dev-session                        # empty nvim
dev-session ~/path/to/file.md      # nvim opens that file
AGENT=claude dev-session           # Claude instead of hermes

The layout:

+--------------------------------------+
|   nvim --listen /tmp/nvim-dev.pipe   |
|          (top pane, 70%)             |
+--------------------------------------+
|   hermes (bottom pane, 30%)          |
+--------------------------------------+

Switch panes with Ctrl-j (down) and Ctrl-k (up), or click with the mouse. Zoom a pane with Ctrl-a z. Detach with Ctrl-a d; re-attach with dev-session. Kill with dev-session -k.

Verification

  1. dev-session opens a tmux session named dev with nvim on top.
  2. tmux list-panes -t dev shows two panes: pane 0 is nvim, pane 1 is the agent.
  3. The socket exists: ls /tmp/nvim-dev.pipe.
  4. From the agent pane, invoke the nvim-send skill’s check operation and confirm it prints “socket OK” – this proves the agent can reach nvim.
  5. Ask the agent to read the buffer; confirm it prints the file’s contents. Then ask it to append a line and confirm the line appears in nvim when you switch to the top pane.

Notes


Want to stay in touch?

If you'd like to support my work:

If there is a topic you'd like me to cover, please let me know! Questions, comments, and suggestions are welcome.