# CI에서 명세 린터로 명세를 린트하기

Canonical: https://specscore.md/ko/articles/lint-specs-in-ci/

마지막 업데이트: 2026년 11월 4일

명세 린터는 명세의 구조적 실수를 검사하고, 실수를 찾으면 실패 코드로 끝나는 프로그램입니다. [지속적 통합](https://specscore.md/ko/validators/)(CI, continuous integration)은 제안된 변경마다 도는 자동 검사입니다. 지속적 통합과 지속적 전달(CI/CD, continuous integration and continuous delivery)은 그 검사를 실행하고, 통과한 변경을 릴리스할 수 있는 상태로 유지하는 파이프라인입니다. [명세 주도 개발](https://specscore.md/ko/spec-driven-development/)(SDD, spec-driven development)은 코드보다 먼저 명세를 쓰고, 명세를 진실의 원천으로 다루는 방식입니다. 제품 요구사항 문서(PRD, product requirements document)는 문제와 범위를 적는 산문입니다. [SpecScore](https://specscore.md/)에서 요구사항(REQ)은 기능 안의 이름이 있는 규칙이고, 인수 기준(AC, acceptance criterion)은 그 규칙 하나 이상을 가리키는 선택적 추상 조건입니다. 그 검사는 [명령줄 인터페이스](https://specscore.md/ko/cli/)(CLI, command-line interface) 명령 `specscore spec lint`이며, CLI는 [specscore/specscore-cli](https://github.com/specscore/specscore-cli)([Apache-2.0](https://github.com/specscore/specscore-cli/blob/main/LICENSE))에 있습니다. [EARS](https://specscore.md/ko/articles/ears-requirements/)(Easy Approach to Requirements Syntax)는 요구사항의 문장 패턴입니다. 이 린터는 제목, 필수 절, 참조를 검사합니다. 영어의 잘잘못은 채점하지 않습니다.

## 명세를 린트한다는 것

명세를 린트하는 것은 코드를 린트하는 것과 같은 종류의 검사입니다. 결정적인 프로그램이 파일을 읽고 규칙 위반을 보고합니다. 제품이 좋은 생각인지는 정하지 않고, 요구사항을 더 나은 산문으로 다시 쓰지도 않습니다. [검증기 페이지](https://specscore.md/ko/validators/)는 그 구조 검사와 AI를 쓰는 수동 검토를 구분합니다. `specscore spec lint`가 구조 검사입니다.

명령의 설명은 [internal/cli/spec.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/internal/cli/spec.go)에 있으며, CLI 태그 v0.55.1과 이 저장소의 워크플로가 설치하는 v0.39.1 태그에 있습니다. 명세 트리를 구조적 관례 위반에 대해 검증한다고 적혀 있습니다. 깨끗한 실행은 `0 violations found`를 출력하고 종료 코드 0입니다. 위반을 찾은 실행은 발견마다 한 줄을 출력하고 종료 코드 1입니다. 그 종료 코드가 CI 작업을 실패하게 합니다. 잘못된 인자는 종료 코드 2입니다. `specscore.yaml`이 없으면 종료 코드 3이고, 메시지는 `specscore init`을 실행하라고 알려 줍니다.

## 명세 린터가 검사하는 것

규칙은 CLI의 것이며, 별도의 클라우드 서비스가 아닙니다. 생성된 목록 [docs/lint-rules.md](https://github.com/specscore/specscore-cli/blob/v0.55.1/docs/lint-rules.md)는 태그 v0.55.1에서 규칙 183개를 나열합니다. 이 웹사이트의 워크플로는 더 오래된 릴리스인 v0.39.1을 설치하므로, 더 나중 태그에만 있는 규칙은 그 작업이 실행하는 것이 아닙니다. 이 절에서 이름을 든 규칙은 두 태그에 모두 있습니다. 기본 `--severity`는 `error`입니다. 경고가 출력되는 것은 `--severity warning` 또는 `info`를 넘길 때뿐이며, 기본 명령은 경고로 실패하지 않습니다. 목록은 `dogfood-version-bump`를 경고로 표시하므로, 워크플로 핀이 바이너리보다 뒤처져 있어도 기본 명령은 실패하지 않습니다.

### 필수 파일과 절

규칙 `readme-exists`([readme_exists.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/readme_exists.go))는 명세의 모든 디렉터리에 `README.md`를 요구합니다. 규칙 `oq-section`([oq_section.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/oq_section.go))는 기능 README에 `## Open Questions` 절이 있을 것을 요구합니다. 예전 제목 `## Outstanding Questions`는 별도의 발견이며, `--fix`는 그 제목을 그 자리에서 다시 씁니다. 아래 예시의 메시지 “Open Questions section not found”는, 그 절을 제거한 기능 README에서 나온 발견입니다.

### 인덱스 행과 자식 디렉터리

규칙 `index-entries`([index_entries.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/index_entries.go))는 기능 인덱스를 디스크의 자식 디렉터리와 맞춥니다. 목록에 없는 자식은 위반이고, 링크가 존재하지 않는 자식을 가리키는 행도 위반입니다. `--fix`는 실체 없는 행을 지우고, 빠진 행을 넣을 수 있습니다. 이것은 디렉터리와 인덱스의 정합성입니다. 산문 안의 모든 URL을 따라가는 것이 아닙니다.

### 인수 기준 제목의 형태

규칙 `ac-heading-format`([ac_heading.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/ac_heading.go))는 제목이 `# Feature:`인 기능 README에 적용됩니다. 인수 기준 제목처럼 보이는 줄은 콜론 뒤에 공백이 하나이고 id가 kebab-case인, 정확히 `### AC: <id>`여야 합니다. `### AC: <id> (verifies ...)` 형태의 제목도 받아들입니다. `--fix`가 고치는 것은 공백뿐입니다. 대문자나 밑줄이 있는 id는 보고되고 사람에게 남습니다. 이 규칙은 `**Requirements:**` 줄을 요구하지 않고, “graceful”이나 “fast” 같은 단어에 점수를 매기지 않으며, 산문에 Given, When, Then이 있어도 경고하지 않습니다. 기준 자체를 쓰는 법은 [AI 에이전트가 검증할 수 있는 인수 기준을 쓰는 법](https://specscore.md/ko/articles/acceptance-criteria/)에 있습니다.

### 그 식별자에 대한 계획의 참조

출처 기능을 이름 붙인 계획에서 [plan_rules.go](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/plan_rules.go)는 그 기능 README의 `### AC:` 제목을 읽습니다. 규칙 `P-002`는 작업의 `**Verifies:**` 값이 그 제목 중 하나에 대한 `<feature-slug>#ac:<ac-slug>`로 풀리지 않는 것, 빈 `**Verifies:**` 줄, 출처 줄이 없거나 알아보지 못하는 것, 또는 출처 기능이 기능 README로 풀리지 않는 것을 보고합니다. 규칙 `P-001`는 어떤 작업도 다루지 않고 `## Deferred AC Coverage` 아래에 올라 있지 않은 제목을 보고합니다. 아이디어를 출처로 하는 계획(`**Source:** idea:<slug>`)과 `**Source:** none`인 계획은 면제되고, 종결된 처분 상태의 계획도 면제됩니다. `P-002`의 목록 한 줄은 “valid dependency references”라고 합니다. 그 파일의 검사기는 방금 설명한 AC 참조 검사입니다.

### 통과한 린트가 아닌 것

같은 명령은 요구사항이 적힌 문제를 푸는지, 이름이 말이 되는지, 두 기능이 의미상 서로 모순되는지를 정하지 않습니다. 검증기 페이지는 그것들을 CLI 린터 밖으로 둡니다. 시나리오 단계 키워드도 검사하지 않습니다. `specscore rehearse`가 시나리오 파일을 실행합니다. 이 저장소의 워크플로는 `specscore spec lint`를 실행하고 rehearse를 호출하지 않습니다. 목록은 또 다른 갈래를 이름 붙입니다. 아이디어, 결정, 엔티티, 속성, 교훈, 이슈, 그리고 나머지 계획 규칙입니다. 각 규칙은 자기가 맡은 파일에 적용됩니다. 목록이 그 명단입니다. 이 페이지는 183개 설명을 모두 되풀이하지 않습니다.

## CI에서 specscore spec lint 실행하기

명령은 작업 디렉터리에서 위로 `specscore.yaml`을 찾습니다. 그 파일이 없으면 종료 코드 3이고 `specscore init`을 이름 붙입니다. 따라서 CI 작업은 체크아웃에 설정 파일이 있어야 합니다. [scripts/install.sh](https://github.com/specscore/specscore-cli/blob/v0.55.1/scripts/install.sh)는 `SPECSCORE_VERSION`을 읽고, 변수가 설정되지 않았으면 `latest`를 씁니다. 실행마다 같은 규칙이 필요하면 태그를 고정하십시오.

이 저장소의 검사는 [dogfood.yml](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)입니다. `SPECSCORE_VERSION`을 `v0.39.1`로 두고 CLI를 설치한 다음, 추가 플래그 없이 `specscore spec lint`를 pull request와 main으로의 push에서 실행합니다. 그 프로세스가 0이 아닌 값으로 끝나면 GitHub Actions는 그 단계를 실패로 둡니다. 아래 발췌는 그 설치와 린트 단계를 남깁니다. 파일은 또한 `permissions: contents: read`, 동시성 그룹, 핀이 `latest`가 아닌 이유에 대한 주석을 설정합니다.

### dogfood.yml의 설치와 린트 단계

```yaml
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
```

### 실패 보고(specscore 0.55.0, v0.39.1에서도 줄의 형태는 같음)

```text
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)
```

### 깨끗한 보고

```text
0 violations found
```

각 발견은 `file:line [severity] rule: message`입니다. 요약은 `N violations found`에 `(3 errors)` 같은 괄호 안 개수를 더한 것입니다. 종료 코드는 프로세스 상태이며, 보고의 한 줄이 아닙니다. 위의 세 줄은 Open Questions 절이 제거되고 인덱스가 빈 자식 디렉터리를 빠뜨린 기능에서 specscore 0.55.0으로 받은 것입니다. CLI 페이지가 보여 주는 것과 같은 보고입니다. `--format`은 `text`(기본값), `json` 또는 `yaml`을 받습니다. `--rules`와 `--ignore`는 규칙을 고르며 함께 쓸 수 없습니다. `--fix`는 고치는 기능이 있는 발견을 다시 쓰며, Outstanding Questions 제목도 포함합니다. dogfood 작업은 `--fix`를 넘기지 않습니다.

## CI에서 이 형식을 린트하지 않는 도구

이 CLI에서 요구사항 품질 검사는 위의 구조 검사입니다. 산문에 점수를 매기는 것이 아닙니다. 다른 명세 주도 도구가 공개하는 검사는 다릅니다. 아래 문단은 그 프로젝트 자신의 페이지가 말하는 것만 씁니다. [도구 정리](https://specscore.md/ko/spec-driven-development/tools/)는 같은 페이지를 2026년 10월 30일에 읽은 것으로 기록합니다. 예외는 2026년 9월 28일이라고 인쇄된 Spec Kit 문서 홈과, 2026년 8월 4일이라고 인쇄된 Kiro 기능 명세 페이지입니다.

[GitHub Spec Kit](https://github.github.io/spec-kit/)는 Markdown 산출물을 쓰는 에이전트 워크플로입니다. [에이전트형 SDD 참고](https://github.github.io/spec-kit/reference/agentic-sdd.html)는 `/speckit.analyze`를 명세, 계획, 작업 사이의 불일치 보고로 설명하며, 파일은 고치지 않습니다. 에이전트 안에서 실행합니다. 문서 홈은 CI Guard라는 것을 포함한 커뮤니티 확장도 이름 붙이며, 그것들은 준수 게이트를 더합니다. 그것은 SpecScore 기능 README를 린트하는 명령이 아닙니다.

[OpenSpec](https://github.com/Fission-AI/OpenSpec)는 구조 검사를 공개합니다. `openspec validate`는 [CLI 참고](https://openspec.dev/docs/cli)에 적혀 있으며, OpenSpec의 변경과 명세 구조를 검사하고, 검증이 실패하면 0이 아닌 값으로 끝납니다. 참고에는 CI 작업이 실행할 수 있는 셸 조각도 있습니다. 그 검사는 OpenSpec의 형태이며, `### AC:` 제목이나 SpecScore 인덱스가 아닙니다.

[Kiro 기능 명세 페이지](https://kiro.dev/docs/specs/feature-specs/)는 Analyze Requirements를 설계 전에 Kiro 안에서 하는 검사로 설명합니다. 찾는 것은 불일치, 모호함, 서로 충돌하는 제약, 빈틈입니다. `dogfood.yml`의 명령이 아닙니다. Kiro가 쓰는 문장 패턴은 [EARS 요구사항 구문](https://specscore.md/ko/articles/ears-requirements/)에 있습니다.

[BMAD Method](https://github.com/bmad-code-org/BMAD-METHOD) README는 그 방법의 산출물과 에이전트 워크플로를 설명합니다. CI에서 고정된 명세 스키마를 린트하는 명령은 적지 않습니다. [Task Master](https://github.com/eyaltoledano/claude-task-master) README는 `task-master parse-prd`로 PRD를 작업으로 파싱하는 것을 설명합니다. 그 PRD의 린터는 설명하지 않습니다. PRD는 여전히 SpecScore 기능의 입력이 될 수 있습니다. 그때 기능 파일을 검사하는 것이 `specscore spec lint`입니다.

## 자주 묻는 질문

### 명세 린터란 무엇입니까?

명세 린터는 명세 파일을 읽고 구조적 위반을 보고합니다. `specscore spec lint`는 SpecScore 트리에 대한 그 명령입니다. 고른 심각도에서 아무것도 찾지 못하면 0으로 끝나고, 위반을 찾으면 1로 끝납니다.

### 명세 린터는 문장 표현으로 요구사항 품질을 판단합니까?

아닙니다. `ac-heading-format`가 검사하는 것은 `### AC:` 제목입니다. “graceful”이나 “fast” 같은 단어에 점수를 매기지 않고, 기준에 Given, When, Then이 있어도 경고하지 않습니다. 문장 표현은 글쓰기 작업입니다. 검증기 페이지는 그 결정적 린트와 AI를 쓰는 수동 검토를 구분합니다.

### CI에서 명세를 어떻게 린트합니까?

CLI를 `SPECSCORE_VERSION`이 릴리스 태그를 가리키게 두고 설치한 다음 `specscore spec lint`를 실행합니다. 체크아웃에는 `specscore.yaml`이 있어야 합니다. [dogfood.yml](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)는 동작하는 GitHub Actions 예입니다. v0.39.1을 고정합니다.

### 실패하는 실행은 무엇을 출력합니까?

발견마다 한 줄, `file:line [severity] rule: message`, 이어서 `3 violations found (3 errors)` 같은 요약입니다. 프로세스는 1로 끝납니다. 깨끗한 트리는 `0 violations found`를 출력하고 0으로 끝납니다.

### 다른 명세 주도 도구는 CI/CD에서 명세를 검증합니까?

OpenSpec의 `openspec validate`는 CI 작업을 실패하게 할 수 있고, OpenSpec 자신의 변경 구조를 검사합니다. Spec Kit의 `/speckit.analyze`는 에이전트 세션에서 실행됩니다. Kiro의 Analyze Requirements는 Kiro 안에서 실행됩니다. BMAD Method와 Task Master의 README는 CI용 형식 린터를 적지 않습니다. SpecScore의 dogfood 워크플로는 SpecScore 트리에서 `specscore spec lint`를 실행합니다.

## 출처

CLI 동작은 2026년 11월 4일에 specscore-cli 태그 v0.55.1과 v0.39.1을 대조해 확인했습니다. 다른 프로젝트의 페이지는 아래에 링크된 것입니다. 도구 정리는 페이지가 자신의 날짜를 인쇄한 경우를 제외하고, 2026년 10월 30일에 읽은 것으로 기록합니다.

- [specscore/specscore-cli](https://github.com/specscore/specscore-cli)
- [specscore-cli — Apache-2.0 라이선스](https://github.com/specscore/specscore-cli/blob/main/LICENSE)
- [specscore/specscore](https://github.com/specscore/specscore)
- [specscore-cli v0.55.1 — lint 규칙 목록 (183개)](https://github.com/specscore/specscore-cli/blob/v0.55.1/docs/lint-rules.md)
- [specscore/specscore — dogfood.yml (CLI v0.39.1)](https://github.com/specscore/specscore/blob/main/.github/workflows/dogfood.yml)
- [specscore-cli — install.sh (SPECSCORE_VERSION)](https://github.com/specscore/specscore-cli/blob/v0.55.1/scripts/install.sh)
- [specscore-cli v0.55.1 — readme-exists](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/readme_exists.go)
- [specscore-cli v0.55.1 — oq-section](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/oq_section.go)
- [specscore-cli v0.55.1 — index-entries](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/index_entries.go)
- [specscore-cli v0.55.1 — ac-heading-format](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/ac_heading.go)
- [specscore-cli v0.55.1 — 계획 규칙 P-001과 P-002](https://github.com/specscore/specscore-cli/blob/v0.55.1/pkg/lint/plan_rules.go)
- [SpecScore가 검증하는 것](https://specscore.md/ko/validators/)
- [AI 에이전트가 검증할 수 있는 인수 기준을 쓰는 법](https://specscore.md/ko/articles/acceptance-criteria/)
- [EARS 요구사항 구문을 예와 함께 설명](https://specscore.md/ko/articles/ears-requirements/)
- [GitHub Spec Kit 문서 (페이지 날짜 2026년 9월 28일)](https://github.github.io/spec-kit/)
- [GitHub Spec Kit — 에이전트형 SDD 참고 (/speckit.analyze)](https://github.github.io/spec-kit/reference/agentic-sdd.html)
- [OpenSpec CLI 참고 — openspec validate](https://openspec.dev/docs/cli)
- [Fission-AI/OpenSpec](https://github.com/Fission-AI/OpenSpec)
- [Kiro — 기능 명세 (2026년 8월 4일 업데이트)](https://kiro.dev/docs/specs/feature-specs/)
- [bmad-code-org/BMAD-METHOD](https://github.com/bmad-code-org/BMAD-METHOD)
- [eyaltoledano/claude-task-master](https://github.com/eyaltoledano/claude-task-master)
- [명세 주도 개발 도구](https://specscore.md/ko/spec-driven-development/tools/)

## 관련

- [Claude Code와 Cursor로 하는 명세 주도 개발](https://specscore.md/ko/articles/claude-code-specs/)
- [AI 코딩을 위한 Markdown PRD 템플릿](https://specscore.md/ko/articles/feature-spec-template/)
- [AI 에이전트가 검증할 수 있는 인수 기준을 쓰는 법](https://specscore.md/ko/articles/acceptance-criteria/)
- [EARS 요구사항 구문을 예와 함께 설명](https://specscore.md/ko/articles/ears-requirements/)
- [SpecScore가 검증하는 것](https://specscore.md/ko/validators/)
- [CLI](https://specscore.md/ko/cli/)
- [CLI 설치](https://specscore.md/ko/cli/install/)
- [명세 주도 개발](https://specscore.md/ko/spec-driven-development/)
- [명세 주도 개발 도구](https://specscore.md/ko/spec-driven-development/tools/)
- [기능 명세](https://specscore.md/feature-specification)
- [인수 기준 명세](https://specscore.md/acceptance-criteria-specification)
