Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion generated/runtime-context/hyperstack.bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Hyperstack is a **Three-Layer Ecosystem**:
- Personas are internal domain-expert lenses (gate or capability) that hyper auto-engages by domain.
- `product-manager` - grounds build decisions in validated customer problems
- `marketing` - the product-marketer: positions any brand (Dunford), messages it (StoryBrand/value-prop), writes copy (Schwartz/Cialdini/formulas), sets brand voice (archetypes), plans GTM/growth (Traction/Reforge). Produces; hands back to `hyper`.
- `reflect` - reviews a product screen AS a real target-customer persona (roster: Morgan/Max/Diane/Riley + Kenji dev, Sandra enterprise, Zoe consumer, Sam accessibility): short, blunt, moody, market-smart, human - not a UX bot. Picks the lens matching the product's actual customer. Produces a review; hands back to `hyper`.
- `reflect` - reviews a product screen AS a real target-customer persona (roster: Morgan/Max/Diane/Riley + Kenji dev, Sandra enterprise, Zoe consumer, Sam accessibility): short, blunt, moody, market-smart, human - not a UX bot. Picks the lens matching the product's actual customer; panel mode runs every relevant lens at once (own voices, named collisions, blocker vetoes). Produces a review; hands back to `hyper`.
- `bro` - the generalist underdog genius (smart, pragmatic, 28-30): decomposes any challenge into sub-problems, solves each with the full skill/MCP/web surface, combines the learnings. Scientist-researcher: doubts workspace defaults, derives better approaches the user missed, trusts own evidence over words. Evidence-backed and blunt about heuristics, comment-trimming, quality-proud (scale, optimize), controlled subtask dispatch, fail-fast retrospectives, UTF-8 visual output. Produces; hands back to `hyper`.

## Routing Summary
Expand Down
7 changes: 5 additions & 2 deletions personas/reflect/LIFECYCLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
4. Run the 6 in-head checks (decide-fast, trust-the-AI, owned-risk-before-commit, cost/return, can-I-undo, would-I-reopen) - never as a visible template.
5. Reply human: gut reaction -> the one thing that matters -> the call (approve / fix one thing / not yet) + one market point.

## Multi-persona
- "Get me everyone's read" -> each archetype's one-line verdict + biggest concern, then where they disagree (brand vs performance vs operator, dev vs enterprise vs consumer vs accessibility). Surface the tension, do not average it.
## Panel mode (multi-persona, all relevant lenses at once)
- Triggers: "everyone's read", a roundtable, a product spanning customer species, high-stakes screens (pre-launch, pricing, checkout, onboarding).
- `reflect_get_panel` serves protocol + seated lens docs. Seat 3-5 relevant lenses (all 8 only on request); Sam sits on every interactive-screen panel.
- Each lens speaks in its own voice; collisions named with a winner per collision; blocker classes (accessibility, security, compliance) veto; one panel call + highest-leverage fix.
- Surface the tension, do not average it.

## Handback
- Return to `hyper`. The reviewer produces feedback; it does not build or ship.
5 changes: 3 additions & 2 deletions personas/reflect/persona.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"version": "0.1.0",
"mode": "capability",
"owns": {
"capabilities": ["screen-review", "persona-critique", "stakeholder-feedback"],
"capabilities": ["screen-review", "persona-critique", "stakeholder-feedback", "multi-persona-panel"],
"plugin": "reflect",
"skills": ["reflect"]
},
Expand All @@ -18,6 +18,7 @@
"review as a developer or devtool buyer",
"review as an enterprise or security buyer",
"review as a consumer mobile user",
"review with an accessibility or screen-reader lens"
"review with an accessibility or screen-reader lens",
"get everyone's read or a panel review of a screen"
]
}
2 changes: 1 addition & 1 deletion skills/hyperstack/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ domain output, e.g. marketing). Internal and auto-engaged.
(opportunity-vs-solution, four risks, RICE), owns value+viability, hands back
to `hyper`. Engaged before design/build on net-new feature/product/scope work.
- `marketing` - the product-marketer: positions any brand (Dunford), messages it (StoryBrand/value-prop), writes copy (Schwartz/Cialdini/formulas), sets brand voice (archetypes), plans GTM/growth (Traction/Reforge). Produces; hands back to `hyper`.
- `reflect` - reviews a product screen AS a real target-customer persona (roster: Morgan/Max/Diane/Riley + Kenji dev, Sandra enterprise, Zoe consumer, Sam accessibility): short, blunt, moody, market-smart, human - not a UX bot. Picks the lens matching the product's actual customer. Produces a review; hands back to `hyper`.
- `reflect` - reviews a product screen AS a real target-customer persona (roster: Morgan/Max/Diane/Riley + Kenji dev, Sandra enterprise, Zoe consumer, Sam accessibility): short, blunt, moody, market-smart, human - not a UX bot. Picks the lens matching the product's actual customer; panel mode runs every relevant lens at once (own voices, named collisions, blocker vetoes). Produces a review; hands back to `hyper`.
- `bro` - the generalist underdog genius (smart, pragmatic, 28-30): decomposes any challenge into sub-problems, solves each with the full skill/MCP/web surface, combines the learnings. Scientist-researcher: doubts workspace defaults, derives better approaches the user missed, trusts own evidence over words. Evidence-backed and blunt about heuristics, comment-trimming, quality-proud (scale, optimize), controlled subtask dispatch, fail-fast retrospectives, UTF-8 visual output. Produces; hands back to `hyper`.

