openspecpm 0.1.0-alpha.0 → 1.0.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.
@@ -1,105 +1,106 @@
1
- # Conventions
2
-
3
- These rules apply to every phase of OpenSpecPM. Read this before touching files.
4
-
5
- ## Paths
6
-
7
- | Artifact | Path |
8
- |---|---|
9
- | Project config | `.openspecpm/config.json` (chosen adapter, repo/org/project identifiers) |
10
- | Project state | `.openspecpm/state.json` (not committed; idempotency hints) |
11
- | OpenSpec changes | `openspec/changes/<feature>/` (owned by OpenSpec) |
12
- | Proposal | `openspec/changes/<feature>/proposal.md` |
13
- | Design | `openspec/changes/<feature>/design.md` |
14
- | Tasks | `openspec/changes/<feature>/tasks.md` |
15
- | BDD specs | `openspec/changes/<feature>/specs/*.md` |
16
- | Progress (local) | `openspec/changes/<feature>/updates/<task-id>/progress.md` |
17
- | Archive | `openspec/archive/<YYYY-MM-DD>-<feature>/` (owned by OpenSpec) |
18
-
19
- The OpenSpec layout is authoritative — do not invent a parallel `.claude/...` tree. We sit *above* OpenSpec, not beside it.
20
-
21
- ## Secrets
22
-
23
- Never write tokens to `.openspecpm/config.json`. Use environment variables:
24
-
25
- - GitHub: `gh auth login` handles the token; no env var needed.
26
- - Azure DevOps: `AZURE_DEVOPS_EXT_PAT` (Work Items: Read/Write).
27
- - Jira: `JIRA_EMAIL` + `JIRA_API_TOKEN`.
28
- - Linear: `LINEAR_API_KEY`.
29
- - GitLab: `GITLAB_TOKEN` (`api` scope).
30
-
31
- ## Frontmatter schemas
32
-
33
- All artifacts use YAML frontmatter. Required fields:
34
-
35
- ### proposal.md
36
-
37
- ```yaml
38
- ---
39
- name: <feature-slug>
40
- status: draft | in_review | approved | shipped
41
- created: <ISO-8601 timestamp>
42
- schema_version: 1
43
- external: # filled by `openspecpm sync`
44
- github:
45
- adapter: github
46
- id: "42"
47
- url: https://github.com/.../issues/42
48
- ---
49
- ```
50
-
51
- ### tasks.md
52
-
53
- ```yaml
54
- ---
55
- schema_version: 1
56
- items:
57
- - title: "Implement X"
58
- sync_state: pending | created | failed
59
- external_id: "43" # filled after sync
60
- external_url: https://...
61
- depends_on: [] # task titles or external ids
62
- parallel: true | false
63
- ---
64
- ```
65
-
66
- If `items:` is absent, OpenSpecPM falls back to parsing `- [ ] title` checklist lines in the body.
67
-
68
- ## BDD format
69
-
70
- Scenarios in `specs/*.md` should use Gherkin-style triplets:
71
-
72
- ```
73
- Scenario: User toggles dark mode
74
- Given the user is signed in
75
- And their theme preference is "system"
76
- When they select "Dark" in the appearance menu
77
- Then the UI re-renders in dark theme
78
- And their preference is saved to the profile
79
- ```
80
-
81
- Lint heuristics (enforced softly at `propose`, hard at `sync` in Sprint 3+):
82
-
83
- - Each scenario has one `Given`, one `When`, one `Then` (with optional `And`s).
84
- - `Then` uses an observable verb (displays, returns, stores, rejects, emails, ).
85
- - Reject "should work", "should be correct", "is successful" as `Then` predicates.
86
- - Reject tautological `Then` (paraphrase of the `When`).
87
-
88
- ## ISO timestamps
89
-
90
- All `created` / `updated` / `synced` fields use ISO-8601 with timezone:
91
-
92
- ```
93
- 2026-05-17T14:30:00Z
94
- ```
95
-
96
- ## Sync markers
97
-
98
- Comments pushed to the PM tool are append-only and stamped:
99
-
100
- ```
101
- <!-- SYNCED: 2026-05-17T14:30:00Z -->
102
- …progress narrative…
103
- ```
104
-
105
- This lets re-syncs detect what's already been sent without duplicating.
1
+ # Conventions
2
+
3
+ These rules apply to every phase of OpenSpecPM. Read this before touching files.
4
+
5
+ ## Paths
6
+
7
+ | Artifact | Path |
8
+ |---|---|
9
+ | Project config | `.openspecpm/config.json` (chosen adapter, repo/org/project identifiers) |
10
+ | Project state | `.openspecpm/state.json` (not committed; idempotency hints) |
11
+ | OpenSpec changes | `openspec/changes/<feature>/` (owned by OpenSpec) |
12
+ | Proposal | `openspec/changes/<feature>/proposal.md` |
13
+ | Design | `openspec/changes/<feature>/design.md` |
14
+ | Tasks | `openspec/changes/<feature>/tasks.md` |
15
+ | BDD specs | `openspec/changes/<feature>/specs/*.md` |
16
+ | Progress (local) | `openspec/changes/<feature>/updates/<task-id>/progress.md` |
17
+ | Archive | `openspec/archive/<YYYY-MM-DD>-<feature>/` (owned by OpenSpec) |
18
+
19
+ The OpenSpec layout is authoritative — do not invent a parallel `.claude/...` tree. We sit *above* OpenSpec, not beside it.
20
+
21
+ ## Secrets
22
+
23
+ Never write tokens to `.openspecpm/config.json`. Use environment variables:
24
+
25
+ - GitHub: `gh auth login` handles the token; no env var needed.
26
+ - Azure DevOps: `AZURE_DEVOPS_EXT_PAT` (Work Items: Read/Write).
27
+ - Jira: `JIRA_EMAIL` + `JIRA_API_TOKEN`.
28
+ - Linear: `LINEAR_API_KEY`.
29
+ - GitLab: `GITLAB_TOKEN` (`api` scope).
30
+ - LLM BDD judge (optional, opt-in via `--llm` or `judge.enabled` config): `ANTHROPIC_API_KEY`.
31
+
32
+ ## Frontmatter schemas
33
+
34
+ All artifacts use YAML frontmatter. Required fields:
35
+
36
+ ### proposal.md
37
+
38
+ ```yaml
39
+ ---
40
+ name: <feature-slug>
41
+ status: draft | in_review | approved | shipped
42
+ created: <ISO-8601 timestamp>
43
+ schema_version: 1
44
+ external: # filled by `openspecpm sync`
45
+ github:
46
+ adapter: github
47
+ id: "42"
48
+ url: https://github.com/.../issues/42
49
+ ---
50
+ ```
51
+
52
+ ### tasks.md
53
+
54
+ ```yaml
55
+ ---
56
+ schema_version: 1
57
+ items:
58
+ - title: "Implement X"
59
+ sync_state: pending | created | failed
60
+ external_id: "43" # filled after sync
61
+ external_url: https://...
62
+ depends_on: [] # task titles or external ids
63
+ parallel: true | false
64
+ ---
65
+ ```
66
+
67
+ If `items:` is absent, OpenSpecPM falls back to parsing `- [ ] title` checklist lines in the body.
68
+
69
+ ## BDD format
70
+
71
+ Scenarios in `specs/*.md` should use Gherkin-style triplets:
72
+
73
+ ```
74
+ Scenario: User toggles dark mode
75
+ Given the user is signed in
76
+ And their theme preference is "system"
77
+ When they select "Dark" in the appearance menu
78
+ Then the UI re-renders in dark theme
79
+ And their preference is saved to the profile
80
+ ```
81
+
82
+ Lint heuristics (enforced softly at `propose`, hard at `sync` in Sprint 3+):
83
+
84
+ - Each scenario has one `Given`, one `When`, one `Then` (with optional `And`s).
85
+ - `Then` uses an observable verb (displays, returns, stores, rejects, emails, …).
86
+ - Reject "should work", "should be correct", "is successful" as `Then` predicates.
87
+ - Reject tautological `Then` (paraphrase of the `When`).
88
+
89
+ ## ISO timestamps
90
+
91
+ All `created` / `updated` / `synced` fields use ISO-8601 with timezone:
92
+
93
+ ```
94
+ 2026-05-17T14:30:00Z
95
+ ```
96
+
97
+ ## Sync markers
98
+
99
+ Comments pushed to the PM tool are append-only and stamped:
100
+
101
+ ```
102
+ <!-- SYNCED: 2026-05-17T14:30:00Z -->
103
+ …progress narrative…
104
+ ```
105
+
106
+ This lets re-syncs detect what's already been sent without duplicating.
@@ -1,52 +1,52 @@
1
- # Structure — Decomposing a proposal into tasks
2
-
3
- **When to use this:** A proposal exists at `openspec/changes/<feature>/proposal.md` and the user wants to break it down into individual work items.
4
-
5
- ## Outcome
6
-
7
- A populated `openspec/changes/<feature>/tasks.md` where the `items:` frontmatter array lists every task with: title, dependency edges, parallelizability, and a `sync_state: pending` marker.
8
-
9
- ## Flow
10
-
11
- 1. **Read the proposal and specs.** Open `proposal.md`, `design.md`, and every file in `specs/`. Build a mental model of what behavior must exist for the change to be complete.
12
-
13
- 2. **Group by stream.** Most features decompose into 2–5 independent streams. Common patterns:
14
- - **Data:** schema, migrations, persistence layer
15
- - **Service:** business logic, validation, domain rules
16
- - **API:** HTTP/RPC/CLI surface
17
- - **UI:** components, flows, accessibility
18
- - **Tests:** end-to-end coverage of the new behavior
19
-
20
- Streams that can be worked in parallel get `parallel: true`. Streams that must wait on another stream get `depends_on: ["<earlier-task-title>"]`.
21
-
22
- 3. **Right-size each task.** A task should be 2–8 hours of focused work for one engineer. If a task is bigger, split. If smaller, merge into the next one (overhead exceeds value).
23
-
24
- 4. **Write tasks.md.** Use the frontmatter schema from `conventions.md`. Every task gets:
25
- ```yaml
26
- - title: "Add user_preferences.theme column"
27
- sync_state: pending
28
- depends_on: []
29
- parallel: true
30
- effort_hours: 3
31
- ```
32
-
33
- 5. **Cross-check against BDD scenarios.** Every scenario in `specs/*.md` should map to at least one task. If a scenario is unimplemented, add a task. If a task isn't traceable to any scenario, ask whether it's actually needed.
34
-
35
- ## Hierarchy and the target PM tool
36
-
37
- The backend's `capabilities().hierarchyDepth` determines how the structure projects into work items:
38
-
39
- | Backend | Depth | Mapping |
40
- |---|---|---|
41
- | GitHub | 2 | Epic issue → sub-issues (via `gh-sub-issue`) |
42
- | Linear | 2 | Project → Issues |
43
- | GitLab | 2 | Parent issue → linked child issues (`relates_to` / `blocks`) |
44
- | Jira | 3 | Epic → Story → Sub-task |
45
- | Azure DevOps | 4 | Epic → Feature → User Story → Task |
46
-
47
- The sync layer will **collapse levels gracefully** when authoring depth exceeds backend depth — e.g. on GitHub, "Feature" and "Story" levels are flattened into siblings of the Epic with a label tag, and a warning is printed. You do not need to author differently for each backend; author the deepest sensible structure and let the adapter compress.
48
-
49
- ## After this phase
50
-
51
- - Route to `references/sync.md` to push tasks to the PM tool.
52
- - If decomposition surfaced unknowns, route back to `references/plan.md` to refine the proposal.
1
+ # Structure — Decomposing a proposal into tasks
2
+
3
+ **When to use this:** A proposal exists at `openspec/changes/<feature>/proposal.md` and the user wants to break it down into individual work items.
4
+
5
+ ## Outcome
6
+
7
+ A populated `openspec/changes/<feature>/tasks.md` where the `items:` frontmatter array lists every task with: title, dependency edges, parallelizability, and a `sync_state: pending` marker.
8
+
9
+ ## Flow
10
+
11
+ 1. **Read the proposal and specs.** Open `proposal.md`, `design.md`, and every file in `specs/`. Build a mental model of what behavior must exist for the change to be complete.
12
+
13
+ 2. **Group by stream.** Most features decompose into 2–5 independent streams. Common patterns:
14
+ - **Data:** schema, migrations, persistence layer
15
+ - **Service:** business logic, validation, domain rules
16
+ - **API:** HTTP/RPC/CLI surface
17
+ - **UI:** components, flows, accessibility
18
+ - **Tests:** end-to-end coverage of the new behavior
19
+
20
+ Streams that can be worked in parallel get `parallel: true`. Streams that must wait on another stream get `depends_on: ["<earlier-task-title>"]`.
21
+
22
+ 3. **Right-size each task.** A task should be 2–8 hours of focused work for one engineer. If a task is bigger, split. If smaller, merge into the next one (overhead exceeds value).
23
+
24
+ 4. **Write tasks.md.** Use the frontmatter schema from `conventions.md`. Every task gets:
25
+ ```yaml
26
+ - title: "Add user_preferences.theme column"
27
+ sync_state: pending
28
+ depends_on: []
29
+ parallel: true
30
+ effort_hours: 3
31
+ ```
32
+
33
+ 5. **Cross-check against BDD scenarios.** Every scenario in `specs/*.md` should map to at least one task. If a scenario is unimplemented, add a task. If a task isn't traceable to any scenario, ask whether it's actually needed.
34
+
35
+ ## Hierarchy and the target PM tool
36
+
37
+ The backend's `capabilities().hierarchyDepth` determines how the structure projects into work items:
38
+
39
+ | Backend | Depth | Mapping |
40
+ |---|---|---|
41
+ | GitHub | 2 | Epic issue → sub-issues (via `gh-sub-issue`) |
42
+ | Linear | 2 | Project → Issues |
43
+ | GitLab | 2 | Parent issue → linked child issues (`relates_to` / `blocks`) |
44
+ | Jira | 3 | Epic → Story → Sub-task |
45
+ | Azure DevOps | 4 | Epic → Feature → User Story → Task |
46
+
47
+ The sync layer will **collapse levels gracefully** when authoring depth exceeds backend depth — e.g. on GitHub, "Feature" and "Story" levels are flattened into siblings of the Epic with a label tag, and a warning is printed. You do not need to author differently for each backend; author the deepest sensible structure and let the adapter compress.
48
+
49
+ ## After this phase
50
+
51
+ - Route to `references/sync.md` to push tasks to the PM tool.
52
+ - If decomposition surfaced unknowns, route back to `references/plan.md` to refine the proposal.
@@ -1,56 +1,56 @@
1
- # Sync — Pushing an OpenSpec change to the PM tool
2
-
3
- **When to use this:** The user has a proposal + tasks ready and wants them tracked in GitHub Issues / Azure DevOps Boards / Jira / Linear / GitLab Issues.
4
-
5
- ## Outcome
6
-
7
- For the chosen adapter, the epic and every task are created as work items, linked into a hierarchy where the backend supports it, and recorded back into local frontmatter (`external:` on `proposal.md`, `external_id` + `external_url` on each task in `tasks.md`).
8
-
9
- ## The CLI does the work
10
-
11
- ```
12
- openspecpm sync <feature> # create + update
13
- openspecpm sync <feature> --dry-run # print the call plan, no remote writes
14
- ```
15
-
16
- Do not script `gh issue create` or hand-craft REST calls in agent reasoning — let the adapter handle vocabulary differences across backends.
17
-
18
- ## Idempotency contract
19
-
20
- Sync is safe to re-run. The rules:
21
-
22
- 1. **Epic:** if `proposal.md` frontmatter already carries `external.<adapter>` with an `id`, the existing epic is reused. No duplicate epics are ever created.
23
- 2. **Tasks:** each task carries `sync_state: pending | created | failed`. `sync` skips `created` items and retries `failed` ones.
24
- 3. **Comments:** progress comments stamped `<!-- SYNCED: <iso-timestamp> -->` are append-only. Re-running sync after a comment was posted does not repost.
25
-
26
- This means: if the network fails halfway through a 30-task sync, fix the cause, re-run, and only the un-created items get created.
27
-
28
- ## Capabilities and hierarchy collapse
29
-
30
- Each adapter reports `capabilities()`. The sync layer reads `hierarchyDepth`:
31
-
32
- - **GitHub (depth 2):** Epic issue + flat task sub-issues. If the task tree authored depth >2, intermediate levels are flattened into siblings tagged `openspec:<feature>` and a one-line warning is printed.
33
- - **Linear (depth 2):** Project as epic, issues as tasks under the project. `parent` relation when supported by the workspace.
34
- - **GitLab (depth 2):** Parent issue + child issues linked via `relates_to` / `blocks`. Milestone serves as the epic container if `--milestone` is supplied.
35
- - **Jira (depth 3):** Epic → Story → optional Sub-task. Stories without sub-tasks just sit under the Epic via `Relates` link.
36
- - **Azure DevOps (depth 4):** Epic → Feature → User Story → Task with `System.LinkTypes.Hierarchy-Reverse` Parent links.
37
-
38
- ## Field mapping per adapter
39
-
40
- | OpenSpec field | GitHub | Azure DevOps | Jira | Linear | GitLab |
41
- |---|---|---|---|---|---|
42
- | `task.title` | Issue title | `System.Title` | `summary` | `title` | `title` |
43
- | `task.body` | Issue body (markdown) | `System.Description` (HTML) | `description` (ADF) | `description` (markdown) | `description` (markdown) |
44
- | `feature.name` (tag) | label `openspec:<name>` | tag `openspec:<name>` | label `openspec-<name>` | label `openspec:<name>` | label `openspec:<name>` |
45
- | `task.depends_on` | task-list reference in body | `System.LinkTypes.Dependency` link | `Blocks` issue link | issue relation `blocks` | issue link `blocks` |
46
- | `task.iteration` | (ignored, depth=2) | `System.IterationPath` | sprint custom field | `cycleId` | `milestone` |
47
- | `task.assignee` | `--add-assignee` | `System.AssignedTo` | `assignee.accountId` | `assigneeId` | `assignee_ids` |
48
- | `task.effort_hours` | (ignored) | `Microsoft.VSTS.Scheduling.Effort` | story-points custom field | `estimate` | `weight` |
49
-
50
- The CLI handles the translation. Author tasks in the OpenSpec/CCPM dialect described in `conventions.md`.
51
-
52
- ## After sync
53
-
54
- - Each item is now visible in the PM tool. The user can route stakeholders to those URLs for sign-off.
55
- - Progress narrative still lives locally in `openspec/changes/<feature>/updates/<task>/progress.md`. Use `openspecpm comment <task>` (Sprint 3) to broadcast a new update to the PM tool.
56
- - Route to `references/execute.md` when the user is ready to start building.
1
+ # Sync — Pushing an OpenSpec change to the PM tool
2
+
3
+ **When to use this:** The user has a proposal + tasks ready and wants them tracked in GitHub Issues / Azure DevOps Boards / Jira / Linear / GitLab Issues.
4
+
5
+ ## Outcome
6
+
7
+ For the chosen adapter, the epic and every task are created as work items, linked into a hierarchy where the backend supports it, and recorded back into local frontmatter (`external:` on `proposal.md`, `external_id` + `external_url` on each task in `tasks.md`).
8
+
9
+ ## The CLI does the work
10
+
11
+ ```
12
+ openspecpm sync <feature> # create + update
13
+ openspecpm sync <feature> --dry-run # print the call plan, no remote writes
14
+ ```
15
+
16
+ Do not script `gh issue create` or hand-craft REST calls in agent reasoning — let the adapter handle vocabulary differences across backends.
17
+
18
+ ## Idempotency contract
19
+
20
+ Sync is safe to re-run. The rules:
21
+
22
+ 1. **Epic:** if `proposal.md` frontmatter already carries `external.<adapter>` with an `id`, the existing epic is reused. No duplicate epics are ever created.
23
+ 2. **Tasks:** each task carries `sync_state: pending | created | failed`. `sync` skips `created` items and retries `failed` ones.
24
+ 3. **Comments:** progress comments stamped `<!-- SYNCED: <iso-timestamp> -->` are append-only. Re-running sync after a comment was posted does not repost.
25
+
26
+ This means: if the network fails halfway through a 30-task sync, fix the cause, re-run, and only the un-created items get created.
27
+
28
+ ## Capabilities and hierarchy collapse
29
+
30
+ Each adapter reports `capabilities()`. The sync layer reads `hierarchyDepth`:
31
+
32
+ - **GitHub (depth 2):** Epic issue + flat task sub-issues. If the task tree authored depth >2, intermediate levels are flattened into siblings tagged `openspec:<feature>` and a one-line warning is printed.
33
+ - **Linear (depth 2):** Project as epic, issues as tasks under the project. `parent` relation when supported by the workspace.
34
+ - **GitLab (depth 2):** Parent issue + child issues linked via `relates_to` / `blocks`. Milestone serves as the epic container if `--milestone` is supplied.
35
+ - **Jira (depth 3):** Epic → Story → optional Sub-task. Stories without sub-tasks just sit under the Epic via `Relates` link.
36
+ - **Azure DevOps (depth 4):** Epic → Feature → User Story → Task with `System.LinkTypes.Hierarchy-Reverse` Parent links.
37
+
38
+ ## Field mapping per adapter
39
+
40
+ | OpenSpec field | GitHub | Azure DevOps | Jira | Linear | GitLab |
41
+ |---|---|---|---|---|---|
42
+ | `task.title` | Issue title | `System.Title` | `summary` | `title` | `title` |
43
+ | `task.body` | Issue body (markdown) | `System.Description` (HTML) | `description` (ADF) | `description` (markdown) | `description` (markdown) |
44
+ | `feature.name` (tag) | label `openspec:<name>` | tag `openspec:<name>` | label `openspec-<name>` | label `openspec:<name>` | label `openspec:<name>` |
45
+ | `task.depends_on` | task-list reference in body | `System.LinkTypes.Dependency` link | `Blocks` issue link | issue relation `blocks` | issue link `blocks` |
46
+ | `task.iteration` | (ignored, depth=2) | `System.IterationPath` | sprint custom field | `cycleId` | `milestone` |
47
+ | `task.assignee` | `--add-assignee` | `System.AssignedTo` | `assignee.accountId` | `assigneeId` | `assignee_ids` |
48
+ | `task.effort_hours` | (ignored) | `Microsoft.VSTS.Scheduling.Effort` | story-points custom field | `estimate` | `weight` |
49
+
50
+ The CLI handles the translation. Author tasks in the OpenSpec/CCPM dialect described in `conventions.md`.
51
+
52
+ ## After sync
53
+
54
+ - Each item is now visible in the PM tool. The user can route stakeholders to those URLs for sign-off.
55
+ - Progress narrative still lives locally in `openspec/changes/<feature>/updates/<task>/progress.md`. Use `openspecpm comment <task>` (Sprint 3) to broadcast a new update to the PM tool.
56
+ - Route to `references/execute.md` when the user is ready to start building.