docpull 4.4.0__tar.gz → 4.4.1__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 (120) hide show
  1. docpull-4.4.1/PKG-INFO +398 -0
  2. docpull-4.4.1/README.md +298 -0
  3. {docpull-4.4.0 → docpull-4.4.1}/pyproject.toml +5 -3
  4. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/__init__.py +1 -1
  5. docpull-4.4.1/src/docpull.egg-info/PKG-INFO +398 -0
  6. {docpull-4.4.0 → docpull-4.4.1}/src/docpull.egg-info/requires.txt +4 -2
  7. {docpull-4.4.0 → docpull-4.4.1}/tests/test_ci_policy.py +7 -2
  8. docpull-4.4.0/PKG-INFO +0 -818
  9. docpull-4.4.0/README.md +0 -720
  10. docpull-4.4.0/src/docpull.egg-info/PKG-INFO +0 -818
  11. {docpull-4.4.0 → docpull-4.4.1}/LICENSE +0 -0
  12. {docpull-4.4.0 → docpull-4.4.1}/setup.cfg +0 -0
  13. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/__main__.py +0 -0
  14. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/benchmark.py +0 -0
  15. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/cache/__init__.py +0 -0
  16. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/cache/frontier.py +0 -0
  17. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/cache/manager.py +0 -0
  18. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/cache/streaming_dedup.py +0 -0
  19. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/cli.py +0 -0
  20. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/__init__.py +0 -0
  21. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/chunking.py +0 -0
  22. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/extractor.py +0 -0
  23. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/filings.py +0 -0
  24. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/markdown.py +0 -0
  25. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/protocols.py +0 -0
  26. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/special_cases.py +0 -0
  27. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/conversion/trafilatura_extractor.py +0 -0
  28. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/core/__init__.py +0 -0
  29. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/core/fetcher.py +0 -0
  30. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/__init__.py +0 -0
  31. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/_fetch.py +0 -0
  32. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/composite.py +0 -0
  33. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/crawler.py +0 -0
  34. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/filters.py +0 -0
  35. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/link_extractors/__init__.py +0 -0
  36. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/link_extractors/enhanced.py +0 -0
  37. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/link_extractors/protocols.py +0 -0
  38. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/link_extractors/static.py +0 -0
  39. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/protocols.py +0 -0
  40. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/discovery/sitemap.py +0 -0
  41. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/doctor.py +0 -0
  42. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/evidence_pack.py +0 -0
  43. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/fixtures/__init__.py +0 -0
  44. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/fixtures/parallel-search-extract.json +0 -0
  45. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/http/__init__.py +0 -0
  46. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/http/client.py +0 -0
  47. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/http/protocols.py +0 -0
  48. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/http/rate_limiter.py +0 -0
  49. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/judge.py +0 -0
  50. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/mcp/__init__.py +0 -0
  51. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/mcp/server.py +0 -0
  52. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/mcp/sources.py +0 -0
  53. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/mcp/tools.py +0 -0
  54. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/metadata_extractor.py +0 -0
  55. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/__init__.py +0 -0
  56. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/config.py +0 -0
  57. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/document.py +0 -0
  58. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/events.py +0 -0
  59. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/profiles.py +0 -0
  60. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/models/run.py +0 -0
  61. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pack_tools.py +0 -0
  62. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/parallel_workflows.py +0 -0
  63. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/passk.py +0 -0
  64. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/__init__.py +0 -0
  65. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/base.py +0 -0
  66. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/manifest.py +0 -0
  67. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/__init__.py +0 -0
  68. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/chunk.py +0 -0
  69. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/convert.py +0 -0
  70. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/dedup.py +0 -0
  71. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/fetch.py +0 -0
  72. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/metadata.py +0 -0
  73. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/save.py +0 -0
  74. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/save_json.py +0 -0
  75. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/save_ndjson.py +0 -0
  76. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/save_okf.py +0 -0
  77. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/save_sqlite.py +0 -0
  78. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/pipeline/steps/validate.py +0 -0
  79. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/provider_cli.py +0 -0
  80. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/provider_keys.py +0 -0
  81. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/py.typed +0 -0
  82. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/scraper.py +0 -0
  83. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/security/__init__.py +0 -0
  84. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/security/download_policy.py +0 -0
  85. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/security/robots.py +0 -0
  86. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/security/url_validator.py +0 -0
  87. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/source_scoring.py +0 -0
  88. {docpull-4.4.0 → docpull-4.4.1}/src/docpull/time_utils.py +0 -0
  89. {docpull-4.4.0 → docpull-4.4.1}/src/docpull.egg-info/SOURCES.txt +0 -0
  90. {docpull-4.4.0 → docpull-4.4.1}/src/docpull.egg-info/dependency_links.txt +0 -0
  91. {docpull-4.4.0 → docpull-4.4.1}/src/docpull.egg-info/entry_points.txt +0 -0
  92. {docpull-4.4.0 → docpull-4.4.1}/src/docpull.egg-info/top_level.txt +0 -0
  93. {docpull-4.4.0 → docpull-4.4.1}/tests/test_benchmark.py +0 -0
  94. {docpull-4.4.0 → docpull-4.4.1}/tests/test_cache_conditional_get.py +0 -0
  95. {docpull-4.4.0 → docpull-4.4.1}/tests/test_chunking.py +0 -0
  96. {docpull-4.4.0 → docpull-4.4.1}/tests/test_cli.py +0 -0
  97. {docpull-4.4.0 → docpull-4.4.1}/tests/test_conversion.py +0 -0
  98. {docpull-4.4.0 → docpull-4.4.1}/tests/test_convert_step_new.py +0 -0
  99. {docpull-4.4.0 → docpull-4.4.1}/tests/test_discovery.py +0 -0
  100. {docpull-4.4.0 → docpull-4.4.1}/tests/test_document_record.py +0 -0
  101. {docpull-4.4.0 → docpull-4.4.1}/tests/test_evidence_pack.py +0 -0
  102. {docpull-4.4.0 → docpull-4.4.1}/tests/test_frontier_resume.py +0 -0
  103. {docpull-4.4.0 → docpull-4.4.1}/tests/test_integration.py +0 -0
  104. {docpull-4.4.0 → docpull-4.4.1}/tests/test_judge.py +0 -0
  105. {docpull-4.4.0 → docpull-4.4.1}/tests/test_link_extractors.py +0 -0
  106. {docpull-4.4.0 → docpull-4.4.1}/tests/test_mcp_server.py +0 -0
  107. {docpull-4.4.0 → docpull-4.4.1}/tests/test_mcp_tools.py +0 -0
  108. {docpull-4.4.0 → docpull-4.4.1}/tests/test_naming.py +0 -0
  109. {docpull-4.4.0 → docpull-4.4.1}/tests/test_outputs_e2e.py +0 -0
  110. {docpull-4.4.0 → docpull-4.4.1}/tests/test_pack_tools.py +0 -0
  111. {docpull-4.4.0 → docpull-4.4.1}/tests/test_parallel_workflows.py +0 -0
  112. {docpull-4.4.0 → docpull-4.4.1}/tests/test_passk.py +0 -0
  113. {docpull-4.4.0 → docpull-4.4.1}/tests/test_pipeline.py +0 -0
  114. {docpull-4.4.0 → docpull-4.4.1}/tests/test_provider_cli.py +0 -0
  115. {docpull-4.4.0 → docpull-4.4.1}/tests/test_real_site_regressions.py +0 -0
  116. {docpull-4.4.0 → docpull-4.4.1}/tests/test_save_ndjson.py +0 -0
  117. {docpull-4.4.0 → docpull-4.4.1}/tests/test_save_sqlite.py +0 -0
  118. {docpull-4.4.0 → docpull-4.4.1}/tests/test_security_hardening.py +0 -0
  119. {docpull-4.4.0 → docpull-4.4.1}/tests/test_special_cases.py +0 -0
  120. {docpull-4.4.0 → docpull-4.4.1}/tests/test_time_utils.py +0 -0
