freeharness 0.4.1 → 0.4.2

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.
Files changed (194) hide show
  1. package/README.md +8 -7
  2. package/canonical/HARVEST.yaml +25 -14
  3. package/canonical/PROVENANCE.yaml +1 -1
  4. package/canonical/agents/README.md +77 -36
  5. package/canonical/agents/agentic-architect.md +2 -1
  6. package/canonical/agents/database-reviewer.md +6 -8
  7. package/canonical/agents/explorer-ai-engineer-analyst.md +2 -6
  8. package/canonical/agents/implementer.md +30 -0
  9. package/canonical/agents/pr-reviewer.md +9 -11
  10. package/canonical/agents/python-reviewer.md +7 -9
  11. package/canonical/agents/report-formatter.md +7 -3
  12. package/canonical/agents/security-reviewer.md +7 -8
  13. package/canonical/agents/test-writer.md +5 -2
  14. package/canonical/hooks/cost-prices.json +11 -9
  15. package/canonical/hooks/freeharness-config-guard.mjs +8072 -87
  16. package/canonical/hooks/freeharness-context-monitor.mjs +88 -54
  17. package/canonical/hooks/freeharness-converge.mjs +78 -23
  18. package/canonical/hooks/freeharness-cost-tracker.mjs +1129 -218
  19. package/canonical/hooks/freeharness-memory-guard.mjs +20 -23
  20. package/canonical/hooks/freeharness-precompact.mjs +217 -87
  21. package/canonical/hooks/freeharness-quota-tap.mjs +173 -0
  22. package/canonical/hooks/freeharness-reload-context.mjs +197 -0
  23. package/canonical/hooks/freeharness-repeat-tool.mjs +1 -1
  24. package/canonical/hooks/freeharness-sdd-context.mjs +970 -0
  25. package/canonical/hooks/freeharness-session-start +297 -59
  26. package/canonical/hooks/hooks.claude-code.json +1 -1
  27. package/canonical/hooks/hooks.config-guard.claude-code.json +3 -2
  28. package/canonical/hooks/hooks.context-monitor.claude-code.json +1 -1
  29. package/canonical/hooks/hooks.converge.claude-code.json +1 -1
  30. package/canonical/hooks/hooks.memory-guard.claude-code.json +3 -2
  31. package/canonical/hooks/hooks.reload-context.claude-code.json +15 -0
  32. package/canonical/openspec/schema.spec-driven.yaml +29 -8
  33. package/canonical/openspec/templates/follow-ups.md +3 -2
  34. package/canonical/openspec/templates/proposal.md +1 -1
  35. package/canonical/openspec/templates/tasks.md +8 -0
  36. package/canonical/rules/CLAUDE.md +5 -4
  37. package/canonical/rules/routing.md +10 -9
  38. package/canonical/skills/agent-evaluation/SKILL.md +17 -6
  39. package/canonical/skills/agent-evaluation/evals/cases.yaml +38 -23
  40. package/canonical/skills/agentic-architecture/SKILL.md +4 -0
  41. package/canonical/skills/agentic-architecture/evals/cases.yaml +27 -0
  42. package/canonical/skills/code-review/SKILL.md +9 -2
  43. package/canonical/skills/code-review/evals/cases.yaml +1118 -27
  44. package/canonical/skills/git-workflow/SKILL.md +2 -0
  45. package/canonical/skills/local-code/SKILL.md +2 -2
  46. package/canonical/skills/local-code/evals/cases.yaml +1 -1
  47. package/canonical/skills/report-formatting/SKILL.md +10 -2
  48. package/canonical/skills/report-formatting/reference/ARCHITECTURE.md +3 -3
  49. package/canonical/skills/report-formatting/reference/HELPERS.md +10 -5
  50. package/canonical/skills/report-formatting/reference/RELEASE.md +1 -2
  51. package/canonical/skills/report-formatting/reference/TEMPLATES.md +3 -2
  52. package/canonical/skills/report-formatting/reference/authoring.md +25 -37
  53. package/canonical/skills/report-formatting/scripts/build-architecture.js +1 -1
  54. package/canonical/skills/report-formatting/scripts/build-md-claro.js +5 -8
  55. package/canonical/skills/report-formatting/scripts/check-env.js +0 -4
  56. package/canonical/skills/report-formatting/scripts/docmodel.js +3 -11
  57. package/canonical/skills/report-formatting/scripts/example-build.js +8 -10
  58. package/canonical/skills/report-formatting/scripts/example_build_ArchitectureReview_docx.js +8 -10
  59. package/canonical/skills/report-formatting/scripts/example_build_ExecutiveReport_docx.js +8 -10
  60. package/canonical/skills/report-formatting/scripts/theme-claro.js +39 -10
  61. package/canonical/skills/subagent-driven-development/SKILL.md +35 -28
  62. package/canonical/skills/subagent-driven-development/evals/cases.yaml +3496 -19
  63. package/canonical/skills/subagent-driven-development/reference/brief.md +185 -35
  64. package/canonical/skills/subagent-driven-development/reference/handoff.md +82 -2
  65. package/canonical/skills/subagent-driven-development/reference/loop.md +57 -0
  66. package/canonical/skills/subagent-driven-development/reference/trees.md +40 -0
  67. package/canonical/skills/subagent-driven-development/reference/workspace.md +31 -0
  68. package/canonical/skills/subagent-driven-development/scripts/validate-handoff.mjs +4771 -326
  69. package/dist/adapters/harness/claude-code.d.ts +19 -3
  70. package/dist/adapters/harness/claude-code.js +204 -39
  71. package/dist/adapters/harness/opencode.js +16 -2
  72. package/dist/adapters/harness/plugin.js +28 -17
  73. package/dist/adapters/memory/doctor.d.ts +174 -29
  74. package/dist/adapters/memory/doctor.js +758 -134
  75. package/dist/adapters/memory/migrate.d.ts +95 -0
  76. package/dist/adapters/memory/migrate.js +497 -0
  77. package/dist/adapters/memory/paths.d.ts +22 -0
  78. package/dist/adapters/memory/paths.js +85 -0
  79. package/dist/adapters/memory/vendored.d.ts +56 -29
  80. package/dist/adapters/memory/vendored.js +191 -154
  81. package/dist/adapters/sync/diff.js +4 -1
  82. package/dist/cli/cleanup-prompt.d.ts +35 -0
  83. package/dist/cli/cleanup-prompt.js +68 -0
  84. package/dist/cli/cleanup.d.ts +22 -24
  85. package/dist/cli/cleanup.js +182 -68
  86. package/dist/cli/cost-quota.d.ts +158 -0
  87. package/dist/cli/cost-quota.js +645 -0
  88. package/dist/cli/cost.d.ts +408 -46
  89. package/dist/cli/cost.js +1731 -57
  90. package/dist/cli/doctor.d.ts +52 -13
  91. package/dist/cli/doctor.js +193 -44
  92. package/dist/cli/hard-cleanup.d.ts +93 -0
  93. package/dist/cli/hard-cleanup.js +552 -0
  94. package/dist/cli/install-facts.d.ts +28 -0
  95. package/dist/cli/install-facts.js +66 -0
  96. package/dist/cli/json-key-edit.d.ts +18 -0
  97. package/dist/cli/json-key-edit.js +118 -0
  98. package/dist/cli/memory-import.d.ts +74 -0
  99. package/dist/cli/memory-import.js +469 -0
  100. package/dist/cli/plugin-validate.d.ts +12 -0
  101. package/dist/cli/plugin-validate.js +43 -0
  102. package/dist/cli/uninstall.d.ts +1 -1
  103. package/dist/cli/uninstall.js +2 -2
  104. package/dist/cli/upstream-launchers.d.ts +49 -0
  105. package/dist/cli/upstream-launchers.js +287 -0
  106. package/dist/index.js +247 -70
  107. package/dist/infra/fsutil.d.ts +31 -3
  108. package/dist/infra/fsutil.js +69 -6
  109. package/dist/infra/manifest.d.ts +2 -1
  110. package/dist/infra/manifest.js +3 -2
  111. package/dist/infra/prices.d.ts +18 -0
  112. package/dist/infra/prices.js +64 -0
  113. package/node_modules/@freeharness/core/dist/tiers.d.ts +10 -1
  114. package/node_modules/@freeharness/core/dist/tiers.js +24 -2
  115. package/node_modules/@freeharness/core/package.json +1 -1
  116. package/node_modules/@freeharness/sdd/PROVENANCE.yaml +279 -2
  117. package/node_modules/@freeharness/sdd/dist/src/bin/openspec.js +34 -8
  118. package/node_modules/@freeharness/sdd/dist/src/shim/archive.d.ts +7 -6
  119. package/node_modules/@freeharness/sdd/dist/src/shim/archive.js +72 -64
  120. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.d.ts +48 -16
  121. package/node_modules/@freeharness/sdd/dist/src/shim/follow-up.js +168 -70
  122. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.d.ts +36 -6
  123. package/node_modules/@freeharness/sdd/dist/src/shim/instructions.js +110 -49
  124. package/node_modules/@freeharness/sdd/dist/src/shim/list.d.ts +1 -1
  125. package/node_modules/@freeharness/sdd/dist/src/shim/list.js +57 -14
  126. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.d.ts +7 -0
  127. package/node_modules/@freeharness/sdd/dist/src/shim/nested-change.js +118 -0
  128. package/node_modules/@freeharness/sdd/dist/src/shim/new-change.js +3 -1
  129. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.d.ts +12 -0
  130. package/node_modules/@freeharness/sdd/dist/src/shim/proposal-capabilities.js +94 -0
  131. package/node_modules/@freeharness/sdd/dist/src/shim/shared.d.ts +17 -0
  132. package/node_modules/@freeharness/sdd/dist/src/shim/shared.js +182 -1
  133. package/node_modules/@freeharness/sdd/dist/src/shim/status.d.ts +2 -2
  134. package/node_modules/@freeharness/sdd/dist/src/shim/status.js +34 -5
  135. package/node_modules/@freeharness/sdd/dist/src/shim/validate.d.ts +9 -0
  136. package/node_modules/@freeharness/sdd/dist/src/shim/validate.js +49 -41
  137. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.d.ts +21 -0
  138. package/node_modules/@freeharness/sdd/dist/src/shim/warnings.js +66 -0
  139. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.d.ts +4 -0
  140. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/line-endings.js +17 -0
  141. package/node_modules/@freeharness/sdd/dist/vendor/openspec/apply/specs-apply.js +95 -22
  142. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.d.ts +6 -0
  143. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/change-status-policy.js +14 -6
  144. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.d.ts +1 -1
  145. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/index.js +1 -1
  146. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.d.ts +3 -3
  147. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/outputs.js +24 -4
  148. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/task-progress.js +4 -7
  149. package/node_modules/@freeharness/sdd/dist/vendor/openspec/engine/types.js +13 -1
  150. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/apply-change.js +21 -6
  151. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/archive-change.js +80 -19
  152. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/explore.js +42 -22
  153. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.d.ts +32 -0
  154. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/project-root.js +39 -0
  155. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/propose.js +16 -9
  156. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/sync-specs.js +36 -1
  157. package/node_modules/@freeharness/sdd/dist/vendor/openspec/generation/templates/workflows/update-change.js +65 -30
  158. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.d.ts +1 -1
  159. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/constants.js +1 -1
  160. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.d.ts +8 -13
  161. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/change-parser.js +79 -102
  162. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/markdown-parser.js +4 -9
  163. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.d.ts +50 -10
  164. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-blocks.js +165 -37
  165. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.d.ts +24 -3
  166. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/requirement-text.js +55 -8
  167. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/parsers/spec-structure.js +4 -1
  168. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/purpose-placeholder.js +19 -9
  169. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.d.ts +10 -0
  170. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/spec-discovery.js +115 -0
  171. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.d.ts +3 -3
  172. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/task-lines.js +20 -20
  173. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.d.ts +6 -0
  174. package/node_modules/@freeharness/sdd/dist/vendor/openspec/validation/validator.js +75 -14
  175. package/node_modules/@freeharness/sdd/package.json +1 -1
  176. package/node_modules/@freeharness/sdd/vendor/openspec/assets/schema.upstream.yaml +47 -7
  177. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-apply-change/SKILL.md +25 -7
  178. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-archive-change/SKILL.md +50 -11
  179. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-bulk-archive-change/SKILL.md +48 -10
  180. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-continue-change/SKILL.md +27 -7
  181. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-explore/SKILL.md +25 -12
  182. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-ff-change/SKILL.md +17 -5
  183. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-new-change/SKILL.md +12 -1
  184. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-onboard/SKILL.md +47 -33
  185. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-propose/SKILL.md +17 -5
  186. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-sync-specs/SKILL.md +29 -1
  187. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-update-change/SKILL.md +31 -13
  188. package/node_modules/@freeharness/sdd/vendor/openspec/assets/skills/openspec-verify-change/SKILL.md +75 -27
  189. package/package.json +6 -4
  190. package/provenance/canonical.PROVENANCE.yaml +1 -1
  191. package/provenance/memory.PROVENANCE.yaml +458 -6
  192. package/provenance/sdd.PROVENANCE.yaml +279 -2
  193. package/canonical/hooks/freeharness-auto-memory.mjs +0 -158
  194. package/canonical/hooks/hooks.auto-memory.claude-code.json +0 -16