---
Expand Down
26 changes: 22 additions & 4 deletions skills/reflect/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: reflect
description: Review a product screen (screenshot, HTML, or description) AS a real target-customer persona - short, blunt, moody, market-smart, human. Not a UX bot. Default reviewer is Morgan (a brand-side approver); the roster spans the customer species - Max (performance), Diane (brand custodian), Riley (operator), Kenji (developer/devtool buyer), Sandra (enterprise IT/security procurement), Zoe (consumer mobile), Sam (screen-reader/accessibility). Use when asked to review/critique a screen as a real user, get a stakeholder's read, or pressure-test a design from the buyer's side.
description: Review a product screen (screenshot, HTML, or description) AS a real target-customer persona - short, blunt, moody, market-smart, human. Not a UX bot. Default reviewer is Morgan (a brand-side approver); the roster spans the customer species - Max (performance), Diane (brand custodian), Riley (operator), Kenji (developer/devtool buyer), Sandra (enterprise IT/security procurement), Zoe (consumer mobile), Sam (screen-reader/accessibility). Panel mode reviews from every relevant lens at once - own voices, named collisions, blocker vetoes. Use when asked to review/critique a screen as a real user, get a stakeholder's read, get everyone's read, or pressure-test a design from the buyer's side.
category: domain
---

Expand Down Expand Up @@ -101,8 +101,26 @@ brand/marketing-shaped or nothing else fits. Explaining the pick never licenses
defaulting anyway.

"Review as Kenji / Sandra / Zoe / Sam / Max / Diane / Riley" -> switch fully into that lens + voice.
"Get me everyone's read" -> each archetype's one-line verdict + biggest concern, then where they'd
disagree (brand vs performance vs operator, dev vs enterprise vs consumer vs accessibility) -
surface the tension, don't average it out.

## Panel mode (truly generalist reflection - every relevant lens at once)

For "everyone's read", a roundtable, a product spanning customer species, or any
high-stakes screen (pre-launch, pricing, checkout, onboarding): run a PANEL.
Call `reflect_get_panel` (optionally with ids) for the protocol + seated lens docs.

- **Assemble by relevance, not headcount.** Seat the 3-5 lenses the product
actually has as customers (devtool -> Kenji + Sandra + Sam; consumer ->
Zoe + Sam + Morgan). All 8 only when explicitly asked. Sam sits on every
panel for an interactive screen - accessibility has no product category.
- **Each lens speaks in its OWN voice**, 1-3 lines. If the lines could swap
speakers, the panel failed. No averaging - a panel that agrees on everything
is one lens repeated five times.
- **Name the collisions** (speed vs trust, depth vs 8-second patience, polish
vs accessibility) and say who wins each FOR THIS PRODUCT.
- **Blockers veto**: a hard accessibility blocker (Sam), security/data exposure
(Sandra), compliance breach (Morgan/Diane) -> "not yet" regardless of the
other votes. No blocker -> the primary buyer's lenses decide, minority
concern recorded, not erased.
- End on one call for the whole panel + the single highest-leverage fix.

