docpull 4.4.0__tar.gz → 5.0.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 (170) hide show
  1. docpull-5.0.0/PKG-INFO +566 -0
  2. docpull-5.0.0/README.md +454 -0
  3. {docpull-4.4.0 → docpull-5.0.0}/pyproject.toml +27 -3
  4. docpull-5.0.0/src/docpull/__init__.py +182 -0
  5. docpull-5.0.0/src/docpull/accounting.py +340 -0
  6. docpull-5.0.0/src/docpull/auth_cli.py +166 -0
  7. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/benchmark.py +796 -259
  8. docpull-5.0.0/src/docpull/cli.py +1449 -0
  9. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/extractor.py +61 -5
  10. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/protocols.py +1 -1
  11. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/core/fetcher.py +39 -13
  12. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/__init__.py +22 -0
  13. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/_fetch.py +12 -4
  14. docpull-5.0.0/src/docpull/discovery/contracts.py +1496 -0
  15. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/crawler.py +31 -4
  16. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/link_extractors/enhanced.py +14 -8
  17. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/link_extractors/static.py +10 -4
  18. docpull-5.0.0/src/docpull/discovery_cli.py +449 -0
  19. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/doctor.py +20 -2
  20. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/evidence_pack.py +2 -1
  21. docpull-5.0.0/src/docpull/exports.py +674 -0
  22. docpull-5.0.0/src/docpull/graph.py +1069 -0
  23. docpull-5.0.0/src/docpull/local_workflows.py +734 -0
  24. docpull-5.0.0/src/docpull/mcp/server.py +2475 -0
  25. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/__init__.py +8 -0
  26. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/config.py +290 -5
  27. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/events.py +1 -0
  28. docpull-5.0.0/src/docpull/monitor.py +458 -0
  29. docpull-5.0.0/src/docpull/pack_reader.py +732 -0
  30. docpull-5.0.0/src/docpull/pack_tools.py +1822 -0
  31. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/parallel_workflows.py +212 -18
  32. docpull-5.0.0/src/docpull/parity.py +953 -0
  33. docpull-5.0.0/src/docpull/parity_cli.py +276 -0
  34. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/__init__.py +2 -0
  35. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/convert.py +2 -2
  36. docpull-5.0.0/src/docpull/pipeline/steps/render.py +82 -0
  37. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/save.py +31 -30
  38. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/save_ndjson.py +2 -1
  39. docpull-5.0.0/src/docpull/policy.py +395 -0
  40. docpull-5.0.0/src/docpull/policy_cli.py +86 -0
  41. docpull-5.0.0/src/docpull/provider_adapters.py +1409 -0
  42. docpull-5.0.0/src/docpull/provider_capabilities.py +190 -0
  43. docpull-5.0.0/src/docpull/provider_cli.py +1363 -0
  44. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/provider_keys.py +81 -21
  45. docpull-5.0.0/src/docpull/provider_probes.py +615 -0
  46. docpull-5.0.0/src/docpull/rendering.py +944 -0
  47. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/security/download_policy.py +2 -2
  48. docpull-5.0.0/src/docpull/server.py +207 -0
  49. docpull-5.0.0/src/docpull/skill_export.py +265 -0
  50. docpull-5.0.0/src/docpull.egg-info/PKG-INFO +566 -0
  51. {docpull-4.4.0 → docpull-5.0.0}/src/docpull.egg-info/SOURCES.txt +41 -1
  52. {docpull-4.4.0 → docpull-5.0.0}/src/docpull.egg-info/requires.txt +19 -2
  53. docpull-5.0.0/tests/test_accounting.py +29 -0
  54. docpull-5.0.0/tests/test_auth_cli.py +177 -0
  55. {docpull-4.4.0 → docpull-5.0.0}/tests/test_benchmark.py +279 -0
  56. docpull-5.0.0/tests/test_ci_policy.py +192 -0
  57. docpull-5.0.0/tests/test_cli.py +802 -0
  58. {docpull-4.4.0 → docpull-5.0.0}/tests/test_discovery.py +30 -0
  59. docpull-5.0.0/tests/test_discovery_contracts.py +647 -0
  60. docpull-5.0.0/tests/test_doctor.py +214 -0
  61. docpull-5.0.0/tests/test_exports.py +271 -0
  62. docpull-5.0.0/tests/test_graph.py +127 -0
  63. {docpull-4.4.0 → docpull-5.0.0}/tests/test_link_extractors.py +56 -6
  64. docpull-5.0.0/tests/test_local_workflows.py +196 -0
  65. docpull-5.0.0/tests/test_mcp_server.py +468 -0
  66. docpull-5.0.0/tests/test_metadata_extractor.py +149 -0
  67. docpull-5.0.0/tests/test_monitor.py +120 -0
  68. docpull-5.0.0/tests/test_pack_server.py +191 -0
  69. docpull-5.0.0/tests/test_pack_tools.py +612 -0
  70. {docpull-4.4.0 → docpull-5.0.0}/tests/test_parallel_workflows.py +58 -0
  71. docpull-5.0.0/tests/test_parity_workflows.py +175 -0
  72. {docpull-4.4.0 → docpull-5.0.0}/tests/test_pipeline.py +150 -0
  73. docpull-5.0.0/tests/test_policy.py +109 -0
  74. docpull-5.0.0/tests/test_policy_cli.py +59 -0
  75. docpull-5.0.0/tests/test_provider_adapters.py +140 -0
  76. docpull-5.0.0/tests/test_provider_cli.py +457 -0
  77. docpull-5.0.0/tests/test_provider_keys.py +169 -0
  78. docpull-5.0.0/tests/test_provider_probes.py +206 -0
  79. docpull-5.0.0/tests/test_rate_limiter.py +46 -0
  80. {docpull-4.4.0 → docpull-5.0.0}/tests/test_real_site_regressions.py +65 -0
  81. docpull-5.0.0/tests/test_rendering.py +506 -0
  82. docpull-5.0.0/tests/test_surface_contract.py +194 -0
  83. docpull-5.0.0/tests/test_trafilatura_extractor.py +94 -0
  84. docpull-4.4.0/PKG-INFO +0 -818
  85. docpull-4.4.0/README.md +0 -720
  86. docpull-4.4.0/src/docpull/__init__.py +0 -74
  87. docpull-4.4.0/src/docpull/cli.py +0 -715
  88. docpull-4.4.0/src/docpull/mcp/server.py +0 -921
  89. docpull-4.4.0/src/docpull/pack_tools.py +0 -517
  90. docpull-4.4.0/src/docpull/provider_cli.py +0 -426
  91. docpull-4.4.0/src/docpull.egg-info/PKG-INFO +0 -818
  92. docpull-4.4.0/tests/test_ci_policy.py +0 -53
  93. docpull-4.4.0/tests/test_cli.py +0 -172
  94. docpull-4.4.0/tests/test_mcp_server.py +0 -64
  95. docpull-4.4.0/tests/test_pack_tools.py +0 -283
  96. docpull-4.4.0/tests/test_provider_cli.py +0 -85
  97. {docpull-4.4.0 → docpull-5.0.0}/LICENSE +0 -0
  98. {docpull-4.4.0 → docpull-5.0.0}/setup.cfg +0 -0
  99. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/__main__.py +0 -0
  100. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/cache/__init__.py +0 -0
  101. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/cache/frontier.py +0 -0
  102. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/cache/manager.py +0 -0
  103. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/cache/streaming_dedup.py +0 -0
  104. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/__init__.py +0 -0
  105. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/chunking.py +0 -0
  106. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/filings.py +0 -0
  107. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/markdown.py +0 -0
  108. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/special_cases.py +0 -0
  109. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/conversion/trafilatura_extractor.py +0 -0
  110. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/core/__init__.py +0 -0
  111. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/composite.py +0 -0
  112. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/filters.py +0 -0
  113. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/link_extractors/__init__.py +0 -0
  114. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/link_extractors/protocols.py +0 -0
  115. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/protocols.py +0 -0
  116. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/discovery/sitemap.py +0 -0
  117. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/fixtures/__init__.py +0 -0
  118. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/fixtures/parallel-search-extract.json +0 -0
  119. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/http/__init__.py +0 -0
  120. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/http/client.py +0 -0
  121. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/http/protocols.py +0 -0
  122. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/http/rate_limiter.py +0 -0
  123. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/judge.py +0 -0
  124. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/mcp/__init__.py +0 -0
  125. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/mcp/sources.py +0 -0
  126. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/mcp/tools.py +0 -0
  127. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/metadata_extractor.py +0 -0
  128. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/document.py +0 -0
  129. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/profiles.py +0 -0
  130. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/models/run.py +0 -0
  131. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/passk.py +0 -0
  132. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/__init__.py +0 -0
  133. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/base.py +0 -0
  134. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/manifest.py +0 -0
  135. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/chunk.py +0 -0
  136. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/dedup.py +0 -0
  137. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/fetch.py +0 -0
  138. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/metadata.py +0 -0
  139. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/save_json.py +0 -0
  140. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/save_okf.py +0 -0
  141. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/save_sqlite.py +0 -0
  142. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/pipeline/steps/validate.py +0 -0
  143. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/py.typed +0 -0
  144. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/scraper.py +0 -0
  145. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/security/__init__.py +0 -0
  146. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/security/robots.py +0 -0
  147. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/security/url_validator.py +0 -0
  148. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/source_scoring.py +0 -0
  149. {docpull-4.4.0 → docpull-5.0.0}/src/docpull/time_utils.py +0 -0
  150. {docpull-4.4.0 → docpull-5.0.0}/src/docpull.egg-info/dependency_links.txt +0 -0
  151. {docpull-4.4.0 → docpull-5.0.0}/src/docpull.egg-info/entry_points.txt +0 -0
  152. {docpull-4.4.0 → docpull-5.0.0}/src/docpull.egg-info/top_level.txt +0 -0
  153. {docpull-4.4.0 → docpull-5.0.0}/tests/test_cache_conditional_get.py +0 -0
  154. {docpull-4.4.0 → docpull-5.0.0}/tests/test_chunking.py +0 -0
  155. {docpull-4.4.0 → docpull-5.0.0}/tests/test_conversion.py +0 -0
  156. {docpull-4.4.0 → docpull-5.0.0}/tests/test_convert_step_new.py +0 -0
  157. {docpull-4.4.0 → docpull-5.0.0}/tests/test_document_record.py +0 -0
  158. {docpull-4.4.0 → docpull-5.0.0}/tests/test_evidence_pack.py +0 -0
  159. {docpull-4.4.0 → docpull-5.0.0}/tests/test_frontier_resume.py +0 -0
  160. {docpull-4.4.0 → docpull-5.0.0}/tests/test_integration.py +0 -0
  161. {docpull-4.4.0 → docpull-5.0.0}/tests/test_judge.py +0 -0
  162. {docpull-4.4.0 → docpull-5.0.0}/tests/test_mcp_tools.py +0 -0
  163. {docpull-4.4.0 → docpull-5.0.0}/tests/test_naming.py +0 -0
  164. {docpull-4.4.0 → docpull-5.0.0}/tests/test_outputs_e2e.py +0 -0
  165. {docpull-4.4.0 → docpull-5.0.0}/tests/test_passk.py +0 -0
  166. {docpull-4.4.0 → docpull-5.0.0}/tests/test_save_ndjson.py +0 -0
  167. {docpull-4.4.0 → docpull-5.0.0}/tests/test_save_sqlite.py +0 -0
  168. {docpull-4.4.0 → docpull-5.0.0}/tests/test_security_hardening.py +0 -0
  169. {docpull-4.4.0 → docpull-5.0.0}/tests/test_special_cases.py +0 -0
  170. {docpull-4.4.0 → docpull-5.0.0}/tests/test_time_utils.py +0 -0
