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.
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
haikuby 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.
| Scenario | Choice |
|---|---|
| Research across 3+ pages, broad topic | Agent(WebResearcher) |
| Fetch one known URL | WebFetch directly |
| Discover links for a term | WebSearch directly |
| Something in the local repo | Agent(Explore) |
Design decisions
| Decision | Value | Why |
|---|---|---|
| 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
WebFetchone 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/WebSearchcalls 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.