hyperresearch 0.2.0__tar.gz → 0.4.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.
Files changed (101) hide show
  1. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/.gitignore +3 -0
  2. hyperresearch-0.4.0/CHANGELOG.md +124 -0
  3. hyperresearch-0.4.0/PKG-INFO +188 -0
  4. hyperresearch-0.4.0/README.md +148 -0
  5. hyperresearch-0.4.0/assets/banner.png +0 -0
  6. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/pyproject.toml +5 -3
  7. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/__init__.py +1 -1
  8. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/fetch.py +45 -4
  9. hyperresearch-0.4.0/src/hyperresearch/core/agent_docs.py +579 -0
  10. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/fetcher.py +39 -3
  11. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/hooks.py +16 -7
  12. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/note.py +1 -0
  13. hyperresearch-0.4.0/src/hyperresearch/skills/research.md +526 -0
  14. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/web/base.py +63 -0
  15. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/web/crawl4ai_provider.py +196 -46
  16. hyperresearch-0.2.0/CHANGELOG.md +0 -72
  17. hyperresearch-0.2.0/PKG-INFO +0 -172
  18. hyperresearch-0.2.0/PLAN.md +0 -330
  19. hyperresearch-0.2.0/README.md +0 -132
  20. hyperresearch-0.2.0/src/hyperresearch/core/agent_docs.py +0 -331
  21. hyperresearch-0.2.0/src/hyperresearch/skills/research.md +0 -172
  22. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/.github/workflows/ci.yml +0 -0
  23. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/.github/workflows/publish.yml +0 -0
  24. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/CONTRIBUTING.md +0 -0
  25. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/LICENSE +0 -0
  26. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/__main__.py +0 -0
  27. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/__init__.py +0 -0
  28. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/_output.py +0 -0
  29. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/assets.py +0 -0
  30. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/batch.py +0 -0
  31. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/config_cmd.py +0 -0
  32. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/dedup.py +0 -0
  33. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/export.py +0 -0
  34. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/fetch_batch.py +0 -0
  35. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/git_cmd.py +0 -0
  36. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/graph.py +0 -0
  37. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/import_cmd.py +0 -0
  38. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/index.py +0 -0
  39. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/install.py +0 -0
  40. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/link.py +0 -0
  41. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/lint.py +0 -0
  42. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/main.py +0 -0
  43. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/mcp_cmd.py +0 -0
  44. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/note.py +0 -0
  45. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/repair.py +0 -0
  46. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/research.py +0 -0
  47. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/search.py +0 -0
  48. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/serve.py +0 -0
  49. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/setup.py +0 -0
  50. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/sources.py +0 -0
  51. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/tag.py +0 -0
  52. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/template.py +0 -0
  53. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/topic.py +0 -0
  54. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/cli/watch.py +0 -0
  55. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/__init__.py +0 -0
  56. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/config.py +0 -0
  57. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/db.py +0 -0
  58. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/enrich.py +0 -0
  59. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/frontmatter.py +0 -0
  60. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/linker.py +0 -0
  61. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/migrations.py +0 -0
  62. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/patterns.py +0 -0
  63. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/similarity.py +0 -0
  64. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/sync.py +0 -0
  65. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/templates.py +0 -0
  66. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/core/vault.py +0 -0
  67. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/export/__init__.py +0 -0
  68. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/graph/__init__.py +0 -0
  69. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/indexgen/__init__.py +0 -0
  70. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/indexgen/generator.py +0 -0
  71. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/mcp/__init__.py +0 -0
  72. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/mcp/server.py +0 -0
  73. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/models/__init__.py +0 -0
  74. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/models/graph.py +0 -0
  75. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/models/note.py +0 -0
  76. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/models/output.py +0 -0
  77. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/models/search.py +0 -0
  78. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/py.typed +0 -0
  79. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/search/__init__.py +0 -0
  80. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/search/filters.py +0 -0
  81. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/search/fts.py +0 -0
  82. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/serve/__init__.py +0 -0
  83. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/serve/renderer.py +0 -0
  84. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/serve/server.py +0 -0
  85. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/skills/__init__.py +0 -0
  86. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/web/__init__.py +0 -0
  87. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/src/hyperresearch/web/builtin.py +0 -0
  88. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/__init__.py +0 -0
  89. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/conftest.py +0 -0
  90. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_cli/__init__.py +0 -0
  91. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_cli/test_commands.py +0 -0
  92. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_cli/test_note_ops.py +0 -0
  93. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_core/__init__.py +0 -0
  94. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_core/test_frontmatter.py +0 -0
  95. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_core/test_note.py +0 -0
  96. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_core/test_sync.py +0 -0
  97. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_core/test_vault.py +0 -0
  98. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_graph/__init__.py +0 -0
  99. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_graph/test_links.py +0 -0
  100. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_search/__init__.py +0 -0
  101. {hyperresearch-0.2.0 → hyperresearch-0.4.0}/tests/test_search/test_fts.py +0 -0
@@ -11,3 +11,6 @@ build/
11
11
  .mypy_cache/
12
12
  .ruff_cache/
13
13
  *.egg
