Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions openspec/changes/add-workspace-control-plane/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-11
174 changes: 174 additions & 0 deletions openspec/changes/add-workspace-control-plane/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
## Context

OpenSpec's current initialization and instruction-loading model is repo-local:

- `openspec init` scaffolds one project path at a time
- `openspec/config.yaml` is loaded relative to one project root
- legacy cleanup explicitly treats root `AGENTS.md` as user-owned content

That makes the current model a poor fit for multi-repo workspaces where teams want one shared control plane plus several sibling implementation repos.

The proposed solution is to add a first-class workspace layer above project repos without regressing the current single-repo flow.

## Goals / Non-Goals

**Goals:**

- provide a checked-in source of truth for multi-repo workspace topology
- support a dedicated control-plane repo pattern without requiring a monorepo
- scaffold and sync workspace files from a stable manifest
- generate a root router file for AGENTS-compatible assistants
- preserve repo-local `AGENTS.md` ownership boundaries
- keep single-repo `openspec init` behavior intact

**Non-Goals:**

- replacing per-repo OpenSpec initialization with workspace-only setup
- standardizing every possible assistant-specific router format in the first change
- recursively inferring arbitrary nested repository graphs
- making network calls or SCM-host assumptions during workspace discovery

## Decisions

### 1. Use a manifest as the source of truth

The workspace root SHALL store `openspec-workspace.yaml` as the authoritative description of the multi-repo topology.

Example shape:

```yaml
version: 1
controlPlane:
path: ./openspec-management
repos:
- name: auth
path: ./service-auth
role: implementation
instructions: ./service-auth/AGENTS.md
- name: payments
path: ./service-payments
role: implementation
instructions: ./service-payments/AGENTS.md
generation:
agentsRouter:
enabled: true
path: ./.agents.md
```

**Rationale:** a manifest is easier to validate, diff, and evolve than treating `.agents.md` as the primary contract.

### 2. Keep router files generated, not authoritative

Workspace router files such as `.agents.md` SHALL be rendered from manifest state.

**Rationale:** this keeps OpenSpec from reintroducing the older pattern of directly owning root and nested `AGENTS.md` files. User-authored repo-local instructions remain user-managed; OpenSpec only references them.

### 3. Add a separate `workspace` command group

Workspace behavior belongs under a dedicated command surface:

- `openspec workspace init`
- `openspec workspace sync`
- `openspec workspace doctor`

**Rationale:** `openspec init` is already well established as project-scoped. Mixing workspace semantics into that command would blur scope and make safety guarantees harder to communicate.

### 4. Default to sibling-directory discovery with explicit confirmation

Workspace discovery SHOULD scan immediate child directories of the chosen workspace root for:

- git repos
- existing `openspec/` directories
- `AGENTS.md` files

Discovered repos SHALL be presented for review before they are written to the manifest.

**Rationale:** sibling discovery matches the common `scm/` layout while avoiding hidden implicit behavior.

### 5. Keep control-plane scaffolding lightweight

The generated control-plane repo SHOULD start with:

- `AGENTS.md` for control-plane instructions
- `specs/` for shared schemas or cross-repo specs
- optional `README.md` describing the workspace contract

It MAY omit initializing a nested OpenSpec project until the team explicitly requests it.

**Rationale:** some teams want only a workspace map first; forcing full repo initialization would add ceremony.

## Command Behavior

### `openspec workspace init`

Responsibilities:

- choose or confirm workspace root
- discover sibling repos and candidate instruction files
- create `openspec-workspace.yaml`
- scaffold the control-plane repo if missing
- generate `.agents.md` when enabled

Key safety rules:

- SHALL not overwrite existing repo-local `AGENTS.md`
- SHALL not add discovered repos without review
- SHALL fail clearly if the target workspace root is not writable

### `openspec workspace sync`

Responsibilities:

- re-read `openspec-workspace.yaml`
- regenerate `.agents.md` and other generated workspace files
- optionally refresh control-plane boilerplate files that are OpenSpec-managed
- report drift between manifest and generated outputs

### `openspec workspace doctor`

Responsibilities:

- validate manifest structure
- detect missing repo paths or instruction files
- warn when generated router files are stale
- report collisions such as duplicate repo names or duplicate paths

## Router Generation

The initial generated `.agents.md` SHOULD be intentionally small and mechanical:

```md
# Workspace Router

@control-plane: ./openspec-management/AGENTS.md
@auth: ./service-auth/AGENTS.md
@payments: ./service-payments/AGENTS.md
```

Generation rules:

- include only repos present in the manifest
- use relative paths from the workspace root
- skip missing instruction files with a warning unless the manifest marks them required

## Risks / Trade-offs

