search-layer

Original🇨🇳 Chinese
Translated
1 scripts

Multi-source search and deduplication layer with intent-aware scoring. Integrates Brave Search (web_search), Exa, Tavily, and Grok to provide high-coverage, high-quality results. Automatically classifies query intent and adjusts search strategy, scoring weights, and result synthesis accordingly. Activated for "deep search", "multi-source search", or when high-quality research is needed.

4installs
Added on

NPX Install

npx skill4agent add blessonism/openclaw-search-skills search-layer

SKILL.md Content (Chinese)

View Translation Comparison →

Search Layer v2.2 — Intent-Aware Multi-Source Retrieval Protocol

Four equal-tier sources: Brave (
web_search
) + Exa + Tavily + Grok. Automatically selects strategies, adjusts weights, and performs synthesis based on intent.

Execution Flow

User Query
[Phase 1] Intent Classification → Determine Search Strategy
[Phase 2] Query Decomposition & Expansion → Generate Sub-Queries
[Phase 3] Multi-Source Parallel Retrieval → Brave + search.py (Exa + Tavily + Grok)
[Phase 4] Result Merging & Sorting → Deduplication + Intent-Weighted Scoring
[Phase 5] Knowledge Synthesis → Structured Output

Phase 1: Intent Classification

Upon receiving a search request, first determine the intent type, then decide the search strategy. Do not ask the user which mode to use.
IntentIdentification SignalsModeFreshnessWeight Bias
Factual"What is X", "Definition of X", "What is X"answerAuthority 0.5
Status"Latest developments of X", "Current status of X", "latest X"deeppw/pmFreshness 0.5
Comparison"X vs Y", "Differences between X and Y"deeppyKeywords 0.4 + Authority 0.4
Tutorial"How to do X", "Tutorial for X", "how to X"answerpyAuthority 0.5
Exploratory"Deep dive into X", "Ecosystem of X", "about X"deepAuthority 0.5
News"News about X", "X this week", "X this week"deeppd/pwFreshness 0.6
Resource"Official website of X", "GitHub of X", "Documentation of X"fastKeywords 0.5
Detailed classification guidelines can be found in
references/intent-guide.md
Judgment Rules:
  1. Scan for signal words in the query
  2. Select the most specific type when multiple types match
  3. Default to
    exploratory
    if intent cannot be determined

Phase 2: Query Decomposition & Expansion

Expand the user's query into a set of sub-queries based on intent type:

General Rules

  • Automatic expansion of technical synonyms: k8s→Kubernetes, JS→JavaScript, Go→Golang, Postgres→PostgreSQL
  • Chinese technical queries: Generate English variants simultaneously (e.g., "Rust 异步编程" → additionally search for "Rust async programming")

Expansion by Intent

IntentExpansion StrategyExample
FactualAdd "definition", "explained""WebTransport" → "WebTransport", "WebTransport explained overview"
StatusAdd year, "latest", "update""Deno 进展" → "Deno 2.0 latest 2026", "Deno update release"
ComparisonSplit into 3 sub-queries"Bun vs Deno" → "Bun vs Deno", "Bun advantages", "Deno advantages"
TutorialAdd "tutorial", "guide", "step by step""Rust CLI" → "Rust CLI tutorial", "Rust CLI guide step by step"
ExploratorySplit into 2-3 perspectives"RISC-V" → "RISC-V overview", "RISC-V ecosystem", "RISC-V use cases"
NewsAdd "news", "announcement", date"AI 新闻" → "AI news this week 2026", "AI announcement latest"
ResourceAdd specific resource types"Anthropic MCP" → "Anthropic MCP official documentation"

Phase 3: Multi-Source Parallel Retrieval

Step 1: Brave (All Modes)

Call
web_search
for each sub-query. If the intent has freshness requirements, pass the
freshness
parameter:
web_search(query="Deno 2.0 latest 2026", freshness="pw")

Step 2: Exa + Tavily + Grok (Deep / Answer Modes)

Call search.py for sub-queries, passing intent and freshness:
bash
python3 /home/node/.openclaw/workspace/skills/search-layer/scripts/search.py \
  --queries "sub-query1" "sub-query2" "sub-query3" \
  --mode deep \
  --intent status \
  --freshness pw \
  --num 5
