CommunityImagemgithub.com

darkhipo/sharethought

Empacote dados em camadas dentro de um PNG. A imagem que os humanos veem é a superfície SVG renderizada; a fonte SVG e um documento markdown viajam dentro do arquivo — em chunks iTXt que sobrevivem a pipelines de imagem e em um trailer pesquisável após o IEND. Use ao criar, desempacotar, editar ou recompactar arquivos sharethought — artefatos autocontidos para troca colaborativa humano-LLM, onde o humano lê a imagem e o LLM lê a profundidade.

O que é sharethought?

O skill 'sharethought' permite criar e gerenciar artefatos PNG que carregam dados em camadas: a imagem visível (superfície SVG renderizada) mais a fonte SVG original e um documento Markdown, transportados em chunks iTXt (que sobrevivem a pipelines de imagem) e em um trailer após o chunk IEND (para transporte byte-exato). É útil para cenários de colaboração humano-LLM onde o humano vê a imagem e o LLM acessa o conteúdo oculto para contexto e edição. Suporta plataformas como Claude Code, Cursor e Codex via linha de comando (script Python padrão da biblioteca). O funcionamento baseia-se em um formato exato com marcador `SHARETHOUGHT-v1`, manifesto JSON indexando seções, e dois carriers opcionais (trailer e chunks iTXt) que podem ser escritos juntos para máxima compatibilidade. A implementação de referência (`sharethought.py`) empacota, desempacota, verifica e recompacta arquivos, garantindo consistência entre carriers e detectando adulteração externa.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/darkhipo/sharethought/tree/HEAD

Installed? Explore more Imagem skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que sharethought faz?

Um arquivo sharethought é um PNG válido com seções de texto transportadas junto à imagem. Ele abre e renderiza como uma imagem normal em todos os lugares. Por trás da imagem: a fonte SVG da qual foi renderizado e um documento markdown. Um manifesto no início dos dados transportados indexa tudo e carrega as instruções de desempacotamento/recompactação dentro do próprio arquivo.

As seções podem viajar em um de dois carriers: anexadas após o chunk IEND (apenas transporte byte-exato simples) ou dentro de chunks PNG ancillares (sobrevive a pipelines de imagem). Consulte Carriers.

Use a implementação de referência

sharethought.py neste repositório é a implementação testada, apenas com a biblioteca padrão. Prefira-a em vez de análise manual — cada reimplementação é uma nova superfície de bugs.

python3 sharethought.py pack   --png base.png --svg s.svg --doc d.md -o out.png --what "uma linha"
python3 sharethought.py unpack out.png [--out-dir DIR]
python3 sharethought.py repack --text out.png --set doc=new.md -o out2.png
python3 sharethought.py verify out.png
python3 -m unittest -q test_sharethought    # a suíte de testes

pack escreve ambos os carriers a partir de uma única construção (eles não podem divergir). unpack prefere chunks, recai para o trailer e gera erro ruidosamente se ambos os carriers estiverem presentes, mas discordarem — o pack não pode produzir isso, então discordância significa adulteração externa. verify verifica assinatura, IEND, ambos os carriers, gramática dos nomes de seção e consistência manifesto↔seção.

Formato (exato)

[ bytes PNG ... chunk IEND ]
SHARETHOUGHT-v1\n
[ manifesto JSON — um objeto UTF-8, veja esquema ]\n
<<<SECTION:nome>>>\n
[ conteúdo da seção — UTF-8 puro por padrão, base64 se "enc":"base64" ]\n
<<<END:nome>>>\n
... (mais seções, mesma estrutura)

O marcador SHARETHOUGHT-v1 começa imediatamente após o chunk IEND do PNG e é terminado por uma nova linha. (O byte anterior a ele é a cauda CRC do chunk IEND, não uma nova linha — então encontre-o por byte, não por linha.) Tudo do marcador até o EOF é o trailer. Seções padrão: svg (a fonte da imagem, image/svg+xml) e doc (markdown, text/markdown). Seções adicionais arbitrárias são permitidas — qualquer tipo de texto.

Nomes de seção devem corresponder a [A-Za-z0-9_]+. Nomes fora dessa gramática são rejeitados no momento do pack e sinalizados com um erro nomeado no unpack — eles nunca desaparecem silenciosamente.

Carriers

O mesmo manifesto e seções podem ser transportados de duas maneiras. Escolha conforme o transporte.

