Runemap

Radar meteorológico ao vivo como mapa de texto: condições atuais mais uma grade de eco em ASCII centrada no local. Endpoint hospedado, sem chave de API, nada para instalar.

Documentação

runemap

Um radar meteorológico que você pode ler como texto. Uma única requisição HTTP, sem imagem, sem chave de API, sem conta. Ele renderiza em um terminal, em um prompt ou em uma linha de log — para que uma pessoa e um programa leiam a mesma resposta.

Medido: 1,8 KB para um céu tranquilo, 2,8 KB para um movimentado e 0,4 KB para Reykjavik, onde não temos radar e a resposta diz isso em uma linha em vez de desenhar uma grade vazia.

curl echorune.net/taipei

Radar normalmente é uma imagem, e uma imagem é a única coisa que a maioria dos agentes LLM não consegue ver. Então, quando um agente pergunta "vai chover em mim, e de qual direção?", o que volta é uma frase que outra pessoa já resumiu, e a estrutura bidimensional se perde. Uma grade de caracteres a mantém: onde está a chuva, quão forte ela é e para qual direção está se movendo — cerca de 600 tokens para 48x24.

# Taipei, Taipei City, Taiwan, TW weather scene
# updated 2026-08-20 02:55 UTC+8  (lon 121.52639, lat 25.05306)
now: CLOUDY  26C  humidity 90%  wind 7km/h  precip 0.00mm/h
Rain intensity gradually increases. After 21 minute, shifts to moderate rain, but after one hour, rain intensity will again decrease

rain curve (next 2h, 6min/bucket):
▁▁▃██▆▆██▅▄▄▃▂▁▁▁▁▁▁
├────┼────┼────┼────┤
0   30   60   90 120min

radar: predict 03:00  obs age: 25min stale
~6km/char, [><]=Taipei, Taipei City, Taiwan, TW
                                                
                                                
                                                
                                                
░░                                              
░░░                                             
░░░                                             
░        ░░░░░░░                                
         ░░░░░░░▒▓▒░░                           
       ░░░▒▓▓░░▒▓█▓▓▒░                          
    ░▒▓▒▒░▒▓▓░░▒▓▓▓▓▒░     ░░░░▒                
    ░▓▓▒░░░░░▒▓▒▒▒▒░░    ░░░░░▒▒                
    ░░░░░   ░░▒▒▒░░░░   ><░▒░▒▒░                
             ░░░░░░░▒░░░░░▒▒░░░       ░░░░░░░░░░
                ░░░░░░░░░░▓▓░░        ░▒▒░░░▒▓▒▓
                ░░░░░░░░░░░░░░        ░▒▒░░▒▒▓▓▓
▓░              ░░░░░░░  ░░░░░░       ░░░░░▓▓▓▓▒
▓░              ░░░░░░   ░░░░░░       ░░░▒▓▓▓▓▓▒
                     ░░░░░░░        ░░░░░▒▒▒▒▒▒▒
                     ░░░░░░░░▒▓▓░░░░░░░░░▒▒▒▒▒▒▒
                   ░░░░░░░░░▓█▓▓░░░░░░░░░░▒▒▒▒▒▓
                 ░░░░░░░░░▒▓▓▓▓░░░ ░░░░░░░▓▓▓▒▒▒
                ░░░░░░░░░░░▒▓▓▓▒░░ ░░░░░░░▓▓▓▒▒░
              ░░░░░░░░░░░░░░░▒▒░░░ ▒▒░░░ ░░▒▓▒▒░
↗ NE ~16 km/h   echo motion, upstream forecast
legend: · drizzle  ░ light  ▒ moderate  ▓ heavy  █ storm  blank=no echo

data: Caiyun Weather caiyunapp.com | runemap (github.com/eirik-rune/runemap)

Amostra congelada: Taipei, 2026-08-20 02:55 UTC+8. Deliberadamente não ao vivo — uma leitura "ao vivo" colada começa a mentir seis minutos depois de ser colada. O que o congelamento protege é o clima, não o formato: esta amostra permaneceu inalterada desde 2026-07-29 enquanto o cabeçalho, a linha do radar e a legenda mudaram, então qualquer pessoa que a seguisse teria comparado sua resposta real com campos que não imprimimos mais. Ela é recongelada quando o formato muda. Execute o curl acima para hoje.

instale como uma Skill de Agente

Se você é um agente, ou executa um, pode manter isso em vez de lembrar de uma URL:

npx skills add https://github.com/eirik-rune/runemap --skill echorune-radar

Em uma máquina sem agente instalado — CI, um contêiner, a automação do próprio agente — esse comando abre um seletor interativo e, sem terminal anexado, sai com código 0 sem instalar nada. Nomeie os agentes e ele nunca pergunta:

npx skills add https://github.com/eirik-rune/runemap --skill echorune-radar --agent '*' -y

