Skip to main content

Codebase Search Module

The Codebase Search module provides semantic code search capabilities, allowing agents to find relevant code snippets by natural language queries.

Overview

This module uses AI-powered semantic search to find code based on intent and meaning rather than exact text matches. It's ideal for:

  • Finding implementations of specific features
  • Locating related code patterns
  • Understanding how functionality is implemented
  • Discovering code examples

Quick Start

import codebolt from '@codebolt/codeboltjs';

// Search for authentication-related code
const results = await codebolt.codebaseSearch.search(
'user authentication login flow'
);

// Display results
for (const result of results.results) {
console.log(`File: ${result.file}`);
console.log(`Content: ${result.content}`);
console.log('---');
}

Available Methods

MethodDescription
search(query, targetDirectories?)Perform semantic code search
searchMcpTool(query, tags?)Search for MCP tools by query

Method Details

Performs a semantic search across the codebase.

const results = await codebolt.codebaseSearch.search(
'database connection handling',
['src/db', 'src/services'] // Optional: limit to specific directories
);

Parameters:

  • query (string) - Natural language search query
  • targetDirectories (string[], optional) - Directories to limit the search

Returns:

{
success: boolean;
results: CodeSearchResult[];
message?: string;
}

Result item:

{
file: string; // Path to the file
content: string; // Matching code snippet
language: string; // Programming language
startLine?: number; // Starting line number
endLine?: number; // Ending line number
score?: number; // Relevance score
}

searchMcpTool

Search for MCP tools by query and optional tags.

const tools = await codebolt.codebaseSearch.searchMcpTool(
'file operations',
['filesystem', 'io']
);

Advanced Examples

Example 1: Search with Result Ranking

const results = await codebolt.codebaseSearch.search('API endpoint validation');

// Rank results by relevance and file type
const ranked = results.results
.sort((a, b) => (b.score || 0) - (a.score || 0))
.map(result => ({
file: result.file,
score: result.score,
type: result.file.endsWith('.test.js') ? 'test' : 'source',
snippet: result.content.substring(0, 100)
}));

console.table(ranked);
async function searchWithVariations(query) {
const variations = [
query,
`${query} implementation`,
`how to ${query}`,
`${query} example`
];

const allResults = await Promise.all(
variations.map(q => codebolt.codebaseSearch.search(q))
);

// Deduplicate and merge results
const uniqueResults = new Map();
allResults.forEach(result => {
result.results.forEach(r => {
const key = `${r.file}:${r.startLine}`;
if (!uniqueResults.has(key)) {
uniqueResults.set(key, r);
}
});
});

return Array.from(uniqueResults.values());
}

// Usage
const results = await searchWithVariations('authenticate user');

Example 3: Search and Annotate

async function searchAndAnnotate(query) {
const results = await codebolt.codebaseSearch.search(query);

const annotated = results.results.map(result => {
// Get file structure for context
const jsTree = await codebolt.codeutils.getJsTree(result.file);

// Find containing function/class
let context = null;
if (jsTree.payload) {
const enclosing = jsTree.payload.structure.find(el =>
el.startLine <= result.startLine && el.endLine >= result.endLine
);
if (enclosing) {
context = {
type: enclosing.type,
name: enclosing.name,
line: enclosing.startLine
};
}
}

return {
...result,
context
};
});

return annotated;
}

Example 4: Fuzzy Search with Suggestions

async function smartSearch(query, threshold = 0.5) {
let results = await codebolt.codebaseSearch.search(query);

// If no results, try alternative queries
if (results.results.length === 0) {
console.log('No exact matches. Trying alternatives...');

const alternatives = [
query.split(' ').slice(0, -1).join(' '), // Remove last word
query.split(' ').slice(1).join(' '), // Remove first word
query.replace(/ing$/, ''), // Remove -ing suffix
];

for (const alt of alternatives) {
if (alt.length > 3) {
const altResults = await codebolt.codebaseSearch.search(alt);
if (altResults.results.length > 0) {
results = altResults;
console.log(`Found results using alternative query: "${alt}"`);
break;
}
}
}
}

return results;
}

