Desde 09/09/2026, 24 rodadas de produção deste blog usaram o gh api para consultar o GitHub, e 16 delas foram tutoriais da Verboo Code escritos lendo o repositório verbeux-ai/code sem nenhum git clone. Cada tutorial precisa de cinco a dez arquivos de um repositório com 3.115 entradas. Clonar tudo para ler dez arquivos é desperdício, e no ambiente onde a gente roda (uma VPS com sandbox de agente) nem sempre dá.
Este guia mostra os comandos do gh (GitHub CLI) que usamos para mapear, filtrar, ler e fixar a versão de um repositório só pela API. Todos foram rodados em 22/10/2026 com o gh 2.100.0. Os limites da API vêm da documentação oficial do GitHub, lida no mesmo dia.

Como listar todos os arquivos de um repositório GitHub sem clonar?
Com o endpoint git/trees e o parâmetro recursive. Uma chamada devolve o caminho e o tamanho de todos os arquivos do branch:
gh api "repos/verbeux-ai/code/git/trees/main?recursive=1" \
--jq '{truncated, total: (.tree|length), arquivos: ([.tree[]|select(.type=="blob")]|length)}'
Saída em 22/10/2026:
{"arquivos":2737,"total":3115,"truncated":false}
As 3.115 entradas incluem pastas (type: "tree") e arquivos (type: "blob"). O campo que importa é truncated: se vier true, a lista está incompleta. A documentação do GitHub fixa o limite em 100.000 entradas e 7 MB por resposta recursiva. Passou disso, o caminho é pedir a árvore sem recursive e descer uma subpasta por vez, usando o sha de cada entrada tree.
Um detalhe da documentação: qualquer valor em recursive liga a recursão, inclusive 0 e false. Para desligar, omita o parâmetro.
Como ver só os arquivos de uma pasta?
Filtre a mesma árvore pelo prefixo do caminho com --jq. Assim você também vê o tamanho de cada arquivo antes de abrir:
gh api "repos/verbeux-ai/code/git/trees/main?recursive=1" \
--jq '.tree[] | select(.type=="blob" and (.path|startswith("src/commands/add-dir/"))) | "\(.size)\t\(.path)"'
4825 src/commands/add-dir/add-dir.tsx
260 src/commands/add-dir/index.ts
3207 src/commands/add-dir/validation.ts
Para uma pasta só, o endpoint contents também lista, sem recursão:
gh api repos/verbeux-ai/code/contents/src/commands/add-dir --jq '.[] | "\(.type)\t\(.name)"'
A diferença é o teto: a documentação diz que o contents lista no máximo 1.000 arquivos por diretório e manda usar a API de árvores acima disso. Para achar arquivo pelo nome em qualquer lugar do repositório, a árvore recursiva é o caminho mais curto.
Este foi o passo que usamos para escrever o tutorial do /add-dir: a árvore mostrou os três arquivos do comando e, filtrando por outros prefixos, os arquivos de permissão e de configuração que ele toca.
Como ler o conteúdo de um arquivo pelo terminal?
Peça o arquivo ao endpoint contents com o header do formato cru. Sai o texto do arquivo, sem JSON e sem base64:
gh api repos/verbeux-ai/code/contents/src/commands/add-dir/index.ts \
-H "Accept: application/vnd.github.raw"
import type { Command } from '../../commands.js'
const addDir = {
type: 'local-jsx',
name: 'add-dir',
description: 'Add a new working directory',
argumentHint: '<path>',
load: () => import('./add-dir.js'),
} satisfies Command
Para achar uma linha num arquivo grande, mande a saída para o grep -n, que já devolve o número da linha:
gh api repos/verbeux-ai/code/contents/src/commands/add-dir/add-dir.tsx \
-H "Accept: application/vnd.github.raw" | grep -n "import"
Armadilha: --jq não funciona com o formato cru
O --jq espera JSON. Com o header raw, a resposta é texto, e o gh falha com esta mensagem:
invalid character 'i' looking for beginning of value
Se você quer filtrar sem pipe (útil quando o ambiente bloqueia |, como o sandbox de alguns agentes), tire o header e decodifique o base64 dentro do próprio jq:
gh api repos/verbeux-ai/code/contents/src/commands/add-dir/add-dir.tsx \
--jq '.content | @base64d | split("\n") | to_entries[] | select(.value|test("import")) | "\(.key+1): \(.value)"'
Isso só funciona em arquivo de até 1 MB. Acima disso o campo content vem vazio, como mostra a tabela abaixo.
Qual o limite de tamanho para ler arquivo pela API do GitHub?
Até 1 MB tudo funciona. De 1 a 100 MB, só o formato cru entrega o conteúdo. Acima de 100 MB, o endpoint não serve. Os números são da documentação oficial do endpoint de conteúdo e do de árvores:
| Situação | O que acontece | O que fazer |
|---|---|---|
| Arquivo de até 1 MB | Todos os formatos funcionam | Raw ou --jq com @base64d |
| Arquivo de 1 a 100 MB | content vem vazio e encoding vem "none" | Usar Accept: application/vnd.github.raw |
| Arquivo acima de 100 MB | Endpoint não suportado | Clonar ou baixar o release |
| Diretório com mais de 1.000 arquivos | contents corta a lista | Usar git/trees |
| Árvore recursiva acima de 100.000 entradas ou 7 MB | truncated: true | Árvore sem recursive, uma subpasta por vez |
No verbeux-ai/code, o maior arquivo tem 265.586 bytes, então tudo cabe na primeira linha da tabela.
Como ler o arquivo de uma versão específica?
Acrescente ?ref= com a tag, o branch ou o hash do commit. É o que garante que o tutorial descreve a versão que o leitor instalou, e não o que mudou no main depois:
gh api repos/verbeux-ai/code/releases/latest --jq .tag_name
gh api "repos/verbeux-ai/code/contents/package.json?ref=v0.15.38" \
-H "Accept: application/vnd.github.raw" | grep -m1 '"version"'
v0.15.38
"version": "0.15.38",
A árvore aceita o mesmo: troque main pela tag em git/trees/v0.15.38?recursive=1. E para saber quando um arquivo mudou pela última vez, o endpoint de commits filtra por caminho:
gh api "repos/verbeux-ai/code/commits?path=src/commands/add-dir/add-dir.tsx&per_page=3" \
--jq '.[] | "\(.sha[0:7]) \(.commit.author.date[0:10])"'
Por que não usar gh search code para achar o arquivo?
Porque a busca de código tem regras de indexação que a árvore não tem, e às vezes volta vazia sem erro. No mesmo dia, a busca por um termo que existe no código voltou vazia no verbeux-ai/code e devolveu resultados no openai/codex:
gh search code "addDir" --repo verbeux-ai/code --limit 3
gh search code "useState" --repo openai/codex --limit 2 --json path --jq '.[].path'
A documentação do GitHub lista as restrições: só o branch padrão é indexado, só arquivos menores que 384 KB, só repositórios com atividade no último ano, e fork só entra se tiver mais estrelas que o original. Não sabemos qual delas pegou o nosso repositório. O ponto prático é que busca vazia não prova que o termo não existe. A árvore recursiva lista tudo, sem índice no meio.
Dá para um agente de programação fazer isso sozinho?
Dá, e é assim que os nossos tutoriais saem. O agente roda a árvore, escolhe os arquivos pelo caminho e pelo tamanho, lê cada um cru e cita o arquivo e a versão no texto. Num tutorial típico isso são de cinco a dez arquivos lidos inteiros, alguns com centenas de linhas. É aí que o custo de leitura pesa: na Verboo Code os tokens são ilimitados, então ler o arquivo inteiro para conferir uma flag custa o mesmo que ler só o trecho que você achou que bastava.



