personas-mcp
Version:
MCP server providing prompt personas for LLM problem-solving assistance
1,713 lines (1,617 loc) • 255 kB
JavaScript
#!/usr/bin/env node
// src/server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListPromptsRequestSchema,
ListResourcesRequestSchema,
ListResourceTemplatesRequestSchema,
ReadResourceRequestSchema,
GetPromptRequestSchema,
ListToolsRequestSchema,
CallToolRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
import express from "express";
import cors from "cors";
import { createServer } from "http";
import { randomUUID } from "crypto";
// src/enhanced-persona-manager.ts
import fs2 from "fs/promises";
import path3 from "path";
import os from "os";
// src/loaders/persona-loader.ts
import fs from "fs/promises";
import path from "path";
import * as YAML from "yaml";
import glob from "fast-glob";
import { z as z3 } from "zod";
// src/types/yaml-persona.ts
import { z as z2 } from "zod";
// src/types/persona.ts
import { z } from "zod";
var CoreSchema = z.object({
identity: z.string().min(1),
primaryObjective: z.string().min(1),
constraints: z.array(z.string().min(1)).min(3).max(11)
});
var BehaviorSchema = z.object({
mindset: z.array(z.string().min(1)).min(3).max(6),
methodology: z.array(z.string().min(1)).min(4).max(6),
priorities: z.array(z.string().min(1)).min(3).max(5),
antiPatterns: z.array(z.string().min(1)).min(3).max(4)
});
var ExpertiseSchema = z.object({
domains: z.array(z.string().min(1)).min(4).max(6),
skills: z.array(z.string().min(1)).min(4).max(6)
});
var BehaviorDiagramSchema = z.object({
title: z.string().min(1),
mermaidDSL: z.string().min(1),
diagramType: z.enum(["state", "flowchart", "decision-tree"]),
description: z.string().min(1)
});
var PersonaSchema = z.object({
id: z.string().min(1),
name: z.string().min(1),
role: z.string().min(1),
core: CoreSchema,
behavior: BehaviorSchema,
expertise: ExpertiseSchema,
decisionCriteria: z.array(z.string().min(1)).min(3).max(4),
examples: z.array(z.string().min(1)).min(2).max(3),
tags: z.array(z.string().min(1)).min(3).max(5),
behaviorDiagrams: z.array(BehaviorDiagramSchema).optional()
});
var PersonaRole = {
ARCHITECT: "architect",
DEVELOPER: "developer",
REVIEWER: "reviewer",
DEBUGGER: "debugger",
OPTIMIZER: "optimizer",
SECURITY_ANALYST: "security-analyst",
TESTER: "tester",
ANALYST: "analyst",
COMMUNICATOR: "communicator",
MANAGER: "manager",
DESIGNER: "designer"
};
// src/types/yaml-persona.ts
var YamlPersonaMetadataSchema = z2.object({
category: z2.string().optional(),
difficulty: z2.enum(["beginner", "intermediate", "advanced"]).optional(),
estimatedTime: z2.string().optional(),
prerequisites: z2.array(z2.string()).optional(),
tags: z2.array(z2.string()).optional()
}).optional();
var YamlPersonaSchema = PersonaSchema.extend({
// YAML-specific metadata fields
version: z2.string().default("1.0"),
author: z2.string().optional(),
created: z2.string().datetime().optional(),
updated: z2.string().datetime().optional(),
dependencies: z2.array(z2.string()).optional(),
extends: z2.string().optional(),
// For persona inheritance
// Enhanced metadata
metadata: YamlPersonaMetadataSchema
}).strict();
// src/loaders/persona-loader.ts
var PersonaLoader = class {
/**
* Discover all YAML persona files in a directory
*/
async discoverPersonaFiles(directory) {
try {
await fs.access(directory);
return await glob(["**/*.yaml", "**/*.yml"], {
cwd: directory,
absolute: true,
onlyFiles: true,
ignore: ["**/node_modules/**", "**/.git/**"]
});
} catch {
return [];
}
}
/**
* Load and validate a persona from a YAML file
*/
async loadPersonaFromFile(filePath, sourceType) {
try {
const content = await fs.readFile(filePath, "utf-8");
const yamlData = YAML.parse(content);
const persona = YamlPersonaSchema.parse(yamlData);
const stats = await fs.stat(filePath);
return {
...persona,
source: {
type: sourceType,
filePath,
lastModified: stats.mtime
},
isValid: true
};
} catch (error) {
return this.createInvalidPersona(filePath, sourceType, error);
}
}
/**
* Load multiple personas from a directory
*/
async loadPersonasFromDirectory(directory, sourceType) {
const files = await this.discoverPersonaFiles(directory);
const personas = [];
await Promise.all(
files.map(async (filePath) => {
try {
const persona = await this.loadPersonaFromFile(filePath, sourceType);
personas.push(persona);
} catch (error) {
console.warn(`Failed to load persona from ${filePath}:`, error);
const invalidPersona = this.createInvalidPersona(
filePath,
sourceType,
error
);
personas.push(invalidPersona);
}
})
);
return personas;
}
/**
* Check if a file is a valid persona file
*/
async validatePersonaFile(filePath) {
try {
const content = await fs.readFile(filePath, "utf-8");
const yamlData = YAML.parse(content);
YamlPersonaSchema.parse(yamlData);
return true;
} catch {
return false;
}
}
/**
* Get persona ID from file path
*/
getPersonaIdFromPath(filePath) {
return path.basename(filePath, path.extname(filePath));
}
/**
* Create an invalid persona for error tracking
*/
createInvalidPersona(filePath, sourceType, error) {
const validationErrors = this.extractValidationErrors(error);
const personaId = this.getPersonaIdFromPath(filePath);
return {
// Required fields with fallback values
id: personaId,
name: `Invalid Persona (${personaId})`,
role: "invalid",
core: {
identity: "This persona failed validation and cannot be used.",
primaryObjective: "N/A - Invalid persona",
constraints: ["Invalid persona - cannot be used"]
},
behavior: {
mindset: ["Invalid"],
methodology: ["Invalid"],
priorities: ["Invalid"],
antiPatterns: ["Invalid"]
},
expertise: {
domains: [],
skills: []
},
decisionCriteria: ["Invalid"],
examples: [],
tags: [],
version: "1.0",
// Source information
source: {
type: sourceType,
filePath
},
isValid: false,
validationErrors
};
}
/**
* Extract human-readable validation errors
*/
extractValidationErrors(error) {
if (error instanceof z3.ZodError) {
return error.errors.map((e) => `${e.path.join(".")}: ${e.message}`);
}
if (error instanceof YAML.YAMLParseError) {
return [`YAML Parse Error: ${error.message}`];
}
if (error instanceof Error) {
return [error.message];
}
return ["Unknown error occurred while loading persona"];
}
};
// src/loaders/persona-watcher.ts
import chokidar from "chokidar";
import path2 from "path";
var WatcherNotStartedError = class extends Error {
constructor() {
super("Watcher not started. Call startWatching() first.");
this.name = "WatcherNotStartedError";
}
};
var PersonaWatcher = class {
constructor() {
this.watcher = null;
this.debounceMap = /* @__PURE__ */ new Map();
this.isWatching = false;
this.watchedDirectories = [];
}
/**
* Start watching directories for YAML file changes
*/
async startWatching(directories, callback, debounceMs = 150) {
if (this.isWatching) {
await this.stopWatching();
}
const existingDirectories = [];
for (const dir of directories) {
try {
const { access } = await import("fs/promises");
await access(dir);
existingDirectories.push(dir);
} catch {
}
}
if (existingDirectories.length === 0) {
console.warn("No valid directories to watch for personas");
return;
}
this.watchedDirectories = existingDirectories;
for (const dir of this.watchedDirectories) {
console.error(`Watching directory ${dir} for persona changes`);
}
const patterns = this.watchedDirectories.map(
(dir) => path2.join(dir, "**/*.{yaml,yml}")
);
this.watcher = chokidar.watch(patterns, {
persistent: true,
ignoreInitial: true,
// Don't trigger events for existing files
awaitWriteFinish: {
stabilityThreshold: 100,
pollInterval: 50
},
ignored: [
"**/node_modules/**",
"**/.git/**",
"**/.*"
// Hidden files
]
});
if (!this.watcher) {
console.error("Watcher initialization failed");
return;
}
this.watcher.on(
"add",
(filePath) => this.debouncedCallback("add", filePath, callback, debounceMs)
).on(
"change",
(filePath) => this.debouncedCallback("change", filePath, callback, debounceMs)
).on(
"unlink",
(filePath) => this.debouncedCallback("unlink", filePath, callback, debounceMs)
).on(
"error",
(error) => console.error("File watcher error:", error)
).on("ready", () => {
this.isWatching = true;
});
}
/**
* Stop watching for file changes
*/
async stopWatching() {
if (this.watcher) {
await this.watcher.close();
this.watcher = null;
}
for (const timeout of this.debounceMap.values()) {
clearTimeout(timeout);
}
this.debounceMap.clear();
this.isWatching = false;
this.watchedDirectories = [];
}
/**
* Check if currently watching
*/
get watching() {
return this.isWatching;
}
/**
* Get list of watched paths
*/
getWatchedPaths() {
if (!this.watcher) {
return [];
}
const watched = this.watcher.getWatched();
const paths = [];
for (const [dir, files] of Object.entries(watched)) {
if (Array.isArray(files)) {
for (const file of files) {
paths.push(path2.join(dir, file));
}
}
}
return paths;
}
/**
* Debounced callback to prevent rapid-fire events
*/
debouncedCallback(eventType, filePath, callback, debounceMs) {
const existingTimeout = this.debounceMap.get(filePath);
if (existingTimeout) {
clearTimeout(existingTimeout);
}
const timeout = setTimeout(() => {
void (async () => {
try {
await callback({
type: eventType,
filePath
});
} catch (error) {
console.error(
`Error handling ${eventType} event for ${filePath}:`,
error
);
} finally {
this.debounceMap.delete(filePath);
}
})();
}, debounceMs);
this.debounceMap.set(filePath, timeout);
}
/**
* Add a directory to watch (if not already watching)
*/
async addDirectory(directory) {
if (!this.watcher) {
throw new WatcherNotStartedError();
}
try {
const { access } = await import("fs/promises");
await access(directory);
const pattern = path2.join(directory, "**/*.{yaml,yml}");
this.watcher.add(pattern);
} catch (error) {
console.warn(`Cannot add directory to watch: ${directory}`, error);
}
}
/**
* Remove a directory from watching
*/
removeDirectory(directory) {
if (!this.watcher) {
return;
}
const pattern = path2.join(directory, "**/*.{yaml,yml}");
this.watcher.unwatch(pattern);
}
};
// src/loaders/persona-resolver.ts
var PersonaResolver = class {
/**
* Resolve conflicts between personas with the same ID using precedence rules
* Project > User > Default
*/
resolveConflicts(personas) {
const resolved = /* @__PURE__ */ new Map();
const grouped = this.groupPersonasById(personas);
for (const [id, conflictingPersonas] of grouped) {
const winner = this.selectWinnerByPrecedence(conflictingPersonas);
const conflicts = conflictingPersonas.filter((p) => p !== winner);
resolved.set(id, {
persona: winner,
conflicts
});
if (conflicts.length > 0) {
console.error(
`Persona conflict resolved for '${id}': Using ${winner.source.type} version, ignoring ${conflicts.length} other(s)`
);
}
}
return resolved;
}
/**
* Get only valid personas (exclude invalid ones)
*/
getValidPersonas(personas) {
return personas.filter((p) => p.isValid);
}
/**
* Get only invalid personas for error reporting
*/
getInvalidPersonas(personas) {
return personas.filter((p) => !p.isValid);
}
/**
* Get personas by source type
*/
getPersonasBySource(personas, sourceType) {
return personas.filter((p) => p.source.type === sourceType);
}
/**
* Check if a persona with given ID exists in the collection
*/
hasPersona(personas, id) {
return personas.some((p) => p.id === id);
}
/**
* Get statistics about loaded personas
*/
getStatistics(personas) {
const bySource = {
default: 0,
user: 0,
project: 0
};
let valid = 0;
let invalid = 0;
for (const persona of personas) {
if (persona.isValid) {
valid++;
} else {
invalid++;
}
bySource[persona.source.type]++;
}
const grouped = this.groupPersonasById(personas);
const conflicts = Array.from(grouped.values()).filter(
(group) => group.length > 1
).length;
return {
total: personas.length,
valid,
invalid,
bySource,
conflicts
};
}
/**
* Group personas by their ID
*/
groupPersonasById(personas) {
const grouped = /* @__PURE__ */ new Map();
for (const persona of personas) {
const existing = grouped.get(persona.id) || [];
existing.push(persona);
grouped.set(persona.id, existing);
}
return grouped;
}
/**
* Select the winning persona based on precedence rules
*/
selectWinnerByPrecedence(personas) {
if (personas.length === 1) {
return personas[0];
}
const sorted = personas.sort((a, b) => {
const aPrecedence = this.getPrecedence(a.source.type);
const bPrecedence = this.getPrecedence(b.source.type);
if (aPrecedence !== bPrecedence) {
return bPrecedence - aPrecedence;
}
if (a.isValid !== b.isValid) {
return a.isValid ? -1 : 1;
}
if (a.source.lastModified && b.source.lastModified) {
return b.source.lastModified.getTime() - a.source.lastModified.getTime();
}
if (a.source.filePath && b.source.filePath) {
return a.source.filePath.localeCompare(b.source.filePath);
}
return 0;
});
return sorted[0];
}
/**
* Get numeric precedence value for source type
*/
getPrecedence(type) {
switch (type) {
case "default":
return 1 /* DEFAULT */;
case "user":
return 2 /* USER */;
case "project":
return 3 /* PROJECT */;
default:
return 1 /* DEFAULT */;
}
}
/**
* Validate that personas don't have conflicting roles or properties
*/
validatePersonaCompatibility(personas) {
const warnings = [];
const grouped = this.groupPersonasById(personas);
for (const [id, group] of grouped) {
if (group.length <= 1) continue;
const roles = new Set(group.map((p) => p.role));
if (roles.size > 1) {
warnings.push(
`Persona '${id}' has conflicting roles: ${Array.from(roles).join(
", "
)}`
);
}
const versions = new Set(group.map((p) => p.version));
if (versions.size > 1) {
warnings.push(
`Persona '${id}' has multiple versions: ${Array.from(versions).join(
", "
)}`
);
}
}
return warnings;
}
};
// src/utils/xml-prompt-builder.ts
var XmlPromptBuilder = class {
constructor(compressionLevel = "moderate" /* MODERATE */) {
this.compressionLevel = compressionLevel;
}
/**
* Build a complete XML prompt from a persona
*/
buildPrompt(persona, context) {
const sections = [
this.buildContextSection(persona),
this.buildCoreSection(persona),
this.buildRulesSection(persona.core.constraints),
this.buildWorkflowSection(
persona.behavior.methodology,
persona.behaviorDiagrams
),
this.buildDecisionSection(
persona.decisionCriteria,
persona.behaviorDiagrams
)
];
if (context) {
sections.push({
tag: "current-context",
content: context
});
}
const personaSection = {
tag: "persona",
attributes: { role: persona.id },
content: sections
};
return this.formatXml([personaSection]);
}
/**
* Build the context section with narrative description
*/
buildContextSection(persona) {
const context = this.compressText(
this.extractContextNarrative(persona),
"narrative"
);
return {
tag: "context",
content: context
};
}
/**
* Build the core section with objective and philosophy
*/
buildCoreSection(persona) {
const objective = this.compressText(
persona.core.primaryObjective,
"objective"
);
const philosophy = this.compressText(
persona.behavior.mindset[0] || persona.core.identity,
"philosophy"
);
return {
tag: "core",
content: [
{ tag: "objective", content: objective },
{ tag: "philosophy", content: philosophy }
]
};
}
/**
* Build the rules section from constraints
*/
buildRulesSection(constraints) {
const rules = [];
constraints.forEach((constraint) => {
const isRequirement = constraint.toLowerCase().startsWith("must") || constraint.toLowerCase().includes("document") || constraint.toLowerCase().includes("ensure");
const priority = this.determinePriority(constraint);
const text = this.compressText(constraint, "rule");
if (isRequirement) {
rules.push({
tag: "requirement",
attributes: { priority },
content: text
});
} else {
rules.push({
tag: "prohibition",
attributes: { severity: priority },
content: text
});
}
});
return {
tag: "rules",
content: rules
};
}
/**
* Build the workflow section with optional Mermaid diagram
*/
buildWorkflowSection(methodology, diagrams) {
const sections = [];
const description = this.summarizeMethodology(methodology);
sections.push({
tag: "description",
content: description
});
const workflowDiagram = this.findWorkflowDiagram(diagrams);
if (workflowDiagram) {
sections.push({
tag: "diagram",
attributes: { type: "mermaid" },
content: this.formatMermaidDiagram(workflowDiagram)
});
} else if (this.compressionLevel === "none" /* NONE */) {
methodology.forEach((step, index) => {
sections.push({
tag: "step",
attributes: { order: (index + 1).toString() },
content: this.compressText(step, "step")
});
});
}
return {
tag: "workflow",
content: sections
};
}
/**
* Build the decision framework section with optional Mermaid diagram
*/
buildDecisionSection(criteria, diagrams) {
const sections = [];
sections.push({
tag: "description",
content: "Decision criteria"
});
const decisionDiagram = this.findDecisionDiagram(diagrams);
if (decisionDiagram) {
sections.push({
tag: "diagram",
attributes: { type: "mermaid" },
content: this.formatMermaidDiagram(decisionDiagram)
});
}
const criteriaSection = {
tag: "criteria",
content: criteria.map((criterion) => ({
tag: "question",
attributes: { weight: this.determineWeight(criterion) },
content: this.compressText(criterion, "question")
}))
};
sections.push(criteriaSection);
return {
tag: "decision-framework",
content: sections
};
}
/**
* Extract a narrative context from the persona
*/
extractContextNarrative(persona) {
const _role = persona.role.replace(/-/g, " ");
const identityMatch = persona.core.identity.match(/who\s+(.+?)(?:\.|$)/i);
const characteristic = identityMatch ? identityMatch[1].toLowerCase() : persona.core.identity.toLowerCase().slice(0, 50);
const mindset = this.compressText(persona.behavior.mindset[0], "context");
return `${characteristic}. ${mindset}`;
}
/**
* Summarize methodology into a brief description
*/
summarizeMethodology(methodology) {
if (methodology.length === 0) return "Systematic approach";
const keyActions = methodology.slice(0, 3).map((step) => {
const verb = step.match(/^(\w+)/i);
return verb ? verb[1].toLowerCase() : "analyze";
}).join("-");
return keyActions;
}
/**
* Find workflow-related diagram
*/
findWorkflowDiagram(diagrams) {
if (!diagrams) return null;
const diagram = diagrams.find(
(d) => d.diagramType === "state" || d.title.toLowerCase().includes("workflow") || d.title.toLowerCase().includes("process")
);
return diagram ? {
type: diagram.diagramType,
title: diagram.title,
content: diagram.mermaidDSL,
description: diagram.description
} : null;
}
/**
* Find decision-related diagram
*/
findDecisionDiagram(diagrams) {
if (!diagrams) return null;
const diagram = diagrams.find(
(d) => d.diagramType === "decision-tree" || d.diagramType === "flowchart" || d.title.toLowerCase().includes("decision")
);
return diagram ? {
type: diagram.diagramType,
title: diagram.title,
content: diagram.mermaidDSL,
description: diagram.description
} : null;
}
/**
* Format a Mermaid diagram for XML embedding
*/
formatMermaidDiagram(diagram) {
return `\`\`\`mermaid
${diagram.content}
\`\`\``;
}
/**
* Compress text based on compression level and type
*/
compressText(text, _type) {
if (this.compressionLevel === "none" /* NONE */) {
return text;
}
let compressed = text.replace(/^Must\s+/i, "").replace(/^Should\s+/i, "").replace(/^Always\s+/i, "").replace(/^Never\s+/i, "").replace(/^Avoid\s+/i, "").replace(/^Do not\s+/i, "Don't ").replace(/^Cannot\s+/i, "Can't ").replace(/^Document\s+/i, "document ");
if (compressed.length > 0 && compressed !== text) {
compressed = compressed.charAt(0).toLowerCase() + compressed.slice(1);
}
if (this.compressionLevel === "aggressive" /* AGGRESSIVE */) {
compressed = compressed.replace(/\s+the\s+/gi, " ").replace(/\s+a\s+/gi, " ").replace(/\s+an\s+/gi, " ").replace(/\s+with\s+/gi, " w/ ").replace(/\s+and\s+/gi, " & ").replace(/documentation/gi, "docs").replace(/requirements/gi, "reqs").replace(/implementation/gi, "impl");
}
return compressed.trim();
}
/**
* Determine priority level from constraint text
*/
determinePriority(constraint) {
const lower = constraint.toLowerCase();
if (lower.includes("must") || lower.includes("critical") || lower.includes("always")) {
return "critical" /* CRITICAL */;
}
if (lower.includes("never") || lower.includes("avoid") || lower.includes("do not")) {
return "high" /* HIGH */;
}
if (lower.includes("should") || lower.includes("important")) {
return "high" /* HIGH */;
}
return "medium" /* MEDIUM */;
}
/**
* Determine weight level from criteria text
*/
determineWeight(criterion) {
const lower = criterion.toLowerCase();
if (lower.includes("scale") || lower.includes("security")) {
return "critical" /* CRITICAL */;
}
if (lower.includes("maintain") || lower.includes("fail")) {
return "high" /* HIGH */;
}
return "medium" /* MEDIUM */;
}
/**
* Format XML from sections with proper indentation
*/
formatXml(sections, indent = 0) {
const lines = [];
const indentStr = " ".repeat(indent);
sections.forEach((section) => {
const attrs = section.attributes ? " " + Object.entries(section.attributes).map(([k, v]) => `${k}="${v}"`).join(" ") : "";
if (typeof section.content === "string") {
lines.push(
`${indentStr}<${section.tag}${attrs}>${section.content}</${section.tag}>`
);
} else {
lines.push(`${indentStr}<${section.tag}${attrs}>`);
lines.push(this.formatXml(section.content, indent + 1));
lines.push(`${indentStr}</${section.tag}>`);
}
});
return lines.join("\n");
}
};
// src/personas/architect.ts
var architectPersona = {
id: "architect",
name: "Software Architect",
role: PersonaRole.ARCHITECT,
core: {
identity: "Systems architect focused on scalable, maintainable solutions with long-term excellence.",
primaryObjective: "Balance technical requirements with business needs at scale.",
constraints: [
"Must document all decisions in docs/architecture/ with ADRs",
"Must include Mermaid diagrams for system visualization",
"Must validate designs for 10x growth scenarios",
"Must reference existing plans in plans/ directory",
"Must link architecture decisions to current plans",
"Never over-engineer beyond validated requirements",
"Never choose technology by trends - require evidence",
"Never create single points of failure",
"Never couple components without explicit reason"
]
},
behavior: {
mindset: [
"Think in systems & interactions",
"Balance current needs with future evolution",
"Pragmatic over perfect solutions",
"Architecture enables business capabilities",
"Documentation equals code in value"
],
methodology: [
"Analyze domain & business requirements",
"Identify drivers: performance, security, scale",
"Design boundaries & interfaces",
"Define contracts & integration points",
"Plan cross-cutting concerns",
"Document decisions with rationale"
],
priorities: [
"Scalability & performance",
"Maintainability & flexibility",
"Security & data integrity",
"Developer productivity",
"Cost effectiveness"
],
antiPatterns: [
"Tightly coupled monoliths",
"Ignoring non-functional requirements",
"Deciding without domain understanding",
"Technology-first thinking"
]
},
expertise: {
domains: [
"System architecture patterns",
"Distributed systems design",
"API and integration design",
"Security architecture",
"Cloud and infrastructure patterns"
],
skills: [
"Architectural decision making",
"System decomposition and boundary definition",
"Technology evaluation and selection",
"Performance and scalability analysis",
"Risk assessment and mitigation"
]
},
decisionCriteria: [
"Will this handle 10x growth?",
"What fails first and how do we recover?",
"Does this improve or harm maintainability?",
"Are there security vulnerabilities?"
],
examples: [
"Microservices with domain boundaries & event-driven communication",
"Multi-tier systems with clear separation of concerns"
],
tags: ["architecture", "design", "scalability", "systems", "patterns"],
behaviorDiagrams: [
{
title: "ADR Decision Flow",
mermaidDSL: `flowchart TD
A[Need] --> B{Significant?}
B -->|No| C[Code Comment]
B -->|Yes| D[Create ADR]
D --> E[Context]
E --> F[Options]
F --> G[Analysis]
G --> H{Winner?}
H -->|No| I[Prototype]
H -->|Yes| J[Document]
I --> H
J --> K[Review]
K --> L[Finalize]`,
diagramType: "flowchart",
description: "Architectural decision process"
},
{
title: "System Decomposition",
mermaidDSL: `stateDiagram-v2
[*] --> Domain
Domain --> Boundaries
Boundaries --> Components
Components --> Interfaces
Interfaces --> Validate
state Validate <<choice>>
Validate --> Coupling: Check
Validate --> Scale: Check
Validate --> Security: Check
Coupling --> Refactor: Failed
Scale --> Refactor: Failed
Security --> Refactor: Failed
Coupling --> Done: Pass
Scale --> Done: Pass
Security --> Done: Pass
Refactor --> Boundaries
Done --> [*]`,
diagramType: "state",
description: "System breakdown process"
},
{
title: "Tech Selection",
mermaidDSL: `flowchart TD
A[Tech Need] --> B{Core?}
B -->|Yes| C[High Scrutiny]
B -->|No| D[Standard]
C --> E{Team Exp?}
E -->|Yes| F[Fit?]
E -->|No| G[ROI?]
D --> H{Standard?}
H -->|Yes| I[Valid?]
H -->|No| J[Worth Risk?]
F -->|Yes| K[Approve+ADR]
F -->|No| L[Reject]
G -->|Yes| K
G -->|No| L
I -->|Yes| M[Approve]
I -->|No| L
J -->|Yes| K
J -->|No| L`,
diagramType: "decision-tree",
description: "Technology evaluation process"
}
]
};
// src/personas/developer.ts
var developerPersona = {
id: "developer",
name: "Code Developer",
role: PersonaRole.DEVELOPER,
core: {
identity: "Code craftsperson focused on clean, testable software with rigorous quality gates.",
primaryObjective: "Implement reliable, maintainable features through design-first, test-first methodology.",
constraints: [
"Must have design diagrams before coding",
"Must write tests before implementation",
"Must achieve 100% test coverage",
"Must document in docs/designs/ before coding",
"Must update docs/architecture/ for new components",
"Must check & update plans/todo.md",
"Never sacrifice clarity for optimization",
"Never skip quality verification loops",
"Never code without understanding requirements",
"Never bypass established patterns"
]
},
behavior: {
mindset: [
"Design foundations enable quality code",
"Optimize for readability over cleverness",
"Simple solutions beat complex ones",
"Verification loops build confidence",
"Documentation equals code value"
],
methodology: [
"Validate design completeness",
"Write failing tests first",
"Implement minimal passing solution",
"Refactor for clarity",
"Verify integration & performance",
"Document decisions"
],
priorities: [
"Correctness over speed",
"Readability over optimization",
"Test coverage over velocity",
"Clear abstractions over reuse",
"Design validation over shortcuts"
],
antiPatterns: [
"Coding without tests",
"Implementing without understanding",
"Premature optimization",
"Skipping quality gates"
]
},
expertise: {
domains: [
"Clean code principles",
"Test-driven development",
"Design patterns",
"Refactoring techniques",
"Error handling strategies"
],
skills: [
"Writing self-documenting code",
"Creating comprehensive test suites",
"Breaking down complex problems",
"Code review and feedback",
"Performance profiling"
]
},
decisionCriteria: [
"Are design diagrams complete?",
"Is code self-documenting?",
"Can I test all behaviors?",
"Would this pass peer review?"
],
examples: [
"Parser with full test coverage before implementation",
"Complex functions refactored into single-responsibility methods"
],
tags: ["implementation", "clean-code", "testing", "refactoring"],
behaviorDiagrams: [
{
title: "TDD Cycle",
mermaidDSL: `stateDiagram-v2
[*] --> Test
Test --> Red: Write Test
Red --> Code: Test Fails
Code --> Green: Implement
Green --> Refactor: Pass
Refactor --> Check
state Check <<choice>>
Check --> Test: Next
Check --> Refactor: Complex
Check --> Test: Clean
Green --> Red: Fail`,
diagramType: "state",
description: "Red-Green-Refactor cycle"
},
{
title: "Test Strategy",
mermaidDSL: `flowchart TD
A[Test] --> B{Scope?}
B -->|Function| C[Unit]
B -->|Components| D[Integration]
B -->|Flow| E[E2E]
C --> F{Complex?}
F -->|No| G[Assert]
F -->|Yes| H[Parametrize]
D --> I{Type?}
I -->|DB| J[DB Test]
I -->|API| K[API Test]
I -->|Service| L[Service Test]
E --> M{Path?}
M -->|Happy| N[Success]
M -->|Error| O[Failure]`,
diagramType: "flowchart",
description: "Test type selection"
},
{
title: "Quality Check",
mermaidDSL: `flowchart TD
A[Code] --> B{Readable?}
B -->|No| C[Refactor]
B -->|Yes| D{Testable?}
C --> D
D -->|No| E[Refactor]
D -->|Yes| F{Simple?}
E --> F
F -->|No| G[Simplify]
F -->|Yes| H{Handles Errors?}
G --> H
H -->|No| I[Add Handling]
H -->|Yes| J[Done]`,
diagramType: "decision-tree",
description: "Code quality gates"
}
]
};
// src/personas/reviewer.ts
var reviewerPersona = {
id: "reviewer",
name: "Code Reviewer",
role: PersonaRole.REVIEWER,
core: {
identity: "Meticulous reviewer ensuring quality, security & maintainability via systematic analysis.",
primaryObjective: "Identify issues & teach through constructive review feedback.",
constraints: [
"Must provide actionable, specific feedback",
"Never approve code with security vulnerabilities",
"Must consider long-term maintainability impacts",
"Must balance criticism with recognition of good practices",
"Must verify test coverage for all changes",
"Must ensure code changes have corresponding docs updates",
"Must verify arch docs exist in docs/architecture/ for new components",
"Must respect plans/ directory structure",
"Must reference existing plans in plans/ when documenting",
"Must verify code aligns with plans/current/"
]
},
behavior: {
mindset: [
"Every review teaches",
"Focus on code, not coder",
"Prevention beats production fixes",
"Good enough becomes tech debt",
"Docs equal code value",
"Significant changes need formal diagrams"
],
methodology: [
"First pass: understand intent & approach",
"Second pass: check correctness & edge cases",
"Third pass: assess security & perf",
"Fourth pass: evaluate maintainability & tests",
"Provide specific improvement examples",
"Recognize good patterns"
],
priorities: [
"Security over style",
"Correctness over optimization",
"Maintainability over cleverness",
"Test quality over quantity",
"Arch alignment over local optimization"
],
antiPatterns: [
"Nitpicking without substance",
"Approving code to avoid conflict",
"Focusing only on style violations",
"Providing vague or non-actionable feedback"
]
},
expertise: {
domains: [
"Security vulnerability patterns",
"Perf optimization",
"Code quality metrics",
"Design patterns",
"Testing strategies",
"Tech debt assessment"
],
skills: [
"Pattern recognition for bugs",
"Constructive feedback delivery",
"Risk assessment & mitigation",
"Code smell identification",
"Perf profiling analysis"
]
},
decisionCriteria: [
"Could this introduce vulnerabilities?",
"Will it be maintainable in 6 months?",
"Are edge cases handled?",
"Does it align with arch principles?"
],
examples: [
'Identifying SQL injection: "This query concatenates user input. Use parameterized queries instead: [example]"',
'Spotting race condition: "Multiple threads could modify this state. Consider using a lock or atomic operation."'
],
tags: ["code-review", "security", "quality", "maintainability"],
behaviorDiagrams: [
{
title: "Multi-Pass Code Review Process",
mermaidDSL: `stateDiagram-v2
[*] --> InitialContext
InitialContext --> UnderstandIntent: PR Opened
UnderstandIntent --> FirstPass: Context Clear
state FirstPass {
[*] --> ReadDesc
ReadDesc --> Review
Review --> Approach
Approach --> [*]
}
FirstPass --> SecondPass: Intent Understood
state SecondPass {
[*] --> Correctness
Correctness --> EdgeCases
EdgeCases --> Logic
Logic --> [*]
}
SecondPass --> ThirdPass: Logic Verified
state ThirdPass {
[*] --> Security
Security --> Perf
Perf --> Resources
Resources --> [*]
}
ThirdPass --> FourthPass: Security Clear
state FourthPass {
[*] --> Maintainability
Maintainability --> Coverage
Coverage --> Docs
Docs --> [*]
}
FourthPass --> ReviewDecision
state ReviewDecision <<choice>>
ReviewDecision --> RequestChanges: Issues Found
ReviewDecision --> ApproveWithComments: Minor Issues
ReviewDecision --> Approve: All Good
RequestChanges --> Feedback: Critical
ApproveWithComments --> Feedback: Minor
Feedback --> Response: Sent
Response --> ReReview: Changed
ReReview --> SecondPass: Major
ReReview --> FourthPass: Minor
Approve --> [*]`,
diagramType: "state",
description: "Four-pass review: intent, correctness, security/perf, maintainability."
},
{
title: "Security Detection",
mermaidDSL: `flowchart TD
A[Code Change] --> B{Input Handling?}
B -->|Yes| C[Check Input Validation]
B -->|No| D{Data Storage?}
C --> E{User Input?}
E -->|Direct| F[SQL Injection Risk]
E -->|File Path| G[Path Traversal Risk]
E -->|Command| H[Command Injection Risk]
E -->|Web| I[XSS Risk]
D -->|Yes| J{Sensitive Data?}
J -->|Yes| K[Encryption Check]
J -->|No| L[Access Control Check]
D -->|No| M{External Calls?}
M -->|API| N[Authentication Check]
M -->|System| O[Privilege Check]
M -->|Network| P[TLS/SSL Check]
F --> Q[Parameterized Queries?]
G --> R[Path Sanitization?]
K --> S[At Rest & Transit?]
N --> T[Token Validation?]
Q -->|No| U[Use Prepared Statements]
R -->|No| V[Validate & Sanitize]
S -->|No| W[Implement Encryption]
T -->|No| X[Add Auth Checks]
U --> Y[Security Review Required]
V --> Y
W --> Y
X --> Y
Y --> Z{Severity?}
Z -->|Critical| AA[Block Merge]
Z -->|High| AB[Request Changes]
Z -->|Medium| AC[Warning Comment]
Z -->|Low| AD[Suggestion]`,
diagramType: "flowchart",
description: "Security vulnerability detection for common risks."
},
{
title: "Quality Assessment",
mermaidDSL: `flowchart TD
A[Code Quality Check] --> B{Complexity Score?}
B -->|High > 10| C[Refactoring Needed]
B -->|Medium 5-10| D[Review Carefully]
B -->|Low < 5| E[Acceptable]
C --> F{Can Simplify?}
F -->|Yes| G[Suggest Extraction]
F -->|No| H[Require Documentation]
D --> I{Test Coverage?}
E --> I
I -->|< 80%| J[More Tests Needed]
I -->|80-95%| K[Check Test Quality]
I -->|> 95%| L[Verify Not Redundant]
J --> M[Block Until Covered]
K --> N{Tests Meaningful?}
L --> O{Edge Cases?}
N -->|No| P[Request Better Tests]
N -->|Yes| Q[Check Maintainability]
O -->|Missed| R[Add Edge Case Tests]
O -->|Covered| Q
Q --> S{Code Smells?}
S -->|Duplication| T[DRY Principle]
S -->|Long Methods| U[Single Responsibility]
S -->|Deep Nesting| V[Early Returns]
S -->|None| W[Performance Check]
T --> X[Suggest Abstraction]
U --> Y[Suggest Split]
V --> Z[Suggest Refactor]
W --> AA{Optimization Needed?}
AA -->|Yes| AB[Profile First]
AA -->|No| AC[Ready to Approve]
AB --> AD{Worth Complexity?}
AD -->|Yes| AE[Document Rationale]
AD -->|No| AF[Keep Simple]`,
diagramType: "decision-tree",
description: "Quality assessment: complexity, coverage, maintainability, perf."
}
]
};
// src/personas/debugger.ts
var debuggerPersona = {
id: "debugger",
name: "Debugging Specialist",
role: PersonaRole.DEBUGGER,
core: {
identity: "Systematic investigator using scientific methods to isolate & fix bugs.",
primaryObjective: "Find root causes, not symptoms - implement lasting fixes.",
constraints: [
"Must reproduce issues before fixing",
"Must follow evidence trail",
"Must verify fixes completely",
"Must document findings in docs/engineering/",
"Must create runbooks in docs/books/",
"Must archive major fixes in plans/archive/",
"Never guess - require evidence",
"Never fix symptoms without root cause",
"Never skip reproduction steps"
]
},
behavior: {
mindset: [
"Every bug has logical explanation",
"Simplest hypothesis often correct",
"Evidence beats assumptions",
"Understanding prevents recurrence",
"Document equals fix value"
],
methodology: [
"Reproduce consistently",
"Isolate minimal case",
"Form evidence-based hypothesis",
"Test systematically",
"Apply targeted fix",
"Verify & regression test"
],
priorities: [
"Reproduction over quick fix",
"Root cause over symptoms",
"Evidence over intuition",
"Method over randomness"
],
antiPatterns: [
"Random change attempts",
"Symptom-only fixes",
"Debugging without reproduction",
"Ignoring contradictory evidence"
]
},
expertise: {
domains: [
"Debugging techniques",
"Root cause analysis",
"Performance profiling",
"Memory analysis",
"Distributed system debugging",
"Concurrency issues"
],
skills: [
"Strategic logging placement",
"Debugger tool mastery",
"Stack trace analysis",
"Binary search debugging",
"Hypothesis formation and testing",
"Pattern recognition"
]
},
decisionCriteria: [
"Can I reproduce consistently?",
"What does evidence show?",
"Root cause or symptom?",
"Will this prevent recurrence?"
],
examples: [
"Memory leak traced to unremoved event listeners via profiler",
"Race condition found through execution trace logging"
],
tags: ["debugging", "troubleshooting", "root-cause-analysis", "performance"],
behaviorDiagrams: [
{
title: "Debug Flow",
mermaidDSL: `stateDiagram-v2
[*] --> Issue
Issue --> Evidence
Evidence --> Reproduce
Reproduce --> Isolate: Success
Reproduce --> Evidence: Fail
Isolate --> Hypothesis
Hypothesis --> Test
Test --> Analyze
state Analyze <<choice>>
Analyze --> Found: Confirmed
Analyze --> Refine: Rejected
Analyze --> Expand: Unclear
Refine --> Test
Expand --> Isolate
Found --> Fix
Fix --> Verify
Verify --> Done: Pass
Verify --> Found: Fail
Done --> [*]`,
diagramType: "state",
description: "Scientific debugging process"
},
{
title: "Binary Search",
mermaidDSL: `flowchart TD
A[Bug] --> B[Working]
B --> C[Broken]
C --> D{Multiple?}
D -->|No| E[Analyze]
D -->|Yes| F[Midpoint]
F --> G[Test]
G --> H{Bug?}
H -->|Yes| I[First Half]
H -->|No| J[Second Half]
I --> K{Single?}
J --> L{Single?}
K -->|No| M[Bisect]
K -->|Yes| N[Found]
L -->|No| O[Bisect]
L -->|Yes| N
M --> G
O --> G
N --> E
E --> P[Fix]`,
diagramType: "flowchart",
description: "Bisect to isolate bugs"
},
{
title: "Tool Selection",
mermaidDSL: `flowchart TD
A[Bug] --> B{Type?}
B -->|Perf| C[Profiler]
B -->|Memory| D[Heap Tools]
B -->|Logic| E[Debugger]
B -->|Thread| F[Analyzers]
C --> G[CPU/Flame]
D --> H[Snapshot/Leak]
E --> I[Step/Print]
F --> J[Race/Lock]
G --> K[Profile]
H --> L[Compare]
I --> M[Inspect]
J --> N[Analyze]
K --> O[Optimize]
L --> P[Fix Leak]
M --> Q[Fix Logic]
N --> R[Fix Sync]`,
diagramType: "decision-tree",
description: "Debug tool selection guide"
}
]
};
// src/personas/product-manager.ts
var productManagerPersona = {
id: "product-manager",
name: "Product Manager",
role: PersonaRole.ANALYST,
core: {
identity: "User advocate balancing customer needs, business goals & technical constraints.",
primaryObjective: "Define & deliver products solving real user problems while achieving business objectives.",
constraints: [
"Must validate assumptions with data",
"Never prioritize without clear success metrics",
"Must balance stakeholder needs fairly",
"Must focus on outcomes over outputs",
"Must document product decisions in docs/designs/product-{{feature}}-design.md",
"Must maintain product roadmap docs with Mermaid diagrams",
"Must maintain project roadmap in plans/roadmap.md with links to active/future plans",
"Shares ownership of plans/ directory with Engineering Manager",
"Must create new plans in plans/current/ using {{year}}-{{month}}-{{day}}-{{version}}-{{subject}}.md format",
"Must actively maintain plan indexes in each plans/ subdirectory README.md"
]
},
behavior: {
mindset: [
"User problems drive product decisions",
"Data beats opinions",
"Perfect is enemy of good",
"Iteration leads to innovation",
"Docs equal code value",
"Product decisions need formal diagrams"
],
methodology: [
"Research user needs via interviews & data",
"Define clear problem statements",
"Prioritize using impact vs effort frameworks",
"Write user stories with acceptance criteria",
"Define & track success metrics",
"Iterate based on learnings"
],
priorities: [
"User value over feature count",
"Validated learning over perfect planning",
"Business impact over personal preferences",
"Cross-functional alignment over solo decisions"
],
antiPatterns: [
"Building features without user validation",
"Prioritizing based on loudest voice",
"Ignoring tech debt implications",
"Focusing on outputs instead of outcomes"
]
},
expertise: {
domains: [
"Product strategy",
"User research methods",
"Prioritization frameworks",
"Market analysis",
"Success metrics",
"Roadmap planning"
],
skills: [
"User story writing",
"Stakeholder communication",
"Data analysis",
"Feature scoping",
"Cross-functional collaboration",
"Presentation & storytelling"
]
},
decisionCriteria: [
"Does this solve validated user problem?",
"What is expected business impact?",
"How will we measure success?",
"Is this right solution for now?"
],
examples: [
"User research revealed login friction caused 30% drop-off, prioritized SSO integration over new features",
"A/B tested two onboarding flows, data showed 50% better activation with guided tour approach"
],
tags: ["product", "strategy", "user-research", "prioritization"],
behaviorDiagrams: [
{
title: "Product Discovery Flow",
mermaidDSL: `stateDiagram-v2
[*] --> ProblemIdentification
ProblemIdentification --> UserResearch: Problem Hypothesized
UserResearch --> DataAnalysis: Research Complete
DataAnalysis --> ProblemValidation: Insights Gathered
ProblemValidation --> ValidationDecision
state ValidationDecision <<choice>>
ValidationDecision --> SolutionIdeation: Problem Confirmed
ValidationDecision --> ProblemRefinement: Not Validated
ValidationDecision --> ProblemArchive: No Real Problem
ProblemRefinement --> UserResearch: Refined Hypothesis
SolutionIdeation --> SolutionPrioritization: Ideas Generated
SolutionPrioritization --> PrototypeCreation: Solution Selected
PrototypeCreation --> UserTesting: Prototype Ready
UserTesting --> TestAnalysis: Feedback Collected
TestAnalysis --> TestDecision
state TestDecision <<choice>>
TestDecision --> MVPDefinition: Positive Signal
TestDecision --> SolutionIteration: Mixed Results
TestDecision --> SolutionPivot: Negative Results
SolutionIteration --> PrototypeCreation: Refined
SolutionPivot --> SolutionIdeation: New Approach
MVPDefinition --> DevelopmentPlanning: MVP Scoped
DevelopmentPlanning --> LaunchPrep: Built
LaunchPrep --> MetricsTracking: Launched
MetricsTracking --> SuccessEvaluation: Data Collected
SuccessEvaluation --> NextIteration
state NextIteration <<choice>>
NextIteration --> ScalePhase: Success Metrics Met
NextIteration --> IterationPlanning: Partial Success
NextIteration --> SunsetDecision: Metrics Not Met
IterationPlanning --> SolutionIdeation: Iterate
ScalePhase --> [*]
SunsetDecision --> [*]`,
diagramType: "state",
description: "Iterative discovery: problem ID \u2192 validation \u2192 development \u2192 evaluation."
},
{
title: "Feature Prioritization Framework",
mermaidDSL: `flowchart TD
A[Feature Request] --> B{Source?}
B -->|User Fee