docpull-4.4.1/PKG-INFO ADDED
@@ -0,0 +1,398 @@
1
+ Metadata-Version: 2.4
2
+ Name: docpull
3
+ Version: 4.4.1
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-extraction,web-scraping,web-crawler,crawler,developer-tools,cli,rag,llm,mcp,ai-agents,context-engineering,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: pyjwt>=2.13.0; extra == "mcp"
66
+ Requires-Dist: python-multipart>=0.0.27; extra == "mcp"
67
+ Requires-Dist: starlette>=1.3.1; extra == "mcp"
68
+ Provides-Extra: parallel
69
+ Requires-Dist: parallel-web>=1.0.1; extra == "parallel"
70
+ Provides-Extra: observability
71
+ Requires-Dist: raindrop-ai>=0.0.50; extra == "observability"
72
+ Provides-Extra: llm
73
+ Requires-Dist: tiktoken>=0.7.0; extra == "llm"
74
+ Provides-Extra: all
75
+ Requires-Dist: aiohttp-socks>=0.11.0; extra == "all"
76
+ Requires-Dist: url-normalize>=1.4.0; extra == "all"
77
+ Requires-Dist: trafilatura>=1.12.0; extra == "all"
78
+ Requires-Dist: tiktoken>=0.7.0; extra == "all"
79
+ Requires-Dist: cryptography>=48.0.1; extra == "all"
80
+ Requires-Dist: mcp>=1.0.0; extra == "all"
81
+ Requires-Dist: pyjwt>=2.13.0; extra == "all"
82
+ Requires-Dist: python-multipart>=0.0.27; extra == "all"
83
+ Requires-Dist: starlette>=1.3.1; extra == "all"
84
+ Requires-Dist: parallel-web>=1.0.1; extra == "all"
85
+ Requires-Dist: raindrop-ai>=0.0.50; extra == "all"
86
+ Provides-Extra: dev
87
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
88
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
89
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
90
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
91
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
92
+ Requires-Dist: bandit>=1.7.0; extra == "dev"
93
+ Requires-Dist: pip-audit>=2.0.0; extra == "dev"
94
+ Requires-Dist: pre-commit>=3.0.0; extra == "dev"
95
+ Requires-Dist: types-requests>=2.31.0; extra == "dev"
96
+ Requires-Dist: types-beautifulsoup4>=4.12.0; extra == "dev"
97
+ Requires-Dist: types-defusedxml>=0.7.0; extra == "dev"
98
+ Requires-Dist: types-pyyaml>=6.0.0; extra == "dev"
99
+ Dynamic: license-file
100
+
101
+ # docpull
102
+
103
+ **Turn public documentation sites into local Markdown, NDJSON, and agent-ready context packs. No browser required.**
104
+
105
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
106
+ [![PyPI version](https://badge.fury.io/py/docpull.svg)](https://badge.fury.io/py/docpull)
107
+ [![PyPI downloads](https://img.shields.io/pepy/dt/docpull?label=downloads)](https://pepy.tech/project/docpull)
108
+ [![GitHub stars](https://img.shields.io/github/stars/raintree-technology/docpull?style=social)](https://github.com/raintree-technology/docpull/stargazers)
109
+ [![License: MIT](https://img.shields.io/github/license/raintree-technology/docpull)](https://github.com/raintree-technology/docpull/blob/main/LICENSE)
110
+
111
+ docpull is a Python CLI, SDK, and MCP server that fetches public static or
112
+ server-rendered web pages and converts them into clean, auditable local
113
+ artifacts for LLMs, retrieval-augmented generation (RAG), offline research, and
114
+ agent workflows.
115
+
116
+ It works best on documentation sites, blogs, API references, OpenAPI specs,
117
+ vendor pages, and other public pages where the useful content is available in
118
+ HTML or embedded page data.
119
+
120
+ docpull is not a browser and does not render JavaScript. JS-only pages are
121
+ skipped with a clear reason. See [Scraping Boundary](docs/scraping-boundary.md)
122
+ and [Alternatives](docs/alternatives.md) for the full boundary.
123
+
124
+ ## Install
125
+
126
+ ```bash
127
+ pip install docpull
128
+ ```
129
+
130
+ Install optional extras as needed:
131
+
132
+ ```bash
133
+ pip install 'docpull[llm]' # tiktoken for token-accurate chunking
134
+ pip install 'docpull[trafilatura]' # alternative extractor for noisy pages
135
+ pip install 'docpull[mcp]' # stdio MCP server
136
+ pip install 'docpull[parallel]' # Parallel context packs
137
+ pip install 'docpull[observability]' # Raindrop benchmark tracing
138
+ pip install 'docpull[all]' # all optional extras
139
+ ```
140
+
141
+ ## 30-Second Usage
142
+
143
+ ```bash
144
+ docpull https://docs.python.org/3/library/asyncio.html --single -o ./asyncio-docs
145
+ ```
146
+
147
+ Example output:
148
+
149
+ ```text
150
+ asyncio-docs/
151
+ index.md
152
+ corpus.manifest.json
153
+ ```
154
+
155
+ Markdown includes source metadata and readable page content:
156
+
157
+ ```markdown
158
+ ---
159
+ title: "asyncio - Asynchronous I/O"
160
+ source: https://docs.python.org/3/library/asyncio.html
161
+ source_type: "sphinx"
162
+ ---
163
+
164
+ # asyncio - Asynchronous I/O
165
+
166
+ asyncio is a library to write concurrent code using the async/await syntax.
167
+ ```
168
+
169
+ Stream chunked NDJSON for agents and RAG:
170
+
171
+ ```bash
172
+ docpull https://docs.python.org/3/library/asyncio.html \
173
+ --single \
174
+ --profile llm \
175
+ --stream | jq .
176
+ ```
177
+
178
+ Each line is a JSON document:
179
+
180
+ ```json
181
+ {"schema_version":1,"document_id":"doc_...","chunk_id":"chunk_...","url":"https://docs.python.org/3/library/asyncio.html","title":"asyncio - Asynchronous I/O","content":"asyncio is a library to write concurrent code...","source_type":"sphinx","chunk_index":0,"token_count":842}
182
+ ```
183
+
184
+ ## Common Workflows
185
+
186
+ ```bash
187
+ # Crawl a site and write Markdown files
188
+ docpull https://docs.example.com -o ./docs-example
189
+
190
+ # Stream LLM-ready NDJSON chunks from a site
191
+ docpull https://docs.example.com --profile llm --stream | jq .
192
+
193
+ # Write SQLite with an FTS5 search index
194
+ docpull https://docs.example.com --format sqlite -o ./docs-db
195
+
196
+ # Build an Open Knowledge Format (OKF) bundle for portable source packs
197
+ docpull https://example.com --profile okf -o ./site-okf
198
+ ```
199
+
200
+ More examples live in [CLI Recipes](docs/examples/README.md).
201
+
202
+ Use docpull when you need to:
203
+
204
+ - Convert public docs, blogs, API references, vendor pages, and OpenAPI specs
205
+ into Markdown or chunked NDJSON for LLM and RAG pipelines.
206
+ - Give an agent a local tool for fetching, caching, grepping, and reading web
207
+ sources.
208
+ - Build repeatable context packs with stable IDs, hashes, manifests, and source
209
+ metadata.
210
+ - Mirror public web content for offline work while preserving attribution.
211
+
212
+ ## Why docpull?
213
+
214
+ docpull is designed for agent and RAG workflows, not just downloading pages.
215
+
216
+ | Need | docpull gives you |
217
+ | --- | --- |
218
+ | Clean Markdown | Article-focused extraction with source metadata |
219
+ | LLM chunks | NDJSON streaming and optional token-aware chunking |
220
+ | Repeatability | Stable document IDs, chunk IDs, hashes, and manifests |
221
+ | Offline work | Cached archives and mirrored source artifacts |
222
+ | Agent access | Local CLI, Python SDK, and stdio MCP server |
223
+ | Safer fetching | HTTPS defaults, robots.txt compliance, SSRF protections, and redirect guards |
224
+
225
+ ## Supported Sources
226
+
227
+ docpull uses async HTTP instead of browser automation and includes special
228
+ handling for common documentation and API surfaces.
229
+
230
+ | Source shape | Support |
231
+ | --- | --- |
232
+ | Static HTML / SSR docs | Extracts article or document regions |
233
+ | Next.js / Mintlify | Parses static HTML and `__NEXT_DATA__` when available |
234
+ | OpenAPI / Swagger | Renders specs into Markdown |
235
+ | Docusaurus / Sphinx / MkDocs | Extracts static article or document regions |
236
+ | VitePress / VuePress / Astro Starlight | Extracts static docs content |
237
+ | GitBook / ReadMe.io | Extracts available article or content regions |
238
+ | Redoc / Scalar | Extracts static API reference regions |
239
+ | JS-only apps | Skipped unless useful content is present in HTML or embedded data |
240
+
241
+ Use `--strict-js-required` when an agent should treat JS-only pages as hard
242
+ errors instead of normal skips.
243
+
244
+ ## Output Formats
245
+
246
+ | Output | Use it for |
247
+ | --- | --- |
248
+ | Markdown | Local readable source snapshots with YAML frontmatter |
249
+ | NDJSON | Streamed records or chunked records for agents and RAG |
250
+ | SQLite | Local retrieval with an FTS5 index |
251
+ | OKF | Portable Open Knowledge Format bundles with indexes and manifests |
252
+ | Archive / mirror | Cached offline source snapshots |
253
+
254
+ Every file-backed run writes `corpus.manifest.json` with stable document IDs,
255
+ chunk IDs, hashes, output paths, and chunk counts. See
256
+ [Corpus Manifest](docs/corpus-manifest.md).
257
+
258
+ ## Profiles
259
+
260
+ ```bash
261
+ docpull https://site.com --profile rag # Default. Dedup + metadata.
262
+ docpull https://site.com --profile llm # NDJSON chunks for agents/RAG.
263
+ docpull https://site.com --profile okf # Portable Open Knowledge Format bundle.
264
+ docpull https://site.com --profile mirror # Cached archive.
265
+ docpull https://site.com --profile quick # Small sampling crawl.
266
+ docpull https://site.com --profile sec-filing # EDGAR-friendly evidence chunks.
267
+ ```
268
+
269
+ Run `docpull --help` for the full option list.
270
+
271
+ ## When Not to Use docpull
272
+
273
+ docpull intentionally does not use a browser. It is not the right tool for:
274
+
275
+ - JS-only pages that require client-side rendering.
276
+ - Authenticated dashboards or private apps.
277
+ - Pages behind CAPTCHA or bot challenges.
278
+ - Workflows that require clicking, scrolling, or browser state.
279
+
280
+ For those cases, use browser automation, such as Playwright, then pass the
281
+ rendered HTML or exported content into your pipeline.
282
+
283
+ ## How It Compares
284
+
285
+ | Tool type | Best for | Tradeoff |
286
+ | --- | --- | --- |
287
+ | `wget` / site mirroring | Downloading raw files | Not agent/RAG-oriented |
288
+ | Browser automation | JS-heavy pages and interactions | Slower, heavier, more stateful |
289
+ | Hosted extraction APIs | Managed extraction at scale | External dependency and cost |
290
+ | docpull | Local public-doc extraction and context packs | No JavaScript rendering |
291
+
292
+ ## Python SDK
293
+
294
+ ```python
295
+ from docpull import fetch_one
296
+
297
+ ctx = fetch_one("https://docs.python.org/3/library/asyncio.html")
298
+ print(ctx.title)
299
+ print(ctx.markdown[:500])
300
+ ```
301
+
302
+ ```python
303
+ import asyncio
304
+ from docpull import Fetcher, DocpullConfig, EventType, ProfileName
305
+
306
+ async def main():
307
+ cfg = DocpullConfig(url="https://docs.example.com", profile=ProfileName.LLM)
308
+ async with Fetcher(cfg) as fetcher:
309
+ async for event in fetcher.run():
310
+ if event.type == EventType.FETCH_PROGRESS:
311
+ print(f"{event.current}/{event.total}: {event.url}")
312
+
313
+ asyncio.run(main())
314
+ ```
315
+
316
+ ## MCP Server
317
+
318
+ docpull can run as a stdio MCP server for agent clients:
319
+
320
+ ```bash
321
+ pip install 'docpull[mcp]'
322
+ docpull mcp
323
+ ```
324
+
325
+ Claude Code:
326
+
327
+ ```bash
328
+ claude mcp add --transport stdio docpull -- docpull mcp
329
+ ```
330
+
331
+ Cursor and Claude Desktop use the same `mcpServers` shape:
332
+
333
+ ```json
334
+ {
335
+ "mcpServers": {
336
+ "docpull": {
337
+ "type": "stdio",
338
+ "command": "docpull",
339
+ "args": ["mcp"]
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ The supported MCP path is the Python stdio server started by `docpull mcp`.
346
+ The repository's `mcp/` directory is an internal TypeScript/Bun lab and is not
347
+ part of the package release contract.
348
+
349
+ ## Advanced Workflows
350
+
351
+ - `docpull[parallel]` can discover, extract, enrich, score, diff, and archive
352
+ live web sources with your own Parallel API key. See
353
+ [Parallel Integration](docs/parallel.md).
354
+ - Optional provider workflows can use Parallel, Tavily, and Exa when configured.
355
+ See [CLI Recipes](docs/examples/README.md#parallel-context-pack).
356
+ - SEC filing evidence packs use rule profiles such as
357
+ [vendor-dependency-rules.yml](docs/examples/vendor-dependency-rules.yml).
358
+
359
+ ## Security Defaults
360
+
361
+ - HTTPS-only fetching with robots.txt compliance.
362
+ - SSRF protections, private network blocking, DNS rebinding protection, and
363
+ connect-time address pinning.
364
+ - XXE protection for sitemaps.
365
+ - Path traversal and CRLF header injection guards.
366
+ - Auth headers stripped on cross-origin redirects.
367
+
368
+ When running with `--proxy`, DNS pinning is delegated to the proxy. Pass
369
+ `--require-pinned-dns` to refuse that configuration.
370
+
371
+ ## Troubleshooting
372
+
373
+ ```bash
374
+ docpull --doctor
375
+ docpull URL --verbose
376
+ docpull URL --dry-run
377
+ docpull URL --preview-urls
378
+ ```
379
+
380
+ ## Documentation
381
+
382
+ - [CLI Recipes](docs/examples/README.md) - common commands and advanced workflows.
383
+ - [Scraping Boundary](docs/scraping-boundary.md) - what docpull does and does not fetch.
384
+ - [Alternatives](docs/alternatives.md) - when to use browser automation or hosted extraction.
385
+ - [Corpus Manifest](docs/corpus-manifest.md) - stable IDs, hashes, and source maps.
386
+ - [Parallel Integration](docs/parallel.md) - live-source context pack workflows.
387
+ - [Changelog](docs/CHANGELOG.md) - release history.
388
+
389
+ ## Links
390
+
391
+ - [Website](https://docpull.raintree.technology)
392
+ - [PyPI](https://pypi.org/project/docpull/)
393
+ - [GitHub](https://github.com/raintree-technology/docpull)
394
+ - [Metrics](METRICS.md)
395
+
396
+ ## License
397
+
398
+ MIT
@@ -0,0 +1,298 @@
1
+ # docpull
2
+
3
+ **Turn public documentation sites into local Markdown, NDJSON, and agent-ready context packs. No browser required.**
4
+
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
6
+ [![PyPI version](https://badge.fury.io/py/docpull.svg)](https://badge.fury.io/py/docpull)
7
+ [![PyPI downloads](https://img.shields.io/pepy/dt/docpull?label=downloads)](https://pepy.tech/project/docpull)
8
+ [![GitHub stars](https://img.shields.io/github/stars/raintree-technology/docpull?style=social)](https://github.com/raintree-technology/docpull/stargazers)
9
+ [![License: MIT](https://img.shields.io/github/license/raintree-technology/docpull)](https://github.com/raintree-technology/docpull/blob/main/LICENSE)
10
+
11
+ docpull is a Python CLI, SDK, and MCP server that fetches public static or
12
+ server-rendered web pages and converts them into clean, auditable local
13
+ artifacts for LLMs, retrieval-augmented generation (RAG), offline research, and
14
+ agent workflows.
15
+
16
+ It works best on documentation sites, blogs, API references, OpenAPI specs,
17
+ vendor pages, and other public pages where the useful content is available in
18
+ HTML or embedded page data.
19
+
20
+ docpull is not a browser and does not render JavaScript. JS-only pages are
21
+ skipped with a clear reason. See [Scraping Boundary](docs/scraping-boundary.md)
22
+ and [Alternatives](docs/alternatives.md) for the full boundary.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install docpull
28
+ ```
29
+
30
+ Install optional extras as needed:
31
+
32
+ ```bash
33
+ pip install 'docpull[llm]' # tiktoken for token-accurate chunking
34
+ pip install 'docpull[trafilatura]' # alternative extractor for noisy pages
35
+ pip install 'docpull[mcp]' # stdio MCP server
36
+ pip install 'docpull[parallel]' # Parallel context packs
37
+ pip install 'docpull[observability]' # Raindrop benchmark tracing
38
+ pip install 'docpull[all]' # all optional extras
39
+ ```
40
+
41
+ ## 30-Second Usage
42
+
43
+ ```bash
44
+ docpull https://docs.python.org/3/library/asyncio.html --single -o ./asyncio-docs
45
+ ```
46
+
47
+ Example output:
48
+
49
+ ```text
50
+ asyncio-docs/
51
+ index.md
52
+ corpus.manifest.json
53
+ ```
54
+
55
+ Markdown includes source metadata and readable page content:
56
+
57
+ ```markdown
58
+ ---
59
+ title: "asyncio - Asynchronous I/O"
60
+ source: https://docs.python.org/3/library/asyncio.html
61
+ source_type: "sphinx"
62
+ ---
63
+
64
+ # asyncio - Asynchronous I/O
65
+
66
+ asyncio is a library to write concurrent code using the async/await syntax.
67
+ ```
68
+
69
+ Stream chunked NDJSON for agents and RAG:
70
+
71
+ ```bash
72
+ docpull https://docs.python.org/3/library/asyncio.html \
73
+ --single \
74
+ --profile llm \
75
+ --stream | jq .
76
+ ```
77
+
78
+ Each line is a JSON document:
79
+
80
+ ```json
81
+ {"schema_version":1,"document_id":"doc_...","chunk_id":"chunk_...","url":"https://docs.python.org/3/library/asyncio.html","title":"asyncio - Asynchronous I/O","content":"asyncio is a library to write concurrent code...","source_type":"sphinx","chunk_index":0,"token_count":842}
82
+ ```
83
+
84
+ ## Common Workflows
85
+
86
+ ```bash
87
+ # Crawl a site and write Markdown files
88
+ docpull https://docs.example.com -o ./docs-example
89
+
90
+ # Stream LLM-ready NDJSON chunks from a site
91
+ docpull https://docs.example.com --profile llm --stream | jq .
92
+
93
+ # Write SQLite with an FTS5 search index
94
+ docpull https://docs.example.com --format sqlite -o ./docs-db
95
+
96
+ # Build an Open Knowledge Format (OKF) bundle for portable source packs
97
+ docpull https://example.com --profile okf -o ./site-okf
98
+ ```
99
+
100
+ More examples live in [CLI Recipes](docs/examples/README.md).
101
+
102
+ Use docpull when you need to:
103
+
104
+ - Convert public docs, blogs, API references, vendor pages, and OpenAPI specs
105
+ into Markdown or chunked NDJSON for LLM and RAG pipelines.
106
+ - Give an agent a local tool for fetching, caching, grepping, and reading web
107
+ sources.
108
+ - Build repeatable context packs with stable IDs, hashes, manifests, and source
109
+ metadata.
110
+ - Mirror public web content for offline work while preserving attribution.
111
+
112
+ ## Why docpull?
113
+
114
+ docpull is designed for agent and RAG workflows, not just downloading pages.
115
+
116
+ | Need | docpull gives you |
117
+ | --- | --- |
118
+ | Clean Markdown | Article-focused extraction with source metadata |
119
+ | LLM chunks | NDJSON streaming and optional token-aware chunking |
120
+ | Repeatability | Stable document IDs, chunk IDs, hashes, and manifests |
121
+ | Offline work | Cached archives and mirrored source artifacts |
122
+ | Agent access | Local CLI, Python SDK, and stdio MCP server |
123
+ | Safer fetching | HTTPS defaults, robots.txt compliance, SSRF protections, and redirect guards |
124
+
125
+ ## Supported Sources
126
+
127
+ docpull uses async HTTP instead of browser automation and includes special
128
+ handling for common documentation and API surfaces.
129
+
130
+ | Source shape | Support |
131
+ | --- | --- |
132
+ | Static HTML / SSR docs | Extracts article or document regions |
133
+ | Next.js / Mintlify | Parses static HTML and `__NEXT_DATA__` when available |
134
+ | OpenAPI / Swagger | Renders specs into Markdown |
135
+ | Docusaurus / Sphinx / MkDocs | Extracts static article or document regions |
136
+ | VitePress / VuePress / Astro Starlight | Extracts static docs content |
137
+ | GitBook / ReadMe.io | Extracts available article or content regions |
138
+ | Redoc / Scalar | Extracts static API reference regions |
139
+ | JS-only apps | Skipped unless useful content is present in HTML or embedded data |
140
+
141
+ Use `--strict-js-required` when an agent should treat JS-only pages as hard
142
+ errors instead of normal skips.
143
+
144
+ ## Output Formats
145
+
146
+ | Output | Use it for |
147
+ | --- | --- |
148
+ | Markdown | Local readable source snapshots with YAML frontmatter |
149
+ | NDJSON | Streamed records or chunked records for agents and RAG |
150
+ | SQLite | Local retrieval with an FTS5 index |
151
+ | OKF | Portable Open Knowledge Format bundles with indexes and manifests |
152
+ | Archive / mirror | Cached offline source snapshots |
153
+
154
+ Every file-backed run writes `corpus.manifest.json` with stable document IDs,
155
+ chunk IDs, hashes, output paths, and chunk counts. See
156
+ [Corpus Manifest](docs/corpus-manifest.md).
157
+
158
+ ## Profiles
159
+
160
+ ```bash
161
+ docpull https://site.com --profile rag # Default. Dedup + metadata.
162
+ docpull https://site.com --profile llm # NDJSON chunks for agents/RAG.
163
+ docpull https://site.com --profile okf # Portable Open Knowledge Format bundle.
164
+ docpull https://site.com --profile mirror # Cached archive.
165
+ docpull https://site.com --profile quick # Small sampling crawl.
166
+ docpull https://site.com --profile sec-filing # EDGAR-friendly evidence chunks.
167
+ ```
168
+
169
+ Run `docpull --help` for the full option list.
170
+
171
+ ## When Not to Use docpull
172
+
173
+ docpull intentionally does not use a browser. It is not the right tool for:
174
+
175
+ - JS-only pages that require client-side rendering.
176
+ - Authenticated dashboards or private apps.
177
+ - Pages behind CAPTCHA or bot challenges.
178
+ - Workflows that require clicking, scrolling, or browser state.
179
+
180
+ For those cases, use browser automation, such as Playwright, then pass the
181
+ rendered HTML or exported content into your pipeline.
182
+
183
+ ## How It Compares
184
+
185
+ | Tool type | Best for | Tradeoff |
186
+ | --- | --- | --- |
187
+ | `wget` / site mirroring | Downloading raw files | Not agent/RAG-oriented |
188
+ | Browser automation | JS-heavy pages and interactions | Slower, heavier, more stateful |
189
+ | Hosted extraction APIs | Managed extraction at scale | External dependency and cost |
190
+ | docpull | Local public-doc extraction and context packs | No JavaScript rendering |
191
+
192
+ ## Python SDK
193
+
194
+ ```python
195
+ from docpull import fetch_one
196
+
197
+ ctx = fetch_one("https://docs.python.org/3/library/asyncio.html")
198
+ print(ctx.title)
199
+ print(ctx.markdown[:500])
200
+ ```
201
+
202
+ ```python
203
+ import asyncio
204
+ from docpull import Fetcher, DocpullConfig, EventType, ProfileName
205
+
206
+ async def main():
207
+ cfg = DocpullConfig(url="https://docs.example.com", profile=ProfileName.LLM)
208
+ async with Fetcher(cfg) as fetcher:
209
+ async for event in fetcher.run():
210
+ if event.type == EventType.FETCH_PROGRESS:
211
+ print(f"{event.current}/{event.total}: {event.url}")
212
+
213
+ asyncio.run(main())
214
+ ```
215
+
216
+ ## MCP Server
217
+
218
+ docpull can run as a stdio MCP server for agent clients:
219
+
220
+ ```bash
221
+ pip install 'docpull[mcp]'
222
+ docpull mcp
223
+ ```
224
+
225
+ Claude Code:
226
+
227
+ ```bash
228
+ claude mcp add --transport stdio docpull -- docpull mcp
229
+ ```
230
+
231
+ Cursor and Claude Desktop use the same `mcpServers` shape:
232
+
233
+ ```json
234
+ {
235
+ "mcpServers": {
236
+ "docpull": {
237
+ "type": "stdio",
238
+ "command": "docpull",
239
+ "args": ["mcp"]
240
+ }
241
+ }
242
+ }
243
+ ```
244
+
245
+ The supported MCP path is the Python stdio server started by `docpull mcp`.
246
+ The repository's `mcp/` directory is an internal TypeScript/Bun lab and is not
247
+ part of the package release contract.
248
+
249
+ ## Advanced Workflows
250
+
251
+ - `docpull[parallel]` can discover, extract, enrich, score, diff, and archive
252
+ live web sources with your own Parallel API key. See
253
+ [Parallel Integration](docs/parallel.md).
254
+ - Optional provider workflows can use Parallel, Tavily, and Exa when configured.
255
+ See [CLI Recipes](docs/examples/README.md#parallel-context-pack).
256
+ - SEC filing evidence packs use rule profiles such as
257
+ [vendor-dependency-rules.yml](docs/examples/vendor-dependency-rules.yml).
258
+
259
+ ## Security Defaults
260
+
261
+ - HTTPS-only fetching with robots.txt compliance.
262
+ - SSRF protections, private network blocking, DNS rebinding protection, and
263
+ connect-time address pinning.
264
+ - XXE protection for sitemaps.
265
+ - Path traversal and CRLF header injection guards.
266
+ - Auth headers stripped on cross-origin redirects.
267
+
268
+ When running with `--proxy`, DNS pinning is delegated to the proxy. Pass
269
+ `--require-pinned-dns` to refuse that configuration.
270
+
271
+ ## Troubleshooting
272
+
273
+ ```bash
274
+ docpull --doctor
275
+ docpull URL --verbose
276
+ docpull URL --dry-run
277
+ docpull URL --preview-urls
278
+ ```
279
+
280
+ ## Documentation
281
+
282
+ - [CLI Recipes](docs/examples/README.md) - common commands and advanced workflows.
283
+ - [Scraping Boundary](docs/scraping-boundary.md) - what docpull does and does not fetch.
284
+ - [Alternatives](docs/alternatives.md) - when to use browser automation or hosted extraction.
285
+ - [Corpus Manifest](docs/corpus-manifest.md) - stable IDs, hashes, and source maps.
286
+ - [Parallel Integration](docs/parallel.md) - live-source context pack workflows.
287
+ - [Changelog](docs/CHANGELOG.md) - release history.
288
+
289
+ ## Links
290
+
291
+ - [Website](https://docpull.raintree.technology)
292
+ - [PyPI](https://pypi.org/project/docpull/)
293
+ - [GitHub](https://github.com/raintree-technology/docpull)
294
+ - [Metrics](METRICS.md)
295
+
296
+ ## License
297
+
298
+ MIT