14
+ .env
15
+ bench/
16
+ codex_bench/
@@ -0,0 +1,124 @@
1
+ # Changelog
2
+
3
+ ## [0.4.0] - 2026-04-13
4
+
5
+ ### New
6
+
7
+ - **Request-type classification (Step 0)** — The research workflow now starts by classifying the user's request into one of 7 types (Canonical Knowledge Retrieval, Market / Landscape Mapping, Engineering / Technical How-To, Interpretive / Humanities Analysis, Comparative Evaluation, Emerging / Cutting-Edge Research, Forecast / Strategy / Recommendation) plus a General fallback. Classification happens before any searching and governs the rest of the workflow.
8
+ - **Type-specific parameter blocks** — Each of the 7 types specifies its own source strategy (count + primary/secondary mix), target length, opening-section shape, H2 heading count, analytical mode, and special rules. A humanities analysis wants 6–10 long thematic sections; a market landscape wants 8–14 vendor-cluster sections with a mandatory comparison matrix; a cutting-edge research request wants primary-heavy preprint reading with a "What we don't know yet" section. One workflow, seven parameterizations.
9
+ - **Primary-heavy vs. secondary-heavy source policy** — New explicit axis: Types 1/4/5/6 are primary-heavy (cite originals, engage deeply, prune irrelevant secondary coverage), Types 2/7 are secondary-heavy (triangulate across many descriptions), Type 3 is balanced. Source count is now a function of request type, not topic complexity.
10
+ - **Conceptual scaffold step (before writing)** — Agent must answer four questions in a scratch file before drafting: the hard question, the naive answer, the structural tension, and a dependency-ordered heading sketch. The final report's opening section must be a framework section, not a definition.
11
+ - **Cross-source comparison step** — Before writing the body, agent finds 3–5 places where sources actually disagree and captures short comparison blocks. Sources earn citations by being compared, not listed. These become the backbone of body sections.
12
+ - **Writing-draft hard constraints** — Target 400–600 words per H2, 12–20 H2s on a 10K-word report, never one-section-per-source, every section ends with an analytical beat, comparison tables not fact tables. Type-specific blocks override these (Type 4 Humanities targets 800–1500 words per section across 6–10 sections).
13
+ - **Frontmatter-first note triage (Step 4.5)** — Six-level protocol for reading notes efficiently. Always start with `note list -j` for summaries, use `note show --meta -j` for frontmatter-only reads, `search --include-body --max-tokens 6000 -j` for token-capped multi-note pulls, and **delegate notes with `word_count > 6000` to a fresh Sonnet subagent** with a pointed extraction prompt (~40× context savings per large note). Rely on the summary field first; read the body only when it earns its place.
14
+ - **Type-aware adversarial audit** — The structure-auditor subagent now checks whether the draft honors its declared type's parameter block: thematic sections for Humanities, mandatory comparison matrix for Comparative, "What we don't know yet" for Emerging, a position on winners for Market. Flags every type violation.
15
+
16
+ ### Changed
17
+
18
+ - **`fit_markdown` via PruningContentFilter** — crawl4ai provider now uses `DefaultMarkdownGenerator` with `PruningContentFilter` so fetched notes contain just the main content, stripping navigation, footers, and sidebar chrome. Both `AsyncWebCrawler.arun()` and the Playwright visible-browser path use the same generator for consistent output. Applied to single fetch, batch fetch, and visible browser paths.
19
+ - **Skip numeric wiki-links in note parser** — `[[100]]`-style citation markers in bibliographies and academic papers are no longer extracted as note references. Avoids thousands of spurious broken-link warnings on papers that use numbered references.
20
+ - **"Over-collect, then prune" reframed as "over-collect, then engage deeply"** — A report built from 30 sources that disagree and force you to take positions is worth more than a report built from 80 sources that each contribute one bullet of description. Collection is a means to an argument, not the goal.
21
+ - **Scaffold and comparison artifacts are ephemeral, NOT hyperresearch notes** — Both the conceptual scaffold and the cross-source comparison blocks live in `/tmp/scaffold.md` or working memory, explicitly not as notes. Protects the research base from pre-writing scratch work.
22
+
23
+ ## [0.3.0] - 2026-04-11
24
+
25
+ ### New
26
+
27
+ - **Native PDF extraction** — PDFs detected by URL pattern, downloaded directly with httpx, text extracted with pymupdf. No browser needed. arXiv `/abs/` links auto-convert to `/pdf/`.
28
+ - **Raw file storage** — PDF bytes saved to `research/raw/<note-id>.pdf`, linked from note frontmatter via `raw_file:` field. Agent can read the raw PDF directly.
29
+ - **Junk page detection** — `WebResult.looks_like_junk()` catches Cloudflare captchas, error pages, cookie walls, binary garbage, reCAPTCHA, and empty content before saving. Returns `JUNK_CONTENT` error instead of creating useless notes.
30
+ - **Gap analysis step** — after drafting the report, agent re-reads the original query word by word, identifies gaps, and does another full round of research to fill them.
31
+ - **Adversarial audit** — two subagents (comprehensiveness auditor + logic/structure auditor) review the draft in parallel. Runs up to 2 loops. Agent uses wait time productively to improve summaries and tags.
32
+ - **Source checkpoint** — agent must review collected sources before writing any draft. Checks coverage breadth, missing angles, uncited references. Expects 50-100+ sources on complex topics.
33
+ - **Scholarly API guidance** — CLAUDE.md and `/research` skill now encourage use of arXiv, Semantic Scholar, CrossRef, and PubMed APIs for academic research.
34
+ - **Date injection** — today's date injected programmatically into CLAUDE.md at install time.
35
+ - **Multi-round research emphasis** — agent docs stress multiple rounds of search → fetch → follow links, spawning 10-20 fetcher agents per round.
36
+
37
+ ### Changed
38
+
39
+ - **Agent-driven curation replaces auto-enrich** — removed the keyword-matching `enrich_note_file()` from the fetch pipeline. Fetcher subagents now read content, write real summaries, add meaningful tags, and quality-check each source (deprecating junk/off-topic notes).
40
+ - **Fetcher subagent quality gate** — subagent now checks relevance, content quality, and duplicates. Deprecates bad notes instead of leaving them as drafts.
41
+ - **`_resolve_executable()` prioritizes venv** — checks venv `Scripts/` dir before PATH, preventing system-wide installs from overriding the project's venv.
42
+ - **PDF binary detection improved** — checks for `endstream`, `endobj`, `/FlateDecode`, `%PDF-` markers and non-printable character ratios. Catches binary garbage in both single-fetch and batch-fetch paths.
43
+ - **Junk detection thresholds raised** — empty content threshold: 100→300 chars, cookie page threshold: 500→1500 chars. Added `recaptcha`, `checking your browser`, `verify you are human` to bot detection signals.
44
+ - **SSL verification disabled for PDF downloads** — academic sites often have self-signed certs. `httpx.get(verify=False)` for PDF fetches only.
45
+ - **PDF fetch logging** — `_fetch_pdf` failures now logged via `logging.getLogger("hyperresearch.pdf")` instead of silently returning None.
46
+ - **Fetcher subagent continues on failure** — no longer stops on first fetch error, tries all URLs and reports failures individually.
47
+
48
+ ### Added dependencies
49
+
50
+ - `pymupdf>=1.24` — PDF text extraction
51
+ - `httpx>=0.27` — direct HTTP downloads for PDFs (bypasses browser)
52
+
53
+ ## [0.2.0] - 2026-04-10
54
+
55
+ ### New
56
+
57
+ - **`/research` skill** — Scripted deep research workflow as a Claude Code slash command. Clarifies ambiguous requests, searches broadly, fetches aggressively, follows rabbit holes, auto-curates, synthesizes, and presents findings with hub notes
58
+ - **`hyperresearch setup`** — Interactive TUI onboarding: web provider, browser profile selection/creation, agent hooks. Auto-launches on first `install`
59
+ - **`hyperresearch fetch-batch`** — Concurrent multi-URL fetch with batched sync (O(1) syncs instead of O(n))
60
+ - **`hyperresearch link --auto`** — Holistic auto-linking: scans notes for mentions of other notes' titles and appends wiki-links
61
+ - **`hyperresearch assets list/path`** — Browse downloaded screenshots and images
62
+ - **`--save-assets` flag** — Opt-in screenshot + content image download on fetch
63
+ - **`--visible` flag** — Non-headless browser for stubborn auth sites (auto-enabled for LinkedIn, Twitter, Facebook, Instagram, TikTok)
64
+ - **`--max-tokens` on search** — Token budget truncation for context-aware agents
65
+ - **Auto-curation at fetch time** — Notes arrive with auto-generated tags and summaries
66
+ - **MCP write tools** — `fetch_url`, `create_note`, `update_note` (MCP server is now read-write)
67
+ - **MinHash+LSH dedup** — O(n) approximate dedup for large vaults (200+ notes), falls back to brute-force for small vaults
68
+ - **Hub notes auto-surfaced** after research sessions
69
+ - **Synthesis notes** saved as feedback loop (agent Q&A becomes searchable)
70
+ - **`hyperresearch-fetcher` subagent** — Haiku-powered URL fetcher installed to `.claude/agents/`
71
+ - **Login wall detection** — `AUTH_REQUIRED` error instead of saving login page junk
72
+ - **Smart SPA wait** — Polls DOM stability (2s initial + 10s ceiling) instead of fixed delays
73
+
74
+ ### Changed
75
+
76
+ - **crawl4ai is the sole browser provider** — Removed firecrawl, tavily, trafilatura
77
+ - **crawl4ai v0.8.x API** — AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, arun/arun_many
78
+ - **Authenticated crawling** via crawl4ai browser profiles (`crwl profiles` or setup TUI)
79
+ - **CLI path baked into CLAUDE.md** — Works without venv activation (forward slashes for Windows bash)
80
+ - **Deep research philosophy** — Agent docs say "over-collect, then prune" and "go down rabbit holes"
81
+ - **Windows encoding fix** — `stream.reconfigure(encoding="utf-8")` at startup, no more charmap crashes
82
+ - **Note slugs capped at 80 chars** — Avoids Windows MAX_PATH issues
83
+ - **Anti-bot stealth always on** when crawl4ai is used (no setup question)
84
+ - **Config commands** now support `web.provider`, `web.profile`, `web.magic`
85
+
86
+ ### Removed
87
+
88
+ - Dead fields: `confidence`, `superseded_by`, `llm_compiled`, `llm_model`, `compile_source`
89
+ - Tag plural normalization (use explicit `tag_aliases` instead)
90
+ - `deprecated-no-successor` and `low-confidence` lint rules
91
+ - Firecrawl, Tavily, Trafilatura web providers
92
+
93
+ ## [0.1.0] - 2026-04-09
94
+
95
+ Initial release. Forked from [llm-kasten](https://github.com/jordan-gibbs/llm-kasten) and repositioned for agent-driven research workflows.
96
+
97
+ ### New
98
+
99
+ - **`hyperresearch install`** — One-step setup: init vault + inject agent docs + install PreToolUse hooks for Claude Code, Codex, Cursor, Gemini CLI
100
+ - **`hyperresearch fetch <url>`** — Fetch a URL, extract content, save as a research note with source tracking
101
+ - **`hyperresearch research <topic>`** — Deep research: web search, fetch results, follow links, save as linked notes, generate synthesis MOC
102
+ - **`hyperresearch sources list/check`** — List and query fetched web sources
103
+ - **Web provider plugin system** — Pluggable backends: builtin (stdlib), crawl4ai (local headless browser)
104
+ - **Agent hook system** — PreToolUse hooks that remind agents to check the research base before web searches
105
+ - **Sources table** — URL deduplication, domain tracking, fetch metadata
106
+ - **Extended frontmatter** — `source_domain`, `fetched_at`, `fetch_provider` fields
107
+ - **MCP server** with 10 tools including `check_source` and `list_sources`
108
+
109
+ ### From kasten (the backbone)
110
+
111
+ - SQLite FTS5 full-text search with BM25 ranking
112
+ - Markdown notes with YAML frontmatter as source of truth
113
+ - `[[wiki-link]]` tracking with backlinks
114
+ - `--json` / `-j` structured output on every command
115
+ - Note lifecycle: draft → review → evergreen → stale → deprecated → archive
116
+ - Auto-sync (mtime + SHA-256 change detection)
117
+ - Agent doc injection (CLAUDE.md, AGENTS.md, GEMINI.md, copilot-instructions.md)
118
+ - Web viewer with force-directed knowledge graph
119
+ - 70 tests
120
+
121
+ [0.4.0]: https://github.com/jordan-gibbs/hyperresearch/releases/tag/v0.4.0
122
+ [0.3.0]: https://github.com/jordan-gibbs/hyperresearch/releases/tag/v0.3.0
123
+ [0.2.0]: https://github.com/jordan-gibbs/hyperresearch/releases/tag/v0.2.0
124
+ [0.1.0]: https://github.com/jordan-gibbs/hyperresearch/releases/tag/v0.1.0
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperresearch
3
+ Version: 0.4.0
4
+ Summary: Agent-driven research knowledge base. Browse, collect, and synthesize web sources into a searchable wiki.
5
+ Project-URL: Homepage, https://github.com/jordan-gibbs/hyperresearch
6
+ Project-URL: Repository, https://github.com/jordan-gibbs/hyperresearch
7
+ Project-URL: Issues, https://github.com/jordan-gibbs/hyperresearch/issues
8
+ Author-email: Jordan Gibbs <jordan@jordangibbs.xyz>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,cli,knowledge-base,llm,markdown,research,wiki,zettelkasten
12
+ Classifier: Development Status :: 3 - Alpha
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
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: crawl4ai>=0.4
22
+ Requires-Dist: httpx>=0.27
23
+ Requires-Dist: jinja2>=3.1
24
+ Requires-Dist: platformdirs>=4.0
25
+ Requires-Dist: pydantic>=2.0
26
+ Requires-Dist: pymupdf>=1.24
27
+ Requires-Dist: pyyaml>=6.0
28
+ Requires-Dist: rich>=13.0
29
+ Requires-Dist: typer>=0.9.0
30
+ Provides-Extra: all
31
+ Requires-Dist: mcp>=1.6; extra == 'all'
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.8; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
35
+ Requires-Dist: pytest>=7.4; extra == 'dev'
36
+ Requires-Dist: ruff>=0.3; extra == 'dev'
37
+ Provides-Extra: mcp
38
+ Requires-Dist: mcp>=1.6; extra == 'mcp'
39
+ Description-Content-Type: text/markdown
40
+
41
+ <p align="center">
42
+ <img src="assets/banner.png" alt="HYPERRESEARCH" width="700">
43
+ </p>
44
+
45
+ <h3 align="center">Ultra deep, persistent web research for AI coding agents</h3>
46
+
47
+ <p align="center">
48
+ <a href="https://pypi.org/project/hyperresearch/"><img src="https://img.shields.io/pypi/v/hyperresearch" alt="PyPI version"></a>
49
+ <a href="https://pypi.org/project/hyperresearch/"><img src="https://img.shields.io/pypi/pyversions/hyperresearch" alt="Python 3.11+"></a>
50
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/jordan-gibbs/hyperresearch" alt="License: MIT"></a>
51
+ <a href="https://github.com/jordan-gibbs/hyperresearch"><img src="https://img.shields.io/github/stars/jordan-gibbs/hyperresearch?style=social" alt="GitHub stars"></a>
52
+ </p>
53
+
54
+ ---
55
+
56
+ Your AI agent searches the web, finds great sources, synthesizes an answer — then the session ends and everything is gone. Next time, it starts from zero.
57
+
58
+ **Hyperresearch makes research persist.** Every source your agent finds is fetched with a real headless browser, saved as searchable markdown, and indexed into a knowledge base that compounds across sessions. Hyperresearch can follow maps of links to digest paths of information that current agent web searching isn't capable of.
59
+
60
+ ```bash
61
+ pip install hyperresearch
62
+ hyperresearch install
63
+ ```
64
+
65
+ ## What people use it for
66
+
67
+ - **In-depth topic research** — "Research the latest advances in state space models" → agent fetches 20+ papers, docs, and blog posts, follows citations to primary sources, builds a linked knowledge graph
68
+ - **News tracking over time** — run research sessions weekly on a topic, each session builds on what's already collected, nothing gets re-fetched
69
+ - **State-of-the-art surveys** — "What's the current SOTA for speech recognition?" → agent goes down rabbit holes, collects benchmarks, papers, and implementations
70
+ - **Competitive analysis** — scrape company pages, LinkedIn profiles, product docs, news articles into a persistent, searchable corpus
71
+ - **Due diligence** — aggregate everything about a person, company, or technology from across the web with authenticated crawling (LinkedIn, Twitter, paywalled sites)
72
+
73
+ ## How it works
74
+
75
+ 1. **You ask your agent to research something**
76
+ 2. **Agent searches the web** — multiple queries, different angles
77
+ 3. **Fetches every source** with a real headless browser (crawl4ai) — JS rendering, bot detection bypass, login-gated content
78
+ 4. **Saves each page** as a searchable markdown note with tags, summary, and source tracking
79
+ 5. **Follows links** to primary sources — the paper, not the blog post about the paper
80
+ 6. **Auto-links related notes** with `[[wiki-links]]` across the knowledge graph
81
+ 7. **Synthesizes findings** into a summary note linking all sources
82
+ 8. **Next session** — agent checks the KB before searching the web. Knowledge compounds.
83
+
84
+ ```
85
+ your-repo/
86
+ .hyperresearch/ # Config + SQLite FTS5 index (rebuildable)
87
+ research/
88
+ notes/ # Markdown notes — the source of truth
89
+ index/ # Auto-generated wiki pages
90
+ CLAUDE.md # Agent docs (auto-injected)
91
+ ```
92
+
93
+ ## Works with every major agent
94
+
95
+ `hyperresearch install` hooks into your agent in one step:
96
+
97
+ | Platform | Hook | Trigger |
98
+ |----------|------|---------|
99
+ | **Claude Code** | `.claude/settings.json` + `/research` skill | Before WebSearch, WebFetch |
100
+ | **Codex** | `.codex/hooks.json` | Before Bash |
101
+ | **Cursor** | `.cursor/rules/hyperresearch.mdc` | Always-apply rule |
102
+ | **Gemini CLI** | `.gemini/settings.json` | Before tool calls |
103
+
104
+ ```bash
105
+ hyperresearch install --platform all # Hook every platform at once
106
+ ```
107
+
108
+ ## Key features
109
+
110
+ - **Real headless browser** — crawl4ai runs local Chromium. Handles JavaScript, bypasses bot detection, renders SPAs. Not a simple HTTP fetch.
111
+ - **Native PDF extraction** — fetches PDFs directly, extracts full text with pymupdf, saves raw files to `research/raw/`. Academic papers, whitepapers, reports — all first-class citizens.
112
+ - **Authenticated crawling** — log into LinkedIn, Twitter, paywalled news. Your sessions persist across fetches.
113
+ - **Agent-driven curation** — fetcher subagents read each source, write real summaries, add meaningful tags, and flag junk. No keyword-matching shortcuts.
114
+ - **Junk detection** — Cloudflare captchas, error pages, cookie walls, binary garbage, login redirects all caught and rejected before saving.
115
+ - **Multi-round deep research** — the agent does multiple rounds of search → fetch → follow links, with a source checkpoint that forces breadth before synthesis.
116
+ - **Gap analysis + adversarial audit** — after drafting, the agent re-reads the original query to find gaps, then spawns two auditor subagents (comprehensiveness + logic) to tear the draft apart. Runs twice.
117
+ - **Cheap parallel fetching** — ships a Haiku-powered subagent that fetches, summarizes, and quality-checks URLs in parallel for pennies. Spawn 10-20 per round.
118
+ - **Scholarly API guidance** — agent docs encourage use of arXiv, Semantic Scholar, CrossRef, and PubMed APIs for academic topics.
119
+ - **`/research` skill** — scripted deep research workflow. Clarifies ambiguous requests, searches broadly, fetches aggressively, follows rabbit holes, audits, synthesizes.
120
+ - **Smart SPA wait** — polls DOM stability instead of fixed delays. Fast pages finish instantly, SPAs get up to 10 seconds.
121
+ - **FTS5 search** — instant full-text search across thousands of notes with BM25 ranking
122
+ - **Knowledge graph** — `[[wiki-links]]`, backlinks, hub detection, auto-linking
123
+ - **MCP server** — 13 tools (read + write) for Claude Desktop, Cursor, or any MCP client
124
+ - **Note lifecycle** — draft → review → evergreen → stale → deprecated → archive
125
+
126
+ ## Commands
127
+
128
+ ```bash
129
+ # Research
130
+ hyperresearch fetch <url> --tag t -j # Fetch a URL into the KB
131
+ hyperresearch fetch-batch <urls...> -j # Fetch many URLs at once
132
+ hyperresearch research "topic" --max 5 -j # Full pipeline: search → fetch → link → synthesize
133
+
134
+ # Search
135
+ hyperresearch search "query" -j # Full-text search
136
+ hyperresearch search "query" --max-tokens 8000 # Stay within context budget
137
+ hyperresearch note show <id> -j # Read a note
138
+
139
+ # Knowledge graph
140
+ hyperresearch link --auto -j # Auto-link related notes
141
+ hyperresearch graph hubs -j # Most-connected notes
142
+ hyperresearch graph backlinks <id> -j # What links to this note
143
+
144
+ # Manage
145
+ hyperresearch sources list -j # Every URL ever fetched
146
+ hyperresearch lint -j # Health check
147
+ hyperresearch repair -j # Fix links, rebuild indexes
148
+ ```
149
+
150
+ Every command returns `{"ok": true, "data": {...}}` with `-j`.
151
+
152
+ ## Authenticated crawling
153
+
154
+ Fetch from LinkedIn, Twitter, paywalled sites — anything you can log into:
155
+
156
+ ```bash
157
+ hyperresearch setup # Browser opens. Log into your sites. Done.
158
+ ```
159
+
160
+ ```toml
161
+ # .hyperresearch/config.toml
162
+ [web]
163
+ provider = "crawl4ai"
164
+ profile = "research"
165
+ ```
166
+
167
+ LinkedIn, Twitter, Facebook, Instagram, and TikTok automatically use a visible browser to avoid session kills.
168
+
169
+ ## Philosophy
170
+
171
+ - **No LLM calls.** Hyperresearch stores, indexes, and searches. Your agent is the LLM.
172
+ - **Markdown is truth.** Notes are plain files. SQLite is a rebuildable cache.
173
+ - **Over-collect, then prune.** Fetch aggressively. Deprecate what you don't need.
174
+ - **Check before you fetch.** Hooks kill redundant searches across sessions.
175
+ - **Raw content is king.** Save the original with formatting, not a rewritten summary.
176
+
177
+ ## Requirements
178
+
179
+ - Python 3.11+
180
+ - Windows, macOS, Linux
181
+
182
+ ## License
183
+
184
+ [MIT](LICENSE)
185
+
186
+ ## Star History
187
+
188
+ [![Star History Chart](https://api.star-history.com/svg?repos=jordan-gibbs/hyperresearch&type=Date)](https://star-history.com/#jordan-gibbs/hyperresearch&Date)
@@ -0,0 +1,148 @@
1
+ <p align="center">
2
+ <img src="assets/banner.png" alt="HYPERRESEARCH" width="700">
3
+ </p>
4
+
5
+ <h3 align="center">Ultra deep, persistent web research for AI coding agents</h3>
6
+
7
+ <p align="center">
8
+ <a href="https://pypi.org/project/hyperresearch/"><img src="https://img.shields.io/pypi/v/hyperresearch" alt="PyPI version"></a>
9
+ <a href="https://pypi.org/project/hyperresearch/"><img src="https://img.shields.io/pypi/pyversions/hyperresearch" alt="Python 3.11+"></a>
10
+ <a href="LICENSE"><img src="https://img.shields.io/github/license/jordan-gibbs/hyperresearch" alt="License: MIT"></a>
11
+ <a href="https://github.com/jordan-gibbs/hyperresearch"><img src="https://img.shields.io/github/stars/jordan-gibbs/hyperresearch?style=social" alt="GitHub stars"></a>
12
+ </p>
13
+
14
+ ---
15
+
16
+ Your AI agent searches the web, finds great sources, synthesizes an answer — then the session ends and everything is gone. Next time, it starts from zero.
17
+
18
+ **Hyperresearch makes research persist.** Every source your agent finds is fetched with a real headless browser, saved as searchable markdown, and indexed into a knowledge base that compounds across sessions. Hyperresearch can follow maps of links to digest paths of information that current agent web searching isn't capable of.
19
+
20
+ ```bash
21
+ pip install hyperresearch
22
+ hyperresearch install
23
+ ```
24
+
25
+ ## What people use it for
26
+
27
+ - **In-depth topic research** — "Research the latest advances in state space models" → agent fetches 20+ papers, docs, and blog posts, follows citations to primary sources, builds a linked knowledge graph
28
+ - **News tracking over time** — run research sessions weekly on a topic, each session builds on what's already collected, nothing gets re-fetched
29
+ - **State-of-the-art surveys** — "What's the current SOTA for speech recognition?" → agent goes down rabbit holes, collects benchmarks, papers, and implementations
30
+ - **Competitive analysis** — scrape company pages, LinkedIn profiles, product docs, news articles into a persistent, searchable corpus
31
+ - **Due diligence** — aggregate everything about a person, company, or technology from across the web with authenticated crawling (LinkedIn, Twitter, paywalled sites)
32
+
33
+ ## How it works
34
+
35
+ 1. **You ask your agent to research something**
36
+ 2. **Agent searches the web** — multiple queries, different angles
37
+ 3. **Fetches every source** with a real headless browser (crawl4ai) — JS rendering, bot detection bypass, login-gated content
38
+ 4. **Saves each page** as a searchable markdown note with tags, summary, and source tracking
39
+ 5. **Follows links** to primary sources — the paper, not the blog post about the paper
40
+ 6. **Auto-links related notes** with `[[wiki-links]]` across the knowledge graph
41
+ 7. **Synthesizes findings** into a summary note linking all sources
42
+ 8. **Next session** — agent checks the KB before searching the web. Knowledge compounds.
43
+
44
+ ```
45
+ your-repo/
46
+ .hyperresearch/ # Config + SQLite FTS5 index (rebuildable)
47
+ research/
48
+ notes/ # Markdown notes — the source of truth
49
+ index/ # Auto-generated wiki pages
50
+ CLAUDE.md # Agent docs (auto-injected)
51
+ ```
52
+
53
+ ## Works with every major agent
54
+
55
+ `hyperresearch install` hooks into your agent in one step:
56
+
57
+ | Platform | Hook | Trigger |
58
+ |----------|------|---------|
59
+ | **Claude Code** | `.claude/settings.json` + `/research` skill | Before WebSearch, WebFetch |
60
+ | **Codex** | `.codex/hooks.json` | Before Bash |
61
+ | **Cursor** | `.cursor/rules/hyperresearch.mdc` | Always-apply rule |
62
+ | **Gemini CLI** | `.gemini/settings.json` | Before tool calls |
63
+
64
+ ```bash
65
+ hyperresearch install --platform all # Hook every platform at once
66
+ ```
67
+
68
+ ## Key features
69
+
70
+ - **Real headless browser** — crawl4ai runs local Chromium. Handles JavaScript, bypasses bot detection, renders SPAs. Not a simple HTTP fetch.
71
+ - **Native PDF extraction** — fetches PDFs directly, extracts full text with pymupdf, saves raw files to `research/raw/`. Academic papers, whitepapers, reports — all first-class citizens.
72
+ - **Authenticated crawling** — log into LinkedIn, Twitter, paywalled news. Your sessions persist across fetches.
73
+ - **Agent-driven curation** — fetcher subagents read each source, write real summaries, add meaningful tags, and flag junk. No keyword-matching shortcuts.
74
+ - **Junk detection** — Cloudflare captchas, error pages, cookie walls, binary garbage, login redirects all caught and rejected before saving.
75
+ - **Multi-round deep research** — the agent does multiple rounds of search → fetch → follow links, with a source checkpoint that forces breadth before synthesis.
76
+ - **Gap analysis + adversarial audit** — after drafting, the agent re-reads the original query to find gaps, then spawns two auditor subagents (comprehensiveness + logic) to tear the draft apart. Runs twice.
77
+ - **Cheap parallel fetching** — ships a Haiku-powered subagent that fetches, summarizes, and quality-checks URLs in parallel for pennies. Spawn 10-20 per round.
78
+ - **Scholarly API guidance** — agent docs encourage use of arXiv, Semantic Scholar, CrossRef, and PubMed APIs for academic topics.
79
+ - **`/research` skill** — scripted deep research workflow. Clarifies ambiguous requests, searches broadly, fetches aggressively, follows rabbit holes, audits, synthesizes.
80
+ - **Smart SPA wait** — polls DOM stability instead of fixed delays. Fast pages finish instantly, SPAs get up to 10 seconds.
81
+ - **FTS5 search** — instant full-text search across thousands of notes with BM25 ranking
82
+ - **Knowledge graph** — `[[wiki-links]]`, backlinks, hub detection, auto-linking
83
+ - **MCP server** — 13 tools (read + write) for Claude Desktop, Cursor, or any MCP client
84
+ - **Note lifecycle** — draft → review → evergreen → stale → deprecated → archive
85
+
86
+ ## Commands
87
+
88
+ ```bash
89
+ # Research
90
+ hyperresearch fetch <url> --tag t -j # Fetch a URL into the KB
91
+ hyperresearch fetch-batch <urls...> -j # Fetch many URLs at once
92
+ hyperresearch research "topic" --max 5 -j # Full pipeline: search → fetch → link → synthesize
93
+
94
+ # Search
95
+ hyperresearch search "query" -j # Full-text search
96
+ hyperresearch search "query" --max-tokens 8000 # Stay within context budget
97
+ hyperresearch note show <id> -j # Read a note
98
+
99
+ # Knowledge graph
100
+ hyperresearch link --auto -j # Auto-link related notes
101
+ hyperresearch graph hubs -j # Most-connected notes
102
+ hyperresearch graph backlinks <id> -j # What links to this note
103
+
104
+ # Manage
105
+ hyperresearch sources list -j # Every URL ever fetched
106
+ hyperresearch lint -j # Health check
107
+ hyperresearch repair -j # Fix links, rebuild indexes
108
+ ```
109
+
110
+ Every command returns `{"ok": true, "data": {...}}` with `-j`.
111
+
112
+ ## Authenticated crawling
113
+
114
+ Fetch from LinkedIn, Twitter, paywalled sites — anything you can log into:
115
+
116
+ ```bash
117
+ hyperresearch setup # Browser opens. Log into your sites. Done.
118
+ ```
119
+
120
+ ```toml
121
+ # .hyperresearch/config.toml
122
+ [web]
123
+ provider = "crawl4ai"
124
+ profile = "research"
125
+ ```
126
+
127
+ LinkedIn, Twitter, Facebook, Instagram, and TikTok automatically use a visible browser to avoid session kills.
128
+
129
+ ## Philosophy
130
+
131
+ - **No LLM calls.** Hyperresearch stores, indexes, and searches. Your agent is the LLM.
132
+ - **Markdown is truth.** Notes are plain files. SQLite is a rebuildable cache.
133
+ - **Over-collect, then prune.** Fetch aggressively. Deprecate what you don't need.
134
+ - **Check before you fetch.** Hooks kill redundant searches across sessions.
135
+ - **Raw content is king.** Save the original with formatting, not a rewritten summary.
136
+
137
+ ## Requirements
138
+
139
+ - Python 3.11+
140
+ - Windows, macOS, Linux
141
+
142
+ ## License
143
+
144
+ [MIT](LICENSE)
145
+
146
+ ## Star History
147
+
148
+ [![Star History Chart](https://api.star-history.com/svg?repos=jordan-gibbs/hyperresearch&type=Date)](https://star-history.com/#jordan-gibbs/hyperresearch&Date)
Binary file
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hyperresearch"
7
- version = "0.2.0"
7
+ version = "0.4.0"
8
8
  description = "Agent-driven research knowledge base. Browse, collect, and synthesize web sources into a searchable wiki."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -28,12 +28,14 @@ dependencies = [
28
28
  "pydantic>=2.0",
29
29
  "jinja2>=3.1",
30
30
  "platformdirs>=4.0",
31
+ "Crawl4AI>=0.4",
32
+ "pymupdf>=1.24",
33
+ "httpx>=0.27",
31
34
  ]
32
35
 
33
36
  [project.optional-dependencies]
34
- crawl4ai = ["Crawl4AI>=0.4"]
35
37
  mcp = ["mcp>=1.6"]
36
- all = ["hyperresearch[crawl4ai,mcp]"]
38
+ all = ["hyperresearch[mcp]"]
37
39
  dev = [
38
40
  "pytest>=7.4",
39
41
  "pytest-cov>=4.1",
@@ -1,3 +1,3 @@
1
1
  """Hyperresearch — agent-driven research knowledge base."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.4.0"
@@ -116,6 +116,16 @@ def fetch(
116
116
  console.print(f"[red]Auth required:[/] {msg}")
117
117
  raise typer.Exit(1)
118
118
 
119
+ # Detect junk pages — captcha, error pages, binary garbage, empty content
120
+ junk_reason = result.looks_like_junk()
121
+ if junk_reason:
122
+ msg = f"Skipped junk content from {url}: {junk_reason}"
123
+ if json_output:
124
+ output(error(msg, "JUNK_CONTENT"), json_mode=True)
125
+ else:
126
+ console.print(f"[yellow]Skipped:[/] {msg}")
127
+ raise typer.Exit(1)
128
+
119
129
  # Write note
120
130
  note_title = title or result.title or urlparse(url).path.split("/")[-1] or "Untitled"
121
131
  domain = result.domain
@@ -140,10 +150,40 @@ def fetch(
140
150
  extra_frontmatter=extra_meta,
141
151
  )
142
152
 
143
- # Auto-enrich: add suggested tags and summary before sync
144
- from hyperresearch.core.enrich import enrich_note_file
145
-
146
- enrich_note_file(note_path, conn, tags)
153
+ # Save raw file (PDF, etc.) if present
154
+ raw_file_path = None
155
+ if result.raw_bytes and result.raw_content_type:
156
+ ext_map = {
157
+ "application/pdf": ".pdf",
158
+ "image/png": ".png",
159
+ "image/jpeg": ".jpg",
160
+ "image/gif": ".gif",
161
+ "image/webp": ".webp",
162
+ }
163
+ ext = ext_map.get(result.raw_content_type, "")
164
+ if ext:
165
+ raw_dir = vault.root / "research" / "raw"
166
+ raw_dir.mkdir(parents=True, exist_ok=True)
167
+ raw_filename = note_path.stem + ext
168
+ raw_file = raw_dir / raw_filename
169
+ raw_file.write_bytes(result.raw_bytes)
170
+ raw_file_path = f"raw/{raw_filename}"
171
+
172
+ # Note: tagging and summarization is the agent's job, not an automatic process.
173
+ # The agent reads the fetched content and writes meaningful summaries and tags.
174
+
175
+ # Add raw_file reference to frontmatter AFTER enrich (enrich rewrites frontmatter)
176
+ if raw_file_path:
177
+ note_text = note_path.read_text(encoding="utf-8")
178
+ if note_text.startswith("---") and "raw_file:" not in note_text:
179
+ end_idx = note_text.find("---", 3)
180
+ if end_idx != -1:
181
+ note_text = (
182
+ note_text[:end_idx]
183
+ + f"raw_file: {raw_file_path}\n"
184
+ + note_text[end_idx:]
185
+ )
186
+ note_path.write_text(note_text, encoding="utf-8")
147
187
 
148
188
  # Sync first so the note exists in the notes table (needed for FK on sources/assets)
149
189
  note_id = note_path.stem
@@ -175,6 +215,7 @@ def fetch(
175
215
  "path": str(note_path.relative_to(vault.root)),
176
216
  "word_count": len(result.content.split()),
177
217
  "assets": saved_assets,
218
+ "raw_file": raw_file_path,
178
219
  }
179
220
 
180
221
  if json_output: