Skip to content
Code SearchMCPFree

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.

AI alone

  • Greps the codebase for a symbol name, matches definitions, calls, comments, and string literals all mixed together
  • camelCase, snake_case, PascalCase of one symbol are three separate searches
  • Cannot rank hits by relevance, every match looks the same
  • No semantic search, can only find what matches literally
  • Cannot ask "find functions like this", only "find this string"
  • Ripgrep runs over the whole tree on every query, fast, but doesn’t get faster with use

Twira Code Search powertool

  • Symbol search, knows function vs class vs type, ignores comments and string literals
  • 5-tier ranked cascade, exact → case-insensitive → normalised → substring → token
  • camelCase ↔ snake_case ↔ PascalCase normalised, one symbol, one result
  • Semantic search, vector embeddings + keyword + call-graph signal fused with Reciprocal Rank Fusion
  • Five modes auto-selected per query: symbol, path, content, regex, semantic
  • Indexed symbol lookups, milliseconds regardless of codebase size

You find by symbol. Your agent finds by string. Twira gives your agent eyes.

symbol

Any function, class, or type, any case.

path

Any file by name.

content

Any text in the codebase.

regex

Any pattern.

Semantic

Vector 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"
✓ 1 symbol · rank 1 (exact) · 380ms↳ src/auth/login.ts:42, function declaration
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
Code Search, Tools · Twira