UNC-RENCI-KGAI/croissant-semantics

Adiciona semântica (o que os dados significam) a um arquivo de metadados Croissant existente para uma base de conhecimento biomédica — agrupa colunas em entidades tipadas (genes, doenças, ...), tipa linhas como associações Biolink, marca prefixos de identificadores, unidades e valores de código — usando apenas construções do Croissant 1.1, e verifica o resultado contra os dados reais. Use quando for solicitado a adicionar semântica, tipos Biolink, prefixos de identificadores ou estrutura de entidade/associação a um croissant.json.

O que é croissant-semantics?

Esta habilidade transforma um arquivo Croissant básico (que lista arquivos e colunas de uma base de conhecimento) em um arquivo semanticamente rico, utilizando construções do padrão Croissant 1.1. Ela adiciona significado aos dados: define quais colunas descrevem entidades como genes ou doenças, especifica que tipo de associação uma linha representa (usando o modelo Biolink), atribui prefixos de identificadores (como 'HGNC' ou 'UniProt'), e mapeia valores de código. O processo é inteiramente baseado em planos: o usuário ou agente gera um plano JSON, que é então aplicado e verificado por scripts automatizados, sem edição manual do croissant. A habilidade é especialmente útil para bases de conhecimento biomédicas que precisam ser integradas em um grafo de conhecimento Biolink. Ela suporta uma ampla variedade de formatos de arquivo (CSV, TSV, VCF, GAF, MITAB, CTD, planilhas, bancos de dados SQLite, Parquet) e inclui ferramentas para amostragem de dados, detecção de dialetos de arquivo, consulta a vocabulários Biolink, e verificação rigorosa. O fluxo de trabalho envolve inventariar layouts, analisar dados amostrados, planejar a semântica, aplicar o plano e verificar o resultado contra os dados reais e os padrões Biolink. A habilidade também gerencia respostas de mantenedores, prefixos de identificadores propostos, e lida graciosamente com problemas como servidores lentos, dados ausentes ou formatos não suportados.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/UNC-RENCI-KGAI/KGB-CIA/tree/HEAD/.agents/skills/metadata/croissant-semantics

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

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

Documentação

Adicionando semântica a um croissant

Um arquivo RoboCroissant informa quais arquivos uma base de conhecimento tem e quais colunas eles contêm. Esta habilidade adiciona o que os dados significam: quais colunas juntas descrevem um gene ou uma doença, o que uma linha afirma, qual prefixo de identificador as ids de uma coluna usam, o que os códigos representam. Ela escreve isso em um novo croissant usando construções do Croissant 1.1 e registra o motivo de cada afirmação.

Você produz um plano (JSON, por layout), e os scripts aplicam e verificam o plano. Você não edita o croissant manualmente.

Entradas e saídas

  • Entrada: um croissant (croissant.json ou croissant.json.gz) e um diretório de saída, além do semantics_answers.json dos mantenedores ao lado do croissant, se houver.
  • Saída, no diretório de saída:
    • semantics_plan.json — o plano (formato: reference/plan-format.md)
    • croissant.semantic.json (ou .json.gz se a entrada estiver compactada) — o resultado
    • check_report.md — saída de check.py (e check_report.load_errors.txt, erros completos do mlcroissant, quando os registros falham ao carregar)
    • notes.md — decisões, layouts omitidos e por quê, e perguntas para os mantenedores da base de conhecimento

O croissant de entrada nunca é modificado. Coloque downloads, scripts auxiliares e outros trabalhos temporários em OUT/work/, não em outro lugar.

Scripts

Todos em scripts/, executados diretamente (são arquivos uv run --script e instalam suas próprias dependências). Use --help em qualquer um deles.

