Spec-driven Requirement/Scenario grammar + spec-delta lifecycle — internalise OpenSpec's best ideas into the Koder Stack's own spec infra
Document format reference: meta/docs/stack/policies/document-format.kmd
Status: ACCEPTED 2026-06-11 (owner). Ratification provenance: owner analysis request 2026-06-11 14:00 ("analise a OpenSpec, diga o que vale usarespecificar criar na Koder Stack") → recommendation delivered same session → owner directive "execute o que você recomendou na sua análise das 14:00" (Telegram, 2026-06-11 17:01). The recommendation was: do not adopt OpenSpec the tool; do internalise its two best ideas into the Stack's own spec infrastructure, grammar first. This RFC +
specs/kmd/requirement-scenario.kmdare phase 1 (done in the landing commit); phases 2–6 are tracked in thetarget_backlogof each owning component and auto-eligible viakoder-spec-audit rfc-phase-pickup.
1. Context & problem
OpenSpec is a lightweight spec-driven development framework for AI assistants. Its thesis: a requirement that lives only in chat is volatile, so you align on a written spec before coding. Its distinctive mechanisms are:
- Structured, testable requirements — RFC 2119 (
SHALL …) +#### Scenario:in GivenWhenThen.
- Change as a reviewable delta — a change folder (
proposal.md+tasks.md+specs/<cap>/spec.md) where the spec file is a diff against canonical (## ADDED / MODIFIED / REMOVED Requirements). - propose → apply → archive — on archive the delta is *erged
mechanically*into the canonical spec.
openspec validate+ averifyin three axes (Completeness / Correctness /Coherence).
The Koder Stack is already far more robust than OpenSpec in this category: .kmd (CommonMark superset with checked frontmatter, validated cross-refs, triggers:/gates); a corpus of ~74 spec dirs, 70+ policies, 13 stack RFCs and 35+ registries; koder-spec-audit + kmd lint; RFC phases: that auto-open backlog tickets when dependencies close; /k-test-gen that emits TDDs from a koder.manifest.json; and multi-session coordination via broadcast-alerts, locks and KVS concurrent-commit. Adopting OpenSpec as a tool would be a downgrade and would violate self-hosted-first.kmd.
But two ideas expose real gaps in our otherwise-stronger infra, and they are exactly OpenSpec's strengths:
- Gap A — no testable unit of obligation. Our specs are prose +
triggers:.There is no fine-grained, machine-consumable requirement that maps 1:1 to a test.
/k-test-gengenerates from the code manifest, not from the spec, so "did we build what the spec demands?" is not mechanically checkable. - Gap B — no spec-delta artifact. We evolve a spec by editing the canonical
.kmdin place in a commit; the "delta" is only thegit diff. There is no reviewable "this is what changes in spec X" artifact before the canonical changes, no conflict-free merge when two concurrent sessions touch the same spec (a real scenario here, with KVS multi-session + worktree-per-session landing in Stage 2), and no mechanical apply step.
2. Decision
Internalise both ideas natively, reusing existing machinery (RFC phases, backlog, kmd lint, koder-spec-audit, /k-test-gen) rather than building a parallel tool. Order by ROI:
- Requirement/Scenario grammar first (
specs/kmd/requirement-scenario.kmd)— closes Gap A. Highest ROI because the spec→test pipeline mostly exists: a
#### Scenario:is a test case, and/k-test-genalready emits TDDs. - Spec-delta lifecycle second — closes Gap B by extending RFC
phases:so aphase can carry a spec-delta that
koder-spec-auditvalidates and applies mechanically to the canonical.kmdon land. - Do not adopt OpenSpec / its CLI — redundant, weaker, and against
self-hosted-first.kmd.
3. The Requirement/Scenario grammar (Gap A)
Specified normatively in specs/kmd/requirement-scenario.kmd. Summary: ### Requirement: <Title> carrying an RFC-2119 obligation, with child #### Scenario: blocks in GivenWhenThen. The grammar is opt-in (prose specs stay valid) but normative once used. Each Scenario has a stable id (<spec-slug>#<requirement-slug>/<scenario-slug>) that becomes the traceability key across koder.manifest.json, the regression registry and generated tests. No new KMD tokens — it reuses H3/H4 headings and bullet lists, so the existing parser/renderer keep working.
The OpenSpec verify triad is realised as already-owned gates: Completeness = every Requirement has ≥1 Scenario; Correctness = every Scenario's THEN is asserted by a passing generated test; Coherence = cross-refs resolve and no two Scenarios contradict.
4. The spec-delta lifecycle (Gap B)
An RFC phase MAY declare a spec_delta: pointing at a delta .kmd whose body is:
## ADDED Requirements
### Requirement: …
## MODIFIED Requirements
### Requirement: …
## REMOVED Requirements
### Requirement: …koder-spec-audit validates the delta against the named canonical spec (every MODIFIED/REMOVED requirement must exist there; every ADDED must not). The delta is the reviewable artifact. On phase land, the audit applies the delta mechanically to the canonical .kmd and records the landing commit in the phase — exactly the propose→apply→archive cycle, mapped onto RFC phases + backlog + kmd lint we already run. This is what makes two concurrent sessions editing the same spec safe: they edit disjoint deltas, merged by requirement id rather than by line.
5. Phasing
See the phases: array in the frontmatter. Phase 1 (this RFC + the grammar spec) lands now. Phases 2–6 are eligible for koder-spec-audit rfc-phase-pickup as their depends_on close; tickets are pre-opened in each owning component's backlog so the work is concrete, not just declared.
6. Alternatives considered
- Adopt OpenSpec + its CLI — rejected: weaker than
.kmd/koder-spec-audit,introduces a second spec corpus, violates
self-hosted-first.kmd. - Grammar only, skip spec-delta — rejected: Gap B is real and grows with KVS
multi-session; but it is correctly second (depends on the requirement id from the grammar to merge deltas by id).
- Spec-delta first — rejected: lower immediate ROI and it needs the
Requirement unit to exist before deltas can target it.
7. Conformance with the Stack
Consulted before deciding (Rule 11): self-hosted-first.kmd (don't adopt the external tool — build native), reuse-first.kmd (extend RFC phases + kmd lint + k-test-gen, no parallel tool), document-format.kmd + content-location.kmd (spec under specs/kmd/, RFC under rfcs/, both .kmd), regression-tests.kmd §7 (Scenario closes the generator-coverage loop at the spec layer), and the rfc-frontmatter / RFC-003 phase-pickup contract (phases wired with target_backlog/depends_on).