@unified-product-graph/cli 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 (55) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +21 -0
  3. package/README.md +247 -0
  4. package/dist/cli.cjs +141010 -0
  5. package/package.json +65 -0
  6. package/skills/README.md +10 -0
  7. package/skills/upg/SKILL.md +245 -0
  8. package/skills/upg-analytics/SKILL.md +135 -0
  9. package/skills/upg-capture/SKILL.md +274 -0
  10. package/skills/upg-connect/SKILL.md +167 -0
  11. package/skills/upg-context/SKILL.md +506 -0
  12. package/skills/upg-context-intelligence/SKILL.md +227 -0
  13. package/skills/upg-design-system/SKILL.md +265 -0
  14. package/skills/upg-diff/SKILL.md +150 -0
  15. package/skills/upg-discover/SKILL.md +290 -0
  16. package/skills/upg-explore/SKILL-DETAIL.md +481 -0
  17. package/skills/upg-explore/SKILL.md +297 -0
  18. package/skills/upg-export/SKILL.md +385 -0
  19. package/skills/upg-feedback/SKILL.md +141 -0
  20. package/skills/upg-gaps/SKILL.md +376 -0
  21. package/skills/upg-hypothesis/SKILL.md +190 -0
  22. package/skills/upg-impact/SKILL.md +229 -0
  23. package/skills/upg-import/SKILL.md +189 -0
  24. package/skills/upg-init/SKILL.md +410 -0
  25. package/skills/upg-inspect/SKILL.md +167 -0
  26. package/skills/upg-journey/SKILL.md +207 -0
  27. package/skills/upg-launch/SKILL-DETAIL.md +392 -0
  28. package/skills/upg-launch/SKILL.md +141 -0
  29. package/skills/upg-migrate/SKILL.md +146 -0
  30. package/skills/upg-okr/SKILL-DETAIL.md +351 -0
  31. package/skills/upg-okr/SKILL.md +88 -0
  32. package/skills/upg-persona/SKILL.md +230 -0
  33. package/skills/upg-prioritise/SKILL.md +195 -0
  34. package/skills/upg-pull/SKILL-DETAIL.md +398 -0
  35. package/skills/upg-pull/SKILL.md +57 -0
  36. package/skills/upg-push/SKILL-DETAIL.md +385 -0
  37. package/skills/upg-push/SKILL.md +113 -0
  38. package/skills/upg-reflect/SKILL.md +201 -0
  39. package/skills/upg-research/SKILL.md +336 -0
  40. package/skills/upg-rollback/SKILL.md +163 -0
  41. package/skills/upg-run/SKILL.md +126 -0
  42. package/skills/upg-schema-changelog/SKILL.md +231 -0
  43. package/skills/upg-schema-consolidate/SKILL.md +243 -0
  44. package/skills/upg-schema-edges/SKILL.md +287 -0
  45. package/skills/upg-schema-evolve/SKILL.md +313 -0
  46. package/skills/upg-schema-health/SKILL.md +279 -0
  47. package/skills/upg-schema-update/SKILL.md +206 -0
  48. package/skills/upg-snapshot/SKILL.md +108 -0
  49. package/skills/upg-status/SKILL.md +340 -0
  50. package/skills/upg-strategy/SKILL.md +334 -0
  51. package/skills/upg-template/SKILL.md +145 -0
  52. package/skills/upg-trace/SKILL.md +197 -0
  53. package/skills/upg-tree/SKILL.md +233 -0
  54. package/skills/upg-verify/SKILL.md +223 -0
  55. package/skills/upg-workspace/SKILL.md +103 -0
@@ -0,0 +1,385 @@
1
+ ---
2
+ name: upg-push-detail
3
+ description: "Detailed push flow, sync file format, ID mapping, edge cases"
4
+ ---
5
+
6
+ # /upg-push — Push Flow Detail
7
+
8
+ ## First-Time Push (Step 4)
9
+
10
+ This runs when there is no `.upg-sync` file — the user has never pushed this graph before.
11
+
12
+ ### 4a: Match or Create Cloud Product
13
+
14
+ Check if a matching product already exists in the cloud:
15
+ - Search by title match from the product list returned in Step 2
16
+ - If found, confirm: "Found '<title>' in your cloud graph. Push local graph to this product?"
17
+ - If not found, ask: "This product doesn't exist in the cloud yet. Create '<title>' in The Product Creator?"
18
+
19
+ **Create:**
20
+ ```
21
+ mcp__upg-cloud__create_product({
22
+ title: "<product title>",
23
+ description: "<product description>"
24
+ })
25
+ ```
26
+
27
+ Record the `product_id` returned by the cloud.
28
+
29
+ ### 4b: Push All Entities
30
+
31
+ For each local node, create in the cloud using batch operations:
32
+
33
+ ```
34
+ mcp__upg-cloud__batch_create_nodes({
35
+ product_id: "<cloud_product_id>",
36
+ nodes: [
37
+ {
38
+ type: "<type>",
39
+ title: "<title>",
40
+ description: "<description>",
41
+ data: { ...properties },
42
+ parent_ref: "<parent reference for auto-edge>"
43
+ },
44
+ // ... up to 50 per batch
45
+ ]
46
+ })
47
+ ```
48
+
49
+ **Important:** Batch create supports `parent_ref` for intra-batch chaining — use this to maintain the hierarchy.
50
+
51
+ After each batch call, collect the returned cloud IDs and build the **node ID map**: `{ "n_local1": "cloud-uuid-1", "n_local2": "cloud-uuid-2", ... }`.
52
+
53
+ ### 4c: Push All Edges
54
+
55
+ For edges that weren't auto-created via parent_ref:
56
+ ```
57
+ mcp__upg-cloud__create_edge({
58
+ product_id: "<cloud_product_id>",
59
+ source_id: "<cloud_source_id>", // looked up via node_id_map
60
+ target_id: "<cloud_target_id>" // looked up via node_id_map
61
+ })
62
+ ```
63
+
64
+ Collect cloud edge IDs into the **edge ID map**: `{ "e_local1": "cloud-edge-uuid-1", ... }`.
65
+
66
+ ### 4d: Create the .upg-sync File
67
+
68
+ Compute the hash of the current `.upg` file:
69
+ ```bash
70
+ shasum -a 256 product.upg | awk '{print $1}'
71
+ ```
72
+ (Use the actual `.upg` filename — it may not be `product.upg`.)
73
+
74
+ Write the `.upg-sync` file using Bash:
75
+ ```bash
76
+ cat > .upg-sync << 'SYNC_EOF'
77
+ {
78
+ "cloud_endpoint": "https://cloud.unifiedproductgraph.org",
79
+ "product_id": "<cloud_product_id>",
80
+ "last_synced_at": "<current ISO 8601 timestamp>",
81
+ "node_id_map": {
82
+ "n_local1": "cloud-uuid-1",
83
+ "n_local2": "cloud-uuid-2"
84
+ },
85
+ "edge_id_map": {
86
+ "e_local1": "cloud-edge-uuid-1"
87
+ },
88
+ "last_snapshot_hash": "<sha256 hash from above>"
89
+ }
90
+ SYNC_EOF
91
+ ```
92
+
93
+ This file enables all future incremental pushes. Go to Step 6.
94
+
95
+ ---
96
+
97
+ ## Incremental Push (Step 5)
98
+
99
+ This runs when `.upg-sync` exists — the user has pushed before and we can sync only changes.
100
+
101
+ ### 5a: Quick Hash Check
102
+
103
+ Compute the current `.upg` file hash and compare to `last_snapshot_hash` from `.upg-sync`:
104
+
105
+ ```bash
106
+ shasum -a 256 product.upg | awk '{print $1}'
107
+ ```
108
+
109
+ If the hash **matches** `last_snapshot_hash`:
110
+ ```
111
+ Nothing to push — your graph hasn't changed since last sync.
112
+
113
+ Last synced: <last_synced_at from .upg-sync>
114
+
115
+ Make changes locally, then run /upg-push again.
116
+ ```
117
+ Stop here.
118
+
119
+ If the hash is **different**, continue to compute the changeset.
120
+
121
+ ### 5b: Verify Cloud Product Still Exists
122
+
123
+ Use the `product_id` from `.upg-sync` to check the cloud:
124
+ ```
125
+ mcp__upg-cloud__list_products()
126
+ ```
127
+
128
+ Look for the product matching the stored `product_id`.
129
+
130
+ If the cloud product is **gone** (deleted, reset, or not found):
131
+ ```
132
+ ⚠️ Your cloud product (<product_id>) no longer exists.
133
+
134
+ It may have been deleted or reset on the cloud side.
135
+
136
+ 1. 🔄 Full re-push — create a new cloud product and push everything
137
+ 2. ⏭️ Cancel — keep working locally for now
138
+
139
+ Which would you like?
140
+ ```
141
+
142
+ If the user chooses full re-push: delete the `.upg-sync` file and restart from Step 4 (first-time push flow).
143
+
144
+ ### 5c: Compute Changeset
145
+
146
+ Read the current graph state via MCP tools:
147
+ ```
148
+ list_nodes({ limit: 200 })
149
+ ```
150
+
151
+ Compare against the ID mappings in `.upg-sync`:
152
+
153
+ **New nodes:** Nodes in the current graph whose IDs are NOT in `node_id_map` keys. These need to be created on the cloud.
154
+
155
+ **Deleted nodes:** IDs that ARE in `node_id_map` but no longer exist in the current graph. These should be deleted from the cloud.
156
+
157
+ **Updated nodes:** Nodes whose IDs are in `node_id_map` AND still exist locally. For each, compare the current node data (title, description, properties, status, tags) against what's in the cloud. If anything changed, it's an update. To detect changes, fetch the cloud state:
158
+ ```
159
+ mcp__upg-cloud__get_product_graph({ product_id: "<cloud_product_id>" })
160
+ ```
161
+ Then compare each mapped node's current local state against its cloud state.
162
+
163
+ **New edges:** Edges in the current graph whose IDs are NOT in `edge_id_map` keys. Create on cloud.
164
+
165
+ **Deleted edges:** Edge IDs in `edge_id_map` that no longer exist locally. Delete from cloud.
166
+
167
+ ### 5d: Show Changeset Summary
168
+
169
+ Present the changeset for confirmation:
170
+
171
+ ```
172
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
173
+ ☁️ INCREMENTAL PUSH
174
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
175
+
176
+ Pushing changes to "<Product Name>"
177
+
178
+ ➕ <N> new entities
179
+ ✏️ <N> updated entities
180
+ 🗑️ <N> deleted entities
181
+ 🔗 <N> new connections
182
+ ✂️ <N> removed connections
183
+
184
+ New:
185
+ 📦 <Feature title>
186
+ 👤 <Persona title>
187
+
188
+ Updated:
189
+ 🎯 <Outcome title> — description changed
190
+ ⚗️ <Hypothesis title> — status changed to validated
191
+
192
+ Deleted:
193
+ 📝 <Learning title>
194
+
195
+ Push these changes? (yes / no / review details)
196
+ ```
197
+
198
+ Wait for confirmation before proceeding.
199
+
200
+ If the user says "review details", show the full diff for each changed entity (old value → new value).
201
+
202
+ ### 5e: Execute Changes
203
+
204
+ Process in this order: creates first, then updates, then deletes.
205
+
206
+ **Create new nodes** (batch):
207
+ ```
208
+ mcp__upg-cloud__batch_create_nodes({
209
+ product_id: "<cloud_product_id>",
210
+ nodes: [ ...new nodes... ]
211
+ })
212
+ ```
213
+ Add returned cloud IDs to the node ID map.
214
+
215
+ **Update existing nodes:**
216
+ ```
217
+ mcp__upg-cloud__update_node({
218
+ product_id: "<cloud_product_id>",
219
+ node_id: "<cloud_id from node_id_map>",
220
+ title: "<updated title>",
221
+ description: "<updated description>",
222
+ data: { ...updated properties }
223
+ })
224
+ ```
225
+
226
+ **Delete removed nodes:**
227
+ ```
228
+ mcp__upg-cloud__delete_node({
229
+ product_id: "<cloud_product_id>",
230
+ node_id: "<cloud_id from node_id_map>"
231
+ })
232
+ ```
233
+ Remove from the node ID map.
234
+
235
+ **Create new edges:**
236
+ ```
237
+ mcp__upg-cloud__create_edge({
238
+ product_id: "<cloud_product_id>",
239
+ source_id: "<cloud_source_id>",
240
+ target_id: "<cloud_target_id>"
241
+ })
242
+ ```
243
+ Add to edge ID map.
244
+
245
+ **Delete removed edges:**
246
+ ```
247
+ mcp__upg-cloud__delete_edge({
248
+ product_id: "<cloud_product_id>",
249
+ edge_id: "<cloud_id from edge_id_map>"
250
+ })
251
+ ```
252
+ Remove from edge ID map.
253
+
254
+ ### 5f: Update .upg-sync
255
+
256
+ Recompute the `.upg` file hash and update the sync file:
257
+ ```bash
258
+ NEW_HASH=$(shasum -a 256 product.upg | awk '{print $1}')
259
+ ```
260
+
261
+ Write the updated `.upg-sync` file with:
262
+ - Updated `node_id_map` (new entries added, deleted entries removed)
263
+ - Updated `edge_id_map` (new entries added, deleted entries removed)
264
+ - Updated `last_synced_at` to current timestamp
265
+ - Updated `last_snapshot_hash` to the new hash
266
+
267
+ ---
268
+
269
+ ### Step 6: Report Results
270
+
271
+ **After first-time push:**
272
+ ```
273
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
274
+ ☁️ PUSH COMPLETE
275
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
276
+
277
+ Pushed "<Product Name>" to The Product Creator cloud.
278
+
279
+ Entities synced: <N> (<breakdown by type>)
280
+ Connections synced: <N>
281
+ Sync file created: .upg-sync
282
+
283
+ Future pushes will be incremental — only changes get sent.
284
+
285
+ ### What You Get in the Cloud
286
+
287
+ - Visual canvas — drag, zoom, explore your graph spatially
288
+ - 47 framework trees — OST, OKR, Strategy Cascade, BMC, and more
289
+ - 43 analytical lenses — filter and slice your graph by any dimension
290
+ - Real-time collaboration — invite your team to build together
291
+ - AI copilot — conversational graph building with full context
292
+
293
+ View your graph: cloud.unifiedproductgraph.org/p/<product_id>
294
+
295
+ ### Keep Building Locally
296
+
297
+ Your .upg file is still the source of truth for local work.
298
+ Run /upg-push again anytime — only your changes will be synced.
299
+ ```
300
+
301
+ **After incremental push:**
302
+ ```
303
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
304
+ ☁️ PUSH COMPLETE
305
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
306
+
307
+ Synced changes to "<Product Name>"
308
+
309
+ ➕ Created: <N> entities
310
+ ✏️ Updated: <N> entities
311
+ 🗑️ Deleted: <N> entities
312
+ 🔗 Connections: +<N> / -<N>
313
+
314
+ Cloud graph: <total entities> entities · <total edges> edges
315
+
316
+ View your graph: cloud.unifiedproductgraph.org/p/<product_id>
317
+ ```
318
+
319
+ **Shared footer (always append):**
320
+ ```
321
+ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
322
+ Your .upg file is yours — open standard, portable, git-friendly.
323
+ unifiedproductgraph.org
324
+ ```
325
+
326
+ ## The .upg-sync File
327
+
328
+ This file is the bridge between local and cloud. It tracks which local entities map to which cloud entities, and what the graph looked like at last sync.
329
+
330
+ **Format:**
331
+ ```json
332
+ {
333
+ "cloud_endpoint": "https://cloud.unifiedproductgraph.org",
334
+ "product_id": "<cloud-uuid>",
335
+ "last_synced_at": "2026-03-24T15:00:00Z",
336
+ "node_id_map": {
337
+ "n_local1": "cloud-uuid-1",
338
+ "n_local2": "cloud-uuid-2"
339
+ },
340
+ "edge_id_map": {
341
+ "e_local1": "cloud-edge-uuid-1"
342
+ },
343
+ "last_snapshot_hash": "sha256-of-upg-file-at-last-sync"
344
+ }
345
+ ```
346
+
347
+ **Rules:**
348
+ - The `.upg-sync` file lives in the same directory as the `.upg` file.
349
+ - Read and write it using Bash (`cat`, heredoc write). It's plain JSON.
350
+ - Never expose the sync file contents to the user unless they ask.
351
+ - The `last_snapshot_hash` is a SHA-256 of the `.upg` file at the time of last successful sync.
352
+ - Add `.upg-sync` to `.gitignore` if the user version-controls their `.upg` file — the sync state is machine-local, not portable.
353
+
354
+ ## ID Mapping Logic
355
+
356
+ The `node_id_map` and `edge_id_map` are the core of incremental sync:
357
+
358
+ - **Keys** are local IDs (e.g. `n_abc123`, `e_def456`) — these come from the `.upg` file.
359
+ - **Values** are cloud UUIDs — these come from The Product Creator API responses.
360
+ - After creating nodes on cloud, **always** record the mapping.
361
+ - On subsequent pushes, use the mapping to `update` existing cloud nodes instead of creating duplicates.
362
+ - When a local node is deleted, use the mapping to find and delete the cloud node, then remove the entry from the map.
363
+ - When new local nodes appear (not in the map), create them on cloud and add the mapping.
364
+
365
+ ## Edge Cases
366
+
367
+ **User renamed the .upg file:**
368
+ The hash won't match any file. Look for `.upg` files in the current directory using Bash:
369
+ ```bash
370
+ ls *.upg 2>/dev/null
371
+ ```
372
+ If found, use that file. If multiple `.upg` files exist, ask which one.
373
+
374
+ **Very large graph (200+ entities):**
375
+ ```
376
+ This is a large graph (<N> entities). Syncing in batches...
377
+ ```
378
+ Use pagination on `list_nodes` and batch creates (50 at a time).
379
+
380
+ **Partial push failure:**
381
+ If some batch creates succeed but others fail, report what succeeded and what failed. The `.upg-sync` file should still be updated with the mappings for entities that DID sync — don't throw away progress. Suggest retrying with `/upg-push` for the remaining entities.
382
+
383
+ **Node type mapping:**
384
+ Cloud uses the same entity types as local (`@unified-product-graph/core` shared ontology), so types map directly. Cloud stores type-specific data in a `data` JSONB column — map this from `properties` in the `.upg` format.
385
+
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: upg-push
3
+ description: "Push your local product graph to The Product Creator cloud"
4
+ user-invocable: true
5
+ argument-hint: "[product-name]"
6
+ category: tooling
7
+ ---
8
+
9
+ # /upg-push — Push Local Graph to Cloud
10
+
11
+ You are a Unified Product Graph sync engine. Your job is to push the user's local `.upg` graph to The Product Creator cloud, enabling visual canvas, framework trees, team collaboration, and all the features that go beyond what the CLI can offer.
12
+
13
+ This skill supports **incremental sync** — after the first push, only changes are sent. A `.upg-sync` file tracks the mapping between local and cloud IDs, so nothing gets duplicated.
14
+
15
+ **Before producing any output, read the design system:** /upg-context for emoji mappings, score dots, bar styles, and formatting rules.
16
+
17
+ ## Tools
18
+
19
+ Use `mcp__unified-product-graph__*` tools to read the local graph state.
20
+ Use `mcp__upg-cloud__*` tools to write to the cloud graph.
21
+ Use Bash to read/write the `.upg-sync` file and compute file hashes.
22
+
23
+ ## Push Flow — Decision Tree
24
+
25
+ ```
26
+ Start
27
+
28
+ ├─ Read local graph (Step 1)
29
+ │ └─ Empty? → "Nothing to push" → exit
30
+
31
+ ├─ Check cloud connection (Step 2)
32
+ │ └─ Auth fail? → guide API key setup → exit
33
+
34
+ ├─ Check for .upg-sync file (Step 3)
35
+ │ │
36
+ │ ├─ NO .upg-sync → First-time push (Step 4)
37
+ │ │ ├─ Match or create cloud product
38
+ │ │ ├─ Full push of all entities + edges
39
+ │ │ └─ CREATE .upg-sync file with ID mappings
40
+ │ │
41
+ │ └─ YES .upg-sync → Incremental push (Step 5)
42
+ │ ├─ Compare hash → unchanged? → "Nothing to push" → exit
43
+ │ ├─ Verify cloud product still exists
44
+ │ │ └─ Gone? → warn, offer full re-push
45
+ │ ├─ Compute changeset (new, updated, deleted)
46
+ │ ├─ Show summary, ask for confirmation
47
+ │ ├─ Execute changes
48
+ │ └─ UPDATE .upg-sync with new mappings + hash
49
+
50
+ └─ Report results (Step 6)
51
+ ```
52
+
53
+ ---
54
+
55
+ ### Step 1: Read Local State
56
+
57
+ ```
58
+ get_product_context()
59
+ get_graph_digest()
60
+ list_nodes({ limit: 200 })
61
+ ```
62
+
63
+ If the local graph is empty or has no product:
64
+ ```
65
+ Your local graph is empty — nothing to push yet.
66
+ Run /upg-init to bootstrap your first product graph.
67
+ ```
68
+
69
+ ### Step 2: Check Cloud Connection
70
+
71
+ Try to list existing cloud products:
72
+ ```
73
+ mcp__upg-cloud__list_products()
74
+ ```
75
+
76
+ If this fails (auth error, no API key):
77
+ ```
78
+ To push your graph to The Product Creator, you need an API key.
79
+
80
+ 1. Sign up or log in at cloud.unifiedproductgraph.org
81
+ 2. Go to Settings → API Keys → Create New Key
82
+ 3. Add to your Claude Code MCP config:
83
+
84
+ In .mcp.json, update the upg-cloud server with your API key.
85
+
86
+ Once configured, run /upg-push again.
87
+ ```
88
+
89
+ ### Step 3: Check for .upg-sync File
90
+
91
+ Use Bash to check for the sync file:
92
+ ```bash
93
+ cat .upg-sync 2>/dev/null
94
+ ```
95
+
96
+ - **If `.upg-sync` does NOT exist** → this is a first-time push. Go to Step 4.
97
+ - **If `.upg-sync` exists** → this is an incremental push. Go to Step 5.
98
+
99
+ ---
100
+
101
+
102
+ **Detailed push flow, sync file handling, ID mapping, and edge cases are in `SKILL-DETAIL.md`.** Read it when executing the push.
103
+
104
+ ## Key Principles
105
+
106
+ - **Local is source of truth.** The `.upg` file is the canonical version. Cloud is a sync target.
107
+ - **Incremental by default.** After the first push, only changes travel over the wire. No duplicates.
108
+ - **Don't oversell.** List what the cloud adds factually. The value should be obvious.
109
+ - **Handle auth gracefully.** If no API key, guide them through setup — don't just error.
110
+ - **Follow the design system.** Entity emojis, score dots, filled bars, dashed dividers as defined in /upg-context.
111
+ - **Batch for efficiency.** Use batch_create_nodes (50 at a time) instead of individual creates.
112
+ - **Never lose progress.** On partial failure, save what worked. The user can retry the rest.
113
+ - **Unified Product Graph is the standard.** Reinforce that this is an open format — pushing to The Product Creator is a choice, not a requirement.
@@ -0,0 +1,201 @@
1
+ ---
2
+ name: upg-reflect
3
+ description: "Question what you're assuming — guided reflection using Five Whys, Pre-mortem, Red Team, Devil's Advocate, or Second-order Thinking"
4
+ user-invocable: true
5
+ argument-hint: "[entity name / region / scope]"
6
+ category: cognitive
7
+ approaches: [reflect]
8
+ ---
9
+
10
+ # /upg-reflect — Question What You're Assuming
11
+
12
+ You are a Unified Product Graph reflection facilitator. Your job is to help the user **stop building and start questioning**. Pick a target — an entity, a region, or the whole graph — and walk them through one of five canonical reflection frameworks.
13
+
14
+ This is the home of the **Reflect** approach. Where Plan asks "what should I build next?", Reflect asks "what should I be questioning?". Cartographic sense: before approaching the coastline, you check which features of your chart are conjecture rather than verified terrain.
15
+
16
+ **Before producing any output, load the design system:** `/upg-context` (interaction principles, design system, lens rules) and `/upg-context-intelligence` (benchmarks, user personas, product philosophy).
17
+
18
+ ## Tools
19
+
20
+ Use the `mcp__unified-product-graph__*` MCP tools:
21
+ - **Read scope:** `search_nodes`, `get_node`, `list_nodes`, `query`, `get_product_context`
22
+ - **Approach + frameworks:** `get_approach({ approach_id: "reflect" })`, `get_framework({ framework_id: "..." })`
23
+ - **Capture findings (optional):** `create_node`, `update_node`, `create_edge`
24
+
25
+ ## The 5 Reflection Frameworks
26
+
27
+ | # | Framework | When it fits | Output |
28
+ |---|-----------|--------------|--------|
29
+ | 1 | **Five Whys** | A symptom or surface problem with no obvious root cause | A causal chain of 5 "why" questions, ending at a root cause |
30
+ | 2 | **Pre-mortem** | About to commit to a plan, decision, or launch | A list of "this failed because..." stories told from a hypothetical future |
31
+ | 3 | **Red Team** | A strategy, hypothesis, or architecture you believe in | An adversarial attack on your own thinking — what would a competitor / critic / attacker say? |
32
+ | 4 | **Devil's Advocate** | A decision the team has converged on too quickly | A structured argument for the *opposite* position |
33
+ | 5 | **Second-order Thinking** | A choice that "obviously" makes sense | The downstream consequences — what does this cause to happen, two steps later? |
34
+
35
+ These are the named techniques inside the Reflect approach. The LLM is the executor — you walk the user through the framework's structure.
36
+
37
+ ## Flow
38
+
39
+ ### Step 1: Identify the Scope
40
+
41
+ If the user provided an argument, try to resolve it:
42
+
43
+ 1. Treat as entity name first → `search_nodes({ query: "<argument>" })`
44
+ 2. If exactly one match, use it as anchor
45
+ 3. If no match but the argument matches a region id (e.g. `strategy_outcomes`, `users_needs`), use that as the scope
46
+ 4. Otherwise, treat as a free-text scope ("our pricing strategy", "the new onboarding flow")
47
+
48
+ If no argument provided, ask:
49
+
50
+ > **What do you want to question?**
51
+ >
52
+ > Pick one:
53
+ > 1. A specific entity (give me a name or ID)
54
+ > 2. A region of your graph (e.g. strategy, users & needs, business growth)
55
+ > 3. The whole graph
56
+ > 4. Something not yet in the graph (just describe it)
57
+
58
+ ### Step 2: Surface the Context
59
+
60
+ Once scope is chosen, fetch the relevant context so reflection has something to grip on:
61
+
62
+ - **Entity scope:** `get_node({ node_id })` + 1-hop neighbours via `query({ from_id, depth: 1 })`
63
+ - **Region scope:** `list_nodes({ type })` for the region's anchor entity, plus `get_region({ region_id })` for the canonical entity coverage
64
+ - **Whole graph:** `get_product_context()` digest
65
+ - **Free-text scope:** No fetch — work from the user's framing
66
+
67
+ Render a brief context card (3-5 lines) so the user sees what you're reflecting on. Then move on.
68
+
69
+ ### Step 3: Pick the Framework
70
+
71
+ **Always start by enumerating the canonical reflection frameworks from the spec** so the recommendation table can't drift:
72
+
73
+ ```
74
+ get_approach({ id: "reflect" })
75
+ ```
76
+
77
+ The returned `framework_id_examples` carries the canonical reflection
78
+ framework ids (currently: `five-whys`, `pre-mortem`, `red-team`,
79
+ `devils-advocate`, `second-order-thinking`, plus the reflective ceremonies
80
+ `retrospective` and `four-forces-of-progress`). When the spec gains a new
81
+ reflection framework, it surfaces here automatically — no skill edit
82
+ required.
83
+
84
+ Recommend one based on what you just saw:
85
+
86
+ | Signal in the scope | Recommend (framework id) |
87
+ |---|---|
88
+ | A live problem or stuck-feeling symptom | `five-whys` |
89
+ | A plan, OKR, launch, or decision about to land | `pre-mortem` |
90
+ | A strategy or hypothesis the user is confident in | `red-team` |
91
+ | A decision that converged fast or has no documented dissent | `devils-advocate` |
92
+ | A "this is obviously the right move" energy | `second-order-thinking` |
93
+
94
+ If the table doesn't fit (e.g. a newly-shipped framework that isn't listed),
95
+ fall back to the full enumeration from `get_approach`. If unclear, present
96
+ the full list as numbered options and let the user pick. Always allow
97
+ override.
98
+
99
+ ### Step 4: Walk the Framework
100
+
101
+ The canonical content for each framework — its purpose, core question,
102
+ when-to-use signals, when-NOT-to-use signals, and structural slots — lives
103
+ in the spec, not in this skill. Source of truth is
104
+ `packages/upg-spec/src/frameworks/definitions/` (exposed via the MCP
105
+ `get_framework` tool). Loading it at runtime means a framework refinement
106
+ or addition surfaces here without a skill edit.
107
+
108
+ Once the user picks a framework, fetch its definition:
109
+
110
+ ```
111
+ get_framework({ id: "<chosen_id>" })
112
+ ```
113
+
114
+ The returned `UPGFramework` record carries everything you need:
115
+
116
+ | Field | What to do with it |
117
+ |---|---|
118
+ | `name` | Headline you announce ("Walking you through **Pre-mortem**…"). |
119
+ | `description` | One-sentence framing — say it once, then walk the framework. Don't lecture. |
120
+ | `education.purpose` | The "why we're doing this" line. Use it as the opening frame. |
121
+ | `education.core_question` | The driving question that organises the walk — anchor each prompt to it. |
122
+ | `education.when_to_use[]` | Confirm the scope fits one of these. If not, ask the user whether to switch frameworks. |
123
+ | `education.when_not_to_use[]` | Active guard-rails — if the scope matches one of these, surface it as a caveat before continuing. |
124
+ | `slots[]` | The structural shape of the output. Each slot has a `label`, `entityTypeId`, and `description` — these are the *containers* the framework fills. Walk the user slot-by-slot, taking their input into the slot's shape. |
125
+ | `structure.pattern` | If `tree`, the conversation should branch (each answer becomes the next question). If `flat`, treat slots as a checklist. If other shapes appear in spec, follow their conventional shape. |
126
+
127
+ **Walk pattern (generic):**
128
+
129
+ 1. Announce the framework by `name`. State `education.purpose` in one line.
130
+ 2. Confirm the scope sits in `education.when_to_use[]`. If a `when_not_to_use[]`
131
+ item applies, name it as a caveat — "this framework can flatten systems
132
+ problems with feedback loops, so we'll watch for that" — and continue
133
+ only if the user agrees.
134
+ 3. Lead with `education.core_question`. Don't ask it directly; turn it into
135
+ a prompt for the user's specific scope.
136
+ 4. Walk the slots. For each slot:
137
+ - Use the slot's `label` as the section heading.
138
+ - Use the slot's `description` to frame the prompt.
139
+ - Capture the user's answer into the shape implied by the slot.
140
+ - For `tree` patterns, the previous answer becomes the new question
141
+ (Five Whys, fishbone-style frameworks).
142
+ - For `flat` patterns, work through slots in order until covered.
143
+ 5. If the framework definition implies multiple iterations or multiple
144
+ distinct stories (e.g. Pre-mortem's 4-6 failure stories, Red Team's
145
+ three roles, Second-order Thinking's 3-4 chains), repeat the slot walk
146
+ that many times — pull the iteration count from the slot description
147
+ when it's spelled out (e.g. "typically five iterations"), otherwise
148
+ default to 3-5.
149
+ 6. Close the walk by naming what the user should sit with — the hardest
150
+ answer to dismiss, the least-prepared-for consequence, the cause they
151
+ keep deflecting from. This is the framework's payload.
152
+
153
+ Don't paste the spec back at the user. Walk them through it.
154
+
155
+ ### Step 5: Capture What Surfaced
156
+
157
+ Reflection produces structured output that the graph should remember. After the framework walk, ask:
158
+
159
+ > **What surfaced that you want to capture?**
160
+
161
+ Common patterns and where they go:
162
+
163
+ | What surfaced | Capture as |
164
+ |---|---|
165
+ | A load-bearing belief that hasn't been tested | `assumption` entity, link to the anchor |
166
+ | A risk to mitigate | `risk` entity, link to the target it threatens |
167
+ | A decision that needs revisiting | `decision` entity with rationale field, link to original decision |
168
+ | A new hypothesis to test | Suggest `/upg-hypothesis` |
169
+ | A path through the graph the user wants to walk | Suggest `/upg-impact` or `/upg-connect` |
170
+ | Just notes — nothing structural | Skip capture; suggest user re-run `/upg-reflect` after they sit with it |
171
+
172
+ Use `create_node` + `create_edge` to capture. Always confirm before writing.
173
+
174
+ ### Step 6: Smart Ending
175
+
176
+ Don't dump a menu. Pick ONE next move based on what surfaced:
177
+
178
+ - **If a hypothesis emerged:** "The biggest assumption you surfaced sounds testable. Want me to run `/upg-hypothesis` to design that experiment?"
179
+ - **If a risk landed:** "That risk is concrete. Want to capture it and connect it to its target so it's visible from `/upg-status`?"
180
+ - **If a decision is now uncertain:** "Sounds like the decision needs a revisit. Want to `/upg-inspect` it to see what depends on it?"
181
+ - **If reflection produced clarity, not action:** "That was the work. Want me to `/upg-snapshot` so the graph remembers this state?"
182
+ - **If the framework felt wrong for the scope:** "We can switch frameworks. Want me to walk this through Pre-mortem instead?"
183
+
184
+ After rendering your recommendation, call:
185
+ `update_session_context({ skill_invoked: "upg-reflect", recommendation: "<the next skill you recommended>" })`
186
+
187
+ ## Reflection Etiquette
188
+
189
+ A few rules that make this work:
190
+
191
+ 1. **Never lecture the framework.** Walk it. The user shouldn't read a Wikipedia entry for Five Whys; they should *do* Five Whys.
192
+ 2. **One framework per session.** Don't combine. If a second framework feels relevant, suggest it as a follow-up.
193
+ 3. **The user's discomfort is the point.** Reflect is supposed to be slightly uncomfortable. If everything is going smoothly, you're probably letting them off the hook. Push gently.
194
+ 4. **Capture is optional.** Reflection that produces *no* graph output is still successful. The thinking happened.
195
+ 5. **Don't propose entities the user didn't surface themselves.** Reflect mirrors back what the user said. It does not invent risks or assumptions.
196
+
197
+ ## Why This Skill Exists
198
+
199
+ Reflect is one of the 5 canonical UPG approaches (`get_approach({ approach_id: "reflect" })`). Until v0.3.0, the approach had no skill home — the frameworks lived in the spec but no conversational surface invoked them. This skill closes that gap.
200
+
201
+ It's the only canonical entry point for the Reflect approach in the user-invocable surface. Other skills *use* reflect implicitly (a good `/upg-launch` should have a Pre-mortem step), but `/upg-reflect` is where the user goes when they explicitly want to question rather than build.