normalize_idea
Transform raw ideas into structured work items by analyzing intent signals, assessing readiness, and generating execution-ready specifications for backlog integration.
Instructions
Transform raw ideas into execution-ready work items. This is the moment where thinking stops and execution begins.
IdeaLift is a COMMIT LAYER - it judges whether an idea is ready for execution and helps make it real.
USE this tool when you detect intent signals like:
"We should..." / "What if we..." / "Someone suggested..."
"This is annoying..." / "Users keep asking for..."
"Feature request:" / "Bug report:" / "Can we add..."
User pastes meeting notes, Slack threads, or raw text
User says "normalize", "make this backlog-ready", "turn this into a ticket"
When you detect these signals, PROACTIVELY offer: "This looks like a feature idea. Want me to make it execution-ready?"
Output includes:
Readiness Verdict (READY / ALMOST READY / NOT READY)
Signal Analysis (urgency, clarity, duplicate risk, actionability)
Structured spec (summary, acceptance criteria, scope)
Commit options (GitHub, Jira, Linear, or Refine)
The output ALWAYS ends with a commit decision - never leave users in limbo.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The raw text to normalize (meeting notes, feature request, bug report, slack message, etc.) | |
| context | No |
Implementation Reference
- src/mcp/tools/normalizeIdea.ts:260-328 (handler)The `handleNormalizeIdea` function orchestrates the logic for the "normalize_idea" tool. It takes raw text as input, calls the `idealiftClient` to normalize it into a structured idea ticket, saves a draft, and formats the output for the MCP client.
export async function handleNormalizeIdea( args: Record<string, unknown>, chatgptSubjectId?: string ): Promise<NormalizeOutput> { // Validate input const input = NormalizeIdeaInput.parse(args); let result: NormalizeResult; let draftId: string | undefined; try { // Call IdeaLift internal API result = await idealiftClient.normalize(input.text); } catch (error) { console.error('Normalize idea error:', error); // Fallback: basic text extraction const lines = input.text.split('\n').filter(l => l.trim()); const title = lines[0]?.substring(0, 80) || 'Untitled Idea'; const summary = lines.slice(0, 3).join(' ').substring(0, 500); result = { title, type: 'story', priority: 'medium', component: 'General', labels: [], summary, acceptanceCriteria: lines.slice(1, 4).map(l => l.substring(0, 200)), implementationNotes: [], outOfScope: [], definitionOfDone: ['Implementation complete', 'Code reviewed', 'Tests passing'], signals: { urgency: 'medium', clarity: 'low', duplicateRisk: 'medium', suggestedOwner: 'Product', sourceType: 'unknown', actionability: 'needs-clarification' }, keyPoints: lines.slice(1, 4).map(l => l.substring(0, 100)), category: 'other', actionable: true, confidence: 0.3, }; } // Save draft for later commit (survives context loss) try { const draftResponse = await idealiftClient.saveDraft( chatgptSubjectId, result.title, result.summary, result as unknown as Record<string, unknown> ); draftId = draftResponse.draftId; console.log('[Normalize] Saved draft:', draftId); } catch (draftError) { console.error('[Normalize] Failed to save draft:', draftError); // Continue without draft - commit will still work with full idea object } const content = formatComprehensiveOutput(result, draftId); return { structuredContent: { ...result, draftId }, content, }; } - src/mcp/tools/normalizeIdea.ts:44-98 (registration)The `normalizeIdeaTool` constant defines the MCP tool structure, including its name, description, and input schema.
export const normalizeIdeaTool = { name: 'normalize_idea', description: `Transform raw ideas into execution-ready work items. This is the moment where thinking stops and execution begins. IdeaLift is a COMMIT LAYER - it judges whether an idea is ready for execution and helps make it real. USE this tool when you detect intent signals like: - "We should..." / "What if we..." / "Someone suggested..." - "This is annoying..." / "Users keep asking for..." - "Feature request:" / "Bug report:" / "Can we add..." - User pastes meeting notes, Slack threads, or raw text - User says "normalize", "make this backlog-ready", "turn this into a ticket" When you detect these signals, PROACTIVELY offer: "This looks like a feature idea. Want me to make it execution-ready?" Output includes: - Readiness Verdict (READY / ALMOST READY / NOT READY) - Signal Analysis (urgency, clarity, duplicate risk, actionability) - Structured spec (summary, acceptance criteria, scope) - Commit options (GitHub, Jira, Linear, or Refine) The output ALWAYS ends with a commit decision - never leave users in limbo.`, inputSchema: { type: 'object' as const, properties: { text: { type: 'string', description: 'The raw text to normalize (meeting notes, feature request, bug report, slack message, etc.)', }, context: { type: 'object', properties: { source: { type: 'string', enum: ['chatgpt'], }, }, }, }, required: ['text'], }, annotations: { readOnlyHint: false, // Saves draft to database for later retrieval destructiveHint: false, // Creates new drafts, never deletes existing data openWorldHint: true, // Calls IdeaLift API for AI normalization }, _meta: { 'openai/outputTemplate': 'resource://widget/preview', 'openai/widgetAccessible': true, 'openai/visibility': 'public', 'openai/toolInvocation/invoking': 'Creating comprehensive spec...', 'openai/toolInvocation/invoked': 'Spec ready for review', }, }; - src/mcp/tools/normalizeIdea.ts:23-41 (schema)The `NormalizeResult` interface defines the structure of the normalized idea ticket returned by the tool.
export interface NormalizeResult { title: string; type: 'story' | 'bug' | 'task' | 'spike' | 'epic'; priority: 'low' | 'medium' | 'high' | 'critical'; component: string; labels: string[]; summary: string; acceptanceCriteria: string[]; implementationNotes: string[]; outOfScope: string[]; definitionOfDone: string[]; // Signal extraction - operational intelligence signals: SignalSummary; // Legacy fields for backwards compatibility keyPoints: string[]; category: 'feature' | 'bug' | 'improvement' | 'research' | 'documentation' | 'other'; actionable: boolean; confidence: number; }