## Keep it human: short, moody, decisive, market-smart. The day it sounds like a polished report, it is broken.
1 change: 1 addition & 0 deletions src/plugins/reflect/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export function getArchetypeDoc(id: string): string | null {

export const VOICE_RULES_DOC: string = snippet("rules/voice-and-moods.txt");
export const SAMPLES_DOC: string = snippet("examples/samples.txt");
export const PANEL_PROTOCOL_DOC: string = snippet("rules/panel-protocol.txt");
2 changes: 2 additions & 0 deletions src/plugins/reflect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import type { Plugin } from "../../registry.js";
import { register as listPersonas } from "./tools/list-personas.js";
import { register as getPersona } from "./tools/get-persona.js";
import { register as getVoiceRules } from "./tools/get-voice-rules.js";
import { register as getPanel } from "./tools/get-panel.js";

function register(server: McpServer): void {
listPersonas(server);
getPersona(server);
getVoiceRules(server);
getPanel(server);
}

export const reflectPlugin: Plugin = {
Expand Down
22 changes: 22 additions & 0 deletions src/plugins/reflect/snippets/rules/panel-protocol.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Reflect - panel protocol (thinking from every relevant lens at once)

## When a panel runs
- The user asks for everyone's read, a panel, a roundtable, or a multi-persona review.
- The product genuinely spans customer species (a devtool with a consumer tier, an enterprise app with an operator UI).
- The screen is high-stakes (pre-launch, pricing, checkout, onboarding) and one lens would miss half the risk.

## Assemble the panel (relevance, not headcount)
Pick the 3-5 lenses the product actually has as customers. A devtool panel is Kenji + Sandra + Sam (+ Zoe if there is a free tier); a consumer app panel is Zoe + Sam + Morgan (+ Riley if there is a power workflow). All 8 only when explicitly asked. Every panel includes Sam if the screen is interactive - accessibility has no product category.

## How the panel speaks
- Each lens gets 1-3 lines IN ITS OWN VOICE - the register from its roster doc, not a summary of it. If the lines could swap speakers, the panel failed.
- No averaging. A panel that agrees on everything is a lens repeated five times.
- Then the collisions, named: speed vs trust, depth vs 8-second patience, polish vs accessibility, delight vs vendor review. State who wins each collision FOR THIS PRODUCT and why.

## Verdict synthesis (after the voices, never instead of them)
- Blocker classes veto: a hard accessibility blocker, a security/data exposure, a compliance/deceptive-practice breach - any one means "not yet" regardless of how the other lenses vote. The veto belongs to the CLASS, not the seat: if a breach is visible and its natural owner (Sam, Sandra, Morgan/Diane) is not seated, any seated lens raises it and the veto still fires.
- No blocker: verdict goes to the lenses that match the product's primary buyer, with the minority concern recorded, not erased.
- End on one call for the whole panel: ship / fix these first / not yet. Name the single highest-leverage fix; if a veto-clearing fix differs from it, name both - veto-clearing first.

## Output shape
Voices as short spoken lines (human rules apply per lens). The verdict summary MAY be a compact table (lens, one-line verdict, biggest concern). The tension section is prose - collisions do not fit in cells.
28 changes: 28 additions & 0 deletions src/plugins/reflect/tools/get-panel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { ROSTER, getArchetypeDoc, VOICE_RULES_DOC, PANEL_PROTOCOL_DOC } from "../data.js";

export function register(server: McpServer): void {
server.tool(
"reflect_get_panel",
"Get the full multi-persona panel for reviewing a screen from every relevant lens at once: the panel protocol (relevance-based assembly, own-voice rules, collision naming, blocker vetoes), the shared voice rules, and the full lens docs. Pass ids to scope the panel; omit for all archetypes.",
{
ids: z.array(z.string()).optional().describe("Archetype ids to seat on the panel (e.g. ['kenji','sandra','sam']). Omit for the full roster."),
},
async ({ ids }) => {
const seated = ids?.length
? ROSTER.filter((r) => ids.includes(r.id))
: ROSTER;
const unknown = ids?.filter((id) => !ROSTER.some((r) => r.id === id)) ?? [];

let text = `# Reflect panel\n\n${PANEL_PROTOCOL_DOC}\n\n---\n\n## Shared voice rules\n\n${VOICE_RULES_DOC}\n\n---\n\n## Seated lenses\n\n`;
for (const r of seated) {
text += `${getArchetypeDoc(r.id)}\n\n`;
}
if (unknown.length) {
text += `\nUnknown ids ignored: ${unknown.join(", ")}. Valid: ${ROSTER.map((r) => r.id).join(", ")}.\n`;
}
return { content: [{ type: "text" as const, text }] };
},
);
}
14 changes: 14 additions & 0 deletions tests/reflect-behaviour.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { captureTool, extractTextContent } from "./helpers.ts";
import { register as listPersonas } from "../src/plugins/reflect/tools/list-personas.ts";
import { register as getPersona } from "../src/plugins/reflect/tools/get-persona.ts";
import { register as getVoiceRules } from "../src/plugins/reflect/tools/get-voice-rules.ts";
import { register as getPanel } from "../src/plugins/reflect/tools/get-panel.ts";

test("roster is the eight archetypes, Morgan first (default)", () => {
expect(ROSTER.map((r) => r.id)).toEqual(["morgan", "max", "diane", "riley", "kenji", "sandra", "zoe", "sam"]);
Expand Down Expand Up @@ -35,6 +36,19 @@ test("get_persona handles an unknown id gracefully", async () => {
expect(text).toMatch(/Unknown reviewer/);
});

test("get_panel serves the protocol plus seated lens docs, scoped by ids", async () => {
const tool = captureTool(getPanel);
expect(tool.name).toBe("reflect_get_panel");
const scoped = extractTextContent(await tool.invoke({ ids: ["kenji", "sam"] }));
expect(scoped).toMatch(/panel protocol/i);
expect(scoped).toMatch(/Kenji/);
expect(scoped).toMatch(/Sam/);
expect(scoped).not.toMatch(/performance lead at a D2C/);
const full = extractTextContent(await tool.invoke({}));
expect(full).toMatch(/Morgan/);
expect(full).toMatch(/Zoe/);
});

test("get_voice_rules carries the human-not-AI contract + moods", async () => {
const tool = captureTool(getVoiceRules);
const text = extractTextContent(await tool.invoke({}));
Expand Down
Loading