PostToolUse hook that automatically fetches LSP diagnostics after Edit/Write tool calls and injects any errors or warnings into the next turn's tool-result.
When the model edits a file, the hook:
- Resolves the file path from the tool call's
arguments["path"]. - Looks up (or spawns) the language server for the file's extension.
- Sends
textDocument/didOpenwith the current file contents. - Polls
publishDiagnosticspush-notifications for up to:lsp_implicit_diagnostics_timeout_ms(default 1500 ms). - Filters to
:lsp_implicit_diagnostics_severities(default[:error, :warning]). - Returns
{:augment, text}with a[lsp diagnostics]block, or:okif there is nothing to report.
All failure paths (LSP disabled, unsupported file type, server crash, timeout)
collapse to :ok — the hook must never stall the agent loop.
Configuration keys
:lsp_implicit_diagnostics_enabled— boolean, defaulttrue:lsp_implicit_diagnostics_timeout_ms— poll deadline in ms, default1500:lsp_implicit_diagnostics_severities— list of:error | :warning | :information | :hint, default[:error, :warning]
Summary
Functions
Default hook entry to merge into Loop.start's hooks map.
Merge the default implicit-diagnostics hook into a user-supplied hooks map.
PostToolUse hook function. Receives the payload map and tool_use_id.
Functions
@spec default_hooks_entry() :: map()
Default hook entry to merge into Loop.start's hooks map.
@spec maybe_merge(ExAthena.Hooks.t()) :: ExAthena.Hooks.t()
Merge the default implicit-diagnostics hook into a user-supplied hooks map.
When :lsp_implicit_diagnostics_enabled is false (the default in tests),
returns hooks unchanged. Otherwise prepends the built-in entry to the
:PostToolUse list so user-supplied hooks still run after it.
PostToolUse hook function. Receives the payload map and tool_use_id.
Returns {:augment, text} when LSP diagnostics are available, otherwise :ok.
Emits [:ex_athena, :lsp, :implicit_diagnostics, :start | :stop] telemetry events.