name: deep-research description: | Deep web research workflow. Plans an investigation, decomposes it into sub-questions researched in parallel, grounds the work in a local knowledge corpus, vets the credibility of cited sources, runs a reflexion self-critique loop to revise weak or incomplete findings, delegates the final write-up to a focused sub-agent, checks that the cited sources are reachable, and gates the result behind human approval. A reviewer's free-form feedback at the approval step feeds back into another research pass. This is the canonical Coyote graph-agent reference: it exercises every node type (script, llm, rag, map, agent, input, approval, end) and both static fan-out and dynamic map fan-out. version: "1.0" global_tools: - web_search_coyote.sh - fetch_url_via_curl.sh - search_arxiv.sh mcp_servers: - ddg-search conversation_starters: - "How does HTTP/3 differ from HTTP/2?" - "Summarize recent advances in solid-state battery chemistry" settings: max_loop_iterations: 40 log_state_snapshots: false validate_before_run: true max_concurrency: 4 initial_state: research_feedback: "" research_attempts: 0 local_context: "" local_sources: "" start: parse_request nodes: parse_request: id: parse_request type: script script: scripts/parse_request.py next: bootstrap_research ask_topic: id: ask_topic type: input question: "What would you like me to research?" validation: "len(input) > 0" state_updates: topic: "{{input}}" next: bootstrap_research bootstrap_research: id: bootstrap_research type: script script: scripts/bootstrap_research.py next: [plan, knowledge_lookup] plan: id: plan type: llm instructions: | You are a research planner. Given a topic, produce a focused research plan and decompose it into 3-5 specific sub-questions that can each be researched independently in parallel. The plan is a short narrative naming the key questions and the kinds of sources that would be authoritative. The sub-questions are precise, self-contained queries (each one is sent on its own to a separate research worker, so they must be answerable without each other's context). prompt: "Research topic: {{topic}}" tools: [] output_schema: type: object properties: research_plan: type: string description: A short plan narrative. questions: type: array items: { type: string } minItems: 1 maxItems: 6 description: 3-5 specific, self-contained sub-questions. required: [research_plan, questions] next: research_each_question knowledge_lookup: id: knowledge_lookup type: rag documents: - ./knowledge/ query: "{{topic}}" top_k: 6 chunk_size: 1000 chunk_overlap: 100 state_updates: local_context: "{{output.context}}" local_sources: "{{output.sources}}" next: research_each_question research_each_question: id: research_each_question type: map over: "{{questions}}" as: question branch: research_one_question collect_into: question_findings max_concurrency: 3 next: combine_findings research_one_question: id: research_one_question type: llm instructions: | You are a web research assistant. Investigate the SINGLE question given to you using your tools: search the web, fetch and read pages, and search arXiv for academic sources. Rules: - Every factual claim must be backed by a real source you actually retrieved. Never fabricate URLs, page titles, authors, or DOIs. - Prefer primary and authoritative sources over aggregators. - Where sources disagree, report the disagreement rather than papering over it. - Put the URL (or DOI) inline next to each claim it supports. Return organized findings in plain text. Do not include meta-commentary about the process. prompt: | Research question: {{question}} Local context that may help: {{local_context}} {{research_feedback}} tools: - web_search_coyote - fetch_url_via_curl - search_arxiv - mcp:ddg-search max_iterations: 10 max_attempts: 2 temperature: 0.1 combine_findings: id: combine_findings type: script script: scripts/combine_findings.py next: vet_sources vet_sources: id: vet_sources type: llm instructions: | You assess the credibility of the sources cited in a set of research findings. For every distinct source URL in the findings, call the `classify_source` tool to get its credibility tier. Then summarize: which claims rest on HIGH-credibility sources, and which rest on PREPRINT or UNVERIFIED sources and so need corroboration. Do NOT do any new research -- assess only what is already cited. prompt: | Findings to assess: {{findings}} tools: - classify_source max_iterations: 15 state_updates: source_assessment: "{{output}}" next: critique critique: id: critique type: llm instructions: | You are a meticulous research reviewer. Judge whether the findings below are good enough to synthesize a complete, well-supported report that answers the research plan. Mark the findings REVISE if ANY of these hold: - A research-plan question is unanswered or only weakly addressed. - A factual claim has no source, or cites a source that looks fabricated. - The findings lean on a single source where corroboration is needed. - A key claim rests only on a PREPRINT or UNVERIFIED source, per the source credibility assessment below. - An obvious counter-perspective or recent development is missing. Otherwise mark them PASS. Respond in EXACTLY this format, nothing else: VERDICT: FEEDBACK: prompt: | Research plan: {{research_plan}} Findings under review: {{findings}} Source credibility assessment: {{source_assessment}} tools: [] state_updates: critique: "{{output}}" next: reflexion_gate reflexion_gate: id: reflexion_gate type: script script: scripts/reflexion_gate.py next: synthesize synthesize: id: synthesize type: agent agent: report-writer prompt: | Research topic: {{topic}} Findings (organized by sub-question, with inline citations): {{findings}} Source credibility assessment: {{source_assessment}} Produce the final report following your instructions. timeout: 300 state_updates: report: "{{output}}" next: verify_sources verify_sources: id: verify_sources type: script script: scripts/verify_sources.py next: approve approve: id: approve type: approval question: | Research report on: {{topic}} {{report}} ---- {{source_check}} ---- Accept this report? Pick "accept" or "reject", or type specific feedback to send the research back for another pass. options: - "accept" - "reject" routes: "accept": end_accepted "reject": end_rejected on_other: incorporate_feedback state_updates: decision: "{{choice}}" incorporate_feedback: id: incorporate_feedback type: script script: scripts/incorporate_feedback.py end_accepted: id: end_accepted type: end output: "{{report}}" end_rejected: id: end_rejected type: end output: "Research on '{{topic}}' was rejected and discarded."