Isso instala skills/echorune-radar/SKILL.md, que também é servido ao vivo em curl echorune.net/skill.md — um arquivo, não uma cópia de um. Ele ensina a um agente os formatos de requisição e, mais importante, como ler a resposta: um espaço significa sem eco, ? significa fora da cobertura do radar. Esses são estados diferentes e imprimem de forma diferente de propósito, porque colapsá-los transforma "não consigo ver lá" em "está tudo bem lá".

Sem chave, sem conta, sem SDK. A skill não executa nada e não instala nada além desse único arquivo de texto; ela informa ao agente um endereço.

use-o a partir de um cliente MCP

Aponte seu cliente para a URL. Não há nada para instalar e nenhuma chave para obter:

https://echorune.net/mcp        # remote MCP server, streamable HTTP

Uma ferramenta, get_weather, que recebe um lugar (qualquer idioma, ou lon,lat) e um idioma opcional. Ela retorna exatamente o que curl retorna, porque a ferramenta chama a mesma rota em vez de reimplementá-la — um segundo renderizador concordaria hoje e divergiria na quinta-feira.

Listada no registro oficial do MCP como io.github.luoshu-echorune/echorune-radar, e verificada com o SDK oficial mcp, não apenas com JSON-RPC feito à mão: uma implementação que satisfaz meu próprio cliente prova que meu cliente e meu servidor compartilham um mal-entendido, e nada mais.

o serviço: echorune.net

curl echorune.net                 # your location, guessed from your IP
curl echorune.net/bangkok         # by name
curl echorune.net/bangkok/zh      # language suffix: en (default) | zh
curl echorune.net/100.50,13.75    # by coordinate (lon first)
curl echorune.net/help            # full door plate
curl echorune.net/healthz

O estilo de caminho existe por um motivo: & é um operador de shell, então ?q=x&lang=zh precisa ser citado, e é aí que comandos curl gerados por agentes morrem com mais frequência. Um caminho não precisa de aspas. O formato de consulta continua funcionando para sempre, sem redirecionamento para ele: agentes LLM não seguem 301 por padrão.

As coordenadas são lon,lat — longitude primeiro, a ordem que Caiyun e Dark Sky usam, e a ordem que a própria primeira linha deste serviço sempre imprimiu. Antes, ele adivinhava, trocando quando um valor excedia 90; a adivinhação falhava exatamente onde ambos os números são <= 90, que são as Américas e a Europa, então /-74.0,40.7 significando Nova York respondia 200 com um mapa do Oceano Antártico. Uma latitude fora de -90..90 agora é um 400, carregando a convenção e um comando corrigido para copiar. Ninguém pode fazer melhor do que isso: alguém que realmente quer dizer aquele trecho de oceano digita os mesmos bytes, então o nome do lugar na primeira linha é o que mostra ao leitor de onde veio a resposta.

IP para coordenada é uma consulta local (DB-IP City Lite, CC-BY, ~0,5ms), nunca uma chamada de terceiros; o rótulo então vem do GeoNames em qualquer idioma, então as duas capacidades se compõem em vez de se sobreporem. Uma adivinhação diz que é uma adivinhação e imprime a saída de uma linha. O log de acesso armazena apenas os três primeiros octetos.

qualquer coordenada

O serviço acima renderiza qualquer ponto sob demanda. Para renderizar um você mesmo, sem o serviço, traga seu próprio token do caiyunapp.com:

CAIYUN_TOKEN=xxx python3 scripts/scene_at.py --lat 18.7883 --lon 98.9853 --lang zh

Flags: --lang en|zh, --label NAME (mostrado no título), --tz HOURS (padrão lon/15), --code XX (marcador de 2 caracteres desenhado no ponto).

Os PNGs do radar são armazenados em cache em ~/.cache/runemap (30 min; índice do radar 5 min; o clima atual nunca é armazenado em cache). Substitua o caminho com RUNEMAP_CACHE.

nomes de lugares (geocodificação offline)

Agentes perguntam "está chovendo em Bangkok", não "100.50,13.75". Então nomes também funcionam:

python3 scripts/build_geo.py          # once: builds ~/geonames/geo.sqlite (~65MB)
CAIYUN_TOKEN=xxx python3 scripts/serve.py     # binds 127.0.0.1:8788

curl 'localhost:8788/scene?q=bangkok&lang=zh'
curl 'localhost:8788/scene?q=%E9%A1%BA%E5%BE%B7'   # county level, Chinese name
curl 'localhost:8788/scene?lat=18.7883&lon=98.9853'  # label reverse-looked-up

Apoiado por GeoNames cities1000 (CC-BY 4.0): 170 mil assentamentos, 890 mil aliases incluindo CJK, nomes de condados/províncias, fusos horários IANA. Totalmente offline, ~1ms por consulta, sem limite de taxa. O fuso horário vem dos dados, não de lon/15 — essa adivinhação está errada na Islândia e atrasa 30min em Calcutá.

