Source routing¶
Decide once which sources will run, then commit. If you commit a source in routing, you must execute it (or surface its unavailability) โ never silently drop it.
Decision tree¶
Is the question about a specific library API, config, or migration?
YES โ Context7 (+ GitHub if real-world usage matters)
Is it a factual / current / vendor / "what or who or when" question?
YES โ Tavily โ see method matrix below
Is it "how should Iโฆ" or a best-practice question?
YES โ Tavily advanced (+ Context7 when a named library is in scope)
Is it about patterns in this repo?
YES โ Codebase (cheez-search + cheez-read)
Is it about how open-source projects solve something?
YES โ GitHub (+ Tavily if written analysis would help)
Is it deep, multi-source, comparative, or "compare X vs Y / market analysis / lit review"?
YES โ Single tavily_research call (see "When to use tavily_research")
Source guide¶
| Source | Best for | Notes |
|---|---|---|
| Context7 (MCP) | Library APIs, config, migration notes for indexed open-source dependencies | Tools: resolve-library-id (libraryName + query) โ query-docs (libraryId + query). Both require a query. See "Context7 method" below. |
| Tavily (MCP) | Current facts, technical articles, vendor docs, best practices, deep multi-source synthesis | Use the method matrix to pick the right rung. |
| Codebase | Local conventions, existing usage, constraints | Use cheez-search and cheez-read. |
| GitHub | Real-world OSS usage patterns | gh CLI or harness GitHub integration. Treat as supporting evidence unless the user asked for OSS precedent. |
Context7 method¶
Two-step flow. Skip the first step only when the user supplies an exact /org/project (or /org/project/version) ID.
| Step | Tool | Args | Notes |
|---|---|---|---|
| 1 | resolve-library-id |
libraryName, query |
query is the user's full question, not just keywords โ the server reranker uses it. |
| 2 | query-docs |
libraryId, query |
Pass the chosen /org/project from step 1, plus the same focused question. |
Rules¶
- Always pass a
query. Both tools rerank against it. A library name alone returns generic noise. - No
topic=ortokens=parameters. Modern Context7 reranks server-side (~3.3 K avg context tokens); the legacytopic/tokensknobs belong to the pre-rebrandget-library-docsand were removed. To narrow scope, write a richerquery("react hooks useState rules", "next.js 15 middleware auth"). - Hard cap: 3 Context7 calls per question. Upstream rule. Beyond that, answer with the best result so far.
- Cache library IDs.
/org/projectand/org/project/versionare stable. Once resolved, reuse without re-resolving โ except for IDs older than ~30 days, where versions may have retired.
Error handling¶
"Documentation not found or not finalized"โ re-callresolve-library-idonce with an alternate name (full vs short, scoped vs unscoped). If still empty, surface UNAVAILABLE perunavailable.mdโ do not retry the same ID.- Multiple
resolve-library-idmatches โ prefer the higher reputation / official org match; cite the chosen ID in the routing block.
When Context7 is the wrong tool¶
- Refactoring, business logic, debugging, code review, general programming concepts.
- Application code or internal libraries with no public docs.
- Niche packages outside Context7's index (~9-33 K libraries indexed; coverage is fixed, not on-demand).
- Mature, well-known libraries the model already covers reliably โ value is marginal; skip to spare a routed call.
Upstream reference (canonical):
- https://github.com/upstash/context7/blob/main/README.md
- https://github.com/upstash/context7/blob/main/rules/context7-mcp.md
Tavily method matrix¶
The Tavily MCP exposes 5 tools at increasing cost and precision. Pick the lowest rung that answers the question; escalate only when the previous rung returns nothing useful.
| Need | Tool | When |
|---|---|---|
| Discover sources, snippets, scores; no URL yet | tavily_search |
First reach for any factual / "what's the latest" question. Leave include_raw_content=false; pull bodies via tavily_extract instead. |
| Have URL(s), need clean markdown | tavily_extract |
After search, or when the user supplies links. Up to 20 URLs per call. Pass query= so chunks rerank against the question. Set extract_depth=advanced for tables, embedded content, LinkedIn, or other protected sites. |
| Big site, don't know the right page | tavily_map |
URL-only structure of a domain. Cheap. Pair with tavily_extract (Map-then-Extract) for surgical access to large docs sites. |
Many pages on a site section (e.g. all /docs/auth/*) |
tavily_crawl |
Most expensive. Start with max_depth=1, use select_paths and semantic instructions to keep results on-topic. |
| Multi-source synthesis with citations (compare X vs Y, market report, lit review) | tavily_research |
One call returns a cited report. 30-120s. Use model=mini for narrow scope, pro for multi-domain, auto if unsure. Rate limit: 20 req/min โ fan out subqueries via tavily_search, not parallel research calls. |
Search depth (when calling tavily_search)¶
| Depth | Latency | Relevance | Use when |
|---|---|---|---|
ultra-fast |
Lowest | Lower | Real-time UX (rare in /briesearch). |
fast |
Low | Good | Need chunks but latency matters. |
basic |
Medium | High | General-purpose default. |
advanced |
Higher | Highest | Specific information queries; precision matters. Follow with tavily_extract(query=โฆ) on the top-scoring URLs. |
Filters¶
- Time:
time_range(day/week/month/year) for "latest" questions. Orstart_date/end_datefor absolute windows. - Domain:
include_domains=[...]for trusted sources (vendor, arxiv.org, github.com);exclude_domains=[...]for noise (reddit.com, quora.com). - Score: post-filter response items by
score > 0.5before extracting (the score is in the response, not a request param). - Exact phrase:
exact_match=truewhen chasing a literal quote, error string, or API name.
Composite patterns¶
- Search-then-Extract (default two-step):
tavily_searchfor discovery โ drop results withscore โค 0.5โtavily_extract(urls=[โฆ], query=<focused question>)on the survivors. Cheaper and lower-noise thaninclude_raw_content=trueon search. - Map-then-Extract (large docs sites):
tavily_map(url=โฆ, select_paths=[โฆ])to find the 1-3 right URLs without paying for content โtavily_extractonly those. Cheaper thantavily_crawlwhen you don't need every page. - Verify-then-cite (link verification): to confirm a URL loads and actually covers the claimed topic, use
tavily_extract(urls=[โฆ], query=<the claim>)โ its LLM-optimized clean content makes the "does this page cover X" judgment sharper and cheaper than raw HTML. This is the preferred verification/extraction primitive. WebFetch is the fallback, not the default โ reach for it only when the Tavily MCP is unavailable (seeunavailable.md).
When to use tavily_research¶
A single MCP call beats hand-orchestrating search+extract when:
- The question is comparative ("X vs Y").
- The deliverable is a cited report, not a single fact.
- The scope is multi-domain (market analysis, competitive landscape, literature review).
- 30-120s latency is acceptable.
Hand-orchestrate (search โ score-filter โ extract โ synthesize) instead when:
- The question is cross-source โ Tavily plus Context7 plus codebase plus GitHub.
tavily_researchonly sees public web; private signals require local synthesis. - You need fine-grained control over which URLs feed synthesis.
- The user wants the raw evidence table, not a narrative report.
Upstream reference (canonical):
- https://github.com/tavily-ai/skills/blob/main/skills/tavily-cli/SKILL.md
- https://github.com/tavily-ai/skills/tree/main/skills/tavily-best-practices/references
Source priority¶
Within each source class, prefer authoritative over secondary:
- Official vendor / library docs for API, config, migration claims.
- Original papers, standards, RFCs for technical claims.
- Release notes / changelogs for version or freshness claims.
- Repo-local evidence (cheez-search) for local conventions.
- GitHub examples as supporting evidence unless the user asked for OSS precedent.
- Blogs, tutorials, AI-generated content only when nothing above answers the question โ and disclose them as such.
For named-library questions, the routed-call order is cheez-search โ Context7 โ Tavily: cheap repo precedent first, the library's own indexed docs second, current-events / vendor announcements / coverage gaps last. Fan all routed calls in a single assistant turn (parallel tool calls) so total wall time is one round-trip.
Routing block¶
Emit the decision compactly before fetching:
ROUTING DECISION:
- Context7: YES (library: "<library>", query: "<focused question>")
- Tavily: YES (rung: search, depth: basic, filters: time_range=month)
- Codebase: YES (local precedent matters)
- GitHub: NO (not looking for OSS usage patterns)
SOURCE PRIORITY: vendor docs > release notes > repo precedent
Hard rule¶
If a source was committed in routing, spawn it. If it returns "unavailable", report that โ do not silently drop a routed source because it later seems low-value.
Make this mechanical, not honor-system. After gather, diff the emitted ROUTING DECISION against what actually ran: for each source marked YES, confirm a call executed and produced evidence, an unavailable result, or an empty result. Any committed source with no corresponding execution is committed-but-skipped โ mark it explicitly in the report (a Searched, empty line if it ran dry, an UNAVAILABLE note per unavailable.md if it failed, or a flagged gap if it was simply not run) and apply the matching confidence cap from synthesis.md. A YES in the routing block with nothing to show for it is a reconciliation failure, not a silent drop.