opensdd 0.1.3 → 0.1.4

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/opensdd/cli.md CHANGED
@@ -24,41 +24,68 @@ Prints usage information including the current version, available commands, and
24
24
 
25
25
  ### `opensdd init`
26
26
 
27
- Initializes the OpenSDD protocol in the current project.
27
+ Initializes the OpenSDD protocol in the current project. Supports two modes:
28
28
 
29
- #### Behavior
30
-
31
- 1. Verify the current directory is a project root (contains `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `.git`, `opensdd.json`, or similar project markers). If no project marker is found, warn the user and ask for confirmation to proceed.
32
- 2. Install both skills (sdd-manager and sdd-generate) into all supported agent configuration directories. If already present, overwrite — skills are always spec-owned. The full installation mapping is defined in the **Skill Installation Mapping** section below.
33
- 3. If `opensdd.json` does not exist at the project root, create it with default contents: `{ "opensdd": "0.1.0", "specsDir": "opensdd", "depsDir": ".opensdd.deps" }`. The `registry`, `publish`, and `dependencies` fields are intentionally omitted from the default — they are optional. When `registry` is absent, the CLI defaults to `https://github.com/deepagents-ai/opensdd` per the registry source resolution logic. If `opensdd.json` already exists, leave it untouched.
34
- 4. Create the `opensdd/` directory (or the directory specified by `specsDir` in an existing `opensdd.json`) if it does not exist.
35
- 5. If `<specsDir>/spec.md` does not exist, create a skeleton `spec.md` with placeholder sections:
36
- ```markdown
37
- # {project-name}
38
-
39
- > TODO: One-line description of what this software does.
40
-
41
- ## Behavioral Contract
29
+ - **Consumer-only**: Install and implement dependency specs. Minimal footprint — only `sdd-manager` skill installed, no specs directory or skeleton `spec.md`.
30
+ - **OpenSDD-driven**: Full SDD methodology adoption. Both skills installed, specs directory and skeleton `spec.md` created.
42
31
 
43
- <!-- Define behaviors here. -->
32
+ Mode detection: presence of `specsDir` in `opensdd.json` = OpenSDD-driven. Absence = consumer-only.
44
33
 
45
- ## NOT Specified (Implementation Freedom)
46
-
47
- <!-- List aspects left to the implementer's discretion. -->
48
-
49
- ## Invariants
50
-
51
- <!-- List properties that must hold true across all inputs and states. -->
52
- ```
53
- The `{project-name}` placeholder SHOULD be inferred from the nearest project manifest (e.g., `name` in `package.json`) or default to the directory name. If `spec.md` already exists, leave it untouched.
54
- 6. Create the `.opensdd.deps/` directory (or the directory specified by `depsDir` in an existing `opensdd.json`) if it does not exist.
55
- 7. Print a success message.
34
+ #### Behavior
56
35
 
57
- - `opensdd init` in a fresh project MUST produce the output below
58
- - `opensdd init` in a project that already has OpenSDD initialized MUST overwrite all skill installation files across all agent formats but MUST NOT overwrite `opensdd.json`
36
+ 1. Verify the current directory is a project root (contains `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`, `.git`, `opensdd.json`, or similar project markers). If no project marker is found, warn the user and ask for confirmation to proceed.
37
+ 2. Read existing `opensdd.json` if present.
38
+ 3. Determine mode:
39
+ - **Existing manifest with `specsDir`** (OpenSDD-driven re-init): `mode = 'full'`. No prompt.
40
+ - **Existing manifest without `specsDir`** (consumer re-init): prompt "Upgrade to OpenSDD-driven? (y/n)". If yes, add `specsDir` to manifest and `mode = 'full'`. If no, `mode = 'consumer'`.
41
+ - **No manifest** (fresh init): prompt "How will this project use OpenSDD?" with numbered choices:
42
+ 1. Consumer only — install and implement dependency specs
43
+ 2. OpenSDD-driven — full SDD methodology (author specs, both skills)
44
+ Create manifest accordingly.
45
+ 4. Install skills with the determined mode. In consumer mode, only `sdd-manager` is installed. In full mode, both `sdd-manager` and `sdd-generate` are installed. The full installation mapping is defined in the **Skill Installation Mapping** section below. If already present, overwrite — skills are always spec-owned.
46
+ 5. Create the `.opensdd.deps/` directory (or the directory specified by `depsDir` in an existing `opensdd.json`) if it does not exist. (Both modes.)
47
+ 6. If `mode === 'full'`:
48
+ a. If `opensdd.json` does not exist at the project root, create it with default contents: `{ "opensdd": "0.1.0", "specsDir": "opensdd", "depsDir": ".opensdd.deps" }`. The `registry`, `publish`, and `dependencies` fields are intentionally omitted from the default — they are optional. When `registry` is absent, the CLI defaults to `https://github.com/deepagents-ai/opensdd` per the registry source resolution logic. If `opensdd.json` already exists, leave it untouched.
49
+ b. Create the `opensdd/` directory (or the directory specified by `specsDir` in the `opensdd.json`) if it does not exist.
50
+ c. If `<specsDir>/spec.md` does not exist, create a skeleton `spec.md` with placeholder sections:
51
+ ```markdown
52
+ # {project-name}
53
+
54
+ > TODO: One-line description of what this software does.
55
+
56
+ ## Behavioral Contract
57
+
58
+ <!-- Define behaviors here. -->
59
+
60
+ ## NOT Specified (Implementation Freedom)
61
+
62
+ <!-- List aspects left to the implementer's discretion. -->
63
+
64
+ ## Invariants
65
+
66
+ <!-- List properties that must hold true across all inputs and states. -->
67
+ ```
68
+ The `{project-name}` placeholder SHOULD be inferred from the nearest project manifest (e.g., `name` in `package.json`) or default to the directory name. If `spec.md` already exists, leave it untouched.
69
+ 7. If `mode === 'consumer'`: create `opensdd.json` with consumer-only contents: `{ "opensdd": "0.1.0", "depsDir": ".opensdd.deps" }` (no `specsDir`). If `opensdd.json` already exists, leave it untouched.
70
+ 8. Print a success message.
71
+
72
+ - `opensdd init` selecting OpenSDD-driven in a fresh project MUST produce the full output below
73
+ - `opensdd init` selecting consumer-only in a fresh project MUST produce the consumer output below
74
+ - `opensdd init` in a project that already has OpenSDD initialized (with `specsDir`) MUST overwrite all skill installation files across all agent formats but MUST NOT overwrite `opensdd.json`
75
+ - `opensdd init` in a consumer project MUST prompt to upgrade to OpenSDD-driven
59
76
 
60
77
  #### Output
61
78
 
79
+ Consumer-only (fresh):
80
+ ```
81
+ Initialized OpenSDD (consumer):
82
+ Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp
83
+ sdd-manager installed (6 agent formats)
84
+ opensdd.json created
85
+ .opensdd.deps/ created
86
+ ```
87
+
88
+ OpenSDD-driven (fresh):
62
89
  ```
63
90
  Initialized OpenSDD:
64
91
  Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp
@@ -70,7 +97,7 @@ Initialized OpenSDD:
70
97
  .opensdd.deps/ created
71
98
  ```
72
99
 
73
- If already initialized:
100
+ OpenSDD-driven (re-init):
74
101
  ```
75
102
  Initialized OpenSDD:
76
103
  Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp
@@ -89,7 +116,7 @@ Initialized OpenSDD:
89
116
 
90
117
  ### Skill Installation Mapping
91
118
 
92
- `opensdd init` installs both skills (sdd-manager and sdd-generate) into the native configuration format of each supported coding agent. The canonical skill content is authored as markdown source files in `opensdd/skills/` (`skills/sdd-manager.md`, `skills/sdd-generate.md`) and `opensdd/` (`spec-format.md`). Source skill files use Agent Skills frontmatter (`name`, `description`) which the CLI parses and transforms per-agent format during installation.
119
+ `opensdd init` installs skills into the native configuration format of each supported coding agent. In **consumer mode**, only `sdd-manager` is installed. In **full (OpenSDD-driven) mode**, both `sdd-manager` and `sdd-generate` are installed. The canonical skill content is authored as markdown source files in `opensdd/skills/` (`skills/sdd-manager.md`, `skills/sdd-generate.md`) and `opensdd/` (`spec-format.md`). Source skill files use Agent Skills frontmatter (`name`, `description`) which the CLI parses and transforms per-agent format during installation.
93
120
 
94
121
  All installed skill files are **spec-owned** — they are overwritten on every `opensdd init` and MUST NOT be edited by the user.
95
122
 
@@ -269,7 +296,7 @@ Fetches a spec from the registry and installs it as a dependency.
269
296
 
270
297
  #### Behavior
271
298
 
272
- 1. Verify `opensdd.json` exists at the project root. If not, print a message suggesting `opensdd init` first and exit with code 1.
299
+ 1. Verify `opensdd.json` exists at the project root. If not, auto-bootstrap as a consumer project: create a minimal `opensdd.json` (no `specsDir`), install consumer-mode skills, create the `.opensdd.deps/` directory, print "Auto-initialized OpenSDD (consumer).", and continue with the normal install flow.
273
300
  2. Check if the spec `<name>` already exists as a key in `opensdd.json`'s `dependencies` object. If it does AND the spec directory exists in `<depsDir>`, print a message indicating the spec is already installed and suggest `opensdd update` instead. Exit with code 1. If the entry exists BUT the spec directory is missing, treat as a re-install: log a message noting the stale entry, then continue to step 4 using the version from the existing entry (unless `[version]` is explicitly provided, in which case use that).
274
301
  3. Validate the spec name (lowercase alphanumeric and hyphens only).
275
302
  4. Fetch `index.json` from `registry/<name>/` in the configured registry source. If `[version]` is provided, use that version; otherwise use `latest` from `index.json`.
@@ -300,7 +327,6 @@ Run "implement the slugify spec" in your agent to generate an implementation.
300
327
  - Spec not found in registry: print error listing available specs and exit with code 1.
301
328
  - Requested version not found: print error listing available versions and exit with code 1.
302
329
  - Spec already installed (entry and directory both exist): print message suggesting `opensdd update` and exit with code 1.
303
- - OpenSDD not initialized: print message suggesting `opensdd init` and exit with code 1.
304
330
 
305
331
  ### `opensdd update [name]`
306
332
 
@@ -620,7 +646,9 @@ The CLI reads the existing `opensdd.json` dependency entry, applies updated meta
620
646
  - Running `opensdd update` when a pending update already exists for the spec: overwrite the existing staged update with the new one.
621
647
  - Running `opensdd update apply` when no pending updates exist: print "No pending updates." and exit with code 0 (not an error).
622
648
  - Running `opensdd update apply <name>` when the agent hasn't finished processing the changeset: the CLI has no way to verify this — it's the user's responsibility to confirm the migration is complete before applying.
623
- - Running `opensdd init` in a project that already has OpenSDD initialized: overwrite all skill installation files across all agent formats, leave `opensdd.json` untouched.
649
+ - Running `opensdd init` in a project that already has OpenSDD initialized (with `specsDir`): overwrite all skill installation files across all agent formats, leave `opensdd.json` untouched.
650
+ - Running `opensdd init` in a consumer-only project: prompt to upgrade to OpenSDD-driven. If declined, re-install consumer skills only.
651
+ - Running `opensdd install` in an uninitialized project: auto-bootstrap as consumer, then continue with install.
624
652
  - Running any command outside a project directory (no project markers found): warn but allow with confirmation, except `opensdd list` and `opensdd validate` which work anywhere.
625
653
  - Spec name contains characters invalid for directory names: reject with an error listing allowed characters (lowercase alphanumeric and hyphens).
626
654
  - Publishing a version that already exists in the registry: reject with an error suggesting a version bump.
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  name: sdd-generate
3
- description: "Generate an OpenSDD behavioral spec from existing code. Use when the user asks to generate, create, or extract a spec from a repository or codebase."
3
+ description: "Extract an OpenSDD behavioral spec from an existing codebase. Use when the user asks to generate, create, or extract a spec from a repository or codebase."
4
4
  ---
5
5
  # SDD Generate
6
6
 
7
- > Guides an AI agent through analyzing a repository and generating a behavioral spec in the OpenSDD format.
7
+ > Guides an AI agent through analyzing an existing codebase and extracting a behavioral spec in the OpenSDD format.
8
8
 
9
9
  ## Overview
10
10
 
@@ -1,20 +1,20 @@
1
1
  ---
2
2
  name: sdd-manager
3
- description: "Implement, update, and verify installed OpenSDD dependency specs. Use when the user asks to implement a spec, process a spec update, check conformance, or create a deviation."
3
+ description: "Manage OpenSDD specs — revise authored specs, implement dependency specs, process updates, check conformance, and create deviations. Use when the user asks to revise a spec, implement a spec, process a spec update, check conformance, or create a deviation."
4
4
  ---
5
5
  # SDD Manager
6
6
 
7
- > Teaches agents how to implement, update, and verify installed dependency specs in an OpenSDD-compliant project.
7
+ > Teaches agents how to revise authored specs, and implement, update, and verify dependency specs in an OpenSDD-compliant project.
8
8
 
9
9
  ## Overview
10
10
 
11
- The sdd-manager skill is installed once per project via `opensdd init` alongside the sdd-generate skill, into each supported coding agent's configuration directory. It teaches agents four workflows: implementing a spec, processing a spec update, checking conformance, and creating deviations. It also defines universal implementation defaults, the project conventions check, and the verification protocol that apply to all spec implementations.
11
+ The sdd-manager skill is installed once per project via `opensdd init` alongside the sdd-generate skill, into each supported coding agent's configuration directory. It teaches agents five workflows: revising an authored spec, implementing a dependency spec, processing a dependency spec update, checking conformance, and creating deviations. It also defines universal implementation defaults, the project conventions check, and the verification protocol that apply to all spec implementations.
12
12
 
13
- This skill is the required entry point whenever an agent reads an installed OpenSDD dependency spec to make changes to the project whether that is a first implementation, an incremental update, a conformance check, or a deviation. The agent MUST NOT implement or modify code based on an OpenSDD spec outside of the workflows defined here.
13
+ This skill is the required entry point whenever an agent works with OpenSDD specs whether revising the project's authored spec, implementing a dependency spec, processing a dependency update, checking conformance, or creating a deviation. The agent MUST NOT implement or modify code based on an OpenSDD spec outside of the workflows defined here.
14
14
 
15
15
  ## Spec as Source of Truth
16
16
 
17
- The dependency spec (`spec.md`) is the authoritative description of what to build. It is already a carefully structured behavioral contract with precise language, edge cases, and constraints. The agent MUST treat it as the primary reference throughout all workflows and MUST NOT replace it with a self-generated substitute.
17
+ The spec (`spec.md`) — whether an authored spec or an installed dependency — is the authoritative description of what to build. It is already a carefully structured behavioral contract with precise language, edge cases, and constraints. The agent MUST treat it as the primary reference throughout all workflows and MUST NOT replace it with a self-generated substitute.
18
18
 
19
19
  **Do not rewrite the spec into a plan.** The agent MUST NOT translate spec requirements into its own planning format (todo lists, step-by-step plans, internal summaries, etc.) as a substitute for the spec itself. Such translations are inherently lossy — they flatten nuance, drop edge cases, and shift intent. The spec's behavioral contract already defines what to build; duplicating it in another format adds no value and introduces drift.
20
20
 
@@ -22,10 +22,61 @@ The dependency spec (`spec.md`) is the authoritative description of what to buil
22
22
 
23
23
  **Plans are for additive context only.** If the agent uses planning tools (todo lists, scratchpads, plan mode, etc.), those plans MUST be limited to information that is _not_ in the spec: project-specific decisions (file paths, module structure, integration points), target language and framework details, implementation ordering, and deviations. Plans SHOULD reference spec sections by name rather than restating their content.
24
24
 
25
+ ## Workflow Identification
26
+
27
+ When entering any sdd-manager workflow, the agent MUST announce the active workflow to the user before proceeding. The announcement MUST include the workflow name, the target spec, and a one-line description of what will happen next.
28
+
29
+ Format:
30
+
31
+ > **[sdd-manager: {Workflow}]** {Target spec}
32
+ > {What the user should expect}
33
+
34
+ Examples:
35
+
36
+ > **[sdd-manager: Revise]** opensdd/cli.md
37
+ > I'll draft a changeset for your review before modifying the spec.
38
+
39
+ > **[sdd-manager: Implement]** .opensdd.deps/slugify/spec.md
40
+ > I'll walk you through the spec, then implement and verify.
41
+
42
+ > **[sdd-manager: Update]** .opensdd.deps/slugify
43
+ > Reading the staged changeset to identify what changed.
44
+
45
+ If the agent determines the wrong workflow was triggered, it MUST stop and clarify with the user before proceeding.
46
+
25
47
  ## Workflows
26
48
 
49
+ ### Revise
50
+
51
+ For incremental changes to the project's authored spec. The agent drafts a changeset for the user to review before modifying the spec or implementation.
52
+
53
+ 1. **Understand the request.** Read the user's description of the desired behavior change. Read the current spec from `<specsDir>/` (`spec.md` and any supplementary files).
54
+
55
+ 2. **Draft changeset.** Write a changeset to `<specsDir>/.changes/changeset.md` containing:
56
+ - **Rationale:** Why this change is being made — the user's request, the problem it solves, and any design decisions.
57
+ - **Changed Files:** For each spec file being modified, a unified diff showing the proposed changes. For new sections being added, show the full proposed content as an addition.
58
+
59
+ The changeset MUST be persisted to disk (not kept in conversation context) so it survives context window clears. The agent MUST NOT modify spec files or implementation code during this step.
60
+
61
+ 3. **Review.** Present the changeset to the user. Summarize what's changing and why. The user may:
62
+ - **Approve** — proceed to step 4.
63
+ - **Request modifications** — the agent updates the changeset and re-presents. The agent MUST re-read the changeset from disk before modifying it.
64
+ - **Reject** — delete `<specsDir>/.changes/` and stop.
65
+
66
+ The agent MUST NOT proceed past this step without explicit user approval.
67
+
68
+ 4. **Apply to spec.** Apply the approved diffs to the spec files. Delete `<specsDir>/.changes/` after successful application.
69
+
70
+ 5. **Implement.** Update the implementation to match the revised spec. Use the changeset to identify which behavioral sections changed — only modify code affected by the changes. The agent MUST re-read the updated spec sections directly (not work from the changeset diffs) when implementing.
71
+
72
+ 6. **Verify.** Execute the verification protocol (see Verification Protocol section below) scoped to the changed sections: regenerate affected tests, run until all pass, dispatch subagent for spec compliance audit scoped to the changed sections, fix any findings, re-run tests.
73
+
74
+ 7. **Report.** Summarize what changed in the spec and implementation. If the project has `publish` configured in `opensdd.json`, remind the user to bump the version before publishing.
75
+
27
76
  ### Implement
28
77
 
78
+ For first-time implementation of a dependency spec.
79
+
29
80
  1. **Read:** Read the dependency spec from `.opensdd.deps/<name>/` (`spec.md` and any supplementary files), `deviations.md` (if it exists), and other dependency specs it depends on.
30
81
 
31
82
  2. **Clarify (pre-implementation Q&A):** Before writing any code, the agent MUST walk the user through the spec's scope and structure and solicit clarifications. The agent MUST:
@@ -21,7 +21,7 @@ A project MAY be both an author (has `opensdd/spec.md`) and a consumer (has `.op
21
21
 
22
22
  In a monorepo, each sub-project that needs its own spec maintains its own `opensdd.json`, `opensdd/`, and `.opensdd.deps/` at its sub-project root — the same way each package in an npm workspace has its own `package.json`. The CLI always operates relative to the nearest `opensdd.json` in the directory hierarchy.
23
23
 
24
- The OpenSDD protocol installs two skills into the project: **sdd-manager** teaches agents how to implement, update, and verify installed dependency specs; **sdd-generate** teaches agents how to generate specs from existing code. Individual specs are not skills — they are data that the skills operate on.
24
+ The OpenSDD protocol installs two skills into the project: **sdd-manager** teaches agents how to revise authored specs and implement, update, and verify dependency specs; **sdd-generate** teaches agents how to extract a spec from an existing codebase. Individual specs are not skills — they are data that the skills operate on.
25
25
 
26
26
  Skills are installed into the native configuration format of each supported coding agent so they are automatically discovered. The canonical skill content follows the Agent Skills standard (agentskills.io) with `SKILL.md` files; adapter files are generated for agents with different configuration systems. See the CLI spec for the full installation mapping. Supported agents:
27
27
 
@@ -227,11 +227,12 @@ The CLI resolves `opensdd.json` by searching upward from the current working dir
227
227
 
228
228
  The development methodology for an OpenSDD-compliant repo:
229
229
 
230
- 1. **Edit the spec** — all behavior changes start in `opensdd/spec.md`. The spec is the source of truth.
231
- 2. **Update the code** — the developer or their AI agent updates the implementation to match the spec. The protocol is deliberately not prescriptive about this step — the agent reads the spec, understands what changed, and updates the code accordingly.
232
- 3. **Publish** — when the spec and implementation are in sync, the developer publishes the spec version to the registry via `opensdd publish`.
233
-
234
- The protocol does not mandate a specific tooling flow for step 2 (e.g., changesets, diffs). The spec is always readable in full, and any capable agent can compare the spec against the implementation to identify gaps.
230
+ 1. **Propose** — behavior changes are drafted as a changeset (rationale + unified diffs) staged in `<specsDir>/.changes/changeset.md`. The sdd-manager skill's Revise workflow guides this process.
231
+ 2. **Review** — the user reviews the proposed changeset, iterates if needed, and approves.
232
+ 3. **Apply** — the agent applies the approved changeset to the spec files and deletes the staging directory.
233
+ 4. **Implement** — the agent updates the implementation to match the revised spec, using the changeset to scope the changes.
234
+ 5. **Verify** the agent runs the verification protocol (tests + spec compliance audit) scoped to the changed sections.
235
+ 6. **Publish** — when the spec and implementation are in sync, the developer publishes the spec version to the registry via `opensdd publish`.
235
236
 
236
237
  #### Publishing
237
238
 
@@ -405,6 +406,10 @@ Captures everything the agent needs to understand and process the update without
405
406
  **Spec-format:** {old version} → {new version} (or "unchanged")
406
407
  **Date:** {ISO 8601 date}
407
408
 
409
+ ## Rationale (optional)
410
+
411
+ {Context for why this version was published. Omitted if not available from the registry.}
412
+
408
413
  ## Changed Files
409
414
 
410
415
  ### spec.md
@@ -438,13 +443,48 @@ Contains the metadata needed to finalize the `opensdd.json` dependency entry whe
438
443
 
439
444
  This is a transient artifact. `opensdd update apply` reads this file, applies the metadata to `opensdd.json`, and deletes the staging directory.
440
445
 
446
+ ### Authored Spec Staging
447
+
448
+ When a behavior change is proposed to the project's authored spec via the sdd-manager Revise workflow, the agent stages the changeset in `<specsDir>/.changes/`:
449
+
450
+ ```
451
+ opensdd/
452
+ .changes/
453
+ changeset.md # Rationale + unified diffs of proposed spec changes
454
+ spec.md # Unchanged until the changeset is approved and applied
455
+ ```
456
+
457
+ The staging directory is persisted to disk so it survives context window clears. It is deleted after the changeset is applied (or rejected).
458
+
459
+ #### changeset.md (authored spec)
460
+
461
+ ```markdown
462
+ # Changeset
463
+
464
+ **Date:** {ISO 8601 date}
465
+
466
+ ## Rationale
467
+
468
+ {Why this change is being made — the user's request, the problem it solves, and any design decisions made.}
469
+
470
+ ## Changed Files
471
+
472
+ ### {filename}
473
+
474
+ \`\`\`diff
475
+ {unified diff of proposed changes}
476
+ \`\`\`
477
+ ```
478
+
479
+ The rationale section distinguishes authored spec changesets from dependency update changesets. For dependency updates, the "why" is implicit in the version change. For authored spec changes, the "why" is the design decision being made and MUST be captured explicitly.
480
+
441
481
  ### SDD-Manager Skill
442
482
 
443
- The sdd-manager skill teaches agents how to implement, update, and verify installed dependency specs. It is installed once per project via `opensdd init` alongside the sdd-generate skill, into each supported agent's configuration directory. See [sdd-manager.md](skills/sdd-manager.md) for the full skill workflow, including implementation defaults, the project conventions check, and the verification protocol.
483
+ The sdd-manager skill teaches agents how to revise authored specs and implement, update, and verify dependency specs. It is installed once per project via `opensdd init` alongside the sdd-generate skill, into each supported agent's configuration directory. See [sdd-manager.md](skills/sdd-manager.md) for the full skill workflow, including implementation defaults, the project conventions check, and the verification protocol.
444
484
 
445
485
  ### SDD-Generate Skill
446
486
 
447
- The sdd-generate skill teaches agents how to generate a spec from existing code. See [sdd-generate.md](skills/sdd-generate.md) for the full skill workflow.
487
+ The sdd-generate skill teaches agents how to extract a behavioral spec from an existing codebase. See [sdd-generate.md](skills/sdd-generate.md) for the full skill workflow.
448
488
 
449
489
  ### Versioning
450
490
 
@@ -475,7 +515,7 @@ Specs use semantic versioning:
475
515
  - How spec dependencies are resolved when circular (not currently supported)
476
516
  - The sdd-generate skill's internal workflow (separate concern)
477
517
  - File encoding (assumed UTF-8)
478
- - How the author syncs implementation with spec changes (the protocol is deliberately not prescriptive about this)
518
+ - The exact wording of the sdd-manager workflow identification announcement
479
519
  - The exact mechanism for authenticating with the registry during publish (deferred to local git/gh credentials)
480
520
 
481
521
  ## Invariants
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opensdd",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "The official OpenSDD (Open Spec-Driven Development) CLI, spec, and spec registry",
5
5
  "type": "module",
6
6
  "bin": {
@@ -75,6 +75,18 @@ function promptYN(question) {
75
75
  });
76
76
  }
