Labsco
tavily-ai logo

tavily-dynamic-search

โ˜… 399

by tavily-ai ยท part of tavily-ai/skills

Search the web, filter results, and extract content so that raw search data never enters your context window . Only your curated print() output comes back.

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeQuick setup
๐Ÿงฉ One of 7 skills in the tavily-ai/skills package โ€” works on its own, and pairs well with its siblings.

Search the web, filter results, and extract content so that raw search data never enters your context window . Only your curated print() output comes back.

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates โ€” shown here so you can audit it before installing. You don't need to read it to use the skill.

by tavily-ai

Search the web, filter results, and extract content so that raw search data never enters your context window . Only your curated print() output comes back. npx skills add https://github.com/tavily-ai/skills --skill tavily-dynamic-search Download ZIPGitHub399

Tavily Dynamic Search

Search the web, filter results, and extract content so that raw search data never enters your context window. Only your curated print() output comes back.

Why this matters

A typical tvly search --include-raw-content returns 8 results ร— 30-50K chars each = ~300K characters of raw page content. If this enters your context window, you burn tokens reading navigation bars, cookie banners, and boilerplate โ€” and your reasoning quality degrades under the noise. By processing results inside a Python script, only your print() output enters context โ€” typically 1-3K characters of pure signal. That's a 100-200x reduction.

Background: Programmatic Tool Calling (PTC)

This skill replicates the architecture of Anthropic's Programmatic Tool Calling (PTC) for web search. PTC lets the model write code that orchestrates tool calls inside a sandbox โ€” intermediate results stay in the sandbox, and only the final print() output reaches the model's context window.

This skill applies the same principle using local Python execution. The Python process is the sandbox. Variables in memory hold the raw data. Only what you print() crosses into your context window. You write the filtering logic โ€” you decide what matters for each query.

Core Rule

NEVER run tvly as a bare command. Always process output through Python so you control what enters your context.

Copy & paste โ€” that's it
# WRONG โ€” raw results flood your context
tvly search "quantum computing 2025" --json

# RIGHT โ€” only your print() output enters context
tvly search "quantum computing 2025" --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
for r in data['results']:
 print(f'[{r[\"score\"]:.2f}] {r[\"title\"]}')
 print(f' {r[\"url\"]}')
"

JSON Schemas

You need these to write correct filtering code.

tvly search --json

Copy & paste โ€” that's it
{
 "query": "string",
 "answer": "string | null",
 "results": [
 {
 "url": "string",
 "title": "string",
 "content": "string (snippet, ~500-1500 chars)",
 "score": 0.0-1.0,
 "raw_content": "string | null (full page, only with --include-raw-content)"
 }
 ],
 "response_time": 0.0
}

tvly extract --json

Copy & paste โ€” that's it
{
 "results": [
 {
 "url": "string",
 "title": "string",
 "raw_content": "string (full page markdown)",
 "images": []
 }
 ],
 "failed_results": [],
 "response_time": 0.0
}

How to search

You have two building blocks and two ways to run them. Compose these however the query demands โ€” there are no fixed patterns. You decide the approach based on what you need.

Building blocks

tvly search โ€” returns titles, URLs, snippets, scores. Optionally includes full page content with --include-raw-content markdown.

tvly extract โ€” fetches full page content for specific URLs. Use when you found a URL from search and need more detail.

Execution modes

Pipe mode โ€” for simple filters (3-5 lines). Pipe tvly output into python3 -c:

Copy & paste โ€” that's it
tvly search "query" --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
# your filtering code here
"

Heredoc mode โ€” for anything more complex. Single Bash call, clean multi-line Python, no escaping, no temp files:

Copy & paste โ€” that's it
python3 Single-quoted heredocs (`<< 'PYEOF'`) don't interpret anything โ€” no escaping needed. This is the default for most tasks.

 **Script mode** โ€” only when you will reuse the same script across multiple turns. Do NOT write one-shot scripts to `/tmp/`. If you run it once, use a heredoc.

 **Important: save DATA to `/tmp/`, not CODE.** Writing `/tmp/tavily_results.json` (data for later turns) = good. Writing `/tmp/my_filter.py` (one-shot code) = wasteful โ€” use a heredoc instead.

## Multi-turn iteration

For complex queries, you often need to **explore before you extract** โ€” just like PTC, where the model searches, sees titles, decides which results to drill into, then extracts.

 The key: **save raw results to a file, then process them in separate steps.** The file is your persistent state between turns.

