This report summarizes scanner evidence for langchain-ai/open_deep_research, a Python project with 12,681 GitHub stars. SynthScan examined 8,675 lines of code across 36 source files, recording 177 pattern matches distributed across 14 syntactic categories. The legacy adjusted pattern signal is 26.4 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 149 finding(s).
Are imports declared and package/API names verified? 2 finding(s).
Are wrappers, guards, and repeated structures necessary? 45 finding(s).
Which changes need focused human review? 177 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 177 distinct pattern matches across 14 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/open_deep_research/utils.py | 61 | # Step 1: Execute search queries asynchronously | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 70 | # Step 2: Deduplicate results by URL to avoid processing the same content multiple times | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 78 | # Step 3: Set up the summarization model with configuration | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 109 | # Step 5: Execute all summarization tasks in parallel | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 112 | # Step 6: Combine results with their summaries | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 464 | # Step 1: Handle authentication if required | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 470 | # Step 2: Validate configuration requirements | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 498 | # Step 4: Load tools from MCP server | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 506 | # Step 5: Filter and configure tools | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 688 | # Step 2: Check provider-specific token limit patterns | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 696 | # Step 3: If provider unknown, check all providers | COMMENT |
| LOW | src/open_deep_research/utils.py | 95 | # Step 4: Create summarization tasks (skip empty content) | COMMENT |
| LOW | src/open_deep_research/utils.py | 125 | # Step 7: Format the final output | COMMENT |
| LOW | src/open_deep_research/utils.py | 481 | # Step 3: Set up MCP server connection | COMMENT |
| LOW | src/open_deep_research/utils.py | 677 | # Step 1: Determine provider from model name if available | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 73 | # Step 1: Check if clarification is enabled in configuration | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 79 | # Step 2: Prepare the model for structured clarification analysis | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 96 | # Step 3: Analyze whether clarification is needed | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 103 | # Step 4: Route based on clarification analysis | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 149 | # Step 2: Generate structured research brief from user messages | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 156 | # Step 3: Initialize supervisor with research brief and instructions | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 212 | # Step 2: Generate supervisor response based on current context | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 216 | # Step 3: Update state and proceed to tool execution | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 413 | # Step 3: Generate researcher response with system context | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 417 | # Step 4: Update state and proceed to tool execution | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 525 | # Step 1: Configure the compression model | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 534 | # Step 2: Prepare messages for compression | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 540 | # Step 3: Attempt compression with retry logic for token limit issues | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 620 | # Step 1: Extract research findings and prepare state cleanup | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 625 | # Step 2: Configure the final report generation model | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 634 | # Step 3: Attempt report generation with token limit retry logic | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 132 | # Step 1: Set up the research model for structured output | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 192 | # Step 1: Configure the supervisor model with available tools | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 240 | # Step 1: Extract current state and check exit conditions | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 264 | # Step 2: Process all tool calls together (both think_tool and ConductResearch) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 344 | # Step 3: Return command with all tool results | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 379 | # Step 1: Load configuration and validate tool availability | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 391 | # Step 2: Configure the researcher model with tools | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 451 | # Step 1: Extract current state and check early exit conditions | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 466 | # Step 2: Handle other tool calls (search, MCP tools, etc.) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 491 | # Step 3: Check late exit conditions (after processing tools) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 576 | # Step 4: Return error result if all attempts failed | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 692 | # Step 4: Return failure result if all retries exhausted | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/open_deep_research/utils.py | 61 | # Step 1: Execute search queries asynchronously | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 70 | # Step 2: Deduplicate results by URL to avoid processing the same content multiple times | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 78 | # Step 3: Set up the summarization model with configuration | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 109 | # Step 5: Execute all summarization tasks in parallel | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 112 | # Step 6: Combine results with their summaries | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 464 | # Step 1: Handle authentication if required | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 470 | # Step 2: Validate configuration requirements | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 498 | # Step 4: Load tools from MCP server | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 506 | # Step 5: Filter and configure tools | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 688 | # Step 2: Check provider-specific token limit patterns | COMMENT |
| LOW⚡ | src/open_deep_research/utils.py | 696 | # Step 3: If provider unknown, check all providers | COMMENT |
| LOW | src/open_deep_research/utils.py | 95 | # Step 4: Create summarization tasks (skip empty content) | COMMENT |
| LOW | src/open_deep_research/utils.py | 125 | # Step 7: Format the final output | COMMENT |
| LOW | src/open_deep_research/utils.py | 481 | # Step 3: Set up MCP server connection | COMMENT |
| LOW | src/open_deep_research/utils.py | 677 | # Step 1: Determine provider from model name if available | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 73 | # Step 1: Check if clarification is enabled in configuration | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 79 | # Step 2: Prepare the model for structured clarification analysis | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 96 | # Step 3: Analyze whether clarification is needed | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 103 | # Step 4: Route based on clarification analysis | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 149 | # Step 2: Generate structured research brief from user messages | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 156 | # Step 3: Initialize supervisor with research brief and instructions | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 212 | # Step 2: Generate supervisor response based on current context | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 216 | # Step 3: Update state and proceed to tool execution | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 413 | # Step 3: Generate researcher response with system context | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 417 | # Step 4: Update state and proceed to tool execution | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 525 | # Step 1: Configure the compression model | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 534 | # Step 2: Prepare messages for compression | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 540 | # Step 3: Attempt compression with retry logic for token limit issues | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 620 | # Step 1: Extract research findings and prepare state cleanup | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 625 | # Step 2: Configure the final report generation model | COMMENT |
| LOW⚡ | src/open_deep_research/deep_researcher.py | 634 | # Step 3: Attempt report generation with token limit retry logic | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 132 | # Step 1: Set up the research model for structured output | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 192 | # Step 1: Configure the supervisor model with available tools | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 240 | # Step 1: Extract current state and check exit conditions | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 264 | # Step 2: Process all tool calls together (both think_tool and ConductResearch) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 344 | # Step 3: Return command with all tool results | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 379 | # Step 1: Load configuration and validate tool availability | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 391 | # Step 2: Configure the researcher model with tools | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 451 | # Step 1: Extract current state and check early exit conditions | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 466 | # Step 2: Handle other tool calls (search, MCP tools, etc.) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 491 | # Step 3: Check late exit conditions (after processing tools) | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 576 | # Step 4: Return error result if all attempts failed | COMMENT |
| LOW | src/open_deep_research/deep_researcher.py | 692 | # Step 4: Return failure result if all retries exhausted | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/open_deep_research/utils.py | 502 | except Exception: | CODE |
| LOW | src/open_deep_research/utils.py | 210 | except Exception as e: | CODE |
| LOW | src/open_deep_research/utils.py | 288 | except Exception as e: | CODE |
| LOW | src/open_deep_research/deep_researcher.py | 332 | except Exception as e: | CODE |
| LOW | src/open_deep_research/deep_researcher.py | 431 | except Exception as e: | CODE |
| LOW | src/open_deep_research/deep_researcher.py | 565 | except Exception as e: | CODE |
| LOW | src/open_deep_research/deep_researcher.py | 661 | except Exception as e: | CODE |
| LOW | src/security/auth.py | 65 | except Exception as e: | CODE |
| MEDIUM | src/legacy/utils.py | 1098 | print(f"Error in Google search for '{query}': {str(e)}") | CODE |
| MEDIUM | src/legacy/utils.py | 1166 | print(f"Error in Google search for query '{query}': {str(e)}") | CODE |
| MEDIUM | src/legacy/utils.py | 607 | def process_single_query(query): | CODE |
| MEDIUM | src/legacy/utils.py | 765 | def process_single_query(query): | CODE |
| MEDIUM | src/legacy/utils.py | 1023 | def google_search(query, max_results): | CODE |
| MEDIUM | src/legacy/utils.py | 558 | print(f"Error processing query '{query}': {str(e)}") | STRING |
| MEDIUM | src/legacy/utils.py | 694 | print(f"Error processing arXiv query '{query}': {str(e)}") | STRING |
| MEDIUM | src/legacy/utils.py | 716 | print(f"Error processing arXiv query '{query}': {str(e)}") | STRING |
| LOW | src/legacy/utils.py | 1097 | except Exception as e: | CODE |
| LOW | src/legacy/utils.py | 1146 | except Exception as e: | CODE |
| LOW | src/legacy/utils.py | 1165 | except Exception as e: | CODE |
| LOW | src/legacy/utils.py | 1232 | except Exception as e: | CODE |
| LOW | src/legacy/utils.py | 1306 | except Exception as e: | CODE |
| LOW | src/legacy/utils.py | 556 | except Exception as e: | STRING |
| LOW | src/legacy/utils.py | 692 | except Exception as e: | STRING |
| LOW | src/legacy/utils.py | 714 | except Exception as e: | STRING |
| LOW | src/legacy/utils.py | 826 | except Exception as e: | STRING |
| LOW | src/legacy/utils.py | 862 | except Exception as e: | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/prompts.py | 1 | OVERALL_QUALITY_PROMPT = """You are an expert evaluator tasked with assessing the quality of research reports. Please ev | CODE |
| MEDIUM | .github/workflows/claude-code-review.yml | 62 | # - For React components: Performance, accessibility, and best practices | COMMENT |
| MEDIUM | .github/workflows/claude-code-review.yml | 69 | # 'Please provide a thorough code review focusing on our coding standards and best practices.' }} | COMMENT |
| MEDIUM | src/open_deep_research/prompts.py | 228 | final_report_generation_prompt = """Based on all the research conducted, create a comprehensive, well-structured answer | CODE |
| MEDIUM | src/open_deep_research/utils.py | 386 | """Wrap MCP tool with comprehensive authentication and error handling. | STRING |
| MEDIUM⚡ | src/open_deep_research/deep_researcher.py | 641 | # Create comprehensive prompt with all research context | COMMENT |
| MEDIUM | src/open_deep_research/deep_researcher.py | 608 | """Generate the final comprehensive research report with retry logic for token limits. | STRING |
| MEDIUM | src/legacy/prompts.py | 83 | query_writer_instructions="""You are an expert technical writer crafting targeted web search queries that will gather co | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/supervisor_parallel_evaluation.py | 10 | def right_parallelism_evaluator( | CODE |
| LOW⚡ | src/open_deep_research/utils.py | 703 | def _check_openai_token_limit(exception: Exception, error_str: str) -> bool: | CODE |
| LOW | src/open_deep_research/utils.py | 385 | def wrap_mcp_authenticate_tool(tool: StructuredTool) -> StructuredTool: | CODE |
| LOW | src/open_deep_research/utils.py | 399 | def _find_mcp_error_in_exception_chain(exc: BaseException) -> McpError | None: | CODE |
| LOW | src/open_deep_research/utils.py | 599 | def get_notes_from_tool_calls(messages: list[MessageLikeRepresentation]): | CODE |
| LOW | src/open_deep_research/utils.py | 607 | def anthropic_websearch_called(response): | CODE |
| LOW | src/open_deep_research/utils.py | 736 | def _check_anthropic_token_limit(exception: Exception, error_str: str) -> bool: | CODE |
| LOW | src/open_deep_research/utils.py | 759 | def _check_gemini_token_limit(exception: Exception, error_str: str) -> bool: | CODE |
| LOW | src/open_deep_research/utils.py | 848 | def remove_up_to_last_ai_message(messages: list[MessageLikeRepresentation]) -> list[MessageLikeRepresentation]: | CODE |
| LOW | src/legacy/multi_agent.py | 340 | async def supervisor_should_continue(state: ReportState) -> str: | CODE |
| LOW | src/legacy/multi_agent.py | 447 | async def research_agent_should_continue(state: SectionState) -> str: | CODE |
| LOW | src/legacy/graph.py | 396 | def gather_completed_sections(state: ReportState): | CODE |
| LOW | src/legacy/graph.py | 451 | def initiate_final_section_writing(state: ReportState): | CODE |
| LOW | src/legacy/utils.py | 89 | def deduplicate_and_format_sources( | CODE |
| LOW | src/legacy/utils.py | 1501 | async def select_and_execute_search(search_api: str, query_list: list[str], params_to_pass: dict) -> str: | CODE |
| LOW | src/legacy/utils.py | 1573 | def split_and_rerank_search_results(embeddings: Embeddings, query: str, search_results: list[dict], max_chunks: int = 5) | CODE |
| LOW | src/legacy/utils.py | 219 | async def azureaisearch_search_async(search_queries: list[str], max_results: int = 5, topic: str = "general", include_ra | STRING |
| LOW | src/legacy/tests/test_report_quality.py | 140 | def test_response_criteria_evaluation(research_agent, search_api, models, eval_model): | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/open_deep_research/deep_researcher.py | 713 | # Define main workflow edges for sequential execution | COMMENT |
| MEDIUM | src/legacy/utils.py | 1207 | # Create an async HTTP client | COMMENT |
| MEDIUM⚡ | src/legacy/utils.py | 417 | # Define the function to process a single query | STRING |
| MEDIUM⚡ | src/legacy/utils.py | 422 | # Define the function for the executor with all parameters | STRING |
| MEDIUM | src/legacy/tests/test_report_quality.py | 147 | # Create a table for model configuration | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/open_deep_research/utils.py | 531 | CODE | |
| LOW | src/open_deep_research/utils.py | 665 | CODE | |
| LOW | src/open_deep_research/utils.py | 892 | CODE | |
| LOW | src/open_deep_research/deep_researcher.py | 607 | CODE | |
| LOW | src/legacy/multi_agent.py | 240 | CODE | |
| LOW | src/legacy/utils.py | 374 | CODE | |
| LOW | src/legacy/utils.py | 577 | CODE | |
| LOW | src/legacy/utils.py | 928 | CODE | |
| LOW | src/legacy/utils.py | 1188 | CODE | |
| LOW | src/legacy/utils.py | 1248 | CODE | |
| LOW | src/legacy/utils.py | 1501 | CODE | |
| LOW | src/legacy/utils.py | 418 | CODE | |
| LOW | src/legacy/utils.py | 607 | CODE | |
| LOW | src/legacy/utils.py | 967 | CODE | |
| LOW | src/legacy/utils.py | 1258 | CODE | |
| LOW | src/legacy/utils.py | 1262 | CODE | |
| LOW | src/legacy/utils.py | 1023 | CODE | |
| LOW | src/legacy/utils.py | 1118 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | src/legacy/CLAUDE.md | 61 | # Test only the multi-agent implementation | COMMENT |
| MEDIUM | src/legacy/tests/test_report_quality.py | 174 | # Checkpointer for the multi-agent approach | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/legacy/utils.py | 1502 | Select and execute the appropriate search API. Args: search_api: Name of the search API to use | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | src/open_deep_research/utils.py | 710 | # Check if this is an OpenAI exception | COMMENT |
| LOW | src/open_deep_research/utils.py | 743 | # Check if this is an Anthropic exception | COMMENT |
| LOW | src/open_deep_research/utils.py | 766 | # Check if this is a Google/Gemini exception | COMMENT |
| LOW⚡ | src/legacy/utils.py | 426 | # Set text to True if max_characters is None, otherwise use an object with max_characters | STRING |
| LOW | src/legacy/tests/run_test.py | 129 | # Display results with rich formatting | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | .github/workflows/claude-code-review.yml | 1 | name: Claude Code Review | COMMENT |
| LOW | .github/workflows/claude-code-review.yml | 61 | # - For API endpoints: Security, input validation, and error handling | COMMENT |
| LOW | .github/workflows/claude.yml | 41 | actions: read | COMMENT |
| LOW | .github/workflows/claude.yml | 61 | # Optional: Custom environment variables for Claude | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH⚡ | src/legacy/utils.py | 428 | "summary": True, # This is an amazing feature by EXA. It provides an AI generated summary of the conten | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/legacy/tests/conftest.py | 5 | CODE | |
| LOW | src/legacy/tests/test_report_quality.py | 13 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | src/security/auth.py | 51 | CODE |