context-linter 2.0.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 (178) hide show
  1. context_linter-2.0.1/LICENSE +21 -0
  2. context_linter-2.0.1/PKG-INFO +423 -0
  3. context_linter-2.0.1/README.md +380 -0
  4. context_linter-2.0.1/pyproject.toml +98 -0
  5. context_linter-2.0.1/setup.cfg +4 -0
  6. context_linter-2.0.1/src/context_cli/__init__.py +8 -0
  7. context_linter-2.0.1/src/context_cli/cli/__init__.py +1 -0
  8. context_linter-2.0.1/src/context_cli/cli/audit.py +590 -0
  9. context_linter-2.0.1/src/context_cli/cli/benchmark.py +145 -0
  10. context_linter-2.0.1/src/context_cli/cli/compare.py +35 -0
  11. context_linter-2.0.1/src/context_cli/cli/generate.py +152 -0
  12. context_linter-2.0.1/src/context_cli/cli/history.py +82 -0
  13. context_linter-2.0.1/src/context_cli/cli/leaderboard.py +124 -0
  14. context_linter-2.0.1/src/context_cli/cli/mcp_cmd.py +16 -0
  15. context_linter-2.0.1/src/context_cli/cli/radar.py +72 -0
  16. context_linter-2.0.1/src/context_cli/cli/retail.py +97 -0
  17. context_linter-2.0.1/src/context_cli/cli/watch.py +130 -0
  18. context_linter-2.0.1/src/context_cli/core/__init__.py +0 -0
  19. context_linter-2.0.1/src/context_cli/core/auditor.py +406 -0
  20. context_linter-2.0.1/src/context_cli/core/batch.py +107 -0
  21. context_linter-2.0.1/src/context_cli/core/benchmark/__init__.py +12 -0
  22. context_linter-2.0.1/src/context_cli/core/benchmark/cost.py +58 -0
  23. context_linter-2.0.1/src/context_cli/core/benchmark/dispatcher.py +76 -0
  24. context_linter-2.0.1/src/context_cli/core/benchmark/judge.py +90 -0
  25. context_linter-2.0.1/src/context_cli/core/benchmark/loader.py +84 -0
  26. context_linter-2.0.1/src/context_cli/core/benchmark/metrics.py +103 -0
  27. context_linter-2.0.1/src/context_cli/core/cache.py +34 -0
  28. context_linter-2.0.1/src/context_cli/core/checks/__init__.py +21 -0
  29. context_linter-2.0.1/src/context_cli/core/checks/content.py +128 -0
  30. context_linter-2.0.1/src/context_cli/core/checks/content_usage.py +66 -0
  31. context_linter-2.0.1/src/context_cli/core/checks/eeat.py +183 -0
  32. context_linter-2.0.1/src/context_cli/core/checks/llms_txt.py +58 -0
  33. context_linter-2.0.1/src/context_cli/core/checks/robots.py +77 -0
  34. context_linter-2.0.1/src/context_cli/core/checks/rsl.py +96 -0
  35. context_linter-2.0.1/src/context_cli/core/checks/schema.py +42 -0
  36. context_linter-2.0.1/src/context_cli/core/ci/__init__.py +1 -0
  37. context_linter-2.0.1/src/context_cli/core/ci/baseline.py +133 -0
  38. context_linter-2.0.1/src/context_cli/core/ci/thresholds.py +73 -0
  39. context_linter-2.0.1/src/context_cli/core/compare.py +73 -0
  40. context_linter-2.0.1/src/context_cli/core/config.py +58 -0
  41. context_linter-2.0.1/src/context_cli/core/cost.py +42 -0
  42. context_linter-2.0.1/src/context_cli/core/crawler.py +188 -0
  43. context_linter-2.0.1/src/context_cli/core/discovery.py +251 -0
  44. context_linter-2.0.1/src/context_cli/core/generate/__init__.py +17 -0
  45. context_linter-2.0.1/src/context_cli/core/generate/batch.py +90 -0
  46. context_linter-2.0.1/src/context_cli/core/generate/compiler.py +133 -0
  47. context_linter-2.0.1/src/context_cli/core/generate/llm.py +23 -0
  48. context_linter-2.0.1/src/context_cli/core/generate/profiles.py +85 -0
  49. context_linter-2.0.1/src/context_cli/core/generate/prompts.py +108 -0
  50. context_linter-2.0.1/src/context_cli/core/history.py +117 -0
  51. context_linter-2.0.1/src/context_cli/core/llm.py +135 -0
  52. context_linter-2.0.1/src/context_cli/core/models.py +977 -0
  53. context_linter-2.0.1/src/context_cli/core/plugin.py +109 -0
  54. context_linter-2.0.1/src/context_cli/core/radar/__init__.py +22 -0
  55. context_linter-2.0.1/src/context_cli/core/radar/analyzer.py +185 -0
  56. context_linter-2.0.1/src/context_cli/core/radar/domains.py +81 -0
  57. context_linter-2.0.1/src/context_cli/core/radar/parser.py +124 -0
  58. context_linter-2.0.1/src/context_cli/core/radar/query.py +73 -0
  59. context_linter-2.0.1/src/context_cli/core/recommend.py +234 -0
  60. context_linter-2.0.1/src/context_cli/core/regression.py +81 -0
  61. context_linter-2.0.1/src/context_cli/core/retail/__init__.py +5 -0
  62. context_linter-2.0.1/src/context_cli/core/retail/auditor.py +74 -0
  63. context_linter-2.0.1/src/context_cli/core/retail/feed_spec.py +100 -0
  64. context_linter-2.0.1/src/context_cli/core/retail/parsers/__init__.py +83 -0
  65. context_linter-2.0.1/src/context_cli/core/retail/parsers/amazon.py +198 -0
  66. context_linter-2.0.1/src/context_cli/core/retail/parsers/base.py +47 -0
  67. context_linter-2.0.1/src/context_cli/core/retail/parsers/blibli.py +195 -0
  68. context_linter-2.0.1/src/context_cli/core/retail/parsers/generic.py +228 -0
  69. context_linter-2.0.1/src/context_cli/core/retail/parsers/lazada.py +137 -0
  70. context_linter-2.0.1/src/context_cli/core/retail/parsers/shopee.py +147 -0
  71. context_linter-2.0.1/src/context_cli/core/retail/parsers/tiktok_shop.py +193 -0
  72. context_linter-2.0.1/src/context_cli/core/retail/parsers/tokopedia.py +146 -0
  73. context_linter-2.0.1/src/context_cli/core/retail/parsers/zalora.py +199 -0
  74. context_linter-2.0.1/src/context_cli/core/retail/scoring.py +262 -0
  75. context_linter-2.0.1/src/context_cli/core/retry.py +78 -0
  76. context_linter-2.0.1/src/context_cli/core/scoring.py +256 -0
  77. context_linter-2.0.1/src/context_cli/core/webhook.py +42 -0
  78. context_linter-2.0.1/src/context_cli/formatters/__init__.py +1 -0
  79. context_linter-2.0.1/src/context_cli/formatters/ci_summary.py +122 -0
  80. context_linter-2.0.1/src/context_cli/formatters/compare.py +94 -0
  81. context_linter-2.0.1/src/context_cli/formatters/csv.py +88 -0
  82. context_linter-2.0.1/src/context_cli/formatters/html.py +300 -0
  83. context_linter-2.0.1/src/context_cli/formatters/leaderboard.py +130 -0
  84. context_linter-2.0.1/src/context_cli/formatters/markdown.py +132 -0
  85. context_linter-2.0.1/src/context_cli/formatters/recommendations.py +106 -0
  86. context_linter-2.0.1/src/context_cli/formatters/rich_output.py +198 -0
  87. context_linter-2.0.1/src/context_cli/formatters/verbose.py +206 -0
  88. context_linter-2.0.1/src/context_cli/formatters/verbose_panels.py +414 -0
  89. context_linter-2.0.1/src/context_cli/main.py +30 -0
  90. context_linter-2.0.1/src/context_cli/py.typed +0 -0
  91. context_linter-2.0.1/src/context_cli/server.py +219 -0
  92. context_linter-2.0.1/src/context_linter.egg-info/PKG-INFO +423 -0
  93. context_linter-2.0.1/src/context_linter.egg-info/SOURCES.txt +176 -0
  94. context_linter-2.0.1/src/context_linter.egg-info/dependency_links.txt +1 -0
  95. context_linter-2.0.1/src/context_linter.egg-info/entry_points.txt +2 -0
  96. context_linter-2.0.1/src/context_linter.egg-info/requires.txt +20 -0
  97. context_linter-2.0.1/src/context_linter.egg-info/top_level.txt +1 -0
  98. context_linter-2.0.1/tests/test_answer_first.py +114 -0
  99. context_linter-2.0.1/tests/test_auditor.py +250 -0
  100. context_linter-2.0.1/tests/test_auditor_coverage.py +514 -0
  101. context_linter-2.0.1/tests/test_batch.py +465 -0
  102. context_linter-2.0.1/tests/test_benchmark_cli.py +476 -0
  103. context_linter-2.0.1/tests/test_benchmark_cost.py +235 -0
  104. context_linter-2.0.1/tests/test_benchmark_dispatcher.py +287 -0
  105. context_linter-2.0.1/tests/test_benchmark_judge.py +402 -0
  106. context_linter-2.0.1/tests/test_benchmark_loader.py +283 -0
  107. context_linter-2.0.1/tests/test_benchmark_metrics.py +335 -0
  108. context_linter-2.0.1/tests/test_cache.py +80 -0
  109. context_linter-2.0.1/tests/test_ci_baseline.py +756 -0
  110. context_linter-2.0.1/tests/test_ci_features.py +184 -0
  111. context_linter-2.0.1/tests/test_ci_summary.py +311 -0
  112. context_linter-2.0.1/tests/test_ci_thresholds.py +682 -0
  113. context_linter-2.0.1/tests/test_cli.py +140 -0
  114. context_linter-2.0.1/tests/test_cli_coverage.py +865 -0
  115. context_linter-2.0.1/tests/test_cli_errors.py +78 -0
  116. context_linter-2.0.1/tests/test_compare.py +462 -0
  117. context_linter-2.0.1/tests/test_config.py +232 -0
  118. context_linter-2.0.1/tests/test_content_boundaries.py +101 -0
  119. context_linter-2.0.1/tests/test_content_chunks.py +102 -0
  120. context_linter-2.0.1/tests/test_content_usage.py +141 -0
  121. context_linter-2.0.1/tests/test_crawler_coverage.py +221 -0
  122. context_linter-2.0.1/tests/test_crawler_errors.py +81 -0
  123. context_linter-2.0.1/tests/test_custom_bots.py +236 -0
  124. context_linter-2.0.1/tests/test_discovery.py +143 -0
  125. context_linter-2.0.1/tests/test_discovery_coverage.py +315 -0
  126. context_linter-2.0.1/tests/test_eeat.py +184 -0
  127. context_linter-2.0.1/tests/test_formatters.py +319 -0
  128. context_linter-2.0.1/tests/test_generate_batch.py +417 -0
  129. context_linter-2.0.1/tests/test_generate_batch_cli.py +373 -0
  130. context_linter-2.0.1/tests/test_generate_cli.py +161 -0
  131. context_linter-2.0.1/tests/test_generate_compiler.py +268 -0
  132. context_linter-2.0.1/tests/test_generate_llm.py +174 -0
  133. context_linter-2.0.1/tests/test_generate_models.py +164 -0
  134. context_linter-2.0.1/tests/test_generate_profiles.py +111 -0
  135. context_linter-2.0.1/tests/test_generate_prompts.py +135 -0
  136. context_linter-2.0.1/tests/test_github_summary.py +90 -0
  137. context_linter-2.0.1/tests/test_heading_structure.py +141 -0
  138. context_linter-2.0.1/tests/test_history.py +228 -0
  139. context_linter-2.0.1/tests/test_history_cli.py +177 -0
  140. context_linter-2.0.1/tests/test_html_report.py +488 -0
  141. context_linter-2.0.1/tests/test_leaderboard_cli.py +475 -0
  142. context_linter-2.0.1/tests/test_leaderboard_formatter.py +502 -0
  143. context_linter-2.0.1/tests/test_llms_txt_edge_cases.py +286 -0
  144. context_linter-2.0.1/tests/test_mcp_expansion.py +218 -0
  145. context_linter-2.0.1/tests/test_mcp_server.py +149 -0
  146. context_linter-2.0.1/tests/test_models.py +268 -0
  147. context_linter-2.0.1/tests/test_page_weight_edges.py +63 -0
  148. context_linter-2.0.1/tests/test_plugin.py +259 -0
  149. context_linter-2.0.1/tests/test_radar_analyzer.py +379 -0
  150. context_linter-2.0.1/tests/test_radar_cli.py +489 -0
  151. context_linter-2.0.1/tests/test_radar_domains.py +159 -0
  152. context_linter-2.0.1/tests/test_radar_parser.py +232 -0
  153. context_linter-2.0.1/tests/test_radar_query.py +186 -0
  154. context_linter-2.0.1/tests/test_readability.py +130 -0
  155. context_linter-2.0.1/tests/test_recommend.py +402 -0
  156. context_linter-2.0.1/tests/test_regression.py +160 -0
  157. context_linter-2.0.1/tests/test_retail_auditor.py +292 -0
  158. context_linter-2.0.1/tests/test_retail_cli.py +479 -0
  159. context_linter-2.0.1/tests/test_retail_feed_spec.py +189 -0
  160. context_linter-2.0.1/tests/test_retail_parsers.py +1010 -0
  161. context_linter-2.0.1/tests/test_retail_parsers2.py +1273 -0
  162. context_linter-2.0.1/tests/test_retail_scoring.py +617 -0
  163. context_linter-2.0.1/tests/test_retry.py +138 -0
  164. context_linter-2.0.1/tests/test_robots_edge_cases.py +100 -0
  165. context_linter-2.0.1/tests/test_rsl.py +152 -0
  166. context_linter-2.0.1/tests/test_save_flag.py +233 -0
  167. context_linter-2.0.1/tests/test_schema_edge_cases.py +105 -0
  168. context_linter-2.0.1/tests/test_schema_weighting.py +117 -0
  169. context_linter-2.0.1/tests/test_scoring_integration.py +158 -0
  170. context_linter-2.0.1/tests/test_scoring_lint.py +329 -0
  171. context_linter-2.0.1/tests/test_shared_llm.py +253 -0
  172. context_linter-2.0.1/tests/test_site_audit.py +192 -0
  173. context_linter-2.0.1/tests/test_sitemap_parsing.py +109 -0
  174. context_linter-2.0.1/tests/test_spider.py +124 -0
  175. context_linter-2.0.1/tests/test_timeout.py +318 -0
  176. context_linter-2.0.1/tests/test_verbose_output.py +1701 -0
  177. context_linter-2.0.1/tests/test_watch.py +254 -0
  178. context_linter-2.0.1/tests/test_webhook.py +377 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 AEO-CLI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,423 @@
