-
-
Notifications
You must be signed in to change notification settings - Fork 40
Add instance per git root #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThe changes introduce multi-instance support to the Claude Code plugin, allowing multiple independent terminal instances keyed by git root or working directory. Documentation is updated to describe this feature and its configuration. The codebase is refactored to manage multiple buffers, update buffer naming, and centralize buffer retrieval logic, while ensuring configuration validation for the new option. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Neovim
participant ClaudeCodePlugin
participant TerminalInstance
User->>Neovim: Opens tab/project (with git root)
Neovim->>ClaudeCodePlugin: Calls toggle()
ClaudeCodePlugin->>ClaudeCodePlugin: Determine instance ID (git root or cwd)
ClaudeCodePlugin->>ClaudeCodePlugin: Check if instance exists
alt Instance exists
ClaudeCodePlugin->>TerminalInstance: Toggle visibility
else New instance
ClaudeCodePlugin->>TerminalInstance: Create terminal buffer (named by instance ID)
ClaudeCodePlugin->>ClaudeCodePlugin: Store buffer in instances table
ClaudeCodePlugin->>TerminalInstance: Show terminal
end
Poem
Note ⚡️ AI Code Reviews for VS Code, Cursor, WindsurfCodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback. Note ⚡️ Faster reviews with cachingCodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 30th. To opt out, configure 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (6)
lua/claude-code/config.lua (1)
174-180
: Trim stray whitespace to satisfy Luacheck & maintain code hygieneLuacheck warns that line 177 contains only whitespace. Keeping the file free of trailing / blank-only lines helps static analysis pass cleanly and avoids noisy diffs later.
- +🧰 Tools
🪛 Luacheck (1.2.0)
[warning] 177-177: line contains only whitespace
(W611)
CLAUDE.md (1)
29-46
: Fix markdown-lint issues around heading & code fence spacing
markdownlint
flags missing blank lines before the “Multi-Instance Support” heading and around the fenced code block. Adding a single blank line before/after each element resolves MD022 & MD031.-28 -… -28 -Adding buffer-specific context management -29# Multi-Instance Support +28 +Adding buffer-specific context management + +29# Multi-Instance Support … -38 Buffer names include the git root path for easy identification -39 -40```lua +38 Buffer names include the git root path for easy identification + +40 +```lua … -45 }) -46``` +45 }) + +46```🧰 Tools
🪛 markdownlint-cli2 (0.17.2)
29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below(MD022, blanks-around-headings)
40-40: Fenced code blocks should be surrounded by blank lines
null(MD031, blanks-around-fences)
lua/claude-code/init.lua (1)
47-56
: Minor guard: ensureinstances
table exists
get_current_buffer_number()
assumesM.claude_code.instances
is always a table. If a third-party test swapsM.claude_code
this could throw. A tiny guard avoids surprises without overhead.- if current_instance then - return M.claude_code.instances[current_instance] + if current_instance and type(M.claude_code.instances) == 'table' then + return M.claude_code.instances[current_instance] endlua/claude-code/terminal.lua (3)
67-78
: Nil-safe buffer validity check
vim.api.nvim_buf_is_valid(bufnr)
is only called whenbufnr == current_bufnr
, but an explicit nil check makes intent clearer and avoids accidental API calls with nil in future edits.- for _, bufnr in pairs(claude_code.claude_code.instances) do - if bufnr == current_bufnr and vim.api.nvim_buf_is_valid(bufnr) then + for _, bufnr in pairs(claude_code.claude_code.instances) do + if bufnr + and bufnr == current_bufnr + and vim.api.nvim_buf_is_valid(bufnr) + then🧰 Tools
🪛 Luacheck (1.2.0)
[warning] 68-68: line contains only whitespace
(W611)
[warning] 77-77: line contains only whitespace
(W611)
166-168
: Prune invalid buffers to keepinstances
table cleanWhen a buffer is wiped (e.g.,
:bd
), its entry remains, forcing a validity check every toggle. Removing stale entries keeps look-ups O(1).if not vim.api.nvim_buf_is_valid(bufnr) then claude_code.claude_code.instances[instance_id] = nil end
148-148
: Remove blank-only lines flagged by LuacheckLine 148 contains only whitespace (
W611
). Deleting it silences the linter.🧰 Tools
🪛 Luacheck (1.2.0)
[warning] 148-148: line contains only whitespace
(W611)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
📒 Files selected for processing (4)
CLAUDE.md
(1 hunks)lua/claude-code/config.lua
(3 hunks)lua/claude-code/init.lua
(2 hunks)lua/claude-code/terminal.lua
(6 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
CLAUDE.md
29-29: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
40-40: Fenced code blocks should be surrounded by blank lines
null
(MD031, blanks-around-fences)
🪛 Luacheck (1.2.0)
lua/claude-code/config.lua
[warning] 177-177: line contains only whitespace
(W611)
lua/claude-code/terminal.lua
[warning] 68-68: line contains only whitespace
(W611)
[warning] 77-77: line contains only whitespace
(W611)
[warning] 109-109: line contains only whitespace
(W611)
[warning] 111-111: line contains only whitespace
(W611)
[warning] 148-148: line contains only whitespace
(W611)
🔇 Additional comments (4)
lua/claude-code/config.lua (2)
82-83
: 👍 Good default formulti_instance
Adding
multi_instance = true
by default is sensible and keeps the new feature opt-out rather than opt-in. No issues spotted here.
178-180
: Validation block looks correctThe boolean check for
git.multi_instance
mirrors the pattern used for other fields and should prevent mis-configuration. No changes needed.lua/claude-code/init.lua (2)
64-66
: Great consolidation of buffer lookupReplacing repeated access to
M.claude_code.bufnr
with the helper keeps toggle logic agnostic to single vs multi-instance. 👍
88-90
: Reuse of helper maintains consistencySame remark as above—good reuse of
get_current_buffer_number()
.
Great PR, thank you. Can you go through the nitpicks and refactor suggestions from coderabbit before we merge it? |
Sure |
- Remove whitespace-only lines throughout codebase - Add nil-safe buffer validity checks - Add guard for instances table access - Add buffer cleanup logic to prune invalid entries
When multi_instance is enabled, now checks use_git_root config: - If true: uses git root as instance identifier - If false: uses current working directory as instance identifier This ensures instance ID respects user configuration preferences.
- Sanitize buffer names to avoid special characters that break :buffer commands - Update keymaps.lua to use instances table instead of single bufnr - Update file_refresh.lua to use instances table instead of single bufnr Note: Tests in terminal_spec.lua still need updating to work with instances table
- Completely rewrite terminal_spec.lua to test instances table instead of single bufnr - Add comprehensive tests for multi-instance functionality: - Instance creation and management - Git root vs current directory as instance identifier - Buffer name sanitization for special characters - Invalid buffer cleanup from instances table - Add tests for single-instance mode using 'global' key - Update force_insert_mode tests to work with instances table - All tests validate both single and multi-instance behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
lua/claude-code/keymaps.lua (1)
92-100
:⚠️ Potential issueAutocommands for only the last instance –
clear = true
wipes the others
vim.api.nvim_create_augroup('ClaudeCodeTerminalFocus', { clear = true })
is executed every timesetup_terminal_navigation()
is called (i.e. once per
instance).
Becauseclear = true
empties the existing group, the autocommands that
belong to previously-opened instances are silently removed.
Result: only the most recently initialised terminal keeps the automatic
“re-enter insert mode” behaviour, while earlier instances lose it.- local augroup = vim.api.nvim_create_augroup('ClaudeCodeTerminalFocus', { clear = true }) + -- use one group per buffer/instance or avoid clearing the shared group + local augroup = vim.api.nvim_create_augroup( + 'ClaudeCodeTerminalFocus_' .. buf, -- unique id + { clear = true } + )Alternatively, keep a single group but pass
{ clear = false }
and give each
autocmd a uniquedesc
/id
so they don't collide.
🧹 Nitpick comments (3)
tests/spec/terminal_spec.lua (1)
135-139
: Trailing whitespace – minor Luacheck warnings
luacheck
flags these lines asW611: line contains only whitespace
.
While harmless, removing the redundant spaces keeps the test file clean.Also applies to: 220-220, 247-247
🧰 Tools
🪛 Luacheck (1.2.0)
[warning] 135-135: line contains only whitespace
(W611)
lua/claude-code/terminal.lua (2)
69-80
: Consider optimizing the buffer check logic.The current implementation iterates through all instances to check if the current buffer matches any Claude instance buffer. This works correctly but could be inefficient with many instances. Consider a more direct approach:
- -- Check if current buffer is any of our Claude instances - local is_claude_instance = false - for _, bufnr in pairs(claude_code.claude_code.instances) do - if bufnr - and bufnr == current_bufnr - and vim.api.nvim_buf_is_valid(bufnr) - then - is_claude_instance = true - break - end - end + -- Check if current buffer is any of our Claude instances + local is_claude_instance = false + -- Create a reverse lookup for faster checking + local function is_valid_claude_buffer(buf_num) + for _, bufnr in pairs(claude_code.claude_code.instances) do + if bufnr == buf_num and vim.api.nvim_buf_is_valid(bufnr) then + return true + end + end + return false + end + is_claude_instance = is_valid_claude_buffer(current_bufnr)This creates a helper function that can be reused if needed elsewhere, making the code more maintainable.
140-142
: Consider adding feedback when pruning invalid buffers.When an invalid buffer is detected, the code correctly removes it from the instances table, but doesn't provide any feedback to the user. Consider adding a notification to help with debugging:
-- Prune invalid buffer entries if bufnr and not vim.api.nvim_buf_is_valid(bufnr) then claude_code.claude_code.instances[instance_id] = nil + vim.notify("Claude Code: Detected and pruned invalid buffer for instance: " .. instance_id, vim.log.levels.DEBUG) end
This would help users understand what's happening if they encounter unexpected behavior.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
lua/claude-code/config.lua
(3 hunks)lua/claude-code/file_refresh.lua
(1 hunks)lua/claude-code/init.lua
(2 hunks)lua/claude-code/keymaps.lua
(1 hunks)lua/claude-code/terminal.lua
(6 hunks)tests/spec/terminal_spec.lua
(7 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- lua/claude-code/init.lua
- lua/claude-code/config.lua
🧰 Additional context used
🪛 Luacheck (1.2.0)
tests/spec/terminal_spec.lua
[warning] 135-135: line contains only whitespace
(W611)
[warning] 220-220: line contains only whitespace
(W611)
[warning] 247-247: line contains only whitespace
(W611)
🔇 Additional comments (7)
lua/claude-code/keymaps.lua (1)
92-95
: Nil-safety guard looks fineRetrieving
current_instance
and the buffer from theinstances
table is the
right approach; the subsequentif buf and vim.api.nvim_buf_is_valid(buf)
check
prevents errors when no instance is active.
No changes required here.lua/claude-code/file_refresh.lua (1)
60-63
: Buffer resolution aligned with multi-instance designThe timer callback now resolves the buffer through
current_instance
➔instances[current_instance]
.
The nil/validity checks ensure thatchecktime
is only executed when an active
instance buffer is both valid and displayed. Looks good.lua/claude-code/terminal.lua (5)
11-17
: Good refactoring to support multi-instance architecture.The change from a single buffer reference to a table mapping instance IDs to buffer numbers is well-implemented and properly documented. The new
current_instance
field provides necessary state tracking.
20-31
: Well-designed instance identifier function.The
get_instance_identifier
function provides a solid foundation for the multi-instance feature, with appropriate fallback to the current working directory when not in a git repository. The documentation is thorough and clear.
104-116
: Good implementation of instance ID logic with proper config respect.The instance ID determination correctly considers both
multi_instance
anduse_git_root
configuration options, addressing the previous review feedback. This gives users flexibility in how instances are managed across different projects.
159-166
: Proper buffer name sanitization implemented.The buffer naming logic now correctly sanitizes the instance ID by replacing non-alphanumeric characters with hyphens, addressing the previous review feedback. This prevents potential issues with spaces and special characters in buffer names.
1-187
: Overall excellent implementation of multi-instance support.The refactoring to support multiple Claude Code instances is well-executed with a clean architecture. The code properly respects configuration options, sanitizes buffer names, and maintains backward compatibility. The changes address all the previous review feedback and introduce a valuable feature that will improve workflows across multiple projects.
- Fix test assertion: use assert.is_nil instead of assert.is_false for pattern matching - Fix autocommand collision: use unique group names per buffer instance - Remove trailing whitespace from test file These changes ensure multi-instance autocommands don't interfere with each other and fix the test assertion logic for buffer name sanitization validation.
@greggh anything left to do here? |
It looks like I need to do some more cleanup on the CI actions that are failing. I'll get to that this weekend. As for the PR, looks good to me. I'll fix all of these CI issues. Most aren't to do with this PR and have something to do with errors in the lua actions it seems. Thanks for the awesome PR. |
@ahdzib-maya thank you for the awesome PR 🙏 I'm curious if you thought about/know how this will behave with git worktrees - Anthropic recommends using them for parallel flows on the same project (https://docs.anthropic.com/en/docs/claude-code/tutorials#run-parallel-claude-code-sessions-with-git-worktrees). It probably comes down to how --- Get the current git root or a fallback identifier
--- @param git table The git module
--- @return string identifier Git root path or fallback identifier
local function get_instance_identifier(git)
local git_root = git.get_git_root()
if git_root then
return git_root
else
-- Fallback to current working directory if not in a git repo
return vim.fn.getcwd()
end
end I'll give this a try this weekend and let you know what I find. |
I actually just started using worktrees after seeing that. My guess is it'll work out of the box, but will try it in a bit. |
Confirmed. Works out of the box. Little extra note. When working with related repositories in which you need claude to know about them (faster without doing web/fetch) you can sym link, and it works as long as you run the instance on the parent (not the sym link) |
Pull Request: Add Multi-Instance Support for Claude Code
Description
This PR adds multi-instance support to the Claude Code Neovim plugin, allowing users to run multiple Claude Code instances simultaneously - one per git repository root. This feature improves workflow when working across multiple
projects in different tabs or windows.
Type of Change
Please check the options that are relevant:
Checklist
Please check all that apply:
Additional Notes
Key changes include:
git.multi_instance
(defaults totrue
)Summary by CodeRabbit
New Features
Documentation
Refactor