Opportunity Solution Tree (OST) sub-skill — given a Problem statement, surface a candidate Desired Outcome by decomposing the problem space into opportunities and tracing each back to the operational outcome it implies. KL-primary via Cagan (Inspired ch.7) + Patton (User Story Mapping ch.13); URL-grounded via Teresa Torres OST reference. Called by /clarification Step 1b via opt-in --via-opportunity-tree flag.
Install
npx skillscat add dmitrydf/q/opportunity-tree Install via the SkillsCat registry.
/opportunity-tree
Given a Problem statement (from /clarification Step 1b), decompose the problem space into 2–5 opportunities and surface a candidate Desired Outcome that, if achieved, would resolve the most load-bearing opportunity branch.
This skill is an AI adapter — "Judgment only, behind a port" (per ~/.claude/rules/code_first_architecture.md §AI Adapter). It receives structured input, returns structured output, and has no state of its own.
The skill does NOT replace /outcome-framing — /outcome-framing reframes an own-words solution into Cagan-shaped outcome wording; /opportunity-tree produces a candidate outcome from a Problem (no solution yet). Both can run; /opportunity-tree is opt-in from Step 1b, /outcome-framing lives at Step 7.
Trigger
Activate when:
- Called by
/clarificationStep 1b via the--via-opportunity-treeopt-in flag (the documented calling site) - User says
/opportunity-treeor "build an opportunity tree" with a Problem statement available
Default OFF in /clarification Step 1b — the user (or /clarification heuristic) opts in.
Main-session use is the default. The skill is pure judgment — no tools required besides Read for KL anchors.
Contract
Input
{
"problem": "<one-paragraph Problem statement, from /clarification Step 1b>",
"context": "<optional plain-text context: domain, users, constraints, prior work>"
}problem is required and non-empty. context may be null.
Output
{
"tree": {
"root_outcome_candidate": "<the candidate Desired Outcome at the tree root>",
"opportunities": [
{
"id": "O1",
"statement": "<one-sentence opportunity — what the team could do to move the outcome>",
"evidence": "<what makes this opportunity load-bearing — from problem or context>",
"branch_outcome_trace": "<one sentence — if this opportunity were resolved, what changes for the user>"
}
]
},
"desired_outcome_candidate": "<the proposed outcome — operational, observable, no implementation mechanism>",
"rationale": "<one paragraph — why this outcome dominates the tree, which opportunity branches it resolves, what's deliberately deferred>",
"next_actions": [
"Present desired_outcome_candidate to user via AskUserQuestion — (a) accept, (b) revise, (c) reject",
"On accept: persist as the candidate Desired Outcome that Step 7 will lock",
"On revise: capture revised text and re-run /outcome-framing for Cagan-shape check",
"On reject: skill exits; /clarification Step 1b continues without OT contribution"
],
"source_citation": "<KL>/ProductManagement/Sources/Books/inspired-cagan/inspired-cagan.md (Cagan, Inspired ch.7 — outcome vs. output) + <KL>/ProductManagement/Sources/Books/user-story-mapping/user-story-mapping.md (Patton, User Story Mapping ch.13 — opportunity canvas lineage) + https://www.producttalk.org/opportunity-solution-tree/ (Teresa Torres OST canonical reference — URL-grounded for Slice K initial cycle per ~/.claude/rules/plan-gates.md Verification Source Registry)"
}opportunities has 2–5 rows. desired_outcome_candidate must be operational and observable from the workflow (no models, algorithms, file paths, function names, thresholds).
Execution
Step 1 — Load KL anchors
Read <KL>/ProductManagement/Sources/Books/inspired-cagan/inspired-cagan.md (Cagan ch.7 — outcome vs. output rubric) and <KL>/ProductManagement/Sources/Books/user-story-mapping/user-story-mapping.md (Patton ch.13 — opportunity canvas lineage). These ground the outcome-shape rubric and the opportunity-decomposition pattern.
If KL files unreachable at runtime, proceed and flag in source_citation (Edge Case E5).
Step 2 — Identify the root outcome candidate
From the Problem statement, infer the operational outcome the team would observe if the problem were resolved. Frame it Cagan-shape:
- Describes the workflow after resolution — what the user (or downstream actor) experiences.
- Observable from the workflow, not the code.
- Names no implementation mechanism (no models, algorithms, file paths, thresholds).
This is a candidate; the user accepts/revises/rejects via the calling chain's AskUserQuestion.
Step 3 — Decompose into 2–5 opportunities
Surface 2–5 opportunity branches — each branch is "if the team could move X, the outcome would shift." Each opportunity must:
- Be evidence-grounded (from
problemorcontext, not invented). - Trace cleanly back to the root outcome — if this opportunity were resolved, what changes for the user?
- Be distinct from siblings — overlapping opportunities collapse to one.
Anti-pattern check: if every opportunity reduces to the same intervention, the tree has only one branch — surface as a single-branch result rather than padding with redundant branches.
Step 4 — Compose rationale + next_actions + return
Write rationale (1 paragraph): why this root outcome dominates the tree, which opportunity branches it resolves, what's deliberately deferred.
Populate next_actions with the four-line standard surface (accept / revise / reject / re-run paths).
Return the JSON object specified in the Output contract.
Edge Cases
| # | Condition | Handling |
|---|---|---|
| E1 | problem missing or empty |
Return {"error": "problem required", "tree": null, ...}. Do not invent one. |
| E2 | Problem statement names an implementation mechanism instead of a user-side change | Surface in rationale as "input was solution-shaped — outcome candidate strips the mechanism, see /outcome-framing for explicit reframe." Still return a candidate outcome. |
| E3 | Only 1 opportunity inferable (problem is monolithic) | Return tree.opportunities with 1 row + flag in rationale: "single-branch tree — opportunity decomposition surfaced no distinct alternatives." Do NOT pad. |
| E4 | More than 5 opportunities inferable | Return the top 5 ranked by evidence weight + flag in rationale: "tree pruned to 5 branches; deferred opportunities listed in rationale." |
| E5 | KL or URL source unreachable at runtime | Return tree + flag source_citation as "... (UNVERIFIED — file/URL unreachable at runtime)". Do not block. |
| E6 | Candidate outcome contains implementation mechanism | Re-draft Step 2 once. If the second draft still leaks mechanism, return the outcome + flag in rationale: "mechanism leak persists — caller should invoke /outcome-framing for explicit reframe." |
Source
<KL>/ProductManagement/Sources/Books/inspired-cagan/inspired-cagan.md— Cagan, Inspired ch.7 (outcome vs. output rubric)<KL>/ProductManagement/Sources/Books/user-story-mapping/user-story-mapping.md— Patton, User Story Mapping ch.13 (opportunity canvas lineage)https://www.producttalk.org/opportunity-solution-tree/— Teresa Torres OST canonical reference (URL-grounded for Slice K's initial cycle per~/.claude/rules/plan-gates.mdVerification Source Registry)~/.claude/rules/code_first_architecture.md— AI adapter / judgment port pattern~/.claude/rules/plan-gates.md— Verification Source Registry + Gate 0b outcome rubric
Origin attribution. The Opportunity Solution Tree was developed by Teresa Torres (Product Talk) as part of the Continuous Discovery Habits methodology. The Cagan outcome-vs-output frame (ch.7 Inspired) and the Patton opportunity-canvas lineage (ch.13 User Story Mapping) are the KL-primary anchors; Torres' OST is the URL-grounded canonical reference for the tree structure itself.
Sample invocation
Input:
{
"problem": "When the team plans the next two-week iteration, they cannot defend the resulting plan at the stakeholder review — stakeholders push back on what's included and what's deferred, often forcing a mid-meeting re-prioritization.",
"context": "Team is 5 engineers + 1 PM; stakeholder review is every other Friday; current process is a flat backlog with no shared rationale recorded per item."
}Output:
{
"tree": {
"root_outcome_candidate": "When the team plans the next iteration, they walk into stakeholder review with a shared plan that survives the meeting without quiet over-commitment or mid-meeting re-prioritization.",
"opportunities": [
{
"id": "O1",
"statement": "Capture per-item rationale before the review, not during it.",
"evidence": "Stakeholders push back on what's included — implies the rationale isn't visible to them at review time.",
"branch_outcome_trace": "Reviewers can read each item's rationale aloud and judge defensibility before re-opening the priority."
},
{
"id": "O2",
"statement": "Make trade-offs (what's deferred and why) explicit per item.",
"evidence": "Stakeholders push back on what's deferred — implies the trade-off isn't named.",
"branch_outcome_trace": "Reviewers see the cost of including any deferred item, and the trade-off becomes the negotiation surface instead of the priority itself."
},
{
"id": "O3",
"statement": "Anchor the plan in a shared strategy artifact for the period.",
"evidence": "Mid-meeting re-prioritization suggests the team has no shared anchor to point at.",
"branch_outcome_trace": "Reviewers see how each item ladders to the period strategy, so the negotiation is against strategy rather than against the team."
}
]
},
"desired_outcome_candidate": "When the team plans the next iteration, they walk into stakeholder review with a shared plan that survives the meeting without quiet over-commitment or mid-meeting re-prioritization.",
"rationale": "The root outcome dominates because all three opportunities ladder back to the same operational change — the team walking out of the review with the original plan intact. O1 (per-item rationale) is load-bearing for defensibility; O2 (trade-off naming) is load-bearing for negotiation honesty; O3 (strategy anchor) is the upstream condition that makes O1 and O2 work. The outcome candidate is observable from the meeting outcome itself — not from any artifact's structure — which is the Cagan-shaped framing.",
"next_actions": [
"Present desired_outcome_candidate to user via AskUserQuestion — (a) accept, (b) revise, (c) reject",
"On accept: persist as the candidate Desired Outcome that Step 7 will lock",
"On revise: capture revised text and re-run /outcome-framing for Cagan-shape check",
"On reject: skill exits; /clarification Step 1b continues without OT contribution"
],
"source_citation": "<KL>/ProductManagement/Sources/Books/inspired-cagan/inspired-cagan.md (Cagan, Inspired ch.7 — outcome vs. output) + <KL>/ProductManagement/Sources/Books/user-story-mapping/user-story-mapping.md (Patton, User Story Mapping ch.13 — opportunity canvas lineage) + https://www.producttalk.org/opportunity-solution-tree/ (Teresa Torres OST canonical reference — URL-grounded for Slice K initial cycle per ~/.claude/rules/plan-gates.md Verification Source Registry)"
}Non-goals
- This skill does not lock the Desired Outcome — that happens at
/clarificationStep 9. - It does not replace
/outcome-framing— OT decomposes the problem space;/outcome-framingreframes an own-words solution into Cagan shape. - It does not generate solutions — the tree carries opportunities (problem-side decompositions), not solutions.
- It does not validate metrics — that is
/lean-analytics-metricsat Step 8. - It does not fact-check itself. The calling
/clarificationchain wraps the outcome chain in/double-checkat Step 7 and again at Step 9. - It does not edit any files. Pure function: input → output.