A. Trailer — anexado após o chunk IEND (o padrão acima).

  • Trivial de escrever manualmente: cat trailer.txt >> arquivo.png. Sem CRC, sem estrutura de chunk, sem biblioteca.
  • Sobrevive apenas a transportes byte-exatos: git, zip, curl -O, uma cópia direta de arquivo.
  • Não sobrevive a nenhum pipeline que re-serializa ou re-codifica a imagem. Uma transcodificação PNG→JPEG o descarta completamente. Uma reescrita em nível de chunk — que muitos pipelines de chat e drive fazem — mantém todos os bytes IDAT e descarta tudo após IEND.

B. Chunks ancillares — iTXt dentro do fluxo de chunks PNG.

  • Vive dentro da lista de chunks, então sobrevive a reescritas em nível de chunk e pipelines de imagem que mantêm PNG.
  • Custa um CRC e estrutura de chunk, e seções grandes querem compressão.
  • Não sobrevive a uma transcodificação PNG→JPEG — nada sobrevive a isso exceto os pixels.

Recomendação: escreva ambos (pack faz). Mesmo payload, uma construção, nenhuma divergência possível. Um leitor procura chunks primeiro e recai para o trailer, então o arquivo funciona tanto em pipelines de chat quanto em transportes byte-exatos. O custo é aproximadamente uma cópia extra do payload.

Layout dos chunks:

[ IHDR ] [ IDAT ... ] [ iTXt sharethought:manifest ] [ iTXt sharethought:<nome> ] ... [ IEND ]

Um iTXt por seção: keyword sharethought:manifest para o manifesto, sharethought:<nome> para o corpo de cada seção (corpo puro, sem delimitadores). Estrutura padrão iTXt — keyword \0, flag de compressão (1 byte, 1 = zlib), método de compressão (0), tag de idioma \0, keyword traduzida \0, então o texto.

Esquema do manifesto

{
  "v": 1,
  "what": "uma linha descrevendo este artefato",
  "how": {
    "unpack": "Leia os chunks iTXt chamados sharethought:* se presentes (o manifesto é sharethought:manifest); caso contrário, leia os bytes do marcador SHARETHOUGHT-v1 até o EOF. Analise o manifesto JSON, depois cada seção entre seus delimitadores <<<SECTION:nome>>> e <<<END:nome>>>. Decodifique seções base64.",
    "repack_text_only": "Mantenha os bytes PNG originais até o marcador, depois reescreva o trailer com manifesto e seções atualizados. Nenhuma re-renderização necessária. Ou execute: python3 sharethought.py repack --text FILE --set doc=new.md",
    "repack_visual": "Para alterar a imagem: edite a seção svg, renderize-a para PNG (rsvg-convert -w 1200 in.svg > out.png, ou cairosvg, ou resvg, ou um navegador headless como Chromium via Playwright), depois empacote novamente."
  },
  "sections": [
    { "name": "svg",  "type": "image/svg+xml", "enc": "utf8",    "summary": "descrição de uma linha da imagem" },
    { "name": "doc",  "type": "text/markdown", "enc": "utf8",    "summary": "descrição de uma linha do documento" }
  ]
}

O campo how é obrigatório e deve conter instruções funcionais — o arquivo ensina qualquer leitor frio a abri-lo.

Desempacotar

Melhor: python3 sharethought.py unpack arquivo.png. Manual, carrier trailer:

raw = open("arquivo.png", "rb").read()
# Percorra os chunks PNG até o IEND real — nunca use raw.index() no marcador,
# bytes IDAT comprimidos podem contê-lo por coincidência.
off = 8
while True:
    import struct
    ln, typ = struct.unpack(">I", raw[off:off+4])[0], raw[off+4:off+8]
    if typ == b"IEND": break
    off += 12 + ln
trailer = raw[off + 12:].decode("utf-8")
import json
manifest, _ = json.JSONDecoder().raw_decode(trailer[trailer.index("\n")+1:])
import re
for m in re.finditer(r"<<<SECTION:(\w+)>>>\n(.*?)\n<<<END:\1>>>", trailer, re.DOTALL):
    name, body = m.group(1), m.group(2)
    # se enc for base64: import base64; body = base64.b64decode(body)

Manual, carrier chunk (verificado primeiro):

import struct, zlib, json
raw = open("arquivo.png", "rb").read()
off, chunks = 8, {}
while off + 8 <= len(raw):
    ln = struct.unpack(">I", raw[off:off+4])[0]
    typ = raw[off+4:off+8]
    data = raw[off+8:off+8+ln]
    if typ == b"IEND": break
    if typ == b"iTXt":
        key, _, rest = data.partition(b"\x00")
        flag = rest[0]
        rest = rest[2:]
        _, _, rest = rest.partition(b"\x00")   # tag de idioma
        _, _, rest = rest.partition(b"\x00")   # keyword traduzida
        if flag == 1:
            rest = zlib.decompress(rest)
        chunks[key.decode()] = rest.decode("utf-8")
    off += 12 + ln