Example 5: Search with Language Filtering

async function searchByLanguage(query, languages) {
const results = await codebolt.codebaseSearch.search(query);

const filtered = results.results.filter(result =>
languages.some(lang => {
const ext = result.file.split('.').pop();
return lang === ext || result.language === lang;
})
);

return {
success: true,
results: filtered,
totalResults: results.results.length,
filteredResults: filtered.length
};
}

// Usage
const typescriptResults = await searchByLanguage('authentication', ['ts', 'tsx']);

Example 6: Search with Pattern Matching

async function searchWithPattern(query, pattern) {
const results = await codebolt.codebaseSearch.search(query);

const patternMatches = results.results.filter(result => {
return result.content.match(pattern);
});

return {
success: true,
results: patternMatches,
metadata: {
totalMatches: results.results.length,
patternMatches: patternMatches.length,
pattern: pattern.toString()
}
};
}

// Usage: Find async functions that handle errors
const results = await searchWithPattern(
'error handling',
/async.*catch|try.*catch/g
);
async function incrementalSearch(baseQuery, additions) {
let currentResults = await codebolt.codebaseSearch.search(baseQuery);
const evolution = [{ query: baseQuery, count: currentResults.results.length }];

for (const addition of additions) {
const refinedQuery = `${baseQuery} ${addition}`;
const refinedResults = await codebolt.codebaseSearch.search(refinedQuery);

evolution.push({
query: refinedQuery,
count: refinedResults.results.length
});

currentResults = refinedResults;
}

return {
finalResults: currentResults,
evolution
};
}

// Usage
const results = await incrementalSearch('database', [
'connection',
'pool',
'retry logic'
]);

Example 8: Search with File Metadata

async function enrichedSearch(query) {
const [searchResults, markdown] = await Promise.all([
codebolt.codebaseSearch.search(query),
codebolt.codeutils.getAllFilesAsMarkDown()
]);

const enriched = searchResults.results.map(result => {
const fileMeta = markdown.files.find(f => f.path === result.file);

return {
...result,
metadata: {
totalLines: fileMeta?.content.split('\n').length || 0,
language: fileMeta?.language || result.language,
size: fileMeta?.content.length || 0
}
};
});

return enriched;
}

Advanced Usage Patterns

async function contextAwareSearch(query, contextFile) {
// Get context from current file
const contextResult = await codebolt.codebaseSearch.search(
`in ${contextFile}: ${query}`
);

// Also search globally
const globalResult = await codebolt.codebaseSearch.search(query);

// Combine and prioritize local results
return {
local: contextResult.results.filter(r =>
r.file === contextFile || r.file.startsWith(path.dirname(contextFile))
),
global: globalResult.results.filter(r =>
!contextResult.results.some(cr => cr.file === r.file)
)
};
}

Pattern 2: Refinement Loop

async function refinementLoop(initialQuery) {
let query = initialQuery;
let results = await codebolt.codebaseSearch.search(query);
let iterations = 0;
const maxIterations = 5;

while (results.results.length > 20 && iterations < maxIterations) {
console.log(`Iteration ${iterations + 1}: ${results.results.length} results`);

// Analyze results to suggest refinements
const commonWords = extractCommonWords(results.results.map(r => r.content));
const refinement = commonWords[0]; // Most common word

query = `${query} ${refinement}`;
results = await codebolt.codebaseSearch.search(query);
iterations++;
}

return {
finalQuery: query,
results: results.results,
iterations
};
}

function extractCommonWords(texts) {
const words = texts.flatMap(t =>
t.toLowerCase().match(/\b\w{4,}\b/g) || []
);
const frequency = {};
words.forEach(w => frequency[w] = (frequency[w] || 0) + 1);
return Object.entries(frequency)
.sort((a, b) => b[1] - a[1])
.map(e => e[0]);
}
async function crossReferenceSearch(query) {
// Find implementations
const implResults = await codebolt.codebaseSearch.search(
`${query} implementation`
);

// Find tests
const testResults = await codebolt.codebaseSearch.search(
`${query} test`
);

// Find documentation
const docResults = await codebolt.codebaseSearch.search(
`${query} documentation comment`
);

return {
implementations: implResults.results,
tests: testResults.results,
documentation: docResults.results,
summary: {
hasImpl: implResults.results.length > 0,
hasTests: testResults.results.length > 0,
hasDocs: docResults.results.length > 0,
coverage: testResults.results.length / Math.max(implResults.results.length, 1)
}
};
}

Pattern 4: Semantic Code Navigation

async function semanticNavigation(startQuery) {
const visited = new Set();
const queue = [startQuery];
const graph = {};

while (queue.length > 0 && visited.size < 20) {
const query = queue.shift();
if (visited.has(query)) continue;

visited.add(query);
const results = await codebolt.codebaseSearch.search(query);

graph[query] = results.results;

// Extract related concepts from results
const related = extractRelatedConcepts(results.results);
related.forEach(r => {
if (!visited.has(r)) queue.push(r);
});
}

return graph;
}

function extractRelatedConcepts(results) {
// Simple concept extraction based on file names and content
const concepts = new Set();
results.forEach(r => {
const words = r.content.match(/\b[A-Z][a-z]+\b/g) || [];
words.forEach(w => concepts.add(w));
});
return Array.from(concepts).slice(0, 5);
}

Error Handling Examples

Handle No Results

async function searchWithFallback(query) {
const results = await codebolt.codebaseSearch.search(query);

if (results.results.length === 0) {
console.warn('No results found. Trying broader search...');

// Try splitting query into keywords
const keywords = query.split(' ').filter(w => w.length > 3);
if (keywords.length > 0) {
const fallbackResults = await codebolt.codebaseSearch.search(
keywords[0]
);

if (fallbackResults.results.length > 0) {
return {
...fallbackResults,
fallback: true,
originalQuery: query,
fallbackQuery: keywords[0]
};
}
}

return {
success: false,
results: [],
message: `No results found for "${query}" or alternatives`
};
}

return results;
}

Handle Invalid Queries

async function validateAndSearch(query) {
if (!query || typeof query !== 'string') {
throw new Error('Query must be a non-empty string');
}

if (query.length < 3) {
throw new Error('Query must be at least 3 characters long');
}

// Remove special characters that might cause issues
const sanitized = query.replace(/[^\w\s]/g, '').trim();

if (sanitized.length === 0) {
throw new Error('Query contains no valid search terms');
}

return await codebolt.codebaseSearch.search(sanitized);
}

Handle Network Errors

async function resilientSearch(query, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await codebolt.codebaseSearch.search(query);
} catch (error) {
if (i === maxRetries - 1) {
throw new Error(`Search failed after ${maxRetries} attempts: ${error.message}`);
}

console.warn(`Search attempt ${i + 1} failed, retrying...`);
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}

Performance Considerations

  1. Query Complexity:

    • Longer, more specific queries often yield better results
    • Avoid overly generic terms (e.g., "function", "variable")
    • Use domain-specific terminology when possible
  2. Result Caching:

    class SearchCache {
    constructor() {
    this.cache = new Map();
    this.ttl = 60000; // 1 minute
    }

    async search(query) {
    const key = query.toLowerCase();
    const cached = this.cache.get(key);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
    return cached.results;
    }

    const results = await codebolt.codebaseSearch.search(query);
    this.cache.set(key, { results, timestamp: Date.now() });
    return results;
    }
    }
  3. Batch Searches:

    async function batchSearch(queries) {
    const results = await Promise.all(
    queries.map(q => codebolt.codebaseSearch.search(q))
    );

    return results;
    }
  4. Scoped Searches:

    • Use targetDirectories to limit search scope
    • Reduces processing time and improves result relevance
    • Particularly useful in large codebases

