Your editor finds it by symbol.
Your AI agent finds it by string.
Twira gives your AI agent the indexed symbol lookups it cannot get from grep alone, symbol search with 5-tier ranking and naming-convention normalisation, plus path / content / regex / semantic modes auto-selected per query, across 26 languages.
You find by symbol. Your agent finds by string. Twira gives your agent eyes.
symbolAny function, class, or type, any case.
pathAny file by name.
contentAny text in the codebase.
regexAny pattern.
SemanticVector embeddings + keyword + call-graph, fused. Find functions by intent or behaviour.
You ask
“Where is handleLogin defined?”
Twira instantly
- searches the symbol index, not the filesystem
- matches getUserName, get_user_name and GetUserName as one
- skips node_modules and dist by default
- returns the exact file, line, and signature
- in 380 milliseconds
Agent navigates straight there. No grep, no guess.
How the agent uses this
Agent calls `search` via MCP. `mode: "auto"` covers most queries.
When you reach for it
- “Where is `handleLogin` defined?”, symbol search.
- “Every file in `src/auth/`”, path search.
- “Any function with a retry block”, content search.
- “`fn\s+\w+_handler`”, regex search.
- “Find functions that look like they verify a webhook signature”, semantic search.
See it work
$ twira search "handleLogin"Technical depth, for engineers who want it
In your editor
In your editor, you press `Cmd+P` to jump to any file. `Cmd+T` to jump to any symbol. Right-click → Go to Definition. `Cmd+Shift+F` for content search. Five everyday shortcuts that let you find any file, any function, any line, instantly, without thinking about which mode you need.
What Code Search does
Think of Code Search as the agent’s `Cmd+P` and `Find All References`, in one tool. Five search modes, symbol, path, content, regex, and semantic, auto-selected for the question being asked. The same instant lookups your editor gives you, available to the agent over MCP. Across 26 languages. Vendored code filtered out by default.
How it actually works
Code Search is how your AI agent looks things up. Five modes, symbol, path, content, regex, and semantic, auto-selected based on the question being asked. Each mode queries a different slice of the knowledge graph the indexer built, with its own precision and its own latency, and the right mode for the right question is picked automatically when the agent leaves mode as auto.
Symbol search is the differentiated mode. It runs a five-tier ranked cascade against two FTS5 indexes, symbols_fts, which is porter-stemmed for natural-language tolerance, and symbol_tokens_fts, which is unicode61 only and camelCase-aware for identifier tokenisation. Tier 1 returns exact name matches. Tier 2 returns case-insensitive matches. Tier 3 returns normalised matches (so camelCase, snake_case, and PascalCase of the same identifier all collapse to one). Tier 4 returns normalised substring matches. Tier 5 returns FTS5 token matches. The cascade stops as soon as it has enough results at a tier. Every hit carries its match_rank (1 to 5) and match_reason, so the agent can show its confidence to you. Handles getUserName, getusername, GetUserName, user, and username against the same underlying symbol.
Path search is a substring LIKE match against the indexed files table. Type src/auth/ or login.ts and get the matching paths back. Fast, simple, deterministic.
Content search uses ripgrep across your working tree rather than the index, so changes are picked up instantly without re-indexing. Case-sensitive by default with an opt-in case_insensitive flag. Parallel by default, one worker per CPU via ripgrep’s WalkBuilder. Respects .gitignore automatically through the same ignore crate ripgrep itself uses, so vendored code, node_modules, and dist/ directories do not pollute the results. Optional file_type filter narrows by extension.
Regex search is the same ripgrep engine with a pattern argument. fn\s+\w+\s*\( finds function declarations, await\s+\w+\(\) finds unawaited promises. Compile errors are surfaced cleanly; you fix the pattern and re-run.
Semantic search is the differentiated mode. The query is embedded into a 512-dimensional vector via your configured provider, then three retrievers run in parallel: a KNN against the symbol embeddings (each one carrying the symbol contract — name, kind, signature, doc, visibility, return type, async/unsafe flags, owning class, language, and top-15 callees), a KNN against the per-function body chunk embeddings (one chunk per function via tree-sitter AST-aware chunking, each chunk enriched with its symbol contract), and a keyword cascade against the FTS5 symbol indexes. The three rankings are fused with Reciprocal Rank Fusion. A final pass rescores candidates using the call graph itself — functions that work together in the codebase rank together in your results. Every hit carries a 0 to 100 relevance score. Requires an embedding provider configured at install (Anthropic, OpenAI, or your own, bring your own key).
Auto mode is a cascade, not a union. If your query contains a forward slash, Twira tries path search first. Otherwise it runs the symbol cascade. If the symbol cascade returns nothing and the query has no slash, it falls back to path. Only one mode runs at a time, if you want both content and symbol results, ask explicitly for each.
Every query takes an optional limit (default 20, max 5000). Content and regex modes also take an optional file_type filter. There is deliberately no test or vendor or generated exclusion flag, .gitignore already handles the common cases, and explicit per-query exclusion adds noise without much benefit.
Every hit returns a consistent shape: the file path, the line number, an optional column, an optional symbol name and kind, and an optional snippet (the signature for symbols, the matching line for content). Symbol hits carry match_rank (1 to 5) and match_reason. Semantic hits carry a relevance score (0 to 100). Content and regex hits are unscored, they either match or they do not. The metadata block tells you which mode ran, the total result count, and elapsed milliseconds.
Setup is one step. Code Search requires the index, run twira index once when you install (see the Index tool) and the post-commit hook keeps it fresh from then on. The non-embedding modes (symbol, path, content, regex) work immediately. Semantic search activates as soon as you configure an embedding provider.
What it isn’t
- Content and regex modes search your working tree, not the index, so changes are picked up instantly without re-indexing.
- Auto mode is a cascade, not a union, one mode runs at a time. Ask explicitly if you need two modes side-by-side.
- Semantic search needs an embedding provider configured. The other four modes work without one.
One install. Your agent will know the difference in the first session.
$ curl -fsSL twira.com/install.sh | sh