Skip to main content
Glama

find_tool_patterns

Analyze tool usage patterns, workflows, and successful practices from Claude Code conversation history to identify effective approaches.

Instructions

Analyze tool usage patterns, workflows, and successful practices

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tool_nameNoOptional specific tool name to analyze
pattern_typeNoType of patterns: tools, workflows, or solutionstools
limitNoMaximum number of patterns (default: 12)

Implementation Reference

  • MCP CallToolRequest handler for find_tool_patterns: delegates to UniversalHistorySearchEngine.getToolPatterns, formats with BeautifulFormatter
    case 'find_tool_patterns': { const universalResult = await this.universalEngine.getToolPatterns( args?.tool_name as string, (args?.limit as number) || 12 ); const patternType = (args?.pattern_type as string) || 'tools'; const formattedResult = this.formatter.formatToolPatterns( universalResult.results as any, args?.tool_name as string, patternType ); return { content: [{ type: 'text', text: formattedResult }], }; }
  • Input schema definition for find_tool_patterns tool in ListTools response
    name: 'find_tool_patterns', description: 'Analyze tool usage patterns, workflows, and successful practices', inputSchema: { type: 'object', properties: { tool_name: { type: 'string', description: 'Optional specific tool name to analyze', }, pattern_type: { type: 'string', description: 'Type of patterns: tools, workflows, or solutions', enum: ['tools', 'workflows', 'solutions'], default: 'tools', }, limit: { type: 'number', description: 'Maximum number of patterns (default: 12)', default: 12, }, }, }, },
  • Core implementation in HistorySearchEngine.getToolPatterns: scans conversation history, identifies tool usage patterns and workflows, constructs ToolPattern results
    async getToolPatterns(toolName?: string, limit: number = 20): Promise<ToolPattern[]> { const toolMap = new Map<string, CompactMessage[]>(); const workflowMap = new Map<string, CompactMessage[]>(); try { const projectDirs = await findProjectDirectories(); const limitedDirs = projectDirs.slice(0, 15); // Focus on core Claude Code tools that GLOBAL would recognize const coreTools = new Set([ 'Edit', 'Read', 'Bash', 'Grep', 'Glob', 'Write', 'Task', 'MultiEdit', 'Notebook', ]); // PARALLEL PROCESSING: Process all projects concurrently const projectResults = await Promise.allSettled( limitedDirs.map(async (projectDir) => { const jsonlFiles = await findJsonlFiles(projectDir); const limitedFiles = jsonlFiles.slice(0, 8); const projectToolMap = new Map<string, CompactMessage[]>(); const projectWorkflowMap = new Map<string, CompactMessage[]>(); // PARALLEL: Process files within project simultaneously const fileResults = await Promise.allSettled( limitedFiles.map(async (file) => { const messages = await this.parser.parseJsonlFile(projectDir, file); // Extract individual tool usage patterns for (const msg of messages) { if (msg.context?.toolsUsed?.length) { for (const tool of msg.context.toolsUsed) { // If toolName specified, only track that tool // Otherwise, track all core tools const shouldTrack = toolName ? tool === toolName : coreTools.has(tool); if (shouldTrack) { if (!projectToolMap.has(tool)) { projectToolMap.set(tool, []); } projectToolMap.get(tool)!.push(msg); } } } } // Extract workflow patterns (tool sequences) for (let i = 0; i < messages.length - 1; i++) { const current = messages[i]; const next = messages[i + 1]; if (current.context?.toolsUsed?.length && next.context?.toolsUsed?.length) { // Create focused workflow patterns for (const currentTool of current.context.toolsUsed) { for (const nextTool of next.context.toolsUsed) { // If toolName specified, workflow must involve that tool // Otherwise, workflows between core tools const shouldTrack = toolName ? currentTool === toolName || nextTool === toolName : coreTools.has(currentTool) && coreTools.has(nextTool); if (shouldTrack) { const workflowKey = `${currentTool} → ${nextTool}`; if (!projectWorkflowMap.has(workflowKey)) { projectWorkflowMap.set(workflowKey, []); } projectWorkflowMap.get(workflowKey)!.push(current, next); } } } } } // Also create longer sequences for complex workflows for (let i = 0; i < messages.length - 2; i++) { const first = messages[i]; const second = messages[i + 1]; const third = messages[i + 2]; if ( first.context?.toolsUsed?.length && second.context?.toolsUsed?.length && third.context?.toolsUsed?.length ) { for (const firstTool of first.context.toolsUsed) { for (const secondTool of second.context.toolsUsed) { for (const thirdTool of third.context.toolsUsed) { // If toolName specified, 3-step workflow must involve that tool const shouldTrack = toolName ? firstTool === toolName || secondTool === toolName || thirdTool === toolName : coreTools.has(firstTool) && coreTools.has(secondTool) && coreTools.has(thirdTool); if (shouldTrack) { const workflowKey = `${firstTool} → ${secondTool} → ${thirdTool}`; if (!projectWorkflowMap.has(workflowKey)) { projectWorkflowMap.set(workflowKey, []); } projectWorkflowMap.get(workflowKey)!.push(first, second, third); } } } } } } }) ); return { tools: projectToolMap, workflows: projectWorkflowMap }; }) ); // Aggregate results from parallel processing for (const result of projectResults) { if (result.status === 'fulfilled') { // Aggregate individual tools for (const [tool, messages] of result.value.tools.entries()) { if (!toolMap.has(tool)) { toolMap.set(tool, []); } toolMap.get(tool)!.push(...messages); } // Aggregate workflows for (const [workflow, messages] of result.value.workflows.entries()) { if (!workflowMap.has(workflow)) { workflowMap.set(workflow, []); } workflowMap.get(workflow)!.push(...messages); } } } const patterns: ToolPattern[] = []; // ENHANCED: Create diverse patterns like GLOBAL showing related tools with workflows const toolFrequency = new Map<string, number>(); // First pass: Calculate tool frequencies for prioritization for (const [tool, messages] of toolMap.entries()) { toolFrequency.set(tool, messages.length); } // Add diverse individual tool patterns (different tools, not just highest frequency) const usedTools = new Set<string>(); for (const [tool, messages] of Array.from(toolMap.entries()).sort( (a, b) => b[1].length - a[1].length )) { if (messages.length >= 1 && !usedTools.has(tool) && patterns.length < limit) { const uniqueMessages = SearchHelpers.deduplicateByContent(messages); // Extract actual patterns and practices instead of generic text const actualPatterns = this.extractActualToolPatterns(tool, uniqueMessages); const actualPractices = this.extractActualBestPractices(tool, uniqueMessages); patterns.push({ toolName: tool, successfulUsages: uniqueMessages.slice(0, 10), commonPatterns: actualPatterns.length > 0 ? actualPatterns : [`${tool} usage pattern`], bestPractices: actualPractices.length > 0 ? actualPractices : [`${tool} used ${uniqueMessages.length}x successfully`], }); usedTools.add(tool); } } // Add related workflow patterns for each tool (like GLOBAL's approach) for (const tool of usedTools) { // Find workflows involving this tool for (const [workflow, messages] of workflowMap.entries()) { if (workflow.includes(tool) && workflow.includes('→') && messages.length >= 1) { const uniqueMessages = SearchHelpers.deduplicateByContent(messages); // Only add if not already added and we have space if (!patterns.some((p) => p.toolName === workflow) && patterns.length < limit) { patterns.push({ toolName: workflow, successfulUsages: uniqueMessages.slice(0, 10), commonPatterns: [workflow], bestPractices: [`${workflow} workflow (${uniqueMessages.length}x successful)`], }); } } } } // If we still have space, add any remaining high-frequency workflows for (const [workflow, messages] of Array.from(workflowMap.entries()).sort( (a, b) => b[1].length - a[1].length )) { if (workflow.includes('→') && messages.length >= 1 && patterns.length < limit) { if (!patterns.some((p) => p.toolName === workflow)) { const uniqueMessages = SearchHelpers.deduplicateByContent(messages); patterns.push({ toolName: workflow, successfulUsages: uniqueMessages.slice(0, 10), commonPatterns: [workflow], bestPractices: [`${workflow} workflow (${uniqueMessages.length}x successful)`], }); } } } // Sort to prioritize individual tools, then their related workflows return patterns .sort((a, b) => { const aIsWorkflow = a.toolName.includes('→'); const bIsWorkflow = b.toolName.includes('→'); // Individual tools first, then workflows, then by usage frequency if (aIsWorkflow !== bIsWorkflow) { return aIsWorkflow ? 1 : -1; } return b.successfulUsages.length - a.successfulUsages.length; }) .slice(0, limit); } catch (error) { console.error('Tool pattern search error:', error); return []; } }
  • UniversalHistorySearchEngine.getToolPatterns delegates to HistorySearchEngine.getToolPatterns
    async getToolPatterns(toolName?: string, limit?: number): Promise<UniversalSearchResult> { await this.initialize(); const claudeCodePatterns = await this.claudeCodeEngine.getToolPatterns(toolName, limit || 12); if (!this.claudeDesktopAvailable) { return { source: 'claude-code', results: claudeCodePatterns as any, enhanced: false, }; } // For tool patterns, Desktop doesn't have tool usage data, so we focus on Code // But we mark as enhanced if Desktop is available for future Desktop tool analysis return { source: 'claude-code', results: claudeCodePatterns as any, enhanced: this.claudeDesktopAvailable, }; }
  • BeautifulFormatter.formatToolPatterns: formats and ranks tool pattern results for output
    formatToolPatterns( patterns: ToolPattern[], toolName?: string, _patternType: string = 'tools' ): string { const filter = toolName ? `"${toolName}"` : 'all'; const header = `${robots.toolPatterns} ${filter} | ${patterns.length} patterns`; if (patterns.length === 0) { return `${header}\n\n{"patterns":[]}`; } const rankedPatterns = this.rankToolPatternsByValue(patterns); const topPatterns = rankedPatterns.slice(0, 8); const structured = { tool: toolName || 'all', patterns: topPatterns.map((p) => ({ name: p.toolName, uses: p.successfulUsages.length, workflow: p.commonPatterns[0] || null, practice: p.bestPractices[0] || null, example: p.successfulUsages[0]?.content || null, ctx: p.successfulUsages[0]?.context || null, })), }; return `${header}\n\n${JSON.stringify(structured, null, 2)}`; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vvkmnn/claude-historian'

If you have feedback or need assistance with the MCP directory API, please join our Discord server