**Risk: assistants interpret router syntax differently**
→ Mitigation: keep the manifest primary and router generation pluggable. `.agents.md` is only one output surface.

**Risk: discovery includes unrelated sibling repos**
→ Mitigation: review step before write, plus `workspace doctor` warnings for low-confidence entries.

**Risk: control-plane repo scope creeps into per-repo config**
→ Mitigation: keep project-root OpenSpec config unchanged; workspace manifest lives one level above individual repos.

**Trade-off: another config file to learn**
→ Acceptable because multi-repo topology is a distinct problem that does not fit cleanly into `openspec/config.yaml`.

## Rollout Plan

1. Add manifest types, parser, validator, and path-normalization helpers
2. Add `workspace init` with discovery and manifest writing
3. Add `.agents.md` generation and `workspace sync`
4. Add `workspace doctor` diagnostics
5. Document the control-plane pattern and migration guidance for existing teams
122 changes: 122 additions & 0 deletions openspec/changes/add-workspace-control-plane/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
## Why

OpenSpec currently assumes one active project root at a time. That works well for single-repo setups, but it leaves multi-repo teams without a standard way to keep agents grounded across a shared workspace.

A common real-world setup looks like this:

```text
scm/
├── openspec-management/
├── service-auth/
└── service-payments/
```

In this model, teams want:

- a dedicated control-plane repo for shared specs, schemas, and workspace metadata
- a predictable workspace manifest that maps sibling repos and their local agent instructions
- generated router files that help AGENTS-compatible assistants discover the full project map
- automation for initial scaffolding and later resync without requiring a monorepo

Today, users must assemble that structure by hand. OpenSpec has no first-class workspace concept, no checked-in manifest for multi-repo topology, and no CLI support for scaffolding or syncing a control-plane repo.

## What Changes

### 1. Add a first-class workspace model

Introduce a checked-in workspace manifest at the shared workspace root. This manifest becomes the source of truth for multi-repo topology and control-plane settings.

The initial format is `openspec-workspace.yaml` and includes:

- control-plane repo path
- member repo paths
- optional repo roles and tags
- local agent-instruction file paths when present
- generation settings for workspace-level router files

### 2. Add a dedicated workspace command surface

Introduce a new `openspec workspace` command group for multi-repo setup and maintenance:

- `openspec workspace init`
- `openspec workspace sync`
- `openspec workspace doctor`

These commands are distinct from `openspec init`, which remains project-scoped.

### 3. Scaffold a control-plane repo and workspace files

`openspec workspace init` scaffolds a control-plane repo such as `openspec-management/`, creates the workspace manifest, and optionally generates a root router file for AGENTS-compatible assistants.

The command SHOULD support starting from either:

- an existing shared parent directory containing sibling repos
- an empty target directory where the control-plane repo will be created first

### 4. Treat router files as generated outputs

OpenSpec SHALL treat agent-facing router files such as `.agents.md` as generated artifacts derived from the workspace manifest, not as the primary persisted contract.

This keeps the system tool-agnostic and avoids making OpenSpec responsible for owning every repo-local `AGENTS.md` file.

### 5. Support auto-discovery with explicit review

Workspace init/sync can scan sibling directories for candidate repos and local `AGENTS.md` files, but discovered entries SHALL be reviewed before being written into the manifest.

This avoids accidentally sweeping unrelated repos into the workspace map.

## Capabilities

### New Capabilities

- `cli-workspace`: Workspace-focused CLI commands for multi-repo scaffolding, sync, and diagnostics
- `workspace-manifest`: Checked-in manifest for control-plane configuration and repo topology

### Modified Capabilities

- `docs-agent-instructions`: Document workspace-generated router files and clarify ownership boundaries between user-authored local instructions and OpenSpec-generated workspace routing

## Impact

### New Files

- `src/commands/workspace.ts` - Register `workspace init|sync|doctor`
- `src/core/workspace/manifest.ts` - Manifest types, parsing, validation
- `src/core/workspace/discovery.ts` - Sibling repo and instruction-file discovery
- `src/core/workspace/sync.ts` - Manifest-driven file generation and drift checks
- `src/core/workspace/router-generation.ts` - Generate `.agents.md` and related router outputs

### Modified Files

- `src/cli/index.ts` - Register workspace commands
- `docs/cli.md` - Document workspace command group
- `docs/getting-started.md` or new workspace docs - Explain control-plane setup and workspace lifecycle

## Recommended UX

