Documentação oficial desta página · v0.20.6
Language Server Protocol (LSP)
O Hermes roda language servers completos — pyright, gopls, rust-analyzer,
typescript-language-server, clangd e uns 20 outros — como subprocessos
em segundo plano e injeta os diagnósticos semânticos deles na
verificação de lint pós-escrita usada por write_file e patch. Quando
o agente edita um arquivo, ele vê exatamente os erros que aquela edição
introduziu — não só erros de sintaxe, mas erros de tipo, nomes não
definidos, imports faltando e problemas semânticos de todo o projeto
que o language server detecta.
É a mesma arquitetura que os melhores agentes de programação usam. O Hermes entrega isso autocontido: sem precisar de um editor hospedeiro, sem plugins para instalar, sem daemon separado para administrar.
Quando o LSP roda
O LSP depende da detecção de espaço de trabalho git. Quando o diretório de trabalho do agente (ou o arquivo em edição) está dentro de um repositório git, o LSP roda contra esse espaço de trabalho. Quando nenhum dos dois está em um repositório git, o LSP fica dormente — útil para gateways de mensagem, em que o cwd é o diretório home do usuário e não há projeto nenhum para diagnosticar.
A verificação é em camadas: primeiro a checagem de sintaxe no próprio processo (microssegundos), depois os diagnósticos do LSP quando a sintaxe está limpa. Um language server instável ou ausente nunca consegue quebrar uma escrita — todo caminho de falha do LSP cai silenciosamente no resultado só de sintaxe.
Na prática, em cada write_file ou patch bem-sucedido:
- O Hermes captura uma linha de base dos diagnósticos atuais do arquivo.
- Realiza a escrita.
- Consulta o language server de novo, filtra os diagnósticos que já estavam na linha de base e mostra apenas os novos.
O agente vê uma saída assim:
{
"bytes_written": 42,
"dirs_created": false,
"lint": {"status": "ok", "output": ""},
"lsp_diagnostics": "LSP diagnostics introduced by this edit:\n<diagnostics file=\"/caminho/do/foo.py\">\nERROR [42:5] Cannot find name 'foo' [reportUndefinedVariable] (Pyright)\nERROR [50:1] Argument of type \"str\" is not assignable to \"int\" [reportArgumentType] (Pyright)\n</diagnostics>"
}
O campo lint carrega o resultado da checagem de sintaxe (parse no
próprio processo, em microssegundos, via ast.parse, json.loads
etc.); o campo lsp_diagnostics carrega os diagnósticos semânticos do
language server de verdade. Dois canais, sinais independentes — o
agente vê um arquivo com sintaxe limpa e problemas semânticos como
lint: ok mais um lsp_diagnostics preenchido.
Linguagens suportadas
| Linguagem | Servidor | Instalação automática |
|---|---|---|
| Python | pyright-langserver | npm |
| TypeScript / JavaScript / JSX / TSX | typescript-language-server | npm |
| Vue | @vue/language-server | npm |
| Svelte | svelte-language-server | npm |
| Astro | @astrojs/language-server | npm |
| Go | gopls | go install |
| Rust | rust-analyzer | manual (rustup) |
| C / C++ | clangd | manual (LLVM) |
| Bash / Zsh | bash-language-server | npm |
| YAML | yaml-language-server | npm |
| Lua | lua-language-server | manual (releases do GitHub) |
| PHP | intelephense | npm |
| OCaml | ocaml-lsp | manual (opam) |
| Dockerfile | dockerfile-language-server-nodejs | npm |
| Terraform | terraform-ls | manual |
| Dart | dart language-server | manual (SDK do dart) |
| Haskell | haskell-language-server | manual (ghcup) |
| Julia | julia + LanguageServer.jl | manual |
| Clojure | clojure-lsp | manual |
| Nix | nixd | manual |
| Zig | zls | manual |
| Gleam | gleam lsp | manual (gleam install) |
| Elixir | elixir-ls | manual |
| Prisma | prisma language-server | manual |
| Kotlin | kotlin-language-server | manual |
| Java | jdtls | manual |
| PowerShell | PowerShellEditorServices (host pwsh) | manual (zip da release) |
Nos casos marcados como "manual", instale o servidor pelo gerenciador de
toolchain que fizer sentido para aquela linguagem (rustup, ghcup, opam,
brew…). O Hermes detecta o binário sozinho, no PATH ou em
<HERMES_HOME>/lsp/bin/.
PowerShell
O PowerShellEditorServices não é um binário único — é um pacote de
módulos do PowerShell iniciado por um host pwsh (PowerShell 7+) ou
powershell. Configuração:
- Instale o PowerShell para
que
pwsh(ou opowershelldo Windows) fique no PATH. - Baixe o zip da release mais recente em releases do PowerShellEditorServices e extraia.
- Aponte o Hermes para o pacote extraído — o diretório que contém
PowerShellEditorServices/Start-EditorServices.ps1. Faça de um destes jeitos:- defina
lsp.servers.powershell.command: ["/caminho/do/pacote"]noconfig.yaml, ou - extraia para
<HERMES_HOME>/lsp/PowerShellEditorServices, ou - exporte
PSES_BUNDLE_PATH=/caminho/do/pacote.
- defina
O hermes lsp status reporta installed quando encontra o pwsh; se o
pacote estiver faltando, você vê um aviso único nos logs com o link de
download.
Alguns servidores são instalados junto com uma dependência par que o npm
não baixa sozinho. O caso atual é o typescript-language-server, que
precisa que o SDK typescript seja importável da mesma árvore
node_modules — o Hermes instala os dois pacotes juntos quando você
roda hermes lsp install typescript ou quando a instalação automática
dispara no primeiro uso.
CLI
hermes lsp status # estado do serviço + status de instalação de cada servidor
hermes lsp list # registro, opcionalmente com --installed-only
hermes lsp install <id> # instala um servidor de imediato
hermes lsp install-all # tenta todo servidor que tenha receita conhecida
hermes lsp restart # derruba os clientes em execução
hermes lsp which <id> # imprime o caminho resolvido do binário
O hermes lsp status é o melhor ponto de partida — ele mostra quais
linguagens vão ter diagnósticos semânticos hoje e quais precisam de um
binário instalado.
Configuração
Os padrões funcionam para instalações típicas; não há nada para definir se os binários estão no PATH.
# config.yaml
lsp:
# Chave-mestra. Desligar pula o subsistema inteiro — nenhum servidor
# sobe, nenhum laço de eventos em segundo plano roda.
enabled: true
# Quanto esperar por diagnósticos depois de cada escrita.
wait_mode: document # "document" ou "full"
# Máximo de segundos a esperar até o servidor re-checar o arquivo
# depois de uma edição. Só diagnósticos *frescos* (produzidos para o
# conteúdo pós-edição) são reportados; se o servidor não terminar
# dentro desse orçamento, a edição reporta "no LSP data" em vez de
# erros velhos de antes da edição. Aumente para servidores lentos em
# projetos grandes (tsserver, rust-analyzer indexando).
wait_timeout: 5.0
# O que fazer quando falta o binário do servidor.
# auto — instala via npm/pip/go install em <HERMES_HOME>/lsp/bin
# manual — usa só binários que já estão no PATH
install_strategy: auto
# Quanto tempo um cliente de language server sem uso fica vivo (segundos).
# Servidores ociosos são desligados automaticamente e sobem de novo na
# próxima operação de arquivo relevante. Defina 0 para desligar a coleta
# por ociosidade e manter os servidores vivos por toda a vida do
# processo. Valores abaixo de 30s são elevados a 30, para que uma
# varredura nunca colete um cliente no meio de uma operação.
idle_timeout: 600
# Sobrescritas por servidor (todas opcionais).
servers:
pyright:
disabled: false
command: ["/caminho/absoluto/do/pyright-langserver", "--stdio"]
env: { PYRIGHT_LOG_LEVEL: "info" }
initialization_options:
python:
analysis:
typeCheckingMode: "strict"
typescript:
disabled: true # pula o TS mesmo quando as extensões batem
Chaves por servidor
disabled: true— pula este servidor por completo, mesmo quando as extensões dele batem com um arquivo.command: [bin, ...args]— fixa um caminho de binário personalizado. Ignora a instalação automática.env: {KEY: value}— variáveis de ambiente extras passadas ao processo criado.initialization_options: {...}— mesclado no payloadinitializationOptionsdo LSP, enviado no aperto de mão doinitialize. É específico de cada servidor; consulte a documentação do language server.
Locais de instalação
Com install_strategy: auto, o Hermes instala os binários em
<HERMES_HOME>/lsp/bin/. Pacotes NPM caem em
<HERMES_HOME>/lsp/node_modules/, com links simbólicos dos binários um
nível acima. Os binários Go vêm de go install, com o GOBIN apontado
para o diretório de preparo.
Nada nunca é instalado em /usr/local/, ~/.local/ ou qualquer outro
local compartilhado — o diretório de preparo é 100% do Hermes e é
removido quando você reseta o perfil.
Características de desempenho
Os servidores LSP sobem de forma preguiçosa, no primeiro uso. Editar
um arquivo Python em um projeto que nunca viu tráfego de .py faz subir
o pyright; a subida leva de 1 a 3 segundos na maioria dos servidores (o
rust-analyzer pode levar mais de 10 em um projeto frio). As edições
seguintes no mesmo espaço de trabalho reaproveitam o servidor em
execução.
A camada de LSP acrescenta poucos milissegundos às escritas limpas,
quando nenhum diagnóstico é emitido. Quando há diagnósticos, o orçamento
de espera é de wait_timeout segundos — normalmente o servidor responde
em dezenas de milissegundos no pyright/tsserver e em alguns segundos no
rust-analyzer enquanto indexa.
Os diagnósticos têm controle de frescor: um resultado só conta quando
o servidor o produziu para o conteúdo da edição atual (um push de
publishDiagnostics no momento da mudança ou depois dela, ou uma
consulta respondida depois dela). Servidores lentos que ainda não
re-checaram resultam em "sem dados" para aquela edição — nunca nos erros
de ontem sendo reportados como atuais.
Os servidores são mantidos vivos enquanto estão em uso e desligados
depois de lsp.idle_timeout segundos (600 por padrão) sem atividade de
arquivo — um gateway de vida longa que mexe em muitas worktrees não
acumula mais um processo de language server por espaço de trabalho para
sempre. Um servidor coletado sobe de novo automaticamente na próxima
operação de arquivo relevante. Defina idle_timeout: 0 para desligar a
coleta e manter o índice de todo servidor quente por toda a vida do
processo.
Como desligar
Defina lsp.enabled: false no config.yaml para desligar o subsistema
inteiro. A verificação pós-escrita cai na checagem de sintaxe no próprio
processo (ast.parse para Python, json.loads para JSON etc.), que vem
inalterada das versões anteriores.
Para desligar uma única linguagem sem desligar a camada toda:
lsp:
servers:
rust-analyzer:
disabled: true
Resolução de problemas
O hermes lsp status mostra um servidor como "missing"
O binário não está no PATH nem em <HERMES_HOME>/lsp/bin/. Rode
hermes lsp install <server_id> para tentar a instalação automática, ou
instale o binário na mão, pela toolchain normal da linguagem.
Seção Backend warnings no hermes lsp status
Alguns servidores vêm como cascas finas em volta de uma CLI externa que
faz o diagnóstico de verdade — eles sobem limpos e aceitam requisições,
mas nunca emitem erros quando o binário auxiliar está faltando. O caso
mais comum é o bash-language-server, que delega os diagnósticos ao
shellcheck. Quando o hermes lsp status mostra uma seção
Backend warnings, instale a ferramenta indicada pelo gerenciador de
pacotes do seu sistema:
apt install shellcheck # Debian / Ubuntu
brew install shellcheck # macOS
scoop install shellcheck # Windows
O mesmo aviso é registrado uma vez, na hora em que o servidor sobe, em
~/.hermes/logs/agent.log.
O servidor sobe, mas nunca devolve diagnósticos
Procure entradas [agent.lsp.client] em ~/.hermes/logs/agent.log — o
stderr do language server e os erros de protocolo caem ali. Alguns
servidores (o rust-analyzer em especial) precisam terminar um índice de
todo o projeto antes de emitir diagnósticos por arquivo; a primeira
edição depois de o servidor subir pode terminar sem diagnóstico nenhum,
e as edições seguintes já pegam tudo.
O servidor quebrou
Um servidor que quebra entra no conjunto de defeituosos e não é tentado
de novo pelo resto da sessão. Rode hermes lsp restart para limpar o
conjunto; a próxima edição sobe o servidor outra vez.
Editar um arquivo fora de qualquer repositório git
Por decisão de projeto, o LSP só roda dentro de um repositório git. Se o
projeto ainda não foi inicializado, rode git init para habilitar os
diagnósticos do LSP. Fora disso, vale o fallback só de sintaxe no
próprio processo.