manifest = json.loads(chunks["sharethought:manifest"])
sections = {k[len("sharethought:"):]: v
            for k, v in chunks.items()
            if k.startswith("sharethought:") and k != "sharethought:manifest"}

Apenas com shell: tail -c +$(( $(grep -abo 'SHARETHOUGHT-v1' arquivo.png | head -1 | cut -d: -f1) + 1 )) arquivo.png imprime o trailer como texto (funciona apenas quando o trailer sobreviveu ao transporte).

Criar

Melhor: renderize o SVG, depois python3 sharethought.py pack --png out.png --svg diagram.svg --doc notes.md -o artifact.png. Manual:

  1. Escreva o SVG (a imagem ou diagrama voltado ao humano).
  2. Renderize para PNG: rsvg-convert -w 1200 diagram.svg > out.png (ou cairosvg diagram.svg -o out.png, ou resvg diagram.svg out.png, ou um navegador headless — Chromium via Playwright — que geralmente é o único renderizador SVG instalado).
  3. Escreva o documento markdown.
  4. Anexe o trailer (formato cat trailer.txt >> arquivo.png) e, melhor ainda, também escreva os chunks iTXt — pack faz ambos a partir de uma única construção.

A saída renderiza como um PNG normal. Verifique: abra-o em qualquer visualizador de imagens (mostra a imagem), depois strings artifact.png | grep SHARETHOUGHT (mostra que o trailer existe), ou python3 sharethought.py verify artifact.png (verifica tudo, incluindo que ambos os carriers concordam).

Recompactar

Melhor: python3 sharethought.py repack --text artifact.png --set doc=new.md -o out.png — reescreve ambos os carriers, nenhum renderizador necessário.

Edição apenas de texto (doc alterado, imagem inalterada): reutilize os bytes PNG originais (tudo antes de SHARETHOUGHT-v1), escreva um novo trailer com a seção editada e resumos do manifesto atualizados. Se o arquivo também carregar chunks, reescreva-os também — a implementação de referência reconstrói ambos a partir de uma única fonte, que é a única maneira segura de mantê-los em concordância.

Edição visual (svg alterado): renderize o SVG modificado para um novo PNG, depois empacote novamente com a nova seção svg + doc + manifesto. Qualquer renderizador SVG funciona, incluindo um navegador headless.

Regra de ida e volta: um arquivo recompactado é um arquivo sharethought. Mesmo formato, mesmo marcador, manifesto atualizado.

Segurança dos delimitadores

Os delimitadores de seção são <<<SECTION:nome>>> e <<<END:nome>>> em suas próprias linhas. Se o conteúdo puder conter tal linha, defina "enc":"base64" no manifesto para essa seção e codifique o corpo em base64 — pack faz isso automaticamente quando um corpo contém seu próprio delimitador de fechamento ou a string do marcador.

Qual colisão realmente quebra: um corpo contendo delimitadores de uma seção diferente é inofensivo. Um corpo contendo sua própria linha <<<END:nome>>> é truncado por uma regex não-gulosa — tudo após essa linha é órfão. A implementação de referência detecta isso (erros de conteúdo órfão e delimitador desbalanceado) em vez de truncar silenciosamente. Em caso de dúvida, use base64.

Mantendo o payload vivo

O payload não faz parte dos dados de pixel do PNG, então qualquer ferramenta que re-codifique a imagem pode descartá-lo silenciosamente e deixar um PNG de aparência perfeitamente normal sem profundidade. Isso inclui Image.open(f).save(g) no Pillow, editores de imagem e otimizadores de CDN. Recompacte a partir dos bytes originais em vez de salvar novamente o arquivo renderizado.

Trailers após IEND sobrevivem apenas a transportes byte-exatos. Se o arquivo precisar viajar por um pipeline de imagem — um anexo de chat, um gerador de miniaturas, um transcodificador — use o carrier de chunk (pack faz), e faça upload como arquivo em vez de como imagem inline para que o PNG não seja transcodificado para JPEG.

Trabalhando com um humano

O humano vê o PNG — a camada visual simplificada. Toda a profundidade (fonte SVG, doc, manifesto) é invisível para visualização casual, mas totalmente presente para você. Quando o humano perguntar sobre a imagem, descompacte e leia o doc para contexto. Quando o humano quiser a imagem alterada, edite o svg e recompacte visualmente. Quando o humano quiser profundidade adicionada, edite o doc e recompacte apenas texto. O arquivo é a troca completa — um artefato, ambas as modalidades, sem canais paralelos.

Habilidades Relacionadas