```text
$ openspec workspace init

Workspace root: /Users/alex/dev/scm
Control plane: ./openspec-management

Discovered sibling repos:
[x] service-auth ./service-auth
[x] service-payments ./service-payments
[ ] playground-scratch ./playground-scratch

Detected instruction files:
service-auth ./service-auth/AGENTS.md
service-payments ./service-payments/AGENTS.md

Create:
- openspec-workspace.yaml
- openspec-management/
- .agents.md
```

## Notes

- This proposal intentionally does not overload `openspec init` with workspace behavior.
- This proposal intentionally does not make OpenSpec the owner of every repo-local `AGENTS.md`.
- Tool-specific router generation beyond `.agents.md` can follow later once the manifest and command surface are in place.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
## ADDED Requirements

### Requirement: Workspace command group
The CLI SHALL provide a dedicated `openspec workspace` command group for multi-repo workspace management.

#### Scenario: Workspace commands are available
- **WHEN** a user runs `openspec --help`
- **THEN** the CLI SHALL list a `workspace` command group
- **AND** that group SHALL include `init`, `sync`, and `doctor` subcommands

### Requirement: Workspace initialization
`openspec workspace init` SHALL scaffold a multi-repo workspace from an explicit root directory.

#### Scenario: Initialize a sibling-repo workspace
- **GIVEN** a workspace root containing multiple sibling repositories
- **WHEN** the user runs `openspec workspace init`
- **THEN** the command SHALL discover candidate repos and instruction files
- **AND** SHALL present the discovered entries for review before writing files
- **AND** SHALL create `openspec-workspace.yaml` at the workspace root
- **AND** SHALL scaffold the configured control-plane repo when missing

#### Scenario: Preserve repo-local instruction ownership
- **WHEN** `openspec workspace init` encounters an existing repo-local `AGENTS.md`
- **THEN** the command SHALL reference that file in the workspace manifest or router output
- **AND** SHALL NOT overwrite the repo-local file

### Requirement: Workspace sync
`openspec workspace sync` SHALL regenerate workspace-managed outputs from the manifest.

#### Scenario: Regenerate workspace router
- **GIVEN** a valid `openspec-workspace.yaml`
- **WHEN** the user runs `openspec workspace sync`
- **THEN** the command SHALL regenerate `.agents.md` when router generation is enabled
- **AND** SHALL use relative paths derived from the manifest
- **AND** SHALL report generated or updated files in its summary

### Requirement: Workspace diagnostics
`openspec workspace doctor` SHALL validate workspace topology and generated outputs.

#### Scenario: Missing referenced repo path
- **GIVEN** a manifest entry whose `path` does not exist
- **WHEN** the user runs `openspec workspace doctor`
- **THEN** the command SHALL report the missing path as a validation problem

#### Scenario: Stale generated router
- **GIVEN** `.agents.md` content that does not match the current manifest
- **WHEN** the user runs `openspec workspace doctor`
- **THEN** the command SHALL report the router as stale
- **AND** SHALL suggest running `openspec workspace sync`
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## ADDED Requirements

### Requirement: Checked-in workspace manifest
The system SHALL represent multi-repo workspace topology in a checked-in manifest file at the workspace root.

#### Scenario: Workspace manifest path
- **WHEN** a workspace is initialized
- **THEN** the system SHALL create `openspec-workspace.yaml` at the workspace root
- **AND** that file SHALL be treated as the source of truth for workspace topology

### Requirement: Manifest schema
The workspace manifest SHALL describe the control-plane repo, member repos, and generated router settings.

#### Scenario: Manifest includes control-plane and repos
- **WHEN** a valid workspace manifest is loaded
- **THEN** it SHALL include a control-plane path
- **AND** it SHALL support a list of member repos with name and relative path
- **AND** it MAY include repo role, tags, and instruction-file path metadata

#### Scenario: Generated router settings
- **WHEN** router generation is configured
- **THEN** the manifest SHALL support generation settings including whether `.agents.md` is enabled and where it should be written

### Requirement: Relative path normalization
The manifest SHALL store paths relative to the workspace root.

#### Scenario: Persisting discovered repos
- **WHEN** `openspec workspace init` persists discovered sibling repos
- **THEN** the manifest SHALL normalize their paths as relative paths from the workspace root
- **AND** SHALL use cross-platform-safe path handling

### Requirement: Validation of collisions and missing data
The manifest loader SHALL reject invalid or ambiguous workspace definitions.

#### Scenario: Duplicate repo names
- **WHEN** two manifest entries declare the same repo name
- **THEN** validation SHALL fail with a clear error

#### Scenario: Duplicate repo paths
- **WHEN** two manifest entries resolve to the same relative path
- **THEN** validation SHALL fail with a clear error

#### Scenario: Missing required control-plane path
- **WHEN** the manifest omits the control-plane path
- **THEN** validation SHALL fail before workspace sync proceeds
Loading