Składy: Planowanie w osobnym repozytorium
Beta. Składy, referencje, kontekst roboczy i zestawy robocze to nowe funkcje. Nazwy poleceń, flagi, formaty plików i wyjście JSON mogą jeszcze zmieniać się między wersjami. Każda instrukcja poniżej została wykonana na bieżącej wersji, ale po aktualizacji warto ponownie przeczytać ten przewodnik.
Problem, który to rozwiązuje
OpenSpec normalnie mieszka w jednym repozytorium kodu: folder openspec/ obok Twojego kodu, zawierający specyfikacje i zmiany dla tego repozytorium.
To przestaje wystarczać, gdy planowanie wykracza poza jedno repozytorium:
- Twoja praca obejmuje kilka repozytoriów — jedna funkcja dotyka serwera API, aplikacji webowej i wspólnej biblioteki. W czyim folderze
openspec/ma mieszkać plan? - Twój zespół planuje, zanim kod jeszcze istnieje, albo planuje rzeczy, które nigdy nie staną się kodem w tym repozytorium.
- Wymagania są własnością jednego zespołu, a konsumowane przez inne. Wersja na wiki się rozjeżdża, a Twój agent kodujący i tak nie potrafi jej odczytać.
Skład to odpowiedź: samodzielne repozytorium, którego jedynym zadaniem jest planowanie. Ma ten sam kształt openspec/, który już znasz — specyfikacje i zmiany — plus mały plik tożsamości. Rejestrujesz go na swojej maszynie raz, pod nazwą, a następnie każde zwykłe polecenie OpenSpec może w nim działać z dowolnego miejsca.
Kształt
team-plans (magazyn: planowanie w swoim własnym repozytorium)
├── .openspec-store/store.yaml tożsamość: "Jestem team-plans"
└── openspec/
├── specs/ co jest prawdą
└── changes/ co jest w ruchu
▲
│ zarejestrowany na każdej maszynie po nazwie;
│ współdzielony przez push/clone jak każde repozytorium
┌─────────────┼─────────────┐
│ │ │
web-app api-server mobile-app
(repo kodu) (repo kodu) (repo kodu)Dwie zasady utrzymują prostotę:
- Magazyn to po prostu repozytorium git. Samodzielnie commitujesz, pushujesz, pullujesz i przeglądasz. OpenSpec nigdy nie klonuje, nie synchronizuje ani nie wypycha niczego samodzielnie.
- Deklaracje, a nie mechanizmy. Repozytoria mogą deklarować, jak odnoszą się do magazynów (pokazane poniżej). Deklaracje zmieniają to, co OpenSpec może ci powiedzieć – nigdy nie miejsce, gdzie działają twoje polecenia.
Pięć minut do pierwszego magazynu
Dwa polecenia przenoszą cię od zera do działającej zmiany w zakresie magazynu:
openspec store setup team-plans --path ~/openspec/team-plansMagazyn gotowy: team-plans
Lokalizacja: /Users/you/openspec/team-plans
Korzeń OpenSpec: gotowy
Rejestr: zarejestrowany
Dalej: uruchamiaj normalne polecenia OpenSpec wobec tego magazynu, np.:
openspec new change <change-id> --store team-plans
Udostępnij ten magazyn, commitując i pushując go jak każde repozytorium Git.openspec new change add-login --store team-plansUżywam korzenia OpenSpec: team-plans (/Users/you/openspec/team-plans)
Utworzono zmianę 'add-login' w /Users/you/openspec/team-plans/openspec/changes/add-login/
Schemat: spec-driven
Dalej: openspec status --change add-login --store team-plansTo cały model. Od tego momentu cykl życia jest dokładnie taki, jaki znasz – status, instructions, validate, archive – z --store team-plans przy każdym poleceniu, a każda wyświetlana podpowiedź niesie tę flagę za ciebie. Linia Używam korzenia OpenSpec: zawsze mówi, gdzie działa polecenie.
Opowieść: jeden zespół, jedno repozytorium planistyczne
Zespół przechowuje swoje specyfikacje i zmiany w team-plans, zamiast rozpraszać je po repozytoriach kodu.
Dzień pierwszy (ktoś to konfiguruje):
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 mainPodanie --remote zapisuje adres URL klonowania w pliku tożsamości magazynu (.openspec-store/store.yaml), w początkowym commicie. Każdy przyszły klon od razu wie, skąd pochodzi, więc sprawdzenia poprawności i komunikaty błędów mogą wyświetlić kompletną, gotową do wklejenia poprawkę dla kolegów, którzy jeszcze go nie mają.
Każdy członek zespołu (raz na maszynę):
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
openspec store register ~/openspec/team-plansOd tej pory wszyscy pracują w tym samym repozytorium planistycznym, używając nazwy:
openspec status --store team-plans --change add-login
openspec show add-login --store team-plansDzielenie się pracą to git, celowo. Zmiana, którą tworzysz, istnieje tylko w twojej kopii roboczej, dopóki jej nie skomitujesz i nie wypchniesz – tak samo jak kod. Plany zyskują gałęzie, pull requesty i przegląd za darmo, ponieważ magazyn jest zwykłym repozytorium.
Łączenie repozytoriów kodu zespołu. Repozytorium kodu, którego planowanie jest w pełni zewnętrzne, potrzebuje dokładnie jednej linii w openspec/config.yaml:
# web-app/openspec/config.yaml
store: team-plansTeraz każde polecenie OpenSpec uruchomione wewnątrz web-app działa na team-plans bez żadnych flag:
cd ~/src/web-app
openspec status --change add-loginUżywam korzenia OpenSpec: team-plans (/Users/you/openspec/team-plans)
...Wskazanie jest wartością domyślną, a nie nadpisaniem: jawny --store zawsze wygrywa, a jeśli repozytorium wyrośnie później własne foldery planowania, one wygrywają (z ostrzeżeniem o usunięciu nieaktualnego wskazania).
Jedna wartość domyślna dla każdego repozytorium na twojej maszynie. Jeśli pracujesz w wielu repozytoriach kodu, które wszystkie planują do tego samego magazynu, ustaw go raz, globalnie, zamiast dodawać linię store: do każdego repozytorium:
openspec config set defaultStore team-plansTeraz każde polecenie uruchomione poza korzeniem planowania – i bez --store oraz bez wskazania projektu – kieruje do team-plans. Znajduje się ono na dole listy priorytetów, więc --store, lokalny korzeń i wskazanie store: w projekcie wciąż wygrywają. Baner korzenia i blok root w JSON-ie raportują source: "global_default" z identyfikatorem magazynu, dzięki czemu zawsze odróżnisz globalną wartość domyślną od wskazania w repozytorium. Wyczyść to przez openspec config unset defaultStore. Jeśli identyfikator nie jest zarejestrowany, polecenia zgłaszają błąd i mówią, aby go zarejestrować lub wyczyścić nieaktualną wartość domyślną.
Przykład: jedna funkcja, dwa repozytoria komponentów
Załóżmy, że add-checkout-promo zmienia zarówno checkout-api, jak i checkout-web. Zespół chce jeden wspólny kontrakt produktu, podczas gdy każde repozytorium kodu nadal potrzebuje własnych zadań implementacyjnych, gałęzi i przeglądu.
Użyj dwóch warstw:
- Przechowuj wspólne zachowanie w
team-plans. - Przechowuj plany implementacyjne w każdym repozytorium komponentu i odwołuj się do magazynu jako kontekstu nadrzędnego tylko do odczytu.
Najpierw zaplanuj wspólny kontrakt w magazynie:
openspec new change add-checkout-promo --store team-plans
openspec status --change add-checkout-promo --store team-plansPropozycja i specyfikacje powinny opisywać zachowanie na granicy między komponentami – na przykład pola promocji zwracane przez usługę i sposób, w jaki frontend obsługuje nieuprawniony checkout. Przejrzyj tę zmianę w repozytorium magazynu jak każdą inną gałąź i pull request.
Jaki kontekst widzi planista?
Wybranie magazynu zmienia korzeń OpenSpec; nie odkrywa on ani nie odczytuje każdego repozytorium kodu, które z niego korzysta. Instrukcje magazynu widzą artefakty i skonfigurowany kontekst w magazynie. Widzą kod komponentów tylko wtedy, gdy te foldery są również dostępne dla agenta lub edytora i agent je odczyta.
Workset jest wygodnym sposobem na otwarcie magazynu planowania i obu repozytoriów kodu razem:
openspec workset create checkout-promo \
--member ~/openspec/team-plans \
--member ~/src/checkout-api \
--member ~/src/checkout-web \
--tool code
openspec workset open checkout-promoTo sprawia, że foldery są widoczne w jednej przestrzeni roboczej IDE. Nie kopiuje to kontekstu źródłowego do magazynu, nie wybiera dotkniętych repozytoriów ani nie daje agentowi uprawnień do ich edycji. Umieszczaj trwałe fakty międzykomponentowe we wspólnych specyfikacjach; nie polegaj na tym, że planista zapamięta źródło, które przypadkiem zbadał.
Jak rozpoczyna się implementacja w każdym repozytorium?
Gdy nie ma jawnego --store ani bliższego korzenia openspec/, wskazanie store: team-plans kieruje polecenia do tego magazynu. Nie dzieli to jednej listy zadań magazynu według katalogu, z którego wywołano apply. OpenSpec obecnie nie kieruje zadań do repozytoriów.
Gdy każdy komponent potrzebuje niezależnego cyklu apply/review, daj mu lokalny korzeń OpenSpec i odwołuj się do centralnego magazynu zamiast na niego wskazywać:
# checkout-api/openspec/config.yaml (i podobnie w checkout-web)
schema: spec-driven
references:
- team-plansPo zatwierdzeniu wspólnego kontraktu i udostępnieniu go w głównych specyfikacjach magazynu, utwórz małą lokalną zmianę dla części komponentowej:
cd ~/src/checkout-api
openspec new change implement-checkout-promo-api
cd ~/src/checkout-web
openspec new change implement-checkout-promo-uiIndeks odwołań w instrukcjach każdego repozytorium dostarcza podsumowanie specyfikacji z magazynu oraz dokładne polecenie pobrania openspec show ... --store team-plans. Każda lokalna propozycja powołuje się na ten wspólny kontrakt, a jej zadania opisują tylko pracę w tym komponencie. Następnie uruchom /opsx:apply osobno w każdym repozytorium; rozwiązywanie korzenia utrzymuje artefakty i edycje implementacyjne w zakresie tego repozytorium. Zmiany w usłudze i frontendzie mogą teraz być testowane, przeglądane, scalane i archiwizowane niezależnie.
Jeśli implementacja musi się rozpocząć, gdy zmiana w magazynie jest nadal aktywna, pobierz ją jawnie przez openspec show add-checkout-promo --store team-plans; indeksy odwołań wymieniają kanoniczne specyfikacje magazynu, a nie aktywne zmiany magazynu. Utrzymuj gałąź magazynu i gałęzie komponentów połączone w opisach pull requestów, aby recenzenci mogli zobaczyć, za którą wersją kontraktu podąża każda implementacja.
Opowieść: wymagania przecinające granice zespołów
Zespół platformowy jest właścicielem wymagań. Zespoły produktowe budują na ich podstawie, w swoich własnych repozytoriach, z własnymi projektami. Odwołanie opisuje tę relację, nie przenosząc niczyjej pracy.
platform-reqs (magazyn) api-server (repo kodu)
własność zespołu platformowego własność zespołu produktowego
┌──────────────────────────┐ ┌──────────────────────────┐
│ openspec/specs/ │ ◀──────────│ openspec/config.yaml │
│ payments/spec.md │ odczytuje │ references: │
│ auth/spec.md │ │ - platform-reqs │
│ │ │ openspec/specs/ │
│ openspec/changes/ │ │ (ich własne projekty) │
│ praca platformowa │ │ openspec/changes/ │
│ │ │ (ich własna praca) │
│ │ └──────────────────────────┘
└──────────────────────────┘Zespół produktowy deklaruje, z czego korzysta w pliku openspec/config.yaml swojego repozytorium:
references:
- platform-reqsOdwołania to kontekst tylko do odczytu. Repozytorium zachowuje swój własny korzeń openspec/; praca pozostaje tam. Co się zmienia: openspec instructions w tym repozytorium zawiera teraz indeks specyfikacji odniesionego magazynu – każda z jednozdaniowym podsumowaniem i dokładnym poleceniem pobrania (openspec show <spec-id> --type spec --store platform-reqs). Agent pracujący w api-server może znaleźć nadrzędne wymagania płatności, zacytować je i napisać swój niskopoziomowy projekt w korzeniu własnego repozytorium – bez konieczności przeklejania kontekstu przez kogokolwiek.
Odwołanie może nieść swoje źródło klonowania, dzięki czemu koledzy, którzy nie mają jeszcze magazynu, otrzymują kompletną naprawę zamiast ślepego zaułka:
references:
- { id: platform-reqs, remote: "git@github.com:acme/platform-reqs.git" }Gdy chcesz mieć plan i kod otwarte razem, utwórz workset. Jest to osobiste i jawne: każda osoba wybiera foldery, z którymi faktycznie pracuje na swojej maszynie. Nic o tych lokalnych ścieżkach nie jest committowane do współdzielonego repozytorium planowania.
openspec workset create platform \
--member ~/openspec/platform-reqs \
--member ~/src/api-server \
--member ~/src/web-appDwa pytania, które zawsze możesz zadać
"Czy moja konfiguracja jest zdrowa?" – openspec doctor sprawdza bieżący korzeń i jego odniesione magazyny, tylko do odczytu, z gotową do wklejenia poprawką dla każdego znaleziska:
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"Z czym pracuję?" – openspec context zestawia zestaw roboczy z deklaracji OpenSpec: korzeń i magazyny, do których się odwołuje.
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-reqsObydwa wspierają --json dla agentów. openspec context --code-workspace <path> dodatkowo zapisuje plik przestrzeni roboczej VS Code zawierający cały zestaw – jedyny zapis, jaki wykonuje to polecenie.
Worksets: ponowne otwieranie folderów, nad którymi wspólnie pracujesz
Osobno od wszystkiego powyżej: większość osób otwiera te same kilka folderów razem w każdej sesji — repozytorium planowania oraz dwa lub trzy repozytoria kodu. Workset to osobisty, nazwany widok dokładnie tego zestawu, ponownie otwierany jedną komendą w wybranym narzędziu.
workset "platform" openspec workset open platform
├── team-plans ~/openspec/team-plans │
├── api-server ~/src/api-server ▼
└── web-app ~/src/web-app all three open in your toolopenspec workset create platform \
--member ~/openspec/team-plans --member ~/src/api-server \
--tool code
openspec workset listplatform (opens in VS Code)
team-plans /Users/you/openspec/team-plans
api-server /Users/you/src/api-serveropenspec workset open platform uruchamia następnie zapisane narzędzie: edytory (VS Code, Cursor) otwierają jedno okno z każdym członkiem i zwracają. Pierwszy członek jest główny. Narzędzie można w dowolnym momencie nadpisać za pomocą --tool <id>.
Worksets celowo nie są współdzielonym stanem. Istnieją na Twoim komputerze, nigdy nie są commitowane i nie formułują żadnych twierdzeń o pracy — jedynie rejestrują, co lubisz otwierać razem. Usunięcie jednego nigdy nie dotyka folderów członków. Nowe narzędzia to konfiguracja, nie kod: wszystko, co uruchamiane za pomocą pliku roboczego lub flag attach per-folder, może zostać dodane pod kluczem openers w globalnej konfiguracji (openspec config edit).
Jak komendy decydują, gdzie działać
Każda zwykła komenda rozwiązuje swój root w ten sam sposób, w tej kolejności:
1. --store <id> you said so explicitly → that store
2. nearest openspec/ a real planning root here → this repo
(walking up from cwd)
3. store: pointer config.yaml declares a store → that store
4. defaultStore global config sets a machine → that store
default
5. none of the above stores registered on this → error with a
machine? selection hint
no stores registered? → the current
directory
(classic behavior)Linia Using OpenSpec root: (oraz blok root w wyjściu --json) informuje Cię, w którym przypadku jesteś.
Znane ograniczenia
- Forma beta. Wszystko na tej stronie może ulec zmianie między wydaniemiami — nazwy, flagi, formaty plików, klucze JSON.
- Jeden checkout na identyfikator magazynu na komputer. Rejestrowanie drugiego checkoutu pod tym samym identyfikatorem kończy się błędem z podpowiedzią, aby najpierw wykonać
store unregister. - Brak synchronizacji, nigdy — zgodnie z projektem. OpenSpec nigdy nie klonuje, nie pobiera ani nie wysyła. Stary checkout wyświetla stare specyfikacje, dopóki Ty nie pobierzesz; odniesienia są indeksowane na żywo z tego, co znajduje się na dysku.
- Puste foldery planowania mogą być nieobecne. Nowy magazyn może nie mieć jeszcze
openspec/changes/,openspec/specs/lubopenspec/changes/archive/w Git. Jest to akceptowane podczas wersji beta; te foldery pojawią się, gdy zwykłe komendy utworzą dla nich pliki. - Repozytoria wskaźnikowe pozostają wskaźnikami. Repozytorium zawierające wyłącznie konfigurację, którego
openspec/config.yamldeklarujestore: <id>, jest traktowane jako zewnętrznione planowanie, a nie jako checkout magazynu do zarejestrowania. Najpierw usuń linięstore:, jeśli celowo chcesz przekonwertować to repozytorium na lokalny root magazynu. - Niektóre komendy pozostają tam, gdzie są.
templatesoraz nieaktualne formy rzeczownikowe (openspec change show, ...) działają wyłącznie na bieżący katalog — bez--store.schemaspodąża za kanonicznym priorytetem wyboru roota i akceptuje--store <id>, zachowując niezmienioną strukturę tablicy JSON przy pomyślnym zakończeniu. - Stan per-komputer to stan per-komputer. Rejestr magazynów i worksets to ustawienia lokalne. Nic o układzu Twojego komputera nigdy nie jest commitowane do wspólnego planowania.
- Dwa style uruchamiania worksets. Narzędzie, którego nie można uruchomić za pomocą pliku roboczego lub flag attach per-folder, nie może zostać dodane jako opener.
- JSON agenta ma znany podział wielkości liter (klucze rodziny store są w snake_case, klucze rodziny workflow w camelCase). Udokumentowane w umowie agenta; ujednolicenie jest odłożone na wydanie z wersjonowaniem.
Gdzie znajdują się poszczególne elementy
| Co | Gdzie | Współdzielone? |
|---|---|---|
| Planowanie magazynu | <store>/openspec/ (specyfikacje, zmiany) | Tak — commituj i pushuj |
| Tożsamość magazynu | <store>/.openspec-store/store.yaml | Tak — commitowane z magazynem |
| Rejestr magazynów | <data dir>/openspec/stores/registry.yaml | Nie — tylko ten komputer |
| Worksets | <data dir>/openspec/worksets/ | Nie — tylko ten komputer |
<data dir> to ~/.local/share/openspec na macOS i Linux (lub $XDG_DATA_HOME/openspec, gdy ustawione), oraz %LOCALAPPDATA%\openspec na Windows.
Referencja
Dokładne flagi i struktury JSON dla każdej komendy na tej stronie: referencja CLI (Stores, Doctor, Working context, Personal worksets) oraz umowa agenta.