@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.
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/cli.cjs +141010 -0
- package/package.json +65 -0
- package/skills/README.md +10 -0
- package/skills/upg/SKILL.md +245 -0
- package/skills/upg-analytics/SKILL.md +135 -0
- package/skills/upg-capture/SKILL.md +274 -0
- package/skills/upg-connect/SKILL.md +167 -0
- package/skills/upg-context/SKILL.md +506 -0
- package/skills/upg-context-intelligence/SKILL.md +227 -0
- package/skills/upg-design-system/SKILL.md +265 -0
- package/skills/upg-diff/SKILL.md +150 -0
- package/skills/upg-discover/SKILL.md +290 -0
- package/skills/upg-explore/SKILL-DETAIL.md +481 -0
- package/skills/upg-explore/SKILL.md +297 -0
- package/skills/upg-export/SKILL.md +385 -0
- package/skills/upg-feedback/SKILL.md +141 -0
- package/skills/upg-gaps/SKILL.md +376 -0
- package/skills/upg-hypothesis/SKILL.md +190 -0
- package/skills/upg-impact/SKILL.md +229 -0
- package/skills/upg-import/SKILL.md +189 -0
- package/skills/upg-init/SKILL.md +410 -0
- package/skills/upg-inspect/SKILL.md +167 -0
- package/skills/upg-journey/SKILL.md +207 -0
- package/skills/upg-launch/SKILL-DETAIL.md +392 -0
- package/skills/upg-launch/SKILL.md +141 -0
- package/skills/upg-migrate/SKILL.md +146 -0
- package/skills/upg-okr/SKILL-DETAIL.md +351 -0
- package/skills/upg-okr/SKILL.md +88 -0
- package/skills/upg-persona/SKILL.md +230 -0
- package/skills/upg-prioritise/SKILL.md +195 -0
- package/skills/upg-pull/SKILL-DETAIL.md +398 -0
- package/skills/upg-pull/SKILL.md +57 -0
- package/skills/upg-push/SKILL-DETAIL.md +385 -0
- package/skills/upg-push/SKILL.md +113 -0
- package/skills/upg-reflect/SKILL.md +201 -0
- package/skills/upg-research/SKILL.md +336 -0
- package/skills/upg-rollback/SKILL.md +163 -0
- package/skills/upg-run/SKILL.md +126 -0
- package/skills/upg-schema-changelog/SKILL.md +231 -0
- package/skills/upg-schema-consolidate/SKILL.md +243 -0
- package/skills/upg-schema-edges/SKILL.md +287 -0
- package/skills/upg-schema-evolve/SKILL.md +313 -0
- package/skills/upg-schema-health/SKILL.md +279 -0
- package/skills/upg-schema-update/SKILL.md +206 -0
- package/skills/upg-snapshot/SKILL.md +108 -0
- package/skills/upg-status/SKILL.md +340 -0
- package/skills/upg-strategy/SKILL.md +334 -0
- package/skills/upg-template/SKILL.md +145 -0
- package/skills/upg-trace/SKILL.md +197 -0
- package/skills/upg-tree/SKILL.md +233 -0
- package/skills/upg-verify/SKILL.md +223 -0
- package/skills/upg-workspace/SKILL.md +103 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upg-pull-detail
|
|
3
|
+
description: "Detailed pull flow, merge logic, incremental sync"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /upg-pull — Pull Flow Detail
|
|
7
|
+
|
|
8
|
+
## Pull Flow
|
|
9
|
+
|
|
10
|
+
### Step 1: Connect to Cloud
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
mcp__upg-cloud__list_products()
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
If this fails (auth error):
|
|
17
|
+
```
|
|
18
|
+
To pull from The Product Creator, you need an API key configured.
|
|
19
|
+
|
|
20
|
+
1. Log in at cloud.unifiedproductgraph.org
|
|
21
|
+
2. Go to Settings → API Keys → Create New Key
|
|
22
|
+
3. Add to your .mcp.json config
|
|
23
|
+
|
|
24
|
+
Once configured, run /upg-pull again.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Step 2: Select Product
|
|
28
|
+
|
|
29
|
+
If the user specified a product name, search for it. Otherwise, list all products:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Your products on The Product Creator:
|
|
33
|
+
|
|
34
|
+
1. My SaaS App (42 entities, 38 edges)
|
|
35
|
+
2. Side Project (12 entities, 8 edges)
|
|
36
|
+
3. Client Engagement (67 entities, 55 edges)
|
|
37
|
+
|
|
38
|
+
Which one do you want to pull down? (number or name)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Step 3: Determine Sync Mode
|
|
42
|
+
|
|
43
|
+
Once the user selects a product, check the local state to determine which pull flow to use:
|
|
44
|
+
|
|
45
|
+
1. **Read the `.upg-sync` file** from the current directory using the Read tool.
|
|
46
|
+
2. **Read the `.upg` file** if it exists.
|
|
47
|
+
|
|
48
|
+
**Decision matrix:**
|
|
49
|
+
|
|
50
|
+
| .upg-sync exists? | Matches selected product_id? | .upg exists? | Flow |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| No | — | No | **First-time pull** (Step 4A) |
|
|
53
|
+
| No | — | Yes | **Overwrite warning** (Step 4B) |
|
|
54
|
+
| Yes | Yes | Yes | **Incremental pull** (Step 4C) |
|
|
55
|
+
| Yes | No | Yes | **Different product warning** (Step 4B) |
|
|
56
|
+
| Yes | Yes | No | **First-time pull** — sync file is stale, treat as fresh (Step 4A) |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Step 4A: First-Time Pull (Full)
|
|
61
|
+
|
|
62
|
+
No sync file exists and no local `.upg` file, or the sync file is stale. This is a clean pull.
|
|
63
|
+
|
|
64
|
+
#### Fetch the full graph:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
mcp__upg-cloud__get_product_graph({
|
|
68
|
+
product_id: "<selected_product_id>"
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Transform to .upg format:
|
|
73
|
+
|
|
74
|
+
For each cloud node, generate a local `n_xxx` ID (nanoid-style short ID). For each cloud edge, generate a local `e_xxx` ID. Build the ID maps as you go.
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"upg_version": "0.1.0",
|
|
79
|
+
"exported_at": "<current ISO 8601 timestamp>",
|
|
80
|
+
"source": {
|
|
81
|
+
"tool": "upg-cloud-cloud",
|
|
82
|
+
"tool_version": "1.0.0"
|
|
83
|
+
},
|
|
84
|
+
"product": {
|
|
85
|
+
"id": "p_<nanoid>",
|
|
86
|
+
"title": "<product title>",
|
|
87
|
+
"description": "<product description>",
|
|
88
|
+
"stage": "<stage if available>"
|
|
89
|
+
},
|
|
90
|
+
"nodes": [
|
|
91
|
+
{
|
|
92
|
+
"id": "n_<nanoid>",
|
|
93
|
+
"type": "<entity type>",
|
|
94
|
+
"title": "<title>",
|
|
95
|
+
"description": "<description>",
|
|
96
|
+
"tags": [],
|
|
97
|
+
"status": "<status>",
|
|
98
|
+
"properties": { ... }
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
"edges": [
|
|
102
|
+
{
|
|
103
|
+
"id": "e_<nanoid>",
|
|
104
|
+
"source": "n_<source local id>",
|
|
105
|
+
"target": "n_<target local id>",
|
|
106
|
+
"type": "<edge type>"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Important:** Edge source/target must reference the LOCAL IDs you generated, not the cloud UUIDs. Use the node_id_map you're building to translate.
|
|
113
|
+
|
|
114
|
+
#### Write both files:
|
|
115
|
+
|
|
116
|
+
1. Write the `.upg` file using the Write tool.
|
|
117
|
+
2. **Create the `.upg-sync` file** with the full ID mapping:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"cloud_endpoint": "https://cloud.unifiedproductgraph.org",
|
|
122
|
+
"product_id": "<cloud-product-uuid>",
|
|
123
|
+
"last_synced_at": "<current ISO 8601 timestamp>",
|
|
124
|
+
"node_id_map": {
|
|
125
|
+
"n_local1": "cloud-uuid-1",
|
|
126
|
+
"n_local2": "cloud-uuid-2"
|
|
127
|
+
},
|
|
128
|
+
"edge_id_map": {
|
|
129
|
+
"e_local1": "cloud-uuid-1",
|
|
130
|
+
"e_local2": "cloud-uuid-2"
|
|
131
|
+
},
|
|
132
|
+
"last_snapshot_hash": "<sha256 of the cloud graph JSON>"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
To compute `last_snapshot_hash`: take the cloud graph response (nodes + edges, sorted by ID for determinism), JSON-stringify it, and compute a SHA-256 hash via Bash:
|
|
137
|
+
```bash
|
|
138
|
+
echo -n '<sorted-json-string>' | shasum -a 256 | cut -d' ' -f1
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Confirm:
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
## Pull Complete
|
|
145
|
+
|
|
146
|
+
Pulled "<Product Name>" from The Product Creator cloud.
|
|
147
|
+
|
|
148
|
+
File: product.upg
|
|
149
|
+
Sync: .upg-sync (ID mapping + sync state created)
|
|
150
|
+
Entities: <N> (<breakdown by type>)
|
|
151
|
+
Connections: <N>
|
|
152
|
+
Domains: <N> covered
|
|
153
|
+
|
|
154
|
+
Your graph is now local. It's a .upg file — portable, git-friendly, yours.
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Then show the "What You Can Do Now" section (Step 6).
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Step 4B: Overwrite Warning
|
|
162
|
+
|
|
163
|
+
A local `.upg` file exists but there's no matching sync file (either no sync file at all, or the sync file points to a different product).
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
A local .upg file already exists: product.upg (<N> entities)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
If no sync file:
|
|
170
|
+
```
|
|
171
|
+
There's no sync file (.upg-sync), so I can't merge incrementally.
|
|
172
|
+
Pulling will overwrite your local graph with the cloud version.
|
|
173
|
+
|
|
174
|
+
Want to proceed? (This is not reversible unless you have a git commit)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
If sync file points to different product:
|
|
178
|
+
```
|
|
179
|
+
Your sync file is linked to a different cloud product ("<other product name>").
|
|
180
|
+
Pulling "<selected product name>" will replace your local graph and sync state.
|
|
181
|
+
|
|
182
|
+
Want to proceed?
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
If user confirms, proceed with Step 4A (full pull, overwriting both files).
|
|
186
|
+
If user declines, suggest:
|
|
187
|
+
```
|
|
188
|
+
You can:
|
|
189
|
+
- Save your current .upg file first: cp product.upg product-backup.upg
|
|
190
|
+
- Or commit it to git: git add product.upg && git commit -m "Backup before pull"
|
|
191
|
+
- Then run /upg-pull again
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Step 4C: Incremental Pull (Sync File Exists and Matches)
|
|
197
|
+
|
|
198
|
+
This is the core incremental sync flow. The sync file exists, matches the selected product, and a local `.upg` file is present.
|
|
199
|
+
|
|
200
|
+
#### 1. Read current state
|
|
201
|
+
|
|
202
|
+
Read three things:
|
|
203
|
+
- The local `.upg` file (via Read tool)
|
|
204
|
+
- The `.upg-sync` file (via Read tool)
|
|
205
|
+
- The cloud graph (via `mcp__upg-cloud__get_product_graph()`)
|
|
206
|
+
|
|
207
|
+
#### 2. Compute the cloud snapshot hash
|
|
208
|
+
|
|
209
|
+
Hash the cloud graph response the same way as during full pull. Compare against `last_snapshot_hash` from the sync file.
|
|
210
|
+
|
|
211
|
+
**If hashes match:**
|
|
212
|
+
```
|
|
213
|
+
Your local graph is up to date with the cloud.
|
|
214
|
+
|
|
215
|
+
No changes detected on The Product Creator since your last sync
|
|
216
|
+
(<last_synced_at formatted nicely>).
|
|
217
|
+
```
|
|
218
|
+
Stop here. No changes needed.
|
|
219
|
+
|
|
220
|
+
**If hashes differ:** Continue to compute the changeset.
|
|
221
|
+
|
|
222
|
+
#### 3. Compute changeset
|
|
223
|
+
|
|
224
|
+
Compare the current cloud graph against what was synced last time. Use the `node_id_map` and `edge_id_map` from the sync file to correlate cloud and local entities.
|
|
225
|
+
|
|
226
|
+
**Cloud nodes — categorise each one:**
|
|
227
|
+
|
|
228
|
+
- **New on cloud:** Cloud node ID is NOT in any value of `node_id_map` — this entity was created on the cloud since last sync.
|
|
229
|
+
- **Updated on cloud:** Cloud node ID IS in `node_id_map`, and the node's content (title, description, type, properties, status, tags) differs from the corresponding local node.
|
|
230
|
+
- **Deleted on cloud:** A cloud ID exists in `node_id_map` values, but that cloud node no longer exists in the cloud graph response — it was deleted on the cloud since last sync.
|
|
231
|
+
- **Unchanged:** Cloud node ID is in `node_id_map` and content matches local. No action needed.
|
|
232
|
+
|
|
233
|
+
Do the same for edges using `edge_id_map`.
|
|
234
|
+
|
|
235
|
+
#### 4. Detect conflicts
|
|
236
|
+
|
|
237
|
+
Check if any node that is "updated on cloud" was ALSO modified locally since last sync. To detect local modifications:
|
|
238
|
+
|
|
239
|
+
- Compare the current local `.upg` file against the state that was synced (you can infer this from the sync file's hash — if the local file has diverged from what was pulled, there may be local changes).
|
|
240
|
+
- A pragmatic v1 approach: if a node appears in the "updated on cloud" set, check if the local version of that same node (via ID map) differs from what the cloud had at last sync time. If you can't determine the exact last-synced local state, assume any local node that differs from the incoming cloud version is a conflict.
|
|
241
|
+
|
|
242
|
+
**Conflict resolution (v1 — last write wins, cloud takes precedence):**
|
|
243
|
+
- Apply the cloud version.
|
|
244
|
+
- But track and report the conflict count to the user.
|
|
245
|
+
|
|
246
|
+
#### 5. Show summary and ask for confirmation
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
## Incoming Changes from Cloud
|
|
250
|
+
|
|
251
|
+
Pulling "<Product Name>" — changes since <last_synced_at>:
|
|
252
|
+
|
|
253
|
+
+ <N> new entities (<breakdown>)
|
|
254
|
+
~ <N> updated entities
|
|
255
|
+
- <N> deleted entities
|
|
256
|
+
+ <N> new connections
|
|
257
|
+
~ <N> updated connections
|
|
258
|
+
- <N> deleted connections
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
If there are conflicts:
|
|
262
|
+
```
|
|
263
|
+
!! <N> entities were modified both locally and on the cloud.
|
|
264
|
+
Cloud version will be kept (last-write-wins).
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
Apply these changes to your local graph? (y/n)
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
If no changes in any category:
|
|
272
|
+
```
|
|
273
|
+
Your local graph is up to date with the cloud.
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
#### 6. Apply changes to local .upg file
|
|
277
|
+
|
|
278
|
+
Read the current `.upg` file, then apply each change:
|
|
279
|
+
|
|
280
|
+
**New cloud nodes:**
|
|
281
|
+
- Generate a new local `n_xxx` ID for each
|
|
282
|
+
- Add the node to the `.upg` nodes array
|
|
283
|
+
- Add the mapping to `node_id_map`
|
|
284
|
+
|
|
285
|
+
**Updated cloud nodes:**
|
|
286
|
+
- Find the local node via `node_id_map` (reverse lookup: find the local ID whose mapped cloud ID matches)
|
|
287
|
+
- Update its title, description, type, properties, status, tags from the cloud version
|
|
288
|
+
|
|
289
|
+
**Deleted cloud nodes:**
|
|
290
|
+
- Find the local node via `node_id_map`
|
|
291
|
+
- Remove it from the `.upg` nodes array
|
|
292
|
+
- Remove the mapping from `node_id_map`
|
|
293
|
+
- Remove any edges that reference the deleted node
|
|
294
|
+
|
|
295
|
+
**New cloud edges:**
|
|
296
|
+
- Generate a new local `e_xxx` ID
|
|
297
|
+
- Translate source/target from cloud IDs to local IDs via `node_id_map`
|
|
298
|
+
- Add to the `.upg` edges array
|
|
299
|
+
- Add the mapping to `edge_id_map`
|
|
300
|
+
|
|
301
|
+
**Updated cloud edges:**
|
|
302
|
+
- Find the local edge via `edge_id_map`
|
|
303
|
+
- Update its source, target, type (translating cloud IDs to local IDs)
|
|
304
|
+
|
|
305
|
+
**Deleted cloud edges:**
|
|
306
|
+
- Find the local edge via `edge_id_map`
|
|
307
|
+
- Remove from `.upg` edges array
|
|
308
|
+
- Remove from `edge_id_map`
|
|
309
|
+
|
|
310
|
+
#### 7. Write updated files
|
|
311
|
+
|
|
312
|
+
1. Write the updated `.upg` file
|
|
313
|
+
2. Update the `.upg-sync` file:
|
|
314
|
+
- `last_synced_at` → current timestamp
|
|
315
|
+
- `node_id_map` → updated with new/removed mappings
|
|
316
|
+
- `edge_id_map` → updated with new/removed mappings
|
|
317
|
+
- `last_snapshot_hash` → hash of the current cloud graph
|
|
318
|
+
|
|
319
|
+
#### 8. Report results
|
|
320
|
+
|
|
321
|
+
```
|
|
322
|
+
## Pull Complete — Incremental Sync
|
|
323
|
+
|
|
324
|
+
Merged cloud changes into "<Product Name>".
|
|
325
|
+
|
|
326
|
+
+ <N> entities added
|
|
327
|
+
~ <N> entities updated
|
|
328
|
+
- <N> entities removed
|
|
329
|
+
+ <N> connections added
|
|
330
|
+
~ <N> connections updated
|
|
331
|
+
- <N> connections removed
|
|
332
|
+
|
|
333
|
+
Local graph: <total N> entities, <total N> connections
|
|
334
|
+
Synced at: <timestamp>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
If there were conflicts:
|
|
338
|
+
```
|
|
339
|
+
!! <N> conflicts resolved (cloud version kept)
|
|
340
|
+
Future: /upg-resolve will let you review conflicts manually.
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Then show the "What You Can Do Now" section (Step 6 below).
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
### Step 5: Handle Edge Cases
|
|
348
|
+
|
|
349
|
+
**Cloud graph is empty:**
|
|
350
|
+
```
|
|
351
|
+
"<Product Name>" has no entities in the cloud yet.
|
|
352
|
+
Build it locally with /upg-init, then /upg-push when ready.
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Very large graph (200+ entities):**
|
|
356
|
+
```
|
|
357
|
+
This is a large graph (<N> entities). The pull may take a moment...
|
|
358
|
+
```
|
|
359
|
+
Use pagination if needed from the cloud API.
|
|
360
|
+
|
|
361
|
+
**Node type mapping:**
|
|
362
|
+
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 to `properties` in the `.upg` format.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
### Step 6: What You Can Do Now
|
|
367
|
+
|
|
368
|
+
Show this section after every successful pull (full or incremental):
|
|
369
|
+
|
|
370
|
+
```
|
|
371
|
+
### What You Can Do Now
|
|
372
|
+
|
|
373
|
+
/upg-status — See your graph health dashboard
|
|
374
|
+
/upg-tree — View through framework lenses (ost, user, validation...)
|
|
375
|
+
/upg-gaps — Find strategic gaps and get action plans
|
|
376
|
+
/upg-explore — Add new entities locally
|
|
377
|
+
/upg-discover — Run a guided discovery session
|
|
378
|
+
/upg-push — Push local changes back to the cloud
|
|
379
|
+
|
|
380
|
+
### Version Control
|
|
381
|
+
|
|
382
|
+
git add product.upg
|
|
383
|
+
git commit -m "Pull <product name> graph from cloud"
|
|
384
|
+
|
|
385
|
+
Now you have full git history of your product thinking.
|
|
386
|
+
Branch, diff, review — your graph is just data.
|
|
387
|
+
|
|
388
|
+
### Stay in Sync
|
|
389
|
+
|
|
390
|
+
Edit locally, then /upg-push to sync back to the cloud.
|
|
391
|
+
Pull again with /upg-pull to get the latest from your team.
|
|
392
|
+
The .upg file is your source of truth for local work.
|
|
393
|
+
|
|
394
|
+
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
|
|
395
|
+
Your .upg file is yours — open standard, portable, git-friendly.
|
|
396
|
+
unifiedproductgraph.org
|
|
397
|
+
```
|
|
398
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upg-pull
|
|
3
|
+
description: "Pull a cloud graph down to a local .upg file"
|
|
4
|
+
user-invocable: true
|
|
5
|
+
argument-hint: "[product-name]"
|
|
6
|
+
category: tooling
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# /upg-pull — Pull Cloud Graph to Local
|
|
10
|
+
|
|
11
|
+
You are a Unified Product Graph sync engine. Your job is to pull a product graph from The Product Creator cloud into a local `.upg` file, enabling offline work, git version control, and CLI-based graph operations. You support both full pulls and incremental sync.
|
|
12
|
+
|
|
13
|
+
**Before producing any output, read the design system:** /upg-context for emoji mappings, score dots, bar styles, and formatting rules.
|
|
14
|
+
|
|
15
|
+
## Tools
|
|
16
|
+
|
|
17
|
+
Use `mcp__upg-cloud__*` tools to read from the cloud graph.
|
|
18
|
+
Use Bash/Read/Write tools to read and write the `.upg` and `.upg-sync` files on disk.
|
|
19
|
+
The upg-local MCP server will auto-detect file changes via file watching — no restart needed.
|
|
20
|
+
|
|
21
|
+
## The .upg-sync File
|
|
22
|
+
|
|
23
|
+
The `.upg-sync` file tracks the sync state between local and cloud. It lives next to the `.upg` file.
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"cloud_endpoint": "https://cloud.unifiedproductgraph.org",
|
|
28
|
+
"product_id": "<cloud-uuid>",
|
|
29
|
+
"last_synced_at": "2026-03-24T15:00:00Z",
|
|
30
|
+
"node_id_map": {
|
|
31
|
+
"n_local1": "cloud-uuid-1",
|
|
32
|
+
"n_local2": "cloud-uuid-2"
|
|
33
|
+
},
|
|
34
|
+
"edge_id_map": {
|
|
35
|
+
"e_local1": "cloud-uuid-1",
|
|
36
|
+
"e_local2": "cloud-uuid-2"
|
|
37
|
+
},
|
|
38
|
+
"last_snapshot_hash": "sha256-of-cloud-graph-at-last-sync"
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- `node_id_map`: maps local `n_xxx` IDs to cloud UUIDs
|
|
43
|
+
- `edge_id_map`: maps local `e_xxx` IDs to cloud UUIDs
|
|
44
|
+
- `last_snapshot_hash`: SHA-256 hash of the cloud graph data at the time of last sync (used to detect cloud changes)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
**Detailed pull flow, merge logic, and incremental sync are in `SKILL-DETAIL.md`.** Read it when executing the pull.
|
|
48
|
+
|
|
49
|
+
## Key Principles
|
|
50
|
+
|
|
51
|
+
- **Cloud to local, not cloud to local lock-in.** The `.upg` file is the user's — portable, open, git-tracked.
|
|
52
|
+
- **Preserve fidelity.** Every entity, every edge, every property should survive the round-trip.
|
|
53
|
+
- **Incremental by default.** If a sync file exists, merge changes instead of overwriting.
|
|
54
|
+
- **Handle conflicts transparently.** v1 uses last-write-wins (cloud takes precedence), but always tell the user when it happens.
|
|
55
|
+
- **Suggest git.** Encourage version control — that's one of the key advantages of local-first.
|
|
56
|
+
- **The `.upg` file auto-reloads.** The upg-local MCP server watches the file — no restart needed.
|
|
57
|
+
- **The `.upg-sync` file is infrastructure.** It should be gitignored (it contains cloud-specific state). Suggest adding it to `.gitignore` if not already there.
|