@trieungoctam/speckit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,12 +2,13 @@
2
2
 
3
3
  Speckit is a local-first Agile + TDD workflow compiler for agentic IDEs. It turns rough intent into specs, stories, TDD evidence, and native IDE instruction packs.
4
4
 
5
- It is inspired by the operating patterns in ClaudeKit, BMad Method, and Beads Viewer, but it does not fork their runtime. Speckit owns the workflow contract and generates adapters for the tools you already use.
5
+ Speckit owns the workflow contract and generates adapters for the tools you already use. The public product vocabulary is Speckit-only: Agile shaping, TDD execution, task graph triage, and IDE adapter compilation.
6
6
 
7
7
  ## Quickstart
8
8
 
9
9
  ```bash
10
10
  npx @trieungoctam/speckit@latest init --ide all
11
+ npx @trieungoctam/speckit@latest init --enterprise --ide all
11
12
  npx @trieungoctam/speckit@latest quick "Add checkout validation"
12
13
  npx @trieungoctam/speckit@latest review
13
14
  ```
@@ -24,9 +25,12 @@ speckit doctor
24
25
 
25
26
  ```text
26
27
  intent
28
+ -> start session
27
29
  -> shape
28
30
  -> plan
31
+ -> context
29
32
  -> story with acceptance criteria
33
+ -> sync / triage
30
34
  -> red test evidence
31
35
  -> minimal implementation
32
36
  -> green test evidence
@@ -41,15 +45,21 @@ For implementation stories, red-green-refactor evidence is mandatory. A story is
41
45
  | Command | Purpose |
42
46
  | --- | --- |
43
47
  | `speckit init` | Create `.speckit/` core rules and all IDE adapters. |
48
+ | `speckit init --enterprise` | Add flow, tool policy, and prompt harness files. |
44
49
  | `speckit init --ide <name>` | Generate one adapter: `claude-code`, `codex`, `antigravity`, `opencode`, or `cursor`. |
45
50
  | `speckit doctor` | Report required tools, optional integrations, test commands, and adapter readiness. |
51
+ | `speckit doctor --deep` | Verify core enterprise harness files. |
52
+ | `speckit start "<idea>"` | Create a durable session handoff and current context. |
46
53
  | `speckit shape "<intent>"` | Create a short spec contract. |
54
+ | `speckit context <story>` | Build the current implementation context from a story. |
47
55
  | `speckit quick "<intent>"` | Create one story plus matching TDD evidence file. |
48
56
  | `speckit plan "<intent>"` | Create PRD, architecture, story, and evidence skeletons. |
57
+ | `speckit triage` | Summarize synced story state without interactive graph commands. |
49
58
  | `speckit next` | Safely wraps `bv --robot-next --format json`. |
50
59
  | `speckit sync` | Export Speckit stories as beads-compatible JSONL metadata. |
51
60
  | `speckit run <story>` | Print the TDD execution handoff for a story. |
52
61
  | `speckit review` | Print the review checklist and current diff summary. |
62
+ | `speckit close <story>` | Create a closure checklist linked to the story and sync step. |
53
63
 
54
64
  ## Supported IDEs
55
65
 
@@ -2,7 +2,6 @@ import { spawnSync } from "node:child_process";
2
2
  const tools = [
3
3
  ["git", true, "Install Git and run Speckit inside a repository."],
4
4
  ["node", true, "Install Node.js 20 or newer."],
5
- ["ck", false, "Recommended for ClaudeKit-style skills and workflows."],
6
5
  ["br", false, "Recommended beads CLI. Use bd only for older projects."],
7
6
  ["bd", false, "Legacy beads CLI fallback."],
8
7
  ["bv", false, "Recommended for Beads Viewer robot commands."],
package/dist/cli.js CHANGED
@@ -1,12 +1,16 @@
1
1
  import { initCommand } from "./commands/init.js";
2
2
  import { doctorCommand } from "./commands/doctor.js";
3
+ import { startCommand } from "./commands/start.js";
3
4
  import { shapeCommand } from "./commands/shape.js";
5
+ import { contextCommand } from "./commands/context.js";
4
6
  import { quickCommand } from "./commands/quick.js";
5
7
  import { planCommand } from "./commands/plan.js";
8
+ import { triageCommand } from "./commands/triage.js";
6
9
  import { nextCommand } from "./commands/next.js";
7
10
  import { syncCommand } from "./commands/sync.js";
8
11
  import { runCommand } from "./commands/run.js";
9
12
  import { reviewCommand } from "./commands/review.js";
13
+ import { closeCommand } from "./commands/close.js";
10
14
  export async function main(argv = process.argv.slice(2), root = process.cwd()) {
11
15
  const parsed = parseArgs(argv);
12
16
  try {
@@ -16,15 +20,22 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
16
20
  root,
17
21
  ide: value(parsed, "ide"),
18
22
  force: has(parsed, "force"),
23
+ enterprise: has(parsed, "enterprise"),
19
24
  });
20
25
  case "doctor":
21
- return doctorCommand({ root, json: has(parsed, "json") });
26
+ return doctorCommand({ root, json: has(parsed, "json"), deep: has(parsed, "deep") });
27
+ case "start":
28
+ return startCommand({ root, intent: requiredIntent(parsed) });
22
29
  case "shape":
23
30
  return shapeCommand({ root, intent: requiredIntent(parsed) });
31
+ case "context":
32
+ return contextCommand({ root, target: requiredIntent(parsed) });
24
33
  case "quick":
25
34
  return quickCommand({ root, intent: requiredIntent(parsed) });
26
35
  case "plan":
27
36
  return planCommand({ root, intent: requiredIntent(parsed) });
37
+ case "triage":
38
+ return triageCommand({ root, json: has(parsed, "json") });
28
39
  case "next":
29
40
  return nextCommand();
30
41
  case "sync":
@@ -33,6 +44,8 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
33
44
  return runCommand({ root, target: requiredIntent(parsed) });
34
45
  case "review":
35
46
  return reviewCommand({ root });
47
+ case "close":
48
+ return closeCommand({ root, target: requiredIntent(parsed) });
36
49
  case "help":
37
50
  case "":
38
51
  printHelp();
@@ -88,14 +101,19 @@ function printHelp() {
88
101
 
89
102
  Usage:
90
103
  speckit init [--ide all|claude-code|codex|antigravity|opencode|cursor] [--force]
91
- speckit doctor [--json]
104
+ speckit init --enterprise [--ide all] [--force]
105
+ speckit doctor [--json] [--deep]
106
+ speckit start "<idea>"
92
107
  speckit shape "<intent>"
108
+ speckit context <story-path-or-id>
93
109
  speckit quick "<intent>"
94
110
  speckit plan "<intent>"
111
+ speckit triage [--json]
95
112
  speckit next
96
113
  speckit sync
97
114
  speckit run <story-path-or-id>
98
115
  speckit review
116
+ speckit close <story-path-or-id>
99
117
  `);
