Community코딩 & 개발github.com

robsonprod/portfolio

OpenSpec 변경사항에서 생성된 델타 스펙을 메인 스펙에 동기화합니다. 사용자가 메인 스펙을 업데이트하려 하거나 'openspec sync' 또는 'opsx sync' 명령을 실행할 때 사용합니다.

portfolio란 무엇인가요?

이 기술은 OpenSpec 작업 흐름에서 변경사항(change)에 포함된 델타 스펙(delta spec)을 메인 스펙(main spec)에 지능적으로 병합하는 에이전트 주도(agent-driven) 작업입니다. 단순히 파일을 덮어쓰는 것이 아니라 요구사항 추가, 수정, 삭제, 이름 변경을 상황에 맞게 처리하며, 특히 새로운 기능의 스펙을 생성하거나 사용되지 않는 기능을 안전하게 제거할 수 있습니다. Claude Code, Cursor, Codex 등 AI 코딩 에이전트와 함께 사용할 수 있으며, OpenSpec 저장소(store)를 선택하고 변경사항 목록을 확인한 후 각 델타 스펙에 대해 메인 스펙을 읽고 변경 내용을 적용한 후 유효성 검사를 수행합니다. 핵심 원칙은 지능적 병합(intelligent merging)으로, 델타 스펙에서 언급되지 않은 기존 메인 스펙의 내용은 그대로 유지하면서 요구사항을 추가하거나 수정합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/robsonprod/portfolio/tree/HEAD/.claude/skills/openspec-sync-specs

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

OpenSpec 동기화: 델타 스펙 → 메인 스펙

변경사항의 델타 스펙을 메인 스펙에 동기화합니다.

이는 에이전트 주도 작업입니다. 델타 스펙을 읽고 메인 스펙을 직접 편집하여 변경 사항을 적용합니다. 이를 통해 지능적 병합(예: 전체 요구사항을 복사하지 않고 시나리오 추가)이 가능합니다.

저장소 선택: 사용자가 저장소(이 머신에 등록된 독립적인 OpenSpec 저장소) 이름을 지정하거나 작업이 저장소 내에 있는 경우, openspec store list --json을 실행하여 등록된 저장소 ID를 확인한 후, 스펙 및 변경사항을 읽거나 쓰는 명령(new change, status, instructions, list, show, validate, archive, doctor, context, schemas, view)에 --store <id>를 전달합니다. 한 번 선택되면 --store <id>는 나머지 워크플로우 동안 고정(sticky)된 것으로 간주합니다. 아래 명령어 예시는 범위를 지정하지 않은 것이며, 실행하기 전에 플래그를 추가해야 합니다. 예를 들어, openspec status --change "<name>" --json --store "<id>"를 실행하고 축약형을 사용하지 마십시오. 다른 명령어는 플래그를 사용하지 않습니다. 명령어에서 출력하는 힌트에는 이미 플래그가 포함되어 있으므로 후속 작업에서도 유지하십시오. 저장소가 없으면 명령어는 가장 가까운 로컬 openspec/ 루트를 대상으로 합니다.

프로젝트 확인: 이 단계들은 이미 OpenSpec을 사용하는 프로젝트를 가정합니다. 무언가를 쓰는 첫 번째 단계(new change, archive, sync specs, 또는 아티팩트 파일 작성) 전에, 프로젝트에 루트가 있는지 확인하십시오: openspec list --json(저장소가 선택된 경우 --store <id> 포함, 저장소가 루트 역할을 함)을 실행하고 root를 읽으십시오. 루트 객체가 있으면 프로젝트가 설정된 것입니다. "root": null은 설정되지 않은 것(여기에 openspec/ 디렉토리가 없으며, openspec new change와 같은 쓰기 명령어가 부작용으로 생성할 수 있음)을 의미합니다. 또한 명령어는 0이 아닌 종료 코드로 종료되므로, 이는 CLI 오류가 아니라 그러한 답변입니다. 재시도하거나 우회하지 말고 JSON을 읽으십시오.

