Skip to content
Docs

Code Intelligence

CodeForge provides three layers of code intelligence that work together: structural pattern matching with ast-grep, syntax tree parsing with tree-sitter, and semantic analysis with LSP servers. Each layer serves a different purpose, and knowing when to reach for each one makes you (and Claude) dramatically more effective at understanding and navigating code.

Before diving into each tool, here is the decision framework:

You need to…UseWhy
Find a text string or identifiergrep / Grep toolFastest for literal text
Find a code pattern with variable partsast-grep (sg)Understands syntax, ignores comments and strings
Parse a file’s structure or extract all symbolstree-sitterDeepest structural insight per file
Get type info, jump to definition, or find all referencesLSPSemantic analysis with full type understanding

ast-grep (sg command, also available as ast-grep) enables structural code search using Abstract Syntax Tree patterns. Unlike text-based search, ast-grep understands code structure — it matches patterns regardless of formatting, whitespace, or naming, and it never matches inside comments or string literals.

Terminal window
# Find all console.log calls, regardless of arguments
sg --pattern 'console.log($$$)' --lang js
# Find Python functions decorated with @app.route
sg --pattern '@app.route($PATH)' --lang python
# Find all async function definitions in a directory
sg --pattern 'async def $NAME($$$PARAMS)' --lang python src/api/
# Find fetch calls with any options
sg --pattern 'fetch($URL, $$$OPTS)' --lang typescript

Metavariables are the key to writing effective ast-grep patterns:

SyntaxMatchesExample
$NAMEAny single AST node$FUNC($ARG) matches foo(bar)
$$$ARGSZero or more nodes (variadic)console.log($$$ARGS) matches console.log(), console.log(a), console.log(a, b, c)

The $ prefix with a name creates a named capture. The $$$ prefix creates a variadic capture that matches any number of nodes, including zero.

ast-grep can also transform code, not just search for it:

Terminal window
# Convert var to const
sg --pattern 'var $NAME = $VALUE' --rewrite 'const $NAME = $VALUE' --lang js
# Convert require to import
sg --pattern 'const $NAME = require($PATH)' --rewrite 'import $NAME from $PATH' --lang js
# Add error handling to fetch calls
sg --pattern 'await fetch($URL)' --rewrite 'await fetch($URL).catch(handleError)' --lang ts

Here are patterns that solve common code search problems:

Terminal window
# Find all class definitions with their names
sg --pattern 'class $NAME { $$$BODY }' --lang python
# Find specific decorator usage
sg --pattern '@pytest.mark.parametrize($$$ARGS)' --lang python
# Find import statements for a specific module
sg --pattern 'from $MOD import $$$NAMES' --lang python
# Find all try/except blocks (Python)
sg --pattern 'try: $$$BODY except $$$HANDLERS' --lang python
# Find React useState hooks
sg --pattern 'const [$STATE, $SETTER] = useState($$$INIT)' --lang tsx
# Find all Express route handlers
sg --pattern 'app.$METHOD($PATH, $$$HANDLERS)' --lang js

Consider searching for all calls to fetch():

  • Grep fetch( matches: function calls, comments mentioning fetch, strings containing “fetch(”, variable names like fetchData(, and import statements.
  • ast-grep fetch($$$ARGS) matches: only actual fetch() function calls in the AST, nothing else.

For simple identifier lookups, Grep is faster and sufficient. For pattern matching where structure matters, ast-grep eliminates false positives.

tree-sitter provides incremental parsing and concrete syntax tree operations. It parses source files into syntax trees that you can query, inspect, and traverse. CodeForge installs tree-sitter with grammars for JavaScript, TypeScript, and Python pre-loaded.

Terminal window
# Parse a file and output its syntax tree
tree-sitter parse src/main.py
# Extract all tagged definitions (functions, classes, methods) from a file
tree-sitter tags src/main.py
# Query the syntax tree with S-expression patterns
tree-sitter query '(function_definition name: (identifier) @name)' src/main.py

tree-sitter is most useful when you need to:

  • Understand file structuretree-sitter tags extracts all definitions (functions, classes, methods) from a file, giving you a quick symbol inventory.
  • Inspect nesting and complexitytree-sitter parse shows the full syntax tree, revealing nesting depth and structural complexity.
  • Write precise queries — tree-sitter’s S-expression query language lets you match specific syntactic constructs with field-level precision.

Both tools work with syntax trees, but they serve different purposes:

Featuretree-sitterast-grep
ScopeSingle file, deep analysisMulti-file search
Query syntaxS-expressions (precise, verbose)Code patterns (intuitive, concise)
Best forSymbol extraction, parse tree inspectionFinding patterns across a codebase
OutputSyntax tree structureMatching code locations

In practice, Claude and the specialized agents use ast-grep for cross-file pattern searches and tree-sitter for per-file structural analysis. The ast-grep-patterns skill provides comprehensive guidance for both tools.

LSP servers provide semantic code intelligence — they understand types, scopes, definitions, and references at a level that syntax analysis alone cannot reach. CodeForge configures LSP servers for your installed language runtimes, giving Claude access to the same “go to definition” and “find references” operations your IDE provides.

LanguageServerVersion
PythonPyright1.1.408
TypeScript/JavaScripttypescript-language-server5.1.3 (with TypeScript 5.9.3)
Gogoplslatest
OperationWhat it doesWhen to use it
goToDefinitionJump to where a symbol is defined”Where is this function defined?”
findReferencesFind all usages of a symbol”Where is this class used?”
hoverGet type info and documentation”What type does this return?”
documentSymbolList all symbols in a file”What functions are in this file?”
workspaceSymbolSearch symbols across the project”Find all classes named Controller”
goToImplementationFind interface implementations”What implements this interface?”
incomingCallsFind callers of a function”What calls this function?”
outgoingCallsFind callees from a function”What does this function call?”

LSP understands semantics — types, scopes, and definitions. ast-grep understands syntax — code patterns and structure.

For example, if you search for UserService with ast-grep, you find every syntactic occurrence of that identifier. With LSP findReferences, you find only the places where that specific UserService class (the one defined in services/user.py:15) is actually used — excluding same-named classes in other modules, string mentions, and comments.

Needast-grepLSP
Find a code patternExcellent — designed for thisNot applicable
Find all references to a specific symbolFinds text matches (may include false positives)Finds semantic references (precise)
Get type informationCannotFull type inference
Navigate definition chainsCannotGo-to-definition across files
Work without a running serverWorks immediatelyRequires server startup

The three tools form a progression from fast-and-broad to slow-and-precise:

Grep (text) → ast-grep (syntax) → LSP (semantics)
Fastest Fast Precise
Broadest Focused Narrowest

A typical investigation might use all three:

  1. Grep to find files mentioning authenticate — casts a wide net quickly.
  2. ast-grep to find all function calls to authenticate(...) — filters out comments, strings, and variable names.
  3. LSP findReferences on the specific authenticate function in auth/middleware.py — finds only the call sites for that exact function, not other functions with the same name.

Claude and the specialized agents (especially the explorer and architect) use this progression automatically, starting with the fastest tool and escalating when precision matters.