Artigos

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.

Passos de instalação e lint de dogfood.yml
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
Relatório de falha (specscore 0.55.0, a mesma forma de linha em v0.39.1)
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)
Relatório limpo
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.

Linte a especificação na CI.

Encontrou um erro na tradução ou tem uma ideia para melhorar esta página?