OpenSpec Architecture: File-System Store and Spec-Driven Development Engine
OpenSpec is a spec-driven development platform built around a file-system-based store that separates system specifications from active changes, orchestrating AI-assisted workflows through a TypeScript core engine and CLI interface.
The Fission-AI/OpenSpec repository implements a spec-driven development methodology using a structured file system layout and modular TypeScript architecture. This platform sits between developers and AI assistants, managing the complete lifecycle of system changes—from proposal to implementation—through YAML and markdown specifications.
File-System Store Layout
OpenSpec architecture centers on a file-system-based store that organizes work into distinct directories separating the system state from active development.
The store maintains three primary locations:
openspec/specs/— The single source of truth containing YAML and markdown files that describe the current state of the entire system.openspec/changes/— A workspace for a single change containing proposals, delta specs, design documents, tasks, and implementation artifacts.openspec/changes/archive/— Archived changes that have been merged; once a change completes, its delta specs fold back intospecs/and the folder moves here.
This layout enforces a clear separation between canonical specifications and work-in-progress changes, enabling the platform to track the high-level flow:
proposal → specs → design → tasks → implement
Core Architecture Components
The OpenSpec architecture consists of eight interconnected modules that handle everything from store initialization to command execution.
Root Management
The Root Management module detects, validates, and creates the OpenSpec store layout. In src/core/openspec-root.ts, the system defines constants such as OPENSPEC_ROOT_DIR and OPENSPEC_SPECS_DIR, alongside functions inspectOpenSpecRoot and ensureOpenSpecRoot that enforce the required directory structure and validate store integrity.
Global Configuration
Global user settings—including profiles and AI tool configurations—are managed through src/core/global-config.ts. This module is re-exported from src/index.ts to provide user-wide settings that persist across projects.
Artifact Graph
The Artifact Graph models relationships between specifications, designs, tasks, and other artifacts while resolving dependencies. Core files include src/core/artifact-graph/graph.ts, src/core/artifact-graph/resolver.ts, and src/core/artifact-graph/outputs.ts. This graph structure enables the system to understand how changes in one specification affect related components.
Parsers
The Parsers module converts markdown and spec files into typed objects consumed by the engine. Key implementations reside in src/core/parsers/markdown-parser.ts, src/core/parsers/change-parser.ts, and src/core/parsers/requirement-blocks.ts, transforming human-readable specifications into structured data.
Command Generation
Dynamic CLI command construction happens in the Command Generation module. The file src/core/command-generation/generator.ts builds commands like opsx:propose and opsx:apply based on the selected workflow schema, automatically registering new workflows added to src/core/schemas/.
Store and Persistence
File-system operations are abstracted through the Store module in src/core/store/registry.ts, src/core/store/index.ts, and src/core/store/git.ts. This registry pattern supports multiple storage backends while providing consistent interfaces for reading, writing, and versioning specifications and changes.
CLI Layer
The user-facing interface is built on commander in src/cli/index.ts. This entry point registers top-level commands including init, list, view, change, and validate, wiring them to the appropriate core services and command classes such as ListCommand, ChangeCommand, and ValidateCommand.
Telemetry
Optional usage analytics are handled by src/telemetry/index.ts, providing insights into command usage and workflow patterns without compromising the local-first architecture.
How OpenSpec Components Work Together
The OpenSpec architecture follows a predictable lifecycle for bootstrapping projects and managing changes.
Bootstrapping begins with openspec init, implemented in src/core/init.ts, which calls ensureOpenSpecRoot to create the store layout, write a default config.yaml, and optionally anchor empty directories to ensure version control compatibility.
Command Dispatch flows through the CLI layer, which parses arguments, resolves the store root via resolveRootForCommand, and invokes the appropriate command class to execute user requests.
Change Lifecycle management creates new changes under openspec/changes/<name>/. The AI generates proposals and delta specs stored as markdown files. Upon completion, the ArchiveCommand merges these deltas into the main specs/ directory and moves the change folder to openspec/changes/archive/.
Validation occurs through src/core/validation/validator.ts, which walks the artifact graph, validates requirements against schemas, and produces JSON or human-readable reports ensuring specification integrity before implementation.
Extensibility is achieved by adding new workflow schemas to src/core/schemas/, which automatically become available to the CLI via the command-generation pipeline without modifying core command logic.
Working with OpenSpec Programmatically
You can interact with the OpenSpec architecture directly through its TypeScript API.
Inspecting the Store Programmatically
import { inspectOpenSpecRoot, ensureOpenSpecRoot } from
'https://github.com/Fission-AI/OpenSpec/blob/main/src/core/openspec-root.ts';
// Inspect an existing store
const inspection = await inspectOpenSpecRoot('/my/project');
console.log(inspection);
// Ensure a store exists (creates missing directories/files)
const result = await ensureOpenSpecRoot('/my/project', { anchorEmptyDirectories: true });
console.log(result.createdArtifacts);
Resolving the Artifact Graph
import { resolveArtifactGraph } from
'https://github.com/Fission-AI/OpenSpec/blob/main/src/core/artifact-graph/resolver.ts';
const graph = await resolveArtifactGraph('/my/project');
const spec = graph.getSpec('auth/login');
console.log(spec);
Common CLI Workflows
# Initialise a repository (creates openspec/ and config.yaml)
openspec init
# List all active changes
openspec list
# Propose a new change (AI drafts proposal, specs, design, tasks)
openspec propose add-dark-mode
# Apply the generated tasks (AI writes code)
openspec apply
# Archive the completed change (merges deltas into main specs)
openspec archive
Summary
- OpenSpec architecture separates canonical specifications (
openspec/specs/) from active changes (openspec/changes/) using a file-system-based store. - Eight core modules handle root management, configuration, artifact graphs, parsing, command generation, persistence, CLI interaction, and telemetry.
- The change lifecycle follows a spec-driven workflow: proposal → specs → design → tasks → implement → archive.
- Key files like
src/core/openspec-root.ts,src/core/artifact-graph/graph.ts, andsrc/cli/index.tsform the backbone of the TypeScript implementation. - Extensibility is built into the architecture through schema-based command generation and a registry pattern for store backends.
Frequently Asked Questions
How does OpenSpec maintain consistency between specs and implementation?
OpenSpec treats openspec/specs/ as the single source of truth while isolating work-in-progress in openspec/changes/. The ArchiveCommand ensures atomic merging of delta specs into the main directory only after validation passes, preventing drift between specifications and actual system state.
What is the role of the Artifact Graph in OpenSpec architecture?
The Artifact Graph, implemented in src/core/artifact-graph/graph.ts and src/core/artifact-graph/resolver.ts, maintains a dependency graph between specifications, designs, and tasks. It enables the system to resolve relationships, validate requirement blocks, and determine the correct order of operations when applying changes.
Can OpenSpec work with different storage backends?
Yes. While the default implementation uses the local file system, the Store module in src/core/store/registry.ts abstracts persistence operations through a registry pattern. This allows the architecture to support alternative backends such as Git-based storage or remote APIs without modifying the core engine logic.
How does the command generation system support custom workflows?
The command generation system in src/core/command-generation/generator.ts dynamically constructs CLI commands by reading workflow schemas from src/core/schemas/. Adding a new workflow automatically exposes commands like opsx:propose and opsx:apply specific to that schema, enabling domain-specific development patterns without rebuilding the CLI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →