Claude Skills Guide

AST-based code search transforms how developers find and modify code. Unlike simple text search, Abstract Syntax Tree (AST) analysis understands code structure, making it possible to locate specific patterns, functions, or constructs regardless of formatting or variable names. When combined with Claude Code’s AI capabilities, you get a powerful workflow for code analysis, refactoring, and maintenance tasks.

This guide walks you through building an effective AST-based code search workflow using Claude Code, with practical examples you can apply immediately to your projects.

Traditional text search looks for literal string matches. Search for function foo() and you miss function bar() or const foo = () => {}. AST search understands that all three are function declarations—it searches by code structure, not just characters.

Consider a common scenario: finding all React components that use useState but lack proper type annotations. Text search can’t reliably solve this. AST search can traverse the syntax tree, identify hooks, and check their context.

Claude Code can help you construct AST queries, interpret results, and even generate refactoring scripts based on findings. This is invaluable for large-scale code changes like upgrading dependencies, enforcing patterns, or identifying technical debt.

Setting Up Your AST Search Environment

Before diving into workflows, ensure your environment supports AST parsing. Most modern languages have established tools:

For JavaScript/TypeScript, use @babel/parser or typescript-eslint. For Python, the built-in ast module works well. Rust projects benefit from rust-analyzer, while Go has go/ast.

Create a Claude Code skill to wrap your preferred AST tools. Here’s a foundational setup for JavaScript/TypeScript projects:

// ast-search-skill.js - Core AST search utilities
import { parse } from '@babel/parser';
import traverse from '@babel/traverse';

export function findNodesByType(code, nodeType) {
  const ast = parse(code, {
    sourceType: 'module',
    plugins: ['typescript', 'jsx']
  });
  
  const results = [];
  
  traverse(ast, {
    [nodeType](path) {
      results.push({
        node: path.node,
        location: path.node.loc,
        code: code.slice(path.node.start, path.node.end)
      });
    }
  });
  
  return results;
}

export function findFunctionsWithoutTypes(code) {
  const ast = parse(code, {
    sourceType: 'module',
    plugins: ['typescript']
  });
  
  const results = [];
  
  traverse(ast, {
    FunctionDeclaration(path) {
      if (!path.node.returnType && !path.node.typeAnnotation) {
        results.push({
          name: path.node.id?.name,
          location: path.node.loc,
          line: path.node.loc.start.line
        });
      }
    }
  });
  
  return results;
}

This setup gives you reusable functions for common search patterns. Save this as a skill that Claude Code can invoke during your workflow.

Building Search Queries That Matter

Effective AST queries require understanding what you actually want to find. Start with specific, actionable questions:

Finding all console.log statements for removal before production:

traverse(ast, {
  CallExpression(path) {
    const callee = path.node.callee;
    if (callee.object?.name === 'console' && callee.property?.name === 'log') {
      results.push({ line: path.node.loc.start.line, code: getSnippet(path) });
    }
  }
});

Identifying potential security issues like unsanitized SQL queries:

traverse(ast, {
  CallExpression(path) {
    if (path.node.callee.name === 'query' || path.node.callee.name === 'execute') {
      const args = path.node.arguments;
      if (args.some(arg => arg.type === 'TemplateLiteral')) {
        results.push({ 
          location: path.node.loc,
          risk: 'potential SQL injection'
        });
      }
    }
  }
});

Finding dead code—functions never called elsewhere:

// First pass: collect all function names defined
// Second pass: collect all function references
// Functions in defined but not referenced are dead code

The key is building a library of queries for your specific needs. As your codebase evolves, add new patterns to catch emerging issues.

Integrating with Claude Code Workflows

Now integrate these search capabilities into Claude Code’s conversational interface. Create a skill file that defines your search commands:

name: AST Code Search
description: Search and analyze code using AST patterns
commands:
  find-dead-code:
    description: "Find unused functions in the codebase"
    action: run-ast-query dead-code
  
  find-console-logs:
    description: "Locate all console.log statements"
    action: run-ast-query console-logs
  
  find-unsafe-queries:
    description: "Identify potential SQL injection risks"
    action: run-ast-query unsafe-sql

When you invoke these commands, Claude Code executes the corresponding AST queries and presents results in a readable format. You can then ask follow-up questions like “Which of these are in production code?” or “Generate a refactoring script to remove these.”

Practical Workflow Example: Component Audit

Let’s walk through a real workflow: auditing a React codebase for performance issues. You want to find all class components that should be converted to functional components.

  1. Define your search criteria: Class components with only render method, components using componentDidMount without cleanup, or components with local state but no memoization.

  2. Execute AST queries:
    // Find all class components
    traverse(ast, {
      ClassDeclaration(path) {
     if (path.node.superClass?.name === 'Component' || 
         path.node.superClass?.name === 'PureComponent') {
       results.push({ name: path.node.id.name, type: 'class' });
     }
      }
    });
    
  3. Analyze results: Claude Code can help categorize findings and estimate refactoring effort based on component complexity.

  4. Generate action items: Export results to a task list or directly create refactoring branches.

Advanced Patterns: Cross-File Analysis

Single-file AST search is powerful, but cross-file analysis reveals patterns invisible to isolated analysis. Build workflows that:

For cross-file analysis, first build an index of your codebase:

// Build codebase index
const index = {};
for (const file of sourceFiles) {
  const ast = parse(readFile(file));
  index[file] = {
    exports: [],
    imports: [],
    definitions: []
  };
  
  traverse(ast, {
    ExportNamedDeclaration(path) {
      index[file].exports.push(extractExportInfo(path));
    },
    ImportDeclaration(path) {
      index[file].imports.push({
        source: path.node.source.value,
        specifiers: path.node.specifiers.map(s => s.local.name)
      });
    }
  });
}

With this index, you can answer complex questions: “Which files import the deprecated utility?” or “What components depend on this context?”

Actionable Advice for Getting Started

Start simple. Pick one recurring code quality issue in your project and build an AST query for it. Test it on a sample of files. Refine until it catches what you need without false positives.

Build a library of reusable queries over time. As your codebase grows, so does the value of having quick answers to “where is this pattern used?” or “what needs updating for this API change?”

Integrate AST search into your CI pipeline for automated enforcement. Run queries for critical patterns on every pull request. Catch issues before they reach production.

Finally, combine AST search with Claude Code’s AI capabilities. Use natural language to refine queries, explain results, and generate fixes. The combination of structural search and AI understanding creates a workflow that’s greater than either approach alone.

Start with one query, refine it, and expand from there. Your future self will thank you when the next major refactoring takes hours instead of weeks.