Openspec Folder Reader
Requirement: Plugin reads the openspec folder and returns a structured representation
The function readOpenSpecFolder(dir: string): OpenSpecFolder SHALL scan the given directory and return a structured representation of all canonical specs, active changes, and archived changes.
Complete openspec folder
- WHEN
readOpenSpecFolder('./openspec')is called on a folder containingspecs/andchanges/ - THEN it returns an object with
specs: CapabilitySpec[],changes: Change[], andarchivedChanges: Change[]
Empty or missing folder
- WHEN
readOpenSpecFolder('./openspec')is called on a non-existent folder - THEN an error is thrown containing the folder path
Requirement: Canonical specs are read from openspec/specs/
For each subdirectory in openspec/specs/ that contains a spec.md, a CapabilitySpec object SHALL be created with name (directory name) and specPath (absolute path to spec.md).
Multiple capabilities
- WHEN
openspec/specs/contains directoriesnav-integration/andsidebar-generation/, each withspec.md - THEN the result contains two
CapabilitySpecentries with the correct names
Subdirectory without spec.md is ignored
- WHEN a subdirectory in
openspec/specs/contains nospec.md - THEN it is not included in the result
Requirement: Changes are read with their artifacts
For each subdirectory in openspec/changes/ (except archive/) that contains a .openspec.yaml, a Change object SHALL be created with name, artifacts (which of proposal/design/tasks are present), and metadata from .openspec.yaml.
Change with all artifacts
- WHEN
openspec/changes/my-feature/contains.openspec.yaml,proposal.md,design.md,tasks.md - THEN the Change object contains all three artifacts in
artifacts
Change with missing design
- WHEN
openspec/changes/my-feature/contains only.openspec.yamlandproposal.md - THEN
artifactscontains onlyproposal
Requirement: Archived changes are read from changes/archive/
Subdirectories in openspec/changes/archive/ SHALL be read as archived changes with the same fields as active changes, plus the date parsed from the directory name (YYYY-MM-DD-<name>).
Archived change
- WHEN
openspec/changes/archive/2026-03-10-my-feature/exists with.openspec.yaml - THEN an archived Change object is created with
archivedDate: '2026-03-10'andname: 'my-feature'
Requirement: title field from .openspec.yaml is read for changes
readOpenSpecFolder() MUST read an optional title field from .openspec.yaml and store it on the Change object as title?: string.
Change with title in .openspec.yaml
- WHEN
.openspec.yamlcontainstitle: "OpenAPI v3 Migration" - THEN the
Changeobject hastitle: 'OpenAPI v3 Migration'
Change without title field
- WHEN
.openspec.yamldoes not contain atitlefield - THEN the
Changeobject hastitle: undefined
Requirement: title frontmatter from spec.md is read for specs
readOpenSpecFolder() MUST parse the YAML frontmatter block of spec.md and extract an optional title field, storing it on the CapabilitySpec object as title?: string.
spec.md with frontmatter title
- WHEN
spec.mdbegins with---\ntitle: "REST API Docs"\n--- - THEN the
CapabilitySpecobject hastitle: 'REST API Docs'
spec.md without frontmatter
- WHEN
spec.mdhas no frontmatter block - THEN the
CapabilitySpecobject hastitle: undefined