### Turn 1: Search and explore

 Search and print only titles + scores. Save raw results to disk for later turns:

python3 Context receives: ~800 tokens of titles + snippets. The 300K of raw page content is in /tmp/tavily_results.json, untouched.

Turn 2: Extract based on what you saw

Now you know what's in the results. Write targeted extraction โ€” you decide which results to drill into and what to filter for:

Copy & paste โ€” that's it
python3 80 and any(kw in para.lower() for kw in
 ['toyota', 'quantumscape', 'samsung', 'commercializ', 'production']):
 print(para)
 print()

 print('---\n')
PYEOF

Context receives: ~600 tokens of targeted content. You made the decision about what to keep.

Turn 3 (optional): Fetch more detail

If you need more from a specific source:

Copy & paste โ€” that's it
python3 **Single turn** (pipe mode or one script): when you know upfront what you're looking for. Specific factual queries, known keywords.

 **Multi-turn** (save + explore + extract): when you need to see what's available before deciding what to extract. Open-ended research, complex topics, queries where you don't know the right keywords yet.

## Examples

### Simple factual lookup (single turn, pipe mode)

tvly search "Python 3.13 release date" --max-results 5 --json 2>/dev/null | python3 -c " import json, sys data = json.load(sys.stdin) for r in data['results'][:3]: print(f'{r["title"]}') print(f'{r["content"][:300]}') print() "

Copy & paste โ€” that's it

### Financial data extraction (single turn, heredoc)

python3 30 ] if financial_lines: print(f'## {r["title"]}') print(f'URL: {r["url"]}') for line in financial_lines[:15]: print(f' {line}') print() PYEOF

Copy & paste โ€” that's it

### Multi-source research (multi-turn)

 **Turn 1** โ€” broad search + triage:

python3 Turn 2 โ€” you see the triage, pick the best sources, and extract:

Copy & paste โ€” that's it
python3 100 and any(kw in para.lower() for kw in
 ['high-risk', 'prohibited', 'deadline', 'obligation',
 'compliance', 'penalty', 'fine', 'article']):
 print(para)
 print()

 print('---\n')
 except Exception:
 continue
PYEOF

Following leads across turns

Sometimes turn 2 reveals new URLs or topics to chase. You can keep iterating:

Copy & paste โ€” that's it
python3 Each turn, you save data to `/tmp/`, decide what to explore next, and write new filtering code as heredocs. The raw data accumulates on disk; your context stays lean.

## Writing your filtering code

The Python you write IS the filtering logic. There are no fixed templates โ€” you write code that makes sense for the specific query. Here are principles, not rules:

 **Triage first.** Inspect titles and scores before fetching full pages. Don't extract everything blindly.

 **Be specific.** A financial query should filter for numbers and financial terms. A technical query should look for code blocks and specifications. A news query should look for dates and quotes. Match your filtering to the query.

 **Structural filtering helps.** Skip lines shorter than ~50-80 chars (usually nav elements). Skip common boilerplate phrases. Keep headings and their following paragraphs. But these are starting points โ€” adapt based on what you see.

 **Print structured output.** Format your output so it's easy to reason over:

print(f'## {title}') print(f'URL: {url}') print(relevant_content) print()

Copy & paste โ€” that's it

 **Handle errors.** Pages fail, URLs 404, extractions timeout. Use try/except and skip failures:

try: raw = subprocess.check_output(['tvly', 'extract', url, '--json'], stderr=subprocess.DEVNULL, timeout=30) except Exception: continue

Copy & paste โ€” that's it

 **Token budget awareness.** Your `print()` output is what enters your context. Target 150-600 tokens per source. If you're printing 5000+ chars from a single page, you're probably not filtering enough. But if a source has a critical data table, it's fine to keep more.

## Options

All standard `tvly search` options work:

 Option Description 
 `--max-results` Number of results (default: 5, max: 20) 
 `--depth` `ultra-fast`, `fast`, `basic` (default), `advanced` 
 `--time-range` `day`, `week`, `month`, `year` 
 `--include-domains` Comma-separated whitelist 
 `--exclude-domains` Comma-separated blacklist 
 `--include-raw-content` Full page content (`markdown` or `text`) 
 `--country` Boost results from country

## Fallback: jq

When `python3` is unavailable, use `jq` for basic filtering:

tvly search "query" --json 2>/dev/null | jq '[.results[] | select(.score > 0.5) | {title, url, content}]'

Copy & paste โ€” that's it

 jq can't do multi-step search-then-extract or complex filtering. Use it only for simple lookups.