77
77
 
78
+ function promptChoice(question, choices) {
79
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
80
+ return new Promise((resolve) => {
81
+ const lines = choices.map((c, i) => ` ${i + 1}. ${c}`).join('\n');
82
+ rl.question(`${question}\n${lines}\nChoice: `, (answer) => {
83
+ rl.close();
84
+ const idx = parseInt(answer, 10);
85
+ resolve(idx >= 1 && idx <= choices.length ? idx : null);
86
+ });
87
+ });
88
+ }
89
+
78
90
  export async function initCommand() {
79
91
  const cwd = process.cwd();
80
92
 
@@ -88,23 +100,9 @@ export async function initCommand() {
88
100
  }
89
101
  }
90
102
 
91
- // Step 2: Install skills to all agent formats
92
- let warnings;
93
- try {
94
- warnings = installSkills(cwd);
95
- } catch (err) {
96
- console.error(`Error: Could not install skills: ${err.message}`);
97
- process.exit(1);
98
- }
99
-
100
- for (const w of warnings) {
101
- console.warn(`Warning: ${w}`);
102
- }
103
-
104
- // Step 3: Read or create opensdd.json
103
+ // Step 2: Read existing opensdd.json if present
105
104
  const manifestPath = path.join(cwd, 'opensdd.json');