Common Pitfalls

Pitfall 1: Too Generic Queries

// ❌ Incorrect - too generic
const results = await codebolt.codebaseSearch.search('function');

// ✅ Correct - specific and descriptive
const results = await codebolt.codebaseSearch.search('authenticate user with JWT token');

Pitfall 2: Ignoring Result Scores

// ❌ Incorrect - treats all results equally
const results = await codebolt.codebaseSearch.search('API');
results.results.forEach(r => processResult(r));

// ✅ Correct - prioritizes high-score results
const results = await codebolt.codebaseSearch.search('API');
const sorted = results.results.sort((a, b) => (b.score || 0) - (a.score || 0));
sorted.slice(0, 10).forEach(r => processResult(r));

Pitfall 3: Not Validating Results

// ❌ Incorrect - assumes results are valid
const results = await codebolt.codebaseSearch.search('database');
const fileContent = await readFile(results.results[0].file);

// ✅ Correct - validates results
const results = await codebolt.codebaseSearch.search('database');

if (results.results.length > 0) {
const firstResult = results.results[0];

if (firstResult.file && firstResult.content) {
const fileContent = await readFile(firstResult.file);
// Process file content
} else {
console.error('Invalid result format');
}
} else {
console.error('No results found');
}

Pitfall 4: Over-Refining Queries

// ❌ Incorrect - adds too many constraints
const results = await codebolt.codebaseSearch.search(
'database connection pool retry logic timeout error handling async await typescript'
); // May return no results

// ✅ Correct - starts broad, refines gradually
let results = await codebolt.codebaseSearch.search('database connection');
if (results.results.length > 50) {
results = await codebolt.codebaseSearch.search('database connection pool');
}

Module Integration Examples

Integration 1: CodebaseSearch + Codeutils

async function searchAndAnalyze(query) {
const [searchResults, markdown] = await Promise.all([
codebolt.codebaseSearch.search(query),
codebolt.codeutils.getAllFilesAsMarkDown()
]);

const analyzed = searchResults.results.map(result => {
const fileMeta = markdown.files.find(f => f.path === result.file);

return {
...result,
fileContext: {
totalLines: fileMeta?.content.split('\n').length || 0,
language: fileMeta?.language,
containsTests: fileMeta?.path.includes('test') || false
}
};
});

return analyzed;
}

Integration 2: CodebaseSearch + Codemap

async function searchAndMap(query) {
const searchResults = await codebolt.codebaseSearch.search(query);

// Create a codemap showing related files
const codemap = await codebolt.codemap.create({
title: `Search Results: ${query}`,
query: `Files related to "${query}"`
});

const structure = {
query,
files: searchResults.results.map(r => ({
path: r.file,
relevance: r.score,
snippet: r.content.substring(0, 200)
}))
};

await codebolt.codemap.save(codemap.codemap.id, {
id: codemap.codemap.id,
title: `Search Results: ${query}`,
structure
});

return codemap;
}

Integration 3: CodebaseSearch + ProjectStructure

async function searchInPackage(query, packageName) {
const [searchResults, structure] = await Promise.all([
codebolt.codebaseSearch.search(query),
codebolt.projectStructure.getMetadata()
]);

const pkg = structure.metadata.packages.find(p => p.name === packageName);

if (!pkg) {
throw new Error(`Package ${packageName} not found`);
}

const packageResults = searchResults.results.filter(r =>
r.file.startsWith(pkg.path)
);

return {
package: pkg.name,
query,
results: packageResults,
totalResults: searchResults.results.length,
packageResults: packageResults.length
};
}

Common Use Cases

Find Implementation

// Find how error handling is implemented
const results = await codebolt.codebaseSearch.search(
'global error handler middleware exception'
);

Explore Patterns

// Find validation patterns
const validation = await codebolt.codebaseSearch.search(
'input validation sanitize user data'
);
// Search only in test files
const tests = await codebolt.codebaseSearch.search(
'user registration test',
['tests', '__tests__', 'spec']
);