/cost, fecha e reinicia o período de contabilidade com /cost reset, revisa sessões passadas com /cost last e /cost sessions, exporta snapshots legíveis por máquina com /cost export, e configura limites de gasto — incluindo um hard stop opcional.
Comando /cost
/cost renderiza o resumo da sessão viva; quatro subcomandos gerenciam o período de contabilidade:
O resumo é renderizado como um painel em caixa (os valores abaixo são autoconsistentes para
claude-sonnet-5):
A linha Source reporta se a sessão tem uso real de API; cada linha de modelo no breakdown de custo carrega adicionalmente sua própria tag —
(API) para contagens reportadas pelo provider, (estimativa) para estimativa por caracteres — porque uma sessão pode misturar as duas. Reasoning tokens (o-series / GPT-5 / thinking do Gemini) ganham uma linha informativa própria quando presentes; já estão cobrados dentro de Output./cost os lista explicitamente (Sem tabela de preço para: provider/modelo — esse gasto NÃO está no total.), então um total sub-reportado sempre fica visível como tal.
Cache de Prompt por Provedor
O ChatCLI monta toda requisição com a parte que não muda entre turnos primeiro (system prompt, contextos anexados, catálogo de tools) e pede ao provedor para cacheá-la onde a API oferece um mecanismo para isso. A linha Cache de prompt do/cost e o cache NN% do rodapé do chat/agent são neutros de provedor: são calculados a partir dos campos de cache que cada provedor reporta, nos dois esquemas de contagem (Anthropic/Bedrock contam leituras de cache além do input; OpenAI/Gemini/Grok/Kimi contam como subconjunto do prompt).
- requisições — quantas chamadas reportaram atividade de cache.
- % do input vindo do cache — parcela do input da sessão servida pelo cache.
- misses instáveis — requisições que perderam o prefixo quando ele deveria estar quente. Cada requisição é julgada contra o que a anterior do mesmo provedor deixou legível: na Anthropic e no Bedrock tudo o que a anterior leu mais o que escreveu; na OpenAI, Gemini, xAI e Kimi o prompt inteiro da anterior. Ler de volta bem menos que isso (abaixo de 90%, ou 80% nos caches por bloco do esquema subconjunto) é a assinatura de um prefixo estável que mudou (troca de modelo/effort, conjunto de tools MCP, anexo atualizado). Uma escrita grande ou um prompt grande sozinhos nunca são miss — é assim que um tool result grande ou um arquivo colado aparecem num prefixo perfeitamente estável. Três misses instáveis seguidos imprimem um aviso único.
- atribuição — o cache de prompt de todo provider é chaveado por prefixo sobre as mesmas regiões na mesma ordem: definições de tools, blocos system, mensagens. Antes de cada requisição o ChatCLI faz o fingerprint dessas regiões e compara a lista com a da requisição anterior, então um prefixo perdido é creditado à primeira região que mudou:
conjunto de tools mudou,bloco system N mudou,mensagem N (tool result / bloco de skills / turn context / mensagem do usuário …) mudou,histórico encolheu. Uma perda numa requisição que só cresceu no fim é reportada comonenhuma mudança na requisição (lado do servidor ou tempo de vida)em vez de culpar o prompt. O/costimprime a tabela (prefixos perdidos por causa) e os últimos cinco eventos (#7 rebuild esperado · tempo de vida do cache promovido para 1h). Quando oautopromove o tempo de vida para uma hora depois de uma expiração observada, a linha de saúde diz quando (promovido para 1h em +13m), e a única reescrita que os marcadores novos forçam na requisição seguinte é declarada e atribuída à promoção em vez de contada como instabilidade. - faixas — a linha de saúde, os contadores de miss e a razão write/read descrevem só a conversa principal. O prompt de extração do memory worker e o loop próprio de um worker de squad compartilham o provider mas não o prefixo, então suas requisições entram em faixas próprias: contam em todo número de tokens e dólares, mas nunca como prefixo perdido da sua conversa. Seus buckets brutos de cache continuam no log por requisição.
- expirados — o prefixo foi perdido depois de uma pausa que o cache não sobreviveu (mais de 5 minutos ocioso, menos de uma hora). Contado à parte porque não diz nada sobre a estabilidade do prefixo; é também a evidência que a promoção para o TTL de uma hora usa.
- por provedor — “primeira requisição” e a razão de acertos são por provedor (cada um tem seu cache e seu schema), então trocar de provedor nunca gasta a “primeira” do outro, e a razão mostrada é a do último provedor usado. Nos provedores de schema-subconjunto (OpenAI, Gemini, xAI, Kimi) um prompt no mínimo cacheável ou acima, servido com
cached_tokens: 0depois da primeira requisição daquele provedor, conta como miss — então o alerta de 3 misses funciona neles também. O Bedrock reporta o TTL que o marcador de fato carregou (1h em Claude 4.5+ quando configurado). - rebuilds esperados — misses causados pelo próprio ChatCLI ao mudar o prefixo de propósito: reescrever a conversa (auto-compact,
/compact, microcompact, skill aging, recovery de overflow, edições de contexto do provedor) ou trocar o que o prefixo contém (/switchde provedor ou modelo,/agent attach|detach,/context attach|detach,/session load|attach, start/stop/restart/reload/login/logout de servidor MCP,pin|unpinde skill), além de reescrever a conversa (auto-compact,/compact, microcompact, envelhecimento de skills). Não é problema. - quente / frio — se a última atividade ainda está dentro do TTL do cache.
Prefixo byte-estável e a mensagem de contexto do turno
Todo provider cacheia por prefixo, então um system message que muda entre turnos faz todo breakpoint depois dele errar. O ChatCLI mantém o system message byte-estável na sessão: tudo que muda por turno — a data (resolução de dia), o recall proativo de memória e de sessões, skills auto-ativadas e manuais, pushes de canais MCP, o snapshot do watcher, passagens recuperadas — vai numa única mensagem com papel de usuário marcadaturn_context, colocada logo antes do seu turno e persistida com a conversa, então a próxima requisição repete bytes idênticos até o breakpoint anterior. Chat, as superfícies RPC e agent/coder compartilham o mecanismo; a mensagem injetada é rotulada nas exportações e ignorada pela extração de memória e pelos hints de recall. O prompt_cache_key da OpenAI hasheia só as partes estáveis marcadas para cache, e o budget do prefixo congela sua razão chars/token por sessão para que seções cacheadas não dobrem e desdobrem entre turnos.
Recursos explícitos de cache (Gemini)
O cache implícito é gratuito e automático. O Gemini também expõe o cache como recurso (cachedContents), com desconto garantido em toda leitura e cobrado como storage por token-hora (Flash 4,50/M/h, 3.x Flash $0,50/M/h). Como essa cobrança nunca aparece na resposta, é opt-in: CHATCLI_PROMPT_CACHE_EXPLICIT=true. A política é conservadora de propósito:
- O recurso carrega a system instruction inteira; a requisição o referencia e omite
system_instruction. - Só prompts de cerca de 4K+ tokens se qualificam, e o mesmo prompt precisa aparecer em duas requisições consecutivas antes de criar o recurso — um one-shot nunca paga storage.
- O tempo de vida é
CHATCLI_PROMPT_CACHE_TTL(5m,1houauto), estendido quando resta menos da metade; o recurso é apagado quando o prompt muda e no encerramento. - Recurso rejeitado pela API (expirado, apagado, abaixo do piso) é descartado e o turno é reenviado inline — um cache nunca derruba um turno. Recusas colocam o prompt em backoff por 10 minutos, e uma resposta “too small” ensina o piso.
/costmostra o storage comprado (Storage de cache: N recurso(s) · $x) e o soma no total da sessão; o valor é persistido com o snapshot de custo.
Custo de embeddings
Toda chamada de embedding do provedor configurado (retrieval de conhecimento e aquecimentos, vetores de memória, HyDE) é medida: os tokens são estimados por caracteres na tarifa de lista do provedor por milhão de tokens, e o/cost imprime Embeddings: N chamada(s) · ~T tokens (estimados por caracteres) · $x. Ollama mede a $0. O valor entra no total da sessão e persiste com o snapshot.
Gasto em background e atribuição
Toda requisição é contabilizada na chamada que a fez. O usage do sumarizador de Nível 2 é lido da própria chamada (um engine de contexto externo, um retorno antecipado ou uma falha não contabilizam nada; um resumo repetido cobra as duas chamadas). O memory worker (extração, rollups, compactação de memória) roda no próprio cliente —CHATCLI_COMPACT_MODEL quando definido, senão uma instância dedicada do modelo da sessão — e por isso nunca sobrescreve o usage do turno interativo; respeita CHATCLI_BUDGET_HARD_STOP como qualquer outro chamador e o /cost imprime Memory worker: N chamada(s) · $x. Uma resposta em streaming que termina sem bloco de usage é contabilizada como estimativa por caracteres (marcada como tal) em vez de sair de graça, e os providers zeram o usage antes de cada requisição para que uma resposta sem usage nunca re-contabilize a chamada anterior. Tokens de thinking do Gemini (thoughtsTokenCount) são cobrados por cima da contagem de candidates; tokens de reasoning da OpenAI já estão dentro de completion_tokens e ficam só informativos.
Custo de compactação
O/cost também imprime Compactações: N (nível 3: M) · sumarizador $x depois que o histórico foi compactado: quantas vezes, quantas caíram no Nível 3 (truncagem de emergência) e o que o sumarizador do Nível 2 consumiu. A requisição do sumarizador é uma requisição real na rota da sessão (ou em CHATCLI_COMPACT_MODEL), então entra nos totais da sessão como qualquer turno; os contadores persistem com a sessão. Veja context recovery para o back-off que para de pagar o sumarizador quando ele não converge.
O context caching da Moonshot/Kimi é totalmente automático na plataforma atual (sem ids de cache nem API de gerenciamento; a requisição anterior precisa passar de 256 tokens de prompt), então nada é criado lá — o split cached_tokens é o que o tracker precifica.
Contagem de tokens por provedor
Octx % do rodapé, o orçamento de compactação e o /context status compartilham uma única estimativa com quatro categorias — system prompt, histórico, definições de tools nativas e reserva da resposta (max_tokens como enviado, limitado a um quarto da janela) — o mesmo detalhamento que o /context do Claude Code mostra. O rodapé mostra a reserva à parte — ctx 2% (+14% reserva) — para uma conversa nova nunca parecer uma janela capada: o primeiro número é o que já ocupa a janela, o segundo é o espaço que a próxima requisição precisa deixar livre para a resposta (os provedores exigem entrada + max_tokens ≤ janela; um /max-tokens menor encolhe a reserva). O /context status imprime as duas últimas linhas, e o compactador reserva o prompt e as definições de tools ao lado do histórico que mede. O orçamento de passagens recuperadas escala com a janela (no máximo 24K chars, 15% da janela em chars, piso de 4K). A razão chars/token por trás dessa estimativa, da projeção do /context status e do orçamento de compactação é aprendida do usage real de todos os provedores (a mesma cobertura de 14 provedores da tabela abaixo), então é exata após o primeiro turno em qualquer lugar. Provedores que também expõem uma API de contagem, e a família GPT por um tokenizer local, ancoram a razão antes de a requisição sair — uma contagem gratuita a cada 8 turnos de chat e no /context status, que então mostra o tamanho do histórico vivo contado pelo provedor:
Uma contagem que falha ou demora (limite de 10 s) nunca afeta um turno: a razão aprendida simplesmente permanece.
As razões aprendidas são persistidas em
~/.chatcli/calibration.json (escrita atômica, descarregada na saída) e recarregadas no próximo start, então um processo novo não recomeça em 4 chars por token. Sob o gateway o arquivo fica sob a raiz de cada tenant, então tenants nunca compartilham razões. Toda estimativa da CLI lê a mesma razão aprendida: o budget de processamento de arquivos, /metrics, /context list e o feedback do attach, o rodapé de economia de compressão, o budget de compactação e o chunker, validador e digests do gerenciador de contexto.
Dados Reais de API — Cobertura por Provider
O tracker prefere o uso real da resposta do provider e só cai em estimativa por caracteres (chars/4, marcada IsReal=false) quando o provider não reporta nada:
Modos cobertos
Toda chamada LLM que uma sessão faz é contabilizada e atribuída ao modelo que de fato a serviu (incluindo hints de skill e overrides de rota do@model):
- Chat — streaming, buffered e o caminho de exceção de tools do
/ask - Agent / Coder — cada turno ReAct, mais os workers/subagents despachados (o cliente de cada worker registra cada chamada LLM ao vivo, sob o provider+modelo do próprio worker — e o hard stop de orçamento gateia cada chamada)
- Painéis MoA — caminhos native-tools, XML e plain, atribuídos por participante
- One-shot (
-p), turnos RPC/Gateway/ACP e execuções agendadas (o scheduler roda em client dedicado e recebe de volta números de tokens/custo — uma estimativa autocontida de propósito, imune a corridas com turnos interativos)
Tabelas de Preço
Preços em USD por 1M de tokens, espelhandocli/cost_tracker.go (pinado por cost_tracker_pricing_test.go). O match é por substring do id do modelo, mais específico primeiro.
Anthropic (cache write = 1,25× input, cache read = 10% do input — 2,5% no Fable 5.1)
OpenAI (cache read = 50% do input, sem sobretaxa de write)
Google (cache read = 25% do input)
xAI (Grok) — cached input = 25% no grok-4.7/4.6, 15% no grok-4.5, 16% nos demais; sem sobretaxa de write
Z.AI (GLM)
DeepSeek (preço de pico; cache read = 25% do input)
Moonshot (Kimi) — preço de cache miss, cache read = 17% do input
Outros
Contabilidade de Cache
Tokens de cache são precificados por família — e, crucialmente, com a semântica correta por provider:- Anthropic / Bedrock Anthropic reportam tokens de cache ao lado de
input_tokens(aditivos): write cobrado a 1,25× do input, read a 10% (2,5% no Fable 5.1). - OpenAI, xAI, Gemini, DeepSeek, Moonshot reportam cache reads como subconjunto da contagem de prompt: a fatia cacheada é recortada do input e cobrada uma única vez na taxa com desconto — nunca preço cheio mais desconto.
Economia do cache é o balanço do cache da sessão em dólares, calculado a partir das tarifas reais de cada modelo — não um percentual fixo. Desconto de leitura é o que as leituras de cache pouparam contra o preço de input. Prêmio de escrita é o que as escritas de cache custaram acima do preço de input: 1,25x na Anthropic e no Bedrock, 2x com o TTL de uma hora, nada na OpenAI, Gemini, xAI e Kimi (a linha some quando é zero). Economia líquida é a diferença, e Sem cache é o que os mesmos tokens custariam sem cache nenhum, ao lado do total real. Só as leituras superestimam a economia: uma sessão que reescreveu o prefixo algumas vezes pode ter devolvido um terço do que as leituras pouparam, e é aqui que isso aparece. A linha Processados de tokens é todo token que o provedor tokenizou, cacheado ou não, já que Input nos esquemas aditivos é só a parte não cacheada.
Persistência de Sessão
Os dados de custo são gravados em disco conforme a sessão roda (write-through com throttle, escrita atômica):-p), o daemon do gateway e os servidores MCP/ACP persistem o snapshot de custo e o gasto diário e liberam caches pagos do provedor na saída, exatamente como o cleanup do REPL; o gasto com embeddings conta no orçamento diário. Quando o hard stop do orçamento dispara dentro do loop do agent, o run é parkado (retoma à meia-noite local seguinte, ou com /parked resume depois de subir o orçamento) em vez de morrer perdendo o trabalho.
Tiers de contexto longo, assinaturas e o orçamento diário. Uma chamada acima do limiar de contexto longo do provedor é precificada no seu tier por chamada — Claude acima de 200K de contexto (2× entrada, 1,5× saída), Gemini 2.5 Pro acima de 200K (2× / 1,5×), Grok 4 acima de 128K (2× / 2×) — e contabilizada como valor cobrado, então o agregado nunca a dilui; a estimativa do rodapé concorda. O GitHub Copilot é assinatura (premium requests, não tokens) e entra como zero conhecido. Todo modelo em zero conhecido que carregou tokens é nomeado abaixo do total (Sem tarifa por token conhecida para: …), para que um $0 nunca pareça grátis quando significa desconhecido, e CHATCLI_MODEL_PRICING atribui uma tarifa a ele. Amazon Nova Micro/Lite/Pro/Premier têm suas linhas de lista on-demand; gerações Nova 2 aparecem como sem preço até a tarifa de lista ser verificada, em vez de chutada. Um orçamento só diário (CHATCLI_DAILY_BUDGET_USD sem limite de sessão) anuncia seus próprios avisos de alerta e de excedido, e quando os dois limites existem o diário fala quando estourou; /cost export caminho.csv grava uma linha CSV por provedor/modelo mais um total.
O snapshot (SessionCostData) carrega os records de uso por modelo, totais, timestamps e o nome da sessão nomeada quando houver. Snapshots também são salvos no encerramento e no /cost reset, e podados após 90 dias.
/cost last— o gasto da sessão (ou período) anterior/cost sessions— os 10 snapshots mais recentes com data, requests, tokens e total, mais o registro de cache de cada sessão: fração de acerto, razão write/read, misses instáveis, expirados, rebuilds esperados e o TTL em vigor. A telemetria do cache de prompt é persistida com o snapshot de custo e restaurada com a sessão, então a estabilidade do prefixo pode ser comparada entre sessões em vez de morrer com o processo; as mesmas duas figuras vão para o OTLP comochatcli.cache.hit_pctechatcli.cache.write_read_ratio./cost export [caminho]— snapshot atual em JSON, para pipelines e auditoria
Orçamento de Sessão
As três são relidas no
/reload — não precisa reiniciar para mudar o orçamento no meio da sessão.
Níveis de Orçamento
O aviso é proativo: chat, agent e coder o imprimem no turno em que a sessão cruza um nível — você não precisa lembrar de rodar
/cost. Sem CHATCLI_BUDGET_HARD_STOP, exceder o orçamento nunca interrompe a sessão; com ele, novos turnos (chat, loop do agent, workers do squad em pleno voo, participantes MoA, execuções agendadas, RPC/gateway) são bloqueados até o limite subir ou o /cost reset abrir um novo período.
Próximos Passos
Controle de Conversa
Use /compact para reduzir tokens e custos.
Modo One-Shot
Monitore custos em pipelines automatizados.
Eficiência de Tokens
As otimizações que o /cost permite verificar.
Roteamento de Modelos
Atribuição por modelo de cada turno roteado.