Documentação oficial desta página · v0.20.6
Instalação com Nix e NixOS
Nix e NixOS são plataformas de nível 2. O flake e o módulo NixOS documentados aqui são mantidos apenas na base do melhor esforço. Commits na main podem quebrar esses pacotes a qualquer momento.
Para uma instalação com suporte, use um dos caminhos padrão de instalação — Docker ou um ambiente FHS.
O Hermes Agent traz um flake Nix, um módulo NixOS e um módulo do Home Manager.
| Nível | Para quem é | O que você ganha |
|---|---|---|
nix run / nix profile install | Qualquer pessoa que use Nix (macOS, Linux) | Binário pré-compilado com todas as dependências — daí em diante, o fluxo normal da CLI |
| Módulo do Home Manager | Um agente para uma pessoa, em qualquer distribuição ou no macOS | Configuração declarativa e um serviço de usuário, sem root |
| Módulo NixOS (nativo) | Implantações em servidor NixOS | Configuração declarativa, serviço systemd endurecido, segredos administrados |
| Módulo NixOS (contêiner) | Agentes que precisam se automodificar | Tudo acima, mais um contêiner Ubuntu persistente onde o agente pode rodar apt/pip/npm install |
O instalador curl | bash administra Python, Node e dependências por conta própria. O flake Nix substitui tudo isso — cada dependência Python é uma derivação Nix construída pelo uv2nix, e as ferramentas de execução (Node.js, git, ripgrep, ffmpeg) são embrulhadas no PATH do binário. Não há pip em tempo de execução, nem ativação de venv, nem npm install.
Para quem não usa NixOS, isso só muda o passo de instalação. Tudo depois (hermes setup, hermes gateway install, edição de configuração) funciona igualzinho à instalação padrão.
Para quem usa o módulo NixOS, o ciclo de vida inteiro é diferente: a configuração vive no configuration.nix, os segredos passam por sops-nix/agenix, o serviço é uma unidade systemd, e os comandos de configuração da CLI ficam bloqueados. Você administra o hermes do mesmo jeito que administra qualquer outro serviço NixOS.
Pré-requisitos
- Nix com flakes habilitados — recomendamos o Determinate Nix (que já habilita flakes por padrão)
- Chaves de API dos serviços que você quer usar (no mínimo: uma chave da OpenRouter ou da Anthropic)
Início rápido (qualquer pessoa que use Nix)
Não precisa clonar. O Nix busca, constrói e roda tudo:
# Roda o aplicativo desktop
nix run github:NousResearch/hermes-agent#desktop
# Ou instala de forma persistente
nix profile install github:NousResearch/hermes-agent#desktop
# roda a tui
nix run github:NousResearch/hermes-agent -- setup
nix run github:NousResearch/hermes-agent -- --tui
# ou instala no seu perfil
nix profile install github:NousResearch/hermes-agent
hermes setup
hermes --tui
Depois do nix profile install, o hermes, o hermes-agent e o hermes-acp ficam no seu PATH. Daqui em diante, o fluxo é idêntico ao da instalação padrão — o hermes setup te guia pela escolha de provedor, o hermes gateway install configura um serviço de usuário launchd (macOS) ou systemd, e a configuração fica em ~/.hermes/.
O pacote padrão inclui TODAS as bibliotecas de que o hermes-agent pode precisar. Se você quer uma variante menor, veja as outras saídas do flake.
O pacote default acrescenta cerca de 700 MB ao fecho. Se você só precisa das plataformas de mensagem, o #messaging acrescenta apenas cerca de 33 MB.
Rodar a partir de um clone local
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
nix develop
hermes setup
Módulo NixOS
O flake exporta nixosModules.default — um módulo completo de serviço NixOS que administra de forma declarativa a criação de usuário, os diretórios, a geração de configuração, os segredos, os documentos e o ciclo de vida do serviço.
Este módulo precisa de NixOS. O Hermes é um agente para uma pessoa. Se você quer um agente para uma pessoa e não um serviço de sistema, use o módulo do Home Manager. Aquele módulo roda no NixOS e em cada outro sistema que o Home Manager suporta.
Acrescentar a entrada do flake
# /etc/nixos/flake.nix (ou o flake do seu sistema)
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
hermes-agent.url = "github:NousResearch/hermes-agent";
};
outputs = { nixpkgs, hermes-agent, ... }: {
nixosConfigurations.your-host = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
hermes-agent.nixosModules.default
./configuration.nix
];
};
};
}
Configuração mínima
# configuration.nix
{ config, ... }: {
services.hermes-agent = {
enable = true;
settings.model.default = "anthropic/claude-sonnet-4";
environmentFiles = [ config.sops.secrets."hermes-env".path ];
addToSystemPackages = true;
};
}
É isso. O nixos-rebuild switch cria o usuário hermes, gera o config.yaml, liga os segredos e sobe o gateway — um serviço de longa duração que conecta o agente às plataformas de mensagem (Telegram, Discord etc.) e fica ouvindo as mensagens que chegam.
A linha environmentFiles acima assume que você tem sops-nix ou agenix configurado. O arquivo deve conter pelo menos uma chave de provedor de LLM (por exemplo, OPENROUTER_API_KEY=sk-or-...). Veja Gestão de segredos para a configuração completa. Se você ainda não tem um gerenciador de segredos, pode usar um arquivo simples como ponto de partida — só garanta que ele não seja legível por todo mundo:
echo "OPENROUTER_API_KEY=sk-or-sua-chave" | sudo install -m 0600 -o hermes /dev/stdin /var/lib/hermes/env
services.hermes-agent.environmentFiles = [ "/var/lib/hermes/env" ];
Definir addToSystemPackages = true faz duas coisas: põe a CLI hermes no PATH do sistema e define HERMES_HOME para o sistema inteiro, para que a CLI interativa compartilhe o estado (sessões, skills, cron) com o serviço de gateway. Sem isso, rodar hermes no seu shell cria um diretório ~/.hermes/ separado.
CLI ciente do contêiner
Quando container.enable = true e addToSystemPackages = true, todo comando hermes no host é roteado automaticamente para dentro do contêiner administrado. Isso quer dizer que a sua sessão interativa de CLI roda no mesmo ambiente do serviço de gateway — com acesso a todos os pacotes e ferramentas instalados no contêiner.
- O roteamento é transparente:
hermes chat,hermes sessions list,hermes --versionetc. todos entram no contêiner por baixo dos panos - Todas as opções da CLI são repassadas como estão
- Se o contêiner não estiver rodando, a CLI tenta de novo por um tempinho (5s com um indicador, para uso interativo; 10s em silêncio, para scripts) e então falha com um erro claro — sem fallback silencioso
- Para quem desenvolve na base de código do hermes, defina
HERMES_DEV=1para contornar o roteamento por contêiner e rodar direto o clone local
Defina container.hostUsers para criar um link simbólico ~/.hermes apontando para o diretório de estado do serviço, de modo que a CLI do host e o contêiner compartilhem sessões, configuração e memórias:
services.hermes-agent = {
container.enable = true;
container.hostUsers = [ "seu-usuario" ];
addToSystemPackages = true;
};
Quem estiver listado em hostUsers é acrescentado automaticamente ao grupo hermes, para ter permissão de acesso aos arquivos.
Quem usa Podman: o serviço NixOS roda o contêiner como root. Quem usa Docker ganha acesso pelo socket do grupo docker, mas os contêineres com root do Podman exigem sudo. Conceda sudo sem senha para o seu runtime de contêiner:
security.sudo.extraRules = [{
users = [ "seu-usuario" ];
commands = [{
command = "/run/current-system/sw/bin/podman";
options = [ "NOPASSWD" ];
}];
}];
A CLI detecta sozinha quando o sudo é necessário e o usa de forma transparente. Sem isso, você vai precisar rodar sudo hermes chat na mão.
Confirme que funciona
Depois do nixos-rebuild switch, confira se o serviço está rodando:
# Confere o status do serviço
systemctl status hermes-agent
# Acompanha os logs (Ctrl+C para parar)
journalctl -u hermes-agent -f
# Se addToSystemPackages estiver true, teste a CLI
hermes --version
hermes config # mostra a configuração gerada
Escolher um modo de implantação
O módulo suporta dois modos, controlados por container.enable:
| Nativo (padrão) | Contêiner | |
|---|---|---|
| Como roda | Serviço systemd endurecido no host | Contêiner Ubuntu persistente com /nix/store montado por bind |
| Segurança | NoNewPrivileges, ProtectSystem=strict, PrivateTmp | Isolamento de contêiner, roda como usuário sem privilégio lá dentro |
| O agente pode instalar pacotes sozinho | Não — só as ferramentas do PATH fornecido pelo Nix | Sim — instalações com apt, pip e npm sobrevivem a reinícios |
| Superfície de configuração | A mesma | A mesma |
| Quando escolher | Implantações padrão, segurança máxima, reprodutibilidade | O agente precisa instalar pacotes em tempo de execução, ambiente mutável, ferramentas experimentais |
Para habilitar o modo contêiner, acrescente uma linha:
{
services.hermes-agent = {
enable = true;
container.enable = true;
# ... o resto da configuração é idêntico
};
}
O modo contêiner habilita sozinho o virtualisation.docker.enable, via mkDefault. Se você usa Podman, defina container.backend = "podman" e virtualisation.docker.enable = false.
Configuração
Configurações declarativas
A opção settings aceita um attrset arbitrário, que é renderizado como config.yaml. Ela suporta mesclagem profunda entre várias definições de módulo (via lib.recursiveUpdate), então você pode dividir a configuração em vários arquivos:
# base.nix
services.hermes-agent.settings = {
model.default = "anthropic/claude-sonnet-4";
toolsets = [ "all" ];
terminal = { backend = "local"; timeout = 180; };
};
# personality.nix
services.hermes-agent.settings = {
display = { compact = false; personality = "kawaii"; };
memory = { memory_enabled = true; user_profile_enabled = true; };
};
As duas são mescladas em profundidade na hora da avaliação. As chaves declaradas no Nix sempre vencem as chaves de um config.yaml já existente no disco, mas as chaves acrescentadas pelo usuário, nas quais o Nix não mexe, são preservadas. Ou seja: se o agente ou uma edição manual acrescentar chaves como skills.disabled ou streaming.enabled, elas sobrevivem ao nixos-rebuild switch.
O settings.model.default usa o identificador de modelo que o seu provedor espera. Com o OpenRouter (o padrão), eles são assim: "anthropic/claude-sonnet-4" ou "google/gemini-3-flash". Se você usa um provedor direto (Anthropic, OpenAI), defina settings.model.base_url apontando para a API dele e use os IDs de modelo nativos (por exemplo, "claude-sonnet-4-20250514"). Quando nenhum base_url está definido, o Hermes assume o OpenRouter.
Rode nix build .#configKeys && cat result para ver cada chave folha de configuração extraída do DEFAULT_CONFIG do Python. Você pode colar o seu config.yaml existente dentro do attrset settings — a estrutura é 1:1.
Exemplo completo: todas as configurações que costumam ser personalizadas
{ config, ... }: {
services.hermes-agent = {
enable = true;
container.enable = true;
# ── Modelo ─────────────────────────────────────────────────────────
settings = {
model = {
base_url = "https://openrouter.ai/api/v1";
default = "anthropic/claude-opus-4.6";
};
toolsets = [ "all" ];
max_turns = 100;
terminal = { backend = "local"; cwd = "."; timeout = 180; };
compression = {
enabled = true;
threshold = 0.85;
summary_model = "google/gemini-3-flash-preview";
};
memory = { memory_enabled = true; user_profile_enabled = true; };
display = { compact = false; personality = "kawaii"; };
agent = { max_turns = 60; verbose = false; };
};
# ── Segredos ───────────────────────────────────────────────────────
environmentFiles = [ config.sops.secrets."hermes-env".path ];
# ── Documentos ─────────────────────────────────────────────────────
# USER.md é memória, então vai para HERMES_HOME. Arquivos do espaço de
# trabalho usam `documents`, e essa opção exige um `workingDirectory` explícito.
hermesHomeFiles = {
"memories/USER.md" = ./documents/USER.md;
};
# ── Servidores MCP ─────────────────────────────────────────────────
mcpServers.filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};
# ── Opções de contêiner ────────────────────────────────────────────
container = {
image = "ubuntu:24.04";
backend = "docker";
hostUsers = [ "seu-usuario" ];
extraVolumes = [ "/home/user/projects:/projects:rw" ];
extraOptions = [ "--gpus" "all" ];
};
# ── Ajuste do serviço ──────────────────────────────────────────────
addToSystemPackages = true;
extraArgs = [ "--verbose" ];
restart = "always";
restartSec = 5;
};
}
Saída de emergência: traga a sua própria configuração
Se você prefere administrar o config.yaml totalmente fora do Nix, use configFile:
services.hermes-agent.configFile = /etc/hermes/config.yaml;
Isso ignora o settings por completo — sem mesclagem, sem geração. O arquivo é copiado como está para $HERMES_HOME/config.yaml a cada ativação.
Colinha de personalização
Referência rápida das coisas que quem usa Nix mais quer personalizar:
| Eu quero... | Opção | Exemplo |
|---|---|---|
| Trocar o modelo de LLM | settings.model.default | "anthropic/claude-sonnet-4" |
| Usar outro endpoint de provedor | settings.model.base_url | "https://openrouter.ai/api/v1" |
| Acrescentar chaves de API | environmentFiles | [ config.sops.secrets."hermes-env".path ] |
| Dar uma identidade ao agente | hermesHomeFiles."SOUL.md" | "Você é um assistente de operações direto ao ponto." |
| Acrescentar contexto de projeto ao espaço de trabalho | documents."AGENTS.md" | ./documents/AGENTS.md |
| Rodar o backend do aplicativo desktop ou do painel | backend.mode | "serve" ou "dashboard" |
| Acrescentar servidores de ferramentas MCP | mcpServers.<name> | Veja Servidores MCP |
| Habilitar Discord/Telegram/Slack | extraDependencyGroups | [ "messaging" ] |
| Montar diretórios do host no contêiner | container.extraVolumes | [ "/data:/data:rw" ] |
| Passar acesso a GPU para o contêiner | container.extraOptions | [ "--gpus" "all" ] |
| Usar Podman em vez de Docker | container.backend | "podman" |
| Compartilhar estado entre a CLI do host e o contêiner | container.hostUsers | [ "sidbin" ] |
| Disponibilizar ferramentas extras ao agente | extraPackages | [ pkgs.pandoc pkgs.imagemagick ] |
| Usar uma imagem base personalizada | container.image | "ubuntu:24.04" |
| Sobrescrever o pacote do hermes | package | inputs.hermes-agent.packages.${system}.default.override { ... } |
| Mudar o diretório de estado | stateDir | "/opt/hermes" |
| Definir o diretório de trabalho do agente | workingDirectory | "/home/user/projects" |
Gestão de segredos
settings nem em environmentValores em expressões Nix vão parar em /nix/store, que é legível por todo mundo. Sempre use environmentFiles com um gerenciador de segredos.
Tanto o environment (variáveis não secretas) quanto o environmentFiles (arquivos de segredo) são mesclados em $HERMES_HOME/.env na hora da ativação (nixos-rebuild switch). O Hermes lê esse arquivo a cada inicialização, então as mudanças passam a valer com um systemctl restart hermes-agent — sem precisar recriar o contêiner.
sops-nix
{
sops = {
defaultSopsFile = ./secrets/hermes.yaml;
age.keyFile = "/home/user/.config/sops/age/keys.txt";
secrets."hermes-env" = { format = "yaml"; };
};
services.hermes-agent.environmentFiles = [
config.sops.secrets."hermes-env".path
];
}
O arquivo de segredos contém pares de chave e valor:
# secrets/hermes.yaml (criptografado com sops)
hermes-env: |
OPENROUTER_API_KEY=sk-or-...
TELEGRAM_BOT_TOKEN=123456:ABC...
ANTHROPIC_API_KEY=sk-ant-...
agenix
{
age.secrets.hermes-env.file = ./secrets/hermes-env.age;
services.hermes-agent.environmentFiles = [
config.age.secrets.hermes-env.path
];
}
Semeadura de OAuth / autenticação
Para plataformas que exigem OAuth (o Discord, por exemplo), use authFile para semear as credenciais na primeira implantação:
{
services.hermes-agent = {
authFile = config.sops.secrets."hermes/auth.json".path;
# authFileForceOverwrite = true; # sobrescreve a cada ativação
};
}
O arquivo só é copiado se o auth.json ainda não existir (a menos que authFileForceOverwrite = true). As renovações de token OAuth em tempo de execução são gravadas no diretório de estado e preservadas entre reconstruções.
Documentos
O Hermes lê arquivos de dois diretórios. Por isso existem duas opções. Use a opção do diretório para onde o arquivo precisa ir.
O documents instala no diretório de trabalho do agente, que é o workingDirectory. O agente lê o contexto de projeto dele nesse espaço de trabalho:
{
services.hermes-agent = {
# documents precisa desta opção. Leia a nota abaixo.
workingDirectory = "/var/lib/hermes/workspace";
documents = {
"AGENTS.md" = ./documents/AGENTS.md; # referência de caminho, copiada do store do Nix
"notes/oncall.md" = "Chame o #infra antes de reiniciar qualquer coisa.";
};
};
}
O módulo recusa o documents até você definir o workingDirectory. O padrão
dessa opção é diferente em cada módulo. É o seu diretório home no Home
Manager, e ${stateDir}/workspace no NixOS. Logo, um padrão não definido põe os
arquivos em um diretório que você não escolheu. Um diretório com o mesmo caminho
do padrão é uma escolha correta, e satisfaz a regra.
O hermesHomeFiles instala em HERMES_HOME. O Hermes lê nesse diretório o arquivo de identidade e os arquivos de memória do agente. O SOUL.md e o memories/ só funcionam a partir dali. Um SOUL.md em documents vira um arquivo do espaço de trabalho. O Hermes não carrega esse arquivo como identidade:
{
services.hermes-agent.hermesHomeFiles = {
"SOUL.md" = "Você é um assistente de IA prestativo.";
"memories/USER.md" = ./documents/USER.md;
};
}
Cada valor é uma string ou um caminho. Uma chave de qualquer uma das opções pode conter subdiretórios, e o módulo cria os diretórios pais. Cada ativação instala os arquivos de novo.
O hermesHomeFiles não precisa de workingDirectory, porque o módulo é dono do diretório HERMES_HOME. A maioria das pessoas quer o hermesHomeFiles.
Servidores MCP
A opção mcpServers configura de forma declarativa os servidores MCP (Model Context Protocol). Cada servidor usa transporte stdio (comando local) ou HTTP (URL remota).
Transporte stdio (servidores locais)
{
services.hermes-agent.mcpServers = {
filesystem = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-filesystem" "/data/workspace" ];
};
github = {
command = "npx";
args = [ "-y" "@modelcontextprotocol/server-github" ];
env.GITHUB_PERSONAL_ACCESS_TOKEN = "\${GITHUB_TOKEN}"; # resolvido a partir do .env
};
};
}
As variáveis de ambiente nos valores de env são resolvidas a partir de $HERMES_HOME/.env em tempo de execução. Use environmentFiles para injetar segredos — nunca ponha tokens direto na configuração Nix.
Transporte HTTP (servidores remotos)
{
services.hermes-agent.mcpServers.remote-api = {
url = "https://mcp.example.com/v1/mcp";
headers.Authorization = "Bearer \${MCP_REMOTE_API_KEY}";
timeout = 180;
};
}
Transporte HTTP com OAuth
Defina auth = "oauth" para servidores que usam OAuth 2.1. O Hermes implementa o fluxo PKCE completo — descoberta de metadados, registro dinâmico de cliente, troca de token e renovação automática.
{
services.hermes-agent.mcpServers.my-oauth-server = {
url = "https://mcp.example.com/mcp";
auth = "oauth";
};
}
Os tokens ficam guardados em $HERMES_HOME/mcp-tokens/<server-name>.json e sobrevivem a reinícios e reconstruções.
Autorização OAuth inicial em servidores sem interface
A primeira autorização OAuth exige um fluxo de consentimento pelo navegador. Em uma implantação sem interface, o Hermes imprime a URL de autorização no stdout/logs em vez de abrir um navegador.
Opção A: inicialização interativa — rode o fluxo uma vez via docker exec (contêiner) ou sudo -u hermes (nativo):
# Modo contêiner
docker exec -it hermes-agent \
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
# Modo nativo
sudo -u hermes HERMES_HOME=/var/lib/hermes/.hermes \
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
O contêiner usa --network=host, então o ouvinte de retorno do OAuth em 127.0.0.1 é alcançável pelo navegador do host.
Opção B: pré-semear os tokens — complete o fluxo em uma estação de trabalho e depois copie os tokens:
hermes mcp add my-oauth-server --url https://mcp.example.com/mcp --auth oauth
scp ~/.hermes/mcp-tokens/my-oauth-server{,.client}.json \
server:/var/lib/hermes/.hermes/mcp-tokens/
# Garanta: chown hermes:hermes, chmod 0600
Sampling (requisições de LLM iniciadas pelo servidor)
Alguns servidores MCP podem pedir completações de LLM ao agente:
{
services.hermes-agent.mcpServers.analysis = {
command = "npx";
args = [ "-y" "analysis-server" ];
sampling = {
enabled = true;
model = "google/gemini-3-flash";
max_tokens_cap = 4096;
timeout = 30;
max_rpm = 10;
};
};
}
Modo administrado
Quando o hermes roda pelo módulo NixOS, os comandos de CLI a seguir ficam bloqueados, com um erro descritivo que te aponta para o configuration.nix:
| Comando bloqueado | Por quê |
|---|---|
hermes setup | A configuração é declarativa — edite o settings na sua configuração Nix |
hermes config edit | A configuração é gerada a partir do settings |
hermes config set <key> <value> | A configuração é gerada a partir do settings |
hermes gateway install | O serviço systemd é administrado pelo NixOS |
hermes gateway uninstall | O serviço systemd é administrado pelo NixOS |
Isso evita a deriva entre o que o Nix declara e o que está no disco. A detecção usa dois sinais:
- A variável de ambiente
HERMES_MANAGED. O serviço a define, e o processo do gateway a lê. - O arquivo marcador
.managedemHERMES_HOME. O script de ativação o escreve, e um shell interativo o lê. Assim, a CLI também bloqueia um comando comodocker exec -it hermes-agent hermes config set ....
Os dois sinais guardam o nome do sistema que administra a instalação. Assim, a recusa aponta o comando de reconstrução correto. O módulo NixOS indica sudo nixos-rebuild switch. O módulo do Home Manager indica home-manager switch.
Módulo do Home Manager
O flake também exporta homeManagerModules.default. O Hermes é um agente para uma pessoa. As credenciais, a memória, as sessões e as tarefas de cron pertencem todas a essa pessoa. Logo, um serviço de usuário é o formato correto em uma máquina pessoal. Ele roda em cada distribuição que o Home Manager suporta, e não só no NixOS.
O conjunto de opções é o mesmo que o módulo NixOS usa. É o services.hermes-agent, com as mesmas opções settings, environmentFiles, documents, mcpServers, extraPlugins e backend. Cada exemplo acima funciona aqui sem mudança. Só as partes necessárias são diferentes:
| Módulo NixOS | Módulo do Home Manager | |
|---|---|---|
| Roda como | um usuário de sistema que você declara, com user, group e createUser | você |
| Diretório de estado | stateDir e /.hermes | hermesHome, definido direto. O padrão é ~/.hermes. |
| Serviço | systemd.services | systemd.user.services no Linux, launchd.agents no macOS |
| CLI no PATH | addToSystemPackages, que exporta HERMES_HOME para o sistema inteiro | programs.hermes-agent.enable, que exporta só para a sua sessão |
| Aplicativo desktop | sem suporte, porque um serviço de sistema não pode ser dono de uma sessão de usuário | programs.hermes-agent.desktop.enable |
| Modo contêiner | com suporte | sem suporte, porque precisa de root e do socket do Docker |
Acrescentar a entrada do flake
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
hermes-agent.url = "github:NousResearch/hermes-agent";
};
}
Depois, importe o módulo na sua configuração do Home Manager. A configuração pode ser autônoma. Também pode ficar sob home-manager.users.<name> em uma configuração NixOS ou nix-darwin:
{
imports = [ hermes-agent.homeManagerModules.default ];
services.hermes-agent = {
enable = true;
gateway.enable = true;
settings.model.default = "anthropic/claude-sonnet-4";
environmentFiles = [ config.sops.secrets."hermes-env".path ];
};
}
O home-manager switch cria o ~/.hermes, escreve o config.yaml, monta o .env e sobe o gateway como serviço de usuário.
CUIDADO: habilite o linger para a sua conta. Sem linger, o systemd para o gerenciador de usuário quando a sua última sessão termina, e o gateway para junto. O Home Manager não consegue definir o linger, porque o linger é uma propriedade da conta:
# NixOS
users.users.your-username.linger = true;
# em qualquer outro lugar
sudo loginctl enable-linger seu-usuario
O macOS não tem opção equivalente. Um agente launchd com RunAtLoad inicia no login e continua rodando.
Rodar o backend do Desktop / do painel
O gateway.enable roda o gateway de mensagens para Telegram, Discord, Slack e as outras plataformas. O Hermes Desktop e o painel web se conectam a um processo diferente, que é o hermes serve ou o hermes dashboard. O backend.mode roda esse processo junto com o gateway:
{
services.hermes-agent = {
enable = true;
gateway.enable = true; # plataformas de mensagem
backend.mode = "dashboard"; # + o painel de navegador em 127.0.0.1:9119
backend.port = 9119;
};
}
O serve roda sem interface de usuário. Ele dá os sockets /api/ws e /api/pty aos quais o Hermes Desktop se conecta, e não constrói a aplicação web. O dashboard dá tudo isso e ainda serve o painel de administração no navegador. Os dois processos usam um mesmo HERMES_HOME com o gateway. Assim, as sessões, as skills, a memória e as tarefas de cron são as mesmas para todos eles. O backend.mode funciona do mesmo jeito no módulo NixOS, mas não no modo contêiner.
O endereço padrão é 127.0.0.1. Cada outro endereço ativa o portão de autenticação do painel. O servidor também recusa cada requisição com um cabeçalho Host diferente do endereço em que o servidor se ligou. Isso é uma defesa contra DNS rebinding. Ligue no nome ou no endereço que o seu cliente usa.
Confirme que funciona
# Linux
systemctl --user status hermes-agent
journalctl --user -u hermes-agent -f
# macOS
launchctl list | grep hermes
tail -f ~/Library/Logs/hermes-agent.log
hermes --version
hermes config # mostra a configuração que o Nix escreveu
Arquitetura do contêiner
Esta seção só interessa se você usa container.enable = true. Pule no caso de implantações em modo nativo.
Com o modo contêiner habilitado, o hermes roda dentro de um contêiner Ubuntu persistente, com o binário construído pelo Nix montado por bind, somente leitura, a partir do host:
Host Contêiner
──── ─────────
/nix/store/...-hermes-agent-0.1.0 ──► /nix/store/... (ro)
~/.hermes -> /var/lib/hermes/.hermes (ponte por link simbólico, por hostUsers)
/var/lib/hermes/ ──► /data/ (rw)
├── current-package -> /nix/store/... (link simbólico, atualizado a cada reconstrução)
├── .gc-root -> /nix/store/... (impede o nix-collect-garbage)
├── .container-identity (hash sha256, dispara recriação)
├── .hermes/ (HERMES_HOME)
│ ├── .env (mesclado de environment + environmentFiles)
│ ├── config.yaml (gerado pelo Nix, mesclado em profundidade na ativação)
│ ├── .managed (arquivo marcador)
│ ├── .container-mode (metadados de roteamento: backend, exec_user etc.)
│ ├── state.db, sessions/, memories/ (estado de execução)
│ └── mcp-tokens/ (tokens OAuth dos servidores MCP)
├── home/ ──► /home/hermes (rw)
└── workspace/ (diretório de trabalho do agente)
├── AGENTS.md (da opção documents)
└── (arquivos criados pelo agente)
Camada gravável do contêiner (apt/pip/npm): /usr, /usr/local, /tmp
O binário construído pelo Nix funciona dentro do contêiner Ubuntu porque o /nix/store está montado por bind — ele traz o próprio interpretador e todas as dependências, então não depende das bibliotecas de sistema do contêiner. O ponto de entrada do contêiner resolve por um link simbólico current-package: /data/current-package/bin/hermes gateway run --replace. No nixos-rebuild switch, só o link simbólico é atualizado — o contêiner continua rodando.
O que sobrevive a quê
| Evento | Contêiner recriado? | /data (estado) | /home/hermes | Camada gravável (apt/pip/npm) |
|---|---|---|---|---|
systemctl restart hermes-agent | Não | Sobrevive | Sobrevive | Sobrevive |
nixos-rebuild switch (mudança de código) | Não (link simbólico atualizado) | Sobrevive | Sobrevive | Sobrevive |
| Reinício do host | Não | Sobrevive | Sobrevive | Sobrevive |
nix-collect-garbage | Não (raiz de GC) | Sobrevive | Sobrevive | Sobrevive |
Mudança de imagem (container.image) | Sim | Sobrevive | Sobrevive | Perdida |
| Mudança de volume/opções | Sim | Sobrevive | Sobrevive | Perdida |
Mudança em environment/environmentFiles | Não | Sobrevive | Sobrevive | Sobrevive |
O contêiner só é recriado quando o hash de identidade dele muda. O hash cobre: versão de esquema, imagem, extraVolumes, extraOptions e o script de ponto de entrada. Mudanças em variáveis de ambiente, configurações, documentos ou no próprio pacote do hermes não disparam recriação.
Quando o hash de identidade muda (atualização de imagem, volumes novos, opções novas de contêiner), o contêiner é destruído e recriado a partir de um download novo da container.image. Todo pacote instalado com apt install, pip install ou npm install na camada gravável se perde. O estado em /data e em /home/hermes é preservado (esses são montagens de bind).
Se o agente depende de pacotes específicos, considere assá-los em uma imagem personalizada (container.image = "my-registry/hermes-base:latest") ou escrever a instalação deles em um script no SOUL.md do agente.
Proteção da raiz de GC
O script preStart cria uma raiz de GC em ${stateDir}/.gc-root, apontando para o pacote atual do hermes. Isso impede que o nix-collect-garbage remova o binário em execução. Se a raiz de GC quebrar de algum jeito, reiniciar o serviço a recria.
Plugins
O módulo NixOS suporta instalação declarativa de plugins — sem precisar do imperativo hermes plugins install.
Plugins de diretório (extraPlugins)
Para plugins que são só uma árvore de fontes com plugin.yaml + __init__.py (por exemplo, o hermes-lcm):
services.hermes-agent.extraPlugins = [
(pkgs.fetchFromGitHub {
owner = "stephenschoettler";
repo = "hermes-lcm";
rev = "v0.7.0";
hash = "sha256-...";
})
];
Os plugins são ligados por link simbólico em $HERMES_HOME/plugins/ na hora da ativação. O Hermes os descobre pela varredura normal de diretório. Tirar um plugin da lista e rodar nixos-rebuild switch remove o link simbólico.
Plugins de ponto de entrada (extraPythonPackages)
Para plugins empacotados com pip, que se registram via [project.entry-points."hermes_agent.plugins"] (por exemplo, o rtk-hermes):
services.hermes-agent.extraPythonPackages = [
(pkgs.python312Packages.buildPythonPackage {
pname = "rtk-hermes";
version = "1.0.0";
src = pkgs.fetchFromGitHub {
owner = "ogallotti";
repo = "rtk-hermes";
rev = "v1.0.0";
hash = "sha256-...";
};
format = "pyproject";
build-system = [ pkgs.python312Packages.setuptools ];
})
];
O site-packages do pacote é acrescentado ao PYTHONPATH no embrulho do hermes. O importlib.metadata descobre o ponto de entrada no início da sessão.
Grupos de dependências opcionais (extraDependencyGroups)
Para os extras opcionais declarados no pyproject.toml do hermes-agent, use o extraDependencyGroups para incluí-los na venv selada em tempo de construção. Isso é obrigatório para qualquer extra que não esteja no conjunto [all] padrão — no Nix, instalar em tempo de execução dentro do store somente leitura é impossível.
# Habilita Discord, Telegram, Slack
services.hermes-agent.extraDependencyGroups = [ "messaging" ];
# Habilita um provedor de memória
services.hermes-agent = {
extraDependencyGroups = [ "hindsight" ];
settings.memory.provider = "hindsight";
};
Isso é resolvido pelo uv junto com as dependências centrais — sem remendo de PYTHONPATH, sem risco de colisão. Grupos disponíveis:
| Grupo | O que ele habilita |
|---|---|
messaging | Discord, Telegram, Slack |
matrix | Matrix/Element (mautrix com criptografia; só Linux) |
dingtalk | DingTalk |
feishu | Feishu/Lark |
voice | Transcrição de fala local (faster-whisper) |
edge-tts | Provedor Edge TTS |
tts-premium | TTS da ElevenLabs |
anthropic | SDK nativo da Anthropic (dispensável via OpenRouter) |
bedrock | AWS Bedrock (boto3) |
azure-identity | Autenticação Azure Entra ID |
honcho | Provedor de memória Honcho |
hindsight | Provedor de memória Hindsight |
modal | Backend de terminal Modal |
daytona | Backend de terminal Daytona |
exa | Busca na web Exa |
firecrawl | Busca na web Firecrawl |
fal | Geração de imagem FAL |
Ou use os pacotes de flake prontos #messaging ou #full, em vez de configurar extra por extra (veja Início rápido).
Quando usar cada um:
| Necessidade | Opção |
|---|---|
| Habilitar um extra opcional do pyproject.toml | extraDependencyGroups |
| Acrescentar um plugin Python externo, fora do pyproject.toml | extraPythonPackages |
| Acrescentar um binário de sistema (pandoc, jq etc.) | extraPackages |
| Acrescentar uma árvore de fontes de plugin de diretório | extraPlugins |
Combinar os dois
Um plugin de diretório com dependências Python de terceiros precisa das duas opções:
services.hermes-agent = {
extraPlugins = [ my-plugin-src ]; # fonte do plugin
extraPythonPackages = [ pkgs.python312Packages.redis ]; # a dependência Python dele
extraPackages = [ pkgs.redis ]; # o binário de sistema de que ele precisa
};
Usar a overlay
Flakes externos podem sobrescrever o pacote direto:
{
inputs.hermes-agent.url = "github:NousResearch/hermes-agent";
outputs = { hermes-agent, nixpkgs, ... }: {
nixpkgs.overlays = [ hermes-agent.overlays.default ];
# Depois:
# pkgs.hermes-agent.override { extraPythonPackages = [...]; }
# pkgs.hermes-agent.override { extraDependencyGroups = [ "hindsight" ]; }
};
}
Configuração de plugins
Os plugins ainda precisam ser habilitados no config.yaml. Acrescente-os pelas configurações declarativas:
services.hermes-agent.settings.plugins.enabled = [
"hermes-lcm"
"rtk-rewrite"
];
Uma checagem de colisão em tempo de construção impede que pacotes de plugin sombreiem dependências centrais do hermes. Se um plugin fornece um pacote que já está na venv selada, o nixos-rebuild falha com um erro claro.
Desenvolvimento
Shell de desenvolvimento
O flake fornece um shell de desenvolvimento com Python 3.12, uv, Node.js e todas as ferramentas de execução:
cd hermes-agent
nix develop
# O shell fornece:
# - Python 3.12 + uv (dependências instaladas em .venv na primeira entrada)
# - Node.js 26, ripgrep, git, openssh, ffmpeg no PATH
# - Otimização por arquivo de carimbo: reentrar é quase instantâneo se as dependências não mudaram
hermes setup
hermes chat
direnv (recomendado)
O .envrc incluído ativa o shell de desenvolvimento automaticamente:
cd hermes-agent
direnv allow # uma vez só
# As entradas seguintes são quase instantâneas (o arquivo de carimbo pula a instalação de dependências)
Verificações do flake
O flake inclui verificações em tempo de construção que rodam no CI e na sua máquina:
# Roda todas as verificações
nix flake check
# Verificações individuais
nix build .#checks.x86_64-linux.package-contents # binários existem + versão
nix build .#checks.x86_64-linux.entry-points-sync # pyproject.toml ↔ pacote Nix em sincronia
nix build .#checks.x86_64-linux.cli-commands # subcomandos gateway/config
nix build .#checks.x86_64-linux.managed-guard # HERMES_MANAGED bloqueia mutação
nix build .#checks.x86_64-linux.bundled-skills # skills presentes no pacote
nix build .#checks.x86_64-linux.config-roundtrip # o script de mesclagem preserva as chaves do usuário
O que cada verificação confere
| Verificação | O que ela testa |
|---|---|
package-contents | Os binários hermes e hermes-agent existem e o hermes --version roda |
entry-points-sync | Cada entrada de [project.scripts] no pyproject.toml tem um binário embrulhado no pacote Nix |
cli-commands | O hermes --help expõe os subcomandos gateway e config |
managed-guard | O HERMES_MANAGED=true hermes config set ... imprime o erro do NixOS |
bundled-skills | O diretório de skills existe, contém arquivos SKILL.md e o HERMES_BUNDLED_SKILLS está definido no embrulho |
config-roundtrip | 7 cenários de mesclagem: instalação nova, sobrescrita pelo Nix, preservação de chave do usuário, mesclagem mista, mesclagem aditiva de MCP, mesclagem profunda aninhada, idempotência |
Referência de opções
Núcleo
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
enable | bool | false | Habilita o serviço hermes-agent |
package | package | hermes-agent | O pacote hermes-agent a usar |
user | str | "hermes" | Usuário do sistema |
group | str | "hermes" | Grupo do sistema |
createUser | bool | true | Cria usuário/grupo automaticamente |
stateDir | str | "/var/lib/hermes" | Diretório de estado (pai de HERMES_HOME) |
workingDirectory | str | "${stateDir}/workspace" | Diretório de trabalho do agente |
addToSystemPackages | bool | false | Acrescenta a CLI hermes ao PATH do sistema e define HERMES_HOME para o sistema inteiro |
Configuração
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
settings | attrs (mesclagem profunda) | {} | Configuração declarativa renderizada como config.yaml. Suporta aninhamento arbitrário; várias definições são mescladas via lib.recursiveUpdate |
configFile | null ou path | null | Caminho para um config.yaml existente. Sobrescreve o settings por completo, se definido |
Segredos e ambiente
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
environmentFiles | listOf str | [] | Caminhos de arquivos de ambiente com segredos. Mesclados em $HERMES_HOME/.env na hora da ativação |
environment | attrsOf str | {} | Variáveis de ambiente não secretas. Visíveis no store do Nix — não ponha segredos aqui |
authFile | null ou path | null | Semente de credenciais OAuth. Só copiada na primeira implantação |
authFileForceOverwrite | bool | false | Sempre sobrescreve o auth.json a partir do authFile na ativação |
Documentos
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
documents | attrsOf (either str path) | {} | Arquivos do espaço de trabalho. Cada chave é um caminho relativo ao workingDirectory. Você precisa definir essa opção para usar esta. |
hermesHomeFiles | attrsOf (either str path) | {} | Arquivos que vão para HERMES_HOME. O SOUL.md e o memories/ precisam estar aqui, senão o Hermes não os carrega. |
Servidores MCP
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
mcpServers | attrsOf submodule | {} | Definições de servidor MCP, mescladas em settings.mcp_servers |
mcpServers.<name>.command | null ou str | null | Comando do servidor (transporte stdio) |
mcpServers.<name>.args | listOf str | [] | Argumentos do comando |
mcpServers.<name>.env | attrsOf str | {} | Variáveis de ambiente do processo do servidor |
mcpServers.<name>.url | null ou str | null | URL do endpoint do servidor (transporte HTTP/StreamableHTTP) |
mcpServers.<name>.headers | attrsOf str | {} | Cabeçalhos HTTP, por exemplo Authorization |
mcpServers.<name>.auth | null ou "oauth" | null | Método de autenticação. "oauth" habilita o OAuth 2.1 PKCE |
mcpServers.<name>.enabled | bool | true | Habilita ou desabilita este servidor |
mcpServers.<name>.timeout | null ou int | null | Tempo limite de chamada de ferramenta, em segundos (padrão: 120) |
mcpServers.<name>.connect_timeout | null ou int | null | Tempo limite de conexão, em segundos (padrão: 60) |
mcpServers.<name>.tools | null ou submodule | null | Filtragem de ferramentas (listas include/exclude) |
mcpServers.<name>.sampling | null ou submodule | null | Configuração de sampling para requisições de LLM iniciadas pelo servidor |
Comportamento do serviço
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
extraArgs | listOf str | [] | Argumentos extras para o hermes gateway |
extraPackages | listOf package | [] | Pacotes extras disponíveis ao agente. Acrescentados ao perfil por usuário do hermes, para que comandos de terminal, skills e tarefas de cron os enxerguem |
extraPlugins | listOf package | [] | Pacotes de plugin de diretório a ligar por link simbólico em $HERMES_HOME/plugins/. Cada um precisa conter plugin.yaml |
extraPythonPackages | listOf package | [] | Pacotes Python acrescentados ao PYTHONPATH, para descoberta de plugin por ponto de entrada. Construa com python312Packages |
extraDependencyGroups | listOf str | [] | Extras opcionais do pyproject.toml a incluir na venv selada (por exemplo, ["hindsight"]). Resolvidos pelo uv — sem colisões |
restart | str | "always" | A política Restart= do systemd. O macOS não a usa. |
restartSec | int | 5 | O valor RestartSec= do systemd. O macOS não o usa. |
Backend (hermes serve / hermes dashboard)
Esta opção roda, junto com o gateway, o processo ao qual o Hermes Desktop e o painel web se conectam. Você não pode usá-la com container.enable.
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
backend.mode | enum ["none" "serve" "dashboard"] | "none" | O serve roda sem interface de usuário e dá /api/ws e /api/pty. O dashboard também serve o painel de navegador. |
backend.host | str | "127.0.0.1" | O endereço em que ligar. Cada endereço diferente do loopback ativa o portão de autenticação. |
backend.port | port | 9119 | A porta em que ligar |
backend.extraArgs | listOf str | [] | Mais argumentos para o comando de backend |
Só no Home Manager
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
hermesHome | str | "${config.home.homeDirectory}/.hermes" | O HERMES_HOME direto. O módulo NixOS o monta a partir do stateDir. |
gateway.enable | bool | false | Roda o gateway de mensagens. No módulo NixOS o gateway é o serviço, então aquele módulo não tem essa opção. |
programs.hermes-agent (só no Home Manager)
O Home Manager separa "instale esta aplicação para mim" de "rode este
daemon". O services.hermes-agent guarda o estado, a configuração e os
daemons. O programs.hermes-agent instala o que você usa, e lê o
hermesHome e o endereço do backend a partir dos serviços.
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
enable | bool | false | Acrescenta a CLI hermes a home.packages e exporta HERMES_HOME para os seus shells |
package | package | services.hermes-agent.package | O pacote a instalar. O padrão aplica o extraPythonPackages e o extraDependencyGroups dos serviços, então os dois são uma construção só. |
desktop.enable | bool | false | Acrescenta a aplicação Hermes Desktop, com uma entrada de lançador no Linux |
desktop.package | package | package.hermesDesktop | O pacote do desktop. O padrão segue o package, então a aplicação e os serviços rodam um mesmo runtime do Hermes. |
programs.hermes-agent = {
enable = true;
desktop.enable = true;
};
services.hermes-agent = {
enable = true;
backend.mode = "serve";
backend.sessionTokenFile = config.sops.secrets."hermes/desktop-token".path;
};
O lançador carrega o HERMES_HOME por conta própria. Um menu de desktop não lê
perfil de shell nenhum, então o valor que o programs.hermes-agent.enable
exporta com home.sessionVariables só chega a um shell interativo. Sem o
valor no lançador, a aplicação abre ~/.hermes enquanto os
serviços usam o hermesHome, e você não vê sessão nem chave nenhuma.
Com o backend.sessionTokenFile, a aplicação se conecta ao backend
do serviço em vez de subir um próprio. Os dois lados leem o
arquivo na inicialização, então o token não entra em nenhum caminho do store do Nix. Sem a
opção, cada lado roda o próprio backend.
O services.hermes-agent.installPackage foi removido por essa separação. Uma
configuração que ainda o define recebe um erro que nomeia a
substituição.
Contêiner (só NixOS)
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
container.enable | bool | false | Habilita o modo de contêiner OCI |
container.backend | enum ["docker" "podman"] | "docker" | Runtime de contêiner |
container.image | str | "ubuntu:24.04" | Imagem base (baixada em tempo de execução) |
container.extraVolumes | listOf str | [] | Montagens de volume extras (host:container:mode) |
container.extraOptions | listOf str | [] | Argumentos extras passados ao docker create |
container.hostUsers | listOf str | [] | Usuários interativos que ganham um link simbólico ~/.hermes para o stateDir do serviço e são acrescentados automaticamente ao grupo hermes |
Layout de diretórios
Modo nativo
/var/lib/hermes/ # stateDir (dono: hermes:hermes, 0750)
├── .hermes/ # HERMES_HOME
│ ├── SOUL.md # de hermesHomeFiles: a identidade do agente
│ ├── config.yaml # gerado pelo Nix (mesclado em profundidade a cada reconstrução)
│ ├── .managed # Marcador: mutação de configuração pela CLI bloqueada
│ ├── .env # Mesclado de environment + environmentFiles
│ ├── auth.json # Credenciais OAuth (semeadas e depois autoadministradas)
│ ├── gateway.pid
│ ├── state.db
│ ├── mcp-tokens/ # Tokens OAuth dos servidores MCP
│ ├── sessions/
│ ├── memories/
│ ├── skills/
│ ├── cron/
│ └── logs/
├── home/ # HOME do agente
└── workspace/ # Diretório de trabalho do agente
├── AGENTS.md # da opção documents
└── (arquivos criados pelo agente)
Home Manager
~/.hermes/ # hermesHome (HERMES_HOME), 0700
├── SOUL.md # de hermesHomeFiles
├── config.yaml # escrito pelo Nix, mesclado a cada ativação
├── .managed # marcador: nomeia o sistema que administra isto
├── .env # reescrito de environment + environmentFiles
├── auth.json # credenciais OAuth: semeadas e depois o Hermes é o dono
├── memories/ sessions/ skills/ cron/ logs/ plugins/
└── (estado de execução)
~/ # workingDirectory, o seu home por padrão
└── AGENTS.md # da opção documents
Modo contêiner
O mesmo layout, montado dentro do contêiner:
| Caminho no contêiner | Caminho no host | Modo | Observações |
|---|---|---|---|
/nix/store | /nix/store | ro | Binário do Hermes + todas as dependências Nix |
/data | /var/lib/hermes | rw | Todo o estado, configuração e espaço de trabalho |
/home/hermes | ${stateDir}/home | rw | Home persistente do agente — pip install --user, caches de ferramentas |
/usr, /usr/local, /tmp | (camada gravável) | rw | Instalações de apt/pip/npm — sobrevivem a reinícios, perdidas na recriação |
Atualizar
# Atualiza a entrada do flake (rode do diretório que contém o flake.nix)
cd /etc/nixos && nix flake update hermes-agent
# Reconstrói
sudo nixos-rebuild switch # para o módulo NixOS
home-manager switch # para o módulo do Home Manager
No modo contêiner, o link simbólico current-package é atualizado e o agente pega o binário novo no reinício. Sem recriação de contêiner, sem perda dos pacotes instalados.
Resolução de problemas
Todos os comandos docker abaixo funcionam igual com o podman. Substitua conforme o caso, se você definiu container.backend = "podman".
Logs do serviço
# Os dois modos usam a mesma unidade systemd
journalctl -u hermes-agent -f
# Modo contêiner: também disponível direto
docker logs -f hermes-agent
Inspeção do contêiner
systemctl status hermes-agent
docker ps -a --filter name=hermes-agent
docker inspect hermes-agent --format='{{.State.Status}}'
docker exec -it hermes-agent bash
docker exec hermes-agent readlink /data/current-package
docker exec hermes-agent cat /data/.container-identity
Forçar a recriação do contêiner
Se você precisa zerar a camada gravável (um Ubuntu novo):
sudo systemctl stop hermes-agent
docker rm -f hermes-agent
sudo rm /var/lib/hermes/.container-identity
sudo systemctl start hermes-agent
Confirmar que os segredos foram carregados
Se o agente sobe mas não consegue se autenticar no provedor de LLM, confira se o arquivo .env foi mesclado direito:
# Modo nativo
sudo -u hermes cat /var/lib/hermes/.hermes/.env
# Modo contêiner
docker exec hermes-agent cat /data/.hermes/.env
Verificação da raiz de GC
nix-store --query --roots $(docker exec hermes-agent readlink /data/current-package)
Problemas comuns
| Sintoma | Causa | Correção |
|---|---|---|
Cannot save configuration: managed by NixOS | Guardas da CLI ativas | Edite o configuration.nix e rode nixos-rebuild switch |
No adapter available for discord (ou telegram/slack) | Faltam as dependências de mensagem na venv Nix selada | Instale a variante #messaging: nix profile install ...#messaging. No módulo NixOS: extraDependencyGroups = [ "messaging" ]. Veja em journalctl -u hermes-agent se aparece FeatureUnavailable ou requirements not met, que trazem o erro de fundo. |
| Contêiner recriado sem aviso | extraVolumes, extraOptions ou image mudaram | Esperado — a camada gravável zera. Reinstale os pacotes ou use uma imagem personalizada |
hermes --version mostra versão antiga | Contêiner não reiniciado | systemctl restart hermes-agent |
Permissão negada em /var/lib/hermes | O diretório de estado é 0750 hermes:hermes | Use docker exec ou sudo -u hermes |
O nix-collect-garbage removeu o hermes | Raiz de GC faltando | Reinicie o serviço (o preStart recria a raiz de GC) |
no container with name or ID "hermes-agent" (Podman) | Contêiner rootful do Podman não visível ao usuário comum | Acrescente sudo sem senha para o podman (veja a seção Modo contêiner) |
unable to find user hermes | Contêiner ainda subindo (o ponto de entrada ainda não criou o usuário) | Espere alguns segundos e tente de novo — a CLI já tenta sozinha |
Ferramenta acrescentada por extraPackages não aparece no terminal | Exige nixos-rebuild switch para atualizar o perfil por usuário | Reconstrua e reinicie: nixos-rebuild switch && systemctl restart hermes-agent |