106
105
  let manifest = null;
107
- let manifestCreated = false;
108
106
 
109
107
  if (fs.existsSync(manifestPath)) {
110
108
  try {
@@ -115,31 +113,84 @@ export async function initCommand() {
115
113
  }
116
114
  }
117
115
 
116
+ // Step 3: Determine mode
117
+ let mode;
118
+ let manifestCreated = false;
119
+
120
+ if (manifest && manifest.specsDir) {
121
+ // OpenSDD-driven re-init — no prompt needed
122
+ mode = 'full';
123
+ } else if (manifest && !manifest.specsDir) {
124
+ // Consumer re-init — offer upgrade
125
+ const upgrade = await promptYN('Upgrade to OpenSDD-driven? (y/n) ');
126
+ if (upgrade) {
127
+ mode = 'full';
128
+ manifest.specsDir = manifest.specsDir || 'opensdd';
129
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
130
+ } else {
131
+ mode = 'consumer';
132
+ }
133
+ } else {
134
+ // Fresh init — prompt for mode
135
+ const choice = await promptChoice('How will this project use OpenSDD?', [
136
+ 'Consumer only \u2014 install and implement dependency specs',
137
+ 'OpenSDD-driven \u2014 full SDD methodology (author specs, both skills)',
138
+ ]);
139
+ mode = choice === 2 ? 'full' : 'consumer';
140
+ }
141
+
142
+ // Step 4: Install skills
143
+ let warnings;
144
+ try {
145
+ warnings = installSkills(cwd, { mode });
146
+ } catch (err) {
147
+ console.error(`Error: Could not install skills: ${err.message}`);
148
+ process.exit(1);
149
+ }
150
+
151
+ for (const w of warnings) {
152
+ console.warn(`Warning: ${w}`);
153
+ }
154
+
155
+ // Step 5: Create or preserve opensdd.json
118
156
  if (!manifest) {
119
- manifest = {
120
- opensdd: '0.1.0',
121
- specsDir: 'opensdd',
122
- depsDir: '.opensdd.deps',
123
- };
157
+ if (mode === 'full') {
158
+ manifest = {
159
+ opensdd: '0.1.0',
160
+ specsDir: 'opensdd',
161
+ depsDir: '.opensdd.deps',
162
+ };
163
+ } else {
164
+ manifest = {
165
+ opensdd: '0.1.0',
166
+ depsDir: '.opensdd.deps',
167
+ };
168
+ }
124
169
  fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
125
170
  manifestCreated = true;
126
171
  }
127
172
 
128
- const specsDir = manifest.specsDir || 'opensdd';
129
173
  const depsDir = manifest.depsDir || '.opensdd.deps';
130
- const specsDirPath = path.join(cwd, specsDir);
131
174
  const depsDirPath = path.join(cwd, depsDir);
132
175
 
133
- // Step 4: Create specs directory
134
- const specsDirCreated = !fs.existsSync(specsDirPath);
135
- fs.mkdirSync(specsDirPath, { recursive: true });
176
+ // Step 6: Create deps directory (both modes)
177
+ const depsDirCreated = !fs.existsSync(depsDirPath);
178
+ fs.mkdirSync(depsDirPath, { recursive: true });
136
179
 
137
- // Step 5: Create skeleton spec.md
138
- const specMdPath = path.join(specsDirPath, 'spec.md');
180
+ // Step 7: Full mode — create specs directory and skeleton spec.md
181
+ let specsDirCreated = false;
139
182
  let specMdCreated = false;
140
- if (!fs.existsSync(specMdPath)) {
141
- const projectName = getProjectName(cwd);
142
- const skeleton = `# ${projectName}
183
+ if (mode === 'full') {
184
+ const specsDir = manifest.specsDir || 'opensdd';
185
+ const specsDirPath = path.join(cwd, specsDir);
186
+
187
+ specsDirCreated = !fs.existsSync(specsDirPath);
188
+ fs.mkdirSync(specsDirPath, { recursive: true });
189
+
190
+ const specMdPath = path.join(specsDirPath, 'spec.md');
191
+ if (!fs.existsSync(specMdPath)) {
192
+ const projectName = getProjectName(cwd);
193
+ const skeleton = `# ${projectName}
143
194
 
144
195
  > TODO: One-line description of what this software does.
145
196
 
@@ -155,30 +206,40 @@ export async function initCommand() {
155
206
 
156
207
  <!-- List properties that must hold true across all inputs and states. -->
157
208
  `;
158
- fs.writeFileSync(specMdPath, skeleton);
159
- specMdCreated = true;
209
+ fs.writeFileSync(specMdPath, skeleton);
210
+ specMdCreated = true;
211
+ }
160
212
  }
161
213
 
162
- // Step 6: Create deps directory
163
- const depsDirCreated = !fs.existsSync(depsDirPath);
164
- fs.mkdirSync(depsDirPath, { recursive: true });
165
-
166
- // Step 7: Print output
214
+ // Step 8: Print output
167
215
  const isReInit = !manifestCreated;
168
216
  const skillVerb = isReInit ? 'updated' : 'installed';
169
217
 
170
- console.log('Initialized OpenSDD:');
171
- console.log(
172
- ' Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp'
173
- );
174
- console.log(` sdd-manager ${skillVerb} (6 agent formats)`);
175
- console.log(` sdd-generate ${skillVerb} (6 agent formats)`);
176
- console.log(
177
- ` opensdd.json ${manifestCreated ? 'created' : 'already exists (preserved)'}`
178
- );
179
- console.log(` ${specsDir}/ ${specsDirCreated ? 'created' : 'already exists'}`);
180
- console.log(
181
- ` ${specsDir}/spec.md ${specMdCreated ? 'created (skeleton)' : 'already exists (preserved)'}`
182
- );
183
- console.log(` ${depsDir}/ ${depsDirCreated ? 'created' : 'already exists'}`);
218
+ if (mode === 'consumer') {
219
+ console.log('Initialized OpenSDD (consumer):');
220
+ console.log(
221
+ ' Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp'
222
+ );
223
+ console.log(` sdd-manager ${skillVerb} (6 agent formats)`);
224
+ console.log(
225
+ ` opensdd.json ${manifestCreated ? 'created' : 'already exists (preserved)'}`
226
+ );
227
+ console.log(` ${depsDir}/ ${depsDirCreated ? 'created' : 'already exists'}`);
228
+ } else {
229
+ const specsDir = manifest.specsDir || 'opensdd';
230
+ console.log('Initialized OpenSDD:');
231
+ console.log(
232
+ ' Skills installed for: Claude Code, Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Amp'
233
+ );
234
+ console.log(` sdd-manager ${skillVerb} (6 agent formats)`);
235
+ console.log(` sdd-generate ${skillVerb} (6 agent formats)`);
236
+ console.log(
237
+ ` opensdd.json ${manifestCreated ? 'created' : 'already exists (preserved)'}`
238
+ );
239
+ console.log(` ${specsDir}/ ${specsDirCreated ? 'created' : 'already exists'}`);
240
+ console.log(
241
+ ` ${specsDir}/spec.md ${specMdCreated ? 'created (skeleton)' : 'already exists (preserved)'}`
242
+ );
243
+ console.log(` ${depsDir}/ ${depsDirCreated ? 'created' : 'already exists'}`);
244
+ }
184
245
  }
@@ -13,17 +13,26 @@ import {
13
13
  fetchSpecFiles,
14
14
  listRegistrySpecs,
15
15
  } from '../lib/registry.js';
16
+ import { installSkills } from '../lib/skills.js';
16
17
 
17
18
  function isValidSpecName(name) {
18
19
  return /^[a-z0-9]+(-[a-z0-9]+)*$/.test(name);
19
20
  }
20
21
 
21
22
  export async function installCommand(name, version, options) {
22
- // Step 1: Verify opensdd.json exists
23
- const manifestPath = findManifestPath(process.cwd());
23
+ // Step 1: Verify opensdd.json exists, auto-bootstrap if not
24
+ let manifestPath = findManifestPath(process.cwd());
24
25
  if (!manifestPath) {
25
- console.error('Error: OpenSDD not initialized. Run `opensdd init` to get started.');
26
- process.exit(1);
26
+ const cwd = process.cwd();
27
+ manifestPath = path.join(cwd, 'opensdd.json');
28
+ const consumerManifest = {
29
+ opensdd: '0.1.0',
30
+ depsDir: '.opensdd.deps',
31
+ };
32
+ fs.writeFileSync(manifestPath, JSON.stringify(consumerManifest, null, 2) + '\n');
33
+ installSkills(cwd, { mode: 'consumer' });
34
+ fs.mkdirSync(path.join(cwd, '.opensdd.deps'), { recursive: true });
35
+ console.log('Auto-initialized OpenSDD (consumer).');
27
36
  }
28
37
 
29
38
  const manifest = readManifest(manifestPath);
@@ -29,6 +29,10 @@ export function writeManifest(manifestPath, data) {
29
29
  fs.writeFileSync(manifestPath, JSON.stringify(data, null, 2) + '\n');
30
30
  }
31
31
 
32
+ export function isConsumerOnly(manifest) {
33
+ return !manifest.specsDir;
34
+ }
35
+
32
36
  export function getSpecsDir(manifest) {
33
37
  return manifest.specsDir || 'opensdd';
34
38
  }
package/src/lib/skills.js CHANGED
@@ -89,9 +89,10 @@ function updateManagedSection(filePath, sectionBody) {
89
89
  * Returns an array of warnings for non-critical failures.
90
90
  * Throws on critical failures (e.g., Claude Code installation fails).
91
91
  */
92
- export function installSkills(projectRoot) {
92
+ export function installSkills(projectRoot, { mode = 'full' } = {}) {
93
93
  const skills = getSkillContent();
94
94
  const warnings = [];
95
+ const isFull = mode === 'full';
95
96
 
96
97
  // 1. Claude Code (critical — Gemini and Amp depend on this)
97
98
  const claudeBase = path.join(projectRoot, '.claude', 'skills');
@@ -103,14 +104,16 @@ export function installSkills(projectRoot) {
103
104
  path.join(claudeBase, 'sdd-manager', 'references', 'spec-format.md'),
104
105
  skills.specFormat
105
106
  );
106
- writeFileSync(
107
- path.join(claudeBase, 'sdd-generate', 'SKILL.md'),
108
- skills.sddGenerate
109
- );
110
- writeFileSync(
111
- path.join(claudeBase, 'sdd-generate', 'references', 'spec-format.md'),
112
- skills.specFormat
113
- );
107
+ if (isFull) {
108
+ writeFileSync(
109
+ path.join(claudeBase, 'sdd-generate', 'SKILL.md'),
110
+ skills.sddGenerate
111
+ );
112
+ writeFileSync(
113
+ path.join(claudeBase, 'sdd-generate', 'references', 'spec-format.md'),
114
+ skills.specFormat
115
+ );
116
+ }
114
117
 
115
118
  // 2. Codex CLI
116
119
  try {
@@ -123,14 +126,16 @@ export function installSkills(projectRoot) {
123
126
  path.join(codexBase, 'sdd-manager', 'references', 'spec-format.md'),
124
127
  skills.specFormat
125
128
  );
126
- writeFileSync(
127
- path.join(codexBase, 'sdd-generate', 'SKILL.md'),
128
- skills.sddGenerate
129
- );
130
- writeFileSync(
131
- path.join(codexBase, 'sdd-generate', 'references', 'spec-format.md'),
132
- skills.specFormat
133
- );
129
+ if (isFull) {
130
+ writeFileSync(
131
+ path.join(codexBase, 'sdd-generate', 'SKILL.md'),
132
+ skills.sddGenerate
133
+ );
134
+ writeFileSync(
135
+ path.join(codexBase, 'sdd-generate', 'references', 'spec-format.md'),
136
+ skills.specFormat
137
+ );
138
+ }
134
139
  } catch (err) {
135
140
  warnings.push(`Could not install Codex CLI skills: ${err.message}`);
136
141
  }
@@ -141,7 +146,6 @@ export function installSkills(projectRoot) {
141
146
  ensureDir(cursorBase);
142
147
 
143
148
  const { frontmatter: managerFm, body: managerBody } = parseFrontmatter(skills.sddManager);
144
- const { frontmatter: generateFm, body: generateBody } = parseFrontmatter(skills.sddGenerate);
145
149
 
146
150
  const sddManagerCursor = `---
147
151
  description: "${managerFm.description}"
@@ -150,13 +154,6 @@ alwaysApply: false
150
154
 
151
155
  ${managerBody}`;
152
156
 
153
- const sddGenerateCursor = `---
154
- description: "${generateFm.description}"
155
- alwaysApply: false
156
- ---
157
-
158
- ${generateBody}`;
159
-
160
157
  const specFormatCursor = `---
161
158
  description: "OpenSDD spec format reference. Defines the structure and rules for behavioral specifications. Referenced by sdd-manager and sdd-generate skills."
162
159
  alwaysApply: false
@@ -165,8 +162,20 @@ alwaysApply: false
165
162
  ${skills.specFormat}`;
166
163
 
167
164
  writeFileSync(path.join(cursorBase, 'sdd-manager.md'), sddManagerCursor);
168
- writeFileSync(path.join(cursorBase, 'sdd-generate.md'), sddGenerateCursor);
169
165
  writeFileSync(path.join(cursorBase, 'opensdd-spec-format.md'), specFormatCursor);
166
+
167
+ if (isFull) {
168
+ const { frontmatter: generateFm, body: generateBody } = parseFrontmatter(skills.sddGenerate);
169
+
170
+ const sddGenerateCursor = `---
171
+ description: "${generateFm.description}"
172
+ alwaysApply: false
173
+ ---
174
+
175
+ ${generateBody}`;
176
+
177
+ writeFileSync(path.join(cursorBase, 'sdd-generate.md'), sddGenerateCursor);
178
+ }
170
179
  } catch (err) {
171
180
  warnings.push(`Could not install Cursor skills: ${err.message}`);
172
181
  }
@@ -177,20 +186,24 @@ ${skills.specFormat}`;
177
186
  ensureDir(copilotBase);
178
187
 
179
188
  const { frontmatter: managerFmCp, body: managerBodyCp } = parseFrontmatter(skills.sddManager);
180
- const { frontmatter: generateFmCp, body: generateBodyCp } = parseFrontmatter(skills.sddGenerate);
181
189
 
182
190
  writeFileSync(
183
191
  path.join(copilotBase, 'sdd-manager.instructions.md'),
184
192
  `---\napplyTo: "**"\ndescription: "${managerFmCp.description}"\n---\n\n${managerBodyCp}`
185
193
  );
186
- writeFileSync(
187
- path.join(copilotBase, 'sdd-generate.instructions.md'),
188
- `---\napplyTo: "**"\ndescription: "${generateFmCp.description}"\n---\n\n${generateBodyCp}`
189
- );
190
194
  writeFileSync(
191
195
  path.join(copilotBase, 'opensdd-spec-format.instructions.md'),
192
196
  `---\napplyTo: "**"\ndescription: "OpenSDD spec format reference. Defines the structure and rules for behavioral specifications. Referenced by sdd-manager and sdd-generate skills."\n---\n\n${skills.specFormat}`
193
197
  );
198
+
199
+ if (isFull) {
200
+ const { frontmatter: generateFmCp, body: generateBodyCp } = parseFrontmatter(skills.sddGenerate);
201
+
202
+ writeFileSync(
203
+ path.join(copilotBase, 'sdd-generate.instructions.md'),
204
+ `---\napplyTo: "**"\ndescription: "${generateFmCp.description}"\n---\n\n${generateBodyCp}`
205
+ );
206
+ }
194
207
  } catch (err) {
195
208
  warnings.push(`Could not install GitHub Copilot skills: ${err.message}`);
196
209
  }
@@ -198,10 +211,12 @@ ${skills.specFormat}`;
198
211
  // 5. Gemini CLI
199
212
  try {
200
213
  const geminiPath = path.join(projectRoot, 'GEMINI.md');
201
- const geminiBody = `@.claude/skills/sdd-manager/SKILL.md
202
- @.claude/skills/sdd-manager/references/spec-format.md
203
- @.claude/skills/sdd-generate/SKILL.md
214
+ let geminiBody = `@.claude/skills/sdd-manager/SKILL.md
215
+ @.claude/skills/sdd-manager/references/spec-format.md`;
216
+ if (isFull) {
217
+ geminiBody += `\n@.claude/skills/sdd-generate/SKILL.md
204
218
  @.claude/skills/sdd-generate/references/spec-format.md`;
219
+ }
205
220
  updateManagedSection(geminiPath, geminiBody);
206
221
  } catch (err) {
207
222
  warnings.push(`Could not install Gemini CLI skills: ${err.message}`);
@@ -210,10 +225,12 @@ ${skills.specFormat}`;
210
225
  // 6. Amp
211
226
  try {
212
227
  const ampPath = path.join(projectRoot, 'AGENTS.md');
213
- const ampBody = `@.claude/skills/sdd-manager/SKILL.md
214
- @.claude/skills/sdd-manager/references/spec-format.md
215
- @.claude/skills/sdd-generate/SKILL.md
228
+ let ampBody = `@.claude/skills/sdd-manager/SKILL.md
229
+ @.claude/skills/sdd-manager/references/spec-format.md`;
230
+ if (isFull) {
231
+ ampBody += `\n@.claude/skills/sdd-generate/SKILL.md
216
232
  @.claude/skills/sdd-generate/references/spec-format.md`;
233
+ }
217
234
  updateManagedSection(ampPath, ampBody);
218
235
  } catch (err) {
219
236
  warnings.push(`Could not install Amp skills: ${err.message}`);