Editors & Clients
Neovim with Verdictan
Point a Neovim AI plugin at your Verdictan gateway, and the requests it sends for the model you choose go through your policies. This page shows CodeCompanion and gp.nvim. Both send OpenAI-style Chat Completions requests. Get chat working first, then check each other feature you use.
Before you start
- A gateway on
http://127.0.0.1:41002with at least one provider target. See Gateway Setup for IDEs. - A client API token. See API Tokens for IDEs.
- One model ID from the gateway's authenticated
GET /v1/modelsresponse. - CodeCompanion or gp.nvim installed in Neovim.
Both plugins read the token from the environment that starts Neovim. Export it there:
export VERDICTAN_CLIENT_TOKEN="<client-api-token>"Configure CodeCompanion
-
Add a
verdictanHTTP adapter and assign it to chat and inline edits. Keep your other plugin settings:init.luarequire("codecompanion").setup({ adapters = { http = { verdictan = function() return require("codecompanion.adapters").extend("openai_compatible", { env = { url = "http://127.0.0.1:41002", chat_url = "/v1/chat/completions", api_key = "VERDICTAN_CLIENT_TOKEN", }, schema = { model = { default = "your-model-id", }, }, }) end, }, }, interactions = { chat = { adapter = "verdictan" }, inline = { adapter = "verdictan" }, }, }) -
Replace
your-model-idwith anidfromGET /v1/models. -
Start Neovim from the shell that exports
VERDICTAN_CLIENT_TOKEN.
The adapter sends requests to url plus chat_url, with Authorization: Bearer and the token. api_key holds the name of the environment variable, not the token. The adapter also reads url plus /v1/models to fill its model picker. Without schema.model.default, it picks the last model in that list, so set the default.
Only the interactions you assign to verdictan use the gateway. An inline prompt with adapter=<name> overrides the assignment for that prompt. The cmd interaction and background tasks have their own settings: interactions.cmd.adapter and interactions.background.adapter. ACP adapters connect to agents, and preset adapters such as copilot call their own services. None of them pass through Verdictan.
CodeCompanion ships openai_compatible as an example adapter that it does not officially support. See CodeCompanion HTTP adapters for the other env value types, such as cmd: and file:.
Configure gp.nvim
-
Add a
verdictanprovider and an agent that uses it. Keep your other settings:init.luarequire("gp").setup({ providers = { verdictan = { endpoint = "http://127.0.0.1:41002/v1/chat/completions", secret = os.getenv("VERDICTAN_CLIENT_TOKEN"), }, }, agents = { { name = "Verdictan", provider = "verdictan", chat = true, command = true, model = { model = "your-model-id" }, system_prompt = "You are a careful coding assistant.", }, }, }) -
Replace
your-model-idwith anidfromGET /v1/models. -
Start Neovim from the shell that exports
VERDICTAN_CLIENT_TOKEN, then run:GpAgent Verdictan.
endpoint is the complete Chat Completions URL, not a base URL. For a provider name that gp.nvim does not know, such as verdictan, it sends the token as Authorization: Bearer. gp.nvim drops an agent that has no model or system_prompt, and drops a provider that has no endpoint.
Only agents with provider = "verdictan" use the gateway. Other agents, and the image agents you pick with :GpImageAgent, keep their own providers. See the gp.nvim README for agent and command options.
Verify
-
Check the token and the model list:
curl -fsS \ -H "Authorization: Bearer $VERDICTAN_CLIENT_TOKEN" \ http://127.0.0.1:41002/v1/models -
Send
Reply with Hello.from a chat::CodeCompanionChatin CodeCompanion, or:GpChatNewin gp.nvim. Check that the reply shows. -
In a second shell, read the recent events:
verdictan events tail --since 10m --jsonThe newest event in the
eventsarray has atimestampfrom the moment you sent the chat. Event delivery can take a few seconds, so run the command again if the event is not there yet. -
Open a scratch file and ask for a small edit:
:CodeCompanion <prompt>in CodeCompanion, or:GpRewritein gp.nvim. Run the same command again, and check that this request also has an event.
An event proves that a request went through the gateway. Count a feature as governed only after you see its event.
Other Neovim plugins
Another plugin can use the gateway if you can set all of these:
- The gateway's base URL
http://127.0.0.1:41002/v1, or the complete URLhttp://127.0.0.1:41002/v1/chat/completions - A token that the plugin sends as
Authorization: Bearer <token> - A model ID from
GET /v1/models
The gateway reads the client token only from the Authorization header. A plugin that sends its key in another header, such as x-api-key, gets 401. Check the plugin's own documentation for the option names, and confirm each feature with verdictan events tail.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Connection refused | The gateway is not running on port 41002 | Start it, and check /healthz with curl. |
401 with missing_api_key | Neovim did not inherit VERDICTAN_CLIENT_TOKEN, or the value is not a vdt_ token | Start Neovim from a shell that exports the variable. Don't use the gateway runtime token. |
401 with invalid_api_token or tokens.expired | The token is revoked or expired | Check the token on the Console API Tokens page. |
422 with no_matching_provider | The model ID does not match anything the gateway serves | Use an id from GET /v1/models. |
404 from the gateway | The URL has the wrong shape, for example a base URL in gp.nvim's endpoint | Use the complete Chat Completions URL in gp.nvim, and url plus chat_url in CodeCompanion. |
| Chat produces events but inline edits do not | The inline interaction uses another adapter or agent | Set interactions.inline.adapter in CodeCompanion, or select the Verdictan agent in gp.nvim. |
| A reply but no event | The plugin used another adapter, agent, or provider | Check which one is active. Then see IDE Integration Troubleshooting. |
Next steps
- Configure Policies for IDE Traffic: controls for the prompts Neovim sends.
- Monitor IDE AI Usage: Neovim traffic in events, History, and Usage.
- API Tokens for IDEs: scope and rotate the plugin's token.