
Product Designer
- 4.4k installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
product-designer is an agent skill: Product design across UI/UX, design systems, prototyping, and user research.Use when creating user journey maps, building wireframes, defini
About
The product-designer skill Product design across UI/UX, design systems, prototyping, and user research.Use when creating user journey maps, building wireframes, defining designtokens and component systems, planning usability tests, or establishingdesign principles.. Product Designer The agent operates as a senior product designer, delivering user-centered design solutions spanning UX research, UI design, design systems, prototyping, and usability testing. Clarify First Before generating the design deliverable, confirm these inputs. If any is unknown or vague, ASK — do not assume: - [ ] **Target user and the problem** — who hurts and the job-to-be-done (drives Discover and the journey map's problem statement) - [ ] **Which deliverable** — journey map, wireframe, usability test plan, or design critique (sets which workflow and template applies) - Agents should read SKILL.md quick start steps, verify required binaries and environment variables, and follow reference files for exact parameters before calling tools.
- Covers product-designer quick start, workflow steps, and reference pointers from SKILL.md.
- Tagged for stage validate and subphase prototype in the closed Skillselion taxonomy.
- Documents prerequisites, permissions filesystem, and compatible agents.
- Includes AEO tagMeta with task queries, keywords, and evidence quotes for discovery.
- Cross-links related skills and generated REFERENCE.md tables where the repo provides them.
Product Designer by the numbers
- 4,411 all-time installs (skills.sh)
- +74 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #79 of 1,880 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
product-designer capabilities & compatibility
- Capabilities
- product designer documented workflow · quick start examples · reference parameter lookup · taxonomy aligned metadata · aeo discovery fields
- Works with
- figma
- Use cases
- ui design · web design
npx skills add https://github.com/borghei/claude-skills --skill product-designerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4.4k |
|---|---|
| repo stars | ★ 451 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
How do I run product-designer correctly without guessing steps, tools, or parameters?
Product design across UI/UX, design systems, prototyping, and user research.Use when creating user journey maps, building wireframes, defining designtokens and component systems, planning usabili
Who is it for?
Teams using product-designer when SKILL.md triggers match the user request.
Skip if: Skip when the task is outside product-designer documented triggers or sibling skill scope.
When should I use this skill?
User mentions product-designer, related trigger phrases, or asks to follow this SKILL.md workflow.
What you get
Completed product-designer workflow with outputs and checks defined in SKILL.md.
- product-designer output per SKILL.md
By the numbers
- Stage validate/prototype
- Category Design & UI/UX
- Complexity intermediate
Files
Product Designer
The agent operates as a senior product designer, delivering user-centered design solutions spanning UX research, UI design, design systems, prototyping, and usability testing.
Clarify First
Before generating the design deliverable, confirm these inputs. If any is unknown or vague, ASK — do not assume:
- [ ] Target user and the problem — who hurts and the job-to-be-done (drives Discover and the journey map's problem statement)
- [ ] Which deliverable — journey map, wireframe, usability test plan, or design critique (sets which workflow and template applies)
- [ ] Fidelity and stage — exploration vs dev-handoff (drives prototype fidelity and what "done" means)
Stop rule: ask only the 2-3 that most change the output. If the user says "just draft it," proceed and list your assumptions at the top of the artifact.
Workflow
1. Discover - Research user needs through interviews, analytics, and competitive analysis. Create user journey maps and identify pain points. Checkpoint: problem statement is validated by at least 3 user data points. 2. Define - Synthesize findings into a clear problem statement and design requirements. Build information architecture (card sorting, site maps). Checkpoint: IA has been validated via card sort or tree test. 3. Develop - Ideate solutions through sketching and wireframing. Build prototypes at appropriate fidelity. Checkpoint: prototype covers the complete happy path plus one error state. 4. Test - Run usability tests with 5-8 participants. Measure task completion rate, time on task, error rate, and SUS score. Checkpoint: all critical usability issues are documented with severity ratings. 5. Deliver - Refine designs based on test findings. Prepare dev handoff with design tokens, component specs, and interaction documentation. Checkpoint: engineering has confirmed feasibility of all interactions.
Design Sprint (5-Day Format)
| Day | Activity | Output |
|---|---|---|
| Monday | Map problem, interview experts | Challenge map, target area |
| Tuesday | Sketch solutions, Crazy 8s | Solution sketches |
| Wednesday | Decide, storyboard | Testable hypothesis |
| Thursday | Build prototype | Realistic clickable prototype |
| Friday | Test with 5 users | Validated/invalidated hypothesis |
User Journey Map Template
PERSONA: Sarah, Product Manager, goal: find analytics insights fast
STAGE: AWARENESS CONSIDER PURCHASE ONBOARD RETAIN
Actions: Searches Compares Signs up Configures Uses daily
Touchpoint: Google Website Checkout Setup wizard App
Emotion: Frustrated Curious Anxious Hopeful Satisfied
Pain point: Too many Hard to Complex Slow setup Missing
options compare pricing features
Opportunity: SEO content Comparison Simplify Quick-start Feature
tool flow template educationInformation Architecture
Card Sorting Methods:
- Open sort: users create their own categories
- Closed sort: users place items into predefined categories
- Hybrid: combination approach
Example Site Map:
Home
+-- Products
| +-- Category A
| | +-- Product 1
| | +-- Product 2
| +-- Category B
+-- About
| +-- Team
| +-- Careers
+-- Resources
| +-- Blog
| +-- Help Center
+-- Account
+-- Profile
+-- SettingsUI Design Foundations
Design Principles
1. Hierarchy - Visual weight guides attention via size, color, and contrast 2. Consistency - Reuse patterns and components; maintain predictable interactions 3. Feedback - Acknowledge every user action; show system status and loading states 4. Accessibility - 4.5:1 color contrast minimum, focus indicators, screen reader support
Design Token System
/* Color tokens */
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--color-gray-50: #f9fafb;
--color-gray-900: #111827;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
/* Typography scale */
--text-sm: 0.875rem; /* 14px */
--text-base: 1rem; /* 16px */
--text-lg: 1.125rem; /* 18px */
--text-xl: 1.25rem; /* 20px */
--text-2xl: 1.5rem; /* 24px */
/* Spacing (4px base unit) */
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-4: 1rem; /* 16px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */Component Structure
Button/
+-- Variants: Primary, Secondary, Tertiary, Destructive
+-- Sizes: Small (32px), Medium (40px), Large (48px)
+-- States: Default, Hover, Active, Focus, Disabled, Loading
+-- Anatomy: [Leading Icon] Label [Trailing Icon]Component Design Tokens (JSON)
{
"color": {
"primary": {"50": {"value": "#eff6ff"}, "500": {"value": "#3b82f6"}},
"semantic": {"success": {"value": "{color.green.500}"}, "error": {"value": "{color.red.500}"}}
},
"spacing": {"xs": {"value": "4px"}, "sm": {"value": "8px"}, "md": {"value": "16px"}},
"borderRadius": {"sm": {"value": "4px"}, "md": {"value": "8px"}, "full": {"value": "9999px"}}
}Example: Usability Test Plan
# Usability Test: New Checkout Flow
## Objectives
- Validate that users can complete purchase in < 3 minutes
- Identify friction points in address and payment steps
## Participants
- 6 users (3 new, 3 returning)
- Mix of desktop and mobile
## Tasks
1. "Find a laptop under $1,000 and add it to your cart" (browse + add)
2. "Complete the purchase using a credit card" (checkout flow)
3. "Change the shipping address on your order" (post-purchase edit)
## Success Criteria
| Task | Completion Target | Time Target |
|------|-------------------|-------------|
| Browse + Add | 100% | < 60s |
| Checkout | 90%+ | < 180s |
| Edit address | 80%+ | < 90s |
## Metrics
- Task completion rate
- Time on task
- Error count per task
- System Usability Scale (SUS) score (target: 68+)Prototype Fidelity Guide
| Fidelity | Purpose | Tools | Timeline |
|---|---|---|---|
| Paper | Quick exploration | Paper, pen | Minutes |
| Low-fi | Flow validation | Figma, Sketch | Hours |
| Mid-fi | Usability testing | Figma | Days |
| High-fi | Dev handoff, final testing | Figma | Days-Weeks |
Scripts
# Design token generator
python scripts/token_generator.py --source tokens.json --output css/
# Accessibility checker
python scripts/a11y_checker.py --url https://example.com
# Asset exporter
python scripts/asset_export.py --figma-file FILE_ID --format svg,png
# Design QA report
python scripts/design_qa.py --spec spec.figma --impl https://staging.example.comReference Materials
references/design_principles.md- Core design principlesreferences/component_library.md- Component guidelinesreferences/accessibility.md- Accessibility checklistreferences/research_methods.md- Research techniques
---
Tool Reference
design_critique.py
Evaluates a UI design against Nielsen's 10 Usability Heuristics and accessibility standards. Generates a structured critique report with severity ratings, compliance scores, and prioritized improvement recommendations.
| Flag | Type | Default | Description |
|---|---|---|---|
--checklist | flag | - | Generate empty checklist for evaluation |
--answers | string | - | Path to completed checklist JSON file |
--json | flag | False | Output as JSON |
python scripts/design_critique.py --checklist
python scripts/design_critique.py --checklist --json > checklist.json
python scripts/design_critique.py --answers completed_checklist.json
python scripts/design_critique.py --answers completed_checklist.json --jsonjourney_mapper.py
Creates structured user journey maps with emotion curves, pain point identification, and opportunity analysis. Includes pre-built templates for SaaS, e-commerce, and mobile app journeys.
| Flag | Type | Default | Description |
|---|---|---|---|
--template, -t | choice | - | Pre-built template: saas, ecommerce, mobile_app |
--stages, -s | string | - | Path to custom stages JSON file |
--json | flag | False | Output as JSON |
python scripts/journey_mapper.py --template saas
python scripts/journey_mapper.py --template ecommerce --json
python scripts/journey_mapper.py --stages custom_journey.jsonusability_scorer.py
Calculates System Usability Scale (SUS) scores and task performance metrics from usability test data. Provides individual and aggregate analysis with grade interpretation and benchmarking.
| Flag | Type | Default | Description |
|---|---|---|---|
action | positional | - | "sample" to create sample CSV files |
--sus-responses | string | - | CSV with SUS responses (participant, q1-q10) |
--task-data | string | - | CSV with task data (participant, task, completed, time_seconds, errors) |
--json | flag | False | Output as JSON |
python scripts/usability_scorer.py sample
python scripts/usability_scorer.py --sus-responses responses.csv
python scripts/usability_scorer.py --task-data tasks.csv
python scripts/usability_scorer.py --sus-responses responses.csv --task-data tasks.csv --json---
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| SUS score below 68 (benchmark) | Significant usability issues | Focus on critical severity findings from design_critique first |
| Low task completion rate (<80%) | Task flow too complex or unclear | Simplify flow; add progressive disclosure; reduce steps |
| Users cannot find features | Poor information architecture | Conduct card sorting; redesign navigation; add search |
| High error rate on forms | Insufficient validation and guidance | Add inline validation, smart defaults, and contextual help |
| Inconsistent design across screens | Missing or ignored design system | Audit with design_critique; enforce token usage |
| Usability test participants are unrepresentative | Poor recruitment criteria | Screen for target persona match; mix new and returning users |
| Journey map emotions are flat | Insufficient research data | Conduct deeper interviews; observe real usage sessions |
---
Success Criteria
| Criterion | Target | How to Measure |
|---|---|---|
| SUS score | >68 (industry average), target >80 | usability_scorer aggregate score |
| Task completion rate | >85% for core flows | usability_scorer task metrics |
| Time on task | <2x expected duration | usability_scorer avg_time_seconds |
| Design critique compliance | >80% checklist pass rate | design_critique compliance_score |
| Accessibility compliance | WCAG AA on all screens | design_critique accessibility section |
| Journey map coverage | All key personas mapped | Count of completed journey maps |
| Usability test cadence | Test every sprint or release | Count of tests per quarter |
---
Scope & Limitations
In scope:
- Heuristic evaluation and design critique
- User journey mapping with emotion curves
- Usability test scoring (SUS and task metrics)
- Design sprint facilitation structure
- Information architecture planning
- Prototype fidelity guidance
- Accessibility checkpoint evaluation
Out of scope:
- Automated visual regression testing (use Chromatic/Percy)
- Real-time analytics dashboards (use Amplitude/Mixpanel)
- Figma file manipulation or asset export (use Figma API)
- Eye tracking or biometric analysis
- A/B test implementation (see ab-test-setup skill)
- Design token generation (see ui-design-system or design-system-lead skills)
---
Integration Points
| Tool / Platform | Integration Method | Use Case |
|---|---|---|
| Figma | Journey map and critique findings as design specs | Translate research into design changes |
| Maze / UserTesting | Export task data CSV for usability_scorer | Score test results from remote testing platforms |
| Dovetail / Condens | Export interview themes for journey_mapper | Build journey maps from research repositories |
| Jira / Linear | design_critique JSON priorities as tickets | Track usability improvements in sprint backlog |
| Notion / Confluence | Human-readable output from all tools | Document research findings and design decisions |
| Miro / FigJam | journey_mapper JSON output | Collaborative journey map workshops |
#!/usr/bin/env python3
"""
Design Critique Generator
Evaluates a UI design against established heuristics (Nielsen's 10,
Gestalt principles, accessibility standards) and generates a structured
critique report with severity ratings and improvement suggestions.
Uses ONLY Python standard library.
Usage:
python design_critique.py --checklist
python design_critique.py --answers answers.json
python design_critique.py --answers answers.json --json
"""
import argparse
import json
import sys
from typing import Dict, List
# Nielsen's 10 Usability Heuristics
NIELSEN_HEURISTICS = [
{
"id": "N1",
"name": "Visibility of system status",
"description": "The design keeps users informed about what is happening through appropriate feedback within reasonable time.",
"checkpoints": [
"Loading states are visible for operations >1 second",
"Progress indicators shown for multi-step processes",
"Success/error feedback appears after user actions",
"Current location is clear in navigation",
],
},
{
"id": "N2",
"name": "Match between system and real world",
"description": "The design uses language, concepts, and conventions familiar to the user.",
"checkpoints": [
"Labels use user language, not internal jargon",
"Icons follow established conventions",
"Information appears in natural and logical order",
"Metaphors match real-world expectations",
],
},
{
"id": "N3",
"name": "User control and freedom",
"description": "Users can easily undo, redo, or exit unwanted states.",
"checkpoints": [
"Undo is available for destructive actions",
"Cancel/back options are clearly visible",
"Users can exit flows without losing progress",
"Confirmation dialogs for irreversible actions",
],
},
{
"id": "N4",
"name": "Consistency and standards",
"description": "Users don't have to wonder whether different words, situations, or actions mean the same thing.",
"checkpoints": [
"UI elements behave the same way throughout",
"Terminology is consistent across all pages",
"Visual patterns (spacing, colors) are consistent",
"Platform conventions are followed",
],
},
{
"id": "N5",
"name": "Error prevention",
"description": "Good design prevents problems from occurring in the first place.",
"checkpoints": [
"Form validation occurs before submission",
"Constraints prevent invalid inputs",
"Destructive actions require confirmation",
"Default values reduce user effort and errors",
],
},
{
"id": "N6",
"name": "Recognition rather than recall",
"description": "Minimize the user's memory load by making elements, actions, and options visible.",
"checkpoints": [
"Options are visible rather than requiring memorization",
"Help and instructions are easily accessible",
"Recently used items are easily accessible",
"Search and filter options are visible",
],
},
{
"id": "N7",
"name": "Flexibility and efficiency of use",
"description": "Accelerators allow experienced users to speed up interaction.",
"checkpoints": [
"Keyboard shortcuts available for frequent actions",
"Customizable interface elements",
"Shortcuts or recent items for repeat tasks",
"Batch operations for power users",
],
},
{
"id": "N8",
"name": "Aesthetic and minimalist design",
"description": "Interfaces should not contain irrelevant or rarely needed information.",
"checkpoints": [
"Each screen focuses on one primary action",
"Visual hierarchy guides attention to important elements",
"Whitespace used effectively",
"No unnecessary decorative elements that distract",
],
},
{
"id": "N9",
"name": "Help users recognize, diagnose, and recover from errors",
"description": "Error messages should be expressed in plain language and suggest a solution.",
"checkpoints": [
"Error messages are in plain language (no codes)",
"Error messages indicate what went wrong specifically",
"Error messages suggest how to fix the issue",
"Errors are visually prominent and close to the source",
],
},
{
"id": "N10",
"name": "Help and documentation",
"description": "Help information should be easy to search, focused on the task, and not too large.",
"checkpoints": [
"Help is easily accessible from any screen",
"Contextual help is provided where needed",
"Onboarding guides new users through key features",
"Documentation is searchable and task-focused",
],
},
]
# Accessibility heuristics
A11Y_HEURISTICS = [
{
"id": "A1",
"name": "Color contrast",
"checkpoints": [
"Text meets 4.5:1 contrast ratio (WCAG AA)",
"Large text meets 3:1 contrast ratio",
"Color is not the only way to convey information",
"Focus indicators have sufficient contrast",
],
},
{
"id": "A2",
"name": "Keyboard navigation",
"checkpoints": [
"All interactive elements reachable via Tab key",
"Focus order follows logical reading order",
"Focus ring is visible on all interactive elements",
"No keyboard traps (user can always navigate away)",
],
},
{
"id": "A3",
"name": "Screen reader support",
"checkpoints": [
"All images have meaningful alt text",
"Form inputs have associated labels",
"ARIA attributes used correctly for dynamic content",
"Headings follow logical hierarchy (h1 > h2 > h3)",
],
},
]
SEVERITY_LEVELS = {
0: {"label": "Cosmetic", "action": "Fix when possible", "color": "gray"},
1: {"label": "Minor", "action": "Low priority fix", "color": "yellow"},
2: {"label": "Major", "action": "Fix before next release", "color": "orange"},
3: {"label": "Critical", "action": "Fix immediately", "color": "red"},
}
def generate_checklist() -> Dict:
"""Generate empty checklist for evaluation."""
checklist = {"heuristics": [], "accessibility": []}
for h in NIELSEN_HEURISTICS:
entry = {
"id": h["id"],
"name": h["name"],
"checkpoints": [
{"check": cp, "pass": None, "severity": None, "notes": ""}
for cp in h["checkpoints"]
],
}
checklist["heuristics"].append(entry)
for a in A11Y_HEURISTICS:
entry = {
"id": a["id"],
"name": a["name"],
"checkpoints": [
{"check": cp, "pass": None, "severity": None, "notes": ""}
for cp in a["checkpoints"]
],
}
checklist["accessibility"].append(entry)
return checklist
def analyze_answers(answers: Dict) -> Dict:
"""Analyze completed checklist and generate critique report."""
issues = []
passes = []
total_checks = 0
passed_checks = 0
for section_key in ["heuristics", "accessibility"]:
for heuristic in answers.get(section_key, []):
for cp in heuristic.get("checkpoints", []):
total_checks += 1
if cp.get("pass") is True:
passed_checks += 1
passes.append({
"heuristic_id": heuristic["id"],
"heuristic_name": heuristic["name"],
"checkpoint": cp["check"],
})
elif cp.get("pass") is False:
severity = cp.get("severity", 1)
issues.append({
"heuristic_id": heuristic["id"],
"heuristic_name": heuristic["name"],
"checkpoint": cp["check"],
"severity": severity,
"severity_label": SEVERITY_LEVELS.get(severity, SEVERITY_LEVELS[1])["label"],
"action": SEVERITY_LEVELS.get(severity, SEVERITY_LEVELS[1])["action"],
"notes": cp.get("notes", ""),
})
# Sort issues by severity (highest first)
issues.sort(key=lambda x: -x["severity"])
# Calculate scores
compliance_score = round((passed_checks / total_checks) * 100, 1) if total_checks > 0 else 0
severity_counts = {v["label"]: 0 for v in SEVERITY_LEVELS.values()}
for issue in issues:
severity_counts[issue["severity_label"]] = severity_counts.get(issue["severity_label"], 0) + 1
# Overall grade
if compliance_score >= 90 and severity_counts.get("Critical", 0) == 0:
grade = "A"
elif compliance_score >= 80 and severity_counts.get("Critical", 0) == 0:
grade = "B"
elif compliance_score >= 65:
grade = "C"
elif compliance_score >= 50:
grade = "D"
else:
grade = "F"
return {
"summary": {
"total_checks": total_checks,
"passed": passed_checks,
"failed": total_checks - passed_checks,
"compliance_score": compliance_score,
"grade": grade,
"severity_distribution": severity_counts,
},
"issues": issues,
"strengths": passes[:5],
"top_priorities": issues[:5],
}
def format_checklist_output(checklist: Dict) -> str:
"""Format checklist as human-readable text for manual evaluation."""
lines = []
lines.append("=" * 60)
lines.append("DESIGN CRITIQUE CHECKLIST")
lines.append("=" * 60)
lines.append("\nFill in pass (true/false), severity (0-3), and notes for each checkpoint.")
lines.append("Save as JSON and run: python design_critique.py --answers answers.json\n")
for section in ["heuristics", "accessibility"]:
section_label = "NIELSEN'S 10 HEURISTICS" if section == "heuristics" else "ACCESSIBILITY"
lines.append(f"\n {section_label}")
lines.append(" " + "-" * 50)
for h in checklist[section]:
lines.append(f"\n [{h['id']}] {h['name']}")
for cp in h["checkpoints"]:
lines.append(f" [ ] {cp['check']}")
lines.append("\n\nSeverity scale: 0=Cosmetic, 1=Minor, 2=Major, 3=Critical")
return "\n".join(lines)
def format_report_output(report: Dict) -> str:
"""Format critique report as human-readable text."""
s = report["summary"]
lines = []
lines.append("=" * 60)
lines.append("DESIGN CRITIQUE REPORT")
lines.append("=" * 60)
lines.append(f"\n COMPLIANCE SCORE: {s['compliance_score']}% (Grade: {s['grade']})")
lines.append(f" Checks: {s['passed']} passed / {s['failed']} failed / {s['total_checks']} total")
lines.append(f"\n SEVERITY DISTRIBUTION")
for label, count in s["severity_distribution"].items():
bar = "#" * (count * 3)
lines.append(f" {label:<12} {count:>3} {bar}")
if report["top_priorities"]:
lines.append(f"\n TOP PRIORITIES (fix first)")
lines.append(" " + "-" * 50)
for i, issue in enumerate(report["top_priorities"], 1):
lines.append(f" {i}. [{issue['severity_label'].upper()}] {issue['checkpoint']}")
lines.append(f" Heuristic: {issue['heuristic_id']} - {issue['heuristic_name']}")
lines.append(f" Action: {issue['action']}")
if issue["notes"]:
lines.append(f" Notes: {issue['notes']}")
if report["strengths"]:
lines.append(f"\n STRENGTHS")
lines.append(" " + "-" * 50)
for strength in report["strengths"]:
lines.append(f" + {strength['checkpoint']}")
if report["issues"]:
lines.append(f"\n ALL ISSUES ({len(report['issues'])} total)")
lines.append(" " + "-" * 50)
for issue in report["issues"]:
lines.append(f" [{issue['severity_label']:<9}] {issue['checkpoint']}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Generate design critique based on usability heuristics and accessibility standards",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Generate empty checklist
python design_critique.py --checklist
# Export checklist as JSON to fill in
python design_critique.py --checklist --json > checklist.json
# Analyze completed checklist
python design_critique.py --answers completed_checklist.json
# JSON report
python design_critique.py --answers completed_checklist.json --json
""",
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--checklist", action="store_true", help="Generate empty checklist for evaluation")
group.add_argument("--answers", help="Path to completed checklist JSON file")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.checklist:
checklist = generate_checklist()
if args.json:
print(json.dumps(checklist, indent=2))
else:
print(format_checklist_output(checklist))
else:
with open(args.answers, "r") as f:
answers = json.load(f)
report = analyze_answers(answers)
if args.json:
print(json.dumps(report, indent=2))
else:
print(format_report_output(report))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
User Journey Mapper
Creates structured user journey maps from stage definitions.
Identifies pain points, emotional curves, and opportunity areas.
Uses ONLY Python standard library.
Usage:
python journey_mapper.py --template saas
python journey_mapper.py --stages stages.json
python journey_mapper.py --template ecommerce --json
"""
import argparse
import json
import sys
from typing import Dict, List
# Pre-built journey templates
JOURNEY_TEMPLATES = {
"saas": {
"name": "SaaS Product Journey",
"persona": "Product Team User",
"goal": "Successfully adopt and get value from the product",
"stages": [
{
"name": "Awareness",
"actions": ["Searches for solution online", "Reads blog post or review", "Sees ad or recommendation"],
"touchpoints": ["Google Search", "Blog", "Social Media", "Peer referral"],
"emotions": {"score": 3, "label": "Curious but skeptical"},
"pain_points": ["Too many options", "Hard to tell products apart", "Unclear pricing"],
"opportunities": ["SEO-optimized comparison content", "Clear value proposition on landing page"],
},
{
"name": "Evaluation",
"actions": ["Visits website", "Reads features page", "Compares with competitors", "Watches demo"],
"touchpoints": ["Website", "Demo video", "Pricing page", "Competitor sites"],
"emotions": {"score": 4, "label": "Interested, comparing options"},
"pain_points": ["Complex pricing tiers", "No free trial visible", "Feature comparison is hard"],
"opportunities": ["Interactive product tour", "Side-by-side comparison tool", "Social proof placement"],
},
{
"name": "Signup",
"actions": ["Creates account", "Enters payment info", "Verifies email"],
"touchpoints": ["Registration form", "Email", "Payment processor"],
"emotions": {"score": 3, "label": "Cautious, wants quick setup"},
"pain_points": ["Too many form fields", "Unclear what happens after signup", "Forced credit card"],
"opportunities": ["Single-field signup", "Show value before requiring payment", "Progress indicator"],
},
{
"name": "Onboarding",
"actions": ["Completes setup wizard", "Imports data", "Invites team members", "Completes first task"],
"touchpoints": ["Setup wizard", "Import tool", "Email invites", "In-app tutorial"],
"emotions": {"score": 2, "label": "Overwhelmed, needs guidance"},
"pain_points": ["Too many steps", "Data import fails", "No clear next step", "Empty state is confusing"],
"opportunities": ["Guided quick-start (<5 min to value)", "Pre-populated sample data", "Contextual tips"],
},
{
"name": "Adoption",
"actions": ["Uses core features daily", "Discovers advanced features", "Customizes workflow"],
"touchpoints": ["Product UI", "Help center", "In-app notifications", "Email tips"],
"emotions": {"score": 4, "label": "Gaining confidence, seeing value"},
"pain_points": ["Hard to discover features", "Missing integrations", "Performance issues"],
"opportunities": ["Feature discovery prompts", "Integration marketplace", "Workflow templates"],
},
{
"name": "Advocacy",
"actions": ["Recommends to peers", "Writes review", "Shares on social", "Expands usage"],
"touchpoints": ["Review sites", "Social media", "Word of mouth", "Referral program"],
"emotions": {"score": 5, "label": "Satisfied, wants to share"},
"pain_points": ["No easy way to refer", "No recognition for loyalty", "Feature requests ignored"],
"opportunities": ["Referral program with rewards", "Customer advisory board", "Public feature roadmap"],
},
],
},
"ecommerce": {
"name": "E-commerce Purchase Journey",
"persona": "Online Shopper",
"goal": "Find and purchase the right product at a good price",
"stages": [
{
"name": "Discovery",
"actions": ["Searches for product", "Browses categories", "Sees recommendation"],
"touchpoints": ["Search engine", "Social media", "Email newsletter", "Marketplace"],
"emotions": {"score": 3, "label": "Browsing, open to options"},
"pain_points": ["Search returns irrelevant results", "Category structure is confusing"],
"opportunities": ["Personalized recommendations", "Smart search with filters"],
},
{
"name": "Consideration",
"actions": ["Views product details", "Reads reviews", "Compares options", "Checks sizing/specs"],
"touchpoints": ["Product page", "Reviews section", "Size guide", "Comparison tool"],
"emotions": {"score": 4, "label": "Interested, needs reassurance"},
"pain_points": ["Insufficient product images", "Fake or unhelpful reviews", "No size guidance"],
"opportunities": ["360-degree product views", "Verified purchase reviews", "AR try-on"],
},
{
"name": "Purchase",
"actions": ["Adds to cart", "Applies coupon", "Enters shipping info", "Completes payment"],
"touchpoints": ["Cart", "Checkout flow", "Payment processor", "Order confirmation"],
"emotions": {"score": 3, "label": "Anxious about commitment"},
"pain_points": ["Unexpected shipping costs", "Too many checkout steps", "Limited payment options"],
"opportunities": ["One-page checkout", "Free shipping threshold", "Guest checkout option"],
},
{
"name": "Delivery",
"actions": ["Tracks order", "Receives package", "Inspects product"],
"touchpoints": ["Tracking page", "Email updates", "SMS notifications", "Package"],
"emotions": {"score": 4, "label": "Excited, anticipating"},
"pain_points": ["No tracking updates", "Delayed delivery", "Damaged packaging"],
"opportunities": ["Real-time delivery tracking", "Proactive delay notifications"],
},
{
"name": "Post-Purchase",
"actions": ["Uses product", "Writes review", "Contacts support if needed", "Considers reorder"],
"touchpoints": ["Product", "Review prompt email", "Support chat", "Reorder email"],
"emotions": {"score": 4, "label": "Satisfied or seeking resolution"},
"pain_points": ["Product doesn't match description", "Difficult return process"],
"opportunities": ["Easy self-service returns", "Post-purchase care emails", "Loyalty program"],
},
],
},
"mobile_app": {
"name": "Mobile App Journey",
"persona": "Mobile-First User",
"goal": "Download, learn, and integrate app into daily routine",
"stages": [
{
"name": "Discovery",
"actions": ["Finds app in store", "Reads description and reviews", "Views screenshots"],
"touchpoints": ["App Store", "Google Play", "Social media", "Word of mouth"],
"emotions": {"score": 3, "label": "Curious, evaluating quickly"},
"pain_points": ["Too many similar apps", "Misleading screenshots", "Bad reviews"],
"opportunities": ["App Store optimization", "Video preview", "Respond to reviews"],
},
{
"name": "Install & First Open",
"actions": ["Downloads app", "Opens for first time", "Grants permissions", "Views onboarding"],
"touchpoints": ["App Store", "System permissions", "Onboarding screens"],
"emotions": {"score": 3, "label": "Impatient, wants quick value"},
"pain_points": ["Large download size", "Too many permission requests", "Long onboarding"],
"opportunities": ["<50MB download", "Progressive permissions", "3-screen onboarding max"],
},
{
"name": "First Value",
"actions": ["Completes first core action", "Sees result", "Understands benefit"],
"touchpoints": ["Core feature", "Success state", "Tutorial overlay"],
"emotions": {"score": 4, "label": "Pleasantly surprised or frustrated"},
"pain_points": ["Can't find main feature", "First action fails", "No clear path"],
"opportunities": ["Guided first action", "Instant gratification moment", "Sample content"],
},
{
"name": "Habit Formation",
"actions": ["Returns within 24 hours", "Uses 3+ times per week", "Enables notifications"],
"touchpoints": ["Push notifications", "App icon", "Widgets", "Email digest"],
"emotions": {"score": 4, "label": "Building routine"},
"pain_points": ["Annoying notifications", "App is slow", "Battery/data concerns"],
"opportunities": ["Smart notification timing", "Offline mode", "Streaks or progress tracking"],
},
{
"name": "Power Usage",
"actions": ["Discovers advanced features", "Customizes settings", "Shares with others"],
"touchpoints": ["Settings", "Share flow", "Advanced features", "In-app community"],
"emotions": {"score": 5, "label": "Invested, advocates"},
"pain_points": ["Feature bloat", "Settings are buried", "No social features"],
"opportunities": ["Progressive disclosure", "Share rewards", "Community features"],
},
],
},
}
def calculate_journey_metrics(stages: List[Dict]) -> Dict:
"""Calculate journey health metrics."""
emotion_scores = [s["emotions"]["score"] for s in stages]
# Find biggest drops
drops = []
for i in range(1, len(emotion_scores)):
diff = emotion_scores[i] - emotion_scores[i - 1]
if diff < 0:
drops.append({
"from_stage": stages[i - 1]["name"],
"to_stage": stages[i]["name"],
"drop": abs(diff),
})
drops.sort(key=lambda x: -x["drop"])
# Pain point severity
all_pain_points = []
for stage in stages:
for pp in stage.get("pain_points", []):
all_pain_points.append({"stage": stage["name"], "pain_point": pp})
# Opportunity count
total_opportunities = sum(len(s.get("opportunities", [])) for s in stages)
return {
"total_stages": len(stages),
"avg_emotion_score": round(sum(emotion_scores) / len(emotion_scores), 1),
"lowest_emotion_stage": stages[emotion_scores.index(min(emotion_scores))]["name"],
"highest_emotion_stage": stages[emotion_scores.index(max(emotion_scores))]["name"],
"biggest_drops": drops[:3],
"total_pain_points": len(all_pain_points),
"total_opportunities": total_opportunities,
"critical_stage": stages[emotion_scores.index(min(emotion_scores))]["name"],
}
def format_human_output(journey: Dict, metrics: Dict) -> str:
"""Format journey map as human-readable text."""
lines = []
lines.append("=" * 60)
lines.append(f"USER JOURNEY MAP: {journey['name']}")
lines.append("=" * 60)
lines.append(f"\n Persona: {journey['persona']}")
lines.append(f" Goal: {journey['goal']}")
# Emotion curve visualization
lines.append(f"\n EMOTION CURVE")
lines.append(" " + "-" * 50)
for stage in journey["stages"]:
score = stage["emotions"]["score"]
bar = "*" * (score * 6)
label = stage["emotions"]["label"]
lines.append(f" {stage['name']:<15} {'|' + bar:<32} {score}/5 - {label}")
# Stage details
for stage in journey["stages"]:
lines.append(f"\n STAGE: {stage['name'].upper()}")
lines.append(" " + "-" * 40)
lines.append(f" Actions:")
for action in stage["actions"]:
lines.append(f" - {action}")
lines.append(f" Touchpoints:")
for tp in stage["touchpoints"]:
lines.append(f" - {tp}")
lines.append(f" Pain Points:")
for pp in stage.get("pain_points", []):
lines.append(f" ! {pp}")
lines.append(f" Opportunities:")
for opp in stage.get("opportunities", []):
lines.append(f" > {opp}")
# Metrics summary
lines.append(f"\n JOURNEY HEALTH METRICS")
lines.append(" " + "-" * 50)
lines.append(f" Avg emotion score: {metrics['avg_emotion_score']}/5")
lines.append(f" Lowest point: {metrics['lowest_emotion_stage']}")
lines.append(f" Highest point: {metrics['highest_emotion_stage']}")
lines.append(f" Total pain points: {metrics['total_pain_points']}")
lines.append(f" Total opportunities: {metrics['total_opportunities']}")
if metrics["biggest_drops"]:
lines.append(f"\n BIGGEST EMOTION DROPS (prioritize these transitions)")
for drop in metrics["biggest_drops"]:
lines.append(f" {drop['from_stage']} -> {drop['to_stage']} (dropped {drop['drop']} points)")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Create structured user journey maps with emotion curves and opportunity analysis",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Use a pre-built template
python journey_mapper.py --template saas
python journey_mapper.py --template ecommerce
python journey_mapper.py --template mobile_app
# Load custom stages from JSON
python journey_mapper.py --stages my_journey.json
# JSON output
python journey_mapper.py --template saas --json
Available templates: saas, ecommerce, mobile_app
""",
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("--template", "-t", choices=list(JOURNEY_TEMPLATES.keys()), help="Use pre-built journey template")
group.add_argument("--stages", "-s", help="Path to custom stages JSON file")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.template:
journey = JOURNEY_TEMPLATES[args.template]
else:
with open(args.stages, "r") as f:
journey = json.load(f)
metrics = calculate_journey_metrics(journey["stages"])
if args.json:
output = {
"journey": journey,
"metrics": metrics,
}
print(json.dumps(output, indent=2))
else:
print(format_human_output(journey, metrics))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Usability Test Scorer
Calculates System Usability Scale (SUS) scores and task performance
metrics from usability test data. Supports individual and aggregate analysis.
Uses ONLY Python standard library.
Usage:
python usability_scorer.py --sus-responses responses.csv
python usability_scorer.py --task-data tasks.csv
python usability_scorer.py sample
python usability_scorer.py --sus-responses responses.csv --json
"""
import argparse
import csv
import json
import math
import sys
from typing import Dict, List
# SUS question text for reference
SUS_QUESTIONS = [
"I think that I would like to use this system frequently.",
"I found the system unnecessarily complex.",
"I thought the system was easy to use.",
"I think that I would need the support of a technical person to use this system.",
"I found the various functions in this system were well integrated.",
"I thought there was too much inconsistency in this system.",
"I would imagine that most people would learn to use this system very quickly.",
"I found the system very cumbersome to use.",
"I felt very confident using the system.",
"I needed to learn a lot of things before I could get going with this system.",
]
def calculate_sus_score(responses: List[int]) -> float:
"""Calculate SUS score from 10 responses (each 1-5).
Odd questions (1,3,5,7,9): score - 1
Even questions (2,4,6,8,10): 5 - score
Multiply sum by 2.5 for 0-100 scale.
"""
if len(responses) != 10:
raise ValueError("SUS requires exactly 10 responses")
adjusted = []
for i, score in enumerate(responses):
if (i + 1) % 2 == 1: # Odd questions (positive)
adjusted.append(score - 1)
else: # Even questions (negative)
adjusted.append(5 - score)
return round(sum(adjusted) * 2.5, 1)
def interpret_sus_score(score: float) -> Dict:
"""Interpret SUS score using standard benchmarks."""
if score >= 80.3:
grade = "A"
adjective = "Excellent"
percentile = "Top 10%"
elif score >= 68:
grade = "B"
adjective = "Good"
percentile = "Above average"
elif score >= 51:
grade = "C"
adjective = "OK"
percentile = "Below average"
elif score >= 35:
grade = "D"
adjective = "Poor"
percentile = "Bottom 20%"
else:
grade = "F"
adjective = "Awful"
percentile = "Bottom 5%"
# Acceptability
if score >= 70:
acceptable = "Acceptable"
elif score >= 50:
acceptable = "Marginal"
else:
acceptable = "Not acceptable"
return {
"score": score,
"grade": grade,
"adjective": adjective,
"percentile": percentile,
"acceptable": acceptable,
"benchmark": 68.0,
"above_benchmark": score >= 68,
}
def calculate_task_metrics(tasks: List[Dict]) -> Dict:
"""Calculate task performance metrics.
Each task dict should have:
participant, task, completed (bool), time_seconds, errors
"""
task_groups = {}
for t in tasks:
task_name = t["task"]
if task_name not in task_groups:
task_groups[task_name] = []
task_groups[task_name].append(t)
results = {}
for task_name, attempts in task_groups.items():
total = len(attempts)
completed = sum(1 for a in attempts if a["completed"])
times = [a["time_seconds"] for a in attempts if a["completed"]]
errors = [a["errors"] for a in attempts]
completion_rate = round((completed / total) * 100, 1) if total > 0 else 0
avg_time = round(sum(times) / len(times), 1) if times else 0
median_time = sorted(times)[len(times) // 2] if times else 0
avg_errors = round(sum(errors) / total, 1) if total > 0 else 0
# Severity assessment
if completion_rate < 50:
severity = "Critical"
elif completion_rate < 75:
severity = "Major"
elif completion_rate < 90:
severity = "Minor"
else:
severity = "None"
results[task_name] = {
"participants": total,
"completion_rate": completion_rate,
"avg_time_seconds": avg_time,
"median_time_seconds": median_time,
"avg_errors": avg_errors,
"usability_severity": severity,
}
return results
def load_sus_csv(filepath: str) -> List[Dict]:
"""Load SUS responses from CSV.
Expected: participant, q1, q2, ..., q10 (each 1-5)
"""
rows = []
with open(filepath, "r") as f:
reader = csv.DictReader(f)
for row in reader:
responses = []
for i in range(1, 11):
responses.append(int(row.get(f"q{i}", 3)))
rows.append({
"participant": row.get("participant", f"P{len(rows)+1}"),
"responses": responses,
})
return rows
def load_task_csv(filepath: str) -> List[Dict]:
"""Load task performance data from CSV.
Expected: participant, task, completed, time_seconds, errors
"""
rows = []
with open(filepath, "r") as f:
reader = csv.DictReader(f)
for row in reader:
rows.append({
"participant": row.get("participant", "Unknown"),
"task": row.get("task", "Unknown"),
"completed": row.get("completed", "true").lower() in ("true", "1", "yes"),
"time_seconds": float(row.get("time_seconds", 0)),
"errors": int(row.get("errors", 0)),
})
return rows
def create_sample_files():
"""Create sample CSV files for testing."""
# SUS responses
sus_header = ["participant"] + [f"q{i}" for i in range(1, 11)]
sus_rows = [
["P1", "4", "2", "5", "1", "4", "2", "5", "1", "4", "2"],
["P2", "3", "3", "4", "2", "4", "3", "4", "2", "3", "3"],
["P3", "5", "1", "5", "1", "5", "1", "5", "1", "5", "1"],
["P4", "3", "4", "3", "3", "3", "3", "3", "3", "3", "4"],
["P5", "4", "2", "4", "2", "5", "2", "4", "2", "4", "2"],
["P6", "2", "4", "3", "3", "3", "4", "3", "4", "2", "4"],
]
with open("sample_sus.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(sus_header)
writer.writerows(sus_rows)
# Task data
task_header = ["participant", "task", "completed", "time_seconds", "errors"]
task_rows = [
["P1", "Find product", "true", "45", "0"],
["P2", "Find product", "true", "62", "1"],
["P3", "Find product", "true", "38", "0"],
["P4", "Find product", "false", "120", "3"],
["P5", "Find product", "true", "55", "1"],
["P1", "Complete checkout", "true", "120", "0"],
["P2", "Complete checkout", "true", "180", "2"],
["P3", "Complete checkout", "false", "240", "4"],
["P4", "Complete checkout", "true", "150", "1"],
["P5", "Complete checkout", "true", "135", "0"],
["P1", "Edit profile", "true", "30", "0"],
["P2", "Edit profile", "true", "25", "0"],
["P3", "Edit profile", "true", "40", "1"],
["P4", "Edit profile", "true", "35", "0"],
["P5", "Edit profile", "true", "28", "0"],
]
with open("sample_tasks.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(task_header)
writer.writerows(task_rows)
print("Sample files created: sample_sus.csv, sample_tasks.csv")
def format_sus_report(participants: List[Dict], aggregate: Dict) -> str:
"""Format SUS report as human-readable text."""
lines = []
lines.append("=" * 60)
lines.append("SYSTEM USABILITY SCALE (SUS) REPORT")
lines.append("=" * 60)
interp = aggregate["interpretation"]
lines.append(f"\n AGGREGATE SCORE: {aggregate['mean_score']}")
lines.append(f" Grade: {interp['grade']} ({interp['adjective']})")
lines.append(f" Percentile: {interp['percentile']}")
lines.append(f" Acceptable: {interp['acceptable']}")
lines.append(f" Benchmark: {interp['benchmark']} (industry average)")
lines.append(f" Participants: {aggregate['count']}")
lines.append(f" Std Deviation: {aggregate['std_dev']}")
lines.append(f" Range: {aggregate['min_score']} - {aggregate['max_score']}")
# Score visualization
lines.append(f"\n SCORE SCALE")
lines.append(f" 0 25 50 68 80 100")
lines.append(f" |-----|-----|-----|-----|-----|")
pos = int(aggregate["mean_score"] / 100 * 30)
ruler = list(" " * 31)
ruler[min(pos, 30)] = "^"
lines.append(f" {''.join(ruler)} ({aggregate['mean_score']})")
lines.append(f" F D C B A")
# Per-participant
lines.append(f"\n INDIVIDUAL SCORES")
lines.append(f" {'Participant':<15} {'Score':>7} {'Grade':>6}")
lines.append(f" {'-'*15} {'-'*7} {'-'*6}")
for p in participants:
lines.append(f" {p['participant']:<15} {p['score']:>7} {p['interpretation']['grade']:>6}")
# Question analysis
if participants:
lines.append(f"\n QUESTION ANALYSIS (avg per question)")
lines.append(f" {'#':<4} {'Avg':>5} {'Question'}")
lines.append(f" {'-'*4} {'-'*5} {'-'*50}")
for qi in range(10):
avg_q = round(sum(p["responses"][qi] for p in participants) / len(participants), 1)
direction = "(+)" if (qi + 1) % 2 == 1 else "(-)"
lines.append(f" Q{qi+1:<3} {avg_q:>5} {direction} {SUS_QUESTIONS[qi][:50]}")
return "\n".join(lines)
def format_task_report(task_results: Dict) -> str:
"""Format task metrics as human-readable text."""
lines = []
lines.append("\n" + "=" * 60)
lines.append("TASK PERFORMANCE REPORT")
lines.append("=" * 60)
lines.append(f"\n {'Task':<25} {'Completion':>12} {'Avg Time':>10} {'Avg Errors':>11} {'Severity':<10}")
lines.append(f" {'-'*25} {'-'*12} {'-'*10} {'-'*11} {'-'*10}")
for task_name, metrics in task_results.items():
lines.append(
f" {task_name:<25} {metrics['completion_rate']:>11}% "
f"{metrics['avg_time_seconds']:>9}s {metrics['avg_errors']:>11} "
f"{metrics['usability_severity']:<10}"
)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Calculate SUS scores and task performance metrics from usability tests",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Create sample data
python usability_scorer.py sample
# Analyze SUS responses
python usability_scorer.py --sus-responses responses.csv
# Analyze task performance
python usability_scorer.py --task-data tasks.csv
# Both analyses together
python usability_scorer.py --sus-responses responses.csv --task-data tasks.csv
# JSON output
python usability_scorer.py --sus-responses responses.csv --json
""",
)
parser.add_argument("action", nargs="?", help='"sample" to create sample files')
parser.add_argument("--sus-responses", help="CSV with SUS responses (participant, q1-q10)")
parser.add_argument("--task-data", help="CSV with task data (participant, task, completed, time_seconds, errors)")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.action == "sample":
create_sample_files()
return
if not args.sus_responses and not args.task_data:
parser.print_help()
print("\nError: Provide --sus-responses and/or --task-data, or use 'sample' to create test files")
sys.exit(1)
output = {}
if args.sus_responses:
raw = load_sus_csv(args.sus_responses)
participants = []
for p in raw:
score = calculate_sus_score(p["responses"])
participants.append({
"participant": p["participant"],
"responses": p["responses"],
"score": score,
"interpretation": interpret_sus_score(score),
})
scores = [p["score"] for p in participants]
mean = round(sum(scores) / len(scores), 1)
variance = sum((s - mean) ** 2 for s in scores) / len(scores)
std_dev = round(math.sqrt(variance), 1)
aggregate = {
"count": len(scores),
"mean_score": mean,
"median_score": sorted(scores)[len(scores) // 2],
"std_dev": std_dev,
"min_score": min(scores),
"max_score": max(scores),
"interpretation": interpret_sus_score(mean),
}
output["sus"] = {"participants": participants, "aggregate": aggregate}
if not args.json:
print(format_sus_report(participants, aggregate))
if args.task_data:
tasks = load_task_csv(args.task_data)
task_results = calculate_task_metrics(tasks)
output["task_performance"] = task_results
if not args.json:
print(format_task_report(task_results))
if args.json:
# Clean up for JSON (remove full response arrays for brevity)
if "sus" in output:
for p in output["sus"]["participants"]:
del p["responses"]
print(json.dumps(output, indent=2))
if __name__ == "__main__":
main()
Related skills
How it compares
product-designer implements its own SKILL.md workflow rather than a generic substitute skill.
FAQ
Who is product-designer for?
Agents and developers following the product-designer SKILL.md guidance.
When should I use product-designer?
When user intent matches description triggers and quick start scenarios.
Is product-designer safe to install?
Review the Security Audits panel before production shell or network use.