Por que no lemon-code a telemetria vem desligada, aponta para um Collector local e nunca exporta prompt, resposta ou caminho de arquivo
English summary: How lemon-code adds OpenTelemetry as an opt-in, best-effort output on top of local SQLite metrics, with a local Collector by default and a strict rule against exporting prompts, responses, paths or secrets.
Publicado: 4 de novembro de 2026
Tempo de leitura: 8 min
Série: lemon-code em 30 dias, parte 8 de 13
A telemetria do lemon-code vem desligada. Quando ativada, usa localhost como endpoint padrão. Os sinais instrumentados não incluem prompts, respostas, argumentos de ferramenta ou caminhos de arquivo.
Mesmo assim, ela responde perguntas úteis: quanto durou cada turno, quantas vezes caiu em fallback e por que aquele modelo foi escolhido. Este post mostra como.
O estado padrão, em uma linha:
telemetry.enabled = false # e, quando ligada: endpoint http://localhost:4318
estimated_cost é uma estimativa para observabilidade; o SQLite local continua sendo a fonte canônica.Pense num avião. Ele tem duas fontes de dados. A caixa-preta grava tudo, fica a bordo e é a fonte da verdade. O painel e o link com a torre mostram um resumo em tempo real. Se o link cair, o avião continua voando e a caixa-preta continua gravando.
No lemon-code, o SQLite local é a caixa-preta. O OpenTelemetry é o link com a torre: uma saída adicional que não recalcula nada, não substitui o SQLite e nunca pode bloquear uma execução.
Ligar a telemetria são três comandos, apontando para um Collector que você roda:
lc config set telemetry.endpoint http://localhost:4318
lc config set telemetry.exportIntervalMs 60000
lc config set telemetry.enabled true
E o padrão de código que garante que a telemetria nunca derrube o agente é este (reescrito e simplificado):
// exportar sem nunca bloquear o turno (ilustrativo)
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("lemon-code");
const tokens = meter.createCounter("gen_ai.client.token.usage");
export function recordTurn(t: { provider: string; model: string; input: number; output: number }) {
try {
const attrs = { "gen_ai.system": t.provider, "gen_ai.request.model": t.model };
tokens.add(t.input, { ...attrs, "gen_ai.token.type": "input" });
tokens.add(t.output, { ...attrs, "gen_ai.token.type": "output" });
// nada de prompt, resposta, caminho ou argumento de ferramenta aqui
} catch {
// telemetria é best-effort: falhar aqui não pode afetar o agente
}
}
Os atributos são só identificadores e números. O conteúdo da conversa nunca entra.
Produtos gratuitos e pagos para transformar ideias em uma base que você consegue executar.
13 produtos disponíveisContinue explorando tópicos similares
Meu agente escolhia o modelo e eu não sabia por quê. Hoje cada escolha vem com uma linha como 'anthropic score 71.5 (risk +20, order +50)'. Este post mostra como chegar nisso.

Seis meses depois, alguém pergunta por que o sistema classificou aquele caso assim. Se a resposta depende de lembrar qual prompt estava no ar, você não tem sistema auditável — tem folclore.

Preço por token é o número do fornecedor. Custo por tarefa concluída é o seu. Entre os dois existem retries, tarefas que falham, contexto que cresce e um nível de esforço que ninguém varre.
Checklist prático para validar segurança, custos, avaliações e observabilidade antes de colocar seu app com IA em produção.
Templates testados em produção, usados por desenvolvedores. Economize semanas de setup no seu próximo projeto.
| Default | Motivo |
|---|---|
telemetry.enabled=false | nenhum exportador ativo por padrão |
endpoint http://localhost:4318 | Collector local via OTLP/HTTP; o endpoint pode ser configurado |
| export a cada 60 s | envio periódico de métricas |
| sem conteúdo | prompts, respostas, argumentos e resultados de ferramenta, caminhos e segredos ficam fora |
Se o Collector exigir autenticação, o header vai na variável de ambiente OTEL_EXPORTER_OTLP_HEADERS, nunca no repositório.
Execuções usam dados já normalizados por turno:
gen_ai.client.token.usage: tokens de entrada e saída reportados pelo provider.gen_ai.client.operation.duration: duração em segundos.lemon.gen_ai.executions, lemon.gen_ai.fallbacks e lemon.gen_ai.estimated_cost.invoke_agent: provider, modelo, resultado, tokens, custo estimado e IDs locais de correlação.O roteamento do post 4 também aparece:
lemon.dispatch.task.score: complexidade, risco, contexto, multimodal e sensibilidade a custo.lemon.prompt.quality.score: clareza, contexto, restrições e verificação.lemon.resource.utilization: CPU e memória no momento da decisão.A qualidade de prompt é uma heurística local e determinística. Ela não chama LLM e não deve ser confundida com qualidade da resposta.
lemon.gen_ai.estimated_cost é uma estimativa de observabilidade, não um registro contábil completo. O SQLite local permanece como fonte canônica para consultar execuções e uso.
Uso contado duas vezes. Alguns providers mandam o uso acumulado no último chunk do streaming e de novo no resultado de tool-use. Somar os dois dobra o número. O lemon-code conta uma vez por chamada e reaproveita o último total.
Observar um agente não exige anexar a conversa à telemetria. Números, identificadores e scores bastam para acompanhar duração, fallback e roteamento. O SQLite continua sendo a caixa-preta local.
Na sexta fecho a parte de engenharia do lemon-code com o que aprendi construindo CLI e app nativo ao mesmo tempo.
Se o seu time precisa de observabilidade para agentes ou features com LLM sem expor dados de usuário, é um trabalho que faço na LEMON.DEV.