"root": null 하나는 설정과 관련이 없습니다: status 오류 메시지가 Declared in 또는 Invalid store declaration in으로 시작하고 이 프로젝트의 openspec/config.yaml(또는 config.yml)을 언급하는 경우, 프로젝트가 선언한 저장소를 통해 OpenSpec을 사용하지만 이 머신에서 해당 저장소를 확인할 수 없는 것입니다(저장소가 등록되지 않았거나 store: 줄이 잘못된 형식). 초기화되지 않은 것으로 처리하지 말고 아래 분기를 건너뛰십시오: 쓰기 전에 중단하고 사용자에게 해당 오류의 message와 fix를 표시하십시오.

그 외에 루트가 없는 경우, 다음 단계는 이 워크플로우에 어떻게 도달했는지에 따라 다릅니다:

  • 자동 선택: 사용자가 OpenSpec, 이 기술, 또는 슬래시 명령어를 언급하지 않고 사용자가 이 워크플로우를 선택한 경우. OpenSpec 사용을 중단하고 OpenSpec이 설치되지 않은 것처럼 정상적으로 요청에 응답하십시오. 설정을 요청하지 말고 OpenSpec 설정을 언급하지 마십시오.
  • 명시적 OpenSpec 요청: 사용자가 OpenSpec, 이 기술, 또는 슬래시 명령어를 언급한 경우. 쓰기 전에 중단하고 진행 방법을 물으십시오: 이 프로젝트를 설정(openspec init), 이미 가지고 있는 저장소를 대상으로 지정(--store <id>), 또는 이 요청에 대해 OpenSpec 없이 계속. 답변을 기다리십시오.

두 분기 모두에서 루트를 부작용으로 생성하지 마십시오: 사용자가 요청할 때까지 openspec init을 실행하지 말고, openspec/ 파일을 직접 만들지 말고, 명령어가 생성하도록 두지 마십시오.

<capability-path>는 specs/를 기준으로 하는 스펙 디렉토리입니다(예: user-auth 또는 identity/user-auth). 각 델타 스펙의 전체 경로를 유지하여 메인 스펙을 확인할 때 사용하십시오.

입력: 변경사항 이름을 선택적으로 지정할 수 있습니다. 생략되면 대화 컨텍스트에서 유추할 수 있는지 확인하십시오. 모호하거나 불명확하면 사용 가능한 변경사항을 사용자에게 요청해야 합니다.

