You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Specs currently have no lifecycle state. Any spec in the tree is implicitly active and included in context compilation. This issue adds a status field (with optional superseded-by and supersedes) to spec-lock.json so that specs can be marked as inactive or superseded, enabling use cases like ADR-style append-only workflows.
Motivation
When a team treats specs as append-only (creating a new spec to replace an old one instead of editing it), there is no way to tell specd that the old spec is no longer operative. Without this, stale specs would still be included in context and potentially mislead the agent.
This also unlocks using specs as a semantic vehicle for ADRs: a superseded ADR-spec is replaced by a new one, not edited — matching standard ADR conventions.
New fields in spec-lock.json
Status lives in spec-lock.json alongside schema and dependsOn. It is system infrastructure — CompileContext filters by it, so it cannot depend on metadata being regenerated.
status is optional; absence is treated as active — fully backwards compatible, no existing spec breaks. Valid values: active (default) | inactive | superseded
supersededBy is only meaningful when status: superseded; it is a workspace:capability-path spec-id
supersedes is informational — it links the new spec to the old one, enabling forward navigation
Written at archive time by the system, never edited directly by the user or LLM
spec-lock.json (#56) provides the immutable sidecar for schema identity and dependencies. status fits the same pattern — it is system infrastructure that must persist independently of metadata extraction. The content of a spec may have a human-visible ## Status section for readability, but the system reads status from spec-lock.json.
## Status section (optional, human-visible)
Specs may optionally include a ## Status section for human readability:
metadata.json may also contain status as a derived cache of the value in spec-lock.json, synced at archive time. This enables fast queries without reading the sidecar. If both exist and disagree, spec-lock.json is the source of truth.
Conflict detection with metadataExtraction
If metadataExtraction extracts a status from spec content that differs from what is in spec-lock.json, validation must fail. spec-lock.json is the source of truth — the content cannot implicitly contradict the sidecar. Same rule applies to dependsOn (see #56).
Overview
Specs currently have no lifecycle state. Any spec in the tree is implicitly active and included in context compilation. This issue adds a
statusfield (with optionalsuperseded-byandsupersedes) tospec-lock.jsonso that specs can be marked asinactiveorsuperseded, enabling use cases like ADR-style append-only workflows.Motivation
When a team treats specs as append-only (creating a new spec to replace an old one instead of editing it), there is no way to tell specd that the old spec is no longer operative. Without this, stale specs would still be included in context and potentially mislead the agent.
This also unlocks using specs as a semantic vehicle for ADRs: a superseded ADR-spec is replaced by a new one, not edited — matching standard ADR conventions.
New fields in
spec-lock.jsonStatus lives in
spec-lock.jsonalongsideschemaanddependsOn. It is system infrastructure —CompileContextfilters by it, so it cannot depend on metadata being regenerated.{ "schema": { "name": "schema-std", "version": 1 }, "status": "superseded", "supersededBy": "cli:spec-list-v2", "supersedes": "cli:spec-list", "dependsOn": [] }statusis optional; absence is treated asactive— fully backwards compatible, no existing spec breaks. Valid values:active(default) |inactive|supersededsupersededByis only meaningful whenstatus: superseded; it is aworkspace:capability-pathspec-idsupersedesis informational — it links the new spec to the old one, enabling forward navigationspec-lock.jsonmechanismDesign note: relationship to #56
spec-lock.json(#56) provides the immutable sidecar for schema identity and dependencies.statusfits the same pattern — it is system infrastructure that must persist independently of metadata extraction. The content of a spec may have a human-visible## Statussection for readability, but the system readsstatusfromspec-lock.json.## Statussection (optional, human-visible)Specs may optionally include a
## Statussection for human readability:This is informational only. The system reads
statusfromspec-lock.json, not from spec content.Affected specs
specs/core/spec-lock/spec.md— addstatus,supersededBy,supersedesfields to spec-lock.json formatspecs/core/compile-context/spec.md— add requirement: exclude specs wherestatus != activefrom context by defaultspecs/cli/spec-list/spec.md— default output toactivespecs only; add--statusflag for lifecycle filteringConstraints
statusfield must be treated asactive(no breaking change)supersededandinactivespecs must remain readable and navigable (e.g.specd spec show)compile-contextmust not includeinactiveorsupersededspecs unless explicitly requestedsuperseded-bymust be a validworkspace:capability-pathformat when presentRelated
Relationship to metadata.json
metadata.jsonmay also containstatusas a derived cache of the value inspec-lock.json, synced at archive time. This enables fast queries without reading the sidecar. If both exist and disagree,spec-lock.jsonis the source of truth.Conflict detection with metadataExtraction
If
metadataExtractionextracts astatusfrom spec content that differs from what is inspec-lock.json, validation must fail.spec-lock.jsonis the source of truth — the content cannot implicitly contradict the sidecar. Same rule applies todependsOn(see #56).