ScriptUso
inventory.py CROISSANT [--layout ID] [--json F] [--common-columns]Lista layouts (conjuntos de colunas distintos), do maior para o menor; descreve as colunas, conjuntos de registros e arquivos de um layout; lista as colunas que a maioria dos conjuntos de registros compartilha
sample.py CROISSANT --layout IDLê linhas reais de três dos arquivos do layout; mostra os valores de exemplo de cada coluna e sua forma (CURIs e seus prefixos, ids simples, listas, códigos)
dialects.py list/show/detect/readFormatos de arquivo conhecidos (VCF, GAF, MITAB, CTD, ...) como dialetos computáveis; qual deles lê os arquivos de um layout; lê registros usando apenas o que um croissant diz sobre o arquivo
vocab.py class/slot/search/associations/prefix/identify/term/ols/inforesConsulta classes e slots Biolink (com sugestões de aproximação), classes de associação para um par sujeito/objeto, prefixos de identificadores (Biolink + Bioregistry), quais prefixos se encaixam em ids simples, termos de ontologia por id ou texto, e ids infores para nomes de fontes
apply_plan.py CROISSANT PLAN OUTEscreve o plano em um novo croissant
check.py CROISSANT PLAN OUT --report R --load-records--plan-only primeiro: termos, prefixos, dialetos e unidades em segundos. Em seguida, a verificação completa: verifica termos, prefixos, códigos e dialetos em relação ao Biolink e dados amostrados, executa o validador MLCommons, lê alguns registros através do mlcroissant (das primeiras linhas de cada arquivo, não downloads completos) e relata a cobertura

