Orchestrata Ultimate / Specs / 104-openspec-format
104-openspec-format: OpenSpec Format Support
A capability that locates a project's spec folder, recognizes whether it follows the OpenSpec convention, and parses / creates / edits OpenSpec specs and change proposals — keeping the OpenSpec markdown format intact.
At a glance
| Item | Value |
|---|---|
| Spec directory | specs/104-openspec-format/ |
| Status line in the spec | Draft |
| Requirement IDs defined | 10 |
With a @traces citation in src/ |
10 (100.0%) |
With a @traces citation in tests/ |
0 (0.0%) |
| Tracked files | 2 |
| RTM page | 104-openspec-format |
Reading this spec
This spec lets orchestrata work with projects that keep their specifications in the OpenSpec convention. Orchestrata's own specs use the SPEC-NNN layout (specs/NNN-name/spec.md with Metadata, FR-NNN and REQ-NNN), but many external projects use an openspec/ directory whose specs are markdown with ### Requirement: and #### Scenario: blocks (WHEN and THEN lines with SHALL statements) and whose changes live under openspec/changes/<id>/. To work on those projects, the system must find the spec folder, recognize the format, and read or produce valid OpenSpec without forcing its own format onto the project.
The design is a self-contained orchestrata_ultimate.openspec module with a detector, a parser, a renderer and a repository layer. Four user stories cover detecting and recognizing the format, creating an OpenSpec capability spec, editing an existing one and scaffolding a change. The seven functional requirements (FR-001 to FR-007) are locating the spec folder, recognizing the format, parsing, creating, editing, validating and sandboxed writes.
The ten requirement IDs (REQ-104-001 to 010) state the behaviour. Locating a spec folder prefers openspec/ and otherwise the orchestrata specs/ layout, returning nothing instead of raising when absent. A folder is classified as openspec, orchestrata or unknown. A capability spec parses into an OpenSpecDoc and a change spec into ADDED, MODIFIED, REMOVED and RENAMED deltas. Rendering produces valid OpenSpec markdown that round-trips structurally. A change scaffold has a proposal, a task checklist and a delta spec. Adding a requirement or scenario preserves existing content and order. Validation requires at least one scenario and a SHALL statement for each requirement and reports violations without raising. All file writes stay inside the detected spec root, and paths that escape it are rejected.
The code is in the openspec package: repo (6 requirements), parse, detect and render. The requirements traceability matrix lists each ID. The spec's own status line reads Draft and it tracks 2 files. Measured coverage is 10 of 10 requirements cited by at least one @traces in src/ (100.0%), spread over 4 modules; the module citing the most of them is orchestrata_ultimate/openspec/repo (6 requirements). In tests/, 0 requirements are cited by a test-side @traces, so test-side citations are thinner than code-side ones.
Requirements
Checkbox is the state recorded in the requirements checklist; Traced by is the count of src/ symbols whose @traces names the ID.
| ID | Done | Requirement | Traced by |
|---|---|---|---|
REQ-104-001 |
no | Given a project root, locate a spec folder, preferring openspec/, else the orchestrata specs/ layout; return None when absent (no raise). |
3 |
REQ-104-002 |
no | Classify a located folder as openspec when it contains an openspec/ tree (project.md / specs / changes) or spec files using ### Requirement: + #### Scenario:. |
3 |
REQ-104-003 |
no | Classify the orchestrata specs/NNN-*/spec.md (Metadata + FR-/REQ-) layout as orchestrata; otherwise unknown. |
2 |
REQ-104-004 |
no | Parse a capability spec.md into an OpenSpecDoc (purpose + requirements, each with its scenarios and WHEN/THEN lines). |
4 |
REQ-104-005 |
no | Parse a change delta spec.md into Delta objects keyed by ADDED/MODIFIED/REMOVED/RENAMED. |
2 |
REQ-104-006 |
no | Render an OpenSpecDoc to valid OpenSpec markdown (## Purpose, ## Requirements, ### Requirement:, #### Scenario:); round-trips structurally. |
3 |
REQ-104-007 |
no | Scaffold a change under changes/<id>/ (proposal.md with Why/What Changes, tasks.md with a checklist, and a delta specs/<cap>/spec.md). |
5 |
REQ-104-008 |
no | Add a requirement or add a scenario to an existing OpenSpecDoc, preserving existing content and order; re-render to markdown. |
1 |
REQ-104-009 |
no | Validate a parsed OpenSpecDoc — each requirement has ≥1 scenario and a SHALL statement; report violations (do not raise). |
1 |
REQ-104-010 |
no | All file writes are confined to the detected spec root; paths escaping it are rejected. | 3 |
Code that traces this spec
| Module | Symbols | Requirements |
|---|---|---|
orchestrata_ultimate/openspec/detect |
4 | 3 |
orchestrata_ultimate/openspec/parse |
5 | 3 |
orchestrata_ultimate/openspec/render |
5 | 2 |
orchestrata_ultimate/openspec/repo |
8 | 6 |
Checklists
checklists/requirements.md
The requirement list above comes from this file; 0 of 10 checkbox items are ticked.
Full spec text
Verbatim from specs/104-openspec-format/spec.md; headings are pushed down two levels.
SPEC-104: OpenSpec Format Support
Metadata
- Spec ID: 104-openspec-format
- Title: OpenSpec Format Support — Detect, Parse, Create, and Edit OpenSpec Specs
- Author: Mohamed
- Status: Draft
- Created: 2026-05-28
- Last Updated: 2026-05-28
- Priority: P2
- Version: 0.1.0
- Extends: SPEC-103 (Tool-Calling Code Refactoring — the refactor agent may use these tools)
Overview
What
A capability that locates a project's spec folder, recognizes whether it follows the OpenSpec convention, and parses / creates / edits OpenSpec specs and change proposals — keeping the OpenSpec markdown format intact.
Why
orchestrata's own specs use the SPEC-NNN format (specs/NNN-name/spec.md with
Metadata, FR-NNN, REQ-NNN). Many external projects instead use OpenSpec: an
openspec/ directory whose specs are markdown with ### Requirement: +
#### Scenario: (WHEN/THEN, SHALL), and whose changes live under
openspec/changes/<id>/. To work on those projects, the system must detect a
spec folder, recognize the format, and read/produce valid OpenSpec — without
forcing the project's own format onto it.
How
A self-contained orchestrata_ultimate.openspec module: a detector (find the
spec folder + classify the format), a model + parser (OpenSpec markdown →
structured objects), and a renderer/editor (objects → OpenSpec markdown;
add/modify requirements and scenarios; scaffold a change proposal). File writes
are sandboxed to the detected spec root.
OpenSpec format (reference)
openspec/
project.md
specs/<capability>/spec.md # current truth
changes/<change-id>/
proposal.md # ## Why / ## What Changes / ## Impact
tasks.md # ## 1. Group \n - [ ] 1.1 task
design.md # optional
specs/<capability>/spec.md # delta: ## ADDED|MODIFIED|REMOVED Requirements
changes/archive/
Capability spec.md:
# <capability> Specification
## Purpose
<text>
## Requirements
### Requirement: <title>
The system SHALL <statement>.
#### Scenario: <name>
- **WHEN** <trigger>
- **THEN** <outcome>
User Scenarios
US-001: Detect and recognize
As a developer I want the system to find the spec folder in a repo and tell me if it's OpenSpec So that tooling can adapt to the project's spec convention Acceptance Criteria:
- Given a repo with
openspec/, detection returns formatopenspecand the spec root. - Given a repo with the orchestrata
specs/NNN-*/spec.mdlayout, detection returnsorchestrata. - Given neither, detection returns
unknown(no spec folder) without raising.
US-002: Create an OpenSpec capability spec
As a developer I want to create a new OpenSpec capability spec from a purpose + requirements So that I can add a capability in valid OpenSpec format Acceptance Criteria:
- The rendered
spec.mdhas## Purpose,## Requirements, and### Requirement:blocks. - Every requirement has at least one
#### Scenario:with WHEN/THEN bullets (OpenSpec rule). - Round-trip: parse(render(spec)) == spec (structurally).
US-003: Edit an existing OpenSpec spec
As a developer I want to add a requirement or a scenario to an existing OpenSpec spec So that I can evolve a capability without hand-editing markdown Acceptance Criteria:
- Adding a requirement/scenario preserves existing requirements and ordering.
- The result re-parses cleanly and still validates.
US-004: Scaffold an OpenSpec change
As a developer I want to scaffold a change proposal (proposal.md + tasks.md + a delta spec) So that a modification follows the OpenSpec change workflow Acceptance Criteria:
changes/<id>/proposal.mdhas## Whyand## What Changes.changes/<id>/tasks.mdhas at least one- [ ]task.- The delta
specs/<cap>/spec.mduses## ADDED Requirements(or MODIFIED/REMOVED).
Data Models
| Type | Fields |
|---|---|
SpecFolder |
root: Path, format: Literal["openspec","orchestrata","unknown"], capabilities: list[str], changes: list[str] |
Scenario |
name: str, lines: list[str] (WHEN/THEN/AND bullets) |
Requirement |
title: str, text: str (SHALL statement), scenarios: list[Scenario] |
OpenSpecDoc |
capability: str, purpose: str, requirements: list[Requirement] |
Delta |
operation: Literal["ADDED","MODIFIED","REMOVED","RENAMED"], requirements: list[Requirement] |
Functional Requirements
FR-001 — Locate the spec folder
REQ-104-001: Given a project root, locate a spec folder, preferringopenspec/, else the orchestrataspecs/layout; return None when absent (no raise).
FR-002 — Recognize the format
REQ-104-002: Classify a located folder asopenspecwhen it contains anopenspec/tree (project.md / specs / changes) or spec files using### Requirement:+#### Scenario:.REQ-104-003: Classify the orchestrataspecs/NNN-*/spec.md(Metadata + FR-/REQ-) layout asorchestrata; otherwiseunknown.
FR-003 — Parse OpenSpec
REQ-104-004: Parse a capabilityspec.mdinto anOpenSpecDoc(purpose + requirements, each with its scenarios and WHEN/THEN lines).REQ-104-005: Parse a change deltaspec.mdintoDeltaobjects keyed by ADDED/MODIFIED/REMOVED/RENAMED.
FR-004 — Create OpenSpec
REQ-104-006: Render anOpenSpecDocto valid OpenSpec markdown (## Purpose,## Requirements,### Requirement:,#### Scenario:); round-trips structurally.REQ-104-007: Scaffold a change underchanges/<id>/(proposal.md with Why/What Changes, tasks.md with a checklist, and a deltaspecs/<cap>/spec.md).
FR-005 — Edit OpenSpec
REQ-104-008: Add a requirement or add a scenario to an existingOpenSpecDoc, preserving existing content and order; re-render to markdown.
FR-006 — Validate OpenSpec
REQ-104-009: Validate a parsedOpenSpecDoc— each requirement has ≥1 scenario and a SHALL statement; report violations (do not raise).
FR-007 — Sandboxed writes
REQ-104-010: All file writes are confined to the detected spec root; paths escaping it are rejected.
Error Conditions
| ID | Trigger | Handling |
|---|---|---|
| ERR-104-001 | No spec folder found | detect() returns unknown/None; callers branch, no raise |
| ERR-104-002 | spec.md not valid OpenSpec (no ### Requirement:) |
parser returns an empty/partial doc + a diagnostic; no raise |
| ERR-104-003 | Requirement without a scenario | validation reports a violation (OpenSpec requires ≥1 scenario) |
| ERR-104-004 | Write path escapes the spec root | rejected with an error result |
| ERR-104-005 | Change id collides with an existing change | refuse to overwrite; return an error |
API Contracts
def detect_spec_folder(root: str | Path) -> SpecFolder: ...
def is_openspec(text: str) -> bool: ...
def parse_spec(text: str, capability: str = "") -> OpenSpecDoc: ...
def render_spec(doc: OpenSpecDoc) -> str: ...
def validate(doc: OpenSpecDoc) -> list[str]: ...
class OpenSpecRepo:
def __init__(self, root: str | Path) -> None: ...
def capabilities(self) -> list[str]: ...
def read_capability(self, name: str) -> OpenSpecDoc: ...
def write_capability(self, doc: OpenSpecDoc) -> Path: ...
def add_requirement(self, capability: str, requirement: Requirement) -> Path: ...
def create_change(self, change_id: str, why: str, what: list[str],
deltas: list[Delta], tasks: list[str]) -> Path: ...
Security Requirements
- SEC-104-001: File writes are confined to the detected spec root; traversal rejected (shared with SPEC-103 sandboxing).
- SEC-104-002:
create_changenever overwrites an existing change directory.
Dependencies
| Component | Spec | Purpose |
|---|---|---|
| Tool-Calling Refactor | SPEC-103 | The refactor agent may invoke these create/edit functions as tools |
| (stdlib only) | — | Parsing/rendering is pure Python (re/pathlib); no external deps |
Testing Requirements
- TST-104-001: Detection —
openspec/→openspec; orchestrataspecs/NNN-*→orchestrata; empty →unknown. - TST-104-002:
is_openspectrue for### Requirement:/#### Scenario:text, false for orchestrata FR-/REQ- text. - TST-104-003: Parse a sample OpenSpec spec → requirements + scenarios + WHEN/THEN captured.
- TST-104-004: Round-trip —
parse(render(doc))equalsdocstructurally. - TST-104-005: Edit — add_requirement / add scenario preserves existing content; re-parses + validates.
- TST-104-006: Delta parse —
## ADDED/MODIFIED/REMOVED Requirements→ Delta objects. - TST-104-007: create_change writes proposal.md/tasks.md/delta; refuses to overwrite (ERR-104-005); traversal rejected (SEC-104-001).
- TST-104-008: validate flags a requirement with no scenario (ERR-104-003).
Tests are pure (no LLM, no mocks, no network); run via the threadpool runner.
Definition of Done
- [ ]
orchestrata_ultimate.openspec: detector + model + parser + renderer/editor + repo (FR-001…007). - [ ]
@traceson the code referencesREQ-104-*. - [ ] Unit tests (TST-104-*) pass via the threadpool runner; test-review clean.
- [ ] Registered in SPEC_INVENTORY.
Revision History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1.0 | 2026-05-28 | Mohamed | Initial spec — OpenSpec format detect/parse/create/edit |