Skip to content
Canopy is in pre-release. These docs describe the product at its public launch — commands, tool names, and integration examples reflect what you'll see once binaries ship. Join the waitlist →

Multi-Language Repo

Canopy indexes all supported languages in a single pass. A repo with TypeScript frontend, Python backend, and Rust services gets one unified index — searches, dependency graphs, and health checks span the whole codebase.

First-class languages — symbols + imports + structural pattern search via canopy_pattern_search:

LanguageExtensionsFeatures
TypeScript.ts, .tsxFull — symbols, imports, AST patterns, graph
JavaScript.js, .jsx, .mjs, .cjsFull — symbols, imports, AST patterns, graph
Python.pyFull — symbols, imports, AST patterns, graph
Rust.rsFull — symbols, imports (use declarations), AST patterns, graph
Go.goFull — symbols, imports, AST patterns, graph
Kotlin.kt, .ktsFull — symbols, imports, AST patterns, graph

Additional languages have AST extractors for symbols and imports but do NOT yet support canopy_pattern_search structural matching: C, C++, C#, Java, Swift, Ruby, PHP, GDScript / Godot scenes, plus 30+ build / config formats (CMake, Make, MSBuild, Razor, Gradle, Markdown, Shell, Gemfile, Composer, YAML, TOML, JSON, INI, Dockerfile, etc.).

Anything else is indexed for full-text search only.

No special flags required. Run canopy index at the repo root:

Terminal window
canopy index /path/to/repo --with-search --with-git

Canopy detects languages automatically from file extensions. After indexing, verify all languages were picked up:

Terminal window
canopy status

Expected output for a TypeScript + Python repo:

canopy status for /home/you/repos/myapp
repo id : 9b1d3e7f4a2c8b...
files : 3847
symbols : 41203
imports : 8412
chunks : 9120
search index: ready
git commits : 1284
embeddings : 9120 vectors (ivf-pq ann index)
license : Solo (expires: 2027-04-17)

The per-language file breakdown isn’t surfaced by canopy status directly — the unified counts above cover the whole repo. Use canopy search "<keyword>" --language <lang> (below) to confirm a specific language was picked up.

If a language you expected is missing, check that files with those extensions exist in non-ignored paths.

Use canopy search with --language to limit results to a specific language:

Terminal window
# Find "checkout" in TypeScript files only
canopy search "checkout" --language typescript
# Find "checkout" in Python files only
canopy search "checkout" --language python

Without --language, results span all indexed languages.

Via MCP (in Claude Code, Cursor, etc.):

Call canopy_search with query="checkout" and language="typescript"

canopy pattern_search (and canopy_pattern_search via MCP) uses ast-grep syntax. Patterns are language-specific — specify which language to match:

Find all async function declarations:

Terminal window
canopy pattern "async function $NAME($$$PARAMS) { $$$BODY }" --language typescript

Find all React useEffect calls:

Terminal window
canopy pattern "useEffect($$$)" --language typescript

Canopy tracks dependencies within each language. Cross-language calls (e.g., a TypeScript frontend calling a Python REST API) are not tracked automatically — Canopy works at the source level, not the network level. However, you can:

  1. Use canopy search to find the API endpoint in both codebases simultaneously.
  2. Use canopy_trace_dependents on the TypeScript API client module to find all callers.
  3. Use canopy_trace_dependents on the Python endpoint to find all its imports and dependencies.

Example: TypeScript frontend + Python backend

Section titled “Example: TypeScript frontend + Python backend”

A common structure:

repo/
├── frontend/ (TypeScript/React)
│ └── src/
│ └── api/
│ └── client.ts
└── backend/ (Python/FastAPI)
└── app/
└── routes/
└── payments.py

Index both:

Terminal window
canopy index . --with-search --with-git

Search across both simultaneously:

Terminal window
canopy search "payment"

Output (numbered list, one entry per hit, with the chunk type, symbol name, file:line range, score, and a 5-line preview):

Search results for 'payment' (5 found):
1. [function] · createPayment — frontend/src/api/client.ts:14-32 (score: 87%)
export async function createPayment(cartId: string) {
const paymentResponse = await post('/api/payments', { cartId })
return paymentResponse.json()
}
2. [module_header] — frontend/src/components/Cart.tsx:1-10 (score: 71%)
import { createPayment } from '../api/client'
import { useCart } from '../hooks/useCart'
3. [class] · PaymentService — backend/app/services/payment.py:3-48 (score: 84%)
class PaymentService:
def __init__(self, db: Database):
self.db = db
4. [function] · create_payment_route — backend/app/routes/payments.py:12-28 (score: 78%)
@router.post("/payments")
async def create_payment_route(req: PaymentRequest):
5. [module_header] — backend/app/routes/payments.py:1-5 (score: 62%)
from fastapi import APIRouter
from app.services.payment import PaymentService
Index: 18923 chunks indexed.

One query, both languages.

canopy health runs checks across all indexed languages. Health check findings are scoped to the language they apply to — broken_import for a TypeScript module won’t appear for Python files.

Custom health check plugins can target specific languages. See Write a Custom Health Check.

Python files indexed but no symbols extracted This typically means the Python files use syntax from Python 3.10+ (structural pattern matching, union type syntax) that Canopy’s parser doesn’t yet support. Check CANOPY_LOG=debug canopy index . for parse errors.

Go files missing from index Make sure Go files aren’t inside vendor/ (which is excluded by default). If vendor/ contains first-party code (unusual but it happens), add a specific include_paths override in .canopy/config.toml.

Pattern search returns no results across languages Each canopy pattern call targets one language. If you don’t specify --language, it searches all languages — but the pattern syntax must be valid in the target language. A TypeScript-specific pattern run without --language may silently skip Python files where the pattern is syntactically invalid.