LSP Server

Lectic includes a small Language Server Protocol (LSP) server that provides completion for directives, macros, and common YAML header fields, plus hovers. It is stdio only.

Overview - Command: lectic lsp - Transport: stdio (no --node-ipc or --socket) - Features: textDocument/completion, textDocument/hover, diagnostics, document symbols (outline), workspace symbols, folding ranges, code actions, semantic tokens, go to definition - Triggers: :, [ in directive brackets, and - in tools arrays - Insertions - Directives use snippets and place the cursor inside brackets (or at the end for reset): :cmd[${0:command}], :ask[$0], :aside[$0], :reset[]$0. - Macro names are suggested on : and insert as directives: :name[]$0. - Inside brackets of :ask[...] and :aside[...], only interlocutor names are offered. - Matching: case‑insensitive; typed prefix after : or inside [ is respected. - Fences: no suggestions inside :: or ::: runs - Trigger filtering: only :ask[/:aside[ produce bracket completions

Where completions come from - Directives: built‑in suggestions for :cmd, :ask, :aside, and :reset. - Macro names: merged from the same places and precedence as the CLI (higher wins): 1) System config: ${LECTIC_CONFIG}/lectic.yaml 2) Workspace config: lectic.yaml in the document directory 3) The document’s YAML header - YAML header fields: - interlocutor / interlocutors blocks: top‑level interlocutor properties such as name, prompt, provider, model, temperature, max_tokens, max_tool_use, thinking_effort, thinking_budget, tools, and nocache. - model: provider‑appropriate model names. - tools array items: tool kinds after a bare -. - kit: ...: merged kit names from system/workspace/header. - agent: ...: merged interlocutor names. - native: ...: supported native types (search, code). - Interlocutors: collected from the merged header as above, combining interlocutor and interlocutors. - De‑duplication is case‑insensitive on name. Higher‑precedence entry wins. - The server shows a simple preview in the completion item.

Behavior examples - Type - on a line inside tools: → suggestions for tool kinds (exec, sqlite, mcp_*, native, kit, …). - Type : → suggestions for directives and macro names. - Type :su (with a summarize macro defined) → summarize appears and inserts :summarize[]$0. - Type :ask[ or :aside[ → invoke completion to see interlocutor names; selecting a name replaces only the text inside the []. - Type :: or ::: → no suggestions (reserved for directive fences). - Place the cursor on a directive (e.g., :name[], :ask[Name]) or a name field in the YAML header (e.g., name: Assistant) and invoke “Go to Definition” to jump to the relevant definition. If multiple definitions exist (e.g., a local override of a workspace or system interlocutor), the LSP returns all locations, prioritized by proximity (local > workspace > system).

Neovim setup (vim.lsp.start) - Minimal startup for the current buffer:

local client_id = vim.lsp.start({
  name = "lectic",
  cmd = { "lectic", "lsp" },
  root_dir = vim.fs.root(0, { ".git", "lectic.yaml" })
             or vim.fn.getcwd(),
  single_file_support = true,
})
vim.api.nvim_create_autocmd("FileType", {
  pattern = { "lectic", "markdown.lectic", "lectic.markdown" },
  callback = function(args)
    vim.lsp.start({
      name = "lectic",
      cmd = { "lectic", "lsp" },
      root_dir = vim.fs.root(args.buf, { ".git", "lectic.yaml" })
                 or vim.fn.getcwd(),
      single_file_support = true,
    })
  end,
})

VS Code setup - The server is an external stdio LSP. You can connect to it from a VS Code extension. The repository includes extra/lectic.vscode for a ready‑made extension.

Diagnostics - The server publishes diagnostics on open/change. - Header field validation covers missing or mistyped interlocutor properties (name, prompt, model, provider, etc.). Unknown top‑level properties on an interlocutor are reported as warnings (for example, Unknown property "mood" on interlocutor A.). - Duplicate names in the document header are warned with precise ranges. Later entries win at runtime; the warning helps catch mistakes. - Duplicates originating only from included configs may be reported with a coarse header-range warning.

Folding - The LSP provides folding ranges for tool‑call and inline‑attachment blocks. A block must be a serialized <tool-call ...> ... </tool-call> or <inline-attachment ...> ... </inline-attachment> that appears as a direct child of an interlocutor container directive (:::Name).

Hovers - Hover over a directive (e.g., :ask[...]) to see a short description. - Hover on a macro directive name (e.g., :summarize[]) to preview the macro expansion.

Notes - Completion previews are static; the server does not expand macros or read files referenced by file:.