Fluxo de trabalho

  1. Levantamento. Se houver um semantics_answers.json ao lado do croissant, leia-o primeiro: ele contém as respostas dos mantenedores da base de conhecimento para perguntas anteriores (veja "Respostas do Mantenedor" abaixo). Não faça essas perguntas novamente; apply_plan.py e check.py aplicam as respostas ao seu plano automaticamente. Em seguida, inventory.py CROISSANT. Anote a base de conhecimento (nome, descrição, url no croissant) e como os conjuntos de registros se distribuem entre os layouts. Bases de conhecimento grandes têm centenas de layouts; trabalhe a partir do topo da lista.

    Encontre o próprio id infores da base de conhecimento agora (vocab.py infores NOME; tente seu nome completo, sua sigla e sua url) e defina-o como infores do plano. Ele nomeia o recurso cujos arquivos são estes, e os construtores de grafos o citam como a fonte de tudo o que é lido deles: sem ele, a etapa de transformação não construirá a base de conhecimento. Quando várias entradas coincidirem, escolha a do recurso que publica estes arquivos, não de um serviço que os re-serve (infores:reactome, não infores:automat-reactome). check.py o compara com o que o resto do seu plano diz: uma única constante aggregator ou provided_by nomeia a base de conhecimento também (os ortólogos do HCOP são agregados por infores:hgnc), e uma incompatibilidade é um aviso a ser resolvido.

    Quando nenhum existir, proponha um: infores: e o nome curto da base de conhecimento em palavras minúsculas separadas por hífens (infores:bioplex, infores:expression-atlas), com "infores_proposed": true no plano. Em seguida, escreva sua entrada de catálogo com vocab.py infores-entry CROISSANT --id infores:NOME, adicionando --knowledge-level e --agent-type quando a documentação os tornar claros, e coloque-a em notes.md sob um cabeçalho Infores id para registrar, próximo ao topo. Diga lá que o usuário deve registrá-lo com um pull request para o registro infores (o comando imprime onde), e que o id pode mudar na revisão. check.py mantém um aviso em um id proposto até que ele seja registrado; não o explique detalhadamente.

  2. Escolha os layouts a serem feitos. Mire nos layouts que cobrem a maioria dos conjuntos de registros e o conteúdo principal (associações e as principais tabelas de entidades) — normalmente os 5 a 15 principais, ou até que os layouts restantes sejam menores (arquivos tipo readme, logs, contagens por versão). Se houver muitos layouts pequenos (inventory.py dirá), os conjuntos de registros provavelmente compartilham colunas principais: use inventory.py --common-columns e planeje essas colunas uma vez com match.has_columns. Tudo o que você deixar de fora vai para a lista skipped do plano com um motivo. Fazer menos layouts bem é melhor do que muitos mal.

  3. Para cada layout, observe os dados antes de decidir qualquer coisa.

    • inventory.py CROISSANT --layout ID para colunas, descrições e nomes de arquivos. Uma coluna marcada como MIXED tem tipos atômicos diferentes em diferentes conjuntos de registros (o pipeline os infere por arquivo); decida seu tipo a partir dos dados e defina atomic.
    • Para tabelas, dialects.py detect CROISSANT --layout ID descobre como os arquivos são escritos (linhas de comentário, cabeçalho ou nenhum, delimitador) entre formatos conhecidos. Formatos bem conhecidos (VCF, GAF, MITAB) têm especificações publicadas; confie neles em vez de redescobrir o formato. Se nada se encaixar, descreva o dialeto inline (reference/dialects.md). Em seguida, amostre com --dialect NOME para que as linhas sejam lidas da maneira que o formato diz, não adivinhada.
    • sample.py CROISSANT --layout ID para valores reais. Ele lê três arquivos do layout (o de aparência mais recente pelo nome, o maior, o menor), porque um arquivo — geralmente um snapshot antigo ou um subconjunto filtrado — pode esconder valores (placeholders N/A, valores de código extras, outros tipos de id). --files N amostra mais deles; --record-set ID amostra um arquivo específico. Se a amostragem falhar (um arquivo enorme, um arquivo, um conjunto de arquivos), diga isso no basis do plano e diminua a confiança.
    • Para colunas de código (tipos, evidência, relações, fontes), uma amostra perde valores raros. sample.py CROISSANT --record-set ID --profile COL1,COL2 lê o arquivo inteiro e conta cada valor distinto; repita --record-set para somar vários arquivos. Mapeie a partir do perfil, não da amostra.
    • Seja gentil com os servidores da base de conhecimento. Execute um comando de amostragem ou verificação de cada vez por base de conhecimento, nunca muitos em paralelo: os hosts bloqueiam rajadas com um desafio de bot, e então toda requisição posterior falha. Os scripts controlam suas próprias requisições e armazenam downloads em cache (em ~/.cache/croissant-semantics/downloads; --refresh baixa novamente), então reexecutar é barato (uma cópia em cache sob um --max-mb maior atende a um menor). Se um script relatar um desafio de bot ou um HTTP 403, pare de amostrar aquele host, não tente contorná-lo, e diga em notes.md quais verificações não puderam ser executadas. Os scripts então recusam aquele host por uma hora, entre execuções, e trabalham a partir de arquivos em cache.
    • Planilhas (xlsx e xls legado), bancos de dados SQLite e arquivos parquet também são amostrados e perfilados: a planilha ou tabela é aquela com que o nome do conjunto de registros termina ("file.xlsx — Sheet1", "file.xlsx: Sheet1"), e a amostragem falha em vez de adivinhar quando não consegue identificar. Eles são lidos por inteiro, então aumente --max-mb se necessário (também no check.py). O mlcroissant não pode ler planilhas ou bancos de dados, portanto seus registros não são carregados.
    • XML, RDF (Turtle, RDF/XML, OWL), FASTA e outros arquivos que não são tabelas não podem ser amostrados: os scripts dizem isso. Se um layout for importante, verifique seus ids com um pequeno script em OUT/work/ (uv run --with rdflib para RDF; faça streaming de XML com xml.etree.ElementTree.iterparse) e diga como em notes.md. Seus campos geralmente não têm extract, então nenhuma ferramenta pode lê-los: um problema do gerador a ser relatado.
    • --profile com --layout perfiliza --files conjuntos de registros do layout (padrão 3, ou all) em vez de nomear cada um com --record-set. --prefixes conta o prefixo ou tag de cada valor, para todas as colunas perfiladas ou apenas as listadas (--prefixes COL1,COL2); --by COL faz tabulação cruzada contra outra coluna (com quais tipos de objeto cada código ocorre); --split SEP conta os itens de células de lista; --per-file perfiliza cada conjunto de registros individualmente (para verificar se os ids são únicos por arquivo); --stop-mb N para cada arquivo após N MB, para arquivos de muitos GB (as contagens então cobrem apenas o início; em um arquivo classificado por espécie ou id, isso pode ser apenas um grupo, então diga isso).
    • Perfilize colunas de id dos layouts principais (--profile COL --shapes) antes de confiar nelas: a verificação de dados lê as primeiras linhas de alguns arquivos, portanto uma coluna cujas linhas posteriores faltam ids, ou contêm outra família de ids, passa. Várias bases de conhecimento tinham 20-30% de linhas sem um id após centenas de linhas que todas tinham um.
    • Uma entrada match.has_columns que cobre muitos layouts é amostrada por check.py em apenas alguns de seus arquivos. Amostre os layouts que ela abrange e que diferem (--record-set-name, --files) antes de confiar nela.
    • Os scripts usam o armazenamento de certificados do sistema operacional. Se os downloads ainda falharem com um erro de certificado, relate-o com a saída; não desative a verificação.
    • Se a documentação estiver atrás de uma verificação de bot ("verify you are human", um desafio Cloudflare ou ALTCHA), não tente contorná-la; planeje a partir de dados e nomes, e limite a confiança a medium para significados que apenas a documentação poderia confirmar. A proveniência do croissant pode citar páginas que desde então foram colocadas atrás de uma verificação: cite apenas o que você pôde ler.
    • Em um arquivo enorme, as primeiras linhas podem ser não representativas (o CTD de 3 GB genes_diseases começa com milhares de linhas inferidas). Perfilize um arquivo menor do mesmo layout (o subconjunto curado) em vez de fazer streaming de tudo.
    • Para selecionar conjuntos de registros pelo nome, use --record-set-name REGEX (em vez de --layout) em vez de construir uma lista de argumentos --record-set no shell (o zsh não divide variáveis em palavras). --per-file mostra cada arquivo amostrado separadamente, para layouts cujos arquivos diferem (um tipo de id por arquivo).
    • A verificação de dados lê as primeiras linhas de alguns arquivos. As linhas posteriores de uma coluna podem diferir (nós em branco após 200 IRIs, um código raro): confirme formas de id e códigos com --profile, que lê arquivos inteiros.
    • inventory.py lista arquivos de documentação enviados com os dados (README.pdf dentro de um zip, um dicionário de dados) após os layouts. Leia os relevantes: sample.py CROISSANT --dump ARQUIVO imprime um arquivo como texto, --member NOME um membro de um arquivo (um zip é lido por inteiro, então aumente --max-mb para um grande) (ele lista os membros de um zip quando o nome está errado), --sheet NOME uma planilha de uma planilha.
    • sample.py sinaliza colunas cujo tipo declarado não se encaixa nos valores (uma coluna sc:Integer contendo 27152464|29518214) e arquivos cujas linhas são mais largas ou mais estreitas que o cabeçalho. Ambos são geralmente problemas de pipeline: corrija tipos com atomic e os relate.
    • Quando os scripts não conseguem ler uma fonte, busque os arquivos você mesmo (um de cada vez, em OUT/work/) e aponte os scripts para eles com --url-map OLD=file:///caminho/absoluto/ para que suas verificações ainda sejam executadas, em vez de escrever seus próprios perfiladores. Os downloads são armazenados em cache, e ~/.cache/croissant-semantics/downloads/index.tsv mapeia cada arquivo em cache para sua URL.
    • Se os "nomes de colunas" de um layout são na verdade dados (sem linha de cabeçalho, então o pipeline pegou a primeira linha de dados como nomes, e cada arquivo se tornou seu próprio layout), pule-o e relate-o em notes.md como um problema de pipeline.
    • Se as URLs dos dados não existirem mais (HTTP 404), a base de conhecimento provavelmente mudou para uma versão mais recente. Encontre as URLs atuais em sua página de download e passe --url-map OLD=NEW para sample.py e check.py (por exemplo, --url-map 202607=202610). Quando mais do que a versão mudar (outro caminho ou nome de arquivo), mapeie URLs inteiras, uma --url-map URL_ANTIGA=URL_NOVA por arquivo. Quando as próprias URLs contiverem = (strings de consulta), escreva URL_ANTIGA=>URL_NOVA. Diga isso em notes.md; também é um problema de pipeline. Uma URL de endpoint SPARQL que retorna JSON onde o croissant descreve uma tabela geralmente precisa de &format=csv (ou text/csv) mapeado.
    • Arquivos: membros de arquivos zip e tar são amostrados. Um zip é baixado por inteiro (até --max-mb); um tar é transmitido até que o membro seja encontrado, portanto um membro profundamente dentro de um tar enorme pode exceder --max-mb. Um arquivo que falha uma vez não é tentado novamente, e a amostragem para após falhas repetidas. Se necessário, extraia um membro em OUT/work/ você mesmo e registre o que verificou e como em notes.md.
    • Se os dados precisarem de login ou chave de API (HTTP 401/403, ou o conditionsOfAccess do croissant disser isso), não procure por credenciais. Planeje a partir da documentação e apenas dos nomes das colunas: source é documentation ou agent, confidence no máximo medium, e notes.md diz que nada foi verificado contra os dados.
    • Procure por um dicionário de dados enviado que um layout não tem; ignore layouts de tabela e enumeração. Se houver um arquivo de dicionário de dados separado, leia-o.
    • Ao planejar uma única coluna que contém | ou outra lista de valores, declare o tipo de célula como sc:List.
  4. Para cada layout, decida a semântica.

    • Combine colunas em entidades Biolink com entity: ENTIDADE (veja reference/plan-format.md). Cada entidade tem uma ou mais colunas de id (com @id ou @type no entity, e um identifier no match.has_columns), e outras colunas para rótulos (nomes, descrições) e atributos (espécie, tipo de célula, ...). Defina columns: ALL para uma entidade de coluna única; isso captura colunas que inventory.py ainda não viu (de layouts para os quais você escreveu um plano sem entidade, e elas aparecerão depois).
    • Tipo de linha: quando um layout descreve associações (gene-doença, variante-gene), dê a ele um row_type Biolink. As classes de associação ligam um subject e um object (veja reference/plan-format.md). Quando não houver associação, defina row_type como a entidade da linha.
    • Identificadores de entrada: cada coluna de id precisa de um prefixo de identificador. Use vocab.py identify para encontrá-lo a partir dos valores da coluna. Quando o prefixo não for conhecido pelo Biolink, use identifiers.org e defina prefix_in_biolink: false no prefixo. Quando um valor não for um CURIE e não houver prefixo (ids simples), defina example e confie no propósito da coluna.
    • Códigos: coloque cada coluna de código em um code_set e mapeie seus valores usando codes.
    • Unidades: defina a unidade na coluna e use vocab.py term para encontrá-la no UO.
    • Colunas de string com poucos valores distintos podem ser colunas de código: se --profile as mostrar repetindo, crie um code_set para elas.
    • Para uma coluna de string com muitos valores, verifique se os valores são ids que pertencem a outra entidade: declare references: ENTIDADE com o prefixo da outra entidade. Não crie uma entidade para a outra tabela aqui; isso é para o layout dela.
    • Colunas com nomes como ICD10_CODE podem conter códigos de ontologia. Use vocab.py identify para encontrá-los e mapeie para uma ontologia Biolink.
    • Colunas com nomes como p-value ou score devem ter um data_type numérico e unit.
    • Para colunas booleanas e de data, defina data_type adequadamente.
    • Colunas de descrição longa devem ser marcadas como description.
    • Colunas de nome devem ser marcadas como name.
    • Quando uma coluna tiver vários propósitos, escolha o principal e anote o resto em notes.md.
    • Colunas computadas derivadas de outros campos não precisam de semântica: marque-as como derived.
    • Colunas de chave estrangeira que referenciam uma entidade diferente da linha devem ser marcadas como foreign_key com references: ENTIDADE.
    • Colunas de array devem ter is_array: true.
  5. Escreva o plano. Siga reference/plan-format.md exatamente. O plano cobre todos os layouts que você decidiu fazer e lista aqueles que você omitiu com um motivo. Execute check.py --plan-only com frequência; ele verifica a estrutura e sabe quais consultas de vocabulário são lentas. As opções do plano que você não usar devem ser omitidas, não definidas como nulas.

  6. Aplique e verifique.

    • apply_plan.py CROISSANT PLAN OUT produz o novo croissant.
    • check.py CROISSANT PLAN OUT verifica tudo. Execute --plan-only primeiro, depois a verificação completa. Execute com --load-records quando quiser que alguns registros sejam carregados (principalmente para relatar cobertura).
    • Quando a verificação falhar, corrija o plano (e a amostragem, se você perdeu um valor) e reaplique. Não edite o croissant de saída.
    • Quando a verificação emitir avisos, decida se eles merecem uma correção do plano ou uma anotação em notes.md.
    • Após a verificação completa passar sem erros fatais, escreva notes.md. Deve ter:
      • Infores id to register se você propôs um.
      • Pipeline problems: erros no croissant de entrada que afetam a semântica.
      • Decisions: escolhas não óbvias no plano, como você resolveu ambiguidades.
      • Skipped layouts: cada um com um motivo.
      • Questions for maintainers: perguntas para as quais apenas os mantenedores da base de conhecimento sabem a resposta.
      • Verification notes: quaisquer verificações que você não pôde executar e por quê.

