🔎 doctor e doctor --deep: config contra realidade
São dois diagnósticos diferentes com o mesmo comando. O npm run doctor lê configuração e ambiente: arquivos, variáveis, RAM, modelos do Ollama, CLIs, units do systemd, banco, conectores. Ele não muda nada e não chama o LLM. Já o npm run doctor -- --deep acrescenta quatro probes que exercitam o sistema de verdade, cada um marcado como probe para você reconhecer que o efeito colateral foi seu.
Legenda: a faixa tracejada de cima é inofensiva e pode rodar a qualquer hora. A faixa sólida de baixo manda mensagem no Telegram e enfileira um job de verdade, por isso cada linha vem com o rótulo deep:.
✓ O que o doctor comum responde
- ✓Falta key, falta arquivo, falta modelo:
.env v2 (keys compartilhadas),config/ollama.yaml,modelo roteador. - ✓A máquina aguenta:
RAMmostra GB disponíveis, total, swap usado e o piso para carregar modelo grande. - ✓Coexistência sã:
v2 ativo,v3 unit,v3 MemoryMax,mesmo modelo geral que o v2eollama serve paralelo.
✗ O que só o --deep pega
- ✗Serviço no ar mas com binário antigo: o job
doctor-probenão é reconhecido e a linha diz "serviço antigo sem a tarefa doctor-probe? reinstale". - ✗Token válido no arquivo mas o bot não entrega: só o
sendMessagereal mostra isso. - ✗Modelo listado no
tagsmas travado: o probe chama o papelroteadorpelo gateway e espera texto de volta.
⌘ Copie e rode: diagnóstico raso e diagnóstico profundo
Objetivo: ver a foto da configuração e, em seguida, provar que o caminho inteiro funciona de ponta a ponta.
cd ~/projetos/openpcbotv3
npm run doctor
npm run doctor -- --deep
Como verificar: a última linha diz Tudo crítico OK ou quantas falhas críticas existem, e o processo sai com código 1 quando há alguma. No --deep, as quatro linhas começam com deep: e trazem o tempo medido, por exemplo job #123 done em 900 ms. Uma mensagem com 🩺 e a palavra probe chega no seu Telegram: é o teste, não um alerta.
✦ Dica prática
O --deep precisa do serviço no ar: sem ele, a linha da fila sai como "pulado: serviço fora do ar" e conta como falha crítica. A ordem que economiza tempo é sempre a mesma: doctor primeiro, resolver o que estiver ❌, e só então --deep. O probe do Ollama grava em banco de memória e não entra em chamadas_llm, então diagnosticar não suja o seu relatório de custo.
📜 Journal e dashboard: as duas janelas do serviço
O v3 registra em log estruturado (pino, JSON) e tudo vai para o journal do systemd do usuário. Para leitura humana, o -o cat tira o carimbo do systemd e deixa só a linha do processo. A segunda janela é o dashboard em http://127.0.0.1:3142/, que mostra health, Ollama e RAM, fila por lane, custo dos últimos 14 dias com sparkline, custo por tier e por agente, memória e jobs recentes, atualizando a cada 10 s.
Acompanhe ao vivo
Enquanto manda uma mensagem
journalctl --user -u openpcbotv3 -f -o cat segue o log. É a forma de ver o caminho da mensagem acontecendo: canal, roteador, fila, resposta.
Olhe para trás
Depois de um erro
journalctl --user -u openpcbotv3 -n 50 --no-pager -o cat mostra as últimas 50 linhas sem abrir o paginador. É o comando que o CLAUDE.md do repo indica para diagnóstico.
Veja o conjunto
No navegador
O dashboard junta o que o log só conta linha a linha. Com DASHBOARD_TOKEN_V3 definido, / e /api/* passam a exigir o segredo; o /health continua aberto porque o hub wifi consome esse endpoint.
⌘ Copie e rode: log ao vivo e health cru
Objetivo: confirmar que o processo está vivo e ler o estado sem depender do Telegram.
systemctl --user is-active openpcbotv3
curl -s http://127.0.0.1:3142/health
journalctl --user -u openpcbotv3 -n 50 --no-pager -o cat
Como verificar: o primeiro comando responde active. O curl devolve JSON com ok, fila, modelos, RAM e orçamento. O journal termina nas linhas mais recentes do processo. Se a porta estiver mudada no .env, troque 3142 pelo valor de <seu-PORT_V3>.
✦ Escutar só em casa é o padrão
O HTTP escuta em 127.0.0.1 por padrão porque POST /mensagem dispara agente com as permissões da sua máquina. Expor na rede local só faz sentido com os dois juntos: HTTP_BIND_V3=0.0.0.0 e DASHBOARD_TOKEN_V3 preenchido. Um sem o outro é dashboard aberto para quem estiver no mesmo Wi-Fi.
📊 /health, /status e /usage: ler fila, Ollama, RAM e custo
Três comandos no chat cobrem a operação inteira sem sair do Telegram. O /health responde saúde, o /status responde trabalho e o /usage responde dinheiro. Vale saber o que é "saudável" para o v3: o GET /health devolve ok quando o Ollama está online, a RAM livre está em 10 GB ou mais e o heartbeat rodou há menos de 90 minutos.
| Comando | O que devolve | Quando usar |
|---|---|---|
/health | Ollama (modelos carregados e latência), RAM e swap, RSS do processo, fila, heartbeat, canais | O bot está lento ou mudo |
/status | Fila por lane: o que está rodando e o que está pendente | Pedi algo e não voltou |
/status <id-do-job> | Detalhe de um job, com resultado ou erro | Um job específico falhou |
/usage | Custo de hoje, da semana e do mês, por tier e por agente, mais o orçamento | Antes de pedir algo caro |
/ollama status | Estado do gestor do Ollama | Suspeita de modelo descarregado |
/daily | Tarefas, feitas nas últimas 24 h, custo do dia, fila, Ollama, MEMORY.md | Começo do dia, às 8h também sai sozinho |
Legenda: as lanes que aparecem no /status são chat (concorrência 2), agente (1), ollama (1), cron (1) e io (4). Job nunca é apagado: a fila é o histórico.
⌘ Copie e rode: a mesma leitura sem o Telegram
Objetivo: ler saúde e custo pela linha de comando, útil quando o canal do Telegram é justamente o que está quebrado. O npm run cli fala com o serviço no ar por POST /mensagem, e comando iniciado por barra é tratado igual em qualquer canal.
cd ~/projetos/openpcbotv3
npm run cli -- "/health"
npm run cli -- "/usage"
Como verificar: a saída é o mesmo texto que o bot mandaria no chat. No /health, confira RAM disponível e heartbeat; no /usage, o total do mês contra o ORCAMENTO_MENSAL_USD. Se o serviço estiver fora do ar, o CLI avisa que o v3 não respondeu na porta; com DASHBOARD_TOKEN_V3 definido, ele manda o segredo sozinho.
✦ Dica prática
Quando o /status mostrar algo preso, prefira operar a fila a reiniciar o serviço: /cancelar <id-do-job> tira o job sem corrida e /prioridade <id-do-job> <número> reordena o que ainda não começou. Restart é remédio de último caso, porque o drain gracioso espera até 110 s antes de abortar o que está em curso.
🔔 Alertas no Telegram e o dedupe de 30 minutos
O v3 avisa sozinho no chat permitido quando algo sai do lugar, e cada alerta tem uma chave própria com dedupe de 30 minutos: a mesma condição não vira dez mensagens seguidas. São sete gatilhos, e cada um tem uma resposta esperada de você.
Legenda: sem ALLOWED_CHAT_ID definido, o próprio doctor avisa que os alertas no Telegram estão desligados. O alerta não substitui o log: ele diz que olhar, o journal diz o que houve.
✓ Resposta certa ao alerta
- ✓Ollama fora: cheque o serviço do Ollama (
systemctl), não subaollama servenum terminal. - ✓RAM baixa: veja quem está residente com
/ollama status; descarregar só o que é do v3. - ✓Orçamento 70 %:
/usagepara ver qual tier ou agente puxou, e segure o premium até virar o mês.
✗ Reação que piora
- ✗Reiniciar o serviço a cada alerta: lease morto e zumbi já são recuperados sozinhos pelo heartbeat de 30 min.
- ✗Descarregar o modelo grande para liberar RAM sem olhar de quem ele é: o v3 nunca descarrega modelo alheio, e você não deve fazer na mão o que ele evita de propósito.
- ✗Ignorar o alerta de 3 falhas da mesma tarefa em 1 h: é exatamente o caso que vira linha no
FALHAS.md.
⌘ Copie e rode: achar o alerta no log
Objetivo: depois de receber um alerta no chat, encontrar no journal a linha que o originou.
journalctl --user -u openpcbotv3 --since "1 hour ago" -o cat | grep -i alerta
journalctl --user -u openpcbotv3 --since today -o cat | grep -i "<palavra-do-alerta>"
Como verificar: as linhas do log são JSON do pino, então cada uma traz o contexto completo do evento. Se o grep não achar nada e o alerta chegou, amplie a janela: o dedupe de 30 min pode ter suprimido as repetições, mas a primeira ocorrência está lá.
💾 Backup noturno: VACUUM INTO, cifra e retenção 14
Todo o estado do v3 mora num arquivo SQLite: fila, memórias, custo, preferências. O cron backup-noturno roda às 4h15 e usa VACUUM INTO, que produz uma cópia consistente mesmo com o banco em uso (WAL). Depois cifra com age se AGE_RECIPIENT estiver definido, ou comprime com gzip quando não estiver, e mantém os 14 arquivos mais recentes em store/backups/.
Cópia consistente
4h15, lane cron
O arquivo sai com carimbo de data e hora no nome, no formato openpcbotv3-<data-e-hora>.db. Nada é parado para isso: VACUUM INTO escreve um banco novo enquanto o atual segue recebendo escrita.
Cifra ou compressão
Com age, ou gzip
Com AGE_RECIPIENT o resultado é .db.age; sem ele, .db.gz. O doctor tem a linha age (backup cifrado) justamente para avisar quando o binário não está instalado e o backup cai para gzip.
Retenção de 14
Os mais antigos somem
Depois de gravar, o backup lista os arquivos que começam com openpcbotv3-, ordena do mais novo para o mais velho e apaga o que passar de 14. Se quiser guardar um marco, copie para fora de store/backups/.
⌘ Copie e rode: conferir que existe backup de ontem
Objetivo: provar que o cron noturno está de fato gravando, antes de precisar do arquivo.
ls -lht ~/projetos/openpcbotv3/store/backups/ | head -5
npm run cli -- "/cron lista"
Como verificar: o arquivo mais recente deve ser da madrugada passada e terminar em .age ou .gz. A lista nunca passa de 14 itens. No /cron lista, backup-noturno precisa aparecer ligado; /cron off backup-noturno e /cron on backup-noturno desligam e religam.
✦ Restaurar é trocar o arquivo, com o serviço parado
Restaurar quer dizer decifrar ou descomprimir o arquivo escolhido e pôr o banco de volta no lugar apontado por store/, com o serviço parado (systemctl --user stop openpcbotv3) para ninguém escrever no meio. O repo documenta a geração do backup, não uma receita de restauração passo a passo; guarde uma cópia do banco atual antes de sobrescrever qualquer coisa.
🚨 Quando quebra: parar, reinstalar, registrar
A ordem importa. Primeiro conter: /parar tudo <motivo> no chat bloqueia novos trabalhos na hora e /retomar libera; o interruptor fica gravado na tabela prefs, então sobrevive a restart. Depois diagnosticar com doctor e journal. Só então reinstalar com bash scripts/instalar-servico.sh, que é build mais restart. E, antes da próxima tarefa, registrar uma linha no FALHAS.md.
⌘ Copie e rode: o ciclo de recuperação
Objetivo: voltar de um serviço quebrado para um serviço saudável, na ordem que não perde informação.
cd ~/projetos/openpcbotv3
journalctl --user -u openpcbotv3 -n 50 --no-pager -o cat
npm run doctor
bash scripts/instalar-servico.sh
npm run doctor -- --deep
Como verificar: o script imprime as primeiras linhas do status e o MemoryMax lido do systemd. O serviço precisa terminar em active (running), e o --deep logo depois precisa fechar as quatro linhas de probe sem falha crítica. O restart é sempre com systemctl --user, sem sudo, e não encosta no v2.
✓ Garantias que já existem
- ✓Unit com
Restart=on-failureeRestartSec=5: queda isolada volta sozinha. - ✓
MemoryHigh=1536MeMemoryMax=2Gno cgroup, mais--max-old-space-size=1024no node: o v3 não come a RAM da máquina. - ✓Drain gracioso no
SIGTERM: renova o lease enquanto espera e aborta só depois de 110 s.
✗ O que não fazer na coexistência
- ✗Mudar a tag do papel
geralsó no v3: viram dois modelos grandes residentes e a máquina vai a OOM. - ✗Descarregar um modelo que o v3 não carregou: o
/ollama descarregarrecusa de propósito. - ✗Ligar Slack ou WhatsApp antes do corte: o v2 é dono da sessão e do token.
✦ Uma linha por falha, antes da próxima tarefa
O FALHAS.md na raiz do repo é uma tabela: data, o que quebrou, a menor correção possível e se era problema de prompt ou de infraestrutura. Mais recente no topo, uma linha só, sem narrativa. A coluna que mais ensina é a da menor correção: se a resposta foi reescrever um módulo, provavelmente faltava só uma proteção, um teto ou uma validação.
✦ Duas linhas reais do FALHAS.md
A primeira conversa do v3 falhou com Ollama error 400 porque keep_alive estava como string "-1" no YAML; a correção foi uma só, deixar o número. E o doctor acusava dois ollama serve e porta ocupada com o serviço parado, porque pgrep -f contava o próprio sh -c e um grep -c sem resultado sai com código 1; a correção foi pgrep -c -x e um || true. Duas linhas, dois consertos pequenos, nenhuma reescrita.
Chegou o alerta de RAM baixa e o modelo grande residente é o mesmo que o v2 usa. O que fazer?
✅ Resumo do módulo
Próximo módulo:
3.1 - Comandos e conversa