Skip to content

lucatume/agent-ask.nvim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-ask.nvim

Queue questions about lines/selections in neovim and flush them as one payload to a CLI coding agent (claude, codex, aider, …) running in an adjacent tmux pane.

<leader>aa opens a capture screen showing the current line or selection as a read-only fenced block; type a question below it and :wq to queue the entry (:q cancels). <leader>af opens a flush screen holding every queued entry as editable text plus a separate trailing-prompt field; :wq sends, :q cancels. The plugin resolves a target pane (from $TMUX_ORIGIN_PANE_ID if set, or a fallback split it manages itself), starts the agent if the pane is at a shell prompt, assembles the payload (file location plus, for selections, the selected code), and sends it.

Both screens are floating windows edited like a file: :wq (or ZZ) confirms, :q (or q) cancels.

demo

Requirements

  • neovim 0.10+
  • tmux (the surrounding terminal must be inside a tmux session)
  • a CLI coding agent in $PATH (default: claude)

Installation

With lazy.nvim:

{
  'lucatume/agent-ask.nvim',
  cmd = { 'AgentAsk', 'AgentSend', 'AgentClear' },
  keys = {
    { '<leader>aa', mode = { 'n', 'v' }, desc = 'agent: ask' },   -- capture current line/selection
    { '<leader>af', mode = 'n',          desc = 'agent: send' },  -- flush queue
  },
  config = function()
    require('agent-ask').setup({})
  end,
}

Configuration

setup() accepts a table merged over the defaults:

require('agent-ask').setup({
  agent           = { cmd = 'claude', args = {} },
  agent_processes = { 'claude', 'codex', 'aider', 'pi' },
  shell_processes = { 'zsh', 'bash', 'fish', 'sh', 'dash', 'ksh', 'tcsh' },
  fallback_split  = { direction = 'right', size = '50%' },
  format          = 'auto',  -- 'auto' | 'file'
  agent_startup_timeout_ms = 8000,
  agent_startup_poll_ms    = 100,
  agent_postinit_delay_ms  = 500,
  paste_settle_ms          = 150,
  keymaps = { ask = '<leader>aa', send = '<leader>af' },
})

format:

  • auto (default) — file reference for current-line context on disk; file reference plus fenced code block for visual selections; fenced code block with a comment header for unsaved buffers.
  • file — always send In path:range: question, no code body.

Commands

  • :AgentAsk — open the capture screen for the current line: a read-only fenced block on top, an editable prompt area below. :wq queues the entry, :q cancels. An empty prompt on :wq queues nothing.
  • :'<,'>AgentAsk (or :N,MAgentAsk) — capture a range; the selection is shown as the fenced block and included in the per-entry payload.
  • :AgentSend — open the flush screen: the assembled queue as editable text, a separator, then a trailing-prompt field. Edit freely, then :wq to send (trailing text, if any, is appended after the queue) or :q to cancel without sending. A no-op on an empty queue.
  • :AgentClear — empty the queue.

:AgentSend auto-resolves the target pane and starts the agent if the pane is at a shell prompt — there is no separate start command.

How the target pane is resolved

  1. $TMUX_ORIGIN_PANE_ID if set and the pane still exists. Set this in the shell that launches neovim to anchor the agent next to a specific pane.
  2. The fallback pane this plugin previously created, if it still exists.
  3. A new split (direction/size from fallback_split).

If the resolved pane is at a shell prompt, the agent is started before the prompt is sent.

I drive this with a Cmd+K shortcut in tmux: from any pane, it splits right, opens nvim there, and forwards the originating pane id so the agent lands back in the pane I came from. Tmux sees Cmd+K as M-k once the terminal forwards it as ESC+k:

# in ~/.tmux.conf
bind -n M-k run-shell "tmux split-window -h \
  -t '#{pane_id}' \
  -c '#{pane_current_path}' \
  -e 'TMUX_ORIGIN_PANE_ID=#{pane_id}' \
  'nvim .'"

-e does not format-expand its argument, so the binding wraps the whole command in run-shell and lets tmux expand #{pane_id} first.

Note for Ghostty: by default super+k is bound to clear_screen and never reaches tmux. Override it to send ESC+k instead:

# in ~/.config/ghostty/config
keybind = super+k=text:\x1bk

macos-option-as-alt defaults to false, so Option+K still types ˚ and does not collide with this binding.

Development

Tests use plenary.nvim's busted runner. Plenary is expected at ~/.local/share/nvim/lazy/plenary.nvim (the default lazy install location); adjust tests/minimal_init.lua if it lives elsewhere.

make test

Spec layout:

tests/
  minimal_init.lua    # rtp bootstrap
  config_spec.lua
  context_spec.lua
  payload_spec.lua
  tmux_spec.lua
  queue_spec.lua
  assemble_spec.lua

When fixing a bug or adding behaviour, write the failing spec first, then make it pass.

About

Queue line/selection questions in neovim and flush them as one payload to a CLI coding agent in an adjacent tmux pane.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors