codearia-sieve

Transforma uma página web em um estado pronto para decisão para agentes de IA: datas como campos ISO, números com unidades como fatos, blocos com orçamento de tokens e âncoras de volta à página, e a conta de tokens (página mediana 53.718 → 1.106 tokens). Determinístico, sem modelo, sem chave de API; combina com modelos de decisão como Jev. Instalação: npx -y codearia-sieve.

Documentação

codearia-sieve — web pages into decision-ready state

codearia-sieve

Analisa uma página web no formato exato que um modelo de decisão precisa.
Datas como datas. Números com unidades. Texto em blocos que cabem na janela do modelo, cada um apontando para sua origem.
Uma chamada — e a conta de tokens, antes e depois.

MCP server TypeScript MCP Registry npm MIT Tests No model, no key

npx codearia-sieve          # MCP server for Claude Code, Cursor and any agent
npm i codearia-sieve        # or the library

Median token saving 98.5%. Median page: 53 718 tokens before, 1 106 after. 1.1 s per page. 50 of 56 random pages usable, 9 languages.

Medido, não prometido. Uma execução ao vivo sobre páginas aleatórias escolhidas no mesmo dia — notícias frescas de feeds RSS em vários idiomas, artigos aleatórios da Wikipédia, documentações, blogs, sites governamentais, receitas, lojas. Cada linha está em bench/analytics/, e npm run analytics reexecuta tudo. O resultado foi então colocado diante de um modelo de decisão: veja Verificado por um juiz.


O que faz

Um agente que precisa de uma página web baixa tudo: navegação, banner de cookies, rodapé, espaços de anúncio, um megabyte de marcação de framework. Depois, um modelo pago por token vasculha a pilha em busca de um parágrafo.

codearia-sieve faz a triagem antes que o modelo veja qualquer coisa — e retorna a página como estado, não como prosa:

Datas viram datas

"Published September 15, 2026""2026-09-15". Lidas de JSON-LD, meta tags e <time> primeiro; de uma linha de autoria apenas quando a marcação está silenciosa, e nunca adivinhadas.

Números viram fatos

"$42 per billion tokens"{ value: 42, unit: "USD_per_billion" }. Funciona em nove idiomas; a vírgula decimal segue o idioma da página. Um número sem unidade não é um fato. Um ano nunca é um fato.

Texto vira blocos que cabem

Cada bloco sabe seu tamanho em tokens e caracteres, os blocos dos quais foi construído e o #anchor na página onde uma decisão pode ser verificada.

Todo o resto — menus, rodapés, banners, linhas de tags, "leia mais" — é removido, e com trace: true você obtém a lista do que foi removido e por quê.


Today: the agent fetches the page and the model does the cleaning. With codearia-sieve: one call, ready state, the model only decides.

Para quem é

Pessoas que constroem agentes e viram a conta. Cada página buscada custa dezenas de milhares de tokens antes que o agente leia uma palavra dela. Mediana de páginas na amostra: 53 718 tokens de entrada, 1 106 de saída.

Pessoas que rodam modelos de decisão baratos. Classificadores, ranqueadores, modelos do Sistema Um como Jev que julgam em vez de escrever. Eles são quase gratuitos e muito rápidos, e têm arestas duras: não sabem contar, leem datas como texto, e sua precisão cai conforme material irrelevante preenche o contexto. Toda ferramenta de "página para markdown" prepara entrada para um leitor. Esta prepara entrada para um juiz.

Pessoas que precisam de respostas verificáveis. Um veredito de texto raspado é improvável a menos que cada peça aponte para sua fonte. Aqui, cada fato nomeia seu bloco e cada bloco carrega uma âncora.


The pipeline: fetch, parse, dates and ids from the untouched tree, clean, blocks, facts and anchors, chunk, assemble. Select is optional and no model runs by default.

Como funciona

Oito etapas de código comum. Nenhum modelo roda a menos que você conecte um. O mesmo HTML gera o mesmo JSON, byte por byte.

  1. Buscarobots.txt primeiro; uma recusa é relatada, não contornada. HTTP simples, user agent honesto.
  2. Análise — HTML em um DOM com linkedom. Sem navegador.
  3. Datas e ids da árvore intocada — a limpeza remove <head>, linhas de autoria e atributos, então ambos são lidos antes que ela rode.
  4. Limpeza — Defuddle remove o chrome; Readability assume se vier vazio. Elementos inline ganham um espaço primeiro, então <span>20 Sept</span><span>10 min</span> nunca vira 202610 min.
  5. Blocos — títulos, parágrafos, listas, tabelas, código, citações, em ordem, com ids posicionais. Páginas antigas configuradas com <br><br> viram parágrafos também; linhas de tabela mantêm seus cabeçalhos de coluna.
  6. Fatos e âncoras — ids restaurados; números viram fatos apenas ao lado de uma unidade; intervalos mantêm ambas as extremidades.
  7. Blocagem — guloso, em ordem, sob dois orçamentos ao mesmo tempo: 20 000 tokens e 50 000 caracteres por padrão.
  8. Montagemstate, markdown, usage, warnings e o rastreamento sob solicitação.
Como é o resultado
const r = await sieve({ kind: 'url', url: 'https://docs.typesafe.ai/models' });

r.state.title         // "Models"
r.state.facts[0]      // { value: 42, unit: "USD_per_billion", label: "price_btok_mtok",
                      //   context: "Price (per Btok / per Mtok) | jev-1.13.0: $42 / $0.042", from: "b3" }
r.state.facts[1]      // { value: 0.042, unit: "USD_per_million", … }   — paired by position
r.state.chunks[0]     // { id: "c1", tokens: 1210, chars: 5357, anchor: "Current models",
                      //   headings: ["Current models", "Pricing", …], blocks: ["b1", …, "b36"], text: "…" }
r.usage               // { rawTokens: 127413, stateTokens: 1211,
                      //   visibleChars: 4939, stateChars: 5357, chunks: 1, ms: 1503 }
r.warnings            // []
r.markdown            // the same article, for a human or a generative model

Resultados esperados nunca lançam exceções. Eles voltam como avisos, cada um nomeado:

AvisoSignificado
robots-disallowedo site pede que rastreadores fiquem de fora; não buscamos
blockedum desafio de bot ou uma recusa (403, 405, 429, "Só um momento…"), com o status
http-errorum 404 ou 500 que ainda renderizou uma página de erro; não é a página que você pediu
paywalla página marca seu artigo como não gratuito; você recebeu o teaser
empty-without-jso contêiner do artigo está vazio e um script o preencheria
thin-contentuma página grande que rendeu pouca prosa — uma página inicial, uma listagem
block-splitum bloco excedeu o orçamento e foi cortado em limites de frase
facts-cappeda página tem mais fatos do que os 500 listados — uma longa tabela de tarifas, por exemplo

You give Claude Code a rule in plain words. Claude calls sieve_page, gets state, asks Jev typed questions through jev-mcp, gets scores with probabilities, sorts and writes up. Sieve prepares. Jev judges. Claude writes.

Use a partir de um agente

Você diz o que quer em palavras simples. O agente encontra as páginas, chama sieve_page para cada uma, entrega o estado a um modelo de decisão com uma pergunta tipada e escreve o resultado. Sieve prepara. O juiz julga. O agente escreve.

{ "mcpServers": { "sieve": { "command": "npx", "args": ["-y", "codearia-sieve"] } } }

Listado no Registro Oficial de MCP como io.github.AntonG87/codearia-sieve; clientes que leem o registro podem instalá-lo pelo nome.

sieve_pageurl ou html

Retorna structuredContent tipado com um esquema de saída: source, state, usage, warnings. No modo padrão summary, os blocos carregam tamanhos, âncoras e seus títulos, mas sem texto — o agente vê o esboço do que existe sem pagar por isso. mode: "full" e mode: "markdown" quando você quer tudo.

sieve_chunkurl, id

O texto de um bloco do último resultado para aquela URL, sem nova busca. Visão geral primeiro, depois apenas o necessário — a ferramenta aplica sua própria ideia a si mesma.

