스토어: 자체 리포지토리에서 계획하기
베타. 스토어, 참조, 작업 컨텍스트 및 워크셋은 새로 추가되었습니다. 명령어 이름, 플래그, 파일 형식 및 JSON 출력은 릴리스 간에 변경될 수 있습니다. 아래의 모든 연습은 현재 빌드를 기준으로 실행되었지만, 업그레이드 후 이 가이드를 다시 읽어주시기 바랍니다.
이것이 해결하는 문제
OpenSpec은 일반적으로 하나의 코드 리포지토리 내에 존재합니다: 코드 옆에 있는 openspec/ 폴더가 해당 리포지토리의 스펙과 변경 사항을 보관합니다.
계획이 하나의 리포지토리보다 규모가 커지면 이 방식은 더 이상 적합하지 않습니다:
- 작업이 여러 리포지토리에 걸쳐 있을 때 — 하나의 기능이 API 서버, 웹 앱, 공유 라이브러리에 영향을 미칩니다. 계획은 어느 리포지토리의
openspec/폴더에 있어야 할까요? - 팀이 코드가 존재하기 전에 계획하거나, 이 리포지토리에서 코드로 구현되지 않을 사항을 계획할 때.
- 요구 사항은 한 팀이 소유하고 다른 팀이 사용합니다. 위키 버전에 괴리가 생기고, 코딩 에이전트는 어차피 읽을 수 없습니다.
스토어가 해결책입니다: 계획하는 것이 유일한 역할인 독립적인 리포지토리입니다. 이미 알고 있는 동일한 openspec/ 구조(스펙 및 변경 사항)에 작은 식별 파일이 추가된 형태입니다. 이름을 지정하여 머신에 한 번만 등록하면, 어디서든 모든 일반 OpenSpec 명령어를 사용하여 해당 스토어에서 작업할 수 있습니다.
구조
team-plans (스토어: 자체 저장소에 계획을 둠)
├── .openspec-store/store.yaml 정체성: "나는 team-plans"
└── openspec/
├── specs/ 사실(무엇이 참인가)
└── changes/ 진행 중인 작업
▲
│ 각 머신에 이름으로 등록됨;
│ 다른 저장소처럼 푸시/클론으로 공유됨
┌─────────────┼─────────────┐
│ │ │
web-app api-server mobile-app
(코드 저장소) (코드 저장소) (코드 저장소)두 가지 규칙이 이 구조를 단순하게 유지합니다:
- 스토어는 그저 git 저장소입니다. 직접 커밋하고, 푸시하고, 풀하고, 리뷰합니다. OpenSpec은 자체적으로 클론하거나, 동기화하거나, 푸시하지 않습니다.
- 선언이지 메커니즘이 아닙니다. 저장소는 스토어와의 관계를 선언할 수 있습니다(아래 참조). 선언은 OpenSpec이 알려줄 수 있는 내용을 바꿉니다 — 명령이 작동하는 위치는 절대 바꾸지 않습니다.
첫 번째 스토어까지 5분
두 가지 명령으로 아무것도 없는 상태에서 작동하는 스토어 범위 변경까지 갈 수 있습니다:
openspec store setup team-plans --path ~/openspec/team-plansStore ready: team-plans
Location: /Users/you/openspec/team-plans
OpenSpec root: ready
Registry: registered
Next: run normal OpenSpec commands against this store, for example:
openspec new change <change-id> --store team-plans
Share this store by committing and pushing it like any Git repo.openspec new change add-login --store team-plansUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
Created change 'add-login' at /Users/you/openspec/team-plans/openspec/changes/add-login/
Schema: spec-driven
Next: openspec status --change add-login --store team-plans이것이 전체 모델입니다. 여기부터의 라이프사이클은 이미 알고 있는 그대로입니다 — status, instructions, validate, archive — 각 명령에 --store team-plans를 붙이고, 모든 출력 힌트에는 그 플래그가 포함됩니다. Using OpenSpec root: 줄은 항상 명령이 어디에서 작동하는지 알려줍니다.
이야기: 한 팀, 하나의 계획 저장소
팀은 사양과 변경 사항을 코드 저장소에 흩어두지 않고 team-plans에 유지합니다.
첫날 (설정하는 사람):
openspec store setup team-plans --path ~/openspec/team-plans \
--remote git@github.com:acme/team-plans.git
git -C ~/openspec/team-plans push -u origin main--remote를 전달하면 스토어 자체의 정체성 파일(.openspec-store/store.yaml)에 클론 URL이, 초기 커밋에 기록됩니다. 이후 모든 클론은 자신이 어디서 왔는지 알고 태어나므로, 건강 검사와 오류 메시지는 아직 그 파일이 없는 팀원에게 완전하고 붙여 넣을 수 있는 해결책을 출력할 수 있습니다.
모든 팀원 (머신당 한 번):
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
openspec store register ~/openspec/team-plans그 후부터 모두가 이름으로 같은 계획 저장소에서 작업합니다:
openspec status --store team-plans --change add-login
openspec show add-login --store team-plans작업 공유는 의도적으로 git입니다. 생성한 변경 사항은 커밋하고 푸시하기 전까지 체크아웃에만 존재합니다 — 코드와 동일합니다. 계획은 브랜치, 풀 리퀘스트, 리뷰를 그대로 얻습니다. 스토어는 일반 저장소이기 때문입니다.
팀의 코드 저장소 연결. 계획을 완전히 외부화한 코드 저장소는 openspec/config.yaml에 단 한 줄만 필요합니다:
# web-app/openspec/config.yaml
store: team-plans이제 web-app 내부에서 실행되는 모든 OpenSpec 명령은 플래그 없이 team-plans를 대상으로 작동합니다:
cd ~/src/web-app
openspec status --change add-loginUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
...포인터는 폴백이지 오버라이드가 아닙니다: 명시적 --store가 항상 우선하며, 저장소에 실제로 자체 계획 폴더가 생기면 그 폴더가 우선합니다(오래된 포인터를 제거하라는 경고와 함께).
머신의 모든 저장소에 대한 하나의 기본값. 여러 코드 저장소에서 같은 스토어로 계획을 두는 경우, 각 저장소에 store: 줄을 추가하는 대신 전역으로 한 번 설정하세요:
openspec config set defaultStore team-plans이제 계획 루트 외부에서 실행되고, --store도 프로젝트 포인터도 없는 모든 명령은 team-plans로 해석됩니다. 이 값은 우선순위 목록의 맨 아래에 있으므로 --store, 로컬 루트, 프로젝트 store: 포인터가 여전히 모두 우선합니다. 루트 배너와 JSON root 블록은 source: "global_default"와 스토어 id를 보고하므로, 머신 전체 기본값과 저장소 자체 포인터를 항상 구분할 수 있습니다. openspec config unset defaultStore로 지울 수 있습니다. id가 등록되지 않은 경우 명령은 오류를 내고 등록하거나 오래된 기본값을 지우라고 알려줍니다.
예제: 하나의 기능, 두 개의 컴포넌트 저장소
add-checkout-promo가 checkout-api와 checkout-web 둘 다를 변경한다고 가정합니다. 팀은 하나의 공유 제품 계약을 원하지만, 각 코드 저장소는 여전히 자체 구현 작업, 브랜치, 리뷰가 필요합니다.
두 계층을 사용하세요:
- 공유 동작은
team-plans에 둡니다. - 각 컴포넌트 저장소에 구현 계획을 두고, 스토어를 읽기 전용 상류 컨텍스트로 참조합니다.
먼저 스토어에서 공유 계약을 계획합니다:
openspec new change add-checkout-promo --store team-plans
openspec status --change add-checkout-promo --store team-plans제안서와 사양은 컴포넌트 경계에서의 동작을 설명해야 합니다 — 예를 들어, 서비스가 반환하는 프로모션 필드와 프론트엔드가 부적격 체크아웃을 처리하는 방법. 이 변경은 다른 브랜치 및 풀 리퀘스트처럼 스토어 저장소에서 리뷰하세요.
계획은 어떤 컨텍스트를 볼까요?
스토어를 선택하면 OpenSpec 루트가 바뀝니다; 해당 스토어를 사용하는 모든 코드 저장소를 발견하거나 읽지 않습니다. 스토어의 지침은 스토어에 있는 아티팩트와 구성된 컨텍스트를 봅니다. 에이전트나 편집기에 해당 폴더가 있고 에이전트가 읽는 경우에만 컴포넌트 코드를 볼 수 있습니다.
워크셋은 계획 스토어와 두 코드 저장소를 함께 여는 편리한 방법입니다:
openspec workset create checkout-promo \
--member ~/openspec/team-plans \
--member ~/src/checkout-api \
--member ~/src/checkout-web \
--tool code
openspec workset open checkout-promo이렇게 하면 폴더가 하나의 IDE 워크스페이스에서 보이게 됩니다. 소스 컨텍스트를 스토어에 복사하거나, 영향 받는 저장소를 선택하거나, 에이전트에게 편집 권한을 부여하지는 않습니다. 지속적인 크로스 컴포넌트 사실은 공유 사양에 두세요; 계획자가 우연히 검사한 소스를 기억하는 것에 의존하지 마세요.
각 저장소에서 구현은 어떻게 시작되나요?
명시적 --store나 더 가까운 openspec/ 루트가 적용되지 않을 때, store: team-plans 포인터는 명령을 해당 스토어로 라우팅합니다. apply가 호출된 디렉토리를 기준으로 하나의 스토어 작업 목록을 나누지 않습니다. OpenSpec은 현재 작업을 저장소로 라우팅하지 않습니다.
각 컴포넌트가 독립적으로 범위가 지정된 apply/리뷰 주기가 필요할 때, 로컬 OpenSpec 루트를 두고 중앙 스토어를 가리키는 대신 참조하세요:
# checkout-api/openspec/config.yaml (checkout-web에도 동일)
schema: spec-driven
references:
- team-plans공유 계약이 승인되어 스토어의 메인 사양에 있게 된 후, 컴포넌트 부분에 대한 작은 로컬 변경을 만드세요:
cd ~/src/checkout-api
openspec new change implement-checkout-promo-api
cd ~/src/checkout-web
openspec new change implement-checkout-promo-ui각 저장소의 지침에 있는 참조 인덱스는 스토어 사양의 요약과 정확한 openspec show ... --store team-plans 인출 명령을 제공합니다. 각 로컬 제안서는 그 공유 계약을 인용하고, 작업은 해당 컴포넌트의 작업만 설명합니다. 그런 다음 각 저장소에서 /opsx:apply를 별도로 실행합니다; 루트 해석은 아티팩트와 구현 편집을 해당 저장소로만 범위를 유지합니다. 서비스와 프론트엔드 변경은 이제 독립적으로 테스트, 리뷰, 병합, 아카이브할 수 있습니다.
공유 스토어 변경이 아직 활성 상태인 동안 구현을 시작해야 한다면 openspec show add-checkout-promo --store team-plans를 명시적으로 인출하세요; 참조 인덱스는 정식 스토어 사양을 나열하지, 활성 스토어 변경을 나열하지 않습니다. 스토어 브랜치와 컴포넌트 브랜치를 풀 리퀘스트 설명에서 연결하여 리뷰어가 각 구현이 어떤 버전의 계약을 따르는지 볼 수 있게 하세요.
이야기: 팀 경계를 넘는 요구사항
플랫폼 팀이 요구사항을 소유합니다. 제품 팀은 자체 저장소에서, 자체 설계로, 그 요구사항에 맞춰 개발합니다. 참조는 아무도 이동시키지 않고 그 관계를 설명합니다.
platform-reqs (스토어) api-server (코드 저장소)
플랫폼 팀 소유 제품 팀 소유
┌──────────────────────────┐ ┌──────────────────────────┐
│ openspec/specs/ │ ◀────────│ openspec/config.yaml │
│ payments/spec.md │ 읽음 │ references: │
│ auth/spec.md │ │ - platform-reqs │
│ │ │ openspec/specs/ │
│ openspec/changes/ │ │ (자체 설계) │
│ 플랫폼 작업 │ │ openspec/changes/ │
│ │ │ (자체 작업) │
│ │ └──────────────────────────┘
└──────────────────────────┘제품 팀은 자기가 참조하는 것을 선언합니다 자신의 저장소의 openspec/config.yaml에:
references:
- platform-reqs참조는 읽기 전용 컨텍스트입니다. 저장소는 자체 openspec/ 루트를 유지합니다; 작업은 그곳에 있습니다. 바뀌는 것: 해당 저장소의 openspec instructions는 이제 참조된 스토어의 사양 인덱스 — 각각 한 줄 요약과 정확한 인출 명령 (openspec show <spec-id> --type spec --store platform-reqs)을 포함합니다. api-server에서 작업하는 에이전트는 상류 결제 요구사항을 찾고, 인용하고, 저장소 자체 루트에 저수준 설계를 작성할 수 있습니다 — 누군가 컨텍스트를 붙여넣지 않아도.
참조는 클론 소스를 포함할 수 있으므로, 아직 스토어가 없는 팀원은 막다른 길 대신 완전한 해결책을 얻습니다:
references:
- { id: platform-reqs, remote: "git@github.com:acme/platform-reqs.git" }계획과 코드를 함께 열고 싶을 때, 워크셋을 만드세요. 이는 개인적이고 명시적입니다: 각 사람은 자신의 머신에서 실제로 작업하는 폴더를 선택합니다. 로컬 체크아웃 경로에 대한 그 어떤 것도 공유 계획 저장소에 커밋되지 않습니다.
openspec workset create platform \
--member ~/openspec/platform-reqs \
--member ~/src/api-server \
--member ~/src/web-app항상 물을 수 있는 두 가지 질문
"내 설정은 건강한가?" — openspec doctor는 현재 루트와 참조된 스토어를 읽기 전용으로 확인하며, 각 발견에 대해 붙여 넣을 수 있는 해결책을 제공합니다:
Doctor
Root
Location: /Users/you/src/api-server
OpenSpec root: ok
References
- platform-reqs: ok (/Users/you/openspec/platform-reqs)
- design-system: Referenced store 'design-system' is not registered on this machine.
Fix: git clone -- git@github.com:acme/design-system.git '/Users/you/openspec/design-system' && openspec store register '/Users/you/openspec/design-system' --id design-system"무엇을 가지고 작업하고 있나?" — openspec context는 OpenSpec 선언에서 작업 세트(루트와 참조된 스토어)를 조립합니다.
Working context for api-server (/Users/you/src/api-server)
OpenSpec root
api-server /Users/you/src/api-server
Referenced stores
platform-reqs /Users/you/openspec/platform-reqs
Fetch: openspec show <spec-id> --type spec --store platform-reqs둘 다 에이전트용 --json을 지원합니다. openspec context --code-workspace <path>는 추가로 전체 세트를 포함하는 VS Code 워크스페이스 파일을 씁니다 — 이 명령이 수행하는 유일한 쓰기입니다.
작업 세트(worksets): 함께 작업하는 폴더를 다시 열기
이전 항목들과는 별도로: 대부분의 사용자는 매 세션마다 동일한 몇몇 폴더를 함께 엽니다 — 계획 저장소(planning repo)와 두세 개의 코드 저장소(code repos)가 대표적입니다. 작업 세트(workset)란 바로 그런 구성을 개인적으로 이름 붙여 정의한 것으로, 선호하는 도구에서 한 번의 명령어로 다시 열 수 있습니다.
workset "platform" openspec workset open platform
├── team-plans ~/openspec/team-plans │
├── api-server ~/src/api-server ▼
└── web-app ~/src/web-app 이 세 개가 모두 도구에서 열림openspec workset create platform \
--member ~/openspec/team-plans --member ~/src/api-server \
--tool code
openspec workset listplatform (VS Code에서 열림)
team-plans /Users/you/openspec/team-plans
api-server /Users/you/src/api-serveropenspec workset open platform은 저장된 도구를 실행합니다. 에디터(VS Code, Cursor 등)는 모든 멤버를 포함하는 하나의 창을 열고 종료됩니다. 첫 번째 멤버가 기본(primary)으로 간주됩니다. --tool <id>를 사용하여 언제든지 도구를 재정의할 수 있습니다.
작업 세트는 의도적으로 공유 상태(shared state)가 아닙니다. 작업 세트는 사용자 머신에 존재하며, 커밋되지 않으며, 작업 내용에 대한 주장을 하지 않습니다. 단지 함께 열어두기를 원하는 것들만 기록할 뿐입니다. 하나를 제거해도 멤버 폴더에는 영향을 미치지 않습니다. 새로운 도구는 코드가 아닌 설정입니다: 워크스페이스 파일이나 폴더별 첨부 플래그(per-folder attach flags)를 통해 실행 가능한 모든 것은 글로벌 설정(openspec config edit)의 openers 키 아래에 추가할 수 있습니다.
명령어가 동작 대상을 어떻게 결정하는지
모든 일반 명령어는 다음 순서로 루트(root)를 해결합니다:
1. --store <id> 명시적으로 지정한 경우 → 해당 저장소(store)
2. nearest openspec/ 여기에 실제 계획 루트가 있음 → 해당 저장소
(현재 디렉토리(cwd)에서 상위 탐색)
3. store: 포인터 config.yaml에 저장소 선언됨 → 해당 저장소
4. defaultStore 글로벌 설정에서 머신 기본값 지정 → 해당 저장소
5. 위의 어느 것도 아님 이 머신에 등록된 저장소가 있는가? → 선택 힌트와 함께 오류
등록된 저장소가 없는가? → 현재 디렉토리
(기존 동작)Using OpenSpec root: 라인(및 --json 출력의 root 블록)은 현재 어떤 경우에 해당하는지 알려줍니다.
알려진 제한 사항
- 베타 버전 형태. 이 페이지의 모든 내용은 릴리스 간에 변경될 수 있습니다 — 이름, 플래그, 파일 형식, JSON 키 등이 해당됩니다.
- 머신당 저장소 ID당 체크아웃(checkout)은 하나만 가능함. 동일한 ID로 두 번째 체크아웃을 등록하면 먼저
store unregister를 수행하라는 힌트와 함께 실패합니다. - 동기화는 절대 없음 — 설계상. OpenSpec은 복제(clone), 풀(pull), 푸시(push)를 수행하지 않습니다. 오래된 체크아웃은 사용자가 풀하기 전까지 오래된 스펙을 표시하며, 참조는 디스크에 있는 내용을 기반으로 실시간으로 인덱싱됩니다.
- 빈 계획 폴더는 부재할 수 있음. 새로운 저장소는 Git에
openspec/changes/,openspec/specs/, 또는openspec/changes/archive/가 아직 없을 수 있습니다. 이는 베타 기간 동안 허용되며, 일반 명령어가 해당 폴더용 파일을 생성하면 이러한 폴더들이 나타납니다. - 포인터 저장소는 포인터로 남음.
openspec/config.yaml에store: <id>를 선언하는 설정 전용 저장소는 로컬 저장소 체크아웃으로 등록되는 것이 아니라 외부화된 계획(externalized planning)으로 처리됩니다. 해당 저장소를 로컬 저장소 루트로 변환하려는 경우, 먼저store:라인을 제거해야 합니다. - 일부 명령어는 위치를 유지함.
templates및 더 이상 권장되지 않는 명사 형태(noun forms, 예:openspec change show등)는 현재 디렉토리에서만 동작하며--store옵션을 받지 않습니다.schemas는 표준 루트 선행 순위를 따르며--store <id>를 받지만, 성공적인 JSON 배열 형태는 그대로 유지합니다. - 머신별 상태는 머신별로 관리됨. 저장소 레지스트리와 작업 세트는 로컬 설정입니다. 사용자의 머신 레이아웃과 관련된 내용은 공유 계획에 결코 커밋되지 않습니다.
- 작업 세트의 두 가지 실행 스타일. 워크스페이스 파일이나 폴더별 첨부 플래그로 실행할 수 없는 도구는 오프너(opener)로 추가할 수 없습니다.
- 에이전트 JSON에는 알려진 케이스(case) 분리가 있음 (저장소 계열 키는 snake_case, 워크플로우 계열은 camelCase). 이는 에이전트 계약에 문서화되어 있으며, 통일 작업은 버전 지정 릴리스로 연기되었습니다.
항목들의 위치
| 항목 | 위치 | 공유 여부 |
|---|---|---|
| 저장소의 계획 | <store>/openspec/ (specs, changes) | 예 — 커밋하고 푸시하세요 |
| 저장소의 식별자 | <store>/.openspec-store/store.yaml | 예 — 저장소와 함께 커밋됨 |
| 저장소 레지스트리 | <data dir>/openspec/stores/registry.yaml | 아니오 — 이 머신 전용 |
| 작업 세트 | <data dir>/openspec/worksets/ | 아니오 — 이 머신 전용 |
<data dir>은 macOS 및 Linux에서 ~/.local/share/openspec(또는 $XDG_DATA_HOME/openspec가 설정된 경우 해당 경로), Windows에서는 %LOCALAPPDATA%\openspec입니다.
참조
이 페이지의 모든 명령어에 대한 정확한 플래그 및 JSON 구조: CLI 참조(Stores, Doctor, Working context, Personal worksets) 및 에이전트 계약.