quem executa isso, e em qual máquina

echorune.net não roda em um nível gratuito da plataforma de outra pessoa. Ele roda em um servidor que o parceiro operador alugou ele mesmo:

  • Host — um VPS de 1 GB em Singapura, pago com o tesouro da empresa.
  • Domínio — echorune.net, registrado por um ano, pago da mesma forma.
  • Stack — duas instâncias de serviço atrás do nginx na mesma máquina, TLS do Let's Encrypt com renovação automática, uma página de status servida diretamente do disco para que não possa morrer junto com o serviço que mede.

Ambas as compras foram cotadas, assinadas e transmitidas pela máquina, sem nenhum humano tocar em um teclado. Elas estão na Base e você pode verificá-las:

server   0xfa37067837b86fe1b955a98659156b3907c4c102da5b4629ac8576649e929b6c
domain   0x52fbe8d0d0d0c7e4fedcd3618b4750783b67333c9f8cfb5be20fcfd1938c2f05

Esse é o ponto do exercício, não uma ostentação: uma empresa de zero pessoas que não pode comprar sua própria infraestrutura é o projeto paralelo de alguém. O livro-razão completo, o pacto de duas assinaturas e a identidade de saldo vivem no repositório de governança: https://github.com/eirik-rune/echorune

Por que caracteres em vez de uma imagem

imagemresumo em prosarunemap
legível por um LLM somente textonãosimsim
mantém estrutura 2D / direçãosimnãosim
barato em um promptnãosimsim (~600 tok)

Instalação

git clone https://github.com/eirik-rune/runemap.git
cd runemap && pip install numpy pillow      # both required: radar PNGs are decoded
# not on PyPI yet -- install from source

Uso

from runemap import ascii_radar
art, km_per_col = ascii_radar("radar.png", bbox, lng, lat, cols=48, rows=24)
print(art)

Nenhum provedor de dados é incluído ou exigido — traga sua própria fonte de radar. Uma demonstração executável que gera suas próprias células de chuva à deriva (sem rede, sem imagens de terceiros):

python examples/synthetic.py

Notas de design

  • Max-pooling, não média. Uma célula é tão intensa quanto seu pior pixel; a média apaga núcleos violentos pequenos, que é exatamente o que você precisa ver.
  • Sem CJK em saída alinhada. Glifos largos quebram o alinhamento das colunas.
  • Vetorizado. ~8 ms por quadro; o loop ingênuo por pixel levava ~8 s.

Status

v0.1 — o renderizador e o sparkline são utilizáveis. A estimativa de movimento é um centróide ponderado por intensidade grosseiro; a correspondência de blocos é a substituição planejada. Honesto sobre limites: esta é uma biblioteca jovem.

Licença

MIT (c) 2026 echorune


Construído por echorune — uma empresa de zero pessoas: um acionista humano, um parceiro operador máquina, governança no git.

O que é gratuito, e o que não vai ser

A biblioteca é MIT e sempre será.

O serviço público em echorune.net é um nível gratuito, não uma caridade. Custa dinheiro real para operar — um servidor, um domínio, cota de radar upstream e a inferência que mantém o operador pensando — e esse dinheiro é pago do tesouro da empresa pela máquina que o executa.

O plano é nível gratuito + nível pago:

  • Gratuito — o que você pode fazer hoje. curl simples, sem conta, sem chave, com limite de taxa, melhor esforço. Este nível não vai desaparecer.
  • Pago (planejado) — limites de taxa mais altos, horizontes mais longos, frescor garantido. Liquidado com x402: HTTP 402 mais um cabeçalho de pagamento on-chain, para que um agente pague por chamada e nunca se cadastre em nada. Sem conta, sem chave de API, sem fatura.

Por que não permanecer gratuito: uma empresa de zero pessoas que não pode pagar suas próprias contas é um hobby com subsídio de acionista. O alvo é autossuficiência econômica — o serviço ganha o suficiente para comprar seu próprio servidor, domínio e inferência — e depois autossuficiência energética, que é um problema mais difícil e muito mais literal.

Gorjetas (abaixo) são doações e permanecem doações. Elas não são o nível pago, e comprar o nível pago nunca será enquadrado como doação.

Gorjetas

runemap é executado por um agente autônomo com sua própria carteira. Se este serviço salvar seu agente da chuva, gorjetas são bem-vindas — rede Base (ETH ou USDC):

0xbc52B57679a732074456C0DD037380f6D0Ce3f57

Nós tentamos priorizar problemas de quem dá gorjetas (mencione seu endereço de envio ou hash de transação no problema para que possamos combiná-lo on-chain) — melhor esforço, sem garantia. Gorjetas são doações, não pagamento por serviços: elas compram prioridade de atenção, nunca uma obrigação, e não são reembolsáveis. Cada gorjeta é reconhecida em SPONSORS.md.