🖥️ TUI completo
A TUI do Hermes é construída sobre Textual e Rich. Não é um REPL bobo: renderiza markdown, syntax highlight em 200+ linguagens, streaming token-a-token, edição multilinha com Vim-like keybindings opcionais, e mostra um painel lateral com custo/tokens em tempo real.
💡 O que torna a TUI especial
- •Streaming real: cada token aparece assim que chega do provider — você corta cedo se a resposta divergir
- •Multiline native:
Alt+Enterinsere quebra,Enterenvia — sem hacks de heredoc - •Autocomplete de slash-commands: digite
/e veja toda a paleta com descrições - •Paste detection: blocos grandes viram anexos automaticamente em vez de poluir o histórico
- •Painel de custo: tokens in/out e USD acumulado por sessão visíveis o tempo todo
# Slash-commands úteis no dia-a-dia
/help # paleta de comandos
/clear # zera contexto (mantém memória persistente)
/cost # quebra detalhada do gasto da sessão
/model gpt-5 # troca de modelo a quente
/reload # recarrega config.yaml sem sair
/skills # lista skills disponíveis
/tools # lista toolsets ativos
/export markdown # exporta a conversa atual
💡 Dica
Se você roda dentro do tmux, exporte TERM=tmux-256color e ative true-color (set -ag terminal-overrides ",*:RGB"). Sem isso o syntax highlight fica pastel.
📡 Gateway de mensagens
O gateway é o cérebro de roteamento: cada entrada — venha do terminal, de um webhook do Discord, do Slack RTM, de um POST HTTP ou de um cron job — é normalizada em um objeto Message com channel, user_id, content e attachments. Daí o agente nem sabe de onde veio.
┌──────────┐ ┌──────────┐ ┌─────────┐
│ CLI/TUI │ │ Discord │ │ Slack │ ... HTTP, Cron
└────┬─────┘ └────┬─────┘ └────┬────┘
│ │ │
└──────┬───────┴───────┬──────┘
▼ ▼
┌──────────────────────┐
│ Gateway Adapter │ → normaliza p/ Message
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Agent Core (loop) │ → escolhe toolset + modelo
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Tool Executor │ → fs, shell, web, mcp, ...
└──────────┬───────────┘
▼
┌──────────────────────┐
│ LLM Provider │ → OpenRouter / Anthropic / ...
└──────────┬───────────┘
▼
Resposta → mesmo canal de origem
✓ O que FAZER
- ✓Habilitar idempotência por
message_id(Discord retransmite) - ✓Definir
rate_limitpor canal — Slack baniu mais de uma instância distraída - ✓Logar o canal de origem em todos os spans de tracing
✗ O que NÃO fazer
- ✗Rodar uma instância por canal — você perde memória compartilhada
- ✗Confiar em ordem de mensagens — webhooks chegam fora de ordem
- ✗Responder síncrono em canais com timeout curto (HTTP <30s)
🧰 Sistema de toolsets
O Hermes vem com 40+ ferramentas nativas agrupadas em toolsets coerentes. Cada toolset é uma unidade ligável/desligável — porque colocar todas as 40 no system prompt destrói a precisão do modelo.
📊 Toolsets nativos
- filesystem — read/write/edit/glob/grep (8 tools)
- shell — bash execução com sandbox opcional (3 tools)
- web — fetch, search, scrape (5 tools)
- code — python/node REPL, lint, test runner (6 tools)
- memory — recall, save, forget, list_skills (4 tools)
- scheduling — cron_add, cron_list, cron_delete (3 tools)
- discord/slack — send_dm, post_channel, get_thread (~10 tools)
# config.yaml — habilita só o que precisa
toolsets:
- name: filesystem
enabled: true
paths_allowed: ["~/projects", "/tmp"]
- name: shell
enabled: true
sandbox: docker # ou "none" se você confia
timeout_seconds: 30
- name: web
enabled: true
rate_limit: "10/min"
- name: code
enabled: false # só ligo quando preciso
- name: memory
enabled: true
💡 Dica
Regra empírica: nunca passe dos 25 tools simultaneamente. Acima disso, modelos médios começam a chamar a ferramenta errada (ex: usam bash quando deveriam usar read_file).
🔌 Protocolo MCP
O Hermes é cliente MCP first-class. Qualquer servidor que fale o protocolo (stdio JSON-RPC ou HTTP+SSE) entra como toolset extra — sem escrever nenhuma linha de Python. Isso abre a porta para o ecossistema crescente do MCP: GitHub oficial, Notion, Postgres, Playwright, Linear, Sentry, Filesystem-extended, etc.
# config.yaml — plugando 3 MCPs
mcp_servers:
github:
transport: stdio
command: "npx"
args: ["-y", "@modelcontextprotocol/server-github"]
env:
GITHUB_TOKEN: ${GITHUB_TOKEN}
postgres:
transport: stdio
command: "npx"
args: ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
playwright:
transport: http
url: "http://localhost:8931/sse"
✓ O que FAZER
- ✓Pinear versão do servidor MCP (
@1.4.2) — APIs mudam - ✓Usar transporte
stdiosempre que possível — zero rede, zero auth - ✓Inspecionar tools com
/tools mcp:githubantes de usar
✗ O que NÃO fazer
- ✗Conectar 10 MCPs "por garantia" — cada um adiciona 5-20 tools no contexto
- ✗Expor MCP HTTP sem auth na rede pública
- ✗Confiar cegamente em servidores MCP de terceiros sem ler o código
⏰ Integração Cron
O Hermes embute um scheduler (APScheduler) que dispara prompts ou ferramentas em horários cron — sem depender do crontab do SO nem de um Kubernetes CronJob.
Você registra um job
Via tool cron_add ou direto no YAML
Ex: "todo dia às 8h, busca métricas do Stripe e me manda no Discord"
Scheduler persiste em SQLite
Reinício do processo não perde jobs
Cada job tem id, cron_expr, prompt, channel, last_run.
No tick, o gateway injeta a mensagem
Como se o cron fosse um usuário virtual
Mesmo pipeline normal: toolsets, LLM, ferramenta, resposta no canal configurado.
Retry exponencial
Falhou? Tenta de novo
Backoff 1m → 5m → 30m, depois marca como failed e te avisa.
schedules:
- id: daily-stripe-report
cron: "0 8 * * *"
timezone: "America/Sao_Paulo"
channel: discord:#financeiro
prompt: |
Busque o MRR de ontem no Stripe, compare com a média dos
últimos 7 dias e poste um resumo de 3 linhas com setas.
🎛️ Configuração declarativa
Tudo no Hermes — provider, modelo, toolsets, MCPs, canais, cron, system prompts — vive num único config.yaml versionado. Substituições ${VAR} permitem secrets via env, e perfis (dev/prod) eliminam duplicação.
profile: ${HERMES_PROFILE:-dev}
provider:
name: openrouter
api_key: ${OPENROUTER_API_KEY}
model: anthropic/claude-sonnet-4.6
fallback: openai/gpt-5-mini
system_prompt: |
Você é o Hermes, agente pessoal do Nei.
Português BR direto. Quando errar, admita.
channels:
cli: { enabled: true }
discord:
enabled: ${DISCORD_ENABLED:-false}
token: ${DISCORD_TOKEN}
memory:
backend: sqlite
path: ~/.hermes/memory.db
retention_days: 365
profiles:
prod:
provider:
model: anthropic/claude-opus-4.7
memory:
retention_days: 730
💡 Dica
Commite o config.yaml sem secrets e use .env local ignorado. No prod, secrets vão para AWS Secrets Manager / GCP Secret Manager via env-var injection.
⚠️ Atenção
Nunca coloque api_key literal no YAML. O /reload é hot, mas vai recarregar o arquivo do disco — secrets em texto plano vazam para o git history se você esquecer.
✅ Resumo do Módulo
Textual + Rich entregam streaming, multiline, autocomplete e painel de custo nativos.
CLI, Discord, Slack, HTTP e cron viram o mesmo objeto Message antes do LLM.
40+ ferramentas agrupadas e ligáveis — habilite só o que importa, não passe de 25 simultâneas.
Plugue qualquer servidor MCP via stdio/HTTP — ecossistema inteiro disponível sem código.
Jobs agendados rodam dentro do mesmo processo, com persistência, retry e timezone.
Um YAML versionado define o agente inteiro — perfis e env-vars cobrem dev/prod.
Próximo módulo:
2.2 — 🧠 Loop de Aprendizado e Memória: como o agente cria skills sozinho, FTS5, Honcho e OpenRouter.