1
+ Metadata-Version: 2.4
2
+ Name: context-linter
3
+ Version: 2.0.1
4
+ Summary: Context CLI — LLM Readiness Linter for token efficiency and RAG readiness
5
+ Author: Hansel Wahjono
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/hanselhansel/context-cli
8
+ Project-URL: Repository, https://github.com/hanselhansel/context-cli
9
+ Project-URL: Issues, https://github.com/hanselhansel/context-cli/issues
10
+ Keywords: llm,ai,linter,token-waste,rag,robots-txt,schema-org,llms-txt
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Internet :: WWW/HTTP
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: typer>=0.9
25
+ Requires-Dist: rich>=13.0
26
+ Requires-Dist: httpx>=0.27
27
+ Requires-Dist: beautifulsoup4>=4.12
28
+ Requires-Dist: pydantic>=2.0
29
+ Requires-Dist: crawl4ai>=0.4
30
+ Requires-Dist: fastmcp>=2.0
31
+ Requires-Dist: pyyaml>=6.0
32
+ Provides-Extra: generate
33
+ Requires-Dist: litellm>=1.40; extra == "generate"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8.0; extra == "dev"
36
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
37
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
38
+ Requires-Dist: mypy>=1.10; extra == "dev"
39
+ Requires-Dist: ruff>=0.4; extra == "dev"
40
+ Requires-Dist: litellm>=1.40; extra == "dev"
41
+ Requires-Dist: types-PyYAML>=6.0; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ # Context CLI
45
+
46
+ [![Tests](https://github.com/hanselhansel/context-cli/actions/workflows/test.yml/badge.svg)](https://github.com/hanselhansel/context-cli/actions/workflows/test.yml)
47
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
48
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
49
+ [![PyPI version](https://img.shields.io/pypi/v/context-cli.svg)](https://pypi.org/project/context-cli/)
50
+
51
+ **Lint any URL for LLM readiness. Get a 0-100 score for token efficiency, RAG readiness, and LLM extraction quality.**
52
+
53
+ ## What is Context CLI?
54
+
55
+ Context CLI is an LLM Readiness Linter that checks how well a URL is structured for AI consumption. As LLM-powered search engines, RAG pipelines, and AI agents become primary consumers of web content, your pages need to be optimized for token efficiency, structured data extraction, and machine-readable formatting.
56
+
57
+ Context CLI analyzes your content across four pillars and returns a structured score from 0 to 100.
58
+
59
+ ## Features
60
+
61
+ - **Robots.txt AI bot access** -- checks 13 AI crawlers (GPTBot, ClaudeBot, DeepSeek-AI, Grok, and more)
62
+ - **llms.txt & llms-full.txt** -- detects both standard and extended LLM instruction files
63
+ - **Schema.org JSON-LD** -- extracts and evaluates structured data with high-value type weighting (Product, Article, FAQ, HowTo)
64
+ - **Content density** -- measures useful content vs. boilerplate with readability scoring, heading structure analysis, and answer-first detection
65
+ - **Batch mode** -- lint multiple URLs from a file with `--file` and configurable `--concurrency`
66
+ - **Custom bot list** -- override default bots with `--bots` for targeted checks
67
+ - **Verbose output** -- detailed per-pillar breakdown with scoring explanations and recommendations
68
+ - **Rich CLI output** -- formatted tables and scores via Rich
69
+ - **JSON / CSV / Markdown output** -- machine-readable results for pipelines
70
+ - **MCP server** -- expose the linter as a tool for AI agents via FastMCP
71
+ - **Context Compiler** -- LLM-powered `llms.txt` and `schema.jsonld` generation, with batch mode for multiple URLs
72
+ - **CI/CD integration** -- `--fail-under` threshold, `--fail-on-blocked-bots`, per-pillar thresholds, baseline regression detection, GitHub Step Summary
73
+ - **GitHub Action** -- composite action for CI pipelines with baseline support
74
+ - **Citation Radar** -- query AI models to see what they cite and recommend, with brand tracking and domain classification
75
+ - **Share-of-Recommendation Benchmark** -- track how often AI models mention and recommend your brand vs competitors, with LLM-as-judge analysis
76
+
77
+ ## Installation
78
+
79
+ ```bash
80
+ pip install context-linter
81
+ ```
82
+
83
+ Context CLI uses a headless browser for content extraction. After installing, run:
84
+
85
+ ```bash
86
+ crawl4ai-setup
87
+ ```
88
+
89
+ ### Development install
90
+
91
+ ```bash
92
+ git clone https://github.com/your-org/context-cli.git
93
+ cd context-cli
94
+ pip install -e ".[dev]"
95
+ crawl4ai-setup
96
+ ```
97
+
98
+ ## Quick Start
99
+
100
+ ```bash
101
+ context-cli lint example.com
102
+ ```
103
+
104
+ This runs a full lint and prints a Rich-formatted report with your LLM readiness score.
105
+
106
+ ## CLI Usage
107
+
108
+ ### Single Page Lint
109
+
110
+ Lint only the specified URL (skip multi-page discovery):
111
+
112
+ ```bash
113
+ context-cli lint example.com --single
114
+ ```
115
+
116
+ ### Multi-Page Site Lint (default)
117
+
118
+ Discover pages via sitemap/spider and lint up to 10 pages:
119
+
120
+ ```bash
121
+ context-cli lint example.com
122
+ ```
123
+
124
+ ### Limit Pages
125
+
126
+ ```bash
127
+ context-cli lint example.com --max-pages 5
128
+ ```
129
+
130
+ ### JSON Output
131
+
132
+ Get structured JSON for CI pipelines, dashboards, or scripting:
133
+
134
+ ```bash
135
+ context-cli lint example.com --json
136
+ ```
137
+
138
+ ### CSV / Markdown Output
139
+
140
+ ```bash
141
+ context-cli lint example.com --format csv
142
+ context-cli lint example.com --format markdown
143
+ ```
144
+
145
+ ### Verbose Mode
146
+
147
+ Show detailed per-pillar breakdown with scoring explanations:
148
+
149
+ ```bash
150
+ context-cli lint example.com --single --verbose
151
+ ```
152
+
153
+ ### Timeout
154
+
155
+ Set the HTTP timeout (default: 15 seconds):
156
+
157
+ ```bash
158
+ context-cli lint example.com --timeout 30
159
+ ```
160
+
161
+ ### Custom Bot List
162
+
163
+ Override the default 13 bots with a custom list:
164
+
165
+ ```bash
166
+ context-cli lint example.com --bots "GPTBot,ClaudeBot,PerplexityBot"
167
+ ```
168
+
169
+ ### Batch Mode
170
+
171
+ Lint multiple URLs from a file (one URL per line, `.txt` or `.csv`):
172
+
173
+ ```bash
174
+ context-cli lint --file urls.txt
175
+ context-cli lint --file urls.txt --concurrency 5
176
+ context-cli lint --file urls.txt --format csv
177
+ ```
178
+
179
+ ### CI Mode
180
+
181
+ Fail the build if the score is below a threshold:
182
+
183
+ ```bash
184
+ context-cli lint example.com --fail-under 60
185
+ ```
186
+
187
+ Fail if any AI bot is blocked:
188
+
189
+ ```bash
190
+ context-cli lint example.com --fail-on-blocked-bots
191
+ ```
192
+
193
+ #### Per-Pillar Thresholds
194
+
195
+ Gate CI on individual pillar scores:
196
+
197
+ ```bash
198
+ context-cli lint example.com --robots-min 20 --content-min 30 --overall-min 60
199
+ ```
200
+
201
+ Available: `--robots-min`, `--schema-min`, `--content-min`, `--llms-min`, `--overall-min`.
202
+
203
+ #### Baseline Regression Detection
204
+
205
+ Save a baseline and detect score regressions in future lints:
206
+
207
+ ```bash
208
+ # Save current scores as baseline
209
+ context-cli lint example.com --single --save-baseline .context-baseline.json
210
+
211
+ # Compare against baseline (exit 1 if any pillar drops > 5 points)
212
+ context-cli lint example.com --single --baseline .context-baseline.json
213
+
214
+ # Custom regression threshold
215
+ context-cli lint example.com --single --baseline .context-baseline.json --regression-threshold 10
216
+ ```
217
+
218
+ Exit codes: 0 = pass, 1 = score below threshold or regression detected, 2 = bots blocked.
219
+
220
+ When running in GitHub Actions, a markdown summary is automatically written to `$GITHUB_STEP_SUMMARY`.
221
+
222
+ ### Quiet Mode
223
+
224
+ Suppress output, exit code 0 if score >= 50, 1 otherwise:
225
+
226
+ ```bash
227
+ context-cli lint example.com --quiet
228
+ ```
229
+
230
+ Use `--fail-under` with `--quiet` to override the default threshold:
231
+
232
+ ```bash
233
+ context-cli lint example.com --quiet --fail-under 70
234
+ ```
235
+
236
+ ### Start MCP server
237
+
238
+ ```bash
239
+ context-cli mcp
240
+ ```
241
+
242
+ Launches a FastMCP stdio server exposing the linter as a tool for AI agents.
243
+
244
+ ## MCP Integration
245
+
246
+ To use Context CLI as a tool in Claude Desktop, add this to your Claude Desktop config (`claude_desktop_config.json`):
247
+
248
+ ```json
249
+ {
250
+ "mcpServers": {
251
+ "context-cli": {
252
+ "command": "context-cli",
253
+ "args": ["mcp"]
254
+ }
255
+ }
256
+ }
257
+ ```
258
+
259
+ Once configured, Claude can call the `audit_url` tool directly to check any URL's LLM readiness.
260
+
261
+ ## Context Compiler (Generate)
262
+
263
+ Generate `llms.txt` and `schema.jsonld` files from any URL using LLM analysis:
264
+
265
+ ```bash
266
+ pip install context-linter[generate]
267
+ context-cli generate example.com
268
+ ```
269
+
270
+ This crawls the URL, sends the content to an LLM, and writes optimized files to `./context-output/`.
271
+
272
+ ### Batch Generate
273
+
274
+ Generate assets for multiple URLs from a file:
275
+
276
+ ```bash
277
+ context-cli generate-batch urls.txt
278
+ context-cli generate-batch urls.txt --concurrency 5 --profile ecommerce
279
+ context-cli generate-batch urls.txt --json
280
+ ```
281
+
282
+ Each URL's output goes to a subdirectory under `--output-dir`.
283
+
284
+ ### BYOK (Bring Your Own Key)
285
+
286
+ The generate command auto-detects your LLM provider from environment variables:
287
+
288
+ | Priority | Env Variable | Model Used |
289
+ |----------|-------------|------------|
290
+ | 1 | `OPENAI_API_KEY` | gpt-4o-mini |
291
+ | 2 | `ANTHROPIC_API_KEY` | claude-3-haiku-20240307 |
292
+ | 3 | Ollama running locally | ollama/llama3.2 |
293
+
294
+ Override with `--model`:
295
+
296
+ ```bash
297
+ context-cli generate example.com --model gpt-4o
298
+ ```
299
+
300
+ ### Industry Profiles
301
+
302
+ Tailor the output with `--profile`:
303
+
304
+ ```bash
305
+ context-cli generate example.com --profile saas
306
+ context-cli generate example.com --profile ecommerce
307
+ ```
308
+
309
+ Available: `generic`, `cpg`, `saas`, `ecommerce`, `blog`.
310
+
311
+ ## Citation Radar
312
+
313
+ Query AI models to see what they cite and recommend for any search prompt:
314
+
315
+ ```bash
316
+ pip install context-linter[generate]
317
+ context-cli radar "best project management tools" --brand Asana --brand Monday --model gpt-4o-mini
318
+ ```
319
+
320
+ Options:
321
+ - `--brand/-b`: Brand name to track (repeatable)
322
+ - `--model/-m`: LLM model to query (repeatable, default: gpt-4o-mini)
323
+ - `--runs/-r`: Runs per model for statistical significance
324
+ - `--json`: Output as JSON
325
+
326
+ ## Share-of-Recommendation Benchmark
327
+
328
+ Track how AI models mention and recommend your brand across multiple prompts:
329
+
330
+ ```bash
331
+ pip install context-linter[generate]
332
+ context-cli benchmark prompts.txt -b "YourBrand" -c "Competitor1" -c "Competitor2"
333
+ ```
334
+
335
+ Options:
336
+ - `prompts.txt`: CSV (with `prompt,category,intent` columns) or plain text (one prompt per line)
337
+ - `--brand/-b`: Target brand to track (required)
338
+ - `--competitor/-c`: Competitor brand (repeatable)
339
+ - `--model/-m`: LLM model to query (repeatable, default: gpt-4o-mini)
340
+ - `--runs/-r`: Runs per model per prompt (default: 3)
341
+ - `--yes/-y`: Skip cost confirmation prompt
342
+ - `--json`: Output as JSON
343
+
344
+ ## GitHub Action
345
+
346
+ Use Context CLI in your CI pipeline:
347
+
348
+ ```yaml
349
+ - name: Run Context Lint
350
+ uses: hanselhansel/context-cli@main
351
+ with:
352
+ url: 'https://your-site.com'
353
+ fail-under: '60'
354
+ ```
355
+
356
+ With baseline regression detection:
357
+
358
+ ```yaml
359
+ - name: Run Context Lint
360
+ uses: hanselhansel/context-cli@main
361
+ with:
362
+ url: 'https://your-site.com'
363
+ baseline-file: '.context-baseline.json'
364
+ save-baseline: '.context-baseline.json'
365
+ regression-threshold: '5'
366
+ ```
367
+
368
+ The action sets up Python, installs context-cli, and runs the lint. Outputs `score` and `report-json` for downstream steps. See [docs/ci-integration.md](docs/ci-integration.md) for full documentation.
369
+
370
+ ## Score Breakdown
371
+
372
+ Context CLI returns a score from 0 to 100, composed of four pillars:
373
+
374
+ | Pillar | Max Points | What it measures |
375
+ |---|---|---|
376
+ | Content density | 40 | Quality and depth of extractable text content |
377
+ | Robots.txt AI bot access | 25 | Whether AI crawlers are allowed in robots.txt |
378
+ | Schema.org JSON-LD | 25 | Structured data markup (Product, Article, FAQ, etc.) |
379
+ | llms.txt presence | 10 | Whether a /llms.txt file exists for LLM guidance |
380
+
381
+ ### Scoring rationale (2026-02-18)
382
+
383
+ The weights reflect how AI search engines (ChatGPT, Perplexity, Claude) actually consume web content:
384
+
385
+ - **Content density (40 pts)** is weighted highest because it's what LLMs extract and cite when answering questions. Rich, well-structured content with headings and lists gives AI better material to work with.
386
+ - **Robots.txt (25 pts)** is the gatekeeper -- if a bot is blocked, it literally cannot crawl. It's critical but largely binary (either you're blocking or you're not).
387
+ - **Schema.org (25 pts)** provides structured "cheat sheets" that help AI understand entities. High-value types (Product, Article, FAQ, HowTo, Recipe) receive bonus weighting. Valuable but not required for citation.
388
+ - **llms.txt (10 pts)** is an emerging standard. Both `/llms.txt` and `/llms-full.txt` are checked. No major AI search engine heavily weights it yet, but it signals forward-thinking AI readiness.
389
+
390
+ ## AI Bots Checked
391
+
392
+ Context CLI checks access rules for 13 AI crawlers:
393
+
394
+ - GPTBot
395
+ - ChatGPT-User
396
+ - Google-Extended
397
+ - ClaudeBot
398
+ - PerplexityBot
399
+ - Amazonbot
400
+ - OAI-SearchBot
401
+ - DeepSeek-AI
402
+ - Grok
403
+ - Meta-ExternalAgent
404
+ - cohere-ai
405
+ - AI2Bot
406
+ - ByteSpider
407
+
408
+ ## Development
409
+
410
+ ```bash
411
+ # Install with dev dependencies
412
+ pip install -e ".[dev]"
413
+
414
+ # Run tests
415
+ pytest
416
+
417
+ # Lint
418
+ ruff check src/ tests/
419
+ ```
420
+
421
+ ## License
422
+
423
+ MIT