Source Participation Matrix by Mode:
ModeExaTavilyGrokNotes
fastfallbackPrioritize Exa; use Grok if Exa key is unavailable
deepThree sources in parallel
answerOnly Tavily (includes AI answer)
Parameter Explanation:
ParameterDescription
--queries
Execute multiple sub-queries in parallel (can also pass a single query as a positional parameter)
--mode
fast / deep / answer
--intent
Intent type, affects scoring weights (if not passed, no scoring is performed, behavior is consistent with v1)
--freshness
pd(24h) / pw(week) / pm(month) / py(year)
--domain-boost
Comma-separated domains, matching results get +0.2 to authority score
--num
Number of results per source per query
Grok Source Notes:
  • Call the Grok model (
    grok-4.1
    ) via the completions API, leveraging its real-time knowledge to return structured search results
  • Automatically detects time-sensitive queries and injects current time context
  • Executes in parallel with Exa and Tavily in deep mode
  • Requires configuring
    Grok API URL
    ,
    Grok API Key
    ,
    Grok Model
    in TOOLS.md
  • If Grok configuration is missing, automatically downgrades to Exa + Tavily dual sources

Step 3: Merging

Merge Brave results with search.py output. Deduplicate by canonical URL and mark sources.
If search.py returns a
score
field, sort using it; for Brave results without a score, calculate it using the same intent weight formula.

Phase 4: Result Sorting

Scoring Formula

score = w_keyword × keyword_match + w_freshness × freshness_score + w_authority × authority_score
Weights are determined by intent (see Phase 1 table). Breakdown of each component:
  • keyword_match (0-1): Coverage of query terms in title + abstract
  • freshness_score (0-1): Based on publication date, newer results score higher (0.5 if no date)
  • authority_score (0-1): Based on domain authority level
    • Tier 1 (1.0): github.com, stackoverflow.com, official documentation sites
    • Tier 2 (0.8): HN, dev.to, well-known technical blogs
    • Tier 3 (0.6): Medium, 掘金 (Juejin), InfoQ
    • Tier 4 (0.4): Others
Complete domain scoring table can be found in
references/authority-domains.json

Domain Boost

Manually specify domains to boost via the
--domain-boost
parameter (matching results get +0.2 to authority score):
bash
search.py "query" --mode deep --intent tutorial --domain-boost dev.to,freecodecamp.org
Recommended Pairings:
  • Tutorial →
    dev.to, freecodecamp.org, realpython.com, baeldung.com
  • Resource →
    github.com
  • News →
    techcrunch.com, arstechnica.com, theverge.com

Phase 5: Knowledge Synthesis

Select synthesis strategy based on the number of results:

Small Result Set (≤5 entries)

Display each entry with source tags and score:
1. [Title](url) — snippet... `[brave, exa]` ⭐0.85
2. [Title](url) — snippet... `[tavily]` ⭐0.72

Medium Result Set (5-15 entries)

Cluster by topic + summary per group:
**Topic A: [Description]**
- [Result1] — Key points... `[source]`
- [Result2] — Key points... `[source]`

**Topic B: [Description]**
- [Result3] — Key points... `[source]`

Large Result Set (15+ entries)

High-level overview + Top 5 + deep dive prompt:
[A paragraph summarizing key findings]

**Top 5 Most Relevant Results:**
1. ...
2. ...

A total of N results found, covering [source list]. Which aspect would you like to explore in depth?

Synthesis Rules

  • Provide the answer first, then list sources (do not start with "I searched for...")
  • Aggregate by topic, not by source (do not use "Brave results: ... Exa results: ...")
  • Explicitly mark conflicting information: Clearly indicate when different sources have contradictory statements
  • Express confidence:
    • Consistent across multiple sources + fresh → State directly
    • Single source or older → "According to [source], ..."
    • Conflicting or uncertain → "Different opinions exist: A believes..., B believes..."

Degradation Strategy

  • Exa 429/5xx → Continue with Brave + Tavily + Grok
  • Tavily 429/5xx → Continue with Brave + Exa + Grok
  • Grok timeout/error → Continue with Brave + Exa + Tavily
  • search.py fails entirely → Use only Brave
    web_search
    (always available)
  • Never block the main process due to failure of a single source

Backward Compatibility

When the
--intent
parameter is not passed, search.py behavior is fully consistent with v1 (no scoring, output in original order).
Existing callers (e.g., github-explorer) do not need modification.

Quick Reference

ScenarioCommand
Quick Facts
web_search
+
search.py --mode answer --intent factual
Deep Research
web_search
+
search.py --mode deep --intent exploratory
Latest Updates
web_search(freshness="pw")
+
search.py --mode deep --intent status --freshness pw
Comparative Analysis
web_search
× 3 queries +
search.py --queries "A vs B" "A pros" "B pros" --intent comparison
Resource Finding
web_search
+
search.py --mode fast --intent resource