Skip to content

Commit a373afb

Browse files
committed
Add multiple instance per git root
1 parent a021225 commit a373afb

File tree

4 files changed

+96
-13
lines changed

4 files changed

+96
-13
lines changed

CLAUDE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ Claude Code Plugin provides seamless integration between the Claude Code AI assi
2626
- Implementing better context synchronization
2727
- Adding buffer-specific context management
2828

29+
## Multi-Instance Support
30+
The plugin supports running multiple Claude Code instances, one per git repository root:
31+
32+
- Each git repository maintains its own Claude instance
33+
- Works across multiple Neovim tabs with different projects
34+
- Allows working on multiple projects in parallel
35+
- Configurable via `git.multi_instance` option (defaults to `true`)
36+
- Instances remain in their own directory context when switching between tabs
37+
- Buffer names include the git root path for easy identification
38+
39+
Example configuration to disable multi-instance mode:
40+
```lua
41+
require('claude-code').setup({
42+
git = {
43+
multi_instance = false -- Use a single global Claude instance
44+
}
45+
})
46+
```
47+
2948
## Documentation Links
3049
- Tasks: `/home/gregg/Projects/docs-projects/neovim-ecosystem-docs/tasks/claude-code-tasks.md`
3150
- Project Status: `/home/gregg/Projects/docs-projects/neovim-ecosystem-docs/project-status.md`

lua/claude-code/config.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ local M = {}
2525
--- ClaudeCodeGit class for git integration configuration
2626
-- @table ClaudeCodeGit
2727
-- @field use_git_root boolean Set CWD to git root when opening Claude Code (if in git project)
28+
-- @field multi_instance boolean Use multiple Claude instances (one per git root)
2829

