Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
623264c
feat(openspec): bootstrap OpenSpec specs for commands domain
jimisola Jun 8, 2026
468671b
feat(openspec): add data-sources capability spec (Pass 3)
jimisola Jun 8, 2026
3a8901c
feat(openspec): add ingestion capability spec (Pass 3)
jimisola Jun 8, 2026
2e763a7
feat(openspec): add imports-and-filtering capability spec (Pass 3)
jimisola Jun 8, 2026
5b6be49
feat(openspec): add parse-validation capability spec (Pass 3)
jimisola Jun 8, 2026
dc643b1
feat(openspec): add lifecycle capability spec; complete Pass 3
jimisola Jun 8, 2026
ec86189
feat(reqstool): derive reqstool SSOT from OpenSpec specs (Pass 4)
jimisola Jun 8, 2026
ef02676
refactor(annotations): re-point source decorators to capability IDs (…
jimisola Jun 8, 2026
1a39477
docs(plan): update tracking for Pass 4 progress
jimisola Jun 8, 2026
67c00ea
refactor(openspec): thin specs to reqstool ID references (Pass 4)
jimisola Jun 8, 2026
7273329
test(reqstool): re-point test @SVCs to new IDs; restore reqstool_conf…
jimisola Jun 8, 2026
1f50c10
feat(reqstool): complete traceability — 71/71 requirements covered (P…
jimisola Jun 8, 2026
aa506d5
chore(openspec): install reqstool openspecui enrichment hook
jimisola Jun 8, 2026
2ccb68b
docs(openspec): title-case spec headings
jimisola Jun 8, 2026
9722760
test(reqstool): back every SVC with a real test; drop placeholders (#1)
jimisola Jun 8, 2026
35d8be4
refactor(reqstool): review derived requirement significance and categ…
jimisola Jun 8, 2026
9678908
fix(reqstool): address full-PR-review findings (test quality, annotat…
jimisola Jun 8, 2026
a39b4cf
docs: remove working planning notes from the PR
jimisola Jun 8, 2026
901fac9
test(reqstool): replace mistagged/parse-only SVCs with genuine behavi…
jimisola Jun 9, 2026
c75c976
test(reqstool): simplify status test setup
jimisola Jun 9, 2026
8571712
fix(reqstool): address remaining full-PR-review findings (annotation …
jimisola Jun 12, 2026
07bad13
Merge branch 'main' into worktree-feat+openspec-reqstool-bootstrap
jimisola Jun 13, 2026
bb27472
fix(reqstool): address round-4 full-PR-review findings (annotation pr…
jimisola Jun 13, 2026
cb97d1a
Merge branch 'main' into worktree-feat+openspec-reqstool-bootstrap
jimisola Jun 21, 2026
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
8 changes: 8 additions & 0 deletions .reqstool-ai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# reqstool-ai configuration — see https://github.com/reqstool/reqstool-ai
# Capability-prefixed IDs (STATUS_, REPORT_, ...) are managed by hand in
# requirements.yml; no per-module prefixes are configured for this single dataset.
urn: reqstool-client
revision: "0.11.0"

system:
path: docs/reqstool
22 changes: 0 additions & 22 deletions docs/reqstool/manual_verification_results.yml

This file was deleted.

1 change: 0 additions & 1 deletion docs/reqstool/reqstool_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ build: hatch
resources:
requirements: requirements.yml
software_verification_cases: software_verification_cases.yml
manual_verification_results: manual_verification_results.yml
annotations: ../../build/reqstool/annotations.yml
test_results:
- ../../build/**/*.xml
671 changes: 446 additions & 225 deletions docs/reqstool/requirements.yml

Large diffs are not rendered by default.

639 changes: 449 additions & 190 deletions docs/reqstool/software_verification_cases.yml

Large diffs are not rendered by default.

108 changes: 108 additions & 0 deletions openspec/openspecui.hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// @reqstool-openspec-hooks: 0.1.1
import { spawn, ChildProcess } from "child_process";
import type { OnReadDocumentHookV1 } from "openspecui/hooks";

// Minimal MCP client over stdio (JSON-RPC 2.0, newline-delimited).
// Uses only Node.js built-ins — no npm packages required.
class McpStdioClient {
private proc: ChildProcess;
private buf = "";
private pending = new Map<
number,
{ resolve: (v: unknown) => void; reject: (e: Error) => void }
>();
private id = 1;
readonly ready: Promise<void>;

constructor(cwd: string) {
this.proc = spawn("reqstool", ["mcp"], {
cwd,
stdio: ["pipe", "pipe", "pipe"],
});
this.proc.stdout!.on("data", (chunk: Buffer) => {
this.buf += chunk.toString();
let nl: number;
while ((nl = this.buf.indexOf("\n")) !== -1) {
const line = this.buf.slice(0, nl).trim();
this.buf = this.buf.slice(nl + 1);
if (line) this.handle(line);
}
});
this.ready = this.init();
}

private handle(line: string) {
try {
const msg = JSON.parse(line) as { id?: number; result?: unknown; error?: { message: string } };
if (msg.id !== undefined) {
const p = this.pending.get(msg.id);
if (p) {
this.pending.delete(msg.id);
msg.error ? p.reject(new Error(msg.error.message)) : p.resolve(msg.result);
}
}
} catch (e) {
console.warn("[reqstool-openspec] Skipping non-JSON line from reqstool mcp:", e instanceof Error ? e.message : e);
}
}

private send(method: string, params: unknown, expectReply = true): Promise<unknown> {
if (!expectReply) {
this.proc.stdin!.write(JSON.stringify({ jsonrpc: "2.0", method, params }) + "\n");
return Promise.resolve();
}
const id = this.id++;
return new Promise((resolve, reject) => {
this.pending.set(id, { resolve, reject });
this.proc.stdin!.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
});
}

private async init(): Promise<void> {
await this.send("initialize", {
protocolVersion: "2024-11-05",
capabilities: { tools: {} },
clientInfo: { name: "openspecui", version: "1.0" },
});
this.send("notifications/initialized", {}, false);
}

async enrich(content: string, preset: string): Promise<string> {
await this.ready;
const result = (await this.send("tools/call", {
name: "enrich_document",
arguments: { content, preset },
})) as { content: { text: string }[] };
return result.content[0].text;
}

close() {
this.proc.stdin?.end();
this.proc.kill();
}
}

let client: McpStdioClient | null = null;

export const onReadDocument: OnReadDocumentHookV1 = async (ctx, read) => {
if (!client) {
client = new McpStdioClient(ctx.projectDir);
ctx.lifecycle.onDispose(() => {
client?.close();
client = null;
});
}

const result = await read();
const preset = `openspec:${ctx.document.kind}`;

try {
const enriched = await client.enrich(result.markdown, preset);
return { ...result, markdown: enriched, sourceLabel: `reqstool ${preset}` };
} catch (e) {
return {
...result,
diagnostics: [{ level: "warning", message: `reqstool enrich failed: ${e}` }],
};
}
};
57 changes: 57 additions & 0 deletions openspec/specs/data-sources/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Data Sources Specification

## Purpose

Requirement and SVC content is owned by reqstool (single source of truth). This spec references
reqstool requirement and SVC IDs only; titles and descriptions are injected at read time via
`reqstool enrich` (or the openspecui hook). See `docs/reqstool/`.

## Requirements

### Requirement: SOURCE_0001
The system SHALL implement SOURCE_0001.

#### Scenario: SVC_SOURCE_0001
The system SHALL pass SVC_SOURCE_0001.

### Requirement: SOURCE_0002
The system SHALL implement SOURCE_0002.

#### Scenario: SVC_SOURCE_0002
The system SHALL pass SVC_SOURCE_0002.

### Requirement: SOURCE_0003
The system SHALL implement SOURCE_0003.

#### Scenario: SVC_SOURCE_0003
The system SHALL pass SVC_SOURCE_0003.

### Requirement: SOURCE_0004
The system SHALL implement SOURCE_0004.

#### Scenario: SVC_SOURCE_0004
The system SHALL pass SVC_SOURCE_0004.

### Requirement: SOURCE_0005
The system SHALL implement SOURCE_0005.

#### Scenario: SVC_SOURCE_0005
The system SHALL pass SVC_SOURCE_0005.

### Requirement: SOURCE_0006
The system SHALL implement SOURCE_0006.

#### Scenario: SVC_SOURCE_0006
The system SHALL pass SVC_SOURCE_0006.

### Requirement: SOURCE_0007
The system SHALL implement SOURCE_0007.

#### Scenario: SVC_SOURCE_0007
The system SHALL pass SVC_SOURCE_0007.

### Requirement: SOURCE_0008
The system SHALL implement SOURCE_0008.

#### Scenario: SVC_SOURCE_0008
The system SHALL pass SVC_SOURCE_0008.
33 changes: 33 additions & 0 deletions openspec/specs/enrich/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Enrich Specification

## Purpose

Requirement and SVC content is owned by reqstool (single source of truth). This spec references
reqstool requirement and SVC IDs only; titles and descriptions are injected at read time via
`reqstool enrich` (or the openspecui hook). See `docs/reqstool/`.

## Requirements

### Requirement: ENRICH_0001
The system SHALL implement ENRICH_0001.

#### Scenario: SVC_ENRICH_0001
The system SHALL pass SVC_ENRICH_0001.

### Requirement: ENRICH_0002
The system SHALL implement ENRICH_0002.

#### Scenario: SVC_ENRICH_0002
The system SHALL pass SVC_ENRICH_0002.

### Requirement: ENRICH_0003
The system SHALL implement ENRICH_0003.

#### Scenario: SVC_ENRICH_0003
The system SHALL pass SVC_ENRICH_0003.

### Requirement: ENRICH_0004
The system SHALL implement ENRICH_0004.

#### Scenario: SVC_ENRICH_0004
The system SHALL pass SVC_ENRICH_0004.
39 changes: 39 additions & 0 deletions openspec/specs/export/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Export Specification

## Purpose

Requirement and SVC content is owned by reqstool (single source of truth). This spec references
reqstool requirement and SVC IDs only; titles and descriptions are injected at read time via
`reqstool enrich` (or the openspecui hook). See `docs/reqstool/`.

## Requirements

### Requirement: EXPORT_0001
The system SHALL implement EXPORT_0001.

#### Scenario: SVC_EXPORT_0001
The system SHALL pass SVC_EXPORT_0001.

### Requirement: EXPORT_0002
The system SHALL implement EXPORT_0002.

#### Scenario: SVC_EXPORT_0002
The system SHALL pass SVC_EXPORT_0002.

### Requirement: EXPORT_0003
The system SHALL implement EXPORT_0003.

#### Scenario: SVC_EXPORT_0003
The system SHALL pass SVC_EXPORT_0003.

### Requirement: EXPORT_0004
The system SHALL implement EXPORT_0004.

#### Scenario: SVC_EXPORT_0004
The system SHALL pass SVC_EXPORT_0004.

### Requirement: EXPORT_0005
The system SHALL implement EXPORT_0005.

#### Scenario: SVC_EXPORT_0005
The system SHALL pass SVC_EXPORT_0005.
57 changes: 57 additions & 0 deletions openspec/specs/imports-and-filtering/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Imports and Filtering Specification

## Purpose

Requirement and SVC content is owned by reqstool (single source of truth). This spec references
reqstool requirement and SVC IDs only; titles and descriptions are injected at read time via
`reqstool enrich` (or the openspecui hook). See `docs/reqstool/`.

## Requirements

### Requirement: IMPORT_0001
The system SHALL implement IMPORT_0001.

#### Scenario: SVC_IMPORT_0001
The system SHALL pass SVC_IMPORT_0001.

### Requirement: IMPORT_0002
The system SHALL implement IMPORT_0002.

#### Scenario: SVC_IMPORT_0002
The system SHALL pass SVC_IMPORT_0002.

### Requirement: IMPORT_0003
The system SHALL implement IMPORT_0003.

#### Scenario: SVC_IMPORT_0003
The system SHALL pass SVC_IMPORT_0003.

### Requirement: IMPORT_0004
The system SHALL implement IMPORT_0004.

#### Scenario: SVC_IMPORT_0004
The system SHALL pass SVC_IMPORT_0004.

### Requirement: IMPORT_0005
The system SHALL implement IMPORT_0005.

#### Scenario: SVC_IMPORT_0005
The system SHALL pass SVC_IMPORT_0005.

### Requirement: IMPORT_0006
The system SHALL implement IMPORT_0006.

#### Scenario: SVC_IMPORT_0006
The system SHALL pass SVC_IMPORT_0006.

### Requirement: IMPORT_0007
The system SHALL implement IMPORT_0007.

#### Scenario: SVC_IMPORT_0007
The system SHALL pass SVC_IMPORT_0007.

### Requirement: IMPORT_0008
The system SHALL implement IMPORT_0008.

#### Scenario: SVC_IMPORT_0008
The system SHALL pass SVC_IMPORT_0008.
57 changes: 57 additions & 0 deletions openspec/specs/ingestion/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Ingestion Specification

## Purpose

Requirement and SVC content is owned by reqstool (single source of truth). This spec references
reqstool requirement and SVC IDs only; titles and descriptions are injected at read time via
`reqstool enrich` (or the openspecui hook). See `docs/reqstool/`.

## Requirements

### Requirement: INGEST_0001
The system SHALL implement INGEST_0001.

#### Scenario: SVC_INGEST_0001
The system SHALL pass SVC_INGEST_0001.

### Requirement: INGEST_0002
The system SHALL implement INGEST_0002.

#### Scenario: SVC_INGEST_0002
The system SHALL pass SVC_INGEST_0002.

### Requirement: INGEST_0003
The system SHALL implement INGEST_0003.

#### Scenario: SVC_INGEST_0003
The system SHALL pass SVC_INGEST_0003.

### Requirement: INGEST_0004
The system SHALL implement INGEST_0004.

#### Scenario: SVC_INGEST_0004
The system SHALL pass SVC_INGEST_0004.

### Requirement: INGEST_0005
The system SHALL implement INGEST_0005.

#### Scenario: SVC_INGEST_0005
The system SHALL pass SVC_INGEST_0005.

### Requirement: INGEST_0006
The system SHALL implement INGEST_0006.

#### Scenario: SVC_INGEST_0006
The system SHALL pass SVC_INGEST_0006.

### Requirement: INGEST_0007
The system SHALL implement INGEST_0007.

#### Scenario: SVC_INGEST_0007
The system SHALL pass SVC_INGEST_0007.

### Requirement: INGEST_0008
The system SHALL implement INGEST_0008.

#### Scenario: SVC_INGEST_0008
The system SHALL pass SVC_INGEST_0008.
Loading