Combina com jev-mcp: os blocos são dimensionados para caber em seus campos, então o estado vai direto para uma pergunta tipada.

Verificado por um juiz

A afirmação é que um modelo de decisão recebe entrada melhor do Sieve do que de texto bruto. Então o resultado foi entregue a um. examples/jev.ts dirige ambos os servidores MCP com o cliente oficial — codearia-sieve prepara seis páginas (documentação de API, uma nota de lançamento, dois artigos da Wikipédia em dois idiomas, duas páginas de preços), Jev as julga através de jev-mcp. Mesma execução, 21 de setembro de 2026:

Pergunta ao JevEntrada do SieveResultado
jev_classify — que tipo de página é esta?título + cabeçalho do primeiro bloco, sob o limite de 2 000 caracteres da ferramenta6 de 6 corretos; 5 automáticos, 1 sinalizado para revisão — uma página que é tanto documentação quanto tabela de tarifas
jev_verify — cada fato extraído está realmente na página?cada fato como uma afirmação, seus blocos como evidência11 de 11 verificados, todos automáticos, confiança 0,86–1,0
jev_extract — quando foi publicado?primeiro bloco, um regex de data, uma descriçãoconcorda com o Sieve onde a página declara uma data; o Sieve também lê JSON-LD e <meta>, que o Jev nunca vê

A primeira passada deste teste fez seu trabalho ao contrário: o Jev enviou três fatos para revisão e contradisse um. Todos os quatro rastrearam até o Sieve — uma linha de tabela rotulada pelo cabeçalho de coluna em vez do cabeçalho de linha, duas tarifas em um cabeçalho deixadas sem par, e uma referência bibliográfica russa "256 с." lida como segundos. Corrigido, testado, reexecutado: 11 de 11. Um juiz que pode dizer quando seu parser está errado é o ponto de todo o emparelhamento.

TYPESAFE_API_KEY=… node --experimental-strip-types examples/jev.ts

Use como biblioteca

import { sieve } from 'codearia-sieve';

await sieve({ kind: 'url', url });                    // fetch it
await sieve({ kind: 'html', html, url });             // already have it; url only for anchors

await sieve(input, {
  budget:    { maxTokens: 8000, maxChars: 30000 },    // chunk limits
  trace:     true,                                    // everything discarded, and why
  tokenizer: myTokenizer,                             // o200k by default; swap for your model's
  fetcher:   myFetcher,                               // your transport, or a file reader in tests
  now:       () => fixedDate,                         // injected clock: identical output on identical input
  selector:  mySelector, task: 'is this about pricing?', // relevance judge; nothing runs without one
});

parseDate, findDates e os limites do fornecedor (JEV, JEV_MCP, DEFAULT_BUDGET) também são exportados.

Onde para

  • Páginas iniciais, listagens e páginas de produto não têm artigo para encontrar. Você recebe os títulos e um aviso thin-content, não uma vitória falsa.
  • Artigos renderizados por JavaScript voltam como empty-without-js quando o contêiner está vazio. Um site que envia um teaser e transmite o resto não pode ser diferenciado sem um navegador; você recebe o teaser.
  • Páginas com muito texto economizam menos. Um romance inteiro economiza 22 %, um RFC 84 %: não há embrulho para remover e o texto é mantido por completo. Isso é a ferramenta funcionando.
  • Uma grade de preços não é uma tabela. Um fato sabe o bloco de onde veio, não a coluna de plano sob a qual está; o Sieve não adivinha o emparelhamento. Envie o bloco — uma página de preços tem cerca de mil tokens após a limpeza — e deixe o juiz ler: examples/pricing-watch.ts.
  • Tokens são contados com o200k como aproximação. Páginas acima de um megabyte recebem uma contagem amostrada e usage.rawTokensEstimated: true.

Desenvolva

npm install
npm test                    # 71 tests, offline, a few seconds
npm run demo -- <url>       # the token bill for one page
npm run bench               # the 20-page benchmark set
npm run analytics           # the 56-page random sample: rows, CSV, summary

Notas de design — visão e arquitetura — estão em docs/.

MIT © 2026 Anton Evelson · Codearia Academy