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.
Supported languages
Section titled “Supported languages”First-class languages — symbols + imports + structural pattern search via canopy_pattern_search:
| Language | Extensions | Features |
|---|---|---|
| TypeScript | .ts, .tsx | Full — symbols, imports, AST patterns, graph |
| JavaScript | .js, .jsx, .mjs, .cjs | Full — symbols, imports, AST patterns, graph |
| Python | .py | Full — symbols, imports, AST patterns, graph |
| Rust | .rs | Full — symbols, imports (use declarations), AST patterns, graph |
| Go | .go | Full — symbols, imports, AST patterns, graph |
| Kotlin | .kt, .kts | Full — 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.
Index a mixed-language repo
Section titled “Index a mixed-language repo”No special flags required. Run canopy index at the repo root:
canopy index /path/to/repo --with-search --with-gitCanopy detects languages automatically from file extensions. After indexing, verify all languages were picked up:
canopy statusExpected 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.
Language-scoped search
Section titled “Language-scoped search”Use canopy search with --language to limit results to a specific language:
# Find "checkout" in TypeScript files onlycanopy search "checkout" --language typescript
# Find "checkout" in Python files onlycanopy search "checkout" --language pythonWithout --language, results span all indexed languages.
Via MCP (in Claude Code, Cursor, etc.):
Call canopy_search with query="checkout" and language="typescript"Language-specific AST patterns
Section titled “Language-specific AST patterns”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:
canopy pattern "async function $NAME($$$PARAMS) { $$$BODY }" --language typescriptFind all React useEffect calls:
canopy pattern "useEffect($$$)" --language typescriptFind all class definitions:
canopy pattern "class $NAME: $$$BODY" --language pythonFind all with statements:
canopy pattern "with $CTX as $VAR: $$$BODY" --language pythonFind all impl blocks:
canopy pattern "impl $TRAIT for $TYPE { $$$BODY }" --language rustFind unwrap() calls (for audit):
canopy pattern "$EXPR.unwrap()" --language rustFind all error returns:
canopy pattern "return nil, $ERR" --language goFind goroutine spawns:
canopy pattern "go $FUNC($$$ARGS)" --language goCross-language dependency tracking
Section titled “Cross-language dependency tracking”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:
- Use
canopy searchto find the API endpoint in both codebases simultaneously. - Use
canopy_trace_dependentson the TypeScript API client module to find all callers. - Use
canopy_trace_dependentson 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.pyIndex both:
canopy index . --with-search --with-gitSearch across both simultaneously:
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.
Health checks in multi-language repos
Section titled “Health checks in multi-language repos”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.
Common pitfalls
Section titled “Common pitfalls”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.