omegon 0.6.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.
Files changed (160) hide show
  1. package/.gitattributes +3 -0
  2. package/AGENTS.md +16 -0
  3. package/LICENSE +15 -0
  4. package/README.md +289 -0
  5. package/bin/pi.mjs +30 -0
  6. package/extensions/00-secrets/index.ts +1126 -0
  7. package/extensions/01-auth/auth.ts +401 -0
  8. package/extensions/01-auth/index.ts +289 -0
  9. package/extensions/auto-compact.ts +42 -0
  10. package/extensions/bootstrap/deps.ts +291 -0
  11. package/extensions/bootstrap/index.ts +811 -0
  12. package/extensions/chronos/chronos.sh +487 -0
  13. package/extensions/chronos/index.ts +148 -0
  14. package/extensions/cleave/assessment.ts +754 -0
  15. package/extensions/cleave/bridge.ts +31 -0
  16. package/extensions/cleave/conflicts.ts +250 -0
  17. package/extensions/cleave/dispatcher.ts +808 -0
  18. package/extensions/cleave/guardrails.ts +426 -0
  19. package/extensions/cleave/index.ts +3121 -0
  20. package/extensions/cleave/lifecycle-emitter.ts +20 -0
  21. package/extensions/cleave/openspec.ts +811 -0
  22. package/extensions/cleave/planner.ts +260 -0
  23. package/extensions/cleave/review.ts +579 -0
  24. package/extensions/cleave/skills.ts +355 -0
  25. package/extensions/cleave/types.ts +261 -0
  26. package/extensions/cleave/workspace.ts +861 -0
  27. package/extensions/cleave/worktree.ts +243 -0
  28. package/extensions/core-renderers.ts +253 -0
  29. package/extensions/dashboard/context-gauge.ts +58 -0
  30. package/extensions/dashboard/file-watch.ts +14 -0
  31. package/extensions/dashboard/footer.ts +1145 -0
  32. package/extensions/dashboard/git.ts +185 -0
  33. package/extensions/dashboard/index.ts +478 -0
  34. package/extensions/dashboard/memory-audit.ts +34 -0
  35. package/extensions/dashboard/overlay-data.ts +705 -0
  36. package/extensions/dashboard/overlay.ts +365 -0
  37. package/extensions/dashboard/render-utils.ts +54 -0
  38. package/extensions/dashboard/types.ts +191 -0
  39. package/extensions/dashboard/uri-helper.ts +45 -0
  40. package/extensions/debug.ts +69 -0
  41. package/extensions/defaults.ts +282 -0
  42. package/extensions/design-tree/dashboard-state.ts +161 -0
  43. package/extensions/design-tree/design-card.ts +362 -0
  44. package/extensions/design-tree/index.ts +2130 -0
  45. package/extensions/design-tree/lifecycle-emitter.ts +41 -0
  46. package/extensions/design-tree/tree.ts +1607 -0
  47. package/extensions/design-tree/types.ts +163 -0
  48. package/extensions/distill.ts +127 -0
  49. package/extensions/effort/index.ts +395 -0
  50. package/extensions/effort/tiers.ts +146 -0
  51. package/extensions/effort/types.ts +105 -0
  52. package/extensions/lib/git-state.ts +227 -0
  53. package/extensions/lib/local-models.ts +157 -0
  54. package/extensions/lib/model-preferences.ts +51 -0
  55. package/extensions/lib/model-routing.ts +720 -0
  56. package/extensions/lib/operator-fallback.ts +205 -0
  57. package/extensions/lib/operator-profile.ts +360 -0
  58. package/extensions/lib/slash-command-bridge.ts +253 -0
  59. package/extensions/lib/typebox-helpers.ts +16 -0
  60. package/extensions/local-inference/index.ts +727 -0
  61. package/extensions/mcp-bridge/README.md +220 -0
  62. package/extensions/mcp-bridge/index.ts +951 -0
  63. package/extensions/mcp-bridge/lib.ts +365 -0
  64. package/extensions/mcp-bridge/mcp.json +3 -0
  65. package/extensions/mcp-bridge/package.json +11 -0
  66. package/extensions/model-budget.ts +752 -0
  67. package/extensions/offline-driver.ts +403 -0
  68. package/extensions/openspec/archive-gate.ts +164 -0
  69. package/extensions/openspec/branch-cleanup.ts +64 -0
  70. package/extensions/openspec/dashboard-state.ts +50 -0
  71. package/extensions/openspec/index.ts +1917 -0
  72. package/extensions/openspec/lifecycle-emitter.ts +65 -0
  73. package/extensions/openspec/lifecycle-files.ts +70 -0
  74. package/extensions/openspec/lifecycle.ts +50 -0
  75. package/extensions/openspec/reconcile.ts +187 -0
  76. package/extensions/openspec/spec.ts +1385 -0
  77. package/extensions/openspec/types.ts +98 -0
  78. package/extensions/project-memory/DESIGN-global-mind.md +198 -0
  79. package/extensions/project-memory/README.md +202 -0
  80. package/extensions/project-memory/api-types.ts +382 -0
  81. package/extensions/project-memory/compaction-policy.ts +29 -0
  82. package/extensions/project-memory/core.ts +164 -0
  83. package/extensions/project-memory/embeddings.ts +230 -0
  84. package/extensions/project-memory/extraction-v2.ts +861 -0
  85. package/extensions/project-memory/factstore.ts +2177 -0
  86. package/extensions/project-memory/index.ts +3459 -0
  87. package/extensions/project-memory/injection-metrics.ts +91 -0
  88. package/extensions/project-memory/jsonl-io.ts +12 -0
  89. package/extensions/project-memory/lifecycle.ts +331 -0
  90. package/extensions/project-memory/migration.ts +293 -0
  91. package/extensions/project-memory/package.json +9 -0
  92. package/extensions/project-memory/sci-renderers.ts +7 -0
  93. package/extensions/project-memory/template.ts +103 -0
  94. package/extensions/project-memory/triggers.ts +52 -0
  95. package/extensions/project-memory/types.ts +102 -0
  96. package/extensions/render/composition/fonts/Inter-Bold.ttf +0 -0
  97. package/extensions/render/composition/fonts/Inter-Regular.ttf +0 -0
  98. package/extensions/render/composition/fonts/Tomorrow-Bold.ttf +0 -0
  99. package/extensions/render/composition/fonts/Tomorrow-Regular.ttf +0 -0
  100. package/extensions/render/composition/package-lock.json +534 -0
  101. package/extensions/render/composition/package.json +22 -0
  102. package/extensions/render/composition/render.mjs +246 -0
  103. package/extensions/render/composition/test-comp.tsx +87 -0
  104. package/extensions/render/composition/types.ts +24 -0
  105. package/extensions/render/excalidraw/UPSTREAM.md +81 -0
  106. package/extensions/render/excalidraw/elements.ts +764 -0
  107. package/extensions/render/excalidraw/index.ts +66 -0
  108. package/extensions/render/excalidraw/types.ts +223 -0
  109. package/extensions/render/excalidraw-renderer/pyproject.toml +8 -0
  110. package/extensions/render/excalidraw-renderer/render_excalidraw.py +182 -0
  111. package/extensions/render/excalidraw-renderer/render_template.html +59 -0
  112. package/extensions/render/index.ts +830 -0
  113. package/extensions/render/native-diagrams/index.ts +57 -0
  114. package/extensions/render/native-diagrams/motifs.ts +542 -0
  115. package/extensions/render/native-diagrams/raster.ts +8 -0
  116. package/extensions/render/native-diagrams/scene.ts +75 -0
  117. package/extensions/render/native-diagrams/spec.ts +204 -0
  118. package/extensions/render/native-diagrams/svg.ts +116 -0
  119. package/extensions/sci-ui.ts +304 -0
  120. package/extensions/session-log.ts +174 -0
  121. package/extensions/shared-state.ts +146 -0
  122. package/extensions/spinner-verbs.ts +91 -0
  123. package/extensions/style.ts +281 -0
  124. package/extensions/terminal-title.ts +191 -0
  125. package/extensions/tool-profile/index.ts +291 -0
  126. package/extensions/tool-profile/profiles.ts +290 -0
  127. package/extensions/types.d.ts +9 -0
  128. package/extensions/vault/index.ts +185 -0
  129. package/extensions/version-check.ts +90 -0
  130. package/extensions/view/index.ts +859 -0
  131. package/extensions/view/uri-resolver.ts +148 -0
  132. package/extensions/web-search/index.ts +182 -0
  133. package/extensions/web-search/providers.ts +121 -0
  134. package/extensions/web-ui/index.ts +110 -0
  135. package/extensions/web-ui/server.ts +265 -0
  136. package/extensions/web-ui/state.ts +462 -0
  137. package/extensions/web-ui/static/index.html +145 -0
  138. package/extensions/web-ui/types.ts +284 -0
  139. package/package.json +76 -0
  140. package/prompts/init.md +75 -0
  141. package/prompts/new-repo.md +54 -0
  142. package/prompts/oci-login.md +56 -0
  143. package/prompts/status.md +50 -0
  144. package/settings.json +4 -0
  145. package/skills/cleave/SKILL.md +218 -0
  146. package/skills/git/SKILL.md +209 -0
  147. package/skills/git/_reference/ci-validation.md +204 -0
  148. package/skills/oci/SKILL.md +338 -0
  149. package/skills/openspec/SKILL.md +346 -0
  150. package/skills/pi-extensions/SKILL.md +191 -0
  151. package/skills/pi-tui/SKILL.md +517 -0
  152. package/skills/python/SKILL.md +189 -0
  153. package/skills/rust/SKILL.md +268 -0
  154. package/skills/security/SKILL.md +206 -0
  155. package/skills/style/SKILL.md +264 -0
  156. package/skills/typescript/SKILL.md +225 -0
  157. package/skills/vault/SKILL.md +102 -0
  158. package/themes/alpharius-legacy.json +85 -0
  159. package/themes/alpharius.conf +59 -0
  160. package/themes/alpharius.json +88 -0