100
118
  }
101
119
  if (import.meta.url === `file://${process.argv[1]}`) {
@@ -0,0 +1,6 @@
1
+ export type CloseOptions = {
2
+ root: string;
3
+ target: string;
4
+ stdout?: Pick<typeof console, "log" | "error">;
5
+ };
6
+ export declare function closeCommand(options: CloseOptions): Promise<number>;
@@ -0,0 +1,34 @@
1
+ import { markdown, writeManagedFiles } from "../core/managed-files.js";
2
+ import { slugify, timestamp } from "../core/slug.js";
3
+ import { resolveStory } from "../core/story.js";
4
+ export async function closeCommand(options) {
5
+ const stdout = options.stdout ?? console;
6
+ const story = await resolveStory(options.root, options.target);
7
+ if (!story) {
8
+ stdout.error(`Story not found: ${options.target}`);
9
+ return 1;
10
+ }
11
+ const closePath = `.speckit/closures/${timestamp()}-${slugify(story.id)}.md`;
12
+ await writeManagedFiles(options.root, [
13
+ {
14
+ path: closePath,
15
+ content: markdown(`# Spec Close: ${story.title}
16
+
17
+ ## Story
18
+ \`${story.path}\`
19
+
20
+ ## Required Verification
21
+ - [ ] Acceptance criteria reviewed
22
+ - [ ] TDD evidence reviewed
23
+ - [ ] Tests passed
24
+ - [ ] Docs impact recorded
25
+ - [ ] Graph sync completed with \`speckit sync\`
26
+
27
+ ## Review Command
28
+ \`speckit review\`
29
+ `),
30
+ },
31
+ ]);
32
+ stdout.log(closePath);
33
+ return 0;
34
+ }
@@ -0,0 +1,6 @@
1
+ export type ContextOptions = {
2
+ root: string;
3
+ target: string;
4
+ stdout?: Pick<typeof console, "log" | "error">;
5
+ };
6
+ export declare function contextCommand(options: ContextOptions): Promise<number>;
@@ -0,0 +1,53 @@
1
+ import { markdown, writeManagedFiles } from "../core/managed-files.js";
2
+ import { resolveStory } from "../core/story.js";
3
+ export async function contextCommand(options) {
4
+ const stdout = options.stdout ?? console;
5
+ const story = await resolveStory(options.root, options.target);
6
+ if (!story) {
7
+ stdout.error(`Story not found: ${options.target}`);
8
+ return 1;
9
+ }
10
+ const contextPath = ".speckit/context/current.md";
11
+ await writeManagedFiles(options.root, [
12
+ {
13
+ path: contextPath,
14
+ content: markdown(`# Current Spec Context
15
+
16
+ ## Story
17
+ ${story.title}
18
+
19
+ ## Story Path
20
+ \`${story.path}\`
21
+
22
+ ## Acceptance Criteria
23
+ ${extractSection(story.content, "Acceptance Criteria") ?? "- Not defined"}
24
+
25
+ ## TDD Evidence
26
+ ${extractEvidenceReference(story.content) ?? "- Create or update matching `.speckit/evidence/*tdd-evidence.md`"}
27
+
28
+ ## Next Command
29
+ \`speckit run ${story.id}\`
30
+ `),
31
+ },
32
+ ], true);
33
+ stdout.log(contextPath);
34
+ return 0;
35
+ }
36
+ function extractEvidenceReference(content) {
37
+ const match = content.match(/`([^`]*tdd-evidence\.md)`/i);
38
+ return match ? `\`${match[1]}\`` : undefined;
39
+ }
40
+ function extractSection(content, heading) {
41
+ const lines = content.split("\n");
42
+ const start = lines.findIndex((line) => line.trim().toLowerCase() === `## ${heading}`.toLowerCase());
43
+ if (start === -1)
44
+ return undefined;
45
+ const collected = [];
46
+ for (const line of lines.slice(start + 1)) {
47
+ if (line.startsWith("## "))
48
+ break;
49
+ if (line.trim())
50
+ collected.push(line);
51
+ }
52
+ return collected.length > 0 ? collected.join("\n") : undefined;
53
+ }
@@ -1,6 +1,7 @@
1
1
  export type DoctorOptions = {
2
2
  root: string;
3
3
  json?: boolean;
4
+ deep?: boolean;
4
5
  stdout?: Pick<typeof console, "log">;
5
6
  };
6
7
  export declare function doctorCommand(options: DoctorOptions): Promise<number>;
@@ -3,10 +3,12 @@ import { join } from "node:path";
3
3
  import { getAdapters } from "../config/adapter-registry.js";
4
4
  import { checkTools } from "../adapters/tool-checks.js";
5
5
  import { detectTestCommands } from "../core/test-detection.js";
6
+ import { coreFiles, enterpriseFiles } from "../core/scaffold.js";
6
7
  export async function doctorCommand(options) {
7
8
  const stdout = options.stdout ?? console;
8
9
  const tools = checkTools();
9
10
  const tests = await detectTestCommands(options.root);
11
+ const deepChecks = options.deep ? await runDeepChecks(options.root) : [];
10
12
  const adapters = await Promise.all(getAdapters("all").map(async (adapter) => ({
11
13
  name: adapter.name,
12
14
  ...(await adapterStatus(options.root, adapter.outputPaths)),
@@ -15,8 +17,9 @@ export async function doctorCommand(options) {
15
17
  node: process.versions.node,
16
18
  tools,
17
19
  tests,
20
+ deepChecks,
18
21
  adapters,
19
- status: tools.filter((tool) => tool.required && !tool.available).length === 0 ? "ok" : "needs-attention",
22
+ status: statusFor(tools, deepChecks),
20
23
  };
21
24
  if (options.json) {
22
25
  stdout.log(JSON.stringify(report, null, 2));
@@ -26,12 +29,37 @@ export async function doctorCommand(options) {
26
29
  stdout.log(`Node: ${report.node}`);
27
30
  stdout.log(`Tools: ${tools.map((tool) => `${tool.name}=${tool.available ? "ok" : "missing"}`).join(", ")}`);
28
31
  stdout.log(`Tests: ${tests[0]?.command ?? "not detected"}`);
32
+ for (const check of deepChecks) {
33
+ stdout.log(`Deep ${check.name}: ${check.ok ? "ok" : "missing"}`);
34
+ }
29
35
  for (const adapter of adapters) {
30
36
  stdout.log(`Adapter ${adapter.name}: ${adapter.present}/${adapter.total} files present`);
31
37
  }
32
38
  }
33
39
  return report.status === "ok" ? 0 : 1;
34
40
  }
41
+ async function runDeepChecks(root) {
42
+ const requiredFiles = [...coreFiles(), ...enterpriseFiles()];
43
+ return Promise.all(requiredFiles.map(async (file) => ({
44
+ name: file.path,
45
+ path: file.path,
46
+ ok: await fileExists(root, file.path),
47
+ })));
48
+ }
49
+ async function fileExists(root, path) {
50
+ try {
51
+ await access(join(root, path));
52
+ return true;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ function statusFor(tools, deepChecks) {
59
+ const requiredToolsMissing = tools.some((tool) => tool.required && !tool.available);
60
+ const deepChecksMissing = deepChecks.some((check) => !check.ok);
61
+ return requiredToolsMissing || deepChecksMissing ? "needs-attention" : "ok";
62
+ }
35
63
  async function adapterStatus(root, paths) {
36
64
  const missing = [];
37
65
  for (const path of paths) {
@@ -2,6 +2,7 @@ export type InitOptions = {
2
2
  root: string;
3
3
  ide?: string;
4
4
  force?: boolean;
5
+ enterprise?: boolean;
5
6
  stdout?: Pick<typeof console, "log">;
6
7
  };
7
8
  export declare function initCommand(options: InitOptions): Promise<number>;
@@ -1,15 +1,17 @@
1
- import { coreFiles } from "../core/scaffold.js";
1
+ import { coreFiles, enterpriseFiles } from "../core/scaffold.js";
2
2
  import { writeManagedFiles } from "../core/managed-files.js";
3
3
  import { getAdapters } from "../config/adapter-registry.js";
4
4
  export async function initCommand(options) {
5
5
  const stdout = options.stdout ?? console;
6
6
  const selectedIde = options.ide ?? "all";
7
+ const baseFiles = options.enterprise ? [...coreFiles(), ...enterpriseFiles()] : coreFiles();
7
8
  const adapterFiles = getAdapters(selectedIde).flatMap((adapter) => adapter.render());
8
- const results = await writeManagedFiles(options.root, [...coreFiles(), ...adapterFiles], options.force ?? false);
9
+ const results = await writeManagedFiles(options.root, [...baseFiles, ...adapterFiles], options.force ?? false);
9
10
  const created = results.filter((result) => result.status === "created").length;
10
11
  const updated = results.filter((result) => result.status === "updated").length;
11
12
  const skipped = results.filter((result) => result.status === "skipped");
12
- stdout.log(`Speckit initialized: ${created} created, ${updated} updated, ${skipped.length} skipped.`);
13
+ const mode = options.enterprise ? "enterprise" : "standard";
14
+ stdout.log(`Speckit initialized (${mode}): ${created} created, ${updated} updated, ${skipped.length} skipped.`);
13
15
  for (const result of skipped) {
14
16
  stdout.log(`skipped ${result.path}: ${result.reason}`);
15
17
  }
@@ -1,15 +1,14 @@
1
- import { access } from "node:fs/promises";
2
- import { join } from "node:path";
1
+ import { resolveStory } from "../core/story.js";
3
2
  export async function runCommand(options) {
4
3
  const stdout = options.stdout ?? console;
5
- const storyPath = await resolveStory(options.root, options.target);
6
- if (!storyPath) {
4
+ const story = await resolveStory(options.root, options.target);
5
+ if (!story) {
7
6
  stdout.error(`Story not found: ${options.target}`);
8
7
  return 1;
9
8
  }
10
9
  stdout.log(`# Speckit TDD Run
11
10
 
12
- Story: ${storyPath}
11
+ Story: ${story.path}
13
12
 
14
13
  1. Read the story and acceptance criteria.
15
14
  2. Identify the smallest executable test that should fail.
@@ -23,20 +22,3 @@ Recommended handoff:
23
22
  `);
24
23
  return 0;
25
24
  }
26
- async function resolveStory(root, target) {
27
- const candidates = [
28
- target,
29
- `.speckit/stories/${target}`,
30
- `.speckit/stories/${target}.md`,
31
- ];
32
- for (const candidate of candidates) {
33
- try {
34
- await access(join(root, candidate));
35
- return candidate;
36
- }
37
- catch {
38
- // Try the next candidate.
39
- }
40
- }
41
- return undefined;
42
- }
@@ -0,0 +1,6 @@
1
+ export type StartOptions = {
2
+ root: string;
3
+ intent: string;
4
+ stdout?: Pick<typeof console, "log">;
5
+ };
6
+ export declare function startCommand(options: StartOptions): Promise<number>;
@@ -0,0 +1,47 @@
1
+ import { markdown, writeManagedFiles } from "../core/managed-files.js";
2
+ import { slugify, timestamp } from "../core/slug.js";
3
+ export async function startCommand(options) {
4
+ const stdout = options.stdout ?? console;
5
+ const sessionId = `${timestamp()}-${slugify(options.intent)}`;
6
+ const handoffPath = `.speckit/sessions/${sessionId}/handoff.md`;
7
+ const contextPath = ".speckit/context/current.md";
8
+ await writeManagedFiles(options.root, [
9
+ {
10
+ path: handoffPath,
11
+ content: markdown(`# Spec Session: ${sessionId}
12
+
13
+ ## Idea
14
+ ${options.intent}
15
+
16
+ ## Current Phase
17
+ shape
18
+
19
+ ## Linked Artifacts
20
+ - Context: \`${contextPath}\`
21
+
22
+ ## Next Command
23
+ \`speckit shape "${options.intent}"\`
24
+ `),
25
+ },
26
+ {
27
+ path: contextPath,
28
+ content: markdown(`# Current Spec Context
29
+
30
+ ## Session
31
+ ${sessionId}
32
+
33
+ ## Idea
34
+ ${options.intent}
35
+
36
+ ## Active Artifact
37
+ \`${handoffPath}\`
38
+
39
+ ## Next Command
40
+ \`speckit shape "${options.intent}"\`
41
+ `),
42
+ },
43
+ ], true);
44
+ stdout.log(sessionId);
45
+ stdout.log(handoffPath);
46
+ return 0;
47
+ }
@@ -1,6 +1,7 @@
1
1
  import { readdir, readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
3
  import { markdown, writeManagedFiles } from "../core/managed-files.js";
4
+ import { firstHeading } from "../core/story.js";
4
5
  export async function syncCommand(options) {
5
6
  const stdout = options.stdout ?? console;
6
7
  const storiesDir = join(options.root, ".speckit", "stories");
@@ -45,10 +46,3 @@ bv --robot-next --format json
45
46
  stdout.log(`Synced ${stories.length} stories to .speckit/sync/beads-sync.jsonl`);
46
47
  return 0;
47
48
  }
48
- function firstHeading(content) {
49
- return content
50
- .split("\n")
51
- .find((line) => line.startsWith("# "))
52
- ?.replace(/^#\s+/, "")
53
- .trim();
54
- }
@@ -0,0 +1,6 @@
1
+ export type TriageOptions = {
2
+ root: string;
3
+ json?: boolean;
4
+ stdout?: Pick<typeof console, "log" | "error">;
5
+ };
6
+ export declare function triageCommand(options: TriageOptions): Promise<number>;
@@ -0,0 +1,33 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ export async function triageCommand(options) {
4
+ const stdout = options.stdout ?? console;
5
+ const stories = await readSyncedStories(options.root);
6
+ const open = stories.filter((story) => story.status === "open");
7
+ const ready = stories.filter((story) => story.status !== "open");
8
+ const report = {
9
+ source: ".speckit/sync/beads-sync.jsonl",
10
+ open: open.length,
11
+ ready: ready.length,
12
+ next: open[0] ?? null,
13
+ };
14
+ if (options.json) {
15
+ stdout.log(JSON.stringify(report, null, 2));
16
+ return 0;
17
+ }
18
+ stdout.log(`Spec triage: ${open.length} open, ${ready.length} ready`);
19
+ stdout.log(open[0] ? `Next: ${open[0].id} (${open[0].path})` : "Next: none");
20
+ return 0;
21
+ }
22
+ async function readSyncedStories(root) {
23
+ try {
24
+ const content = await readFile(join(root, ".speckit", "sync", "beads-sync.jsonl"), "utf8");
25
+ return content
26
+ .split("\n")
27
+ .filter(Boolean)
28
+ .map((line) => JSON.parse(line));
29
+ }
30
+ catch {
31
+ return [];
32
+ }
33
+ }
@@ -1,2 +1,3 @@
1
1
  import { ManagedFile } from "./managed-files.js";
2
2
  export declare function coreFiles(): ManagedFile[];
3
+ export declare function enterpriseFiles(): ManagedFile[];
@@ -69,3 +69,49 @@ adapters:
69
69
  },
70
70
  ];
71
71
  }
72
+ export function enterpriseFiles() {
73
+ return [
74
+ {
75
+ path: ".speckit/flows/spec-flow.md",
76
+ content: markdown(`# Spec Flow
77
+
78
+ ## Order
79
+ start -> shape -> plan -> context -> sync -> triage -> run -> review -> close
80
+
81
+ ## Traceability
82
+ - A session links the original idea to every downstream artifact.
83
+ - A story links acceptance criteria to TDD evidence.
84
+ - Sync links stories to graph-ready JSONL.
85
+ - Close links review output back to story and graph sync.
86
+ `),
87
+ },
88
+ {
89
+ path: ".speckit/tool-policy.yaml",
90
+ content: text(`version: 1
91
+ phases:
92
+ shape:
93
+ may_edit_code: false
94
+ plan:
95
+ may_edit_code: false
96
+ run:
97
+ may_edit_code: true
98
+ requires_tdd_evidence: true
99
+ review:
100
+ may_edit_code: false
101
+ graph:
102
+ robot_only: true`),
103
+ },
104
+ {
105
+ path: ".speckit/prompts/spec-run.md",
106
+ content: markdown(`# Spec Run Prompt
107
+
108
+ 1. Read \`.speckit/context/current.md\`.
109
+ 2. Confirm story acceptance criteria.
110
+ 3. Write or run the failing test first.
111
+ 4. Implement the smallest change.
112
+ 5. Record red, green, and refactor evidence.
113
+ 6. Run \`speckit review\` before handoff.
114
+ `),
115
+ },
116
+ ];
117
+ }
@@ -0,0 +1,8 @@
1
+ export type StoryResolution = {
2
+ path: string;
3
+ content: string;
4
+ id: string;
5
+ title: string;
6
+ };
7
+ export declare function resolveStory(root: string, target: string): Promise<StoryResolution | undefined>;
8
+ export declare function firstHeading(content: string): string | undefined;
@@ -0,0 +1,33 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { basename, join } from "node:path";
3
+ export async function resolveStory(root, target) {
4
+ const candidates = [
5
+ target,
6
+ `.speckit/stories/${target}`,
7
+ `.speckit/stories/${target}.md`,
8
+ ];
9
+ for (const candidate of candidates) {
10
+ try {
11
+ const fullPath = join(root, candidate);
12
+ await access(fullPath);
13
+ const content = await readFile(fullPath, "utf8");
14
+ return {
15
+ path: candidate,
16
+ content,
17
+ id: basename(candidate).replace(/\.md$/, ""),
18
+ title: firstHeading(content) ?? basename(candidate).replace(/\.md$/, ""),
19
+ };
20
+ }
21
+ catch {
22
+ // Try the next candidate.
23
+ }
24
+ }
25
+ return undefined;
26
+ }
27
+ export function firstHeading(content) {
28
+ return content
29
+ .split("\n")
30
+ .find((line) => line.startsWith("# "))
31
+ ?.replace(/^#\s+/, "")
32
+ .trim();
33
+ }
@@ -6,7 +6,7 @@ Speckit MVP is implemented and pushed to `git@github.com:trieungoctam/speckit.gi
6
6
 
7
7
  Current package target: `@trieungoctam/speckit@0.1.0`.
8
8
 
9
- The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, supports five IDE adapters, wraps Beads Viewer safely, and has automated tests plus CI.
9
+ The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, supports five IDE adapters, wraps Beads Viewer safely, includes an enterprise harness, and has automated tests plus CI.
10
10
 
11
11
  ## Milestones
12
12
 
@@ -14,17 +14,18 @@ The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, s
14
14
  | --- | --- | --- |
15
15
  | Product contract | Complete | Contract, workflow model, and command surface documented. |
16
16
  | CLI scaffold | Complete | `bin/speckit`, TypeScript build, command router, managed file writer. |
17
- | Workflow engine | MVP Complete | `shape`, `plan`, `quick`, `run`, and `review` generate usable artifacts. |
17
+ | Workflow engine | Complete | `start`, `shape`, `plan`, `context`, `quick`, `sync`, `triage`, `run`, `review`, and `close` generate linked artifacts. |
18
18
  | IDE adapters | Complete | Claude Code, Codex, Antigravity, OpenCode, Cursor. |
19
19
  | Beads integration | MVP Complete | `next` wraps BV robot mode; `sync` exports story metadata JSONL. |
20
- | Validation | Complete | Build and `node:test` suite pass locally. |
20
+ | Enterprise harness | MVP Complete | `init --enterprise` creates flow, tool-policy, and prompt harness files; `doctor --deep` verifies them. |
21
+ | Validation | Complete | Build and `node:test` suite pass locally with flow contract gates. |
21
22
  | GitHub publish | Complete | Initial code pushed to `trieungoctam/speckit` at commit `7e5c582`; status docs follow-up in progress. |
22
23
  | npm package readiness | Ready | Package scoped as `@trieungoctam/speckit`; `npm pack --dry-run` passes. |
23
24
 
24
25
  ## Next Roadmap
25
26
 
26
- - Publish `@trieungoctam/speckit` to npm.
27
+ - Release Speckit-only vocabulary cleanup as `0.1.1` or fold it into `0.2.0`.
28
+ - Expand Speckit Enterprise Harness with richer profile and context-pack layers.
29
+ - Add graph commands: `graph-plan`, `insights`, and `drift`.
27
30
  - Add GitHub trusted publishing for npm releases.
28
- - Add richer config loading from `.speckit/config.yaml`.
29
- - Add optional direct `br`/`bd` import once command compatibility is pinned.
30
31
  - Add snapshot tests for full adapter file contents.
@@ -5,7 +5,7 @@ Speckit owns the workflow contract for enterprise Agile + TDD development with a
5
5
  ## Speckit Owns
6
6
 
7
7
  - The `.speckit/` source of truth: config, rules, workflows, templates, generated artifacts.
8
- - The command surface: `init`, `doctor`, `shape`, `plan`, `quick`, `next`, `sync`, `run`, `review`.
8
+ - The command surface: `init`, `doctor`, `start`, `shape`, `plan`, `context`, `quick`, `sync`, `triage`, `next`, `run`, `review`, `close`.
9
9
  - The TDD gate: code stories require red, green, and refactor evidence.
10
10
  - The adapter compiler for Claude Code, Codex, Antigravity, OpenCode, and Cursor.
11
11
  - The safety policy for destructive commands, secrets, production access, and review readiness.
@@ -13,15 +13,15 @@ Speckit owns the workflow contract for enterprise Agile + TDD development with a
13
13
  ## Speckit Delegates
14
14
 
15
15
  - Implementation to the selected IDE and agent runtime.
16
- - Product lifecycle inspiration to BMad-style phases, without copying BMad personas or branding.
17
- - Execution orchestration inspiration to ClaudeKit-style plan/cook/test/review flows.
16
+ - Product lifecycle, story readiness, and quality gates to Speckit-native phases.
17
+ - Execution orchestration to Speckit-native plan/run/test/review flows.
18
18
  - Task graph prioritization to beads and Beads Viewer robot commands.
19
19
  - Git, tests, CI, and deployment to project-local tooling.
20
20
 
21
21
  ## State Model
22
22
 
23
23
  ```text
24
- intake -> shaped -> planned -> sliced -> spec-ready -> tests-red -> running -> tests-green -> refactor -> review-ready -> closed
24
+ intake -> session -> shaped -> planned -> context-ready -> synced -> triaged -> tests-red -> running -> tests-green -> refactor -> review-ready -> closed
25
25
  ```
26
26
 
27
27
  Implementation starts only after a story is spec-ready. Review starts only after test evidence exists.
@@ -1,7 +1,36 @@
1
1
  # Project Changelog
2
2
 
3
+ ## 0.2.0 - 2026-05-10
4
+
5
+ ### Added
6
+
7
+ - Added enterprise harness generation with `speckit init --enterprise`.
8
+ - Added deep harness verification with `speckit doctor --deep`.
9
+ - Added linked flow commands: `start`, `context`, `triage`, and `close`.
10
+ - Added quality gates for Speckit-only vocabulary, flow linkage, adapter parity, and robot-safe graph commands.
11
+
12
+ ### Validation
13
+
14
+ - `npm run lint` passes.
15
+ - `npm test` passes with 21 tests.
16
+ - `npm pack --dry-run` passes.
17
+ - Full enterprise temp flow passes: `init --enterprise -> start -> quick -> context -> sync -> triage -> close -> doctor --deep`.
18
+
3
19
  ## 2026-05-10
4
20
 
21
+ ### Changed
22
+
23
+ - Migrated product vocabulary to Speckit-only workflow language.
24
+ - Added Spec Enterprise Harness planning and quality gates.
25
+ - Removed legacy workflow runtime checks from `speckit doctor`.
26
+ - Added enterprise flow commands for session start, story context, graph triage, and closure.
27
+
28
+ ### Quality
29
+
30
+ - Added forbidden vocabulary regression test.
31
+ - Added Spec flow contract tests for TDD linkage, adapter parity, and robot-safe graph commands.
32
+ - Added end-to-end command tests for `start`, `context`, `triage`, and `close`.
33
+
5
34
  ### Added
6
35
 
7
36
  - Created Speckit TypeScript CLI package.
@@ -9,6 +38,7 @@
9
38
  - Added GitHub repository metadata for `trieungoctam/speckit`.
10
39
  - Added GitHub Actions CI for lint, test, and package dry-run checks.
11
40
  - Added `init`, `doctor`, `shape`, `quick`, `plan`, `next`, `sync`, `run`, and `review` commands.
41
+ - Added `init --enterprise`, `doctor --deep`, `start`, `context`, `triage`, and `close` commands.
12
42
  - Added managed-file generation with overwrite protection.
13
43
  - Added native adapter generation for Claude Code, Codex, Antigravity, OpenCode, and Cursor.
14
44
  - Added Beads Viewer-safe `next` command using robot mode only.
@@ -21,7 +51,7 @@
21
51
  - `bin/speckit init --ide all` works in a temporary directory.
22
52
  - `npm run build` passes.
23
53
  - `npm run lint` passes.
24
- - `npm test` passes with 13 tests.
54
+ - `npm test` passes with 21 tests.
25
55
  - `npm pack --dry-run` passes.
26
56
 
27
57
  ### Published
@@ -12,7 +12,7 @@ Before publishing Speckit:
12
12
  - [x] Adapter output paths match `docs/adapters.md`.
13
13
  - [x] Cursor output uses `.cursor/rules/*.mdc`, not `.cursorrules`.
14
14
  - [x] `speckit next` only invokes `bv --robot-*`.
15
- - [ ] License and attribution review is complete for ClaudeKit, BMad Method, and Beads Viewer inspiration.
15
+ - [ ] License and attribution review is complete for Speckit, Speckit Method, and Beads Viewer inspiration.
16
16
  - [x] README quickstart is accurate.
17
17
  - [x] No secrets, local credentials, or generated private data are included.
18
18
  - [x] Initial code pushed to `git@github.com:trieungoctam/speckit.git`.
@@ -0,0 +1,68 @@
1
+ # Spec Enterprise Harness Plan
2
+
3
+ ## Goal
4
+
5
+ Speckit Enterprise must behave like one coherent Spec system, not a bundle of unrelated prompts.
6
+
7
+ The product vocabulary is Spec-only. External tools may exist underneath, but generated prompts, docs, commands, sessions, context packs, and adapter outputs must speak Speckit terms.
8
+
9
+ ## Operating Model
10
+
11
+ ```text
12
+ idea
13
+ -> spec start
14
+ -> spec shape
15
+ -> spec plan
16
+ -> spec context
17
+ -> graph triage
18
+ -> spec run
19
+ -> spec review
20
+ -> spec close
21
+ ```
22
+
23
+ ## Harness Layers
24
+
25
+ | Layer | Responsibility | Required Output |
26
+ | --- | --- | --- |
27
+ | Spec Flow | Phase order and state transitions | `.speckit/flows/*.md` |
28
+ | Spec Prompt | Phase-specific instructions | `.speckit/prompts/**/*.md` |
29
+ | Spec Session | Durable continuity across agents | `.speckit/sessions/<id>/*` |
30
+ | Spec Context | Bounded task context | `.speckit/context/current.md` |
31
+ | Spec Tool | Phase-aware allowed/denied actions | `.speckit/tool-policy.yaml` |
32
+ | Spec Graph | Work queue and priority bridge | `.speckit/graph/*` |
33
+ | IDE Compiler | Native adapter generation | IDE-specific config files |
34
+
35
+ ## Command Contract
36
+
37
+ ```bash
38
+ speckit init --enterprise --ide all
39
+ speckit doctor --deep
40
+ speckit start "<idea>"
41
+ speckit shape "<idea>"
42
+ speckit plan "<feature>"
43
+ speckit context <story-or-bead>
44
+ speckit triage
45
+ speckit next
46
+ speckit run <story-or-bead>
47
+ speckit review
48
+ speckit close <story-or-bead>
49
+ speckit sync
50
+ ```
51
+
52
+ ## Quality Gates
53
+
54
+ - Forbidden legacy vocabulary must not appear in publishable source, docs, tests, prompts, or generated adapter templates.
55
+ - Every implementation story must link to acceptance criteria and TDD evidence.
56
+ - Every run must have a session handoff.
57
+ - Every graph task must trace back to a story or spec artifact.
58
+ - Every review must check AC coverage, TDD evidence, tool policy, and docs impact.
59
+ - All robot task graph commands must use non-interactive flags.
60
+
61
+ ## Definition Of Enterprise Ready
62
+
63
+ - `speckit init --enterprise --ide all` creates a complete harness in a temp repo.
64
+ - `speckit doctor --deep --json` returns stable machine-readable status.
65
+ - `speckit start -> context -> run -> review -> close` preserves a single session id.
66
+ - `speckit sync -> triage -> next` preserves story-to-graph traceability.
67
+ - All IDE adapters compile from the same Spec policies.
68
+ - Tests enforce vocabulary, flow links, adapter parity, and robot-safe graph commands.
@@ -0,0 +1,70 @@
1
+ # Spec Quality Gates
2
+
3
+ ## Vocabulary Gate
4
+
5
+ Publishable files must not contain legacy workflow brand names or command prefixes.
6
+
7
+ Allowed:
8
+
9
+ - `Speckit`
10
+ - `Spec`
11
+ - IDE names such as `Claude Code`
12
+ - external graph tool names such as `Beads` and `Beads Viewer`
13
+
14
+ Forbidden in publishable files:
15
+
16
+ - old workflow brand names
17
+ - old slash command prefixes
18
+ - old implementation command names
19
+
20
+ ## Flow Link Gate
21
+
22
+ Every phase must link to the next durable artifact.
23
+
24
+ | Phase | Input | Output | Required Link |
25
+ | --- | --- | --- | --- |
26
+ | start | idea | session | session id |
27
+ | shape | session | spec brief | session -> spec |
28
+ | plan | spec brief | PRD / architecture / story | spec -> plan |
29
+ | context | story | context pack | story -> context |
30
+ | sync | story | graph task | story -> task id |
31
+ | run | task/story | TDD evidence | task -> evidence |
32
+ | review | diff + evidence | review checklist | evidence -> review |
33
+ | close | review | changelog / graph close | review -> close |
34
+
35
+ ## Tool Gate
36
+
37
+ Tool permissions are phase-specific.
38
+
39
+ - Shape and plan may inspect files but should not edit implementation code.
40
+ - Run may edit code but must record TDD evidence.
41
+ - Review should inspect and test; it should not implement.
42
+ - Graph commands must never launch an interactive TUI.
43
+
44
+ ## Adapter Parity Gate
45
+
46
+ All supported IDEs must receive the same Speckit policy:
47
+
48
+ - Spec policy
49
+ - TDD policy
50
+ - Enterprise safety policy
51
+ - Session/context instructions
52
+ - Graph command safety
53
+
54
+ ## Release Gate
55
+
56
+ Before release:
57
+
58
+ ```bash
59
+ npm run lint
60
+ npm test
61
+ npm pack --dry-run
62
+ speckit doctor --json
63
+ ```
64
+
65
+ For enterprise releases:
66
+
67
+ ```bash
68
+ speckit init --enterprise --ide all
69
+ speckit doctor --deep --json
70
+ ```
@@ -24,4 +24,4 @@ bin/speckit
24
24
  user intent -> CLI command -> markdown/json artifact -> IDE adapter -> agent workflow
25
25
  ```
26
26
 
27
- The CLI does not depend on running ClaudeKit, BMad, or Beads code. External tools are optional integrations discovered at runtime.
27
+ The CLI does not depend on external workflow runtimes. Beads and Beads Viewer are optional integrations discovered at runtime.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trieungoctam/speckit",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Enterprise Agile + TDD workflow compiler for agentic IDEs.",
5
5
  "type": "module",
6
6
  "files": [