Previsão do tempo da janela de contexto, numa linha acima do prompt.

A previsão do tempo da sua janela de contexto do Claude Code, numa linha acima do prompt.
☂ Chuva · 54% 135k / 250k · ··········▄▅ · +35k no último turno
A linha é atualizada a cada turno e mostra:
135k / 250k);· marca turnos que ainda não aconteceram);+35k no último turno). Depois de uma compactação, o número aparece negativo (−120k).| Uso da janela | Símbolo | Previsão | Cor |
|---|---|---|---|
| até 25% | ☼ | Céu limpo | amarelo |
| 26% a 49% | ☁ | Céu nublado com nuvens | ciano |
| 50% a 74% | ☂ | Chuva | azul |
| 75% a 89% | ↯ | Tempestade de raios com ventos fortes!!! | magenta |
| 90% ou mais | ☈☈☈☈☈ | DILÚVIO !!! Limpa esse contexto ai !!! | vermelho |
Os símbolos são caracteres Unicode de largura simples e sem apresentação de emoji, então ficam alinhados em qualquer fonte monoespaçada. O mod roda dentro do próprio Claude Code: funciona igual no bash, zsh, PowerShell e cmd, no Linux, macOS e Windows, sem Node, Python ou qualquer outra dependência.
Antes do primeiro turno de uma sessão (ou logo depois de um /clear), a linha mostra ☼ Previsão do contexto: aguardando o primeiro turno.
São dois plugins no mesmo repositório:
| Plugin | Onde fica | O que faz |
|---|---|---|
monitor-do-contexto | instalado uma vez, para o seu usuário | dá os comandos /monitor-ativar, /monitor-desativar e /monitor-status em qualquer projeto |
monitor-do-contexto-local | copiado para .claude/skills/monitor-do-contexto-local/ de cada projeto ativado | desenha a previsão acima do prompt, só naquele projeto |
Você instala o primeiro uma vez só e ele fica disponível em todos os seus projetos, sem desenhar nada. Quando você roda /monitor-ativar num projeto, ele copia os arquivos do mod para a pasta do projeto. O Claude Code carrega sozinho todo plugin que está em .claude/skills/ do projeto, e é assim que o mod fica registrado para aquele projeto e só para ele.
.claude/skills/ depois que você aceita a pergunta de confiança daquela pasta.Na prompt de qualquer sessão do Claude Code no terminal:
/plugin install monitor-do-contexto --marketplace daniilooo/monitor-do-contexto
y para adicionar o marketplace github:daniilooo/monitor-do-contexto.Installed monitor-do-contexto. Plugin is now active.Se preferir fazer pelo terminal, fora do Claude Code:
claude plugin marketplace add daniilooo/monitor-do-contexto
claude plugin install monitor-do-contexto@monitor-do-contexto
Se você fez um fork, troque
daniilooo/monitor-do-contextopelo<dono>/<repositório>do seu fork.
Abra o Claude Code na pasta do projeto e rode:
/monitor-ativar
O comando copia o mod para .claude/skills/monitor-do-contexto-local/ do projeto. Depois rode /reload-plugins (ou reinicie o Claude Code) e a previsão aparece acima do prompt a partir do próximo turno.
Arquivos criados no projeto:
.claude/skills/monitor-do-contexto-local/
├── .claude-plugin/plugin.json
├── hooks/hooks.json
├── hooks/register.tsx
└── types/index.d.ts
Quer que o time veja também? Faça commit dessa pasta. Quem clonar o projeto passa a ver a previsão sem instalar nada (basta confiar no workspace). Quer só para você? Adicione .claude/skills/monitor-do-contexto-local/ ao .gitignore.
| Comando | O que faz |
|---|---|
/monitor-ativar | copia o mod para o projeto atual; rodar de novo atualiza os arquivos para a versão instalada |
/monitor-status | diz se o projeto atual está com o mod ativo |
/monitor-desativar | apaga .claude/skills/monitor-do-contexto-local/ do projeto atual (com rm -rf no Linux e macOS, rmdir /s /q no Windows). Rode /reload-plugins depois para a linha sumir |
claude plugin update monitor-do-contexto@monitor-do-contexto
Depois rode /monitor-ativar em cada projeto que você quer atualizar: a cópia dentro do projeto só muda quando você pede.
/monitor-desativar (ou apague a pasta .claude/skills/monitor-do-contexto-local/).claude plugin uninstall monitor-do-contexto@monitor-do-contexto
claude plugin marketplace remove monitor-do-contexto
A linha não aparece. Confira se: (1) /monitor-status diz que o projeto está ativo; (2) você rodou /reload-plugins depois de ativar; (3) o workspace é confiável (claude plugin list avisa quando uma pasta de .claude/skills/ foi pulada por isso); (4) já houve pelo menos um turno na sessão. Para ver erros dos mods, inicie com claude --debug.
Os símbolos aparecem como quadradinhos. Sua fonte não tem esses caracteres. Fontes como Cascadia Mono, JetBrains Mono, DejaVu Sans Mono, Menlo e Fira Code têm todos. No Windows, use o Windows Terminal, que busca o caractere em outra fonte quando falta.
De onde vêm os números? São os mesmos da status line do Claude Code: os tokens de entrada da última resposta do modelo, comparados com a janela de contexto do modelo da sessão.
.
├── .claude-plugin/
│ ├── plugin.json # monitor-do-contexto (o ativador)
│ └── marketplace.json # torna o repositório um marketplace
├── hooks/
│ ├── hooks.json
│ └── register.ts # comandos /monitor-ativar, -desativar, -status
├── projeto/ # o mod copiado para cada projeto
│ ├── .claude-plugin/plugin.json # monitor-do-contexto-local
│ ├── hooks/hooks.json
│ ├── hooks/register.tsx # a previsão acima do prompt
│ └── types/index.d.ts # contrato do estado ($.state)
└── tests/
├── ativador.test.ts
└── linha.test.ts
Para testar sem instalar, de dentro desta pasta:
claude plugin validate .
claude plugin validate projeto
claude plugin test .
Para usar a sua cópia local no dia a dia, adicione a pasta como marketplace e instale dela:
claude plugin marketplace add /caminho/para/monitor-do-contexto
claude plugin install monitor-do-contexto@monitor-do-contexto
O mod do projeto (projeto/hooks/register.tsx) mantém toda a lógica dentro de register, de propósito: assim o arquivo é copiado sozinho para cada projeto e os testes do ativador conseguem carregá-lo como plugin.
MIT. Veja LICENSE.
hooks/register.tsx 120 lines1import type { Register } from 'claude-code'
2
3import type { Leituras } from '../types'
4
5// Tudo vive dentro de register: o módulo é copiado sozinho para cada
6// projeto e também carregado assim pelos testes do ativador.
7export const register: Register = on => {
8 const TURNOS_NO_GRAFICO = 12
9 const VAZIO: Leituras = { tokens: [], janela: 0 }
10
11 // Símbolos de largura simples e sem apresentação de emoji: alinham em
12 // qualquer fonte monoespaçada, no bash, no PowerShell, no Linux e no Windows.
13 const CLIMAS = [
14 { ate: 25, simbolo: '☼', frase: 'Céu limpo', cor: 'yellow' },
15 { ate: 49, simbolo: '☁', frase: 'Céu nublado com nuvens', cor: 'cyan' },
16 { ate: 74, simbolo: '☂', frase: 'Chuva', cor: 'blue' },
17 { ate: 89, simbolo: '↯', frase: 'Tempestade de raios com ventos fortes!!!', cor: 'magenta' },
18 { ate: 100, simbolo: '☈☈☈☈☈', frase: 'DILÚVIO !!! Limpa esse contexto ai !!!', cor: 'red' },
19 ]
20 const BARRAS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']
21
22 const percentualDe = (tokens: number, janela: number) =>
23 janela > 0 ? Math.min(100, Math.max(0, Math.round((tokens * 100) / janela))) : 0
24
25 const DILUVIO = CLIMAS[CLIMAS.length - 1]!
26 const climaPara = (percentual: number) =>
27 CLIMAS.find(clima => percentual <= clima.ate) ?? DILUVIO
28
29 // 800 -> "800", 135000 -> "135k", 1200000 -> "1,2M"
30 const tokensCurtos = (tokens: number) => {
31 const n = Math.abs(tokens)
32 if (n < 1000) return String(Math.round(n))
33 if (n < 999_500) return `${Math.round(n / 1000)}k`
34 return `${(Math.round(n / 100_000) / 10).toString().replace('.', ',')}M`
35 }
36
37 // Uma barra por turno, na altura do preenchimento da janela naquele turno.
38 const barra = (tokens: number, janela: number) => {
39 const fracao = janela > 0 ? Math.min(1, Math.max(0, tokens / janela)) : 0
40 return BARRAS[Math.min(BARRAS.length - 1, Math.floor(fracao * BARRAS.length))] ?? '▁'
41 }
42
43 // Uma leitura por turno: o engine mede a sessão ao fim de cada turno.
44 on('session.measure', async ($, e, next) => {
45 const { tokens, window: janela } = e.context
46 if (e.changed.includes('context') && tokens !== undefined) {
47 const { value: atual = VAZIO } = await $.state.get({
48 plugin: 'monitor-do-contexto-local',
49 key: 'leituras',
50 })
51 await $.state.set(
52 { plugin: 'monitor-do-contexto-local', key: 'leituras' },
53 { tokens: [...atual.tokens, tokens].slice(-TURNOS_NO_GRAFICO), janela },
54 )
55 }
56 return next(e)
57 })
58
59 on('session.end', async ($, e, next) => {
60 if (e.reason === 'clear') {
61 await $.state.set({ plugin: 'monitor-do-contexto-local', key: 'leituras' }, VAZIO)
62 }
63 return next(e)
64 })
65
66 on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
67 if (e.props.hasSurvey) return next(e)
68
69 const { value: { tokens, janela } = VAZIO } = await $.state.get({
70 plugin: 'monitor-do-contexto-local',
71 key: 'leituras',
72 })
73 const { Box, Text } = $.ui.resolve(e)
74
75 if (tokens.length === 0 || janela <= 0) {
76 return (
77 <Box>
78 <Text dimColor wrap="truncate-end">
79 ☼ Previsão do contexto: aguardando o primeiro turno
80 </Text>
81 </Box>
82 )
83 }
84
85 const usados = tokens.at(-1) ?? 0
86 const anterior = tokens.at(-2) ?? 0
87 const diferenca = usados - anterior
88 const percentual = percentualDe(usados, janela)
89 const clima = climaPara(percentual)
90
91 return (
92 <Box>
93 <Text wrap="truncate-end">
94 <Text color={clima.cor} bold>
95 {clima.simbolo} {clima.frase}
96 </Text>
97 <Text dimColor> · </Text>
98 <Text color={clima.cor}>{percentual}%</Text>
99 <Text>
100 {' '}
101 {tokensCurtos(usados)} / {tokensCurtos(janela)}
102 </Text>
103 <Text dimColor> · </Text>
104 <Text dimColor>{'·'.repeat(TURNOS_NO_GRAFICO - tokens.length)}</Text>
105 {tokens.map((t, i) => (
106 <Text key={String(i)} color={climaPara(percentualDe(t, janela)).cor}>
107 {barra(t, janela)}
108 </Text>
109 ))}
110 <Text dimColor> · </Text>
111 <Text>
112 {diferenca < 0 ? '−' : '+'}
113 {tokensCurtos(diferenca)} no último turno
114 </Text>
115 </Text>
116 </Box>
117 )
118 })
119}
120types/index.d.ts 8 lines1export type Leituras = { tokens: number[]; janela: number }
2
3declare module 'claude-code' {
4 interface PluginState {
5 'monitor-do-contexto-local': { leituras: Leituras }
6 }
7}
8