1

Pitch: Criei um widget flutuante para acompanhar os limites do Claude Code — Tauri v2 + Rust + vanilla JS

Quem usa o Claude Code no plano Max sabe a dor: você está no meio de um fluxo, abre o /usage, vê os percentuais, fecha. Abre de novo dez minutos depois. Fecha. Repete.

Resolvi criar o UsoAI — um widgetzinho que fica no canto da tela, sempre à vista, mostrando exatamente o que o /usage mostraria: % da sessão (5h) e % da semana (7d), com os horários de reset.


O problema real

O Claude Code tem dois limites rolantes:

  • Sessão (5h): janela deslizante de 5 horas.
  • Semana (7d): janela de 7 dias, todos os modelos.

O painel oficial mostra isso, mas é uma página que você abre e fecha. Queria algo que ficasse visível enquanto trabalho, sem precisar trocar de janela.


Como os números chegam até você (a parte interessante)

O primeiro instinto seria ler os logs locais em ~/.claude/projects/**/*.jsonl, mas eles só têm tokens consumidos — não os limites nem o percentual real do servidor.

A informação certa vem de outra fonte: toda resposta da API da Anthropic traz headers HTTP com a utilização em tempo real:

anthropic-ratelimit-unified-5h-utilization: 0.42
anthropic-ratelimit-unified-5h-reset: 1751234567
anthropic-ratelimit-unified-7d-utilization: 0.17
anthropic-ratelimit-unified-7d-reset: 1751456789
anthropic-ratelimit-unified-status: allowed

Esses headers existem tanto em respostas 200 quanto em 429 (rate limited) — o que é ótimo, porque dá pra ler o estado mesmo quando você já estourou o limite.

O app faz uma chamada barata — max_tokens: 1, modelo Haiku, custa ~1 token — e lê só os headers. Não processa o corpo da resposta.

⚠️ Isso não é API pública documentada. É o mesmo mecanismo que o Claude Code usa internamente, descoberto pela comunidade (créditos no final). Pode mudar a qualquer momento.


Stack: por que Tauri v2 e vanilla JS?

Tauri v2 porque queria uma janela transparente, sem borda, always-on-top, cross-platform (Windows, Linux, macOS), com acesso ao cofre do SO para guardar o token. Electron faria o mesmo mas pesaria ~150 MB. O binário do UsoAI fica em ~8 MB.

Vanilla JS porque não tem build step. O frontendDist aponta direto para src/. Abrir src/index.html no navegador já mostra o app em modo demo com dados animados — zero dependências npm para o front-end.

A única "framework" usada foi a própria API do Tauri via window.__TAURI__.core.invoke.


Fluxo de dados

app.js  →  invoke("get_limits", { token })  →  limits.rs
                                                    ↓
                                         POST /v1/messages
                                         (max_tokens: 1, Haiku)
                                                    ↓
                                         lê headers da resposta
                                         (200 ou 429)
                                                    ↓
                                         retorna { session_util,
                                                   session_reset,
                                                   weekly_util,
                                                   weekly_reset,
                                                   status }
                                                    ↓
app.js  ←  render(d)  ←─────────────────────────────

O backend Rust é quem faz a chamada HTTP — a WebView não toca na rede. Isso permite uma CSP restritiva (default-src 'self') e garante que o token nunca vaza para o front-end de forma persistente.


Skins

A parte mais divertida. O app tem 6 formas de visualizar o mesmo dado:

SkinConceito
PlanoDuas barras, igual ao /usage oficial
Sabre de luzA lâmina cresce com o uso; CSS puro com color-mix() e box-shadow em camadas para o glow
DuoDois sabres lado a lado — sessão e semana
MaulSabre de Darth Maul: lâmina de cima = sessão, de baixo = semana
KartUm carrinho percorre uma pista rumo à bandeira
MinimalDois pills discretos

O modo inverso inverte a lógica: a lâmina começa cheia e vai apagando conforme você usa — útil para quem pensa em "quanto me resta" em vez de "quanto usei".


Segurança do token

O token OAuth (sk-ant-oat01-…) é obtido via claude setup-token e armazenado no cofre do SO:

  • macOS → Keychain
  • Windows → Credential Manager
  • Linux → Secret Service / libsecret (com fallback para arquivo 0600 se não houver chaveiro)

Nunca vai para localStorage, nunca é logado, nunca sai da máquina além da chamada HTTPS para api.anthropic.com.


Download direto

Não quer compilar nada? Vai nos Releases do GitHub e baixa o instalador do seu sistema:

  • Windows.msi
  • macOS.dmg
  • Linux.AppImage ou .deb

Instala, abre, cola o token (claude setup-token) e pronto.


Como rodar (para quem quer mexer no código)

Pré-requisitos: Rust (stable) + Node 20+.

git clone https://github.com/SEU_USER/UsoAI
npm install
npm run dev

Na primeira abertura o ⚙ pede o token. Rode claude setup-token, cole e clique em Testar agora.

Para só ver as skins sem compilar nada: abra src/index.html no navegador. O modo demo anima os valores automaticamente.


O que vem por aí

Algumas coisas que quero adicionar (sem prazo):

  • Auto-detectar o token lendo ~/.claude/.credentials.json em vez de pedir manualmente
  • Autostart com o sistema via tauri-plugin-autostart
  • Histórico em SQLite local com mini-gráfico de tendência
  • Mais skins: barra de XP, bateria, tanque de combustível

Créditos

O UsoAI não teria saído do chão sem o trabalho de outras pessoas:

  • semaphore — por Luciano dii Souza: a arquitetura de widget flutuante Tauri com bandeja e temas.
  • claude-monitor — por R. J. Walters: como usar o token OAuth e ler os limites nos headers.
  • claude-meter + o artigo "I Tried to Reverse Engineer Claude Code's Usage Limits" — por Abhishek Ray: documentação detalhada dos headers anthropic-ratelimit-unified-*.
  • ccusage — por ryoppippi: referência para leitura dos .jsonl locais.
  • Kevin Powell — pela técnica CSS do efeito sabre de luz (glow em camadas com box-shadow borrado).

Se quiser contribuir com uma skin nova, o processo é simples: adicionar o HTML da skin em index.html e garantir que os data-bind certos estejam lá para o render() preencher. Nada de framework, nada de compilação.

Feedbacks e pull requests são bem-vindos.

Carregando publicação patrocinada...