docpull-5.0.0/PKG-INFO ADDED
@@ -0,0 +1,566 @@
1
+ Metadata-Version: 2.4
2
+ Name: docpull
3
+ Version: 5.0.0
4
+ Summary: Convert public web pages into clean Markdown for AI agents and RAG
5
+ Author-email: Zachary Roth <support@raintree.technology>
6
+ Maintainer-email: Raintree Technology <support@raintree.technology>
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://docpull.raintree.technology
9
+ Project-URL: Documentation, https://docpull.raintree.technology
10
+ Project-URL: Repository, https://github.com/raintree-technology/docpull
11
+ Project-URL: Source Code, https://github.com/raintree-technology/docpull
12
+ Project-URL: Bug Tracker, https://github.com/raintree-technology/docpull/issues
13
+ Project-URL: Releases, https://github.com/raintree-technology/docpull/releases
14
+ Project-URL: MCP Plugin, https://github.com/raintree-technology/docpull/tree/main/plugin
15
+ Project-URL: Comparison Guide, https://github.com/raintree-technology/docpull/blob/main/docs/alternatives.md
16
+ Project-URL: Download Stats, https://pepy.tech/project/docpull
17
+ Project-URL: Changelog, https://github.com/raintree-technology/docpull/blob/main/docs/CHANGELOG.md
18
+ Keywords: python,markdown,documentation,web,website,web-extraction,web-to-markdown,web-scraping,web-crawler,crawler,content-extraction,developer-tools,cli,rag,llm,mcp,ai-agents,context-engineering,source-packs,research,claude,ai-training-data
19
+ Classifier: Development Status :: 5 - Production/Stable
20
+ Classifier: Intended Audience :: Developers
21
+ Classifier: Intended Audience :: Information Technology
22
+ Classifier: Intended Audience :: Science/Research
23
+ Classifier: Intended Audience :: Education
24
+ Classifier: Environment :: Console
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
26
+ Classifier: Topic :: Text Processing :: Markup :: HTML
27
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
28
+ Classifier: Topic :: Utilities
29
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
30
+ Classifier: Natural Language :: English
31
+ Classifier: Operating System :: OS Independent
32
+ Classifier: Programming Language :: Python :: 3
33
+ Classifier: Programming Language :: Python :: 3.10
34
+ Classifier: Programming Language :: Python :: 3.11
35
+ Classifier: Programming Language :: Python :: 3.12
36
+ Classifier: Programming Language :: Python :: 3.13
37
+ Classifier: Programming Language :: Python :: 3.14
38
+ Classifier: Programming Language :: Python :: 3 :: Only
39
+ Classifier: Typing :: Typed
40
+ Requires-Python: >=3.10
41
+ Description-Content-Type: text/markdown
42
+ License-File: LICENSE
43
+ Requires-Dist: beautifulsoup4>=4.12.0
44
+ Requires-Dist: html2text>=2020.1.16
45
+ Requires-Dist: defusedxml>=0.7.1
46
+ Requires-Dist: extruct>=0.15.0
47
+ Requires-Dist: aiohttp>=3.14.0
48
+ Requires-Dist: idna>=3.15
49
+ Requires-Dist: regex>=2024.11.6
50
+ Requires-Dist: rich>=13.0.0
51
+ Requires-Dist: pyyaml>=6.0
52
+ Requires-Dist: pydantic>=2.0
53
+ Requires-Dist: urllib3>=2.7.0
54
+ Provides-Extra: proxy
55
+ Requires-Dist: aiohttp-socks>=0.11.0; extra == "proxy"
56
+ Provides-Extra: normalize
57
+ Requires-Dist: url-normalize>=1.4.0; extra == "normalize"
58
+ Provides-Extra: trafilatura
59
+ Requires-Dist: trafilatura>=1.12.0; extra == "trafilatura"
60
+ Provides-Extra: tokens
61
+ Requires-Dist: tiktoken>=0.7.0; extra == "tokens"
62
+ Provides-Extra: mcp
63
+ Requires-Dist: cryptography>=48.0.1; extra == "mcp"
64
+ Requires-Dist: mcp>=1.0.0; extra == "mcp"
65
+ Requires-Dist: pydantic-settings>=2.14.2; extra == "mcp"
66
+ Requires-Dist: pyjwt>=2.13.0; extra == "mcp"
67
+ Requires-Dist: python-multipart>=0.0.27; extra == "mcp"
68
+ Requires-Dist: starlette>=1.3.1; extra == "mcp"
69
+ Provides-Extra: serve
70
+ Requires-Dist: uvicorn>=0.30.0; extra == "serve"
71
+ Provides-Extra: parallel
72
+ Requires-Dist: parallel-web>=1.0.1; extra == "parallel"
73
+ Provides-Extra: observability
74
+ Requires-Dist: raindrop-ai>=0.0.50; extra == "observability"
75
+ Provides-Extra: parquet
76
+ Requires-Dist: pyarrow>=16.0.0; extra == "parquet"
77
+ Provides-Extra: e2b
78
+ Requires-Dist: e2b>=2.0.0; extra == "e2b"
79
+ Provides-Extra: llm
80
+ Requires-Dist: tiktoken>=0.7.0; extra == "llm"
81
+ Provides-Extra: all
82
+ Requires-Dist: aiohttp-socks>=0.11.0; extra == "all"
83
+ Requires-Dist: url-normalize>=1.4.0; extra == "all"
84
+ Requires-Dist: trafilatura>=1.12.0; extra == "all"
85
+ Requires-Dist: tiktoken>=0.7.0; extra == "all"
86
+ Requires-Dist: cryptography>=48.0.1; extra == "all"
87
+ Requires-Dist: mcp>=1.0.0; extra == "all"
88
+ Requires-Dist: pydantic-settings>=2.14.2; extra == "all"
89
+ Requires-Dist: pyjwt>=2.13.0; extra == "all"
90
+ Requires-Dist: python-multipart>=0.0.27; extra == "all"
91
+ Requires-Dist: starlette>=1.3.1; extra == "all"
92
+ Requires-Dist: uvicorn>=0.30.0; extra == "all"
93
+ Requires-Dist: parallel-web>=1.0.1; extra == "all"
94
+ Requires-Dist: raindrop-ai>=0.0.50; extra == "all"
95
+ Requires-Dist: pyarrow>=16.0.0; extra == "all"
96
+ Requires-Dist: e2b>=2.0.0; extra == "all"
97
+ Provides-Extra: dev
98
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
99
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
100
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
101
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
102
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
103
+ Requires-Dist: bandit>=1.7.0; extra == "dev"
104
+ Requires-Dist: pip-audit>=2.0.0; extra == "dev"
105
+ Requires-Dist: msgpack>=1.2.1; extra == "dev"
106
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
107
+ Requires-Dist: types-requests>=2.31.0; extra == "dev"
108
+ Requires-Dist: types-beautifulsoup4>=4.12.0; extra == "dev"
109
+ Requires-Dist: types-defusedxml>=0.7.0; extra == "dev"
110
+ Requires-Dist: types-pyyaml>=6.0.0; extra == "dev"
111
+ Dynamic: license-file
112
+
113
+ # docpull
114
+
115
+ **Turn public web sources into local Markdown, NDJSON, and agent-ready context packs. Browser-free by default.**
116
+
117
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
118
+ [![PyPI version](https://badge.fury.io/py/docpull.svg)](https://badge.fury.io/py/docpull)
119
+ [![PyPI downloads](https://img.shields.io/pepy/dt/docpull?label=downloads)](https://pepy.tech/project/docpull)
120
+ [![GitHub stars](https://img.shields.io/github/stars/raintree-technology/docpull?style=social)](https://github.com/raintree-technology/docpull/stargazers)
121
+ [![License: MIT](https://img.shields.io/github/license/raintree-technology/docpull)](https://github.com/raintree-technology/docpull/blob/main/LICENSE)
122
+
123
+ docpull is a Python CLI, SDK, and MCP server that fetches public or explicitly
124
+ authorized static/server-rendered web pages and converts them into clean,
125
+ auditable local artifacts for LLMs, retrieval-augmented generation (RAG),
126
+ offline research, and agent workflows.
127
+
128
+ DocPull is local-first: direct fetching, sitemap/link discovery, extraction,
129
+ indexing, pack intelligence, and local `agent-browser` rendering can run with no
130
+ provider account and no required API spend. Tavily, Exa, Parallel, and cloud
131
+ renderers are optional escalation paths when local and open-source routes are
132
+ not enough.
133
+
134
+ DocPull exposes the same core workflows through CLI, Python SDK, and MCP, with
135
+ each surface optimized for its user. The [Surface Contract](docs/surface-contract.md)
136
+ defines how those surfaces align and where they intentionally differ.
137
+
138
+ Web-source ingestion is the core workflow. Documentation is one high-value
139
+ lane, not the product boundary. It works best on static or server-rendered
140
+ pages such as blogs, API references, OpenAPI specs, changelogs, vendor pages,
141
+ product pages, filings, docs sites, and other pages where the useful content is
142
+ available in HTML or embedded page data.
143
+
144
+ docpull is browser-free by default. JS-only pages are skipped with a clear
145
+ reason unless you explicitly opt into the local `agent-browser` renderer. See
146
+ [Scraping Boundary](docs/scraping-boundary.md) and
147
+ [Alternatives](docs/alternatives.md) for the full boundary.
148
+
149
+ ## Install
150
+
151
+ ```bash
152
+ pip install docpull
153
+ ```
154
+
155
+ Install optional extras as needed:
156
+
157
+ ```bash
158
+ pip install 'docpull[llm]' # tiktoken for token-accurate chunking
159
+ pip install 'docpull[trafilatura]' # alternative extractor for noisy pages
160
+ pip install 'docpull[mcp]' # stdio MCP server
161
+ pip install 'docpull[serve]' # local pack JSON server runner
162
+ pip install 'docpull[parallel]' # Parallel context packs
163
+ pip install 'docpull[observability]' # Raindrop benchmark tracing
164
+ pip install 'docpull[e2b]' # E2B cloud sandbox renderer SDK
165
+ pip install 'docpull[all]' # all optional extras
166
+ ```
167
+
168
+ Browser rendering is an explicit external extension, not part of the base
169
+ install. Install an `agent-browser` compatible CLI separately, put it on
170
+ `PATH`, or set `DOCPULL_AGENT_BROWSER_BIN=/path/to/agent-browser`. Verify the
171
+ runtime with `docpull render --check`. Render targets must use HTTPS except for
172
+ localhost/loopback HTTP during local testing, and DocPull keeps renderer action
173
+ permissions locked down to HTML retrieval only.
174
+
175
+ For stronger isolation, cloud runtimes are available explicitly:
176
+ `docpull render URL --runtime vercel` uses the Vercel Sandbox CLI and Vercel
177
+ auth, while `docpull render URL --runtime e2b` uses the E2B Python SDK and
178
+ `E2B_API_KEY`. These are never enabled by default. All runtimes execute the same
179
+ `agent-browser --json` renderer contract. Use `--cloud-max-estimated-cost` to
180
+ set a local per-render budget guard, and use `--cloud-agent-browser-install skip`
181
+ with a prebuilt sandbox/template that already includes `agent-browser`. For E2B,
182
+ pass `--template` or set `DOCPULL_E2B_TEMPLATE` to use that prebuilt environment.
183
+
184
+ ## Free-First Budgets
185
+
186
+ Use `--budget 0` when a run must not make paid-capable provider or cloud calls:
187
+
188
+ ```bash
189
+ docpull https://docs.example.com --budget 0 -o ./docs/example
190
+ docpull discover scan https://docs.example.com -o ./packs/discovery
191
+ docpull render https://example.com/app --runtime local --budget 0
192
+ docpull providers context-pack "Find official docs" --provider all --dry-run --budget 0 --json
193
+ docpull benchmark quick --zero-dollar --target-set zero-dollar --provider all
194
+ ```
195
+
196
+ Under a zero budget, local cache, direct HTTP, sitemap/static-link discovery,
197
+ local extraction, local indexing, pack analysis, monitors, and local
198
+ `agent-browser` rendering remain allowed. Live Tavily, Exa, Parallel, Vercel
199
+ Sandbox, and E2B calls are blocked before execution. Runs involving a budget or
200
+ paid-capable route write `run.accounting.json` with non-secret route, cost,
201
+ HTTP/cache, browser, and blocked-action metadata.
202
+
203
+ Use `docpull discover scan URL` to build a provider-free discovery pack from
204
+ open site hints: `llms.txt`, RSS/Atom feeds, OpenAPI specs, sitemap indexes,
205
+ and public GitHub docs trees. It writes the same `candidate_sources.ndjson`
206
+ contract as provider imports and URL/sitemap files, so the next step is still
207
+ `docpull discover select` or `docpull discover fetch`.
208
+
209
+ When a zero-dollar benchmark or local run is partial, DocPull reports the
210
+ lowest-friction escalation path before spending money: local `--render fallback`
211
+ first, BYOK providers next, and cloud rendering only when local rendering or
212
+ infrastructure is the blocker. Benchmark reports include suggested commands,
213
+ estimated paid request counts, and estimated paid cost guards before any
214
+ provider or cloud call is made.
215
+
216
+ The `zero-dollar` benchmark target set is the Phase 2 measurement matrix. It
217
+ keeps the existing docs/provider targets and adds JS-heavy docs, pricing,
218
+ filings, feeds, sitemaps, and search-to-evidence tasks. The report classifies
219
+ each target as `complete_for_0`, `complete_with_local_browser`, `partial_for_0`,
220
+ `requires_provider`, `requires_cloud_browser`, or `blocked_by_policy`.
221
+
222
+ ## Open Source And Hosted Boundary
223
+
224
+ The open-source package owns local fetching, local rendering adapters,
225
+ provider-free discovery, extraction, indexing, packs, diffs, monitors, MCP,
226
+ BYOK providers, budget policy, accounting, and benchmarks.
227
+
228
+ A hosted DocPull product, if offered, should sell managed execution: always-on
229
+ schedules, browser/proxy infrastructure, persistent auth profiles, queues,
230
+ alerts, dashboards, collaboration, retention, SSO, audit logs, SLAs, and
231
+ bundled provider billing. The hosted boundary does not change the OSS default:
232
+ no hidden paid calls, no CAPTCHA bypass, no stealth scraping, and no claim of a
233
+ proprietary web-scale index.
234
+
235
+ ## 30-Second Usage
236
+
237
+ ```bash
238
+ docpull https://www.python.org/blogs/ --single -o ./python-news
239
+ ```
240
+
241
+ Example output:
242
+
243
+ ```text
244
+ python-news/
245
+ index.md
246
+ corpus.manifest.json
247
+ ```
248
+
249
+ Markdown includes source metadata and readable page content:
250
+
251
+ ```markdown
252
+ ---
253
+ title: "Blogs"
254
+ source: https://www.python.org/blogs/
255
+ source_type: "html"
256
+ ---
257
+
258
+ # Blogs
259
+
260
+ News from the Python Software Foundation, Python core developers, and the
261
+ wider Python community.
262
+ ```
263
+
264
+ Stream chunked NDJSON for agents and RAG:
265
+
266
+ ```bash
267
+ docpull https://www.python.org/blogs/ \
268
+ --single \
269
+ --profile llm \
270
+ --stream | jq .
271
+ ```
272
+
273
+ Each line is a JSON document:
274
+
275
+ ```json
276
+ {"schema_version":1,"document_id":"doc_...","chunk_id":"chunk_...","url":"https://www.python.org/blogs/","title":"Blogs","content":"News from the Python Software Foundation...","source_type":"html","chunk_index":0,"token_count":842}
277
+ ```
278
+
279
+ ## Common Workflows
280
+
281
+ ```bash
282
+ # Crawl a public web section and write Markdown files
283
+ docpull https://www.python.org/blogs/ -o ./python-news
284
+
285
+ # Stream LLM-ready NDJSON chunks from a source
286
+ docpull https://www.python.org/blogs/ --profile llm --stream | jq .
287
+
288
+ # Write SQLite with an FTS5 search index
289
+ docpull https://www.python.org/blogs/ --format sqlite -o ./python-news-db
290
+
291
+ # Build an Open Knowledge Format (OKF) bundle for portable source packs
292
+ docpull https://example.com --profile okf -o ./site-okf
293
+
294
+ # Turn a source corpus into agent-ready skills/rules
295
+ docpull https://sdk.vercel.ai \
296
+ --skill vercel-ai \
297
+ --skill-agent all \
298
+ --skill-description "Vercel AI SDK source reference"
299
+ ```
300
+
301
+ Local-first parity workflows mirror common hosted search/extract/crawl/research
302
+ API shapes while writing auditable files instead of relying on a hosted index:
303
+
304
+ ```bash
305
+ # Normalize candidate URLs without fetching content
306
+ docpull map urls ./urls.txt -o ./packs/map
307
+
308
+ # Extract known URLs into a local pack
309
+ docpull extract-pack ./urls.txt -o ./packs/extract
310
+
311
+ # Select mapped candidates and fetch them
312
+ docpull crawl-pack ./packs/map --select top:10 -o ./packs/crawl
313
+
314
+ # Answer/research from an existing local pack with lifecycle artifacts
315
+ docpull research-pack ./packs/crawl \
316
+ --objective "Summarize auth and webhook behavior" \
317
+ --schema ./output.schema.json
318
+
319
+ # Build a cited entity/list pack from existing evidence
320
+ docpull entities-pack ./packs/crawl --limit 100
321
+ ```
322
+
323
+ More examples live in [CLI Recipes](docs/examples/README.md).
324
+
325
+ With an explicit `--skill-agent`, docpull stores the scraped corpus under
326
+ `.docpull/skills/<name>/references` and creates agent-specific wrappers that
327
+ point at that corpus. `--skill-agent claude` writes a Claude Code skill under
328
+ `.claude/skills/<name>/`, `--skill-agent codex` writes a Codex skill under
329
+ `.agents/skills/<name>/` with `agents/openai.yaml`, and `--skill-agent cursor`
330
+ writes a Cursor project rule at `.cursor/rules/<name>.mdc`. Use
331
+ `--skill-agent all` to create all three. If you pass `--output-dir`, docpull
332
+ stages the generated corpus there; explicit `--skill-agent` targets still write
333
+ their active agent wrappers.
334
+
335
+ Use docpull when you need to:
336
+
337
+ - Convert public web sources - docs, blogs, API references, vendor pages,
338
+ product pages, changelogs, filings, and OpenAPI specs - into Markdown or
339
+ chunked NDJSON for LLM and RAG pipelines.
340
+ - Give an agent a local tool for fetching, caching, grepping, and reading web
341
+ sources.
342
+ - Build repeatable context packs with stable IDs, hashes, manifests, and source
343
+ metadata.
344
+ - Mirror public web content for offline work while preserving attribution.
345
+
346
+ ## Why docpull?
347
+
348
+ docpull is designed for agent and RAG workflows, not just downloading pages.
349
+
350
+ | Need | docpull gives you |
351
+ | --- | --- |
352
+ | Clean Markdown | Article-focused extraction with source metadata |
353
+ | LLM chunks | NDJSON streaming and optional token-aware chunking |
354
+ | Repeatability | Stable document IDs, chunk IDs, hashes, and manifests |
355
+ | Offline work | Cached archives and mirrored source artifacts |
356
+ | Agent access | Local CLI, Python SDK, and stdio MCP server |
357
+ | Downstream exports | JSONL, Sheets CSV/TSV, n8n JSON, Vercel AI JSON, CrewAI JSON, warehouse NDJSON, optional Parquet, and agent skills |
358
+ | Safer fetching | HTTPS defaults, robots.txt compliance, SSRF protections, and redirect guards |
359
+
360
+ ## Supported Sources
361
+
362
+ docpull uses async HTTP instead of browser automation by default and includes
363
+ special handling for common web, documentation, and API surfaces.
364
+
365
+ | Source shape | Support |
366
+ | --- | --- |
367
+ | Static HTML / SSR pages | Extracts article, main, or document regions |
368
+ | Next.js / Mintlify | Parses static HTML and `__NEXT_DATA__` when available |
369
+ | OpenAPI / Swagger | Renders specs into Markdown |
370
+ | Docusaurus / Sphinx / MkDocs | Extracts static article or document regions |
371
+ | VitePress / VuePress / Astro Starlight | Extracts static content regions |
372
+ | GitBook / ReadMe.io | Extracts available article or content regions |
373
+ | Redoc / Scalar | Extracts static API reference regions |
374
+ | JS-only apps | Skipped unless useful content is present in HTML or embedded data |
375
+
376
+ Use `--strict-js-required` when an agent should treat JS-only pages as hard
377
+ errors instead of normal skips.
378
+
379
+ ## Output Formats
380
+
381
+ | Output | Use it for |
382
+ | --- | --- |
383
+ | Markdown | Local readable source snapshots with YAML frontmatter |
384
+ | NDJSON | Streamed records or chunked records for agents and RAG |
385
+ | SQLite | Local retrieval with an FTS5 index |
386
+ | OKF | Portable Open Knowledge Format bundles with indexes and manifests |
387
+ | Archive / mirror | Cached offline source snapshots |
388
+
389
+ Every file-backed run writes `corpus.manifest.json` with stable document IDs,
390
+ chunk IDs, hashes, output paths, and chunk counts. See
391
+ [Corpus Manifest](docs/corpus-manifest.md).
392
+
393
+ ## Profiles
394
+
395
+ ```bash
396
+ docpull https://site.com --profile rag # Default. Dedup + metadata.
397
+ docpull https://site.com --profile llm # NDJSON chunks for agents/RAG.
398
+ docpull https://site.com --profile okf # Portable Open Knowledge Format bundle.
399
+ docpull https://site.com --profile mirror # Cached archive.
400
+ docpull https://site.com --profile quick # Small sampling crawl.
401
+ docpull https://site.com --profile sec-filing # EDGAR-friendly evidence chunks.
402
+ ```
403
+
404
+ Run `docpull --help` for the full option list.
405
+
406
+ ## When Not to Use docpull
407
+
408
+ docpull intentionally does not use a browser unless rendering is explicitly
409
+ enabled. It is not the right tool for:
410
+
411
+ - JS-only pages that require complex browser workflows beyond static rendered HTML.
412
+ - Authenticated dashboards or private apps.
413
+ - Pages behind CAPTCHA or bot challenges.
414
+ - Workflows that require clicking, scrolling, or browser state.
415
+
416
+ For those cases, use browser automation, such as Playwright, then pass rendered
417
+ HTML or exported content into your pipeline. For simple public JS-rendered
418
+ pages, `docpull render` and `--render fallback` provide an explicit local
419
+ fallback without changing the default crawler behavior. The fallback requires
420
+ the optional external `agent-browser` backend.
421
+
422
+ ## How It Compares
423
+
424
+ | Tool type | Best for | Tradeoff |
425
+ | --- | --- | --- |
426
+ | `wget` / site mirroring | Downloading raw files | Not agent/RAG-oriented |
427
+ | Browser automation | JS-heavy pages and interactions | Slower, heavier, more stateful |
428
+ | Hosted extraction APIs | Managed extraction at scale | External dependency and cost |
429
+ | docpull | Local public web-source extraction and context packs | No JavaScript rendering by default |
430
+
431
+ ## Python SDK
432
+
433
+ ```python
434
+ from docpull import fetch_one
435
+
436
+ ctx = fetch_one("https://docs.python.org/3/library/asyncio.html")
437
+ print(ctx.title)
438
+ print(ctx.markdown[:500])
439
+ ```
440
+
441
+ ```python
442
+ import asyncio
443
+ from docpull import Fetcher, DocpullConfig, EventType, ProfileName
444
+
445
+ async def main():
446
+ cfg = DocpullConfig(url="https://example.com/blog", profile=ProfileName.LLM)
447
+ async with Fetcher(cfg) as fetcher:
448
+ async for event in fetcher.run():
449
+ if event.type == EventType.FETCH_PROGRESS:
450
+ print(f"{event.current}/{event.total}: {event.url}")
451
+
452
+ asyncio.run(main())
453
+ ```
454
+
455
+ ## MCP Server
456
+
457
+ docpull can run as a stdio MCP server for agent clients:
458
+
459
+ ```bash
460
+ pip install 'docpull[mcp]'
461
+ docpull mcp
462
+ ```
463
+
464
+ Claude Code:
465
+
466
+ ```bash
467
+ claude mcp add --transport stdio docpull -- docpull mcp
468
+ ```
469
+
470
+ Cursor and Claude Desktop use the same `mcpServers` shape:
471
+
472
+ ```json
473
+ {
474
+ "mcpServers": {
475
+ "docpull": {
476
+ "type": "stdio",
477
+ "command": "docpull",
478
+ "args": ["mcp"]
479
+ }
480
+ }
481
+ }
482
+ ```
483
+
484
+ The supported MCP path is the Python stdio server started by `docpull mcp`.
485
+ The repository's `mcp/` directory is an internal TypeScript/Bun lab and is not
486
+ part of the package release contract.
487
+
488
+ ## Advanced Workflows
489
+
490
+ - `docpull[parallel]` can discover, extract, enrich, score, diff, and archive
491
+ live web sources with your own Parallel API key. See
492
+ [Parallel Integration](docs/parallel.md).
493
+ - Local pack intelligence can build citation maps, extract cited entities,
494
+ search pack records, write provider-free research briefs, build cited source
495
+ graphs, or prepare the full sidecar bundle with
496
+ `docpull pack citations`, `docpull pack entities`, `docpull pack search`,
497
+ `docpull pack brief`, `docpull graph build`, `docpull graph query`, and
498
+ `docpull pack prepare`.
499
+ - Local-first expansion commands add policy files, discovery packs, refresh
500
+ reports, audits, cited answers, exports, a localhost pack server, explicit
501
+ rendering, authenticated-source checks, and cron-friendly monitors:
502
+ `docpull policy`, `docpull discover`, `docpull refresh`,
503
+ `docpull pack audit`, `docpull answer-pack`, `docpull export`,
504
+ `docpull serve`, `docpull render`, `docpull auth check`, and
505
+ `docpull monitor`.
506
+ - `docpull export` writes local files for OpenAI vector JSONL, LangChain,
507
+ LlamaIndex, DSPy, Sheets CSV/TSV, n8n workflow JSON, Vercel AI SDK JSON,
508
+ CrewAI JSON, warehouse NDJSON, optional Parquet via `docpull[parquet]`, and
509
+ Codex/Claude/Cursor agent references.
510
+ - Optional provider workflows can use Parallel, Tavily, and Exa when configured.
511
+ Tavily and Exa are available through `docpull providers ...` and first-class
512
+ aliases such as `docpull tavily context-pack`, `docpull exa context-pack`,
513
+ `docpull exa extract-pack`, and `docpull tavily map-pack`. Use
514
+ `docpull providers capabilities` to see the shared baseline and provider-only
515
+ extensions. For agent or CI logs, use
516
+ `docpull providers auth --json --require-ready --redact-paths` for offline
517
+ local readiness, then `docpull providers probe --json --require-verified
518
+ --redact-paths` when explicit live key validation is intended. Successful
519
+ provider context-pack runs are post-processed into the same local pack
520
+ intelligence artifacts.
521
+ See [CLI Recipes](docs/examples/README.md#parallel-context-pack).
522
+ - SEC filing evidence packs use rule profiles such as
523
+ [vendor-dependency-rules.yml](docs/examples/vendor-dependency-rules.yml).
524
+
525
+ ## Security Defaults
526
+
527
+ - HTTPS-only fetching with robots.txt compliance.
528
+ - SSRF protections, private network blocking, DNS rebinding protection, and
529
+ connect-time address pinning.
530
+ - XXE protection for sitemaps.
531
+ - Path traversal and CRLF header injection guards.
532
+ - Auth headers stripped on cross-origin redirects.
533
+
534
+ When running with `--proxy`, DNS pinning is delegated to the proxy. Pass
535
+ `--require-pinned-dns` to refuse that configuration.
536
+
537
+ ## Troubleshooting
538
+
539
+ ```bash
540
+ docpull --doctor
541
+ docpull render --check
542
+ docpull URL --verbose
543
+ docpull URL --dry-run
544
+ docpull URL --preview-urls
545
+ ```
546
+
547
+ ## Documentation
548
+
549
+ - [CLI Recipes](docs/examples/README.md) - common commands and advanced workflows.
550
+ - [Scraping Boundary](docs/scraping-boundary.md) - what docpull does and does not fetch.
551
+ - [Alternatives](docs/alternatives.md) - when to use browser automation or hosted extraction.
552
+ - [Corpus Manifest](docs/corpus-manifest.md) - stable IDs, hashes, and source maps.
553
+ - [Surface Contract](docs/surface-contract.md) - how the CLI, Python SDK/API, and MCP surfaces align.
554
+ - [Parallel Integration](docs/parallel.md) - live-source context pack workflows.
555
+ - [Changelog](docs/CHANGELOG.md) - release history.
556
+
557
+ ## Links
558
+
559
+ - [Website](https://docpull.raintree.technology)
560
+ - [PyPI](https://pypi.org/project/docpull/)
561
+ - [GitHub](https://github.com/raintree-technology/docpull)
562
+ - [Metrics](METRICS.md)
563
+
564
+ ## License
565
+
566
+ MIT