@@ -1,12 +1,15 @@
1
1
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
2
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
2
3
  export function getArchiveChangeSkillTemplate() {
3
4
  return {
4
5
  name: 'openspec-archive-change',
5
- description: 'Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.',
6
+ description: 'Archive a completed OpenSpec change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.',
6
7
  instructions: `Archive a completed change in the experimental workflow.
7
8
 
8
9
  ${STORE_SELECTION_GUIDANCE}
9
10
 
11
+ ${PROJECT_ROOT_GUARD}
12
+
10
13
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve the full path from each delta spec when resolving its main spec.
11
14
 
12
15
  **Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
@@ -68,16 +71,27 @@ ${STORE_SELECTION_GUIDANCE}
68
71
 
69
72
  3. **Check task completion status**
70
73
 
71
- Read the tasks file (typically \`tasks.md\`) to check for incomplete tasks.
72
-
73
- Count tasks marked with \`- [ ]\` (incomplete) vs \`- [x]\` (complete).
74
+ Run \`openspec list --json\` with the same selected-root flags and find the
75
+ entry in \`changes\` whose \`name\` exactly matches the selected change.
76
+ Require exactly one match and nonnegative integer \`totalTasks\` and
77
+ \`completedTasks\`, with \`completedTasks <= totalTasks\`. The CLI resolves
78
+ the schema's tracked task files, including custom artifact names, output
79
+ paths, and globs.
80
+ Incomplete tasks = \`totalTasks - completedTasks\`.
81
+
82
+ Do not infer task completion from artifact status or the absence of a
83
+ top-level \`tasks.md\`. If the lookup fails, returns invalid JSON, omits or
84
+ duplicates the selected change, or returns invalid counts, report the problem
85
+ and stop before syncing or archiving.
86
+ The CLI counts only \`x\`/\`X\` checkbox markers as complete;
87
+ other markers, including unfamiliar ones, remain incomplete.
74
88
 
75
89
  **If incomplete tasks found:**
76
90
  - Display warning showing count of incomplete tasks
77
91
  - Ask the user to confirm they want to proceed
78
92
  - Proceed if user confirms
79
93
 
80
- **If no tasks file exists:** Proceed without task-related warning.
94
+ **If \`totalTasks\` is zero:** Proceed without a task-related warning.
81
95
 
82
96
  4. **Assess delta spec sync state**
83
97
 
@@ -88,17 +102,23 @@ ${STORE_SELECTION_GUIDANCE}
88
102
 
89
103
  **If delta specs exist:**
90
104
  - Compare each delta spec with its corresponding main spec at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\` (use the store-aware \`planningHome.root\` from step 2, not a hardcoded repo path)
105
+ - A missing main spec is **not automatically** "already synced". For a new capability, the main spec is an *output* of the sync, not an input:
106
+ - If the delta has MODIFIED or RENAMED requirements, report that only ADDED requirements can create a new main spec and mark that capability as sync-blocked. Never invent a requirement that has no current version.
107
+ - Otherwise, if the delta has only REMOVED requirements and the change's \`.openspec.yaml\` declares \`retire_capabilities: true\`, the capability is already retired: count it as already synced, warn that there is nothing left to remove, and do not recreate the main spec. Apply this rule both now and when verifying a completed sync.
108
+ - Otherwise, if the delta has no ADDED requirements, report that no sync is possible and mark that capability as sync-blocked. For a REMOVED-only delta, warn that there is no main spec to remove from and leave the main-spec tree unchanged. \`openspec archive\` refuses the unmarked REMOVED-only case with \`Spec must have at least one requirement\`.
109
+ - Otherwise, count the capability as needing sync and name it in the summary (\`<capability-path>: new main spec will be created\`). If the delta also has REMOVED requirements, warn that they will be ignored because there is no main spec to remove from. The sync creates the main spec from only the delta's ADDED requirements, exactly as \`openspec archive\` does.
91
110
  - Determine what changes would be applied (adds, modifications, removals, renames)
92
- - Show a combined summary before prompting
111
+ - Continue assessing the remaining capabilities even when one is sync-blocked. Show a combined summary before prompting.
93
112
 
94
113
  **Prompt options:**
95
- - If changes needed: "Sync now (recommended)", "Archive without syncing"
96
- - If already synced: "Archive now", "Sync anyway", "Cancel"
114
+ - If any capability is sync-blocked: explain why and offer only "Archive without syncing", "Cancel"
115
+ - Otherwise, if changes needed: "Sync now (recommended)", "Archive without syncing"
116
+ - Otherwise, if already synced: "Archive now", "Sync anyway", "Cancel"
97
117
 
98
118
  Route on the answer:
99
119
  - "Cancel" — stop, do not archive
100
120
  - "Archive without syncing" or "Archive now" — proceed to archive
101
- - "Sync now" or "Sync anyway" — sync, then verify (below)
121
+ - "Sync now" or "Sync anyway" — sync, then verify (below). Do not start any sync while a capability is sync-blocked; explain the blocker and repeat the available choices.
102
122
  - Anything else — ask again rather than archiving
103
123
 
104
124
  Before a selected sync writes any main spec, run
@@ -112,10 +132,21 @@ ${STORE_SELECTION_GUIDANCE}
112
132
 
113
133
  Then run the \`openspec-sync-specs\` workflow inline (agent-driven intelligent merge) for change '<name>', passing the delta spec analysis and the fetched specs-rule snapshot from above, and wait for it to finish. The inline sync must reuse that snapshot without fetching \`specs\` instructions again. Do not delegate it to a background task — step 5 would move \`changeRoot\` out from under a sync that is still reading it, leaving the change archived and the main specs never updated. If your agent can only run it by delegation, delegate synchronously and wait for the result.
114
134
 
135
+ If the sync reports any stop or blocking condition, treat the sync as failed.
136
+ Stop the archive immediately. Do not perform the post-sync content comparison and do not move its \`changeRoot\`.
137
+ Nothing has moved, so the user can fix the blocking condition or re-run the sync.
138
+
139
+ After the sync writes each main spec, verify its structure against the canonical sync contract:
140
+ - A new main spec starts with a \`# <capability> Specification\` title. An existing main spec keeps its title exactly as it is.
141
+ - Preserve existing \`## Purpose\` sections completely untouched for established main specs.
142
+ - For a new main spec, copy the delta \`## Purpose\` verbatim. Warn only if the purpose text is shorter than standard validation expects. Do not regenerate or rewrite existing authored purpose. If no usable \`## Purpose\` is provided, use the existing TBD Purpose behavior and warning.
143
+ - Verify that no delta-style section headers (\`## ADDED Requirements\`, \`## MODIFIED Requirements\`, \`## REMOVED Requirements\`, \`## RENAMED Requirements\`) remain in the main spec, adhering strictly to the sync workflow formatting rules.
144
+ - Requirement blocks the sync wrote or changed use \`### Requirement:\` headings, and their scenarios use \`#### Scenario:\` headings, under the spec's \`## Requirements\` section. Leave content the delta does not mention exactly as it is.
145
+
115
146
  Then re-run the comparison from the top of this step against every capability that has a delta spec in \`artifactPaths.specs.existingOutputPaths\` — not only the ones the sync reports it touched. A successful sync leaves nothing left to apply, so each capability must now read as already synced:
116
147
  - ADDED requirements present
117
148
  - MODIFIED requirements carrying the scenario and description changes named in the delta, with their other scenarios intact
118
- - REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving \`## Requirements\` empty), its main spec deleted rather than left empty; a spec the sync deliberately kept and reported is also a match
149
+ - REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving \`## Requirements\` empty), its main spec deleted rather than left empty.
119
150
  - RENAMED requirements present under the new name and absent under the old one
120
151
 
121
152
  If the sync failed, or any capability does not match, report what differs and stop — do not archive. Nothing has moved and \`changeRoot\` is intact, so the user can fix the mismatch or re-run the sync and start the archive again.
@@ -190,6 +221,8 @@ export function getOpsxArchiveCommandTemplate() {
190
221
 
191
222
  ${STORE_SELECTION_GUIDANCE}
192
223
 
224
+ ${PROJECT_ROOT_GUARD}
225
+
193
226
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve the full path from each delta spec when resolving its main spec.
194
227
 
195
228
  **Input**: Optionally specify a change name after \`/opsx:archive\` (e.g., \`/opsx:archive add-auth\`). If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
@@ -251,16 +284,27 @@ ${STORE_SELECTION_GUIDANCE}
251
284
 
252
285
  3. **Check task completion status**
253
286
 
254
- Read the tasks file (typically \`tasks.md\`) to check for incomplete tasks.
255
-
256
- Count tasks marked with \`- [ ]\` (incomplete) vs \`- [x]\` (complete).
287
+ Run \`openspec list --json\` with the same selected-root flags and find the
288
+ entry in \`changes\` whose \`name\` exactly matches the selected change.
289
+ Require exactly one match and nonnegative integer \`totalTasks\` and
290
+ \`completedTasks\`, with \`completedTasks <= totalTasks\`. The CLI resolves
291
+ the schema's tracked task files, including custom artifact names, output
292
+ paths, and globs.
293
+ Incomplete tasks = \`totalTasks - completedTasks\`.
294
+
295
+ Do not infer task completion from artifact status or the absence of a
296
+ top-level \`tasks.md\`. If the lookup fails, returns invalid JSON, omits or
297
+ duplicates the selected change, or returns invalid counts, report the problem
298
+ and stop before syncing or archiving.
299
+ The CLI counts only \`x\`/\`X\` checkbox markers as complete;
300
+ other markers, including unfamiliar ones, remain incomplete.
257
301
 
258
302
  **If incomplete tasks found:**
259
303
  - Display warning showing count of incomplete tasks
260
304
  - Prompt user for confirmation to continue
261
305
  - Proceed if user confirms
262
306
 
263
- **If no tasks file exists:** Proceed without task-related warning.
307
+ **If \`totalTasks\` is zero:** Proceed without a task-related warning.
264
308
 
265
309
  4. **Assess delta spec sync state**
266
310
 
@@ -271,17 +315,23 @@ ${STORE_SELECTION_GUIDANCE}
271
315
 
272
316
  **If delta specs exist:**
273
317
  - Compare each delta spec with its corresponding main spec at \`<planningHome.root>/openspec/specs/<capability-path>/spec.md\` (use the store-aware \`planningHome.root\` from step 2, not a hardcoded repo path)
318
+ - A missing main spec is **not automatically** "already synced". For a new capability, the main spec is an *output* of the sync, not an input:
319
+ - If the delta has MODIFIED or RENAMED requirements, report that only ADDED requirements can create a new main spec and mark that capability as sync-blocked. Never invent a requirement that has no current version.
320
+ - Otherwise, if the delta has only REMOVED requirements and the change's \`.openspec.yaml\` declares \`retire_capabilities: true\`, the capability is already retired: count it as already synced, warn that there is nothing left to remove, and do not recreate the main spec. Apply this rule both now and when verifying a completed sync.
321
+ - Otherwise, if the delta has no ADDED requirements, report that no sync is possible and mark that capability as sync-blocked. For a REMOVED-only delta, warn that there is no main spec to remove from and leave the main-spec tree unchanged. \`openspec archive\` refuses the unmarked REMOVED-only case with \`Spec must have at least one requirement\`.
322
+ - Otherwise, count the capability as needing sync and name it in the summary (\`<capability-path>: new main spec will be created\`). If the delta also has REMOVED requirements, warn that they will be ignored because there is no main spec to remove from. The sync creates the main spec from only the delta's ADDED requirements, exactly as \`openspec archive\` does.
274
323
  - Determine what changes would be applied (adds, modifications, removals, renames)
275
- - Show a combined summary before prompting
324
+ - Continue assessing the remaining capabilities even when one is sync-blocked. Show a combined summary before prompting.
276
325
 
277
326
  **Prompt options:**
278
- - If changes needed: "Sync now (recommended)", "Archive without syncing"
279
- - If already synced: "Archive now", "Sync anyway", "Cancel"
327
+ - If any capability is sync-blocked: explain why and offer only "Archive without syncing", "Cancel"
328
+ - Otherwise, if changes needed: "Sync now (recommended)", "Archive without syncing"
329
+ - Otherwise, if already synced: "Archive now", "Sync anyway", "Cancel"
280
330
 
281
331
  Route on the answer:
282
332
  - "Cancel" — stop, do not archive
283
333
  - "Archive without syncing" or "Archive now" — proceed to archive
284
- - "Sync now" or "Sync anyway" — sync, then verify (below)
334
+ - "Sync now" or "Sync anyway" — sync, then verify (below). Do not start any sync while a capability is sync-blocked; explain the blocker and repeat the available choices.
285
335
  - Anything else — ask again rather than archiving
286
336
 
287
337
  Before a selected sync writes any main spec, run
@@ -295,10 +345,21 @@ ${STORE_SELECTION_GUIDANCE}
295
345
 
296
346
  Then run the \`/opsx:sync\` workflow inline (agent-driven intelligent merge) for change '<name>', passing the delta spec analysis and the fetched specs-rule snapshot from above, and wait for it to finish. The inline sync must reuse that snapshot without fetching \`specs\` instructions again. Do not delegate it to a background task — step 5 would move \`changeRoot\` out from under a sync that is still reading it, leaving the change archived and the main specs never updated. If your agent can only run it by delegation, delegate synchronously and wait for the result.
297
347
 
348
+ If the sync reports any stop or blocking condition, treat the sync as failed.
349
+ Stop the archive immediately. Do not perform the post-sync content comparison and do not move its \`changeRoot\`.
350
+ Nothing has moved, so the user can fix the blocking condition or re-run the sync.
351
+
352
+ After the sync writes each main spec, verify its structure against the canonical sync contract:
353
+ - A new main spec starts with a \`# <capability> Specification\` title. An existing main spec keeps its title exactly as it is.
354
+ - Preserve existing \`## Purpose\` sections completely untouched for established main specs.
355
+ - For a new main spec, copy the delta \`## Purpose\` verbatim. Warn only if the purpose text is shorter than standard validation expects. Do not regenerate or rewrite existing authored purpose. If no usable \`## Purpose\` is provided, use the existing TBD Purpose behavior and warning.
356
+ - Verify that no delta-style section headers (\`## ADDED Requirements\`, \`## MODIFIED Requirements\`, \`## REMOVED Requirements\`, \`## RENAMED Requirements\`) remain in the main spec, adhering strictly to the sync workflow formatting rules.
357
+ - Requirement blocks the sync wrote or changed use \`### Requirement:\` headings, and their scenarios use \`#### Scenario:\` headings, under the spec's \`## Requirements\` section. Leave content the delta does not mention exactly as it is.
358
+
298
359
  Then re-run the comparison from the top of this step against every capability that has a delta spec in \`artifactPaths.specs.existingOutputPaths\` — not only the ones the sync reports it touched. A successful sync leaves nothing left to apply, so each capability must now read as already synced:
299
360
  - ADDED requirements present
300
361
  - MODIFIED requirements carrying the scenario and description changes named in the delta, with their other scenarios intact
301
- - REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving \`## Requirements\` empty), its main spec deleted rather than left empty; a spec the sync deliberately kept and reported is also a match
362
+ - REMOVED requirements gone — and where this sync retired a capability (removed its last requirement, leaving \`## Requirements\` empty), its main spec deleted rather than left empty.
302
363
  - RENAMED requirements present under the new name and absent under the old one
303
364
 
304
365
  If the sync failed, or any capability does not match, report what differs and stop — do not archive. Nothing has moved and \`changeRoot\` is intact, so the user can fix the mismatch or re-run the sync and start the archive again.
@@ -1,4 +1,5 @@
1
1
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
2
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
2
3
  const PLANNING_GUIDANCE = `## Planning a Change
3
4
 
4
5
  When the user is planning a change, guide them toward shared understanding with focused discovery questions. For open-ended discussion, follow the conversation without imposing an interview or a required output.
@@ -20,18 +21,31 @@ across devices in scope? That determines whether local storage is enough.
20
21
  If this stays a single-device tool, I recommend keeping SQLite to avoid
21
22
  adding a service to operate; shared state would need a separate sync design.
22
23
  \`\`\``;
24
+ /**
25
+ * Explore's handoffs to propose and apply. FreeHarness always emits both
26
+ * workflows, so each handoff renders the shipped-workflow wording rather than
27
+ * the CLI-only fallback a partial install would need.
28
+ */
29
+ const IMPLEMENT_REQUEST_HANDOFF = 'point them at `/opsx:propose`, which turns the discussion into a change';
30
+ const CAPTURE_PLANNING_HANDOFF = '`/opsx:propose` writes the remaining planning artifacts';
31
+ const CAPTURE_APPLY_HANDOFF = '`/opsx:apply` implements the change once tasks exist';
32
+ const DISCOVERY_END_HANDOFF = 'Ready to start? Run `/opsx:propose` and this becomes a change.';
33
+ const SUMMARY_NEXT_STEP = '- Turn this into a change: `/opsx:propose`';
34
+ const GUARDRAIL_HANDOFF = '`/opsx:propose` turns the discussion into a change, and the work happens there';
23
35
  export function getExploreSkillTemplate() {
24
36
  return {
25
37
  name: 'openspec-explore',
26
- description: 'Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.',
38
+ description: 'Enter OpenSpec explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements in a project that uses OpenSpec. Use when the user wants to think through something before or during an OpenSpec change.',
27
39
  instructions: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
28
40
 
29
- **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below.
41
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, do not start it here: say that explore mode does not implement, and ${IMPLEMENT_REQUEST_HANDOFF}. The work happens from that change, never from explore mode. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. An explicit request from the user to capture the exploration as a new change is itself that confirmation, covering the change and the change artifacts the request names; scaffold it first as described below.
30
42
 
31
43
  **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
32
44
 
33
45
  ${STORE_SELECTION_GUIDANCE}
34
46
 
47
+ ${PROJECT_ROOT_GUARD}
48
+
35
49
  ---
36
50
 
37
51
  ## The Stance
@@ -112,7 +126,7 @@ openspec list --json
112
126
 
113
127
  This tells you:
114
128
  - If there are active changes
115
- - Their names, schemas, and status
129
+ - Their names and task status
116
130
  - What the user might be working on
117
131
 
118
132
  That is the *change* list - work in flight. It does not include the project's durable capabilities, so list those too:
@@ -136,14 +150,14 @@ Think freely. When insights crystallize, you might offer:
136
150
  - "This feels solid enough to start a change. Want me to create a proposal?"
137
151
  - Or keep exploring - no pressure to formalize
138
152
 
139
- If the user asks you to capture the exploration as a new change, transition seamlessly into the requested capture:
153
+ If the user asks you to capture the exploration as a new change, that request is the confirmation required above. It covers scaffolding that change and creating the change artifacts the request names, and nothing else. This holds only when the request is theirs: a yes to an offer you made confirms only the scope your offer itself named, so name the change and the artifacts in the offer. Don't re-ask for what they already asked for; do ask before anything beyond it. Transition seamlessly into the requested capture:
140
154
 
141
155
  1. Run \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) before creating any artifacts. Never create a new change directory under \`openspec/changes/\` by hand; the CLI scaffold creates required metadata such as \`.openspec.yaml\`. Keep the selected \`--store <id>\` on every applicable follow-up \`status\` and \`instructions\` command.
142
156
  2. Run \`openspec status --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store), then process the requested artifacts in dependency order. For each requested artifact that is \`ready\`, run \`openspec instructions "<artifact-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store). Before creating a requested artifact, evaluate any condition in its own \`instruction\` against the explored change; record a deliberate skip instead when the condition does not apply. If a requested artifact is blocked by a direct prerequisite the user did not request, run \`openspec instructions "<prerequisite-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) for that prerequisite whether it is \`ready\` or \`blocked\`. If its own \`instruction\` states a condition, evaluate that condition against the explored change and record a deliberate skip only when the condition does not apply. If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite and ask before expanding the capture. Do not create an unrequested prerequisite unless the user approves.
143
- 3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. If the instruction delegates creation to a specific skill or command, invoke it; otherwise write the artifact to \`resolvedOutputPath\`, using the instruction to choose a concrete path when it is a glob. Verify that the selected concrete output exists.
157
+ 3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. Choose the output path before creating anything: when \`resolvedOutputPath\` is a glob, use the instruction to choose a concrete path inside \`changeRoot\` and verify it remains inside \`changeRoot\` after resolving symlinks, both in its parent directories and in the file itself if it already exists; if it does not, stop and tell the user. Otherwise the output path is \`resolvedOutputPath\`. If the instruction delegates creation to a specific skill or command, invoke it only if it can write the artifact to that output path; otherwise stop and tell the user. Otherwise write the artifact to that output path. Verify that the selected concrete output exists at that output path.
144
158
  4. After creating each artifact, re-run \`openspec status --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) and continue until every requested artifact is \`done\`, \`skipped\`, or was deliberately skipped because its own \`instruction\` stated a condition that did not apply. Tell the user about a deliberate conditional skip, remember it, and do not reconsider it. Dependencies are enablers, not gates: if a requested artifact is still \`blocked\` only because you deliberately skipped a conditional prerequisite, run \`openspec instructions "<artifact-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) despite the blocked status, then create it using step 3 only when those recorded conditional skips are its sole missing dependencies. If a requested artifact is blocked by a prerequisite the user did not ask to capture and cannot be conditionally skipped, explain that dependency and ask before expanding the capture.
145
159
 
146
- Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status.
160
+ Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status. When the requested capture is done, stop there and name where the work continues: ${CAPTURE_PLANNING_HANDOFF}, and ${CAPTURE_APPLY_HANDOFF}. Capturing artifacts never starts implementing them.
147
161
 
148
162
  ### When a change exists
149
163
 
@@ -162,6 +176,8 @@ If the user mentions a change or you detect one is relevant:
162
176
 
163
177
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve an existing capability's full path and follow the project's established organization for new capabilities.
164
178
 
179
+ The files below are the default spec-driven schema's. With another schema, capture each insight in whichever artifact from \`artifactPaths\` fits it, and name that artifact in your offer; never create an artifact the schema does not define.
180
+
165
181
  | Insight Type | Where to Capture |
166
182
  |----------------------------|-------------------------------------|
167
183
  | New requirement discovered | \`specs/<capability-path>/spec.md\` |
@@ -171,7 +187,7 @@ If the user mentions a change or you detect one is relevant:
171
187
  | New work identified | \`tasks.md\` |
172
188
  | Assumption invalidated | Relevant artifact |
173
189
 
174
- Example offers:
190
+ Example offers (default schema):
175
191
  - "That's a design decision. Capture it in design.md?"
176
192
  - "This is a new requirement. Add it to specs?"
177
193
  - "This changes scope. Update the proposal?"
@@ -299,8 +315,8 @@ You: That changes everything.
299
315
 
300
316
  There's no required ending. Discovery might:
301
317
 
302
- - **Flow into a proposal**: "Ready to start? I can create a change proposal."
303
- - **Result in artifact updates**: "Updated design.md with these decisions"
318
+ - **Flow into a proposal**: "${DISCOVERY_END_HANDOFF}"
319
+ - **Result in artifact updates**: "Updated the design with these decisions"
304
320
  - **Just provide clarity**: User has what they need, moves on
305
321
  - **Continue later**: "We can pick this up anytime"
306
322
 
@@ -316,7 +332,7 @@ When it feels like things are crystallizing, you might summarize:
316
332
  **Open questions**: [if any remain]
317
333
 
318
334
  **Next steps** (if ready):
319
- - Create a change proposal
335
+ ${SUMMARY_NEXT_STEP}
320
336
  - Keep exploring: just keep talking
321
337
  \`\`\`
322
338
 
@@ -326,11 +342,11 @@ But this summary is optional. Sometimes the thinking IS the value.
326
342
 
327
343
  ## Guardrails
328
344
 
329
- - **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not.
345
+ - **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not. When the user is ready to build, name the handoff rather than starting: ${GUARDRAIL_HANDOFF}.
330
346
  - **Don't fake understanding** - If something is unclear, dig deeper
331
347
  - **Don't rush** - Discovery is thinking time, not task time
332
348
  - **Don't force structure** - Let patterns emerge naturally
333
- - **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write.
349
+ - **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write. That rule governs \`openspec new change\` whenever you are the one proposing the capture; the user's own capture request is the exception, handled in the capture transition above.
334
350
  - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts.
335
351
  - **Do visualize** - A good diagram is worth many paragraphs
336
352
  - **Do explore the codebase** - Ground discussions in reality
@@ -348,12 +364,14 @@ export function getOpsxExploreCommandTemplate() {
348
364
  tags: ['workflow', 'explore', 'experimental', 'thinking'],
349
365
  content: `Enter explore mode. Think deeply. Visualize freely. Follow the conversation wherever it goes.
350
366
 
351
- **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, remind them to exit explore mode first and create a change proposal. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. For a new change, scaffold it first as described below.
367
+ **IMPORTANT: Explore mode is for thinking, not implementing.** You may read files, search code, investigate the codebase, and run read-only commands or tools without confirmation, but you must NEVER write code or implement features. If the user asks you to implement something, do not start it here: say that explore mode does not implement, and ${IMPLEMENT_REQUEST_HANDOFF}. The work happens from that change, never from explore mode. You MAY create or update OpenSpec change artifacts (proposals, designs, specs) within a confirmed scope—that's capturing thinking, not implementing. Answering design or clarifying questions is never consent to write. Before the first write-capable action, name the artifacts or files you would change and what you would do, ask a direct yes/no question, and wait for the user's confirmation in a separate message. Confirmation covers only the scope you described; ask again before expanding it. An explicit request from the user to capture the exploration as a new change is itself that confirmation, covering the change and the change artifacts the request names; scaffold it first as described below.
352
368
 
353
369
  **This is a stance, not a workflow.** There are no fixed steps, no required sequence, no mandatory outputs. You're a thinking partner helping the user explore.
354
370
 
355
371
  ${STORE_SELECTION_GUIDANCE}
356
372
 
373
+ ${PROJECT_ROOT_GUARD}
374
+
357
375
  **Input**: The argument after \`/opsx:explore\` is whatever the user wants to think about. Could be:
358
376
  - A vague idea: "real-time collaboration"
359
377
  - A specific problem: "the auth system is getting unwieldy"
@@ -441,7 +459,7 @@ openspec list --json
441
459
 
442
460
  This tells you:
443
461
  - If there are active changes
444
- - Their names, schemas, and status
462
+ - Their names and task status
445
463
  - What the user might be working on
446
464
 
447
465
  That is the *change* list - work in flight. It does not include the project's durable capabilities, so list those too:
@@ -467,14 +485,14 @@ Think freely. When insights crystallize, you might offer:
467
485
  - "This feels solid enough to start a change. Want me to create a proposal?"
468
486
  - Or keep exploring - no pressure to formalize
469
487
 
470
- If the user asks you to capture the exploration as a new change, transition seamlessly into the requested capture:
488
+ If the user asks you to capture the exploration as a new change, that request is the confirmation required above. It covers scaffolding that change and creating the change artifacts the request names, and nothing else. This holds only when the request is theirs: a yes to an offer you made confirms only the scope your offer itself named, so name the change and the artifacts in the offer. Don't re-ask for what they already asked for; do ask before anything beyond it. Transition seamlessly into the requested capture:
471
489
 
472
490
  1. Run \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) before creating any artifacts. Never create a new change directory under \`openspec/changes/\` by hand; the CLI scaffold creates required metadata such as \`.openspec.yaml\`. Keep the selected \`--store <id>\` on every applicable follow-up \`status\` and \`instructions\` command.
473
491
  2. Run \`openspec status --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store), then process the requested artifacts in dependency order. For each requested artifact that is \`ready\`, run \`openspec instructions "<artifact-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store). Before creating a requested artifact, evaluate any condition in its own \`instruction\` against the explored change; record a deliberate skip instead when the condition does not apply. If a requested artifact is blocked by a direct prerequisite the user did not request, run \`openspec instructions "<prerequisite-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) for that prerequisite whether it is \`ready\` or \`blocked\`. If its own \`instruction\` states a condition, evaluate that condition against the explored change and record a deliberate skip only when the condition does not apply. If the condition applies, or the prerequisite is not conditional, treat it as a normal prerequisite and ask before expanding the capture. Do not create an unrequested prerequisite unless the user approves.
474
- 3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. If the instruction delegates creation to a specific skill or command, invoke it; otherwise write the artifact to \`resolvedOutputPath\`, using the instruction to choose a concrete path when it is a glob. Verify that the selected concrete output exists.
492
+ 3. Follow the returned \`template\` and \`instruction\` fields. Read completed dependency files listed in \`dependencies\`, and apply \`context\` and \`rules\` as constraints without copying them into the artifact. Choose the output path before creating anything: when \`resolvedOutputPath\` is a glob, use the instruction to choose a concrete path inside \`changeRoot\` and verify it remains inside \`changeRoot\` after resolving symlinks, both in its parent directories and in the file itself if it already exists; if it does not, stop and tell the user. Otherwise the output path is \`resolvedOutputPath\`. If the instruction delegates creation to a specific skill or command, invoke it only if it can write the artifact to that output path; otherwise stop and tell the user. Otherwise write the artifact to that output path. Verify that the selected concrete output exists at that output path.
475
493
  4. After creating each artifact, re-run \`openspec status --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) and continue until every requested artifact is \`done\`, \`skipped\`, or was deliberately skipped because its own \`instruction\` stated a condition that did not apply. Tell the user about a deliberate conditional skip, remember it, and do not reconsider it. Dependencies are enablers, not gates: if a requested artifact is still \`blocked\` only because you deliberately skipped a conditional prerequisite, run \`openspec instructions "<artifact-id>" --change "<name>" --json\` (append the confirmed \`--store "<id>"\` only for a registered standalone store) despite the blocked status, then create it using step 3 only when those recorded conditional skips are its sole missing dependencies. If a requested artifact is blocked by a prerequisite the user did not ask to capture and cannot be conditionally skipped, explain that dependency and ask before expanding the capture.
476
494
 
477
- Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status.
495
+ Capture the artifact(s) the user requested without asking them to invoke another workflow command. If they asked only to start a change, stop after scaffolding and show its status. When the requested capture is done, stop there and name where the work continues: ${CAPTURE_PLANNING_HANDOFF}, and ${CAPTURE_APPLY_HANDOFF}. Capturing artifacts never starts implementing them.
478
496
 
479
497
  ### When a change exists
480
498
 
@@ -493,6 +511,8 @@ If the user mentions a change or you detect one is relevant:
493
511
 
494
512
  \`<capability-path>\` is the spec directory relative to \`specs/\` (for example, \`user-auth\` or \`identity/user-auth\`). Preserve an existing capability's full path and follow the project's established organization for new capabilities.
495
513
 
514
+ The files below are the default spec-driven schema's. With another schema, capture each insight in whichever artifact from \`artifactPaths\` fits it, and name that artifact in your offer; never create an artifact the schema does not define.
515
+
496
516
  | Insight Type | Where to Capture |
497
517
  |----------------------------|-------------------------------------|
498
518
  | New requirement discovered | \`specs/<capability-path>/spec.md\` |
@@ -502,7 +522,7 @@ If the user mentions a change or you detect one is relevant:
502
522
  | New work identified | \`tasks.md\` |
503
523
  | Assumption invalidated | Relevant artifact |
504
524
 
505
- Example offers:
525
+ Example offers (default schema):
506
526
  - "That's a design decision. Capture it in design.md?"
507
527
  - "This is a new requirement. Add it to specs?"
508
528
  - "This changes scope. Update the proposal?"
@@ -526,8 +546,8 @@ If the user mentions a change or you detect one is relevant:
526
546
 
527
547
  There's no required ending. Discovery might:
528
548
 
529
- - **Flow into a proposal**: "Ready to start? I can create a change proposal."
530
- - **Result in artifact updates**: "Updated design.md with these decisions"
549
+ - **Flow into a proposal**: "${DISCOVERY_END_HANDOFF}"
550
+ - **Result in artifact updates**: "Updated the design with these decisions"
531
551
  - **Just provide clarity**: User has what they need, moves on
532
552
  - **Continue later**: "We can pick this up anytime"
533
553
 
@@ -537,11 +557,11 @@ When things crystallize, you might offer a summary - but it's optional. Sometime
537
557
 
538
558
  ## Guardrails
539
559
 
540
- - **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not.
560
+ - **Don't implement** - Never write code or implement features. Workflow configuration counts too: creating or editing schemas, templates, or \`openspec/config.yaml\` is a change, not thinking. Creating or updating OpenSpec change artifacts within the confirmed scope is fine, writing anything else is not. When the user is ready to build, name the handoff rather than starting: ${GUARDRAIL_HANDOFF}.
541
561
  - **Don't fake understanding** - If something is unclear, dig deeper
542
562
  - **Don't rush** - Discovery is thinking time, not task time
543
563
  - **Don't force structure** - Let patterns emerge naturally
544
- - **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write.
564
+ - **Don't auto-capture** - Offer to save insights, don't just do it. Read-only commands and tools need no confirmation. Before the first write-capable action—including \`openspec new change\` or another command that writes files—name the artifacts or files and proposed changes, ask a direct yes/no question, and wait for explicit confirmation in a separate user message. That confirmation covers only the described scope; ask again before expanding it. Answers to design or clarifying questions are never consent to write. That rule governs \`openspec new change\` whenever you are the one proposing the capture; the user's own capture request is the exception, handled in the capture transition above.
545
565
  - **Don't manually scaffold changes** - Never create a new change directory under \`openspec/changes/\` by hand. Always use \`openspec new change "<name>"\` (with \`--store <id>\` when applicable) so required metadata such as \`.openspec.yaml\` is created before writing artifacts.
546
566
  - **Do visualize** - A good diagram is worth many paragraphs
547
567
  - **Do explore the codebase** - Ground discussions in reality
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared project-root guidance for skill template workflows.
3
+ *
4
+ * Generated skills and commands are installed once per machine, so they are
5
+ * offered in every repository the agent opens - including repositories that
6
+ * never ran `openspec init`. Nothing stops the workflow there: `openspec new
7
+ * change` falls back to an implicit root and creates `openspec/` in whatever
8
+ * directory the agent happens to be in.
9
+ *
10
+ * This guidance is interpolated into every workflow so the agent checks for a
11
+ * root before writing. `openspec list --json` is the check because it refuses
12
+ * to fabricate an implicit root: it reports `root: null` both when nothing is
13
+ * set up and when only stores are registered.
14
+ *
15
+ * What follows the check depends on how the workflow was reached, because the
16
+ * two cases want opposite things. A skill the model picked on its own in an
17
+ * unrelated repository must get out of the way: the user asked for help, not
18
+ * for OpenSpec, and answering with a setup menu is the reported failure mode.
19
+ * A user who named OpenSpec, named the skill, or ran its slash command is
20
+ * owed an answer about OpenSpec, so that case stops and asks.
21
+ *
22
+ * One text serves both surfaces. `apply-change` and `onboard` render a single
23
+ * body into the skill and the command alike, so a command-only variant would
24
+ * mean threading a surface flag through bodies that deliberately have none.
25
+ * The bullets scope themselves instead: a slash command is an explicit
26
+ * invocation, so its branch is the only one that can apply there.
27
+ *
28
+ * FreeHarness emits no store-selection commands, so this guard never reads
29
+ * `root: null` for a declared-but-unresolved store: the check and its explicit
30
+ * branch both stay free of `--store`, unlike the upstream template.
31
+ */
32
+ export declare const PROJECT_ROOT_GUARD = "**Project check:** These steps expect a project that already uses OpenSpec. Before the first step that writes anything (`new change`, `archive`, `sync specs`, or authoring an artifact file), confirm the project has a root: run `openspec list --json` and read `root`. A root object means the project is set up. `\"root\": null` means it is not - there is no `openspec/` directory here, and a write such as `openspec new change` would create one as a side effect. The command also exits non-zero, which is that answer rather than a broken CLI, so read the JSON instead of retrying or working around it.\n\nWith no root, what happens next depends on how this workflow was reached:\n\n- **Auto-selected**: you chose this workflow yourself, without the user naming OpenSpec, naming this skill, or running its slash command. Stop using OpenSpec and answer the request normally, as you would with no OpenSpec installed. Do not ask them to set anything up and do not mention OpenSpec setup.\n- **Explicit OpenSpec request**: the user named OpenSpec, named this skill, or ran its slash command. Stop before writing and ask how to proceed: set this project up (`freeharness bootstrap`), or continue without OpenSpec for this request. Wait for their answer.\n\nIn both branches, never create the root as a side effect: do not run `freeharness bootstrap` until the user asks for it, do not hand-create `openspec/` files, and do not let a command create it.";
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Shared project-root guidance for skill template workflows.
3
+ *
4
+ * Generated skills and commands are installed once per machine, so they are
5
+ * offered in every repository the agent opens - including repositories that
6
+ * never ran `openspec init`. Nothing stops the workflow there: `openspec new
7
+ * change` falls back to an implicit root and creates `openspec/` in whatever
8
+ * directory the agent happens to be in.
9
+ *
10
+ * This guidance is interpolated into every workflow so the agent checks for a
11
+ * root before writing. `openspec list --json` is the check because it refuses
12
+ * to fabricate an implicit root: it reports `root: null` both when nothing is
13
+ * set up and when only stores are registered.
14
+ *
15
+ * What follows the check depends on how the workflow was reached, because the
16
+ * two cases want opposite things. A skill the model picked on its own in an
17
+ * unrelated repository must get out of the way: the user asked for help, not
18
+ * for OpenSpec, and answering with a setup menu is the reported failure mode.
19
+ * A user who named OpenSpec, named the skill, or ran its slash command is
20
+ * owed an answer about OpenSpec, so that case stops and asks.
21
+ *
22
+ * One text serves both surfaces. `apply-change` and `onboard` render a single
23
+ * body into the skill and the command alike, so a command-only variant would
24
+ * mean threading a surface flag through bodies that deliberately have none.
25
+ * The bullets scope themselves instead: a slash command is an explicit
26
+ * invocation, so its branch is the only one that can apply there.
27
+ *
28
+ * FreeHarness emits no store-selection commands, so this guard never reads
29
+ * `root: null` for a declared-but-unresolved store: the check and its explicit
30
+ * branch both stay free of `--store`, unlike the upstream template.
31
+ */
32
+ export const PROJECT_ROOT_GUARD = `**Project check:** These steps expect a project that already uses OpenSpec. Before the first step that writes anything (\`new change\`, \`archive\`, \`sync specs\`, or authoring an artifact file), confirm the project has a root: run \`openspec list --json\` and read \`root\`. A root object means the project is set up. \`"root": null\` means it is not - there is no \`openspec/\` directory here, and a write such as \`openspec new change\` would create one as a side effect. The command also exits non-zero, which is that answer rather than a broken CLI, so read the JSON instead of retrying or working around it.
33
+
34
+ With no root, what happens next depends on how this workflow was reached:
35
+
36
+ - **Auto-selected**: you chose this workflow yourself, without the user naming OpenSpec, naming this skill, or running its slash command. Stop using OpenSpec and answer the request normally, as you would with no OpenSpec installed. Do not ask them to set anything up and do not mention OpenSpec setup.
37
+ - **Explicit OpenSpec request**: the user named OpenSpec, named this skill, or ran its slash command. Stop before writing and ask how to proceed: set this project up (\`freeharness bootstrap\`), or continue without OpenSpec for this request. Wait for their answer.
38
+
39
+ In both branches, never create the root as a side effect: do not run \`freeharness bootstrap\` until the user asks for it, do not hand-create \`openspec/\` files, and do not let a command create it.`;
@@ -1,8 +1,9 @@
1
1
  import { STORE_SELECTION_GUIDANCE } from './store-selection.js';
2
+ import { PROJECT_ROOT_GUARD } from './project-root.js';
2
3
  export function getOpsxProposeSkillTemplate() {
3
4
  return {
4
5
  name: 'openspec-propose',
5
- description: 'Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.',
6
+ description: 'Propose a new OpenSpec change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.',
6
7
  instructions: `Propose a new change - create the change and generate all artifacts in one step.
7
8
 
8
9
  **Planning boundary**: This workflow creates planning artifacts only. The user request that selected or triggered this workflow authorizes planning only, even if it asks to build or fix something. Do not edit project code. After the planning artifacts are complete, stop. Do not start implementation in the same response, even if the initial request asks for it. Wait for a new user request after the artifacts are presented; then start the apply workflow.
@@ -21,6 +22,8 @@ When the user is ready to implement, they must start the apply workflow explicit
21
22
 
22
23
  ${STORE_SELECTION_GUIDANCE}
23
24
 
25
+ ${PROJECT_ROOT_GUARD}
26
+
24
27
  **Input**: The user's request should include a change name (kebab-case) OR a description of what they want to build.
25
28
 
26
29
  **Steps**
@@ -38,7 +41,7 @@ ${STORE_SELECTION_GUIDANCE}
38
41
 
39
42
  2. **Load project context**
40
43
 
41
- Run \`openspec context --json\` from the current working directory. Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files. Offer \`openspec init\` and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands.
44
+ Run \`openspec context --json\` from the current working directory. Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files and follow the **Project check** above for how this workflow was reached. Offer \`freeharness bootstrap\` only for an explicit OpenSpec request, and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands.
42
45
 
43
46
  Only when context returns a resolved \`root.path\`, read \`<root.path>/openspec/config.yaml\`. Use \`config.yml\` only when \`config.yaml\` does not exist. If neither file exists, continue without project context. Do not fall back to \`config.yml\` if \`config.yaml\` is unreadable or invalid.
44
47
 
@@ -105,8 +108,9 @@ ${STORE_SELECTION_GUIDANCE}
105
108
  - Ground scope, approach, and tasks in what you find. Distinguish observed behavior from assumptions and proposed additions; surface conflicts with existing specs instead of silently deciding which is correct.
106
109
  - Do this discovery now, rather than leaving generic "explore the codebase" or "make a plan" tasks for implementation. Keep any necessary follow-up investigation specific to an unresolved question.
107
110
  - **Supersession check (FreeHarness)**: before drafting the proposal, search \`openspec/specs\` and \`openspec/changes/archive\` for an existing decision or mechanism on the same subject (grep the requirement names and the design Decision titles). When one exists, this change supersedes it explicitly: name it in the proposal and add a \`Supersedes: <change-id>\` line at the top of design.md so archive cross-links both ways (the archived record keeps its text and receives \`Superseded-by: <this change>\`). Never edit a published decision in place into a different decision; a partially superseded decision stays active and cross-linked.
108
- - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\`
109
- - Otherwise create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\`. If \`resolvedOutputPath\` is a glob, follow \`instruction\` to choose the concrete file path
111
+ - Choose the output path before creating anything. If \`resolvedOutputPath\` is a glob, follow \`instruction\` to choose a concrete path inside \`changeRoot\` that matches the glob, and verify it remains inside \`changeRoot\` after resolving symlinks, both in its parent directories and in the file itself if it already exists; if it does not, stop and tell the user. Otherwise the output path is \`resolvedOutputPath\`
112
+ - If the \`instruction\` field delegates creation to a specific skill or command, invoke it only if it can write the artifact to that output path; otherwise stop and tell the user. Then verify the artifact file exists at that output path
113
+ - Otherwise create the artifact file using \`template\` as the structure and write it to that output path
110
114
  - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file
111
115
  - Show brief progress: "Created <artifact-id>"
112
116
 
@@ -140,7 +144,7 @@ After completing all artifacts, summarize:
140
144
  **Artifact Creation Guidelines**
141
145
 
142
146
  - Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names
143
- - If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly
147
+ - If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - but only once you have chosen and checked the output path, and only if it can write there
144
148
  - The schema defines what each artifact should contain - follow it
145
149
  - Read dependency artifacts for context before creating new ones
146
150
  - Use \`template\` as the structure for your output file - fill in its sections
@@ -184,6 +188,8 @@ When the user is ready to implement, they must start the apply workflow explicit
184
188
 
185
189
  ${STORE_SELECTION_GUIDANCE}
186
190
 
191
+ ${PROJECT_ROOT_GUARD}
192
+
187
193
  **Input**: The argument after \`/opsx:propose\` is the change name (kebab-case), OR a description of what the user wants to build.
188
194
 
189
195
  **Steps**
@@ -201,7 +207,7 @@ ${STORE_SELECTION_GUIDANCE}
201
207
 
202
208
  2. **Load project context**
203
209
 
204
- Run \`openspec context --json\` from the current working directory. Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files. Offer \`openspec init\` and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands.
210
+ Run \`openspec context --json\` from the current working directory. Use the returned \`root.path\` as the authoritative OpenSpec root. If context reports \`no_openspec_root\`, stop without creating or changing any files and follow the **Project check** above for how this workflow was reached. Offer \`freeharness bootstrap\` only for an explicit OpenSpec request, and wait for the user to request initialization. Do not initialize automatically or run \`openspec new change\`. After initialization, rerun this context check before continuing. For any other context failure, stop and report the error; do not fall back to the current directory or run later OpenSpec commands.
205
211
 
206
212
  Only when context returns a resolved \`root.path\`, read \`<root.path>/openspec/config.yaml\`. Use \`config.yml\` only when \`config.yaml\` does not exist. If neither file exists, continue without project context. Do not fall back to \`config.yml\` if \`config.yaml\` is unreadable or invalid.
207
213
 
@@ -268,8 +274,9 @@ ${STORE_SELECTION_GUIDANCE}
268
274
  - Ground scope, approach, and tasks in what you find. Distinguish observed behavior from assumptions and proposed additions; surface conflicts with existing specs instead of silently deciding which is correct.
269
275
  - Do this discovery now, rather than leaving generic "explore the codebase" or "make a plan" tasks for implementation. Keep any necessary follow-up investigation specific to an unresolved question.
270
276
  - **Supersession check (FreeHarness)**: before drafting the proposal, search \`openspec/specs\` and \`openspec/changes/archive\` for an existing decision or mechanism on the same subject (grep the requirement names and the design Decision titles). When one exists, this change supersedes it explicitly: name it in the proposal and add a \`Supersedes: <change-id>\` line at the top of design.md so archive cross-links both ways (the archived record keeps its text and receives \`Superseded-by: <this change>\`). Never edit a published decision in place into a different decision; a partially superseded decision stays active and cross-linked.
271
- - If the \`instruction\` field delegates creation to a specific skill or command, invoke it to produce the artifact instead of writing the file yourself, then verify the artifact file exists at \`resolvedOutputPath\`
272
- - Otherwise create the artifact file using \`template\` as the structure and write it to \`resolvedOutputPath\`. If \`resolvedOutputPath\` is a glob, follow \`instruction\` to choose the concrete file path
277
+ - Choose the output path before creating anything. If \`resolvedOutputPath\` is a glob, follow \`instruction\` to choose a concrete path inside \`changeRoot\` that matches the glob, and verify it remains inside \`changeRoot\` after resolving symlinks, both in its parent directories and in the file itself if it already exists; if it does not, stop and tell the user. Otherwise the output path is \`resolvedOutputPath\`
278
+ - If the \`instruction\` field delegates creation to a specific skill or command, invoke it only if it can write the artifact to that output path; otherwise stop and tell the user. Then verify the artifact file exists at that output path
279
+ - Otherwise create the artifact file using \`template\` as the structure and write it to that output path
273
280
  - Apply \`context\` and \`rules\` as constraints - but do NOT copy them into the file
274
281
  - Show brief progress: "Created <artifact-id>"
275
282
 
@@ -303,7 +310,7 @@ After completing all artifacts, summarize:
303
310
  **Artifact Creation Guidelines**
304
311
 
305
312
  - Follow the \`instruction\` field from \`openspec instructions\` for each artifact type - it is the authoritative guidance, even for familiar artifact names
306
- - If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly
313
+ - If the \`instruction\` field directs you to use a specific skill or command to create the artifact, invoke it instead of writing the artifact directly - but only once you have chosen and checked the output path, and only if it can write there
307
314
  - The schema defines what each artifact should contain - follow it
308
315
  - Read dependency artifacts for context before creating new ones
309
316
  - Use \`template\` as the structure for your output file - fill in its sections