Respostas do Mantenedor

O arquivo semantics_answers.json contém respostas dos mantenedores da base de conhecimento para perguntas feitas em uma execução anterior. Ele pode conter:

  • prefix_for: COLUNA -> PREFIXO para mapear uma coluna de id a um prefixo.
  • code_set_for: COLUNA -> lista de códigos para mapear códigos no formato {código: {id: ontologia_id, label: rótulo, parents: [ids_pai]}}.
  • entity_for: COLUNA -> ENTIDADE para definir a entidade de uma coluna.
  • row_type_for: LAYOUT -> TIPO para definir o tipo de linha de um layout.
  • infores: ID para definir o id infores.
  • url_map: URL_ANTIGA -> URL_NOVA para mapear URLs antigas para novas.
  • dialect: LAYOUT -> DIALETO para definir o dialeto de um layout.
  • skip: LAYOUT -> motivo para pular um layout.

apply_plan.py e check.py aplicam essas respostas automaticamente ao seu plano, se presentes. Você não precisa incluí-los em seu plano; eles são aplicados por cima.

Notas

  • Confiança: Cada declaração semântica pode ter uma confiança: high (verificada contra dados reais), medium (de documentação ou heurística forte), low (adivinhada). Defina a confiança no plano.
  • Fonte: Cada declaração pode ter uma fonte: data, documentation, agent (você), inferred, maintainer. Defina a fonte no plano.
  • Base: O plano deve ter um campo basis que descreve o que você examinou para fazer cada declaração.
  • O plano é um JSON com chaves layouts, infores, basis, skipped. Cada layout tem chaves id, entity, row_type, match, columns, code_sets, dialect.

Habilidades Relacionadas