bad-research 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bad_research-0.1.0/.gitignore +25 -0
- bad_research-0.1.0/LICENSE +21 -0
- bad_research-0.1.0/PKG-INFO +143 -0
- bad_research-0.1.0/README.md +75 -0
- bad_research-0.1.0/assets/banner.png +0 -0
- bad_research-0.1.0/docs/HOW_IT_WORKS.md +142 -0
- bad_research-0.1.0/golden-eval-report.json +179 -0
- bad_research-0.1.0/pyproject.toml +187 -0
- bad_research-0.1.0/src/bad_research/__init__.py +3 -0
- bad_research-0.1.0/src/bad_research/__main__.py +5 -0
- bad_research-0.1.0/src/bad_research/_banner.py +33 -0
- bad_research-0.1.0/src/bad_research/browse/__init__.py +55 -0
- bad_research-0.1.0/src/bad_research/browse/agent_browser.py +470 -0
- bad_research-0.1.0/src/bad_research/browse/aql.py +476 -0
- bad_research-0.1.0/src/bad_research/browse/base.py +76 -0
- bad_research-0.1.0/src/bad_research/browse/cache.py +45 -0
- bad_research-0.1.0/src/bad_research/browse/extract_llm.py +113 -0
- bad_research-0.1.0/src/bad_research/browse/ladder.py +216 -0
- bad_research-0.1.0/src/bad_research/calibrate/__init__.py +51 -0
- bad_research-0.1.0/src/bad_research/calibrate/baselines.py +74 -0
- bad_research-0.1.0/src/bad_research/calibrate/constants.py +39 -0
- bad_research-0.1.0/src/bad_research/calibrate/cost.py +122 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/01_causal_light.json +23 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/02_comparison.json +22 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/03_multidomain_full.json +24 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/04_contested_argumentative.json +22 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/05_definitional.json +21 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/06_recency_temporal.json +22 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/07_breadth_list.json +22 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden/08_numeric_precise.json +22 -0
- bad_research-0.1.0/src/bad_research/calibrate/golden.py +324 -0
- bad_research-0.1.0/src/bad_research/calibrate/harness.py +152 -0
- bad_research-0.1.0/src/bad_research/calibrate/judge.py +204 -0
- bad_research-0.1.0/src/bad_research/calibrate/runner.py +55 -0
- bad_research-0.1.0/src/bad_research/cli/__init__.py +70 -0
- bad_research-0.1.0/src/bad_research/cli/_output.py +29 -0
- bad_research-0.1.0/src/bad_research/cli/calibrate.py +212 -0
- bad_research-0.1.0/src/bad_research/cli/doctor.py +121 -0
- bad_research-0.1.0/src/bad_research/cli/fetch.py +80 -0
- bad_research-0.1.0/src/bad_research/cli/install.py +63 -0
- bad_research-0.1.0/src/bad_research/cli/research.py +523 -0
- bad_research-0.1.0/src/bad_research/config.py +121 -0
- bad_research-0.1.0/src/bad_research/core/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/core/agent_docs.py +204 -0
- bad_research-0.1.0/src/bad_research/core/config.py +113 -0
- bad_research-0.1.0/src/bad_research/core/db.py +171 -0
- bad_research-0.1.0/src/bad_research/core/enrich.py +110 -0
- bad_research-0.1.0/src/bad_research/core/fetcher.py +383 -0
- bad_research-0.1.0/src/bad_research/core/frontmatter.py +55 -0
- bad_research-0.1.0/src/bad_research/core/hooks.py +3738 -0
- bad_research-0.1.0/src/bad_research/core/linker.py +138 -0
- bad_research-0.1.0/src/bad_research/core/migrations.py +254 -0
- bad_research-0.1.0/src/bad_research/core/note.py +129 -0
- bad_research-0.1.0/src/bad_research/core/patterns.py +94 -0
- bad_research-0.1.0/src/bad_research/core/similarity.py +81 -0
- bad_research-0.1.0/src/bad_research/core/sync.py +372 -0
- bad_research-0.1.0/src/bad_research/core/templates.py +209 -0
- bad_research-0.1.0/src/bad_research/core/vault.py +168 -0
- bad_research-0.1.0/src/bad_research/embed/__init__.py +7 -0
- bad_research-0.1.0/src/bad_research/embed/base.py +45 -0
- bad_research-0.1.0/src/bad_research/embed/bge_local.py +38 -0
- bad_research-0.1.0/src/bad_research/export/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/funnel/__init__.py +30 -0
- bad_research-0.1.0/src/bad_research/funnel/_async.py +28 -0
- bad_research-0.1.0/src/bad_research/funnel/canonical.py +38 -0
- bad_research-0.1.0/src/bad_research/funnel/config.py +72 -0
- bad_research-0.1.0/src/bad_research/funnel/dedup.py +76 -0
- bad_research-0.1.0/src/bad_research/funnel/fanout.py +93 -0
- bad_research-0.1.0/src/bad_research/funnel/filter.py +73 -0
- bad_research-0.1.0/src/bad_research/funnel/orchestrator.py +107 -0
- bad_research-0.1.0/src/bad_research/funnel/rank.py +103 -0
- bad_research-0.1.0/src/bad_research/funnel/read.py +128 -0
- bad_research-0.1.0/src/bad_research/funnel/store.py +93 -0
- bad_research-0.1.0/src/bad_research/graph/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/grounding/__init__.py +51 -0
- bad_research-0.1.0/src/bad_research/grounding/anchors.py +149 -0
- bad_research-0.1.0/src/bad_research/grounding/extract.py +62 -0
- bad_research-0.1.0/src/bad_research/grounding/gate.py +212 -0
- bad_research-0.1.0/src/bad_research/grounding/nli.py +91 -0
- bad_research-0.1.0/src/bad_research/grounding/render.py +129 -0
- bad_research-0.1.0/src/bad_research/grounding/verifier.py +376 -0
- bad_research-0.1.0/src/bad_research/indexgen/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/indexgen/generator.py +256 -0
- bad_research-0.1.0/src/bad_research/llm/__init__.py +19 -0
- bad_research-0.1.0/src/bad_research/llm/anthropic.py +167 -0
- bad_research-0.1.0/src/bad_research/llm/base.py +54 -0
- bad_research-0.1.0/src/bad_research/mcp/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/mcp/server.py +475 -0
- bad_research-0.1.0/src/bad_research/models/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/models/graph.py +21 -0
- bad_research-0.1.0/src/bad_research/models/note.py +119 -0
- bad_research-0.1.0/src/bad_research/models/output.py +28 -0
- bad_research-0.1.0/src/bad_research/models/search.py +24 -0
- bad_research-0.1.0/src/bad_research/pipeline.py +268 -0
- bad_research-0.1.0/src/bad_research/providers.py +127 -0
- bad_research-0.1.0/src/bad_research/py.typed +0 -0
- bad_research-0.1.0/src/bad_research/quality/__init__.py +49 -0
- bad_research-0.1.0/src/bad_research/quality/consistency.py +135 -0
- bad_research-0.1.0/src/bad_research/quality/content_filter.py +85 -0
- bad_research-0.1.0/src/bad_research/quality/dedup.py +78 -0
- bad_research-0.1.0/src/bad_research/quality/grader.py +118 -0
- bad_research-0.1.0/src/bad_research/quality/injection.py +41 -0
- bad_research-0.1.0/src/bad_research/quality/prefilter.py +268 -0
- bad_research-0.1.0/src/bad_research/quality/rank.py +20 -0
- bad_research-0.1.0/src/bad_research/quality/recitation.py +148 -0
- bad_research-0.1.0/src/bad_research/quality/relevance.py +57 -0
- bad_research-0.1.0/src/bad_research/quality/sources.py +56 -0
- bad_research-0.1.0/src/bad_research/retrieval/__init__.py +12 -0
- bad_research-0.1.0/src/bad_research/retrieval/anchors.py +39 -0
- bad_research-0.1.0/src/bad_research/retrieval/base.py +28 -0
- bad_research-0.1.0/src/bad_research/retrieval/cache.py +194 -0
- bad_research-0.1.0/src/bad_research/retrieval/chunker.py +101 -0
- bad_research-0.1.0/src/bad_research/retrieval/chunker_code.py +221 -0
- bad_research-0.1.0/src/bad_research/retrieval/constants.py +66 -0
- bad_research-0.1.0/src/bad_research/retrieval/engine.py +318 -0
- bad_research-0.1.0/src/bad_research/retrieval/fts_chunks.py +52 -0
- bad_research-0.1.0/src/bad_research/retrieval/fusion.py +70 -0
- bad_research-0.1.0/src/bad_research/retrieval/reflections.py +217 -0
- bad_research-0.1.0/src/bad_research/retrieval/rerank.py +247 -0
- bad_research-0.1.0/src/bad_research/retrieval/store.py +134 -0
- bad_research-0.1.0/src/bad_research/search/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/search/filters.py +105 -0
- bad_research-0.1.0/src/bad_research/search/fts.py +142 -0
- bad_research-0.1.0/src/bad_research/serve/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/serve/renderer.py +124 -0
- bad_research-0.1.0/src/bad_research/serve/server.py +588 -0
- bad_research-0.1.0/src/bad_research/skills/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-0.5-clarify.md +81 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-1-decompose.md +194 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-1.6-plan-gate.md +113 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-10-triple-draft.md +285 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-11-synthesize.md +339 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-11.5-citation-verifier.md +86 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-12-critics.md +128 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-12.5-grader.md +154 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-13-gap-fetch.md +99 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-14-patcher.md +182 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-15-polish.md +159 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-16-readability-audit.md +248 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-2-width-sweep.md +441 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-3-contradiction-graph.md +73 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-4-loci-analysis.md +128 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-5-depth-investigation.md +152 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-6-cross-locus-reconcile.md +81 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-7-source-tensions.md +100 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-8-corpus-critic.md +134 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-9-evidence-digest.md +82 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-agentic-fast.md +86 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-fresh-review.md +83 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research-query-router.md +89 -0
- bad_research-0.1.0/src/bad_research/skills/bad-research.md +366 -0
- bad_research-0.1.0/src/bad_research/skills/router.py +406 -0
- bad_research-0.1.0/src/bad_research/skills/routing_constants.py +193 -0
- bad_research-0.1.0/src/bad_research/web/__init__.py +1 -0
- bad_research-0.1.0/src/bad_research/web/base.py +258 -0
- bad_research-0.1.0/src/bad_research/web/builtin.py +127 -0
- bad_research-0.1.0/src/bad_research/web/content/__init__.py +55 -0
- bad_research-0.1.0/src/bad_research/web/content/fetch_clean.py +736 -0
- bad_research-0.1.0/src/bad_research/web/content/sources.py +441 -0
- bad_research-0.1.0/src/bad_research/web/crawl4ai_provider.py +448 -0
- bad_research-0.1.0/src/bad_research/web/search/__init__.py +50 -0
- bad_research-0.1.0/src/bad_research/web/search/base.py +249 -0
- bad_research-0.1.0/src/bad_research/web/search/loop.py +46 -0
- bad_research-0.1.0/src/bad_research/web/search/rank.py +116 -0
- bad_research-0.1.0/src/bad_research/web/search/rerank.py +164 -0
- bad_research-0.1.0/src/bad_research/web/search/route.py +48 -0
- bad_research-0.1.0/src/bad_research/web/search/verticals.py +393 -0
- bad_research-0.1.0/tests/__init__.py +1 -0
- bad_research-0.1.0/tests/conftest.py +39 -0
- bad_research-0.1.0/tests/test_browse/__init__.py +0 -0
- bad_research-0.1.0/tests/test_browse/conftest.py +153 -0
- bad_research-0.1.0/tests/test_browse/test_agent_browser_browse.py +155 -0
- bad_research-0.1.0/tests/test_browse/test_agent_browser_cli.py +101 -0
- bad_research-0.1.0/tests/test_browse/test_agent_browser_snapshot.py +80 -0
- bad_research-0.1.0/tests/test_browse/test_aql.py +104 -0
- bad_research-0.1.0/tests/test_browse/test_aql_resolver.py +83 -0
- bad_research-0.1.0/tests/test_browse/test_base.py +56 -0
- bad_research-0.1.0/tests/test_browse/test_cache.py +40 -0
- bad_research-0.1.0/tests/test_browse/test_extract_llm.py +81 -0
- bad_research-0.1.0/tests/test_browse/test_fetcher_hook.py +75 -0
- bad_research-0.1.0/tests/test_browse/test_graceful_degradation.py +63 -0
- bad_research-0.1.0/tests/test_browse/test_ladder.py +164 -0
- bad_research-0.1.0/tests/test_calibrate/__init__.py +0 -0
- bad_research-0.1.0/tests/test_calibrate/conftest.py +64 -0
- bad_research-0.1.0/tests/test_calibrate/test_baselines.py +50 -0
- bad_research-0.1.0/tests/test_calibrate/test_calibrate_cmd.py +58 -0
- bad_research-0.1.0/tests/test_calibrate/test_cost.py +75 -0
- bad_research-0.1.0/tests/test_calibrate/test_gate_cmd.py +85 -0
- bad_research-0.1.0/tests/test_calibrate/test_golden.py +114 -0
- bad_research-0.1.0/tests/test_calibrate/test_harness.py +107 -0
- bad_research-0.1.0/tests/test_calibrate/test_judge.py +79 -0
- bad_research-0.1.0/tests/test_calibrate/test_judge_rails.py +104 -0
- bad_research-0.1.0/tests/test_calibrate/test_runner_bridge.py +20 -0
- bad_research-0.1.0/tests/test_cli/__init__.py +0 -0
- bad_research-0.1.0/tests/test_cli/test_cli_subcommands.py +244 -0
- bad_research-0.1.0/tests/test_cli/test_keyless_rewire.py +431 -0
- bad_research-0.1.0/tests/test_config/__init__.py +1 -0
- bad_research-0.1.0/tests/test_config/test_config.py +80 -0
- bad_research-0.1.0/tests/test_content/__init__.py +0 -0
- bad_research-0.1.0/tests/test_content/conftest.py +88 -0
- bad_research-0.1.0/tests/test_content/test_cache_fetch.py +211 -0
- bad_research-0.1.0/tests/test_content/test_classify_source.py +30 -0
- bad_research-0.1.0/tests/test_content/test_highlights.py +28 -0
- bad_research-0.1.0/tests/test_content/test_init_shadow.py +30 -0
- bad_research-0.1.0/tests/test_content/test_keyless_guard.py +78 -0
- bad_research-0.1.0/tests/test_content/test_llm_clean.py +43 -0
- bad_research-0.1.0/tests/test_content/test_main_content.py +39 -0
- bad_research-0.1.0/tests/test_content/test_markdown.py +32 -0
- bad_research-0.1.0/tests/test_content/test_metadata.py +48 -0
- bad_research-0.1.0/tests/test_content/test_pdf.py +18 -0
- bad_research-0.1.0/tests/test_content/test_render_ssrf.py +130 -0
- bad_research-0.1.0/tests/test_content/test_sources_cli.py +87 -0
- bad_research-0.1.0/tests/test_content/test_sources_html.py +96 -0
- bad_research-0.1.0/tests/test_content/test_sources_ssrf.py +64 -0
- bad_research-0.1.0/tests/test_content/test_strip_boilerplate.py +53 -0
- bad_research-0.1.0/tests/test_core/__init__.py +0 -0
- bad_research-0.1.0/tests/test_core/test_ssrf.py +231 -0
- bad_research-0.1.0/tests/test_core/test_ssrf_predicate.py +60 -0
- bad_research-0.1.0/tests/test_embed/__init__.py +1 -0
- bad_research-0.1.0/tests/test_embed/test_base.py +51 -0
- bad_research-0.1.0/tests/test_embed/test_bge_local.py +23 -0
- bad_research-0.1.0/tests/test_funnel/__init__.py +0 -0
- bad_research-0.1.0/tests/test_funnel/conftest.py +194 -0
- bad_research-0.1.0/tests/test_funnel/test_async.py +52 -0
- bad_research-0.1.0/tests/test_funnel/test_canonical.py +39 -0
- bad_research-0.1.0/tests/test_funnel/test_config.py +48 -0
- bad_research-0.1.0/tests/test_funnel/test_dedup.py +54 -0
- bad_research-0.1.0/tests/test_funnel/test_fanout.py +59 -0
- bad_research-0.1.0/tests/test_funnel/test_filter.py +66 -0
- bad_research-0.1.0/tests/test_funnel/test_orchestrator.py +117 -0
- bad_research-0.1.0/tests/test_funnel/test_rank.py +58 -0
- bad_research-0.1.0/tests/test_funnel/test_read.py +99 -0
- bad_research-0.1.0/tests/test_grounding/__init__.py +0 -0
- bad_research-0.1.0/tests/test_grounding/conftest.py +38 -0
- bad_research-0.1.0/tests/test_grounding/test_anchors.py +135 -0
- bad_research-0.1.0/tests/test_grounding/test_confidence_band.py +31 -0
- bad_research-0.1.0/tests/test_grounding/test_extract.py +37 -0
- bad_research-0.1.0/tests/test_grounding/test_gate.py +163 -0
- bad_research-0.1.0/tests/test_grounding/test_host_judge.py +175 -0
- bad_research-0.1.0/tests/test_grounding/test_nli.py +114 -0
- bad_research-0.1.0/tests/test_grounding/test_public_api.py +13 -0
- bad_research-0.1.0/tests/test_grounding/test_render.py +120 -0
- bad_research-0.1.0/tests/test_grounding/test_seam.py +11 -0
- bad_research-0.1.0/tests/test_grounding/test_verifier.py +409 -0
- bad_research-0.1.0/tests/test_install/__init__.py +0 -0
- bad_research-0.1.0/tests/test_install/test_install_cli_e2e.py +34 -0
- bad_research-0.1.0/tests/test_install/test_install_global.py +51 -0
- bad_research-0.1.0/tests/test_install/test_install_project.py +32 -0
- bad_research-0.1.0/tests/test_install/test_step_list.py +25 -0
- bad_research-0.1.0/tests/test_llm/__init__.py +1 -0
- bad_research-0.1.0/tests/test_llm/test_anthropic.py +289 -0
- bad_research-0.1.0/tests/test_llm/test_base.py +52 -0
- bad_research-0.1.0/tests/test_mcp/__init__.py +0 -0
- bad_research-0.1.0/tests/test_mcp/test_mcp_tools.py +16 -0
- bad_research-0.1.0/tests/test_packaging/__init__.py +0 -0
- bad_research-0.1.0/tests/test_packaging/test_base_leanness.py +88 -0
- bad_research-0.1.0/tests/test_packaging/test_doctor.py +63 -0
- bad_research-0.1.0/tests/test_packaging/test_install_idempotent.py +51 -0
- bad_research-0.1.0/tests/test_packaging/test_live_skip.py +18 -0
- bad_research-0.1.0/tests/test_packaging/test_pyproject.py +104 -0
- bad_research-0.1.0/tests/test_packaging/test_pytest_config.py +65 -0
- bad_research-0.1.0/tests/test_packaging/test_wheel_build.py +80 -0
- bad_research-0.1.0/tests/test_pipeline/__init__.py +0 -0
- bad_research-0.1.0/tests/test_pipeline/test_build_real.py +98 -0
- bad_research-0.1.0/tests/test_pipeline/test_run_query.py +134 -0
- bad_research-0.1.0/tests/test_providers.py +83 -0
- bad_research-0.1.0/tests/test_quality/__init__.py +0 -0
- bad_research-0.1.0/tests/test_quality/conftest.py +104 -0
- bad_research-0.1.0/tests/test_quality/test_consistency.py +132 -0
- bad_research-0.1.0/tests/test_quality/test_content_filter.py +64 -0
- bad_research-0.1.0/tests/test_quality/test_dedup.py +48 -0
- bad_research-0.1.0/tests/test_quality/test_grader.py +94 -0
- bad_research-0.1.0/tests/test_quality/test_injection.py +40 -0
- bad_research-0.1.0/tests/test_quality/test_pipeline_e2e.py +66 -0
- bad_research-0.1.0/tests/test_quality/test_prefilter.py +180 -0
- bad_research-0.1.0/tests/test_quality/test_public_api.py +33 -0
- bad_research-0.1.0/tests/test_quality/test_rank.py +56 -0
- bad_research-0.1.0/tests/test_quality/test_recitation.py +112 -0
- bad_research-0.1.0/tests/test_quality/test_relevance.py +65 -0
- bad_research-0.1.0/tests/test_quality/test_sources.py +55 -0
- bad_research-0.1.0/tests/test_retrieval/__init__.py +0 -0
- bad_research-0.1.0/tests/test_retrieval/conftest.py +104 -0
- bad_research-0.1.0/tests/test_retrieval/test_anchors.py +35 -0
- bad_research-0.1.0/tests/test_retrieval/test_base.py +24 -0
- bad_research-0.1.0/tests/test_retrieval/test_cache.py +91 -0
- bad_research-0.1.0/tests/test_retrieval/test_chunker.py +55 -0
- bad_research-0.1.0/tests/test_retrieval/test_chunker_code.py +104 -0
- bad_research-0.1.0/tests/test_retrieval/test_config.py +15 -0
- bad_research-0.1.0/tests/test_retrieval/test_constants.py +42 -0
- bad_research-0.1.0/tests/test_retrieval/test_engine.py +280 -0
- bad_research-0.1.0/tests/test_retrieval/test_fts_chunks.py +46 -0
- bad_research-0.1.0/tests/test_retrieval/test_fusion.py +93 -0
- bad_research-0.1.0/tests/test_retrieval/test_import_keyless.py +60 -0
- bad_research-0.1.0/tests/test_retrieval/test_no_keys_invariant.py +43 -0
- bad_research-0.1.0/tests/test_retrieval/test_reflections.py +150 -0
- bad_research-0.1.0/tests/test_retrieval/test_rerank.py +225 -0
- bad_research-0.1.0/tests/test_retrieval/test_schema_migration.py +32 -0
- bad_research-0.1.0/tests/test_skills/__init__.py +0 -0
- bad_research-0.1.0/tests/test_skills/conftest.py +15 -0
- bad_research-0.1.0/tests/test_skills/test_agentic_fast_skill.py +16 -0
- bad_research-0.1.0/tests/test_skills/test_all_skills_valid.py +15 -0
- bad_research-0.1.0/tests/test_skills/test_citation_verifier_skill.py +16 -0
- bad_research-0.1.0/tests/test_skills/test_clarify_skill.py +15 -0
- bad_research-0.1.0/tests/test_skills/test_delegation_contract.py +46 -0
- bad_research-0.1.0/tests/test_skills/test_entry_skill.py +22 -0
- bad_research-0.1.0/tests/test_skills/test_fresh_review_skill.py +15 -0
- bad_research-0.1.0/tests/test_skills/test_grader_skill.py +27 -0
- bad_research-0.1.0/tests/test_skills/test_light_critic.py +101 -0
- bad_research-0.1.0/tests/test_skills/test_modified_stages.py +189 -0
- bad_research-0.1.0/tests/test_skills/test_plan_gate.py +162 -0
- bad_research-0.1.0/tests/test_skills/test_router.py +74 -0
- bad_research-0.1.0/tests/test_skills/test_router_effort.py +114 -0
- bad_research-0.1.0/tests/test_skills/test_router_modality.py +169 -0
- bad_research-0.1.0/tests/test_skills/test_router_shape.py +244 -0
- bad_research-0.1.0/tests/test_skills/test_router_skill.py +15 -0
- bad_research-0.1.0/tests/test_skills/test_router_tiering.py +195 -0
- bad_research-0.1.0/tests/test_skills/test_validate_self.py +18 -0
- bad_research-0.1.0/tests/test_skills/validate.py +54 -0
- bad_research-0.1.0/tests/test_web/__init__.py +0 -0
- bad_research-0.1.0/tests/test_web/fixtures/arxiv_query.atom +23 -0
- bad_research-0.1.0/tests/test_web/fixtures/crossref_works.json +16 -0
- bad_research-0.1.0/tests/test_web/fixtures/europepmc_search.json +20 -0
- bad_research-0.1.0/tests/test_web/fixtures/openalex_works.json +16 -0
- bad_research-0.1.0/tests/test_web/fixtures/pubmed_esearch.json +7 -0
- bad_research-0.1.0/tests/test_web/fixtures/pubmed_esummary.json +7 -0
- bad_research-0.1.0/tests/test_web/fixtures/s2_search.json +16 -0
- bad_research-0.1.0/tests/test_web/fixtures/wikipedia_search.json +1 -0
- bad_research-0.1.0/tests/test_web/fixtures/wikipedia_summary.json +1 -0
- bad_research-0.1.0/tests/test_web/test_provider_factory.py +71 -0
- bad_research-0.1.0/tests/test_web/test_search_live.py +49 -0
- bad_research-0.1.0/tests/test_web/test_search_loop.py +75 -0
- bad_research-0.1.0/tests/test_web/test_search_providers.py +150 -0
- bad_research-0.1.0/tests/test_web/test_search_rank.py +73 -0
- bad_research-0.1.0/tests/test_web/test_search_rerank.py +122 -0
- bad_research-0.1.0/tests/test_web/test_search_route.py +45 -0
- bad_research-0.1.0/tests/test_web/test_search_verticals.py +146 -0
- bad_research-0.1.0/tests/test_web/test_web_search_query.py +78 -0
- bad_research-0.1.0/uv.lock +3936 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.venv/
|
|
4
|
+
venv/
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.pytest_cache/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.coverage
|
|
12
|
+
htmlcov/
|
|
13
|
+
.DS_Store
|
|
14
|
+
|
|
15
|
+
# dev-only build artifacts — not shipped (kept on disk for dev, out of the prod repo)
|
|
16
|
+
docs/plans/
|
|
17
|
+
docs/investigation/
|
|
18
|
+
docs/INTERFACES.md
|
|
19
|
+
docs/INTERFACES_KEYLESS.md
|
|
20
|
+
docs/KEYLESS_REBUILD_PLAN_OUTLINE.md
|
|
21
|
+
docs/SPEC.md
|
|
22
|
+
docs/enhancements/
|
|
23
|
+
|
|
24
|
+
# research vault — per-run output/scratch (eval + real runs), never shipped
|
|
25
|
+
research/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bad Research
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bad-research
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: michael jackson bad
|
|
5
|
+
Project-URL: Homepage, https://github.com/LeventySeven/badresearch
|
|
6
|
+
Project-URL: Repository, https://github.com/LeventySeven/badresearch
|
|
7
|
+
Project-URL: Issues, https://github.com/LeventySeven/badresearch/issues
|
|
8
|
+
Author: Bad Research
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agent,claude,cli,deep-research,llm,rag,research,retrieval
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Python: <3.14,>=3.11
|
|
20
|
+
Requires-Dist: anthropic>=0.40
|
|
21
|
+
Requires-Dist: beautifulsoup4>=4.12
|
|
22
|
+
Requires-Dist: crawl4ai>=0.4
|
|
23
|
+
Requires-Dist: dateparser>=1.2
|
|
24
|
+
Requires-Dist: ddgs>=9.14
|
|
25
|
+
Requires-Dist: feedparser>=6.0
|
|
26
|
+
Requires-Dist: httpx>=0.27
|
|
27
|
+
Requires-Dist: jinja2>=3.1
|
|
28
|
+
Requires-Dist: langdetect>=1.0.9
|
|
29
|
+
Requires-Dist: lxml>=5.0
|
|
30
|
+
Requires-Dist: platformdirs>=4.0
|
|
31
|
+
Requires-Dist: pydantic>=2.0
|
|
32
|
+
Requires-Dist: pymupdf4llm>=0.0.17
|
|
33
|
+
Requires-Dist: pymupdf>=1.24
|
|
34
|
+
Requires-Dist: pyyaml>=6.0
|
|
35
|
+
Requires-Dist: rank-bm25>=0.2
|
|
36
|
+
Requires-Dist: rapidfuzz>=3.0
|
|
37
|
+
Requires-Dist: rich>=13.0
|
|
38
|
+
Requires-Dist: snowballstemmer>=2.2
|
|
39
|
+
Requires-Dist: trafilatura>=1.8
|
|
40
|
+
Requires-Dist: tree-sitter-language-pack>=0.7
|
|
41
|
+
Requires-Dist: tree-sitter>=0.23
|
|
42
|
+
Requires-Dist: typer>=0.9.0
|
|
43
|
+
Provides-Extra: all
|
|
44
|
+
Requires-Dist: lancedb>=0.13; extra == 'all'
|
|
45
|
+
Requires-Dist: mcp>=1.6; extra == 'all'
|
|
46
|
+
Requires-Dist: playwright>=1.40; extra == 'all'
|
|
47
|
+
Requires-Dist: pyarrow>=15.0; extra == 'all'
|
|
48
|
+
Requires-Dist: sentence-transformers>=3.0; extra == 'all'
|
|
49
|
+
Requires-Dist: torch>=2.0; extra == 'all'
|
|
50
|
+
Provides-Extra: browse
|
|
51
|
+
Requires-Dist: playwright>=1.40; extra == 'browse'
|
|
52
|
+
Provides-Extra: dev
|
|
53
|
+
Requires-Dist: mcp>=1.6; extra == 'dev'
|
|
54
|
+
Requires-Dist: mypy>=1.8; extra == 'dev'
|
|
55
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
56
|
+
Requires-Dist: pytest-cov>=4.1; extra == 'dev'
|
|
57
|
+
Requires-Dist: pytest>=7.4; extra == 'dev'
|
|
58
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
59
|
+
Requires-Dist: ruff>=0.3; extra == 'dev'
|
|
60
|
+
Provides-Extra: local
|
|
61
|
+
Requires-Dist: lancedb>=0.13; extra == 'local'
|
|
62
|
+
Requires-Dist: pyarrow>=15.0; extra == 'local'
|
|
63
|
+
Requires-Dist: sentence-transformers>=3.0; extra == 'local'
|
|
64
|
+
Requires-Dist: torch>=2.0; extra == 'local'
|
|
65
|
+
Provides-Extra: mcp
|
|
66
|
+
Requires-Dist: mcp>=1.6; extra == 'mcp'
|
|
67
|
+
Description-Content-Type: text/markdown
|
|
68
|
+
|
|
69
|
+
<p align="center">
|
|
70
|
+
<img src="assets/banner.png" alt="BAD — michael jackson bad" width="520">
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
<h1 align="center">Bad Research</h1>
|
|
74
|
+
|
|
75
|
+
<p align="center"><em>michael jackson bad</em></p>
|
|
76
|
+
|
|
77
|
+
A **keyless** deep-research agent that runs as a Claude Code skill — a
|
|
78
|
+
fork-and-enhance of [hyperresearch](https://github.com/jordan-gibbs/hyperresearch).
|
|
79
|
+
It searches wide, filters garbage, grounds every claim to a source, and needs
|
|
80
|
+
**zero API keys**: the Claude Code host model supplies all inference, exactly like
|
|
81
|
+
hyperresearch. Optional local CLIs and a `[local]` neural extra are enhancements,
|
|
82
|
+
never requirements.
|
|
83
|
+
|
|
84
|
+
## Install
|
|
85
|
+
|
|
86
|
+
Bad Research is a small CLI that registers itself as a Claude Code skill. No API keys. Requires Python 3.11–3.13.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Install the CLI (pipx or uv — either works)
|
|
90
|
+
pipx install bad-research
|
|
91
|
+
uv tool install bad-research
|
|
92
|
+
|
|
93
|
+
# Register the /bad-research skill into ~/.claude
|
|
94
|
+
bad install
|
|
95
|
+
|
|
96
|
+
# Verify
|
|
97
|
+
bad doctor
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`bad install` writes the entry skill to `~/.claude/skills/bad-research/`; the per-step
|
|
101
|
+
skills install lazily on first use. For a project-local install instead of global, run
|
|
102
|
+
`bad install --project` inside the project. `bad doctor` shows what's wired (host model,
|
|
103
|
+
keyless search/browse, the optional external CLIs it can drive, the `[local]` neural stack).
|
|
104
|
+
|
|
105
|
+
## Use it in Claude Code
|
|
106
|
+
|
|
107
|
+
After `bad install`, open Claude Code in any project and either:
|
|
108
|
+
|
|
109
|
+
- **Invoke it directly** — type the slash command with your question:
|
|
110
|
+
```
|
|
111
|
+
/bad-research Is open-source AI more dangerous than closed-source for national security?
|
|
112
|
+
```
|
|
113
|
+
- **Let Claude trigger it** — just ask a research-shaped question (*"write me a cited report
|
|
114
|
+
comparing vector databases"*, *"literature review on GLP-1 drugs"*) and Claude loads the
|
|
115
|
+
skill automatically.
|
|
116
|
+
|
|
117
|
+
It scales to the question: a simple lookup gets a fast cited answer in minutes; a broad or
|
|
118
|
+
contested one runs the full adversarially-reviewed pipeline (~1.5–2.5 h). The final report
|
|
119
|
+
and every fetched source land in a vault under `./research/` that compounds across sessions.
|
|
120
|
+
|
|
121
|
+
> Want the latest unreleased build? Install from source: `pipx install git+https://github.com/LeventySeven/badresearch.git`
|
|
122
|
+
|
|
123
|
+
## What it does
|
|
124
|
+
|
|
125
|
+
A tier-adaptive pipeline turns a question into an audited, fully-cited report, and
|
|
126
|
+
every fetched source lands in a persistent, searchable vault that compounds across
|
|
127
|
+
sessions. Keyless by design:
|
|
128
|
+
|
|
129
|
+
- **Search** — the host `WebSearch` tool + DuckDuckGo + 7 scholarly APIs, fused and reranked by the host model.
|
|
130
|
+
- **Content** — a native fetch-and-clean pipeline (readability → markdown → optional LLM clean), SSRF-guarded.
|
|
131
|
+
- **Browse** — an agentic observe → act → extract loop driven by a local, keyless headless browser.
|
|
132
|
+
- **Retrieve** — SQLite FTS5/BM25 by default (no model required), with an optional local neural lane.
|
|
133
|
+
- **Ground** — every report sentence is checked against its source; uncited claims are blocked.
|
|
134
|
+
|
|
135
|
+
## How it works & where the patterns came from
|
|
136
|
+
|
|
137
|
+
Bad Research takes hyperresearch as its base and enhances each stage with patterns
|
|
138
|
+
drawn from the best deep-research systems — Perplexity, Gemini, Firecrawl, Stagehand,
|
|
139
|
+
AgentQL, and others — reimplemented to run **keyless** on the host model. The full
|
|
140
|
+
write-up, stage by stage with provenance, is in
|
|
141
|
+
[**docs/HOW_IT_WORKS.md**](docs/HOW_IT_WORKS.md).
|
|
142
|
+
|
|
143
|
+
MIT licensed.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner.png" alt="BAD — michael jackson bad" width="520">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Bad Research</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><em>michael jackson bad</em></p>
|
|
8
|
+
|
|
9
|
+
A **keyless** deep-research agent that runs as a Claude Code skill — a
|
|
10
|
+
fork-and-enhance of [hyperresearch](https://github.com/jordan-gibbs/hyperresearch).
|
|
11
|
+
It searches wide, filters garbage, grounds every claim to a source, and needs
|
|
12
|
+
**zero API keys**: the Claude Code host model supplies all inference, exactly like
|
|
13
|
+
hyperresearch. Optional local CLIs and a `[local]` neural extra are enhancements,
|
|
14
|
+
never requirements.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
Bad Research is a small CLI that registers itself as a Claude Code skill. No API keys. Requires Python 3.11–3.13.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Install the CLI (pipx or uv — either works)
|
|
22
|
+
pipx install bad-research
|
|
23
|
+
uv tool install bad-research
|
|
24
|
+
|
|
25
|
+
# Register the /bad-research skill into ~/.claude
|
|
26
|
+
bad install
|
|
27
|
+
|
|
28
|
+
# Verify
|
|
29
|
+
bad doctor
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`bad install` writes the entry skill to `~/.claude/skills/bad-research/`; the per-step
|
|
33
|
+
skills install lazily on first use. For a project-local install instead of global, run
|
|
34
|
+
`bad install --project` inside the project. `bad doctor` shows what's wired (host model,
|
|
35
|
+
keyless search/browse, the optional external CLIs it can drive, the `[local]` neural stack).
|
|
36
|
+
|
|
37
|
+
## Use it in Claude Code
|
|
38
|
+
|
|
39
|
+
After `bad install`, open Claude Code in any project and either:
|
|
40
|
+
|
|
41
|
+
- **Invoke it directly** — type the slash command with your question:
|
|
42
|
+
```
|
|
43
|
+
/bad-research Is open-source AI more dangerous than closed-source for national security?
|
|
44
|
+
```
|
|
45
|
+
- **Let Claude trigger it** — just ask a research-shaped question (*"write me a cited report
|
|
46
|
+
comparing vector databases"*, *"literature review on GLP-1 drugs"*) and Claude loads the
|
|
47
|
+
skill automatically.
|
|
48
|
+
|
|
49
|
+
It scales to the question: a simple lookup gets a fast cited answer in minutes; a broad or
|
|
50
|
+
contested one runs the full adversarially-reviewed pipeline (~1.5–2.5 h). The final report
|
|
51
|
+
and every fetched source land in a vault under `./research/` that compounds across sessions.
|
|
52
|
+
|
|
53
|
+
> Want the latest unreleased build? Install from source: `pipx install git+https://github.com/LeventySeven/badresearch.git`
|
|
54
|
+
|
|
55
|
+
## What it does
|
|
56
|
+
|
|
57
|
+
A tier-adaptive pipeline turns a question into an audited, fully-cited report, and
|
|
58
|
+
every fetched source lands in a persistent, searchable vault that compounds across
|
|
59
|
+
sessions. Keyless by design:
|
|
60
|
+
|
|
61
|
+
- **Search** — the host `WebSearch` tool + DuckDuckGo + 7 scholarly APIs, fused and reranked by the host model.
|
|
62
|
+
- **Content** — a native fetch-and-clean pipeline (readability → markdown → optional LLM clean), SSRF-guarded.
|
|
63
|
+
- **Browse** — an agentic observe → act → extract loop driven by a local, keyless headless browser.
|
|
64
|
+
- **Retrieve** — SQLite FTS5/BM25 by default (no model required), with an optional local neural lane.
|
|
65
|
+
- **Ground** — every report sentence is checked against its source; uncited claims are blocked.
|
|
66
|
+
|
|
67
|
+
## How it works & where the patterns came from
|
|
68
|
+
|
|
69
|
+
Bad Research takes hyperresearch as its base and enhances each stage with patterns
|
|
70
|
+
drawn from the best deep-research systems — Perplexity, Gemini, Firecrawl, Stagehand,
|
|
71
|
+
AgentQL, and others — reimplemented to run **keyless** on the host model. The full
|
|
72
|
+
write-up, stage by stage with provenance, is in
|
|
73
|
+
[**docs/HOW_IT_WORKS.md**](docs/HOW_IT_WORKS.md).
|
|
74
|
+
|
|
75
|
+
MIT licensed.
|
|
Binary file
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# How Bad Research was built — and where the patterns came from
|
|
2
|
+
|
|
3
|
+
Bad Research is a **fork-and-enhance of [hyperresearch](https://github.com/jordan-gibbs/hyperresearch)**.
|
|
4
|
+
Hyperresearch gave us the foundation: a tier-adaptive, ~16-stage research pipeline
|
|
5
|
+
driven as a Claude Code skill, with a persistent markdown + SQLite vault that
|
|
6
|
+
compounds knowledge across sessions. We kept that whole spine and enhanced each
|
|
7
|
+
stage with the best pattern we could find for it — the approaches that the leading
|
|
8
|
+
deep-research and web-agent systems are known for — and reimplemented every one of
|
|
9
|
+
them to run **keyless**, on the Claude Code host model, with no third-party API key.
|
|
10
|
+
|
|
11
|
+
This document is the honest tour: each stage, the pattern it borrows, and who
|
|
12
|
+
pioneered that pattern. Nothing here needs an API key; where a pattern was
|
|
13
|
+
originally a paid product, we adopted the *idea* and rebuilt it on the host model
|
|
14
|
+
and open tooling.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## The build approach
|
|
19
|
+
|
|
20
|
+
1. **Start from hyperresearch.** Its pipeline, vault, skill packaging, and grounding
|
|
21
|
+
gate are the base. We did not rewrite what already worked.
|
|
22
|
+
2. **Enhance stage by stage.** For each stage — search, content, browse, retrieval,
|
|
23
|
+
reranking, grounding, the control loop — we took the strongest known pattern and
|
|
24
|
+
wired it in behind a clean seam.
|
|
25
|
+
3. **Keyless by design.** Every enhancement is implemented on the host model (via a
|
|
26
|
+
single `LLMProvider` seam) plus open-source libraries and optional local CLIs.
|
|
27
|
+
No vendor key is ever required to install or run; `bad doctor` proves it.
|
|
28
|
+
4. **Built with reviews.** Each stage was implemented and then independently
|
|
29
|
+
reviewed for correctness, security (e.g. SSRF), and faithfulness to the pattern
|
|
30
|
+
before it landed.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The stages and their provenance
|
|
35
|
+
|
|
36
|
+
### Search — wide recall, then a relevance-gated loop
|
|
37
|
+
*Pattern from: Perplexity.* Perplexity's deep search popularised the loop of
|
|
38
|
+
casting a wide net across many sources and then **re-querying until the results are
|
|
39
|
+
actually good enough** rather than answering from the first page. We implement that
|
|
40
|
+
as a "retrieve-until-good" loop: a relevance gate (default 0.70) and a minimum
|
|
41
|
+
pass-fraction (0.30) decide whether to expand and search again, up to a small round
|
|
42
|
+
cap. Recall comes from the host `WebSearch` tool + DuckDuckGo (`ddgs`), with an
|
|
43
|
+
optional self-hosted SearXNG if you have one.
|
|
44
|
+
|
|
45
|
+
### Scholarly verticals — go to the primary sources
|
|
46
|
+
*Pattern from: the open scholarly ecosystem.* For research-grade questions, general
|
|
47
|
+
web search isn't enough, so we route to the primary academic APIs directly —
|
|
48
|
+
**arXiv, OpenAlex, Crossref, Semantic Scholar, Europe PMC, PubMed, and Wikipedia**.
|
|
49
|
+
All are free and keyless; an intent classifier sends a query to the right ones
|
|
50
|
+
(medical → PubMed/Europe PMC, academic → OpenAlex/arXiv, etc.).
|
|
51
|
+
|
|
52
|
+
### Rank fusion — merge many ranked lists fairly
|
|
53
|
+
*Pattern from: Reciprocal Rank Fusion (a standard IR technique, used by systems like
|
|
54
|
+
Exa).* When several sources each return their own ranked list, we combine them with
|
|
55
|
+
**RRF (k = 60)** so no single source dominates and consensus results rise to the top.
|
|
56
|
+
|
|
57
|
+
### Reranking — a cross-encoder pass for precision
|
|
58
|
+
*Pattern from: Cohere Rerank.* Cohere popularised dropping a cross-encoder reranker
|
|
59
|
+
in front of the final results to sharply improve precision. We adopt the pattern but
|
|
60
|
+
keep it **keyless**: the **host model itself** scores each candidate against the
|
|
61
|
+
query with one frozen rubric prompt. It's a frontier cross-encoder you already have —
|
|
62
|
+
≥ rerank-API quality at zero dollars. (An optional `[local]` extra adds an offline
|
|
63
|
+
`ms-marco-MiniLM` cross-encoder for users who want it.)
|
|
64
|
+
|
|
65
|
+
### Content extraction — clean signal out of messy HTML
|
|
66
|
+
*Pattern from: Firecrawl.* Firecrawl is known for turning arbitrary pages into clean,
|
|
67
|
+
model-ready markdown by stripping boilerplate (nav, ads, cookie banners) before
|
|
68
|
+
conversion. We rebuilt that natively: a readability/pruning pass strips chrome,
|
|
69
|
+
HTML→markdown conversion preserves citations and structure, PDFs go through a PDF
|
|
70
|
+
text extractor, and a final optional LLM-clean pass tidies what's left — all with a
|
|
71
|
+
strict anti-prompt-injection preamble so page content is always treated as data.
|
|
72
|
+
Every fetch is **SSRF-guarded** (private-IP/metadata-endpoint denylist, re-validated
|
|
73
|
+
on each redirect).
|
|
74
|
+
|
|
75
|
+
### Agentic browse — observe, act, extract
|
|
76
|
+
*Pattern from: Stagehand / Browserbase.* The modern web-agent pattern is a loop of
|
|
77
|
+
**observe** the page's accessibility tree → **act** (click/type/navigate) → **extract**
|
|
78
|
+
structured data, with the model choosing actions against stable element references.
|
|
79
|
+
We use Stagehand's well-known observe/act/extract prompts as the loop's brain — but
|
|
80
|
+
instead of a paid cloud browser, we drive **[vercel's `agent-browser`](https://github.com/vercel-labs/agent-browser)**,
|
|
81
|
+
a local, keyless headless-Chrome CLI (with `lightpanda` as a fast optional engine).
|
|
82
|
+
The model only ever acts on element references that exist in the live page snapshot,
|
|
83
|
+
so it can't be steered onto a hallucinated element.
|
|
84
|
+
|
|
85
|
+
### Element querying — ask the page in a query language
|
|
86
|
+
*Pattern from: AgentQL.* AgentQL's idea is a small declarative query language for
|
|
87
|
+
locating page elements by role/intent rather than brittle CSS selectors. We ported a
|
|
88
|
+
parser for that query style so the browse layer can resolve elements the same way —
|
|
89
|
+
again, purely local, no service.
|
|
90
|
+
|
|
91
|
+
### Retrieval — hybrid lexical + (optional) semantic
|
|
92
|
+
*Pattern from: Perplexity-style hybrid retrieval.* The robust pattern is to blend
|
|
93
|
+
keyword and semantic recall rather than rely on either alone. Our **default is
|
|
94
|
+
keyless and model-free**: SQLite **FTS5/BM25** lexical recall, three-tier rank
|
|
95
|
+
fusion, and a lexical semantic cache (0.85 overlap) — fast, deterministic, and it
|
|
96
|
+
runs anywhere. If you install the `[local]` extra, a dense vector lane (a local
|
|
97
|
+
`bge` embedder + **LanceDB** ANN, the pattern LanceDB is built for) is used
|
|
98
|
+
automatically on large corpora, fused with BM25 via RRF.
|
|
99
|
+
|
|
100
|
+
### Grounding & no-hallucination — cite or don't say it
|
|
101
|
+
*Pattern from: Gemini's grounding & recitation guarantees.* Gemini is known for
|
|
102
|
+
binding generated claims back to retrieved evidence and guarding against verbatim
|
|
103
|
+
recitation. We enforce both deterministically: every report sentence is checked
|
|
104
|
+
against its cited source (exact-match → local NLI → a host-model gate), **uncited
|
|
105
|
+
factual claims are blocked**, and a recitation gate flags any sentence that copies a
|
|
106
|
+
source too closely (a 12-word verbatim run or >50% overlap) — with a carve-out only
|
|
107
|
+
for genuine, attributed direct quotes.
|
|
108
|
+
|
|
109
|
+
### Reasoning-effort dial — spend compute where it matters
|
|
110
|
+
*Pattern from: OpenAI's reasoning-effort control.* We expose a `--reasoning-effort`
|
|
111
|
+
continuum (minimal → low → medium → high) that maps to route, model tier, fetch
|
|
112
|
+
budget, and a token ceiling, with a defined degrade order so the system spends more
|
|
113
|
+
only when the question warrants it.
|
|
114
|
+
|
|
115
|
+
### Confidence-band hedging — say how sure it is
|
|
116
|
+
*Pattern from: calibrated-uncertainty practice in research assistants.* The final
|
|
117
|
+
report's claims carry a confidence band derived from grounding scores, so
|
|
118
|
+
low-confidence statements are hedged rather than asserted flatly.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## What's keyless vs. optional
|
|
123
|
+
|
|
124
|
+
| Capability | Default (keyless, no setup) | Optional enhancement |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| Inference | Claude Code host model | — |
|
|
127
|
+
| Web search | host `WebSearch` + DuckDuckGo + 7 scholarly APIs | self-hosted SearXNG |
|
|
128
|
+
| Reranking | host-model cross-encoder | `[local]` `ms-marco-MiniLM` |
|
|
129
|
+
| Retrieval | SQLite FTS5/BM25 | `[local]` `bge` + LanceDB dense lane |
|
|
130
|
+
| Content render | native httpx + readability | `crawl4ai` JS render (bundled) |
|
|
131
|
+
| Browse | — | `agent-browser` / `lightpanda` CLIs |
|
|
132
|
+
| Media transcripts | — | `yt-dlp` CLI |
|
|
133
|
+
|
|
134
|
+
Everything in the left column works the moment you `pip install bad-research`. The
|
|
135
|
+
right column is detected at runtime (`bad doctor` shows the status) and degrades
|
|
136
|
+
gracefully when absent — it never blocks a run.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
*Built on the shoulders of [hyperresearch](https://github.com/jordan-gibbs/hyperresearch),
|
|
141
|
+
with patterns from Perplexity, Gemini, Cohere, Firecrawl, Stagehand/Browserbase,
|
|
142
|
+
AgentQL, LanceDB, and the open scholarly web — all reimplemented keyless.*
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pass_rate": 1.0,
|
|
3
|
+
"total": 8,
|
|
4
|
+
"components": {
|
|
5
|
+
"decompose": 1.0,
|
|
6
|
+
"retrieval": 1.0,
|
|
7
|
+
"synthesis": 1.0
|
|
8
|
+
},
|
|
9
|
+
"cases": [
|
|
10
|
+
{
|
|
11
|
+
"id": "01_causal_light",
|
|
12
|
+
"passed": true,
|
|
13
|
+
"verdict": {
|
|
14
|
+
"rails": {
|
|
15
|
+
"factual": "pass",
|
|
16
|
+
"citation": "pass",
|
|
17
|
+
"completeness": "pass",
|
|
18
|
+
"source_quality": "pass",
|
|
19
|
+
"efficiency": "pass"
|
|
20
|
+
},
|
|
21
|
+
"pass_rate": 1.0,
|
|
22
|
+
"passed": true,
|
|
23
|
+
"rationale": "deterministic offline rubric"
|
|
24
|
+
},
|
|
25
|
+
"components": {
|
|
26
|
+
"decompose": true,
|
|
27
|
+
"retrieval": true,
|
|
28
|
+
"synthesis": true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "02_comparison",
|
|
33
|
+
"passed": true,
|
|
34
|
+
"verdict": {
|
|
35
|
+
"rails": {
|
|
36
|
+
"factual": "pass",
|
|
37
|
+
"citation": "pass",
|
|
38
|
+
"completeness": "pass",
|
|
39
|
+
"source_quality": "pass",
|
|
40
|
+
"efficiency": "pass"
|
|
41
|
+
},
|
|
42
|
+
"pass_rate": 1.0,
|
|
43
|
+
"passed": true,
|
|
44
|
+
"rationale": "deterministic offline rubric"
|
|
45
|
+
},
|
|
46
|
+
"components": {
|
|
47
|
+
"decompose": true,
|
|
48
|
+
"retrieval": true,
|
|
49
|
+
"synthesis": true
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"id": "03_multidomain_full",
|
|
54
|
+
"passed": true,
|
|
55
|
+
"verdict": {
|
|
56
|
+
"rails": {
|
|
57
|
+
"factual": "pass",
|
|
58
|
+
"citation": "pass",
|
|
59
|
+
"completeness": "pass",
|
|
60
|
+
"source_quality": "pass",
|
|
61
|
+
"efficiency": "pass"
|
|
62
|
+
},
|
|
63
|
+
"pass_rate": 1.0,
|
|
64
|
+
"passed": true,
|
|
65
|
+
"rationale": "deterministic offline rubric"
|
|
66
|
+
},
|
|
67
|
+
"components": {
|
|
68
|
+
"decompose": true,
|
|
69
|
+
"retrieval": true,
|
|
70
|
+
"synthesis": true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "04_contested_argumentative",
|
|
75
|
+
"passed": true,
|
|
76
|
+
"verdict": {
|
|
77
|
+
"rails": {
|
|
78
|
+
"factual": "pass",
|
|
79
|
+
"citation": "pass",
|
|
80
|
+
"completeness": "pass",
|
|
81
|
+
"source_quality": "pass",
|
|
82
|
+
"efficiency": "pass"
|
|
83
|
+
},
|
|
84
|
+
"pass_rate": 1.0,
|
|
85
|
+
"passed": true,
|
|
86
|
+
"rationale": "deterministic offline rubric"
|
|
87
|
+
},
|
|
88
|
+
"components": {
|
|
89
|
+
"decompose": true,
|
|
90
|
+
"retrieval": true,
|
|
91
|
+
"synthesis": true
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"id": "05_definitional",
|
|
96
|
+
"passed": true,
|
|
97
|
+
"verdict": {
|
|
98
|
+
"rails": {
|
|
99
|
+
"factual": "pass",
|
|
100
|
+
"citation": "pass",
|
|
101
|
+
"completeness": "pass",
|
|
102
|
+
"source_quality": "pass",
|
|
103
|
+
"efficiency": "pass"
|
|
104
|
+
},
|
|
105
|
+
"pass_rate": 1.0,
|
|
106
|
+
"passed": true,
|
|
107
|
+
"rationale": "deterministic offline rubric"
|
|
108
|
+
},
|
|
109
|
+
"components": {
|
|
110
|
+
"decompose": true,
|
|
111
|
+
"retrieval": true,
|
|
112
|
+
"synthesis": true
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"id": "06_recency_temporal",
|
|
117
|
+
"passed": true,
|
|
118
|
+
"verdict": {
|
|
119
|
+
"rails": {
|
|
120
|
+
"factual": "pass",
|
|
121
|
+
"citation": "pass",
|
|
122
|
+
"completeness": "pass",
|
|
123
|
+
"source_quality": "pass",
|
|
124
|
+
"efficiency": "pass"
|
|
125
|
+
},
|
|
126
|
+
"pass_rate": 1.0,
|
|
127
|
+
"passed": true,
|
|
128
|
+
"rationale": "deterministic offline rubric"
|
|
129
|
+
},
|
|
130
|
+
"components": {
|
|
131
|
+
"decompose": true,
|
|
132
|
+
"retrieval": true,
|
|
133
|
+
"synthesis": true
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "07_breadth_list",
|
|
138
|
+
"passed": true,
|
|
139
|
+
"verdict": {
|
|
140
|
+
"rails": {
|
|
141
|
+
"factual": "pass",
|
|
142
|
+
"citation": "pass",
|
|
143
|
+
"completeness": "pass",
|
|
144
|
+
"source_quality": "pass",
|
|
145
|
+
"efficiency": "pass"
|
|
146
|
+
},
|
|
147
|
+
"pass_rate": 1.0,
|
|
148
|
+
"passed": true,
|
|
149
|
+
"rationale": "deterministic offline rubric"
|
|
150
|
+
},
|
|
151
|
+
"components": {
|
|
152
|
+
"decompose": true,
|
|
153
|
+
"retrieval": true,
|
|
154
|
+
"synthesis": true
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"id": "08_numeric_precise",
|
|
159
|
+
"passed": true,
|
|
160
|
+
"verdict": {
|
|
161
|
+
"rails": {
|
|
162
|
+
"factual": "pass",
|
|
163
|
+
"citation": "pass",
|
|
164
|
+
"completeness": "pass",
|
|
165
|
+
"source_quality": "pass",
|
|
166
|
+
"efficiency": "pass"
|
|
167
|
+
},
|
|
168
|
+
"pass_rate": 1.0,
|
|
169
|
+
"passed": true,
|
|
170
|
+
"rationale": "deterministic offline rubric"
|
|
171
|
+
},
|
|
172
|
+
"components": {
|
|
173
|
+
"decompose": true,
|
|
174
|
+
"retrieval": true,
|
|
175
|
+
"synthesis": true
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|