A lightweight, extensible chat plugin for Neovim with AI integration. Chat with AI assistants directly in your editor using a clean, floating window interface.

@read_file, @find_files, @search_text), version control (@git_diff, @git_log, @git_status, @git_show), conversation history (@get_history), memory management...@zettelkasten_create and @zettelkasten_get tools for knowledge management (requires zettelkasten.nvim):Chat new), navigating (:Chat prev/next), clearing (:Chat clear), deleting (:Chat delete), saving (:Chat save), loading (:Chat load), sharing (:Chat share), bridging (:Chat bridge), previewing (:Chat preview), and changing working directory (:Chat cd)picker-chat), switching providers (chat_provider), and selecting models (chat_model)Ctrl-C) and retry mechanism (r):Chat preview command or <C-o> in pickerlua/chat/tools/<tool_name>.lua with automatic discoverySystem Dependencies (optional but recommended for full functionality):
ripgrep (rg): Required for the @search_text tool
curl: Required for the @fetch_web tool
git: Required for the @git_diff tool
Install with your package manager:
# Ubuntu/Debian
sudo apt install ripgrep curl git
# macOS
brew install ripgrep curl git
# Arch Linux
sudo pacman -S ripgrep curl git
Neovim Plugin Dependencies:
job.nvim: Required dependency for asynchronous operationspicker.nvim: Recommended for enhanced session and provider managementrequire('plug').add({
{
'wsdjeg/chat.nvim',
depends = {
{
'wsdjeg/job.nvim', -- Required
'wsdjeg/picker.nvim', -- Optional but recommended
},
},
},
})
{
'wsdjeg/chat.nvim',
dependencies = {
'wsdjeg/job.nvim', -- Required
'wsdjeg/picker.nvim', -- Optional but recommended
},
}
use({
'wsdjeg/chat.nvim',
requires = {
'wsdjeg/job.nvim', -- Required
'wsdjeg/picker.nvim', -- Optional but recommended
},
})
If you're not using a package manager:
Clone the repositories:
git clone https://github.com/wsdjeg/chat.nvim ~/.local/share/nvim/site/pack/chat/start/chat.nvim
git clone https://github.com/wsdjeg/job.nvim ~/.local/share/nvim/site/pack/chat/start/job.nvim
Add to your Neovim configuration (~/.config/nvim/init.lua or ~/.config/nvim/init.vim):
vim.cmd[[packadd job.nvim]]
vim.cmd[[packadd chat.nvim]]
require('chat').setup({
-- Your configuration here
})
api_key tableallowed_path to control which directories tools can accessAfter installation, you can immediately start using chat.nvim:
:Chat " Open chat window
:Chat new " Start a new session
:Chat prev " Switch to previous session
:Chat next " Switch to next session
For detailed usage instructions, see the Usage section.
chat.nvim provides flexible configuration options through the require('chat').setup() function. All configurations have sensible defaults.
| Option | Type | Default | Description |
|---|---|---|---|
width |
number | 0.8 |
Chat window width (percentage of screen width, 0.0-1.0) |
height |
number | 0.8 |
Chat window height (percentage of screen height, 0.0-1.0) |
auto_scroll |
boolean | true |
Controls automatic scrolling behavior of the result window |
border |
string | 'rounded' |
Window border style, supports all Neovim border options |
provider |
string | 'deepseek' |
Default AI provider |
model |
string | 'deepseek-chat' |
Default AI model |
strftime |
string | '%m-%d %H:%M:%S' |
Time display format |
system_prompt |
string or function | '' |
Default system prompt, can be a string or a function that returns a string |
highlights |
table | {title = 'ChatNvimTitle', title_badge = 'ChatNvimTitleBadge'} |
Highlight groups for title text and decorative badges |
Configure the built-in HTTP server for receiving external messages:
| Option | Type | Default | Description |
|---|---|---|---|
http.host |
string | '127.0.0.1' |
Host address for the HTTP server |
http.port |
number | 7777 |
Port number for the HTTP server |
http.api_key |
string | 'test_chat_nvim' |
API key for authenticating incoming requests (must be set to enable server) |
Example configuration:
http = {
host = '127.0.0.1',
port = 7777,
api_key = 'your-secret-api-key-here', -- Set to empty string to disable HTTP server
}
Notes:
http.api_key is not emptyX-API-Key headerConfigure API keys for the AI providers you plan to use:
api_key = {
deepseek = 'sk-xxxxxxxxxxxx', -- DeepSeek AI
github = 'github_pat_xxxxxxxx', -- GitHub AI
moonshot = 'sk-xxxxxxxxxxxx', -- Moonshot AI
openrouter = 'sk-or-xxxxxxxx', -- OpenRouter
qwen = 'qwen-xxxxxxxx', -- Alibaba Qwen
siliconflow = 'xxxxxxxx-xxxx-xxxx', -- SiliconFlow
tencent = 'xxxxxxxx-xxxx-xxxx', -- Tencent Hunyuan
bigmodel = 'xxxxxxxx-xxxx-xxxx', -- BigModel AI
volcengine = 'xxxxxxxx-xxxx-xxxx', -- Volcengine AI
openai = 'sk-xxxxxxxxxxxx', -- OpenAI
longcat = 'lc-xxxxxxxxxxxx', -- LongCat AI
cherryin = 'sk-xxxxxxxxxxxx', -- CherryIN AI
}
Only configure keys for providers you plan to use; others can be omitted.
Control which file paths tools can access for security:
-- Option 1: Disable all file access (default)
allowed_path = ''
-- Option 2: Allow a single directory
allowed_path = '/home/user/projects'
-- Option 3: Allow multiple directories
allowed_path = {
vim.fn.getcwd(), -- Current working directory
vim.fn.expand('~/.config/nvim'), -- Neovim config directory
'/etc', -- System configuration files
}
Configure automatic context truncation to manage token usage:
context = {
enable = true, -- Enable/disable context truncation
trigger_threshold = 50, -- Number of messages to trigger truncation
keep_recent = 10, -- Keep recent N messages (not included in truncation search)
}
Notes:
trigger_threshold messages, older messages may be summarized or removedkeep_recent parameter ensures recent context is preservedchat.nvim implements a sophisticated three-tier memory system inspired by cognitive psychology:
Memory Architecture:
Configuration:
memory = {
enable = true, -- Global memory system switch
-- Long-term memory: Permanent knowledge (never expires)
long_term = {
enable = true,
max_memories = 500, -- Maximum memories to store
retrieval_limit = 3, -- Maximum memories to retrieve per query
similarity_threshold = 0.3, -- Text similarity threshold (0-1)
},
-- Daily memory: Temporary tasks and goals (auto-expires)
daily = {
enable = true,
retention_days = 7, -- Days before auto-deletion
max_memories = 100, -- Maximum daily memories
similarity_threshold = 0.3,
},
-- Working memory: Current session focus (highest priority)
working = {
enable = true,
max_memories = 20, -- Maximum working memories per session
priority_weight = 2.0, -- Priority multiplier (higher = more important)
},
-- Storage location
storage_dir = vim.fn.stdpath('cache') .. '/chat.nvim/memory/',
}
Memory Type Characteristics:
| Type | Lifetime | Priority | Use Case |
|---|---|---|---|
| Working | Session only | Highest | Current tasks, decisions, active context |
| Daily | 7-30 days | Medium | Short-term goals, today's tasks, reminders |
| Long-term | Permanent | Normal | Facts, preferences, skills, knowledge |
Auto-Detection:
The @extract_memory tool automatically detects memory type based on keywords:
Example Usage:
-- Minimal configuration (use defaults)
memory = {
enable = true,
}
-- Disable specific memory types
memory = {
enable = true,
working = { enable = false },
daily = { enable = false },
}
-- Adjust retention and capacity
memory = {
enable = true,
long_term = {
max_memories = 1000,
retrieval_limit = 5,
},
daily = {
retention_days = 14,
max_memories = 200,
},
working = {
max_memories = 30,
priority_weight = 3.0,
},
}
Notes:
retention_daysHere are different ways to use the system_prompt option:
String (simple):
system_prompt = 'You are a helpful programming assistant.',
Function loading from file:
system_prompt = function()
local path = vim.fn.expand('~/.config/nvim/AGENTS.md')
if vim.fn.filereadable(path) == 1 then
return table.concat(vim.fn.readfile(path), '\n')
end
return 'Default system prompt'
end
Function with project-specific prompts:
system_prompt = function()
local cwd = vim.fn.getcwd()
if string.find(cwd, 'chat%.nvim') then
return 'You are a specialized assistant for chat.nvim plugin development.'
elseif string.find(cwd, 'picker%.nvim') then
return 'You are a specialized assistant for picker.nvim plugin development.'
end
return 'You are a general programming assistant.'
end
Function with time-based prompts:
system_prompt = function()
local hour = tonumber(os.date("%H"))
local day = os.date("%A")
return string.format('Good %s! Today is %s. I am your AI assistant.',
hour < 12 and 'morning' or hour < 18 and 'afternoon' or 'evening',
day)
end
chat.nvim supports Model Context Protocol (MCP) servers for extended tool capabilities. MCP allows you to connect external tool servers that provide additional functionality.
Supported Transports:
Basic Configuration (stdio transport):
mcp = {
-- Example: Web search MCP server using stdio transport
open_webSearch = {
command = 'npx',
args = { '-y', 'open-websearch@latest' },
disabled = false, -- Set to true to disable this server
},
-- Example: Another stdio MCP server
my_custom_server = {
command = '/path/to/mcp-server',
args = { '--config', '/path/to/config.json' },
},
}
HTTP Transport Configuration:
For HTTP-based MCP servers, use the streamable_http transport:
mcp = {
-- HTTP-based MCP server
my_http_server = {
url = 'https://mcp-server.example.com',
headers = {
['Authorization'] = 'Bearer YOUR_TOKEN',
},
},
-- HTTP server with command to start
my_managed_http_server = {
command = 'my-mcp-http-server',
args = { '--port', '8080' },
url = 'http://localhost:8080',
transport = {
type = 'streamable_http',
url = 'http://localhost:8080',
},
},
}
Transport Configuration Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
command |
string | โ No* | Path to MCP server executable (required for stdio) |
args |
array | โ No | Command-line arguments for the server |
url |
string | โ No* | HTTP URL for streamable_http transport |
headers |
table | โ No | HTTP headers (key-value pairs) |
transport |
table | โ No | Explicit transport configuration |
transport.type |
string | โ No | Transport type: "stdio" or "streamable_http" |
transport.url |
string | โ No | Override URL for transport |
transport.headers |
table | โ No | Override headers for transport |
disabled |
boolean | โ No | Set to true to disable this server (default: false) |
*Either command (for stdio) or url (for HTTP) is required.
MCP Tool Naming:
MCP tools are automatically prefixed with mcp_<server>_<tool> format:
searchopen_webSearchmcp_open_webSearch_searchUsage in Chat:
@mcp_open_webSearch_search query="neovim plugins" limit=10
Key Features:
Complete Example:
require('chat').setup({
-- ... other configuration
-- MCP servers configuration
mcp = {
-- Stdio-based MCP server
open_webSearch = {
command = 'npx',
args = { '-y', 'open-websearch@latest' },
},
-- HTTP-based MCP server
remote_tools = {
url = 'https://mcp-api.example.com',
headers = {
['Authorization'] = 'Bearer YOUR_API_KEY',
},
},
-- Managed HTTP server (starts local process)
local_http_server = {
command = 'my-mcp-server',
args = { '--port', '3000' },
transport = {
type = 'streamable_http',
url = 'http://localhost:3000',
},
},
-- Disabled server (won't start)
experimental = {
command = 'mcp-experimental',
disabled = true,
},
},
})
Transport Detection:
chat.nvim automatically detects the transport type:
transport.type is specified, use that transportcommand exists without transport, use stdio transporturl exists without command, use streamable_http transportNotes:
:messages for connection issues:Chat mcp commands for manual server managementTroubleshooting:
command path is correct and executableFor more information about MCP, see the Model Context Protocol specification.
Configure instant messaging platform integrations for remote AI interaction:
integrations = {
-- Discord
discord = {
token = 'YOUR_DISCORD_BOT_TOKEN', -- Discord bot token
channel_id = 'YOUR_CHANNEL_ID', -- Discord channel ID
},
-- Lark (Feishu)
lark = {
app_id = 'YOUR_APP_ID', -- Lark app ID
app_secret = 'YOUR_APP_SECRET', -- Lark app secret
chat_id = 'YOUR_CHAT_ID', -- Lark chat ID
},
-- DingTalk
dingtalk = {
-- Webhook mode (one-way, simpler)
webhook = 'https://oapi.dingtalk.com/robot/send?access_token=XXX',
-- OR API mode (two-way, requires app credentials)
app_key = 'YOUR_APP_KEY',
app_secret = 'YOUR_APP_SECRET',
conversation_id = 'YOUR_CONVERSATION_ID',
user_id = 'YOUR_USER_ID',
},
-- WeCom (Enterprise WeChat)
wecom = {
-- Webhook mode (one-way, simpler)
webhook_key = 'YOUR_WEBHOOK_KEY',
-- OR API mode (two-way, requires corporate credentials)
corp_id = 'YOUR_CORP_ID',
corp_secret = 'YOUR_CORP_SECRET',
agent_id = 'YOUR_AGENT_ID',
user_id = 'YOUR_USER_ID',
},
-- Telegram
telegram = {
bot_token = 'YOUR_BOT_TOKEN', -- Telegram bot token
chat_id = 'YOUR_CHAT_ID', -- Telegram chat ID
},
},
Platform Comparison:
| Platform | Mode | Bidirectional | Setup Complexity | Message Limit |
|---|---|---|---|---|
| Discord | Bot API | โ Yes | Medium | 2,000 chars |
| Lark | Bot API | โ Yes | Medium | 30,720 chars |
| DingTalk | Webhook | โ No | Low | 20,000 chars |
| DingTalk | API | โ Yes | High | 20,000 chars |
| WeCom | Webhook | โ No | Low | 2,048 chars |
| WeCom | API | โ Yes | High | 2,048 chars |
| Telegram | Bot API | โ Yes | Low | 4,096 chars |
require('chat').setup({
-- Window settings
width = 0.8,
height = 0.8,
auto_scroll = true, -- Enable smart auto-scrolling (default)
border = 'rounded',
-- AI provider settings
provider = 'deepseek',
model = 'deepseek-chat',
api_key = {
deepseek = 'sk-xxxxxxxxxxxx',
github = 'github_pat_xxxxxxxx',
},
-- HTTP server configuration
http = {
host = '127.0.0.1',
port = 7777,
api_key = 'your-secret-key-here', -- Set to empty string to disable
},
-- File access control
allowed_path = {
vim.fn.getcwd(), -- Current working directory
vim.fn.expand('~/.config/nvim'), -- Neovim config directory
},
-- Other settings
strftime = '%Y-%m-%d %H:%M',
system_prompt = function()
local path = vim.fn.expand('./AGENTS.md')
if vim.fn.filereadable(path) == 1 then
return table.concat(vim.fn.readfile(path), '\n')
end
return 'You are a helpful programming assistant.'
end,
-- Memory system
memory = {
enable = true,
max_memories = 1000,
retrieval_limit = 5,
similarity_threshold = 0.25,
},
-- IM Integrations (configure platforms you need)
integrations = {
-- Discord
discord = {
token = 'YOUR_DISCORD_BOT_TOKEN',
channel_id = 'YOUR_CHANNEL_ID',
},
-- Add other platforms as needed...
},
-- MCP servers configuration
mcp = {
--https://github.com/Aas-ee/open-webSearch
open_webSearch = {
command = 'npx',
args = {
'-y',
'open-websearch@latest',
},
},
},
})
allowed_path restricts which file paths tools can access. Empty string disables all file access. Recommended to set to your current project directory for security.memory.enable = false.http.api_key to enable the HTTP server. The server binds to localhost by default for security.auto_scroll option controls whether the result window automatically scrolls to show new content. When enabled (default), it only scrolls if the cursor was already at the bottom, preventing interruptions when reviewing history.system_prompt option can be either a string or a function that returns a string. When a function is provided, it is called each time a new session is created, allowing for dynamic prompts based on time, project context, or external files. The function should handle errors gracefully and return a string value.chat.nvim provides several commands to manage your AI conversations.
The main command is :Chat, which opens the chat window.
You can also navigate between sessions using the following commands.
| Command | Description |
|---|---|
:Chat |
Open the chat window with the current session |
:Chat new |
Start a new chat session |
:Chat prev |
Switch to the previous chat session |
:Chat next |
Switch to the next chat session |
:Chat delete |
Delete current session and create new empty session |
:Chat clear |
Clear all messages in current session |
:Chat cd <dir> |
Change current session cwd, open chat window |
:Chat save <path> |
Save current session to specified file path |
:Chat load <path> |
Load session from file path or URL |
:Chat share |
Share current session via pastebin |
:Chat preview |
Open HTML preview of current session in browser |
:Chat bridge |
Bind current session to external platform (Discord) |
:Chat mcp stop |
Stop all MCP servers |
:Chat mcp start |
Start all MCP servers |
:Chat mcp restart |
Restart all MCP servers |
Manage MCP (Model Context Protocol) servers with the following commands:
Stop MCP servers:
:Chat mcp stop
Stops all running MCP servers and cleans up resources.
Start MCP servers:
:Chat mcp start
Starts all configured MCP servers. Note: Servers are automatically started when opening the chat window.
Restart MCP servers:
:Chat mcp restart
Restarts all MCP servers (stops and starts with a delay for cleanup).
Notes:
:Chat)chat.nvim supports running multiple chat sessions simultaneously, with each session operating independently:
:Chat prev and :Chat next to navigate between active sessionsWorkflow Example:
:Chat new (then select DeepSeek model):Chat new (select GitHub model):Chat prev / :Chat nextStart a new conversation:
:Chat new
This creates a fresh session and opens the chat window.
Resume a previous conversation:
:Chat prev
Cycles backward through your saved sessions.
Switch to the next conversation:
:Chat next
Cycles forward through your saved sessions.
Open or forced to the chat window:
:Chat
This command will not change current sessions.
Delete current session:
:Chat delete
Cycles to next session or create a new session if current session is latest one.
Change the working directory of current session:
:Chat cd ../picker.nvim/
If the current session is in progress, the working directory will not be changed, and a warning message will be printed.
Clear messages in current session:
:Chat clear
If the current session is in progress, a warning message will be printed, and current session will not be cleared. This command also will forced to chat window.
Work with multiple parallel sessions:
" Start first session with DeepSeek
:Chat new
" Select DeepSeek as provider and choose a model
" Start second session with GitHub AI
:Chat new
" Select GitHub as provider and choose a model
" Switch between sessions
:Chat prev " Go to first session
:Chat next " Go to second session
This enables simultaneous conversations with different AI assistants for different tasks.
Save current session to a file:
:Chat save ~/sessions/my-session.json
Saves the current session to a JSON file for backup or sharing.
Load session from file:
:Chat load ~/sessions/my-session.json
Loads a previously saved session from a JSON file.
Load session from URL:
:Chat load https://paste.rs/xxxxx
Loads a session from a URL (e.g., from paste.rs).
Share current session:
:Chat share
Uploads the current session to paste.rs and copies the URL to clipboard. This allows easy sharing of conversations with others.
Preview current session in browser:
:Chat preview
Opens an HTML preview of the current session in your default browser.
The preview includes session metadata, messages, tool calls, and token usage statistics.
You can also use <C-o> in the picker's chat source to open previews.
All sessions are automatically saved and can be resumed later. For more advanced session management, see the Picker Integration section below.
Note: The plugin is currently in active development phase. Key bindings may change and may reflect the author's personal preferences. Configuration options for customizing key bindings are planned for future releases.
The following key bindings are available in the Input window:
| Mode | Key Binding | Description |
|---|---|---|
Normal |
<Enter> |
Send message |
Normal |
q |
Close chat window |
Normal |
<Tab> |
Switch between input and result windows |
Normal |
Ctrl-C |
Cancel current request |
Normal |
Ctrl-N |
Open new session |
Normal |
r |
Retry last cancelled request |
Normal |
alt-h |
previous chat session |
Normal |
alt-l |
next chat session |
Normal |
<Leader>fr |
run :Picker chat |
Normal |
<Leader>fp |
run :Picker chat_provider |
Normal |
<Leader>fm |
run :Picker chat_model |
The following key bindings are available in the Result window:
| Mode | Key Binding | Description |
|---|---|---|
Normal |
q |
Close chat window |
Normal |
<Tab> |
Switch between input and result windows |
chat.nvim uses a two-layer architecture for AI service integration:
Most AI services use OpenAI-compatible APIs, so the default protocol is openai. Providers can specify a custom protocol via the protocol field if needed.
deepseek - DeepSeek AIgithub - GitHub AImoonshot - Moonshot AIopenrouter - OpenRouterqwen - Alibaba Cloud Qwensiliconflow - SiliconFlowtencent - Tencent Hunyuanbigmodel - BigModel AIvolcengine - Volcengine AIopenai - OpenAIanthropic - Anthropic Claudegemini - Google Geminiollama - Ollamalongcat - LongCat AIcherryin - CherryIN AIyuanjing - yuanjing AINote: Most built-in providers use the OpenAI protocol by default. Exceptions:
anthropic uses the Anthropic protocolgemini uses the Gemini protocolYou can create custom providers for AI services not in the built-in list. Create a file at ~/.config/nvim/lua/chat/providers/<provider_name>.lua.
A provider module must implement:
available_models() - Return a list of available model namesrequest(opt) - Send HTTP request and return job IDOptional fields:
protocol - Specify which protocol to use (default: openai)Example custom provider:
-- ~/.config/nvim/lua/chat/providers/my_provider.lua
local M = {}
local job = require('job')
local sessions = require('chat.sessions')
local config = require('chat.config')
function M.available_models()
return {
'model-1',
'model-2',
}
end
function M.request(opt)
local cmd = {
'curl',
'-s',
'https://api.example.com/v1/chat/completions',
'-H',
'Content-Type: application/json',
'-H',
'Authorization: Bearer ' .. config.config.api_key.my_provider,
'-X',
'POST',
'-d',
'@-',
}
local body = vim.json.encode({
model = sessions.get_session_model(opt.session),
messages = opt.messages,
stream = true,
stream_options = { include_usage = true },
tools = require('chat.tools').available_tools(),
})
local jobid = job.start(cmd, {
on_stdout = opt.on_stdout,
on_stderr = opt.on_stderr,
on_exit = opt.on_exit,
})
job.send(jobid, body)
job.send(jobid, nil)
sessions.set_session_jobid(opt.session, jobid)
return jobid
end
-- Optional: specify custom protocol (defaults to 'openai')
-- M.protocol = 'anthropic'
return M
Protocols handle parsing of API responses. Currently, chat.nvim supports:
openai: OpenAI-compatible API format (default for all built-in providers)anthropic: Anthropic Claude API formatgemini: Google Gemini API formatIf you need a custom protocol, create a file at ~/.config/nvim/lua/chat/protocols/<protocol_name>.lua and implement:
on_stdout(id, data) - Handle stdout data from curlon_stderr(id, data) - Handle stderr dataon_exit(id, code, signal) - Handle request completionSee lua/chat/protocol/openai.lua for reference implementation.
chat.nvim supports tool call functionality, allowing the AI assistant to interact with your filesystem, manage memories, and perform other operations during conversations. Tools are invoked using the @tool_name syntax directly in your messages.
MCP (Model Context Protocol) tools are automatically discovered and integrated when MCP servers are configured. These tools follow the naming pattern mcp_<server>_<tool> and work seamlessly with built-in tools.
Example MCP Tools:
mcp_open_webSearch_search - Web search via MCP servermcp_open_webSearch_fetchGithubReadme - Fetch GitHub README via MCPmcp_open_webSearch_fetchCsdnArticle - Fetch CSDN article via MCPMCP tools are automatically available when their servers are configured in the mcp section of your setup configuration. See MCP Server Configuration for details.
Using MCP Tools:
@mcp_open_webSearch_search query="neovim plugins" engines=["bing"] limit=10
@mcp_open_webSearch_fetchGithubReadme url="https://github.com/wsdjeg/chat.nvim"
MCP tools support all parameter types defined by their servers and execute asynchronously without blocking Neovim's UI.
read_fileReads the content of a file and makes it available to the AI assistant.
Usage:
@read_file <filepath>
Examples:
@read_file ./src/main.lua - Read a Lua file in the current directory@read_file /etc/hosts - Read a system file using absolute path@read_file ../config.json - Read a file from a parent directoryAdvanced Usage with Line Ranges:
@read_file ./src/main.lua line_start=10 line_to=20
Notes:
line_start and line_to parametersline_start is not specified, defaults to line 1line_to is not specified, defaults to last linefind_filesFinds files in the current working directory that match a given pattern.
Usage:
@find_files <pattern>
Examples:
@find_files *.lua - Find all Lua files in the current directory@find_files **/*.md - Recursively find all Markdown files@find_files src/**/*.js - Find JavaScript files in the src directory and its subdirectories@find_files README* - Find files starting with "README"Notes:
directory, hidden, no_ignore, excludeallowed_path configuration settingsearch_textAdvanced text search tool using ripgrep (rg) to search text content in directories with regex support, file type filtering, exclusion patterns, and other advanced features.
Usage:
@search_text <pattern> [options]
Basic Examples:
@search_text "function.*test" - Search for regex pattern in current directory@search_text "TODO:" --file-types "*.lua" - Search TODO comments in Lua files@search_text "error" --context-lines 2 - Search for "error" with 2 lines of contextAdvanced Usage with JSON Parameters:
For more complex searches, you can provide a JSON object with multiple parameters:
@search_text {"pattern": "function.*test", "directory": "./src", "file_types": ["*.lua", "*.vim"], "ignore_case": true, "max_results": 50}
Parameters:
| Parameter | Type | Description |
|---|---|---|
pattern |
string | Required. Text pattern to search for (supports regex) |
directory |
string | Directory path to search in (default: current working directory) |
ignore_case |
boolean | Whether to ignore case (default: false) |
regex |
boolean | Whether to use regex (default: true) |
max_results |
integer | Maximum number of results (default: 100) |
context_lines |
integer | Number of context lines to show around matches (default: 0) |
whole_word |
boolean | Whether to match whole words only (default: false) |
file_types |
array | File type filter, e.g., ["*.py", "*.md", "*.txt"] |
exclude_patterns |
array | Exclude file patterns, e.g., ["*.log", "node_modules/*"] |
More Examples:
Case-insensitive search:
@search_text {"pattern": "config", "ignore_case": true}
Search with file type filtering:
@search_text {"pattern": "function", "file_types": ["*.lua", "*.vim"]}
Search with context and exclusions:
@search_text {"pattern": "FIXME", "context_lines": 3, "exclude_patterns": ["*.log", "node_modules/*"]}
Whole word matching:
@search_text {"pattern": "test", "whole_word": true}
Notes:
allowed_path configuration settingextract_memoryExtract memories from conversation text into a three-tier memory system (working, daily, long-term). Automatically detects memory type and category based on content analysis.
Usage:
@extract_memory <parameters>
Memory Types:
| Type | Icon | Lifetime | Priority | Use Case |
|---|---|---|---|---|
working |
โก | Session only | Highest | Current tasks, decisions, active context |
daily |
๐ | 7-30 days | Medium | Short-term goals, today's tasks, reminders |
long_term |
๐พ | Permanent | Normal | Facts, preferences, skills, knowledge |
Basic Examples:
@extract_memory text="Python็GILๆฏๅ
จๅฑ่งฃ้ๅจ้๏ผๆไน ๆฏ็จVimๅไปฃ็ " (auto-detect type and category)@extract_memory text="ไปๅคฉ่ฆๅฎๆ็จๆท็ปๅฝๅ่ฝ" memory_type="daily" (force daily memory)@extract_memory text="ๅฝๅๆญฃๅจไฟฎๅค็ปๅฝbug" memory_type="working" (force working memory)Advanced Examples:
Extract with specific type and category:
@extract_memory text="Python็GILๆฏๅ
จๅฑ่งฃ้ๅจ้" memory_type="long_term" category="fact"
Extract working memory with importance:
@extract_memory text="ๅฝๅไปปๅก๏ผๅฎ็ฐ็จๆท่ฎค่ฏ" memory_type="working" importance="high"
Extract daily memory:
@extract_memory text="ไปๅคฉไธๅ3็นๆไผ่ฎฎ" memory_type="daily" category="event"
Batch extract multiple memories:
@extract_memory memories='[{"content":"ไบๅฎ1","category":"fact","memory_type":"long_term"},{"content":"ๅๅฅฝ1","category":"preference"}]'
Parameters:
| Parameter | Type | Description |
|---|---|---|
text |
string | Text to analyze for memory extraction |
memories |
array | Pre-extracted memories array (alternative to text parameter) |
memory_type |
string | Memory type: "long_term", "daily", or "working" (auto-detected if not set) |
category |
string | Category: "fact", "preference", "skill", or "event" (auto-detected if not set) |
Memory Object Structure (for memories array):
{
"content": "Memory content text",
"memory_type": "working", // Optional: auto-detected if not specified
"category": "fact", // Optional: auto-detected if not specified
"work_type": "task", // Optional: only for working memory
"importance": "high" // Optional: only for working memory
}
Category Definitions:
Working Memory Types:
Auto-Detection Rules:
The system automatically detects memory type based on keywords:
Notes:
recall_memoryRetrieve relevant information from the three-tier memory system with priority-based ranking. Automatically extracts keywords if no query is provided.
Usage:
@recall_memory <parameters>
Memory Priority Order:
Basic Examples:
@recall_memory query="vim configuration" - Search all memory types@recall_memory - Auto-extract keywords from current conversation@recall_memory query="current task" memory_type="working" - Search only working memory@recall_memory query="today" memory_type="daily" - Search only daily memory@recall_memory query="python" memory_type="long_term" - Search only long-term memoryAdvanced Examples:
Search with limit:
@recall_memory query="programming tips" limit=8
Filter by memory type:
@recall_memory query="current task" memory_type="working"
Search across all sessions:
@recall_memory query="vim" all_sessions=true
Auto-extract from conversation:
@recall_memory
Parameters:
| Parameter | Type | Description |
|---|---|---|
query |
string | Search query (optional, auto-extracted from last message if not provided) |
memory_type |
string | Filter by memory type: "working", "daily", or "long_term" (optional) |
limit |
integer | Number of results (default: 5, maximum: 10) |
all_sessions |
boolean | Search all sessions instead of just current (default: false) |
Output Format:
๐ Retrieved 3 memories (โก working: 1, ๐
daily: 1, ๐พ long_term: 1)
1. โก working ๐ [task]
> ๅฝๅไปปๅก๏ผๅฎ็ฐ็จๆท่ฎค่ฏๅ่ฝ
๐ 2025-01-15 14:30 | ๐ฏ High Priority | ๐ท๏ธ task
2. ๐
daily ๐
[event]
> ไปๅคฉไธๅ3็นๆๅข้ไผ่ฎฎ
๐ 2025-01-15 09:15 | Expires in 6 days
3. ๐พ long_term ๐ [skill]
> Python GILๆฏๅ
จๅฑ่งฃ้ๅจ้๏ผๅฝฑๅๅค็บฟ็จๆง่ฝ
๐ 2025-01-10 16:42 | Accessed 5 times
๐ง Actions:
โข Working memory will be cleaned after session ends
โข Daily memory expires in 7-30 days
โข Use `@recall_memory memory_type="long_term"` to filter by type
Notes:
set_promptRead a prompt file and set it as the current session's system prompt.
Usage:
@set_prompt <filepath>
Examples:
@set_prompt ./AGENTS.md@set_prompt ./prompts/code_review.txt@set_prompt ~/.config/chat.nvim/default_prompt.mdParameters:
| Parameter | Type | Description |
|---|---|---|
filepath |
string | Path to prompt file |
Notes:
allowed_path configured in chat.nvimfetch_webFetch content from web URLs using curl with comprehensive HTTP support.
Usage:
@fetch_web <parameters>
Basic Examples:
@fetch_web url="https://example.com" - Fetch content from a URL@fetch_web url="https://api.github.com/repos/neovim/neovim" timeout=60 user_agent="MyApp/1.0" - Fetch with custom timeout and user agent@fetch_web url="https://api.github.com/user" headers=["Authorization: Bearer token123"] - Fetch with custom headers@fetch_web url="https://api.example.com/data" method="POST" data='{"key":"value"}' headers=["Content-Type: application/json"] - POST request with JSON data@fetch_web url="https://self-signed.example.com" insecure=true - Disable SSL verification (testing only)@fetch_web url="https://example.com/redirect" max_redirects=2 - Limit redirectsAdvanced Usage with JSON Parameters:
For complex requests, you can provide a JSON object:
@fetch_web {"url": "https://example.com", "method": "POST", "data": "{\"key\":\"value\"}", "headers": ["Content-Type: application/json"], "timeout": 30}
Parameters:
| Parameter | Type | Description |
|---|---|---|
url |
string | Required. URL to fetch (must start with http:// or https://) |
method |
string | HTTP method (default: "GET", options: GET, POST, PUT, DELETE, PATCH, HEAD) |
headers |
array | Additional HTTP headers as strings (e.g., ["Authorization: Bearer token", "Accept: application/json"]) |
data |
string | Request body data for POST/PUT requests |
timeout |
integer | Timeout in seconds (default: 30, minimum: 1, maximum: 300) |
user_agent |
string | Custom User-Agent header string (default: "Mozilla/5.0 (compatible; chat.nvim)") |
insecure |
boolean | Disable SSL certificate verification (use with caution, for testing only) |
max_redirects |
integer | Maximum number of redirects to follow (default: 5, set to 0 to disable) |
output |
string | Save response to file instead of displaying (e.g., "./response.html") |
More Examples:
Basic GET request:
@fetch_web url="https://jsonplaceholder.typicode.com/posts/1"
POST request with JSON data:
@fetch_web url="https://api.example.com/users" method="POST" data='{"name": "John", "age": 30}' headers=["Content-Type: application/json"]
With authentication header:
@fetch_web url="https://api.github.com/user/repos" headers=["Authorization: Bearer YOUR_TOKEN", "Accept: application/vnd.github.v3+json"]
Save response to file:
@fetch_web url="https://example.com" output="./downloaded_page.html"
Configure timeout and SSL verification:
@fetch_web url="https://slow-api.example.com" timeout=60 insecure=true
Notes:
insecure=true for testing)output parameter to save to a fileweb_searchSearch the web using Firecrawl, Google Custom Search API, or SerpAPI.
Usage:
@web_search <parameters>
Supported Engines:
Configuration:
API keys must be set in chat.nvim configuration:
require('chat').setup({
api_key = {
firecrawl = 'fc-YOUR_API_KEY',
google = 'YOUR_GOOGLE_API_KEY',
google_cx = 'YOUR_SEARCH_ENGINE_ID',
serpapi = 'YOUR_SERPAPI_KEY'
}
})
Alternatively, provide API keys directly as parameters.
Examples:
Basic Firecrawl search:
@web_search query="firecrawl web scraping"
Firecrawl with result limit:
@web_search query="neovim plugins" limit=10
Google search:
@web_search query="latest news" engine="google"
Google search with custom API key and cx:
@web_search query="test" engine="google" api_key="GOOGLE_API_KEY" cx="SEARCH_ENGINE_ID"
SerpAPI with Google (default):
@web_search query="neovim plugins" engine="serpapi"
SerpAPI with Bing:
@web_search query="latest news" engine="serpapi" serpapi_engine="bing"
SerpAPI with DuckDuckGo:
@web_search query="privacy tools" engine="serpapi" serpapi_engine="duckduckgo"
Custom timeout:
@web_search query="slow site" timeout=60
Firecrawl with scrape options:
@web_search query="news" scrape_options={"formats":["markdown"]}
Parameters:
| Parameter | Type | Description |
|---|---|---|
query |
string | Required. Search query string |
engine |
string | Search engine to use: "firecrawl", "google", or "serpapi" (default: "firecrawl") |
limit |
integer | Number of results to return (default: 5 for firecrawl, 10 for google/serpapi) |
scrape_options |
object | Options for scraping result pages (Firecrawl only, see Firecrawl docs) |
api_key |
string | API key (optional if configured in config) |
cx |
string | Google Custom Search engine ID (required for Google engine if not in config) |
timeout |
integer | Timeout in seconds (default: 30, minimum: 1, maximum: 300) |
serpapi_engine |
string | SerpAPI search engine: "google", "bing", "duckduckgo", "yahoo", "baidu", etc. (optional) |
SerpAPI Search Engines:
When using SerpAPI, you can specify different search engines via the serpapi_engine parameter:
| Engine | Description |
|---|---|
google |
Google Search |
bing |
Microsoft Bing |
duckduckgo |
DuckDuckGo |
yahoo |
Yahoo Search |
baidu |
Baidu |
yandex |
Yandex |
ebay |
eBay Search |
| ...and more | See SerpAPI docs |
Notes:
serpapi_engine parametergit_diffRun git diff to compare changes between working directory, index, or different branches.
Usage:
@git_diff <parameters>
Basic Examples:
@git_diff - Show all unstaged changes in the repository@git_diff cached=true - Show staged changes (--cached)@git_diff branch="main" - Compare working directory with main branch@git_diff path="./src" - Show changes for specific file or directory@git_diff branch="master" cached=true - Compare staged changes with master branchAdvanced Usage with JSON Parameters:
For more complex comparisons, you can provide a JSON object:
@git_diff {"path": "./lua/chat", "branch": "develop", "cached": true}
Parameters:
| Parameter | Type | Description |
|---|---|---|
path |
string | File or directory path to show diff for (optional) |
cached |
boolean | Show staged changes (git diff --cached) (optional) |
branch |
string | Branch to compare against (e.g., "master", "origin/main") (optional) |
More Examples:
View all unstaged changes:
@git_diff
View staged changes only:
@git_diff cached=true
Compare with another branch:
@git_diff branch="main"
Check changes in specific file:
@git_diff path="./lua/chat/tools/git_diff.lua"
Compare staged changes with master branch:
@git_diff branch="master" cached=true
Combined usage:
@git_diff {"path": "./lua/chat/tools", "branch": "develop", "cached": false}
Notes:
cached flag shows changes that are staged (git diff --cached)branch parameter allows comparing with another branch (git diff )path parameter restricts diff output to specific file or directorygit_logShow commit logs with various filters and options.
Usage:
@git_log [parameters]
Basic Examples:
@git_log - Show last 5 commits (default)@git_log count=10 - Show last 10 commits@git_log count=0 - Show all commits (no limit)@git_log path="./src/main.lua" - Show commits for specific file@git_log author="john" - Filter by author@git_log since="2024-01-01" - Commits since date@git_log from="v1.4.0" - Commits from tag to HEAD@git_log from="v1.0.0" to="v2.0.0" - Commits between tags@git_log grep="fix" - Search in commit messagesParameters:
| Parameter | Type | Description |
|---|---|---|
path |
string | File or directory path (default: current working directory) |
count |
integer | Limit number of commits (default: 5, use 0 for no limit) |
oneline |
boolean | Show each commit on a single line (default: true) |
author |
string | Filter commits by author name or email |
since |
string | Show commits after this date (e.g., "2024-01-01", "2 weeks ago") |
from |
string | Starting tag/commit for range (e.g., "v1.4.0") |
to |
string | Ending tag/commit for range (default: HEAD) |
grep |
string | Search for pattern in commit messages |
Notes:
git_statusShow the working tree status.
Usage:
@git_status [parameters]
Basic Examples:
@git_status - Show repository status (short format)@git_status path="./src" - Status for specific path@git_status short=false - Long format output@git_status show_branch=false - Hide branch infoParameters:
| Parameter | Type | Description |
|---|---|---|
path |
string | File or directory path (optional) |
short |
boolean | Use short format (default: true) |
show_branch |
boolean | Show branch info (default: true) |
Output (short mode):
Branch: master...origin/master
M file.lua (staged)
M file.lua (modified)
?? file.lua (untracked)
Notes:
M (modified), A (added), D (deleted), R (renamed), C (copied), ?? (untracked), !! (ignored)git_showShow detailed changes of a specific commit.
Usage:
@git_show commit=<commit> [parameters]
Basic Examples:
@git_show commit="abc123" - Show commit details@git_show commit="v1.0.0" - Show tag commit@git_show commit="HEAD~1" - Show previous commit@git_show commit="abc123" stat=true - Show stat only (file list)@git_show commit="abc123" path="./src/main.lua" - Show changes for specific fileParameters:
| Parameter | Type | Description |
|---|---|---|
commit |
string | Commit hash, tag, or reference (e.g., "abc123", "v1.0.0", "HEAD~1") |
stat |
boolean | Show stat only (file list with change counts) (optional) |
path |
string | Filter to specific file path (optional) |
Notes:
commit can be a commit hash, tag, or relative referencestat=true to see only the file list with change countspath to filter changes to a specific fileget_historyGet conversation history messages from the current session.
Usage:
@get_history [parameters]
Basic Examples:
@get_history - Get first 20 messages (default)@get_history offset=0 limit=20 - Get first 20 messages (oldest)@get_history offset=20 limit=20 - Get messages 21-40@get_history offset=0 limit=50 - Get first 50 messages (max)Parameters:
| Parameter | Type | Description |
|---|---|---|
offset |
integer | Starting index (0 = oldest message, default: 0) |
limit |
integer | Number of messages to retrieve (default: 20, max: 50) |
Notes:
planPlan mode for creating, managing, and reviewing task plans with step-by-step tracking.
Usage:
@plan action="<action>" [parameters]
Actions:
| Action | Description |
|---|---|
create |
Create new plan with title and optional steps |
show |
Show plan details by ID |
list |
List all plans (optional status filter) |
add |
Add step to existing plan |
next |
Start next pending step |
done |
Mark current/completed step as done |
review |
Review completed plan with summary |
delete |
Delete a plan |
Basic Examples:
Create a new plan:
@plan action="create" title="Implement feature X" steps=["Design API", "Write code", "Test"]
List all plans:
@plan action="list"
List plans with status filter:
@plan action="list" status="in_progress"
Show plan details:
@plan action="show" plan_id="plan-20250110-1234"
Start next step:
@plan action="next" plan_id="plan-20250110-1234"
Complete a step:
@plan action="done" plan_id="plan-20250110-1234" step_id=1
Add step to existing plan:
@plan action="add" plan_id="plan-20250110-1234" step_content="Add documentation"
Review completed plan:
@plan action="review" plan_id="plan-20250110-1234" summary="Feature implemented successfully" lessons=["Lesson 1", "Lesson 2"]
Delete a plan:
@plan action="delete" plan_id="plan-20250110-1234"
Advanced Usage with JSON Parameters:
For more complex operations, you can provide a JSON object:
@plan {"action": "create", "title": "Refactor codebase", "steps": ["Analyze current structure", "Design new architecture", "Migrate modules", "Update tests"]}
Parameters:
| Parameter | Type | Description |
|---|---|---|
action |
string | Required. Plan action to perform (create, show, list, add, next, done, review, delete) |
title |
string | Plan title (required for create action) |
steps |
array | Initial steps array (optional for create action) |
plan_id |
string | Plan ID (required for show, add, next, done, review, delete) |
step_content |
string | Step content (required for add action) |
step_id |
integer | Step ID (required for done action, auto-detected if not provided) |
notes |
string | Notes for step completion (optional for done action) |
status |
string | Filter by status for list action (pending, in_progress, completed) |
summary |
string | Plan summary (for review action) |
lessons |
array | Lessons learned (for review action) |
issues |
array | Issues encountered (for review action) |
Workflow Example:
Create a plan:
@plan action="create" title="Build REST API" steps=["Design endpoints", "Implement handlers", "Add authentication", "Write tests", "Deploy"]
Response: โ
Plan created: **Build REST API** ID: plan-20250115-5678
Start first step:
@plan action="next" plan_id="plan-20250115-5678"
Response: โณ **Started Step 1:** Design endpoints
Complete the step:
@plan action="done" plan_id="plan-20250115-5678" notes="API endpoints documented"
Response: โ
**Completed Step 1:** Design endpoints
Continue with remaining steps...
Review the plan:
@plan action="review" plan_id="plan-20250115-5678" summary="API successfully built and deployed" lessons=["Test early", "Document as you go"]
Notes:
memory.enable = true)plans.json in the memory storage directoryplan-YYYYMMDD-XXXX (e.g., plan-20250110-1234)step_id, the tool auto-detects the current in-progress stepzettelkasten_createCreate new zettelkasten notes, provided by zettelkasten.nvim.
Usage:
@zettelkasten_create <parameters>
Parameters:
| Parameter | Type | Description |
|---|---|---|
title |
string | The title of zettelkasten note |
content |
string | The note body of zettelkasten |
tags |
array | Optional tags for the note (max 3) |
Notes:
zettelkasten_getRetrieve zettelkasten notes by tags, provided by zettelkasten.nvim.
Usage:
@zettelkasten_get <tags>
Parameters:
| Parameter | Type | Description |
|---|---|---|
tags |
array | Tags to search for (e.g., ["programming", "vim"]) |
Notes:
file_name and title fieldsDirect invocation: Include the tool call directly in your message:
Can you review this code? @read_file ./my_script.lua
Multiple tools: Combine multiple tools in a single message:
Compare these two configs: @read_file ./config1.json @read_file ./config2.json
Natural integration: The tool calls can be embedded naturally within your questions:
What's wrong with this function? @read_file ./utils.lua
Memory management: Use memory tools for context-aware conversations:
Based on what we discussed earlier about Vim: @recall_memory query="vim"
The AI assistant will process the tool calls, execute the specified operations, and incorporate their results into its response. This enables more context-aware assistance without needing to manually copy-paste file contents or repeat previous information.
chat.nvim supports both synchronous and asynchronous custom tools. Users can create lua/chat/tools/<tool_name>.lua file in their Neovim runtime path.
This module should provide at least two functions: scheme() and <tool_name> function. The scheme() function returns a table describing the tool's schema (name, description, parameters). The <tool_name> function is the actual implementation that will be called when the tool is invoked.
Synchronous Tool: Returns { content = "..." } or { error = "..." } directly.
Asynchronous Tool: Returns { jobid = <number> } and calls ctx.callback({ content = "..." }) when done.
Here is an example for a synchronous get_weather tool:
local M = {}
---@param action { city: string, unit?: string }
function M.get_weather(action)
if not action.city or action.city == '' then
return { error = 'City name is required for weather information.' }
end
-- ... synchronous implementation ...
return { content = 'Weather in ...' }
end
function M.scheme()
return {
type = 'function',
['function'] = {
name = 'get_weather',
description = 'Get weather information for a specific city.',
parameters = { ... },
},
}
end
return M
For long-running operations, you can create asynchronous tools using job.nvim:
local M = {}
local job = require('job')
---@param action { url: string }
---@param ctx { cwd: string, session: string, callback: function }
function M.fetch_data(action, ctx)
if not action.url or action.url == '' then
return { error = 'URL is required.' }
end
local stdout = {}
local stderr = {}
local jobid = job.start({
'curl',
'-s',
action.url,
}, {
on_stdout = function(_, data)
for _, v in ipairs(data) do
table.insert(stdout, v)
end
end,
on_stderr = function(_, data)
for _, v in ipairs(data) do
table.insert(stderr, v)
end
end,
on_exit = function(id, code, signal)
if code == 0 and signal == 0 then
-- Call the callback with the result
ctx.callback({
content = table.concat(stdout, '\n'),
jobid = id,
})
else
ctx.callback({
error = 'Failed to fetch data: ' .. table.concat(stderr, '\n'),
jobid = id,
})
end
end,
})
-- Return jobid to indicate async execution
if jobid > 0 then
return { jobid = jobid }
else
return { error = 'Failed to start job' }
end
end
function M.scheme()
return {
type = 'function',
['function'] = {
name = 'fetch_data',
description = 'Fetch data from a URL asynchronously.',
parameters = {
type = 'object',
properties = {
url = {
type = 'string',
description = 'URL to fetch data from',
},
},
required = { 'url' },
},
},
}
end
return M
Key Points for Asynchronous Tools:
ctx parameter containing { cwd, session, callback }{ jobid = <number> } when starting async operationctx.callback({ content = "..." }) or ctx.callback({ error = "..." }) when donejobid in the result to match the async trackingchat.nvim includes a built-in HTTP server that allows external applications to send messages to your chat sessions. This enables integration with other tools, scripts, and automation workflows.
The HTTP server is automatically started when the http.api_key configuration is set to a non-empty value:
require('chat').setup({
-- ... other configuration
http = {
host = '127.0.0.1', -- Default: '127.0.0.1'
port = 7777, -- Default: 7777
api_key = 'your-secret-key', -- Required to enable server
},
})
chat.nvim provides the following HTTP API endpoints for external integration:
| Endpoint | Method | Description |
|---|---|---|
/ |
POST | Send messages to a specified chat session |
/sessions |
GET | Get a list of all active session IDs |
/session |
GET | Get HTML preview of a session (requires id parameter) |
Base URL: http://{host}:{port}/ where {host} and {port} are configured in your chat.nvim settings (default: 127.0.0.1:7777)
Authentication: All requests require the X-API-Key header containing your configured API key.
Example Usage:
# Send message to session
curl -X POST http://127.0.0.1:7777/ \
-H "X-API-Key: your-secret-key" \
-H "Content-Type: application/json" \
-d '{"session": "my-session", "content": "Hello from curl!"}'
# Get session list
curl -H "X-API-Key: your-secret-key" http://127.0.0.1:7777/sessions
For detailed request/response formats and examples, see the sections below.
{
"session": "session-id",
"content": "Message content from external application"
}
Parameters:
| Parameter | Type | Description |
|---|---|---|
session |
string | Chat session ID. |
content |
string | Message content to send to the chat session |
//sessions[
"2024-01-15-10-30-00",
"2024-01-15-11-45-00",
"2024-01-16-09-20-00"
] # Example output: array of session ID strings
Note: Session IDs follow the format YYYY-MM-DD-HH-MM-SS (e.g., 2024-01-15-10-30-00) and are automatically generated when new sessions are created.
/sessionReturns an HTML preview of the specified chat session.
Request Parameters:
| Parameter | Type | Description |
|---|---|---|
id |
string | Required. Session ID to preview |
Example Request:
curl "http://127.0.0.1:7777/session?id=2024-01-15-10-30-00" \
-H "X-API-Key: your-secret-key"
Response:
Content-Type: text/html; charset=utf-8HTML Preview Features:
Integration:
The HTML preview can be opened via:
:Chat preview command in Neovim<C-o> key binding in picker's chat source/session?id=<session_id> endpointIncoming messages are processed through a queue system:
# Send a message to a session
curl -X POST http://127.0.0.1:7777/ \
-H "X-API-Key: your-secret-key" \
-H "Content-Type: application/json" \
-d '{"session": "my-session", "content": "Hello from curl!"}'
# Get all session IDs
curl -H "X-API-Key: your-secret-key" http://127.0.0.1:7777/sessions
import requests
# Send a message to a session
url = "http://127.0.0.1:7777/"
headers = {
"X-API-Key": "your-secret-key",
"Content-Type": "application/json"
}
data = {
"session": "python-script",
"content": "Message from Python script"
}
response = requests.post(url, json=data, headers=headers)
print(f"Status: {response.status_code}")
# Get session list
sessions_response = requests.get("http://127.0.0.1:7777/sessions", headers=headers)
if sessions_response.status_code == 200:
sessions = sessions_response.json()
print(f"Active sessions: {sessions}")
chat.nvim provides built-in picker sources for seamless integration with picker.nvim. These sources allow you to quickly access and manage your chat sessions, providers, and models.
Note: The chat picker source displays all your active sessions, allowing quick switching between parallel conversations with different models.
Available Sources:
chat - Search through your chat history sessions

