A native Lua plugin for ezstack. Browse your stacks in a styled buffer, jump between worktrees with Telescope, see your stack in the statusline, and run the full :Ezs command suite — all without leaving Neovim.
Run :Ezs to open the stack viewer in a split. It's a non-modifiable buffer that renders every stack with PR state, CI status, and review info — with a focused keymap for everything you'd want to do.
The viewer is a normal Neovim buffer — cursor position is preserved on refresh, and it plays nicely with windows, tabs, and your colorscheme.
" :Ezs opens the viewer
Stack: my-feature [a1b2c3d] root: main
─────────────────────────────────────────────────────────────────
> ├── feature-1 PR #100 [OPEN] CI: 3/3 +120 -8 (→ main)
├── feature-2 PR #101 [DRAFT] CI: pending +50 -2 (→ feature-1)
└── feature-3 [no PR] (→ feature-1)
Every common operation is one keystroke away inside the viewer. Press ? for the help popup.
<CR> # goto worktree
o # open PR in browser
r # refresh R rename stack
n # new branch d delete branch under cursor
p # push branch P push entire stack
s # sync (terminal) c continue an in-progress sync
u # update PR D diff against parent
a # open agent A build feature with agent
? # help q close viewer
The viewer refreshes after every CLI mutation through the User EzstackChanged autocommand. With vim-fugitive installed, it also refreshes on FugitiveChanged.
" Hook your own logic into refreshes
autocmd User EzstackChanged echom "stack updated"
autocmd User EzstackGoto echom "switched worktree"
The plugin exposes a single :Ezs user command with subcommand and flag completion. Everything the CLI can do, you can do without leaving Neovim.
Create branches, navigate the stack, sync, push, and reparent. Sync and commit run in a Neovim terminal split so you can resolve conflicts in place.
:Ezs new feature-1 main # create stacked branch
:Ezs goto feature-1 # switch worktree (tcd)
:Ezs up / :Ezs down # move along the stack
:Ezs sync -s # sync entire stack
:Ezs sync --continue # resume after conflicts
:Ezs push -s # push every branch in the stack
:Ezs reparent feature-2 main # move branch to a new parent
:Ezs delete feature-3 # delete branch + worktree
Create, update, merge, and toggle draft for the current branch's PR. :Ezs pr stack updates the navigation table in every PR description in the stack.
:Ezs pr create "Part 1: scaffold"
:Ezs pr update # push + refresh PR
:Ezs pr draft # toggle draft / ready
:Ezs pr merge # prompts for method
:Ezs pr stack # refresh stack tables
:Ezs pr open # open in browser
Launch the ezstack AI agent or build a feature as stacked PRs — from inside Neovim. View, edit, and reset prompts across all three layers (shipped, custom, repo).
:Ezs agent # branch- or stack-scoped agent
:Ezs agent feature "add JWT auth"
:Ezs agent prompt # view shipped prompts
:Ezs agent prompt edit work # edit custom layer in nvim
:Ezs agent prompt edit repo feature # edit repo layer
:Ezs agent prompt reset work
If you have telescope.nvim installed, the bundled extension gives you fuzzy pickers for branches and stacks. When Telescope isn't available, :Ezs goto falls back to vim.ui.select.
Browse every branch across every stack with PR and CI info inline. Jump straight to a worktree, or run actions on the entry under your cursor.
:Telescope ezstack branches
<CR> # goto worktree
<C-o> # open PR in browser
<C-d> # delete branch
<C-p> # push branch
Browse stacks at the top level. Open a stack in the viewer, or rename it inline.
:Telescope ezstack stacks
<CR> # open stack viewer
<C-r> # rename stack
Drop the current branch and stack into your statusline. Results are cached (default: 5s) so it never hammers the CLI.
-- lualine example
require("lualine").setup({
sections = {
lualine_b = {
"branch",
{ function() return require("ezstack").statusline() end },
},
},
})
-- renders: feature-1 | my-feature [a1b2c3d]
Requires Neovim 0.10+ and the ezs CLI on your $PATH. Telescope and fugitive are optional but recommended.
Lazy-load the plugin on first :Ezs with a single spec entry. :Ezs is also registered eagerly when the plugin is on the runtimepath, so it works without an explicit setup() call.
{
"KulkarniKaustubh/ezstack",
subdir = "neovim-plugin",
cmd = { "Ezs" },
keys = { { "<leader>ez", "<cmd>Ezs<cr>" } },
config = function()
require("ezstack").setup()
require("telescope").load_extension("ezstack")
end,
}
Use the rtp field to point Packer at the neovim-plugin/ subdirectory of the repo.
use {
"KulkarniKaustubh/ezstack",
rtp = "neovim-plugin",
config = function()
require("ezstack").setup()
end,
}
Pass these to require("ezstack").setup({ ... }).
| Option | Default | Description |
|---|---|---|
cli_path |
"ezs" |
Path to the ezs binary. Auto-discovered from common bin dirs if missing on $PATH. |
auto_refresh |
true |
Refresh the viewer on FugitiveChanged and EzstackChanged. |
viewer_position |
"botright" |
Split position for the stack viewer. |
viewer_height |
15 |
Stack viewer window height. |
statusline_cache_ttl |
5000 |
Statusline cache TTL in milliseconds. |
goto_strategy |
"tcd" |
Worktree switch strategy: "tcd" (tab-local), "cd" (global), "lcd" (window). |
goto_close_buffers |
false |
Close unmodified buffers from the previous worktree on goto. |
goto_open_explorer |
true |
Open your file explorer at the new worktree root after goto. |