Development
April 30, 2026 ยท View on GitHub
Getting Started
First follow the installation instructions to install the required prerequisites.
To build Expert, run:
just release
You may point your editor's LSP configuration to the start_expert executable
in the generated release:
<your-repo>/apps/expert/_build/prod/rel/plain/bin/start_expert --stdio
Parser Configuration
Expert uses Spitfire as the default
parser. To use the built-in Elixir parser instead, set the EXPERT_PARSER env
variable to elixir when building the release:
EXPERT_PARSER=elixir just release
Logging
When expert starts up, it creates a .expert directory in the root
directory of a project. Inside that directory are two log files,
expert.log and project.log. The expert.log log file contains
logging and OTP messages from the language server, while the
project.log file contains logging and OTP messages from the
project's node. While developing expert, it's helpful to open up a
terminal and tail both of these log files so you can see any errors
and messages that expert emits. To do that, run the following in a
terminal while in the project's root directory:
tail -f .expert/*.log
Note: These log files roll over when they reach 1 megabyte, so after a time, it will be necessary to re-run the above command.
Remote Shell
Expert supports a remote shell, which will connect a remote IEx session to a currently-running language server process.
connectionDetails command
The connectionDetails LSP command (via workspace/executeCommand) returns
the connection info needed to attach a remote shell:
{
"nodeName": "expert-manager-core-41110@127.0.0.1",
"port": 59345,
"cookie": "expert",
"epmdModule": "Elixir.XPForge.EPMD",
"epmdEbinPath": "/path/to/forge/ebin",
"debugScriptPath": "/path/to/remote_shell.sh",
"command": "'/path/to/remote_shell.sh' 'expert-manager-core-41110@127.0.0.1' '59345' 'Elixir.XPForge.EPMD' '/path/to/forge/ebin' 'expert'"
}
Editor extensions can use debugScriptPath to spawn a terminal running the
remote shell with the connection details as arguments:
<debugScriptPath> <nodeName> <port> <epmdModule> <epmdEbinPath> [cookie]
This will connect you to a remote IEx session inside the language server,
where all evaluation happens on the manager node. You can investigate processes,
make changes to the running code, or run :observer.
Editor integrations can use these details to launch a remote shell and some of them may already have a builtin integration for it.
If your editor does not include one, you can manually configure it to launch the
shell on demand, for example you can add this to your neovim+lsp-config configuration
to open a new terminal pane with the remote shell, assuming you have configured the
Expert LSP client with the name expert:
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("kickstart-lsp-attach", { clear = true }),
callback = function(event)
local client = vim.lsp.get_client_by_id(event.data.client_id)
if client.name == "expert" then
map("<leader>ed", function()
client:request('workspace/executeCommand', {
command = 'connectionDetails',
arguments = {},
}, function(err, result)
if err then
vim.notify('connectionDetails failed: ' .. vim.inspect(err), vim.log.levels.ERROR)
return
end
vim.cmd('belowright split | terminal')
vim.api.nvim_chan_send(vim.b.terminal_job_id, result.command .. '\n')
end)
end, "Expert remote shell")
end
end,
})