2930
--- ClaudeCodeKeymapsToggle class for toggle keymap configuration
3031
-- @table ClaudeCodeKeymapsToggle
@@ -78,6 +79,7 @@ M.default_config = {
7879
-- Git integration settings
7980
git = {
8081
use_git_root = true, -- Set CWD to git root when opening Claude Code (if in git project)
82+
multi_instance = true, -- Use multiple Claude instances (one per git root)
8183
},
8284
-- Command settings
8385
command = 'claude', -- Command used to launch Claude Code
@@ -172,6 +174,10 @@ local function validate_config(config)
172174
if type(config.git.use_git_root) ~= 'boolean' then
173175
return false, 'git.use_git_root must be a boolean'
174176
end
177+
178+
if type(config.git.multi_instance) ~= 'boolean' then
179+
return false, 'git.multi_instance must be a boolean'
180+
end
175181

176182
-- Validate command settings
177183
if type(config.command) ~= 'string' then

lua/claude-code/init.lua

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,25 @@ function M.force_insert_mode()
4444
terminal.force_insert_mode(M, M.config)
4545
end
4646

47+
--- Get the current active buffer number
48+
--- @return number|nil bufnr Current Claude instance buffer number or nil
49+
local function get_current_buffer_number()
50+
-- Get current instance from the instances table
51+
local current_instance = M.claude_code.current_instance
52+
if current_instance then
53+
return M.claude_code.instances[current_instance]
54+
end
55+
return nil
56+
end
57+
4758
--- Toggle the Claude Code terminal window
4859
--- This is a public function used by commands
4960
function M.toggle()
5061
terminal.toggle(M, M.config, git)
5162

5263
-- Set up terminal navigation keymaps after toggling
53-
if M.claude_code.bufnr and vim.api.nvim_buf_is_valid(M.claude_code.bufnr) then
64+
local bufnr = get_current_buffer_number()
65+
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
5466
keymaps.setup_terminal_navigation(M, M.config)
5567
end
5668
end
@@ -73,7 +85,8 @@ function M.toggle_with_variant(variant_name)
7385
terminal.toggle(M, M.config, git)
7486

7587
-- Set up terminal navigation keymaps after toggling
76-
if M.claude_code.bufnr and vim.api.nvim_buf_is_valid(M.claude_code.bufnr) then
88+
local bufnr = get_current_buffer_number()
89+
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
7790
keymaps.setup_terminal_navigation(M, M.config)
7891
end
7992

lua/claude-code/terminal.lua

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,28 @@ local M = {}
88

99
--- Terminal buffer and window management
1010
-- @table ClaudeCodeTerminal
11-
-- @field bufnr number|nil Buffer number of the Claude Code terminal
11+
-- @field instances table Key-value store of git root to buffer number
1212
-- @field saved_updatetime number|nil Original updatetime before Claude Code was opened
13+
-- @field current_instance string|nil Current git root path for active instance
1314
M.terminal = {
14-
bufnr = nil,
15+
instances = {},
1516
saved_updatetime = nil,
17+
current_instance = nil,
1618
}
1719

20+
--- Get the current git root or a fallback identifier
21+
--- @param git table The git module
22+
--- @return string identifier Git root path or fallback identifier
23+
local function get_instance_identifier(git)
24+
local git_root = git.get_git_root()
25+
if git_root then
26+
return git_root
27+
else
28+
-- Fallback to current working directory if not in a git repo
29+
return vim.fn.getcwd()
30+
end
31+
end
32+
1833
--- Create a split window according to the specified position configuration
1934
--- @param position string Window position configuration
2035
--- @param config table Plugin configuration containing window settings
@@ -49,8 +64,18 @@ end
4964
--- @param claude_code table The main plugin module
5065
--- @param config table The plugin configuration
5166
function M.force_insert_mode(claude_code, config)
52-
local bufnr = claude_code.claude_code.bufnr
53-
if bufnr and vim.api.nvim_buf_is_valid(bufnr) and vim.fn.bufnr '%' == bufnr then
67+
local current_bufnr = vim.fn.bufnr('%')
68+
69+
-- Check if current buffer is any of our Claude instances
70+
local is_claude_instance = false
71+
for _, bufnr in pairs(claude_code.claude_code.instances) do
72+
if bufnr == current_bufnr and vim.api.nvim_buf_is_valid(bufnr) then
73+
is_claude_instance = true
74+
break
75+
end
76+
end
77+
78+
if is_claude_instance then
5479
-- Only enter insert mode if we're in the terminal buffer and not already in insert mode
5580
-- and not configured to stay in normal mode
5681
if config.window.start_in_normal_mode then
@@ -72,10 +97,22 @@ end
7297
--- @param config table The plugin configuration
7398
--- @param git table The git module
7499
function M.toggle(claude_code, config, git)
75-
-- Check if Claude Code is already running
76-
local bufnr = claude_code.claude_code.bufnr
100+
-- Determine instance ID based on config
101+
local instance_id
102+
if config.git.multi_instance then
103+
-- Use git root or current directory as instance identifier
104+
instance_id = get_instance_identifier(git)
105+
else
106+
-- Use a fixed ID for single instance mode
107+
instance_id = "global"
108+
end
109+
110+
claude_code.claude_code.current_instance = instance_id
111+
112+
-- Check if this Claude Code instance is already running
113+
local bufnr = claude_code.claude_code.instances[instance_id]
77114
if bufnr and vim.api.nvim_buf_is_valid(bufnr) then
78-
-- Check if there's a window displaying Claude Code buffer
115+
-- Check if there's a window displaying this Claude Code buffer
79116
local win_ids = vim.fn.win_findbuf(bufnr)
80117
if #win_ids > 0 then
81118
-- Claude Code is visible, close the window
@@ -93,7 +130,7 @@ function M.toggle(claude_code, config, git)
93130
end
94131
end
95132
else
96-
-- Claude Code is not running, start it in a new split
133+
-- This Claude Code instance is not running, start it in a new split
97134
create_split(config.window.position, config)
98135

99136
-- Determine if we should use the git root directory
@@ -108,7 +145,15 @@ function M.toggle(claude_code, config, git)
108145

109146
vim.cmd(cmd)
110147
vim.cmd 'setlocal bufhidden=hide'
111-
vim.cmd 'file claude-code'
148+
149+
-- Create a unique buffer name (or a standard one in single instance mode)
150+
local buffer_name
151+
if config.git.multi_instance then
152+
buffer_name = 'claude-code-' .. instance_id:gsub('[/\\\\]', '-')
153+
else
154+
buffer_name = 'claude-code'
155+
end
156+
vim.cmd('file ' .. buffer_name)
112157

113158
if config.window.hide_numbers then
114159
vim.cmd 'setlocal nonumber norelativenumber'
@@ -118,8 +163,8 @@ function M.toggle(claude_code, config, git)
118163
vim.cmd 'setlocal signcolumn=no'
119164
end
120165

121-
-- Store buffer number for future reference
122-
claude_code.claude_code.bufnr = vim.fn.bufnr '%'
166+
-- Store buffer number for this instance
167+
claude_code.claude_code.instances[instance_id] = vim.fn.bufnr('%')
123168

124169
-- Automatically enter insert mode in terminal unless configured to start in normal mode
125170
if config.window.enter_insert and not config.window.start_in_normal_mode then

0 commit comments

Comments
 (0)