@@ -0,0 +1,338 @@
1
+ ---
2
+ name: oci
3
+ description: OCI container and artifact best practices. Covers Containerfile authoring, multi-arch builds, registry authentication, image tagging, security scanning, and artifact management. Use when building, pushing, or managing container images and OCI artifacts.
4
+ ---
5
+
6
+ # OCI Skill
7
+
8
+ Conventions for container images, OCI artifacts, and registry operations.
9
+
10
+ ## Core Conventions
11
+
12
+ - **Containerfile** (not Dockerfile) as the canonical name
13
+ - **Podman** preferred, Docker compatible — commands are interchangeable
14
+ - **Multi-stage builds** to minimize final image size
15
+ - **Non-root** user in production images
16
+ - **Immutable tags** — never overwrite a published tag
17
+
18
+ ## Registry Authentication
19
+
20
+ ### GHCR (GitHub Container Registry)
21
+
22
+ ```bash
23
+ echo "$GITHUB_TOKEN" | docker login ghcr.io -u USERNAME --password-stdin
24
+ ```
25
+
26
+ ### AWS ECR
27
+
28
+ ```bash
29
+ aws ecr get-login-password --region us-east-1 | \
30
+ docker login --username AWS --password-stdin ACCOUNT.dkr.ecr.us-east-1.amazonaws.com
31
+ ```
32
+
33
+ ECR tokens expire after 12 hours. In CI, call before every push.
34
+
35
+ ### Docker Hub
36
+
37
+ ```bash
38
+ echo "$DOCKER_TOKEN" | docker login -u USERNAME --password-stdin
39
+ ```
40
+
41
+ ### Credential Helpers
42
+
43
+ | Registry | Helper |
44
+ |----------|--------|
45
+ | GHCR | `docker-credential-gh` (via `gh auth setup-docker`) |
46
+ | ECR | `docker-credential-ecr-login` (from `amazon-ecr-credential-helper`) |
47
+ | GCR/GAR | `docker-credential-gcloud` |
48
+
49
+ Configure in `~/.docker/config.json`:
50
+ ```json
51
+ {
52
+ "credHelpers": {
53
+ "ghcr.io": "gh",
54
+ "ACCOUNT.dkr.ecr.REGION.amazonaws.com": "ecr-login"
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Containerfile Conventions
60
+
61
+ ### Structure
62
+
63
+ ```dockerfile
64
+ # syntax=docker/dockerfile:1
65
+ FROM python:3.12-slim AS builder
66
+
67
+ WORKDIR /app
68
+ COPY requirements.txt .
69
+ RUN pip install --no-cache-dir -r requirements.txt
70
+
71
+ COPY src/ src/
72
+
73
+ FROM python:3.12-slim
74
+ WORKDIR /app
75
+ COPY --from=builder /app /app
76
+
77
+ RUN useradd -r -s /bin/false appuser
78
+ USER appuser
79
+
80
+ EXPOSE 8080
81
+ ENTRYPOINT ["python", "-m", "myapp"]
82
+ ```
83
+
84
+ ### Rules
85
+
86
+ | Rule | Rationale |
87
+ |------|-----------|
88
+ | Pin base image digests in CI | Reproducible builds |
89
+ | `--no-cache-dir` on pip install | Smaller layers |
90
+ | `COPY` specific paths, not `.` | Cache efficiency, avoid leaking secrets |
91
+ | `ARG` defaults for versions | Co-locate version with build definition |
92
+ | `LABEL org.opencontainers.image.*` | OCI metadata standard |
93
+ | One `RUN` per logical step | Readability over layer count (BuildKit caches well) |
94
+
95
+ ### ARG Defaults — Not Build Scripts
96
+
97
+ Define version defaults in the Containerfile, not in justfiles or Makefiles:
98
+
99
+ ```dockerfile
100
+ # Good — version lives with the build definition
101
+ ARG PYTHON_VERSION=3.12
102
+ FROM python:${PYTHON_VERSION}-slim
103
+
104
+ # Bad — hardcoded in justfile creates manual update obligation
105
+ # just build --build-arg PYTHON_VERSION=3.12
106
+ ```
107
+
108
+ Override only when needed: `docker build --build-arg PYTHON_VERSION=3.13 .`
109
+
110
+ ### .dockerignore
111
+
112
+ Always include one. Minimum:
113
+
114
+ ```
115
+ .git
116
+ .venv
117
+ __pycache__
118
+ *.pyc
119
+ node_modules
120
+ .env
121
+ *.secret
122
+ ```
123
+
124
+ ## Cross-Platform Builds
125
+
126
+ ### Apple Silicon → amd64 Clusters
127
+
128
+ **Always specify `--platform` when the build host differs from the target.**
129
+
130
+ ```bash
131
+ # Building on arm64 Mac for amd64 Kubernetes
132
+ docker build --platform linux/amd64 -t myimage:latest .
133
+ ```
134
+
135
+ Without `--platform`, the image is arm64 and **fails silently** on amd64 nodes.
136
+
137
+ ### Multi-Arch with Buildx
138
+
139
+ ```bash
140
+ docker buildx create --name multiarch --use
141
+ docker buildx build \
142
+ --platform linux/amd64,linux/arm64 \
143
+ --tag ghcr.io/org/image:v1.0.0 \
144
+ --push .
145
+ ```
146
+
147
+ ### Cache Busting
148
+
149
+ Combine `--no-cache` with `--platform` to prevent stale cross-arch layer caches:
150
+
151
+ ```bash
152
+ docker build --platform linux/amd64 --no-cache -t myimage:latest .
153
+ ```
154
+
155
+ Stale pip caches can serve arm64 wheels even when targeting amd64.
156
+
157
+ ## Tagging Strategy
158
+
159
+ ### Convention
160
+
161
+ ```
162
+ REGISTRY/ORG/IMAGE:TAG
163
+ ```
164
+
165
+ ### Tag Types
166
+
167
+ | Tag | When | Example |
168
+ |-----|------|---------|
169
+ | Semver | Release | `v1.2.3` |
170
+ | SHA | Every build | `sha-a1b2c3d` |
171
+ | Branch | Dev builds | `main`, `feature-x` |
172
+ | `latest` | **Avoid** | Ambiguous, not reproducible |
173
+
174
+ ### Tagging Commands
175
+
176
+ ```bash
177
+ # Tag with semver + SHA
178
+ IMAGE=ghcr.io/org/myapp
179
+ SHA=$(git rev-parse --short HEAD)
180
+ VERSION=v1.2.3
181
+
182
+ docker tag myapp:latest "$IMAGE:$VERSION"
183
+ docker tag myapp:latest "$IMAGE:sha-$SHA"
184
+ docker push "$IMAGE:$VERSION"
185
+ docker push "$IMAGE:sha-$SHA"
186
+ ```
187
+
188
+ ## OCI Artifacts (Beyond Images)
189
+
190
+ OCI registries store more than container images:
191
+
192
+ | Artifact | Tool | Push Command |
193
+ |----------|------|-------------|
194
+ | Helm charts | `helm` | `helm push chart.tgz oci://ghcr.io/org/charts` |
195
+ | SBOMs | `cosign` | `cosign attach sbom --sbom sbom.spdx IMAGE` |
196
+ | Signatures | `cosign` | `cosign sign IMAGE` |
197
+ | Attestations | `cosign` | `cosign attest --predicate provenance.json IMAGE` |
198
+ | Arbitrary files | `oras` | `oras push ghcr.io/org/artifact:v1 ./file.txt` |
199
+
200
+ ### Helm OCI Push
201
+
202
+ ```bash
203
+ helm package ./chart
204
+ helm push chart-1.0.0.tgz oci://ghcr.io/org/charts
205
+ ```
206
+
207
+ ### Image Signing with Cosign
208
+
209
+ ```bash
210
+ # Keyless signing (GitHub Actions OIDC)
211
+ cosign sign ghcr.io/org/image@sha256:DIGEST
212
+
213
+ # Key-based
214
+ cosign generate-key-pair
215
+ cosign sign --key cosign.key ghcr.io/org/image:v1.0.0
216
+ cosign verify --key cosign.pub ghcr.io/org/image:v1.0.0
217
+ ```
218
+
219
+ ## Security Scanning
220
+
221
+ ### Trivy
222
+
223
+ ```bash
224
+ trivy image ghcr.io/org/image:v1.0.0 # Scan image
225
+ trivy fs . # Scan filesystem/deps
226
+ trivy image --severity HIGH,CRITICAL IMAGE # Filter severity
227
+ trivy image --exit-code 1 IMAGE # Fail CI on findings
228
+ ```
229
+
230
+ ### Docker Scout (Docker Desktop)
231
+
232
+ ```bash
233
+ docker scout cves IMAGE # CVE scan
234
+ docker scout quickview IMAGE # Summary
235
+ docker scout recommendations IMAGE # Base image suggestions
236
+ ```
237
+
238
+ ### Grype
239
+
240
+ ```bash
241
+ grype IMAGE # Vulnerability scan
242
+ grype dir:. # Scan local project
243
+ ```
244
+
245
+ ## Registry Management
246
+
247
+ ### Lifecycle Policies (ECR)
248
+
249
+ ```json
250
+ {
251
+ "rules": [{
252
+ "rulePriority": 1,
253
+ "description": "Expire untagged after 7 days",
254
+ "selection": {
255
+ "tagStatus": "untagged",
256
+ "countType": "sinceImagePushed",
257
+ "countUnit": "days",
258
+ "countNumber": 7
259
+ },
260
+ "action": { "type": "expire" }
261
+ }]
262
+ }
263
+ ```
264
+
265
+ ### GHCR Cleanup
266
+
267
+ ```bash
268
+ # List package versions
269
+ gh api user/packages/container/IMAGE/versions | jq '.[].metadata.container.tags'
270
+
271
+ # Delete untagged
272
+ gh api --method DELETE user/packages/container/IMAGE/versions/VERSION_ID
273
+ ```
274
+
275
+ ### Repository Naming
276
+
277
+ ```
278
+ ghcr.io/ORG/SERVICE # Application image
279
+ ghcr.io/ORG/charts/SERVICE # Helm chart
280
+ ghcr.io/ORG/base/RUNTIME # Shared base images
281
+ ```
282
+
283
+ ## CI/CD Integration
284
+
285
+ ### GitHub Actions
286
+
287
+ ```yaml
288
+ - uses: docker/login-action@v3
289
+ with:
290
+ registry: ghcr.io
291
+ username: ${{ github.actor }}
292
+ password: ${{ secrets.GITHUB_TOKEN }}
293
+
294
+ - uses: docker/build-push-action@v6
295
+ with:
296
+ context: .
297
+ push: true
298
+ platforms: linux/amd64,linux/arm64
299
+ tags: |
300
+ ghcr.io/${{ github.repository }}:${{ github.sha }}
301
+ ghcr.io/${{ github.repository }}:latest
302
+ cache-from: type=gha
303
+ cache-to: type=gha,mode=max
304
+ ```
305
+
306
+ ### Build Cache (BuildKit)
307
+
308
+ | Cache Backend | Use Case |
309
+ |--------------|----------|
310
+ | `type=gha` | GitHub Actions (free, limited) |
311
+ | `type=registry` | Push cache layers to registry |
312
+ | `type=local` | Local directory (CI runners with persistent storage) |
313
+
314
+ ## Debugging
315
+
316
+ ```bash
317
+ docker history IMAGE # Layer sizes
318
+ docker inspect IMAGE # Full metadata
319
+ docker manifest inspect IMAGE # Multi-arch manifest
320
+ dive IMAGE # Interactive layer explorer
321
+ crane manifest IMAGE # OCI manifest (no Docker needed)
322
+ skopeo inspect docker://IMAGE # Remote inspection
323
+ ```
324
+
325
+ ## Common Gotchas
326
+
327
+ | Issue | Fix |
328
+ |-------|-----|
329
+ | Image works locally, fails in k8s | Missing `--platform linux/amd64` on Apple Silicon build |
330
+ | Push denied to GHCR | `gh auth token` scope needs `write:packages` |
331
+ | Stale layers after dep update | `--no-cache` or `--no-cache-filter=stage_name` |
332
+ | ECR login expired | Re-run `aws ecr get-login-password` (12h TTL) |
333
+ | `latest` tag not updating | Tag is a pointer, not auto-updated — push explicitly |
334
+ | Large image size | Multi-stage build, slim/distroless base, `.dockerignore` |
335
+ | Build context too large | Check `.dockerignore`, avoid `COPY . .` |
336
+ | Helm OCI push fails | `helm registry login` first, chart must be packaged `.tgz` |
337
+ | Runtime DB lost on restart | Mount persistent volume, or use config-file-backed state |
338
+ | `ARG` before `FROM` not visible after | Re-declare `ARG` after `FROM` to use in later stages |
@@ -0,0 +1,346 @@
1
+ ---
2
+ name: openspec
3
+ description: OpenSpec lifecycle for spec-driven development. Use when proposing changes, writing Given/When/Then specs, generating tasks, verifying implementations, or archiving completed changes. Commands /opsx:propose, /opsx:spec, /opsx:ff, /opsx:status, /opsx:verify, /opsx:archive.
4
+ ---
5
+
6
+ # OpenSpec — Spec-Driven Development Lifecycle
7
+
8
+ > **Load this skill** when working with OpenSpec changes, writing specs, generating tasks, or verifying implementations against specifications.
9
+
10
+ ## Overview
11
+
12
+ OpenSpec is Omegon's specification layer for spec-and-test-driven development. It ensures that every non-trivial change follows the lifecycle:
13
+
14
+ ```
15
+ propose → spec → plan → implement → verify → archive
16
+ ```
17
+
18
+ Specs define **what must be true** before code is written. They are the source of truth for correctness.
19
+
20
+ ## Lifecycle Stages
21
+
22
+ | Stage | Artifacts | Next Action |
23
+ |-------|-----------|-------------|
24
+ | **proposed** | `proposal.md` | `/opsx:spec <change>` — write specs |
25
+ | **specified** | `specs/*.md` | `/opsx:ff <change>` — generate design + tasks |
26
+ | **planned** | `design.md`, `tasks.md` | `/cleave` — execute tasks |
27
+ | **implementing** | tasks in progress | continue work or `/cleave` |
28
+ | **verifying** | all tasks done | `/assess spec <change>` → `/opsx:archive` |
29
+ | **archived** | specs merged to baseline | complete |
30
+
31
+ ## Lifecycle Reconciliation (required)
32
+
33
+ OpenSpec artifacts are not write-once planning docs. Treat them as runtime lifecycle state.
34
+
35
+ At these checkpoints, reconcile the artifacts to match reality:
36
+
37
+ 1. **Implement / scaffold** — ensure the design-tree node is bound to the OpenSpec change and marked `implementing`
38
+ 2. **Post-cleave** — ensure `tasks.md` reflects merged work, not just original intent
39
+ 3. **Post-assess / post-fix** — after `/assess spec` or `/assess cleave`, reopen lifecycle state if review found remaining work, and append implementation-note deltas when fixes expanded file scope or constraints
40
+ 4. **Pre-archive** — ensure the bound design-tree node and `tasks.md` are current before closing the change
41
+
42
+ Archive is expected to refuse obviously stale lifecycle state, especially:
43
+ - incomplete tasks in `tasks.md`
44
+ - no design-tree binding for the change
45
+
46
+ ## Directory Structure
47
+
48
+ ```
49
+ openspec/
50
+ ├── changes/
51
+ │ └── <change-name>/
52
+ │ ├── proposal.md # Intent, scope, success criteria
53
+ │ ├── design.md # Architecture decisions, file changes
54
+ │ ├── tasks.md # Numbered task groups for /cleave
55
+ │ └── specs/
56
+ │ ├── <domain>.md # Delta specs with Given/When/Then
57
+ │ └── <domain>/
58
+ │ └── <sub>.md # Nested domain specs
59
+ ├── baseline/ # Accumulated specs (post-archive)
60
+ │ └── <domain>.md
61
+ └── archive/ # Completed changes (timestamped)
62
+ └── YYYY-MM-DD-<name>/
63
+ ```
64
+
65
+ ## Spec File Format
66
+
67
+ Spec files use a **delta format** — they describe changes relative to the current baseline:
68
+
69
+ ```markdown
70
+ # <domain> — Delta Spec
71
+
72
+ ## ADDED Requirements
73
+
74
+ ### Requirement: <title>
75
+
76
+ <description of what must be true>
77
+
78
+ #### Scenario: <scenario title>
79
+ Given <precondition>
80
+ When <action>
81
+ Then <expected outcome>
82
+ And <additional expectation>
83
+
84
+ ## MODIFIED Requirements
85
+
86
+ ### Requirement: <title>
87
+
88
+ <what changed and why>
89
+
90
+ #### Scenario: <updated scenario>
91
+ Given <new precondition>
92
+ When <action>
93
+ Then <updated expectation>
94
+
95
+ ## REMOVED Requirements
96
+
97
+ ### Requirement: <title>
98
+
99
+ <why this is being removed>
100
+ ```
101
+
102
+ ### Writing Good Scenarios
103
+
104
+ - **Given** establishes the starting state — be specific
105
+ - **When** is a single action — not a compound operation
106
+ - **Then** is the observable outcome — measurable and testable
107
+ - **And** adds additional assertions to Then
108
+
109
+ **Good:**
110
+ ```
111
+ #### Scenario: Expired token rejected
112
+ Given a user has a JWT token that expired 5 minutes ago
113
+ When they make a GET request to /api/protected
114
+ Then the response status is 401
115
+ And the body contains {"error": "token_expired"}
116
+ ```
117
+
118
+ **Bad:**
119
+ ```
120
+ #### Scenario: Auth works
121
+ Given the system is running
122
+ When a user authenticates
123
+ Then it works correctly
124
+ ```
125
+
126
+ ### Deriving API Contracts from Scenarios
127
+
128
+ When a change introduces or modifies a network API (HTTP, gRPC, WebSocket), **derive an OpenAPI 3.1 spec** (or AsyncAPI for event-driven APIs) from the scenarios during the Plan phase. Place it at `openspec/changes/<id>/api.yaml`.
129
+
130
+ **Mapping rules:**
131
+
132
+ | Scenario element | OpenAPI element |
133
+ |------------------|-----------------|
134
+ | `Given` preconditions (auth, existing data) | Security schemes, parameter constraints, `x-setup` |
135
+ | `When ... request to <path>` | `paths.<path>.<method>`, request body schema |
136
+ | `Then status is <code>` | `responses.<code>` |
137
+ | `Then body contains {...}` | Response schema (`application/json`) |
138
+ | `And header <name> is <value>` | Response headers |
139
+ | Error scenarios (`401`, `404`, `422`) | Error response schemas, problem detail types |
140
+
141
+ **Example — from scenario to contract:**
142
+
143
+ Scenario:
144
+ ```
145
+ Given a user has a valid API key
146
+ When they POST to /api/widgets with {"name": "foo", "color": "blue"}
147
+ Then the response status is 201
148
+ And the body contains {"id": "<uuid>", "name": "foo", "color": "blue"}
149
+ And the Location header contains /api/widgets/<uuid>
150
+ ```
151
+
152
+ Derived OpenAPI fragment:
153
+ ```yaml
154
+ paths:
155
+ /api/widgets:
156
+ post:
157
+ security:
158
+ - apiKey: []
159
+ requestBody:
160
+ required: true
161
+ content:
162
+ application/json:
163
+ schema:
164
+ type: object
165
+ required: [name, color]
166
+ properties:
167
+ name: { type: string }
168
+ color: { type: string }
169
+ responses:
170
+ '201':
171
+ description: Widget created
172
+ headers:
173
+ Location:
174
+ schema: { type: string, format: uri }
175
+ content:
176
+ application/json:
177
+ schema:
178
+ type: object
179
+ properties:
180
+ id: { type: string, format: uuid }
181
+ name: { type: string }
182
+ color: { type: string }
183
+ ```
184
+
185
+ The contract is the **source of truth for API shape** — code implements the contract. If implementation diverges, fix the code or amend the spec with rationale.
186
+
187
+ ## Commands
188
+
189
+ | Command | Description |
190
+ |---------|-------------|
191
+ | `/opsx:propose <name> <title>` | Create a new change with proposal.md |
192
+ | `/opsx:spec <change>` | Generate/add specs (triggers agent to write scenarios) |
193
+ | `/opsx:ff <change>` | Fast-forward: scaffold design.md + tasks.md from specs |
194
+ | `/opsx:status` | Show all active changes with lifecycle stage |
195
+ | `/opsx:verify <change>` | Delegates to `/assess spec` for spec verification |
196
+ | `/opsx:archive <change>` | Archive change, merge specs to baseline |
197
+ | `/opsx:apply <change>` | Continue implementing (delegates to `/cleave`) |
198
+
199
+ ## Tool: `openspec_manage`
200
+
201
+ Agent-callable tool for programmatic lifecycle operations.
202
+
203
+ ### Actions
204
+
205
+ | Action | Required Params | Description |
206
+ |--------|----------------|-------------|
207
+ | `status` | — | List all active changes |
208
+ | `get` | `change_name` | Get change details, stage, spec summary |
209
+ | `propose` | `name`, `title`, `intent` | Create new change |
210
+ | `add_spec` | `change_name`, `domain`, `spec_content` | Add raw spec markdown |
211
+ | `generate_spec` | `change_name`, `domain` | Generate spec scaffold from proposal |
212
+ | `fast_forward` | `change_name` | Generate design.md + tasks.md |
213
+ | `archive` | `change_name` | Archive completed change |
214
+
215
+ ### `generate_spec` Optional Params
216
+
217
+ - `decisions`: Array of `{title, rationale}` — generates requirements per decision
218
+ - `open_questions`: Array of strings — generates MODIFIED Requirements placeholders
219
+
220
+ ## Integration with Cleave
221
+
222
+ OpenSpec and cleave work together:
223
+
224
+ 1. **`/opsx:ff`** generates `tasks.md` in the format cleave expects (numbered groups with checkboxes)
225
+ 2. **`/cleave`** detects `openspec/changes/<name>/tasks.md` and uses it as the split plan
226
+ 3. **`cleave_run`** with `openspec_change_path` updates task checkboxes on completion
227
+ 4. **`/assess spec`** verifies implementation against spec scenarios
228
+
229
+ ### Scenario-First Task Grouping
230
+
231
+ When generating `tasks.md`, group tasks by **spec domain** — not by file layer. Each group should own the end-to-end implementation of one or more spec files, including all file changes needed to satisfy those scenarios, even if that means multiple groups touch the same file.
232
+
233
+ **Do:**
234
+ ```markdown
235
+ ## 1. RBAC Enforcement
236
+ <!-- specs: relay/rbac -->
237
+ - [ ] Add relay.request and relay.accept capabilities to rbac.py
238
+ - [ ] Wire has_capability() check into create_session() in relay_service.py
239
+ - [ ] Return 403 when capability missing
240
+ ```
241
+
242
+ **Don't** (splits enforcement across layers):
243
+ ```markdown
244
+ ## 1. Models
245
+ - [ ] Add capabilities to rbac.py
246
+
247
+ ## 2. Service Logic
248
+ - [ ] Add session limits to relay_service.py
249
+ (RBAC enforcement falls between chairs — nobody wires has_capability)
250
+ ```
251
+
252
+ ### Spec-Domain Annotations
253
+
254
+ Each task group header should include a `<!-- specs: domain/name -->` comment declaring which spec files the group owns. Multiple domains are comma-separated:
255
+
256
+ ```markdown
257
+ ## 2. Auth and Sessions
258
+ <!-- specs: relay/rbac, relay/session -->
259
+ - [ ] Implement auth checks
260
+ - [ ] Add session lifecycle
261
+ ```
262
+
263
+ Cleave uses these annotations to deterministically map spec scenarios to child tasks as acceptance criteria. Groups without annotations fall back to heuristic matching.
264
+
265
+ ### tasks.md Format
266
+
267
+ The full format that cleave parses:
268
+ ```markdown
269
+ ## 1. Group Title
270
+ <!-- specs: domain/name -->
271
+
272
+ - [ ] 1.1 Task description
273
+ - [ ] 1.2 Another task
274
+ - [x] 1.3 Completed task
275
+ ```
276
+
277
+ ## Integration with Design Tree
278
+
279
+ The design-tree `implement` action scaffolds OpenSpec change directories from design nodes:
280
+
281
+ - Design node **children** → task groups
282
+ - Design node **decisions** → additional task groups
283
+ - Design node **open questions** → noted in tasks
284
+
285
+ ### ⚠️ The scaffolder produces a draft — always rewrite tasks.md immediately
286
+
287
+ The scaffolder reads **decisions only**. It does NOT read research sections, impl_notes file scope, or constraints. The generated `tasks.md` will contain one vague one-liner per decision title. This is expected scaffolding behaviour — it is not a usable task list.
288
+
289
+ **Immediately after every `implement` call**, you must:
290
+
291
+ 1. Read the generated `tasks.md`
292
+ 2. Read the design node's `impl_notes` (file scope + constraints) and research sections
293
+ 3. Rewrite `tasks.md` completely — treat the generated file as a placeholder, not a draft to polish
294
+
295
+ **What a correct rewrite looks like:**
296
+
297
+ - One task group per file or coherent feature area (derived from impl_notes file scope)
298
+ - Each constraint maps to at least one concrete task item
299
+ - Research code examples (method signatures, class names) translate into numbered implementation tasks
300
+ - Rejected decisions are omitted entirely — never "implement" a rejected decision
301
+ - Dependencies between groups are stated explicitly at the top of the file
302
+ - If a scaffolded OpenSpec was created before a design decision was superseded, the tasks must reflect the current decision, not the old one
303
+
304
+ **Detecting a bad tasks.md:**
305
+
306
+ - Any task item whose text is a verbatim copy of a decision title → rewrite required
307
+ - Any task group labelled "Implement [rejected decision]" → immediately rewrite
308
+ - Fewer than 3 concrete numbered subtasks per group → likely too shallow
309
+ - No mention of specific method names, file paths, or test assertions → too abstract
310
+
311
+ This rewrite step is not optional polish — it is the primary authoring step for task content. The scaffolder provides structure; the agent provides substance.
312
+
313
+ ## When to Use OpenSpec
314
+
315
+ **Always use** for:
316
+ - Multi-file changes (complexity ≥ 2.0 in cleave_assess)
317
+ - Any change affecting public APIs or data models
318
+ - Cross-cutting concerns (auth, logging, error handling)
319
+ - Changes that will be reviewed by others
320
+
321
+ **Skip for:**
322
+ - Single-file fixes, typos, config tweaks
323
+ - Changes with obvious correctness (renaming, formatting)
324
+ - Urgent hotfixes (document retroactively)
325
+
326
+ ## Workflow Example
327
+
328
+ ```
329
+ # 1. Propose
330
+ /opsx:propose jwt-auth "JWT Authentication"
331
+
332
+ # 2. Write specs (agent generates Given/When/Then)
333
+ /opsx:spec jwt-auth
334
+
335
+ # 3. Generate implementation plan
336
+ /opsx:ff jwt-auth
337
+
338
+ # 4. Execute in parallel
339
+ /cleave implement jwt-auth changes
340
+
341
+ # 5. Verify against specs
342
+ /assess spec jwt-auth
343
+
344
+ # 6. Archive
345
+ /opsx:archive jwt-auth
346
+ ```