Lintar especificações na CI com um linter de especificações
Um linter de especificações é um programa que verifica uma especificação em busca de erros de estrutura e termina com um código de falha quando os encontra. A integração contínua (CI, continuous integration) é uma verificação automática em cada mudança proposta. A integração contínua e a entrega contínua (CI/CD, continuous integration and continuous delivery) é o pipeline que executa essa verificação e mantém publicável uma mudança que passa. O desenvolvimento guiado por especificação (SDD, spec-driven development) é a prática de escrever a especificação antes do código e tratá-la como a fonte da verdade. Um documento de requisitos de produto (PRD, product requirements document) é a prosa que enuncia o problema e o escopo. No SpecScore, um requisito (REQ) é uma regra nomeada dentro de uma funcionalidade, e um critério de aceitação (AC, acceptance criterion) é uma condição abstrata opcional que aponta para uma ou mais dessas regras. A verificação é um comando da interface de linha de comando (CLI, command-line interface), specscore spec lint, da CLI em specscore/specscore-cli (Apache-2.0). Easy Approach to Requirements Syntax (EARS) é um padrão de frase para um requisito. Este linter verifica cabeçalhos, seções obrigatórias e referências. Não avalia o inglês.
Atualizado em 4 de novembro de 2026
O que significa lintar uma especificação
Lintar uma especificação é o mesmo tipo de verificação que lintar código. Um programa determinístico lê os arquivos e informa violações de regras. Não decide se o produto é uma boa ideia, e não reescreve o requisito com prosa melhor. A página de validadores separa essa verificação estrutural de uma revisão manual com IA. specscore spec lint é a verificação estrutural.
A descrição do comando, em internal/cli/spec.go na tag v0.55.1 da CLI e na tag v0.39.1 que o fluxo deste repositório instala, diz que valida a árvore de especificações contra violações de convenções estruturais. Uma execução limpa imprime 0 violations found e sai com 0. Uma execução que encontra violações imprime uma linha por achado e sai com 1. Esse código de saída é o que faz um job de CI falhar. Argumentos inválidos saem com 2. Se falta specscore.yaml, sai com 3 e a mensagem manda executar specscore init.
O que o linter de especificações verifica
As regras são da CLI, não de um serviço separado na nuvem. O catálogo gerado docs/lint-rules.md na tag v0.55.1 lista 183 regras. O fluxo deste site instala v0.39.1, uma versão anterior, então uma regra que só existe numa tag posterior não é o que esse job executa. As regras nomeadas nesta seção estão nas duas tags. O --severity padrão é error. Um aviso só é impresso se você passa --severity warning ou info, e o comando padrão não falha por um aviso. O catálogo marca dogfood-version-bump como aviso, então o comando padrão não falha quando o pin do fluxo está atrás do binário.
Arquivos e seções obrigatórios
A regra readme-exists (readme_exists.go) exige um README.md em cada diretório da especificação. A regra oq-section (oq_section.go) exige que o README de uma funcionalidade contenha uma seção ## Open Questions. Um cabeçalho herdado ## Outstanding Questions é um achado à parte, e --fix reescreve esse cabeçalho no lugar. A mensagem do exemplo abaixo, “Open Questions section not found”, é o achado de um README de funcionalidade do qual a seção foi removida.
Linhas do índice e diretórios filhos
A regra index-entries (index_entries.go) confere um índice de funcionalidades contra os diretórios filhos no disco. Um filho que não está na lista é uma violação, e uma linha cujo link aponta para um filho que não está lá também é uma violação. --fix pode apagar a linha fantasma e inserir a que falta. Isso é integridade de diretórios e de índice. Não é um rastreamento de cada URL da prosa.
Forma do cabeçalho de critérios de aceitação
A regra ac-heading-format (ac_heading.go) se aplica ao README de uma funcionalidade, um arquivo cujo título é # Feature:. Uma linha que parece um cabeçalho de critério de aceitação deve ser exatamente ### AC: <id> com um espaço depois dos dois pontos e um id em kebab-case. Também se aceita um cabeçalho da forma ### AC: <id> (verifies ...). --fix só repara o espaçamento. Um id com maiúsculas ou sublinhados é informado e deixado para uma pessoa. A regra não exige a linha **Requirements:**, não pontua palavras como “graceful” ou “fast”, e não avisa quando a prosa contém Given, When ou Then. Como escrever o próprio critério está em como escrever critérios de aceitação.
Referências do plano a esses identificadores
Num plano que nomeia uma funcionalidade de origem, plan_rules.go lê os cabeçalhos ### AC: do README dessa funcionalidade. A regra P-002 informa um valor **Verifies:** de uma tarefa que não resolve para <feature-slug>#ac:<ac-slug> de um desses cabeçalhos, uma linha **Verifies:** vazia, uma linha de origem ausente ou não reconhecida, ou uma funcionalidade de origem que não resolve para um README de funcionalidade. A regra P-001 informa um cabeçalho que nenhuma tarefa cobre e que não está listado sob ## Deferred AC Coverage. Ficam isentos os planos com origem numa ideia (**Source:** idea:<slug>) e os planos com **Source:** none, e também um plano em status de disposição terminal. O texto de uma linha do catálogo para P-002 diz “valid dependency references”; o checker desse arquivo é a verificação de referências a AC que acaba de ser descrita.
O que um lint que passa não é
O mesmo comando não decide se um requisito resolve o problema enunciado, se um nome faz sentido, ou se duas funcionalidades se contradizem no significado. A página de validadores lista isso fora do linter da CLI. Também não verifica as palavras-chave dos passos de um cenário. specscore rehearse executa os arquivos de cenário. O fluxo deste repositório executa specscore spec lint e não chama o rehearse. O catálogo nomeia mais famílias — ideias, decisões, entidades, propriedades, lições, issues e o resto das regras de planos — e cada regra se aplica aos arquivos que lhe correspondem. O catálogo é a lista. Esta página não repete as 183 descrições.
Executar specscore spec lint na CI
O comando procura para cima, a partir do diretório de trabalho, um specscore.yaml. Sem esse arquivo sai com 3 e nomeia specscore init. Um job de CI precisa portanto do arquivo de configuração no checkout. scripts/install.sh lê SPECSCORE_VERSION e, se a variável não está definida, usa latest. Fixe uma tag se quiser as mesmas regras em cada execução.
A verificação deste repositório é dogfood.yml. Instala a CLI com SPECSCORE_VERSION em v0.39.1 e depois executa specscore spec lint sem flags extras, em pull requests e em pushes para main. O GitHub Actions marca o passo como falho quando o processo sai com código diferente de zero. O trecho abaixo conserva esses passos de instalação e de lint. O arquivo também define permissions: contents: read, um grupo de concorrência e um comentário sobre por que o pin não é latest.
name: Dogfood lint
on:
push:
branches: [main]
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Install specscore CLI (pinned)
env:
SPECSCORE_VERSION: v0.39.1
run: |
curl -fsSL https://specscore.md/install/get-cli | \
SPECSCORE_INSTALL_DIR="$HOME/.local/bin" sh
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
specscore --version
- name: Lint spec tree
run: specscore spec lint
features/apply-discount/README.md:0 [error] oq-section: Open Questions section not found
features/apply-discount/README.md:0 [error] index-entries: Child directory not listed in index: refunds
features/apply-discount/refunds:0 [error] readme-exists: README.md not found
3 violations found (3 errors)
0 violations found
Cada achado é file:line [severity] rule: message. O resumo é N violations found mais uma contagem entre parênteses, como (3 errors). O código de saída é o estado do processo, não uma linha do relatório. As três linhas acima foram capturadas com specscore 0.55.0 numa funcionalidade da qual se removeu a seção Open Questions e cujo índice omitia um diretório filho vazio. São o mesmo relatório que a página da CLI mostra. --format aceita text (o padrão), json ou yaml. --rules e --ignore selecionam regras e não podem ser combinados. --fix reescreve os achados que têm um corretor, inclusive o cabeçalho Outstanding Questions. O job dogfood não passa --fix.
Ferramentas que não lintam este formato na CI
Uma verificação de qualidade de requisitos, nesta CLI, é a verificação estrutural acima. Não é uma nota da prosa. Outras ferramentas de desenvolvimento guiado por especificação publicam verificações diferentes. Os parágrafos abaixo usam só o que dizem as páginas desses projetos. O guia de ferramentas registra as mesmas páginas como lidas em 30 de outubro de 2026, salvo a página inicial da documentação do Spec Kit, que imprime 28 de setembro de 2026, e a página de especificações de funcionalidade do Kiro, que imprime 4 de agosto de 2026.
GitHub Spec Kit é um fluxo de agente que escreve artefatos Markdown. A referência de SDD agêntico descreve /speckit.analyze como um relatório de inconsistências entre a especificação, o plano e as tarefas, sem editar os arquivos. Executa-se no agente. A página inicial da documentação também nomeia extensões da comunidade, inclusive uma chamada CI Guard, que acrescentam portões de conformidade. Isso não é um comando que linta um README de funcionalidade do SpecScore.
OpenSpec publica sim uma verificação estrutural. openspec validate, documentado na referência da CLI, verifica a estrutura de mudança e de especificação do OpenSpec, sai com código diferente de zero quando a validação falha, e a referência inclui um trecho de shell que um job de CI pode executar. Essa verificação é a forma do OpenSpec, não os cabeçalhos ### AC: nem um índice do SpecScore.
A página de especificações de funcionalidade do Kiro descreve Analyze Requirements como uma verificação dentro do Kiro, antes do design, que procura inconsistências, ambiguidade, restrições em conflito e lacunas. Não é o comando de dogfood.yml. Os padrões de frase que o Kiro escreve estão na sintaxe de requisitos EARS.
O README do BMAD Method descreve os artefatos do método e os fluxos de agentes. Não documenta um comando que linta um esquema fixo de especificação na CI. O README do Task Master descreve converter um PRD em tarefas com task-master parse-prd. Não descreve um linter para esse PRD. Um PRD ainda pode ser a entrada de uma funcionalidade SpecScore, e specscore spec lint é o que então verifica o arquivo da funcionalidade.
Perguntas frequentes
O que é um linter de especificações?
Um linter de especificações lê arquivos de especificação e informa violações estruturais. specscore spec lint é esse comando para uma árvore SpecScore. Sai com 0 quando não encontra nada na severidade escolhida, e com 1 quando encontra violações.
O linter julga a qualidade dos requisitos na redação?
Não. ac-heading-format verifica o cabeçalho ### AC:. Não pontua palavras como “graceful” ou “fast”, e não avisa quando um critério contém Given, When ou Then. A redação é uma tarefa de escrita. A página de validadores separa esse lint determinístico da revisão manual com IA.
Como linto especificações na CI?
Instale a CLI com SPECSCORE_VERSION fixada numa tag de release e execute specscore spec lint. O checkout precisa de um specscore.yaml. dogfood.yml é um exemplo que funciona no GitHub Actions. Fixa v0.39.1.
O que uma execução que falha imprime?
Uma linha por achado, file:line [severity] rule: message, e depois um resumo como 3 violations found (3 errors). O processo sai com 1. Uma árvore limpa imprime 0 violations found e sai com 0.
Outras ferramentas validam especificações em CI/CD?
O openspec validate do OpenSpec pode fazer um job de CI falhar, e verifica a estrutura de mudança própria do OpenSpec. O /speckit.analyze do Spec Kit executa-se na sessão do agente. O Analyze Requirements do Kiro executa-se dentro do Kiro. Os README do BMAD Method e do Task Master não documentam um linter de formato para a CI. O fluxo dogfood do SpecScore executa specscore spec lint sobre a árvore SpecScore.
Fontes
Comportamento da CLI verificado em 4 de novembro de 2026 contra as tags v0.55.1 e v0.39.1 do specscore-cli. As páginas dos concorrentes são as ligadas abaixo; o guia de ferramentas as registra como lidas em 30 de outubro de 2026, salvo onde a página imprime a própria data.
- specscore/specscore-cli
- specscore-cli — licença Apache-2.0
- specscore/specscore
- specscore-cli v0.55.1 — catálogo de regras de lint (183 regras)
- specscore/specscore — dogfood.yml (CLI v0.39.1)
- specscore-cli — install.sh (SPECSCORE_VERSION)
- specscore-cli v0.55.1 — readme-exists
- specscore-cli v0.55.1 — oq-section
- specscore-cli v0.55.1 — index-entries
- specscore-cli v0.55.1 — ac-heading-format
- specscore-cli v0.55.1 — regras de plano P-001 e P-002
- O que o SpecScore valida
- Como escrever critérios de aceitação que um agente de IA possa verificar
- Sintaxe de requisitos EARS explicada, com exemplos
- Documentação do GitHub Spec Kit (data da página 28 de setembro de 2026)
- GitHub Spec Kit — referência de SDD agêntico (/speckit.analyze)
- Referência da CLI do OpenSpec — openspec validate
- Fission-AI/OpenSpec
- Kiro — especificações de funcionalidade (atualizado em 4 de agosto de 2026)
- bmad-code-org/BMAD-METHOD
- eyaltoledano/claude-task-master
- Ferramentas de desenvolvimento guiado por especificação
Relacionados
- Desenvolvimento baseado em especificações com Claude Code e Cursor
- Modelo de PRD em Markdown para programar com IA
- Como escrever critérios de aceitação que um agente de IA possa verificar
- Sintaxe de requisitos EARS explicada, com exemplos
- O que o SpecScore valida
- CLI
- Instalar a CLI
- Desenvolvimento guiado por especificação
- Ferramentas de desenvolvimento guiado por especificação
- Especificação de funcionalidade
- Especificação de critérios de aceitação