Shows every Claude Code session on your machine as colored dots in your statusline. Whatever project you're in, one glance tells you which session is working, which is done, and which one is waiting for your permission.
- 🟡 waiting — needs your permission
- 🔴 busy — working (the dot animates)
- 🟢 idle — done, waiting for input
Sessions running in your current project show dimmed, since you can already
see those. If there are more than max_dots, the rest collapse into a +N.
It also pairs with tmux-claude-session-manager: hit a key, get a picker with every session, and jump to one — or approve/reject its permission prompt right there, without leaving your buffer. That works even when Claude runs inside a sidekick.nvim split.
How does it know all this? Claude Code writes a small state file for every
session it runs (~/.claude/sessions/*.json). The plugin just reads those.
No hooks, no CLI calls, nothing to set up on the Claude side.
- Neovim ≥ 0.10
- Claude Code ≥ 2.1.139 (older versions don't write the session files)
- A Nerd Font for the default icons
Optional:
- tmux-claude-session-manager under tmux, if you want the picker. The statusline works without it.
- sidekick.nvim, if you run Claude inside nvim and want the picker to preview and approve those sessions too.
With lazy.nvim:
{
"rashedInt32/claude-sessions.nvim",
event = "VeryLazy",
opts = {},
}All options with their defaults:
require("claude-sessions").setup({
dir = "~/.claude/sessions", -- honors $CLAUDE_CONFIG_DIR
poll_ms = 1000, -- how often to re-read the session files
spin_ms = 120, -- busy animation speed (only runs while busy)
statusline = {
max_dots = 10, -- show at most this many dots, then `+N`
dim_own = true, -- dim sessions running in this nvim's own cwd
dim_alpha = 0.55, -- how much color the dimmed dots keep
bg = nil, -- background behind the dots; nil = same as StatusLine
colors = {
waiting = "#f5d76e",
busy = "#f2555a",
idle = "#7fe08a",
more = "#9f9ca6",
},
icons = {
waiting = "",
idle = "",
busy = { "", "", "", "", "", "", "", "" },
},
},
picker = {
-- where tmux-claude-session-manager lives
script = "~/.tmux/plugins/tmux-claude-session-manager/scripts/list.sh",
},
repaint = {
-- Fixes a rendering bug: after switching tmux sessions, Claude's TUI can
-- leave stale text painted over its input box (claude-code#62740). When
-- enabled, the plugin sends Ctrl-L to embedded Claude terminals whenever
-- nvim regains focus, which makes Claude redraw cleanly. Turn it on if
-- you run Claude in sidekick under tmux.
enabled = false,
},
})require("lualine").setup({
sections = {
lualine_x = { require("claude-sessions").lualine() },
},
})Not on lualine? status() returns a plain statusline string (with %#…#
highlights baked in) and has_sessions() tells you when there's something
to show.
The plugin doesn't set any keymaps. Here's one that works well:
vim.keymap.set("n", "<leader>au", function()
require("claude-sessions").pick()
end, { desc = "Pick Claude session" })The two are halves of one workflow:
- The tmux plugin owns the picker popup: jump to a session, watch it live,
ctrl-yapprove /ctrl-rreject a permission prompt,ctrl-xkill. - This plugin puts the dots in your statusline and opens that picker from nvim. It also handles the picker's requests for sessions running inside nvim: their tmux pane belongs to the editor, so the picker can't preview or type into them directly — instead it asks nvim, and this plugin passes the keystroke (or the conversation text) to the right terminal.
Each works on its own. Together, you can sit in one buffer and manage every Claude session on the machine.
| Function | What it does |
|---|---|
setup(opts) |
Apply config, define highlights, start polling |
status() |
The statusline string (empty when nothing runs) |
has_sessions() |
True if any session is running |
lualine() |
Ready-made lualine component |
pick() |
Open the tmux picker (also :ClaudeSessions) |
permit(action, pid) |
Approve or reject an embedded session's permission prompt |
preview(pid, lines?) |
The tail of an embedded session's conversation |
permit and preview exist for the picker's scripts, which call them over
nvim's RPC socket. You won't call these yourself.
:checkhealth claude-sessions
Checks the session directory, tmux, the picker script, and sidekick.