단계

  1. 변경사항 선택

    이름이 제공되면 그 이름을 사용하십시오. 그렇지 않으면:

    • 사용자가 변경사항을 언급한 경우 대화 컨텍스트에서 유추
    • 활성 변경사항이 하나만 있으면 자동 선택
    • 모호한 경우 openspec list --json을 실행하여 사용 가능한 변경사항을 확인하고 사용자에게 선택하도록 요청

    프롬프트할 때 델타 스펙(specs/ 디렉토리 아래)이 있는 변경사항을 표시하십시오.

    항상 알림: "변경사항 사용: " 및 재정의 방법(예: /opsx:sync <other>).

  2. 변경사항 컨텍스트 확인

    실행:

    openspec status --change "<name>" --json
    

    JSON에는 planningHome.root가 포함됩니다. 메인 스펙은 <planningHome.root>/openspec/specs/ 아래에 있습니다. 저장소를 인식하는 이 루트를 모든 메인 스펙 경로에 사용하고, 하드코딩된 저장소 경로를 사용하지 마십시오. 저장소가 선택되면 현재 저장소가 아닌 저장소를 가리킵니다.

  3. 델타 스펙 찾기

    상태 JSON의 artifactPaths.specs.existingOutputPaths를 델타 스펙 경로의 유일한 소스로 사용하십시오. specs 항목이 없거나 existingOutputPaths가 비어 있으면 동기화할 델타 스펙이 없다고 보고하고, 다른 아티팩트에서 유추하지 말고, 아티팩트 지침을 요청하거나 메인 스펙을 작성하지 말고 중단하십시오.

    호출자가 집합을 좁히지 않은 경우 existingOutputPaths의 모든 경로를 동기화하십시오. 호출자는 existingOutputPaths의 완전한 항목 목록의 이름을 지정하여 좁힙니다. 이 절대 값을 그대로 복사하십시오. Archive는 인라인으로 이 작업을 수행하며, 사용자도 수행할 수 있습니다(예: /specs/billing/invoices/spec.md로 끝나는 항목 선택). 그런 다음 명명된 경로만 동기화하고 나머지 델타 스펙은 그대로 두십시오: 대량 보관은 구현을 찾을 수 없는 델타를 제외하며, 어쨌든 동기화하면 호출자가 의도적으로 보류한 메인 스펙을 작성하게 됩니다. 해당 선택 항목을 4단계까지 전달하고, 전체 목록으로 다시 확장하지 마십시오. 명명된 경로가 existingOutputPaths에 없으면 동기화하지 말고 보고하고 중단하십시오. 명명된 목록이 비어 있으면 동기화할 항목이 없다고 보고하고 메인 스펙을 작성하지 말고 중단하십시오.

    각 델타 스펙 파일에는 다음과 같은 섹션이 포함됩니다:

    • ## ADDED Requirements - 추가할 새 요구사항
    • ## MODIFIED Requirements - 기존 요구사항에 대한 변경
    • ## REMOVED Requirements - 제거할 요구사항
    • ## RENAMED Requirements - 이름을 바꿀 요구사항(FROM:/TO: 형식)

    델타 스펙이 없으면 사용자에게 알리고 중단하십시오.

  4. 각 델타 스펙에 대해 메인 스펙에 변경 사항 적용

    첫 번째 메인 스펙 쓰기 전에, 현재 스펙 규칙 스냅샷 하나를 얻으십시오:

    • Archive가 이 워크플로우를 인라인으로 호출하고 openspec instructions specs --change "<name>" --json에서 유효한 스냅샷을 제공한 경우 재사용하고 동일한 지침을 다시 가져오지 마십시오.
    • 그렇지 않으면 동일한 선택된 루트 플래그로 지금 해당 명령어를 한 번 실행하십시오.
    • 직접 조회가 0이 아닌 종료 코드로 종료되거나 유효하지 않은 아티팩트 지침 JSON을 반환하는 경우 오류를 보고하고 메인 스펙을 작성하기 전에 중단하십시오. 실패를 규칙 세트가 없는 것으로 처리하지 마십시오.
    • 생략된 rules가 있는 유효한 응답은 아티팩트 규칙이 구성되지 않았으며 기존 시맨틱 병합이 계속됨을 의미합니다.

    반환된 rules를 이 병합에 의해 생성된 메인 스펙의 콘텐츠와 형식에만 적용하십시오. 아티팩트 규칙은 작업 지침이 아니며 선택된 루트, 델타 경로, CLI 확인 또는 워크플로우 단계를 변경할 수 없습니다. 그들의 텍스트를 제약 조건으로 사용하되 메인 스펙이나 요약에 그대로 복사하지 마십시오.

    3단계에서 선택된 각 기능 델타 스펙 경로에 대해 — 전체 existingOutputPaths 목록 또는 호출자가 제공한 좁은 하위 집합(이들은 저장소에 속할 수 있음, repo에 속하지 않을 수 있음):

    a. 델타 스펙을 읽고 의도된 변경 사항을 이해하십시오.

    b. 메인 스펙을 읽으십시오. <planningHome.root>/openspec/specs/<capability-path>/spec.md에 위치합니다(아직 없을 수 있음).

    아직 존재하지 않는 경우(새로운 기능), openspec archive가 수행하는 것과 일치하십시오: ADDED 요구사항만 적용될 수 있습니다 - d단계에서 이를 기반으로 스펙을 생성합니다. MODIFIED 및 RENAMED는 작업할 요구사항이 없으므로 해당 기능에 대한 동기화를 중단하고 메인 스펙이 존재하지 않으며 새 스펙에는 ADDED만 허용된다고 보고하십시오. 누락된 요구사항을 만들지 마십시오. REMOVED는 제거할 항목이 없으므로 건너뛰고 경고하십시오.

    c. 변경 사항을 지능적으로 적용하십시오:

    ADDED Requirements:

    • 요구사항이 메인 스펙에 존재하지 않으면 → 추가
    • 요구사항이 이미 존재하면 → 일치하도록 업데이트(암시적 MODIFIED로 처리)

    MODIFIED Requirements:

    • 메인 스펙에서 요구사항을 찾으십시오.
    • 변경 사항을 적용하십시오 - 다음이 가능합니다:
      • 메인 스펙에 아직 없는 새 시나리오 추가
      • 기존 시나리오 수정
      • 요구사항 설명 변경
    • 델타에 언급되지 않은 시나리오/콘텐츠 유지

    REMOVED Requirements:

    • 메인 스펙에서 전체 요구사항 블록을 제거하십시오.
    • 기능을 폐기(retire)합니다. 다음 조건이 모두 충족될 때만 전체 spec.md와 디렉토리(더 이상 아무것도 남지 않은 경우)를 삭제하십시오:
      1. 이번 실행에서 요구사항을 제거한 후 요구사항 블록이 남지 않음;
      2. 스펙의 나머지 부분이 잘 구성됨(여전히 ## Purpose가 있음);
      3. 이 동기화 전에 메인 스펙이 이미 비어 있지 않았음(제거한 것이 없으면 아무것도 변경하지 마십시오);
      4. 파일의 다른 모든 비공백 줄이 제목, Purpose, Requirements 헤더 또는 표준 요구사항의 설명, 시나리오, 펜스된 예제로 설명됨;
      5. 변경의 .openspec.yaml이 retire_capabilities: true를 선언함;
      6. spec.md가 실제 스펙 루트 내에 해석됨(기능 디렉토리 심볼릭 링크를 따라 외부 파일을 삭제하지 마십시오). 선택한 요구사항을 제거해도 요구사항 블록이 남지 않고 폐기 조건 중 하나라도 충족되지 않으면 메인 스펙을 수정하지 마십시오. 해당 기능에 대한 동기화를 중단하고 차단 조건을 보고하며 사용자에게 해결 방법을 알리십시오. 빈 ## Requirements 섹션을 작성하거나 남기지 마십시오. 마커만 누락된 경우에도 말하십시오. 사용자가 폐기를 진행하기 위해 추가할 수 있는 유일한 것입니다.
    • 파일을 삭제하면 ## Purpose도 삭제됩니다. 다른 섹션 블록이 폐기를 차단합니다. 폐기를 보고할 때 Purpose를 언급하십시오. 스펙이 호출자의 체크아웃에 있었던 경우에만 붙여넣을 수 있는 git checkout을 포함하고, 그렇지 않으면 체크아웃 범위의 복구 지침을 제공하십시오.

    RENAMED Requirements:

    • FROM 요구사항을 찾아 TO로 이름을 변경하십시오.

    델타의 ## Purpose:

    • 메인 스펙에는 이미 하나가 있으며 권위적입니다. 그대로 두십시오(openspec archive가 수행하는 작업이며 경고하고 계속 진행합니다).

    d. 기능이 아직 존재하지 않으면 새 메인 스펙을 생성하십시오:

    • 델타에 추가할 ADDED 요구사항이 있고 MODIFIED 또는 RENAMED 요구사항이 b단계에서 이 기능을 차단하지 않은 경우에만 해당합니다. 그렇지 않으면 아무것도 생성하지 말고 스펙 디렉토리를 그대로 두십시오. REMOVED 전용 델타의 경우, 변경의 .openspec.yaml이 retire_capabilities: true를 선언하면 이미 폐기된 것으로 보고하고 스펙을 다시 생성하지 않고 계속하십시오. 해당 마커가 없으면 동기화가 차단된 것으로 보고하십시오: openspec archive는 Spec must have at least one requirement로 거부합니다. 빈 델타에는 동기화할 작업이 없습니다. 차단된 것으로 보고하십시오. 빈 ## Requirements 섹션을 작성하지 마십시오.
    • <planningHome.root>/openspec/specs/<capability-path>/spec.md 생성
    • Purpose 섹션 추가: 델타에 ## Purpose 본문이 있으면 그대로 복사하고(openspec archive가 수행하는 작업), 없으면 간단한 TBD 자리 표시자를 작성하십시오.
    • ADDED 요구사항으로 Requirements 섹션 추가
    • 아래의 메인 스펙 형식 참조를 따르십시오.
  5. 업데이트된 메인 스펙 유효성 검사

    이전에 사용한 것과 동일한 선택된 루트 플래그로 openspec validate --specs를 실행하십시오. 유효성 검사에 실패하면 문제를 보고하고 동기화가 성공했다고 말하지 마십시오.

  6. 요약 표시

    모든 변경 사항을 적용한 후 요약:

    • 업데이트된 기능
    • 어떤 변경 사항이 적용되었는지(요구사항 추가/수정/제거/이름 변경)
    • TBD Purpose 자리 표시자가 남아 있는 새 메인 스펙이 있으므로 지금 작성되고 지연되지 않음
    • 폐기된 기능, 삭제된 spec.md, 해당 Purpose, 그리고 붙여넣을 수 있는 git checkout 또는 체크아웃 범위의 복구 지침

델타 스펙 형식 참조

# Spec Delta

## Purpose

완전히 새로운 기능을 도입하는 델타에만 해당됩니다. 새 메인 스펙을 시드합니다.

## ADDED Requirements

### Requirement: New Feature
시스템 SHALL 새로운 작업을 수행합니다.

#### Scenario: Basic case
- **WHEN** 사용자가 X를 수행
- **THEN** 시스템이 Y를 수행

## MODIFIED Requirements

### Requirement: Existing Feature
시스템 SHALL 기존 작업을 계속 수행하며, 이제 A도 처리합니다.

#### Scenario: 메인 스펙이 이미 가지고 있는 시나리오
- **WHEN** 사용자가 X를 수행
- **THEN** 시스템이 Y를 수행

#### Scenario: 추가할 새 시나리오
- **WHEN** 사용자가 A를 수행
- **THEN** 시스템이 B를 수행

## REMOVED Requirements

### Requirement: Deprecated Feature

## RENAMED Requirements

- FROM: `### Requirement: Old Name`
- TO: `### Requirement: New Name`

메인 스펙 형식 참조

메인 스펙은 델타가 병합되는 대상입니다. 델타 작업 헤더(## ADDED/MODIFIED/REMOVED/RENAMED Requirements)를 포함해서는 안 됩니다. 동기화 후 모든 요구사항은 단일 ## Requirements 섹션 아래에 있습니다:

# <capability> Specification

## Purpose
이 기능이 수행하는 작업과 존재 이유에 대한 간략한 설명.

## Requirements

### Requirement: New Feature
시스템 SHALL 새로운 작업을 수행합니다.

#### Scenario: Basic case
- **WHEN** 사용자가 X를 수행
- **THEN** 시스템이 Y를 수행

핵심 원칙: 지능적 병합

프로그래매틱 병합과 달리 덮어쓰지 않고 병합합니다:

  • MODIFIED 블록은 전체 요구사항(본문과 변경에서 살아남은 모든 시나리오)을 전달합니다. openspec validate 및 openspec archive는 모두 메인 스펙이 여전히 가지고 있는 시나리오를 삭제하는 블록을 거부합니다.
  • 델타가 언급하지 않은 항목을 메인 스펙의 기존 순서로 유지하십시오.
  • 주의: REMOVED는 시나리오가 아닌 전체 요구사항에 적용됩니다. 시나리오 수준 세분성은 지원되지 않습니다. 대신 시나리오를 수정해야 하는 경우 MODIFIED를 사용하십시오.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

관련 스킬