Keyboard Shortcuts in chat picker:
<CR> (Enter): Open selected session<C-d>: Delete selected session<C-o>: Open HTML preview in browserchat_provider - Switch between different AI providers

chat_model - Select available models for the current provider

chat.nvim supports integration with multiple instant messaging platforms for remote AI interaction.
| Platform | Icon | Bidirectional | Features |
|---|---|---|---|
| Discord | ๐ฌ | โ Yes | Full-featured bot with session binding |
| Lark | ๐ฆ | โ Yes | Feishu/Lark bot with message polling |
| DingTalk | ๐ฑ | โ Yes* | Webhook (one-way) or API (two-way) |
| WeCom | ๐ผ | โ Yes* | Enterprise WeChat webhook or API |
| Weixin | ๐ฌ | โ Yes* | Personal WeChat via external API |
| Telegram | โ๏ธ | โ Yes | Bot API with group/private chat support |
*Webhook mode is one-way only; API mode supports bidirectional communication.
Discord integration allows you to interact with AI assistants via Discord messages.
1. Create Discord Application
2. Create Bot User
integrations.discord.token)3. Enable Message Content Intent
4. Get Channel ID
integrations.discord.channel_id)5. Invite Bot to Server
6. Configure chat.nvim
integrations = {
discord = {
token = 'YOUR_DISCORD_BOT_TOKEN',
channel_id = 'YOUR_CHANNEL_ID',
},
}
Neovim Commands:
:Chat bridge discord - Bind current chat.nvim session to Discord channelDiscord Commands:
/session - Bind current Discord channel to active chat.nvim session/clear - Clear messages in the bound session:Chat bridge discord to bind the session/session to confirm bindingstdpath('data')/chat-discord-state.jsonBot not responding:
State issues:
:lua require('chat.integrations.discord').clear_state()Lark/Feishu integration for enterprise communication.
1. Create Lark App
2. Configure Bot Permissions
Required permissions:
im:message.group_msg - Get all messages in groups (sensitive permission)im:message - Get and send messages in private chats and groupsConfiguration steps:
3. Get Chat ID
4. Configure chat.nvim
integrations = {
lark = {
app_id = 'YOUR_APP_ID',
app_secret = 'YOUR_APP_SECRET',
chat_id = 'YOUR_CHAT_ID',
},
}
:Chat bridge lark - Bind current session to Lark chatstdpath('data')/chat-lark-state.jsonDingTalk integration with webhook or API mode.
Webhook Mode (Simple, One-Way):
integrations = {
dingtalk = {
webhook = 'https://oapi.dingtalk.com/robot/send?access_token=XXX',
},
}
API Mode (Advanced, Bidirectional):
integrations = {
dingtalk = {
app_key = 'YOUR_APP_KEY',
app_secret = 'YOUR_APP_SECRET',
conversation_id = 'YOUR_CONVERSATION_ID',
user_id = 'YOUR_USER_ID',
},
}
stdpath('data')/chat-dingtalk-state.jsonWeCom integration with webhook or API mode.
Webhook Mode (Simple, One-Way):
integrations = {
wecom = {
webhook_key = 'YOUR_WEBHOOK_KEY',
},
}
API Mode (Advanced, Bidirectional):
integrations = {
wecom = {
corp_id = 'YOUR_CORP_ID',
corp_secret = 'YOUR_CORP_SECRET',
agent_id = 'YOUR_AGENT_ID',
user_id = 'YOUR_USER_ID',
},
}
stdpath('data')/chat-wecom-state.jsonWeixin integration for personal WeChat accounts via QR code login.
1. First-Time Login
Run the following Lua command in Neovim:
:lua require('chat.integrations.weixin').login()
A QR code will be displayed in a floating window.
2. Scan QR Code
3. Done!
Login credentials are automatically saved to:
stdpath('data')/chat-weixin-state.json
Subsequent restarts will auto-connect using saved credentials.
| Command | Description |
|---|---|
:lua require('chat.integrations.weixin').login() |
Start QR code login |
:lua require('chat.integrations.weixin').logout() |
Logout and clear credentials |
:lua require('chat.integrations.weixin').get_state() |
Check connection status |
stdpath('data')/chat-weixin-state.jsonTelegram bot integration with full feature support.
/session and /clear commands1. Create Telegram Bot
@BotFather/newbot command123456789:ABCdefGHIjklMNOpqrsTUVwxyz)2. Get Chat ID
For Private Chat:
https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates"chat":{"id": value in the responseFor Group Chat:
3. Configure chat.nvim
integrations = {
telegram = {
bot_token = 'YOUR_BOT_TOKEN',
chat_id = 'YOUR_CHAT_ID',
},
}
Neovim Commands:
:Chat bridge telegram - Bind current session to Telegram chatTelegram Commands:
/session - Bind current Telegram chat to active session/clear - Clear messages in the bound session:Chat bridge telegram to bind the sessionstdpath('data')/chat-telegram-state.jsonBot not responding:
/start to the bot firstState issues:
:lua require('chat.integrations.telegram').clear_state()All IM integrations share these common features:
Commands:
:Chat bridge <platform> - Bind current session to platform/session - Check/update session binding/clear - Clear current session messagesTechnical Details:
stdpath('data')Discord:
Lark:
DingTalk:
WeCom:
Telegram:
To add a new IM platform integration:
lua/chat/integrations/<platform>.luaconnect(callback) - Start listening for messagesdisconnect() - Stop listeningsend_message(content) - Send messagecurrent_session() - Get current session IDset_session(session) - Set current sessioncleanup() - Cleanup resourceslua/chat/integrations/init.luaSee lua/chat/integrations/discord.lua for reference implementation.
Like this plugin? Star the repository on GitHub.
Love this plugin? Follow me on GitHub.
If you encounter any bugs or have suggestions, please file an issue in the issue tracker.
This project is licensed under the GPL-3.0 License.