show_conflicts
Identify disagreements among AI models on technology choices, approach, and assumptions from Round 1 of a multi-model planning session.
Instructions
Show all points where models disagreed in Round 1 — technology choices, approach, and assumption conflicts
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| modelName | No | Your model name (optional) |
Implementation Reference
- src/server.ts:204-216 (registration)Registration of the 'show_conflicts' tool on the MCP server. Defines the schema (optional modelName) and the handler that calls executeConflicts().
// ─── show_conflicts ─────────────────────────────────────────────── server.tool( "show_conflicts", "Show all points where models disagreed in Round 1 — technology choices, approach, and assumption conflicts", { modelName: z.string().optional().describe("Your model name (optional)"), }, async (params, extra) => { const identity = detectCaller(server.server.getClientVersion(), params.modelName); const formatted = await executeConflicts(projectRoot, identity); return { content: [{ type: "text", text: formatted }] }; } ); - src/tools/conflicts.ts:16-38 (handler)The executeConflicts function that orchestrates conflict detection. Reads round 1 plans, calls detectConflicts and formatConflicts from the engine, logs the action, and returns the formatted result.
export async function executeConflicts( projectRoot: string, identity: CallerIdentity ): Promise<string> { const round1Plans = await readPlansByRound(projectRoot, "round1"); if (round1Plans.length < 2) { return `Need at least 2 Round 1 plans to detect conflicts. Currently have ${round1Plans.length}.`; } const conflicts = detectConflicts(round1Plans); const formatted = formatConflicts(conflicts, "Round 1"); await logAction( projectRoot, identity.cliTool, identity.modelName, "conflicts", `Analyzed conflicts: ${conflicts.length} found across ${round1Plans.length} plans` ); return formatted; } - src/server.ts:208-209 (schema)Input schema for show_conflicts: optional modelName string parameter.
{ modelName: z.string().optional().describe("Your model name (optional)"), - src/core/conflictEngine.ts:180-229 (helper)Core conflict detection logic: compares keyword-based technology choices across plans to find disagreements.
export function detectConflicts(plans: PlanFile[]): Conflict[] { if (plans.length < 2) return []; const conflicts: Conflict[] = []; // Collect mentions per plan const planMentions = plans.map((plan) => ({ identifier: `${plan.cliTool}-${plan.modelName}`, mentions: detectMentions(plan.content, TECH_CATEGORIES), })); // Check each category for disagreement for (const category of TECH_CATEGORIES) { const positions: Record<string, string> = {}; const allChoices = new Set<string>(); for (const pm of planMentions) { const mentions = pm.mentions.get(category.name); if (mentions && mentions.length > 0) { const choice = mentions.join(" + "); positions[pm.identifier] = choice; allChoices.add(choice); } } // Conflict only if 2+ models mentioned this category AND they disagree const modelsThatMentioned = Object.keys(positions); if (modelsThatMentioned.length >= 2 && allChoices.size >= 2) { // Count votes per choice const voteCounts = new Map<string, number>(); for (const choice of Object.values(positions)) { voteCounts.set(choice, (voteCounts.get(choice) ?? 0) + 1); } // Build summary const sortedChoices = [...voteCounts.entries()].sort((a, b) => b[1] - a[1]); const summary = sortedChoices .map(([choice, count]) => `${count} model(s) prefer ${choice}`) .join(", "); conflicts.push({ category: category.name, positions, summary, }); } } return conflicts; } - src/core/conflictEngine.ts:234-255 (helper)Formats detected conflicts into a human-readable string for display.
export function formatConflicts(conflicts: Conflict[], round: string): string { if (conflicts.length === 0) { return `✅ No conflicts detected across ${round} plans. All models are in agreement on technology choices.`; } const lines: string[] = []; lines.push(`CONFLICTS DETECTED — ${round}`); lines.push(""); conflicts.forEach((conflict, index) => { lines.push(`[CONFLICT ${index + 1}] ${conflict.category}`); for (const [model, position] of Object.entries(conflict.positions)) { lines.push(` ${model.padEnd(28)} ${position}`); } lines.push(` → ${conflict.summary}`); lines.push(""); }); lines.push("These conflicts will be surfaced to the Final round model for resolution."); return lines.join("\n"); }