Web Researcher

Built-in subagent for multi-page web research — runs in isolation, returns just the synthesis.

Overview

The WebResearcher is a built-in subagent the main agent can invoke through the Agent tool whenever a question needs digging through several web pages. It runs in an isolated context, with access only to WebSearch and WebFetch, and returns a single textual synthesis with cited URLs.

Before this subagent existed, prompts like "how do I configure OAuth device flow for provider X" made the main model chain 5–7 direct WebFetch / WebSearch calls. Every WebFetch dumped 3–5k tokens of HTML-to-markdown into the main history — roughly 20k tokens of mechanical browsing taking up expensive context (typically Opus) during long sessions.

~20 000 tokens kept out of the main context per research query
~10× cheaper model used for the mechanical browsing

With the WebResearcher:

  • Raw HTML stays in the child's context and is discarded when it finishes.
  • The parent receives only the final synthesis — hundreds of tokens, not tens of thousands.
  • The child runs on haiku by default (the cheapest first-party alias), so the mechanical work doesn't consume the expensive model.

When the parent picks WebResearcher vs. direct tools

The description injected into the parent's prompt makes the choice explicit. The parent model decides — there is no automatic routing.

ScenarioChoice
Research across 3+ pages, broad topicAgent(WebResearcher)
Fetch one known URLWebFetch directly
Discover links for a termWebSearch directly
Something in the local repoAgent(Explore)

Design decisions

DecisionValueWhy
Tools allowlist [WebSearch, WebFetch] Pure public-web scope; no local file reads, no MCP. The allowlist won't silently widen if new write-tools are added later.
Model haiku Cheapest of the first-party aliases. Resolves correctly on Anthropic, Bedrock, Vertex, and Foundry. See "Model override" for OpenAI-compatible providers.
Omit CLAUDE.md yes Web research doesn't need project-level commit/lint/TypeScript rules.
Omit git status yes Web research never touches the local repo; skipping the gitStatus blob (up to 40 KB) is pure savings.
One-shot trailer built-in one-shot agent Parent doesn't receive agentId / SendMessage / usage trailer — saves ~135 chars per call.
Permission mode inherited Domain checks for WebFetch on a new host still surface for approval in the parent UI.
Continue (SendMessage) not exposed Preserves isolation. If the parent needs to dig deeper it spawns a fresh WebResearcher.
Feature flag none Always on. Simplicity over an extra knob.

Why haiku and not hard-coded Gemini Flash / DeepSeek?

Hard-coding a specific provider would violate Claudin's "no hardcoded provider logic" rule and would break for anyone who hasn't configured that provider. haiku is the cheapest universal alias.

Model override (important for non-Anthropic providers)

On providers that aren't Claude-native — anything routed through the OpenAI shim such as OpenRouter, Gemini, DeepSeek, Mistral, LM Studio, Together — the alias haiku falls back to the parent's model. That means on OpenRouter + Opus, without an override, the WebResearcher also runs on Opus, cancelling the cost win.

Fix it by setting an explicit override in ~/.claudin/settings.json:

{
  "agentModelOverrides": {
    "built-in:WebResearcher": "deepseek-chat"
  }
}

Or any other cheap model your active provider exposes. No code changes required.

Override with a custom agent

Drop a file at .claudin/agents/WebResearcher.md (same agentType) and it will override the built-in. The merge order is built-in → plugin → user settings → project settings → flag settings → policy settings, with each source winning over the previous one. This is a feature, not a bug — useful for customizing the system prompt without forking.

Trade-offs

  • Extra latency. Queries that would have been 1–2 direct fetches pay the overhead of a subagent round-trip. The injected description is explicit about when not to use it.
  • Synthesis can lose nuance. The parent never sees raw HTML. If detail is needed, the parent can WebFetch one of the URLs the child cited.
  • No MCP, no local reads. The allowlist excludes both by design. To cross web with internal docs (Notion, repo, etc.), the parent does that before or after — not inside the WebResearcher.
  • No feature flag. Can't be turned off at build-time; if something breaks, revert via PR. Accepted for simplicity.

Try it

Inside the Claudin REPL, ask something that naturally requires multi-page research:

research how to configure OAuth device flow for the GitHub Copilot CLI provider

What you should see:

  • The parent calls Agent(subagent_type='WebResearcher').
  • Several WebFetch / WebSearch calls happen inside the subagent — they don't appear in the parent history.
  • The final answer in the parent cites URLs in markdown, without any raw HTML.