@unified-product-graph/mcp-server 0.8.0 → 0.8.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.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/TOOLS.md +20 -14
- package/dist/index.js +1289 -485
- package/dist/index.js.map +1 -1
- package/dist/tools-manifest.json +95 -76
- package/package.json +1 -1
- package/scripts/claudemd-snippet.md +7 -7
- package/scripts/install-skills.sh +2 -2
- package/skills/upg/SKILL.md +41 -41
- package/skills/{upg-gaps → upg-check-gaps}/SKILL.md +40 -43
- package/skills/{upg-schema-health → upg-check-schema}/SKILL.md +7 -7
- package/skills/{upg-schema-evolve → upg-check-schema-coverage}/SKILL.md +12 -12
- package/skills/{upg-schema-edges → upg-check-schema-edges}/SKILL.md +3 -3
- package/skills/{upg-schema-consolidate → upg-check-schema-merge}/SKILL.md +5 -5
- package/skills/upg-context/SKILL.md +96 -72
- package/skills/upg-context-intelligence/SKILL.md +23 -27
- package/skills/upg-design-system/SKILL.md +21 -26
- package/skills/{upg-verify → upg-find-untracked}/SKILL.md +7 -12
- package/skills/{upg-rollback → upg-fix-rollback}/SKILL.md +6 -12
- package/skills/{upg-migrate → upg-fix-types}/SKILL.md +5 -9
- package/skills/upg-link/SKILL.md +125 -0
- package/skills/{upg-discover → upg-new-discovery}/SKILL.md +42 -58
- package/skills/{upg-capture → upg-new-from-session}/SKILL.md +13 -15
- package/skills/{upg-template → upg-new-from-template}/SKILL.md +8 -12
- package/skills/{upg-init → upg-new-graph}/SKILL.md +50 -82
- package/skills/{upg-hypothesis → upg-new-hypothesis}/SKILL.md +27 -36
- package/skills/{upg-launch → upg-new-launch}/SKILL-DETAIL.md +36 -92
- package/skills/{upg-launch → upg-new-launch}/SKILL.md +8 -18
- package/skills/{upg-okr → upg-new-okr}/SKILL-DETAIL.md +28 -46
- package/skills/{upg-okr → upg-new-okr}/SKILL.md +3 -3
- package/skills/{upg-persona → upg-new-persona}/SKILL.md +35 -67
- package/skills/{upg-research → upg-new-research}/SKILL.md +25 -33
- package/skills/{upg-schema-update → upg-new-schema-type}/SKILL.md +2 -2
- package/skills/{upg-strategy → upg-new-strategy}/SKILL.md +21 -27
- package/skills/upg-prioritise/SKILL.md +4 -4
- package/skills/upg-reflect/SKILL.md +7 -7
- package/skills/{upg-feedback → upg-send-feedback}/SKILL.md +30 -51
- package/skills/{upg-diff → upg-show-diff}/SKILL.md +6 -12
- package/skills/{upg-inspect → upg-show-entity}/SKILL.md +7 -9
- package/skills/{upg-impact → upg-show-impact}/SKILL.md +11 -15
- package/skills/{upg-journey → upg-show-journey}/SKILL.md +31 -32
- package/skills/{upg-analytics → upg-show-metrics}/SKILL.md +9 -12
- package/skills/{upg-schema-changelog → upg-show-schema-changelog}/SKILL.md +5 -5
- package/skills/{upg-status → upg-show-status}/SKILL.md +39 -40
- package/skills/{upg-tree → upg-show-tree}/SKILL.md +15 -15
- package/skills/{upg-export → upg-sync-export}/SKILL.md +10 -13
- package/skills/{upg-import → upg-sync-import}/SKILL.md +7 -13
- package/skills/{upg-pull → upg-sync-pull}/SKILL-DETAIL.md +13 -17
- package/skills/{upg-pull → upg-sync-pull}/SKILL.md +3 -3
- package/skills/{upg-push → upg-sync-push}/SKILL-DETAIL.md +4 -10
- package/skills/{upg-push → upg-sync-push}/SKILL.md +4 -4
- package/skills/{upg-snapshot → upg-sync-snapshot}/SKILL.md +2 -6
- package/skills/upg-trace/SKILL.md +7 -7
- package/skills/{upg-workspace → upg-use-workspace}/SKILL.md +8 -14
- package/skills/{upg-run → upg-walk-playbook}/SKILL.md +14 -14
- package/skills/upg-walk-region/SKILL-DETAIL.md +320 -0
- package/skills/upg-walk-region/SKILL.md +89 -0
- package/skills/upg-connect/SKILL.md +0 -167
- package/skills/upg-explore/SKILL-DETAIL.md +0 -481
- package/skills/upg-explore/SKILL.md +0 -297
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upg-launch
|
|
2
|
+
name: upg-new-launch
|
|
3
3
|
description: "Guided go-to-market planning: positioning, messaging, channels, launch timeline as graph entities"
|
|
4
4
|
user-invocable: true
|
|
5
5
|
argument-hint: "[description]"
|
|
6
6
|
category: cognitive
|
|
7
7
|
approaches: [plan]
|
|
8
|
-
playbooks: [business-gtm-growth, business-marketing]
|
|
8
|
+
playbooks: [playbook:business-gtm-growth, playbook:business-marketing-audience-first]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# /upg-launch: Go-to-Market Planning
|
|
11
|
+
# /upg-new-launch: Go-to-Market Planning
|
|
12
12
|
|
|
13
13
|
You are a GTM strategist. Your job is to help the user plan and structure a product launch as a connected set of graph entities; from positioning and messaging to channels and phased rollout.
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@ You are a GTM strategist. Your job is to help the user plan and structure a prod
|
|
|
18
18
|
|
|
19
19
|
Use the `mcp__unified-product-graph__*` MCP tools (create_node, create_edge, update_node, get_product_context, search_nodes, list_nodes).
|
|
20
20
|
|
|
21
|
-
> **Note:** This covers positioning, messaging, and channels. For pricing strategy, run `/upg-
|
|
21
|
+
> **Note:** This covers positioning, messaging, and channels. For pricing strategy, run `/upg-walk-region pricing`. For the full business model, run `/upg-walk-region business_model`.
|
|
22
22
|
|
|
23
23
|
## Phase Map
|
|
24
24
|
|
|
@@ -55,18 +55,11 @@ If the user already gave you context (from the product, personas, business model
|
|
|
55
55
|
|
|
56
56
|
When the user answers, don't just silently move on. Briefly acknowledge, reflect back what you heard, or add a small insight. Then move to the next question. This makes it feel like a conversation.
|
|
57
57
|
|
|
58
|
-
## Entity Types
|
|
58
|
+
## Entity Types
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|---|---|---|
|
|
62
|
-
| gtm_strategy | 📣 | Container for the overall GTM plan |
|
|
63
|
-
| ideal_customer_profile | 🎯 | Who you're launching to |
|
|
64
|
-
| positioning | 🎯 | How you position in the market |
|
|
65
|
-
| messaging | 💬 | Key messages for the launch |
|
|
66
|
-
| launch | 🚀 | The launch itself; phases and timeline |
|
|
67
|
-
| acquisition_channel | 📣 | Ongoing growth channels beyond launch day |
|
|
68
|
-
| content_strategy | 📝 | Content approach to fuel acquisition |
|
|
60
|
+
A GTM plan spans a container strategy, the ideal-customer profile, positioning, messaging, the launch itself, acquisition channels, and content strategy. **Confirm the exact type ids and their emojis live**: call `list_entity_types` (or `get_region` for the Business GTM region) to see which types exist, and `get_type_label(<type>)` for each emoji rather than trusting a baked table. Don't assume a type exists; if a region doesn't define one of these, adapt to what `list_entity_types` returns.
|
|
69
61
|
|
|
62
|
+
> **MCP-first.** Before creating any of these, call `get_entity_schema(<type>)`: drive `properties` from its `expected_properties`, set `status` top-level from its lifecycle phases, and resolve every edge with `resolve_edge_for_pair({ source_type, target_type })`. The flow detail's payloads show shape and intent only.
|
|
70
63
|
|
|
71
64
|
## Discovery Flow
|
|
72
65
|
|
|
@@ -123,11 +116,8 @@ Check the graph for the biggest gap across the 8 business areas. Recommend ONE n
|
|
|
123
116
|
|
|
124
117
|
> Based on what we built, your biggest gap is **[area]**. I'd suggest running `/upg-[skill]` next to [reason].
|
|
125
118
|
>
|
|
126
|
-
> Or run `/upg-journey` to see where you are in the bigger picture.
|
|
119
|
+
> Or run `/upg-show-journey` to see where you are in the bigger picture.
|
|
127
120
|
|
|
128
|
-
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
|
|
129
|
-
Your `.upg` file is yours: open standard, portable, git-friendly.
|
|
130
|
-
unifiedproductgraph.org
|
|
131
121
|
|
|
132
122
|
## Key Principles
|
|
133
123
|
|
|
@@ -3,7 +3,9 @@ name: upg-okr-detail
|
|
|
3
3
|
description: "Detailed OKR builder discovery flow"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /upg-okr: Discovery Flow Detail
|
|
6
|
+
# /upg-new-okr: Discovery Flow Detail
|
|
7
|
+
|
|
8
|
+
> **MCP-first (applies to every create below).** Before creating an objective, key result, initiative, or metric, call `get_entity_schema({ type: <type> })` for its `expected_properties`. Set the node's top-level `status` from a phase id returned by `get_lifecycle({ entity_type: <type> })` — that is where lifecycle phases live, NOT in `get_entity_schema` (objective phases are `draft`/`active`/`achieved`/`missed`/`deferred`). Note that a `*_status` PROPERTY (e.g. `objective_status`, `kr_status`) is a distinct enum field inside `expected_properties` — it is NOT the node's lifecycle `status`; don't conflate the two. Pass any assessment property as `{ value, label }`. Before any edge, call `resolve_edge_for_pair({ source_type, target_type })` and let the server infer the edge type. The payloads below show shape and intent only; the authoritative keys and phases come from the schema/lifecycle at runtime.
|
|
7
9
|
|
|
8
10
|
## Discovery Flow
|
|
9
11
|
|
|
@@ -82,18 +84,18 @@ Coach if they give a metric as an objective: **"That sounds like a key result; a
|
|
|
82
84
|
|
|
83
85
|
STOP. Wait for the answer. Then create the objective:
|
|
84
86
|
|
|
85
|
-
> **Note:**
|
|
87
|
+
> **Note:** The product is a top-level `.upg` field, not a node — `list_nodes({ type: "product" })` is empty and there is no product id to parent under. Create the objective at ROOT (no `parent_id`); its canonical anchor is an `outcome`, so if a relevant outcome exists, parent under that, otherwise leave it at root and wire edges later. Don't invent a `product_id`.
|
|
86
88
|
|
|
87
89
|
```
|
|
90
|
+
// Read get_entity_schema({ type: "objective" }) for properties; read
|
|
91
|
+
// get_lifecycle({ entity_type: "objective" }) for the status phases. Then:
|
|
88
92
|
create_node({
|
|
89
93
|
type: "objective",
|
|
90
94
|
title: "<objective statement>",
|
|
91
95
|
description: "<why this matters this quarter>",
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
},
|
|
96
|
-
parent_id: "<product_id>"
|
|
96
|
+
status: "active", // a phase id from get_lifecycle({ entity_type: "objective" }): draft|active|achieved|missed|deferred
|
|
97
|
+
properties: { /* keys from get_entity_schema objective: timeframe, etc. */ }
|
|
98
|
+
// no parent_id — objective is created at root (or under an outcome if one exists)
|
|
97
99
|
})
|
|
98
100
|
```
|
|
99
101
|
|
|
@@ -133,18 +135,14 @@ STOP. Wait for the answer.
|
|
|
133
135
|
Then create the key result:
|
|
134
136
|
|
|
135
137
|
```
|
|
138
|
+
// Read get_entity_schema({ type: "key_result" }) for properties and
|
|
139
|
+
// get_lifecycle({ entity_type: "key_result" }) for its status phases, then:
|
|
136
140
|
create_node({
|
|
137
141
|
type: "key_result",
|
|
138
142
|
title: "<metric>: <current> → <target>",
|
|
139
143
|
description: "<why this metric matters for the objective>",
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
current_value: <number>,
|
|
143
|
-
target_value: <number>,
|
|
144
|
-
unit: "<%, users, seconds, NPS, etc.>",
|
|
145
|
-
score: 0,
|
|
146
|
-
status: "active"
|
|
147
|
-
},
|
|
144
|
+
status: "<a phase id from get_lifecycle({ entity_type: 'key_result' })>",
|
|
145
|
+
properties: { /* keys from the schema: current_value, target_value, unit, etc. (kr_status, if present, is a PROPERTY, not this lifecycle status) */ },
|
|
148
146
|
parent_id: "<objective_id>"
|
|
149
147
|
})
|
|
150
148
|
```
|
|
@@ -197,32 +195,26 @@ You have initiatives and features in your graph that might drive this:
|
|
|
197
195
|
If creating a new initiative:
|
|
198
196
|
|
|
199
197
|
```
|
|
198
|
+
// Read get_entity_schema({ type: "initiative" }) for properties and
|
|
199
|
+
// get_lifecycle({ entity_type: "initiative" }) for its status phases, then:
|
|
200
200
|
create_node({
|
|
201
201
|
type: "initiative",
|
|
202
202
|
title: "<initiative name>",
|
|
203
203
|
description: "<how this drives the key result>",
|
|
204
|
-
|
|
205
|
-
status: "planned"
|
|
206
|
-
},
|
|
204
|
+
status: "<a phase id from get_lifecycle({ entity_type: 'initiative' })>",
|
|
207
205
|
parent_id: "<key_result_id>"
|
|
208
206
|
})
|
|
209
207
|
```
|
|
210
208
|
|
|
211
|
-
If linking to an existing entity,
|
|
209
|
+
If linking to an existing entity, resolve the canonical edge for the pair and let the server infer the type:
|
|
212
210
|
|
|
213
211
|
```
|
|
214
|
-
//
|
|
215
|
-
create_edge({
|
|
216
|
-
source_id: "<feature_id>",
|
|
217
|
-
target_id: "<key_result_id>",
|
|
218
|
-
type: "feature_drives_key_result"
|
|
219
|
-
})
|
|
212
|
+
// feature → key_result: edge = resolve_edge_for_pair({ source_type: "feature", target_type: "key_result" })
|
|
213
|
+
create_edge({ source_id: "<feature_id>", target_id: "<key_result_id>" }) // server infers type
|
|
220
214
|
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
// (initiatives currently connect to outcomes; key_result quantifies the
|
|
225
|
-
// outcome via objective_achieved_through_key_result + metric_measures_key_result)
|
|
215
|
+
// initiative → its driven entity: resolve_edge_for_pair({ source_type: "initiative", target_type: <that type> })
|
|
216
|
+
// then create_edge without an explicit type:. Use resolve_edge_for_pair to discover
|
|
217
|
+
// what an initiative validly drives rather than assuming a fixed target type.
|
|
226
218
|
```
|
|
227
219
|
|
|
228
220
|
### Step 5: Additional Metrics (optional)
|
|
@@ -253,31 +245,21 @@ STOP. Wait for the answer.
|
|
|
253
245
|
Create the `metric` entity:
|
|
254
246
|
|
|
255
247
|
```
|
|
248
|
+
// Read get_entity_schema({ type: "metric" }) first, then:
|
|
256
249
|
create_node({
|
|
257
250
|
type: "metric",
|
|
258
251
|
title: "<metric name>",
|
|
259
252
|
description: "<what this metric measures and why it matters>",
|
|
260
|
-
properties: {
|
|
261
|
-
designation: "<input | guardrail | health | counter | vanity | north_star>",
|
|
262
|
-
metric_category: "<aarrr or heart category>",
|
|
263
|
-
current_value: <number if known>,
|
|
264
|
-
unit: "<%, count, seconds, score, etc.>",
|
|
265
|
-
indicator_direction: "<leading | lagging>"
|
|
266
|
-
// Note: connect this metric to the related key_result via the
|
|
267
|
-
// `metric_measures_key_result` edge below instead of a free-text property.
|
|
268
|
-
},
|
|
253
|
+
properties: { /* keys from the schema: designation, category, current value, unit, direction */ },
|
|
269
254
|
parent_id: "<objective_id>"
|
|
270
255
|
})
|
|
271
256
|
```
|
|
272
257
|
|
|
273
|
-
Connect to the relevant key result:
|
|
258
|
+
Connect to the relevant key result; resolve the edge first:
|
|
274
259
|
|
|
275
260
|
```
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
target_id: "<key_result_id>",
|
|
279
|
-
type: "metric_measures_key_result"
|
|
280
|
-
})
|
|
261
|
+
// edge = resolve_edge_for_pair({ source_type: "metric", target_type: "key_result" })
|
|
262
|
+
create_edge({ source_id: "<metric_id>", target_id: "<key_result_id>" }) // server infers type
|
|
281
263
|
```
|
|
282
264
|
|
|
283
265
|
Confirm: "📊 **<Metric Name>** added as a <metric type> metric."
|
|
@@ -347,5 +329,5 @@ Check the graph for the biggest gap across the 8 business areas. Recommend ONE n
|
|
|
347
329
|
|
|
348
330
|
> Based on what we built, your biggest gap is **[area]**. I'd suggest running `/upg-[skill]` next to [reason].
|
|
349
331
|
>
|
|
350
|
-
> Or run `/upg-journey` to see where you are in the bigger picture.
|
|
332
|
+
> Or run `/upg-show-journey` to see where you are in the bigger picture.
|
|
351
333
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upg-okr
|
|
2
|
+
name: upg-new-okr
|
|
3
3
|
description: "Guided OKR Builder"
|
|
4
4
|
user-invocable: true
|
|
5
5
|
argument-hint: "[timeframe or objective]"
|
|
6
6
|
category: cognitive
|
|
7
7
|
approaches: [plan]
|
|
8
|
-
playbooks: [strategy-outcomes]
|
|
8
|
+
playbooks: [playbook:strategy-outcomes]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# /upg-okr: OKR Builder
|
|
11
|
+
# /upg-new-okr: OKR Builder
|
|
12
12
|
|
|
13
13
|
You are a Unified Product Graph OKR facilitator. Your job is to walk the user through building well-structured OKRs: objectives with measurable key results, connected to initiatives that drive them. Based on John Doerr's "Measure What Matters" framework.
|
|
14
14
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upg-persona
|
|
2
|
+
name: upg-new-persona
|
|
3
3
|
description: "Guided Persona Creation"
|
|
4
4
|
user-invocable: true
|
|
5
5
|
argument-hint: "[description]"
|
|
6
6
|
category: cognitive
|
|
7
7
|
approaches: [plan]
|
|
8
|
-
playbooks: [users-needs]
|
|
8
|
+
playbooks: [playbook:users-needs]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# /upg-persona: Guided Persona Creation
|
|
11
|
+
# /upg-new-persona: Guided Persona Creation
|
|
12
12
|
|
|
13
13
|
You are a Unified Product Graph persona specialist. Your job is to walk the user through creating a rich, detailed persona, not a shallow name-and-role card, but a real human with context, desired outcomes, needs, and motivations. Then connect them to their first Job-to-be-Done.
|
|
14
14
|
|
|
@@ -62,7 +62,7 @@ Show: **"Phase 2 of 4: What drives them"**
|
|
|
62
62
|
|
|
63
63
|
Ask: **"What are they trying to achieve? Think both immediate and aspirational; what does success look like for them?"**
|
|
64
64
|
|
|
65
|
-
> **
|
|
65
|
+
> **Chain model:** capture 2-4 desired outcomes; these become SEPARATE nodes connected to the persona, never a `goals` array on the persona. The exact child type and the edge that links them are resolved live at create time (see "Create the Persona"), not assumed here.
|
|
66
66
|
|
|
67
67
|
Cover the spectrum:
|
|
68
68
|
- Immediate outcomes (this quarter, this project)
|
|
@@ -73,7 +73,7 @@ Cover the spectrum:
|
|
|
73
73
|
|
|
74
74
|
Ask: **"What gets in their way? What frustrates them about how they work today? Where does the current experience break down?"**
|
|
75
75
|
|
|
76
|
-
> **
|
|
76
|
+
> **Chain model:** capture 2-4 needs; these become SEPARATE nodes connected to the persona, never a `frustrations` array on the persona. The child type and edge are resolved live at create time, not assumed here.
|
|
77
77
|
|
|
78
78
|
Cover the dimensions:
|
|
79
79
|
- Tool-related needs
|
|
@@ -85,9 +85,9 @@ Cover the dimensions:
|
|
|
85
85
|
|
|
86
86
|
Show: **"Phase 3 of 4: How they work"**
|
|
87
87
|
|
|
88
|
-
Ask: **"How comfortable are they with technology?
|
|
88
|
+
Ask: **"How comfortable are they with technology? Low (avoids it), medium, high, or expert (power user who automates everything)?"**
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
`tech_comfort` is a **string enum**, not a 1-5 assessment. Valid values are `"low"`, `"medium"`, `"high"`, `"expert"`, `"other"` (confirm against `get_entity_schema({ type: "persona" }).expected_properties.tech_comfort.enum`). Write the chosen enum string verbatim — `tech_comfort: "high"`, never a bare number. If the user gives you a number or a phrase, map it to the closest enum value and confirm. If you can't tell, infer from context (or use `"other"`).
|
|
91
91
|
|
|
92
92
|
### Step 6: Motivation
|
|
93
93
|
|
|
@@ -99,80 +99,58 @@ Use this as the persona's `description`; the narrative that brings them to life.
|
|
|
99
99
|
|
|
100
100
|
**Vibe check first:** Before creating, show a summary card and ask: **"Here's what I've captured about <Name>; anything you'd change before I save?"**
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
**MCP-first (do not write payloads from memory).** Before creating anything:
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
1. Call `get_entity_schema({ type: "persona" })`. Build `properties` from its `expected_properties` (use the keys it returns; map the answers you gathered onto them — `tech_comfort` is a string enum, see Step 5), and respect its valid parent→child hierarchy. Persona is a stateless type: it has no lifecycle, so do **not** set a top-level `status`. The schema is the source of truth for which property keys exist; don't assume a fixed allowlist. **Never set `goals` or `frustrations` arrays on the persona**: those become separate chain nodes (next).
|
|
105
|
+
2. For each child type you'll chain (the desired-outcome node, the need node), call `get_entity_schema({ type: <child_type> })` to confirm the type id and its properties. Use `get_valid_children({ parent_type: "persona" })` if you're unsure what can live under a persona.
|
|
106
|
+
3. For each edge, call `resolve_edge_for_pair({ source_type, target_type })` to get the canonical edge for that pair, then create the edge letting the server infer the type (omit an explicit `type:`).
|
|
105
107
|
|
|
106
108
|
```
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
//
|
|
109
|
+
// 1. Schema-driven create. The persona is a top-level entity: create it at ROOT
|
|
110
|
+
// (no parent_id). The product is a top-level .upg field, NOT a node, so there is
|
|
111
|
+
// no product node to parent under or link to by default. Read
|
|
112
|
+
// get_entity_schema({ type: "persona" }) first, then:
|
|
111
113
|
create_node({
|
|
112
114
|
type: "persona",
|
|
113
115
|
title: "<Name>; <Role>",
|
|
114
116
|
description: "<Motivation narrative; what drives them, what they care about>",
|
|
115
|
-
properties: {
|
|
116
|
-
context: "<Their world; company, industry, experience, daily reality>",
|
|
117
|
-
motivation: "<Primary motivation or driving need>",
|
|
118
|
-
tech_comfort: "<low|medium|high or descriptive>"
|
|
119
|
-
},
|
|
120
|
-
parent_id: "<product_id>"
|
|
117
|
+
properties: { /* keys from get_entity_schema persona.expected_properties; tech_comfort is an enum */ }
|
|
121
118
|
})
|
|
122
119
|
// → persona_id = result.node.id
|
|
123
120
|
|
|
124
|
-
// 2. For each desired outcome from Step 3:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
parent_id: "<persona_id>"
|
|
130
|
-
})
|
|
131
|
-
create_edge({
|
|
132
|
-
source_id: "<persona_id>",
|
|
133
|
-
target_id: "<desired_outcome_id>",
|
|
134
|
-
type: "persona_aspires_to_desired_outcome"
|
|
135
|
-
})
|
|
121
|
+
// 2. For each desired outcome from Step 3 — child type + edge resolved live:
|
|
122
|
+
// childType = the outcome/aspiration type from get_valid_children({ parent_type: "persona" })
|
|
123
|
+
create_node({ /* type from schema */ title: "<outcome>", parent_id: "<persona_id>" })
|
|
124
|
+
// edge = resolve_edge_for_pair({ source_type: "persona", target_type: childType })
|
|
125
|
+
create_edge({ source_id: "<persona_id>", target_id: "<child_id>" }) // server infers type
|
|
136
126
|
|
|
137
|
-
// 3. For each need from Step 4
|
|
138
|
-
create_node({
|
|
139
|
-
type: "need",
|
|
140
|
-
title: "<need statement>",
|
|
141
|
-
description: "<the specific frustration or unmet demand>",
|
|
142
|
-
parent_id: "<persona_id>"
|
|
143
|
-
})
|
|
144
|
-
create_edge({
|
|
145
|
-
source_id: "<persona_id>",
|
|
146
|
-
target_id: "<need_id>",
|
|
147
|
-
type: "persona_experiences_need"
|
|
148
|
-
})
|
|
127
|
+
// 3. For each need from Step 4 — same pattern, child type + edge resolved live.
|
|
149
128
|
```
|
|
150
129
|
|
|
151
130
|
Tip: for 3+ chain nodes, use `batch_create_nodes` with `parent_ref` chaining instead of N individual `create_node` calls.
|
|
152
131
|
|
|
153
132
|
## Show the Result
|
|
154
133
|
|
|
155
|
-
Display the complete persona card with entity emojis
|
|
134
|
+
Display the complete persona card with entity emojis (tech comfort renders as its enum value, not score dots; persona properties are strings/enums, not 1-5 assessments):
|
|
156
135
|
|
|
157
136
|
```
|
|
158
137
|
### 👤 <Name>: <Role>
|
|
159
138
|
|
|
160
139
|
**Context:** <their world>
|
|
161
|
-
**Tech comfort:**
|
|
140
|
+
**Tech comfort:** <enum value: low | medium | high | expert | other>
|
|
162
141
|
|
|
163
|
-
**Desired outcomes
|
|
142
|
+
**Desired outcomes:**
|
|
164
143
|
- 🎯 <outcome 1>
|
|
165
144
|
- 🎯 <outcome 2>
|
|
166
145
|
- 🎯 <outcome 3>
|
|
167
146
|
|
|
168
|
-
**Needs
|
|
147
|
+
**Needs:**
|
|
169
148
|
- ⚡ <need 1>
|
|
170
149
|
- ⚡ <need 2>
|
|
171
150
|
- ⚡ <need 3>
|
|
172
151
|
|
|
173
152
|
**Motivation:** <what drives them>
|
|
174
153
|
|
|
175
|
-
Connected to: 🎯 <Product Name>
|
|
176
154
|
Domain: User
|
|
177
155
|
```
|
|
178
156
|
|
|
@@ -184,33 +162,29 @@ A Job-to-be-Done (JTBD) is the thing your user is trying to accomplish; the reas
|
|
|
184
162
|
|
|
185
163
|
After creating the persona, ask: **"What's the most important job this persona is hiring your product to do? Think about it as: 'When I [situation], I want to [action], so I can [outcome].'"**
|
|
186
164
|
|
|
187
|
-
If they answer, create
|
|
165
|
+
If they answer, create the JTBD and connect it. **First call `get_entity_schema({ type: <job_type> })`** — find the job/JTBD type id via `get_valid_children({ parent_type: "persona" })` — to learn its real property keys and which of them are assessments. Assessment properties take `{ value, label }` objects (not bare ints); the schema flags them. Then resolve the linking edge with `resolve_edge_for_pair`.
|
|
188
166
|
|
|
189
167
|
```
|
|
168
|
+
// Read get_entity_schema for the job type first; build properties from its keys.
|
|
190
169
|
create_node({
|
|
191
|
-
type: "job",
|
|
170
|
+
type: "<job type from get_valid_children({ parent_type: 'persona' })>",
|
|
192
171
|
title: "<concise job statement>",
|
|
193
172
|
description: "<the full When I... I want to... So I can... statement>",
|
|
194
173
|
properties: {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
importance: <1-5>,
|
|
198
|
-
current_satisfaction: <1-5> // how well current solutions handle this
|
|
174
|
+
// keys from the schema; the situation/action/outcome statement + job category.
|
|
175
|
+
// Any property the schema marks as an assessment → { value: <1-5>, label: "<...>" }.
|
|
199
176
|
},
|
|
200
177
|
parent_id: "<persona_id>"
|
|
201
178
|
})
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
target_id: "<job_id>",
|
|
205
|
-
type: "persona_pursues_job"
|
|
206
|
-
})
|
|
179
|
+
// edge = resolve_edge_for_pair({ source_type: "persona", target_type: "<job type>" })
|
|
180
|
+
create_edge({ source_id: "<persona_id>", target_id: "<job_id>" }) // server infers type
|
|
207
181
|
```
|
|
208
182
|
|
|
209
183
|
Then use the smart ending pattern: check the graph for the biggest business area gap and recommend ONE next skill:
|
|
210
184
|
|
|
211
185
|
> Based on what we built, your biggest gap is **[area]**. I'd suggest running `/upg-[skill]` next to [reason].
|
|
212
186
|
>
|
|
213
|
-
> Or run `/upg-journey` to see where you are in the bigger picture.
|
|
187
|
+
> Or run `/upg-show-journey` to see where you are in the bigger picture.
|
|
214
188
|
|
|
215
189
|
For JTBD importance and satisfaction: ask the user ("On a scale of 1-5, how important is this job? And how well do current solutions handle it?") or, if the conversation already gave clear signals, infer and confirm: "Based on what you said, I'd put importance at 5 and current satisfaction at 2; sound right?"
|
|
216
190
|
|
|
@@ -220,11 +194,5 @@ For JTBD importance and satisfaction: ask the user ("On a scale of 1-5, how impo
|
|
|
220
194
|
- **One question at a time.** Don't dump all 6 questions at once. React to each answer.
|
|
221
195
|
- **Push for specificity.** "Wants to be more productive" is too vague. "Wants to ship features 2x faster without burning out the team" is useful.
|
|
222
196
|
- **Follow the design system.** Entity emojis, score dots, filled bars, dashed dividers as defined in /upg-context.
|
|
223
|
-
- **
|
|
197
|
+
- **Connect the persona to its jobs and needs, not to a phantom product.** The product is a top-level `.upg` field, not a node — `list_nodes({ type: "product" })` is empty and there is no product id to link from by default. Create the persona at root and chain its desired outcomes, needs, and JTBD off it. (If a graph genuinely contains a `product` *node*, you may link it via `resolve_edge_for_pair({ source_type: "product", target_type: "persona" })` — but never assume one exists.)
|
|
224
198
|
- **Bridge to JTBD.** A 👤 persona without a 💼 job is incomplete. Always offer to create the first JTBD.
|
|
225
|
-
|
|
226
|
-
```
|
|
227
|
-
┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
|
|
228
|
-
Your .upg file is yours: open standard, portable, git-friendly.
|
|
229
|
-
unifiedproductgraph.org
|
|
230
|
-
```
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upg-research
|
|
2
|
+
name: upg-new-research
|
|
3
3
|
description: "Guided User Research Session"
|
|
4
4
|
user-invocable: true
|
|
5
5
|
argument-hint: "[research type or question]"
|
|
6
6
|
category: cognitive
|
|
7
7
|
approaches: [plan]
|
|
8
|
-
playbooks: [discovery-research-validation]
|
|
8
|
+
playbooks: [playbook:discovery-research-validation]
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
# /upg-research: User Research Session
|
|
11
|
+
# /upg-new-research: User Research Session
|
|
12
12
|
|
|
13
13
|
You are a Unified Product Graph research facilitator. Your job is to walk the user through setting up a research study, capturing insights from it, and connecting those insights to opportunities in their product graph.
|
|
14
14
|
|
|
@@ -21,6 +21,8 @@ When creating 3+ entities, use `batch_create_nodes` with `parent_ref` chaining;
|
|
|
21
21
|
When creating 3+ edges, use `batch_create_edges`; never loop `create_edge`.
|
|
22
22
|
When deleting 3+ entities, use `batch_delete_nodes`.
|
|
23
23
|
|
|
24
|
+
> **MCP-first (applies to every create below).** Before creating a research study, insight, or opportunity, call `get_entity_schema(<type>)`. Build `properties` from its `expected_properties`, set `status` **top-level** from one of the lifecycle phases the schema returns (don't hard-code the status enum), and pass any property the schema marks as an assessment as `{ value, label }`. Before any edge, call `resolve_edge_for_pair({ source_type, target_type })` and let the server infer the edge type. The payloads below show shape and intent; the authoritative keys and phases come from the schema.
|
|
25
|
+
|
|
24
26
|
## Phase Map
|
|
25
27
|
|
|
26
28
|
| Phase | Label | Steps |
|
|
@@ -144,23 +146,22 @@ Ask: **"How many participants, and what's the status?"**
|
|
|
144
146
|
STOP. Wait for the answer. Then create the research study node:
|
|
145
147
|
|
|
146
148
|
```
|
|
149
|
+
// Read get_entity_schema("research_study") first, then:
|
|
147
150
|
create_node({
|
|
148
151
|
type: "research_study",
|
|
149
152
|
title: "<method>; <topic>",
|
|
150
|
-
description: "<research question>",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
research_question: "<the question>",
|
|
154
|
-
participant_count: <number>,
|
|
155
|
-
status: "<planned|in_progress|completed>"
|
|
156
|
-
},
|
|
153
|
+
description: "<the research question, as narrative>",
|
|
154
|
+
status: "<planned phase from the schema>",
|
|
155
|
+
properties: { /* keys from the schema, e.g. method, participant count */ },
|
|
157
156
|
parent_id: "<product_id>"
|
|
158
157
|
})
|
|
158
|
+
// The research question is typically a separate entity, not a property; if you
|
|
159
|
+
// model it, resolve the linking edge with resolve_edge_for_pair.
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
Confirm: "**<Study Title>** is in the graph."
|
|
162
163
|
|
|
163
|
-
If the study is still `planned`, suggest next steps for running it and end here. If `in_progress` or `
|
|
164
|
+
If the study is still `planned`, suggest next steps for running it and end here. If `in_progress` or `complete`, proceed to insight capture.
|
|
164
165
|
|
|
165
166
|
### Step 4: Capture Insights: One at a Time
|
|
166
167
|
|
|
@@ -193,16 +194,14 @@ React to the insight; reflect it back and add analytical context. Then ask: **"H
|
|
|
193
194
|
STOP. Wait for the answer. Then create the insight node:
|
|
194
195
|
|
|
195
196
|
```
|
|
197
|
+
// Read get_entity_schema("insight") first, then:
|
|
196
198
|
create_node({
|
|
197
199
|
type: "insight",
|
|
198
200
|
title: "<concise insight statement>",
|
|
199
201
|
description: "<supporting evidence; what was observed>",
|
|
202
|
+
status: "<proposed phase from the schema>",
|
|
200
203
|
properties: {
|
|
201
|
-
|
|
202
|
-
confidence: "<high|medium|low>",
|
|
203
|
-
source_method: "<method from study>",
|
|
204
|
-
evidence_count: <how many exhibited this>,
|
|
205
|
-
status: "identified"
|
|
204
|
+
/* keys from the schema; any assessment property (e.g. confidence) → { value, label } */
|
|
206
205
|
},
|
|
207
206
|
parent_id: "<research_study_id>"
|
|
208
207
|
})
|
|
@@ -241,34 +240,27 @@ This insight might connect to opportunities already in your graph:
|
|
|
241
240
|
If creating a new opportunity:
|
|
242
241
|
|
|
243
242
|
```
|
|
243
|
+
// Read get_entity_schema("opportunity") first, then:
|
|
244
244
|
create_node({
|
|
245
245
|
type: "opportunity",
|
|
246
246
|
title: "<opportunity derived from insight>",
|
|
247
247
|
description: "<how the research insight points to this opportunity>",
|
|
248
|
+
status: "<identified phase from the schema>",
|
|
248
249
|
properties: {
|
|
249
|
-
|
|
250
|
-
source: "research",
|
|
251
|
-
reach: <1-5>,
|
|
252
|
-
pain: <1-5>
|
|
250
|
+
/* keys from the schema; assessment properties (e.g. reach, pain) → { value, label } */
|
|
253
251
|
},
|
|
254
252
|
parent_id: "<product_id>"
|
|
255
253
|
})
|
|
256
254
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
target_id: "<opportunity_id>",
|
|
260
|
-
type: "insight_informs_opportunity"
|
|
261
|
-
})
|
|
255
|
+
// edge = resolve_edge_for_pair({ source_type: "insight", target_type: "opportunity" })
|
|
256
|
+
create_edge({ source_id: "<insight_id>", target_id: "<opportunity_id>" }) // server infers type
|
|
262
257
|
```
|
|
263
258
|
|
|
264
|
-
If linking to an existing opportunity
|
|
259
|
+
If linking to an existing opportunity, resolve the same edge and create it without an explicit `type:`:
|
|
265
260
|
|
|
266
261
|
```
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
target_id: "<existing_opportunity_id>",
|
|
270
|
-
type: "insight_informs_opportunity"
|
|
271
|
-
})
|
|
262
|
+
// edge = resolve_edge_for_pair({ source_type: "insight", target_type: "opportunity" })
|
|
263
|
+
create_edge({ source_id: "<insight_id>", target_id: "<existing_opportunity_id>" }) // server infers type
|
|
272
264
|
```
|
|
273
265
|
|
|
274
266
|
### Step 6: More Insights?
|
|
@@ -319,10 +311,10 @@ Check the graph for the biggest gap across the 8 business areas. Recommend ONE n
|
|
|
319
311
|
|
|
320
312
|
> Based on what we built, your biggest gap is **[area]**. I'd suggest running `/upg-[skill]` next to [reason].
|
|
321
313
|
>
|
|
322
|
-
> Or run `/upg-journey` to see where you are in the bigger picture.
|
|
314
|
+
> Or run `/upg-show-journey` to see where you are in the bigger picture.
|
|
323
315
|
|
|
324
316
|
After rendering your recommendation, call:
|
|
325
|
-
`update_session_context({ skill_invoked: "upg-research", recommendation: "<the next skill you recommended>" })`
|
|
317
|
+
`update_session_context({ skill_invoked: "upg-new-research", recommendation: "<the next skill you recommended>" })`
|
|
326
318
|
|
|
327
319
|
## Key Principles
|
|
328
320
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upg-schema-
|
|
2
|
+
name: upg-new-schema-type
|
|
3
3
|
description: "Add or update UPG entity types, edge types, or properties: cascades through the full codebase"
|
|
4
4
|
user-invocable: false
|
|
5
5
|
audience: advanced
|
|
@@ -9,7 +9,7 @@ category: schema
|
|
|
9
9
|
|
|
10
10
|
> ⚠️ **Advanced skill**: intended for UPG contributors and power users who understand the spec internals. Not for general use. Running mutation skills (schema-update, schema-consolidate, schema-evolve) without understanding the cascade can corrupt your graph.
|
|
11
11
|
|
|
12
|
-
# /upg-schema-
|
|
12
|
+
# /upg-new-schema-type: UPG Schema Update Cascade
|
|
13
13
|
|
|
14
14
|
You are a schema update operator. When new entity types, edge types, or properties need to be added to the UPG specification, you cascade the change through every registration point in the codebase; from spec to MCP server to Graph UI to cloud server.
|
|
15
15
|
|