sitemend 1.2.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.
- sitemend-1.2.1/LICENSE +21 -0
- sitemend-1.2.1/PKG-INFO +286 -0
- sitemend-1.2.1/README.md +265 -0
- sitemend-1.2.1/assets/dashboard.html +466 -0
- sitemend-1.2.1/pyproject.toml +44 -0
- sitemend-1.2.1/scripts/__init__.py +1 -0
- sitemend-1.2.1/scripts/audit.py +902 -0
- sitemend-1.2.1/scripts/build_dashboard.py +61 -0
- sitemend-1.2.1/scripts/crawl.py +644 -0
- sitemend-1.2.1/scripts/report.py +342 -0
- sitemend-1.2.1/scripts/schema_check.py +347 -0
- sitemend-1.2.1/scripts/seo_repair.py +110 -0
- sitemend-1.2.1/scripts/seolib.py +359 -0
- sitemend-1.2.1/scripts/verify.py +96 -0
- sitemend-1.2.1/scripts/vitals.py +205 -0
- sitemend-1.2.1/setup.cfg +4 -0
- sitemend-1.2.1/sitemend.egg-info/PKG-INFO +286 -0
- sitemend-1.2.1/sitemend.egg-info/SOURCES.txt +21 -0
- sitemend-1.2.1/sitemend.egg-info/dependency_links.txt +1 -0
- sitemend-1.2.1/sitemend.egg-info/entry_points.txt +2 -0
- sitemend-1.2.1/sitemend.egg-info/requires.txt +3 -0
- sitemend-1.2.1/sitemend.egg-info/top_level.txt +1 -0
- sitemend-1.2.1/tests/test_skill.py +1701 -0
sitemend-1.2.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 surendhar-v
|
|
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.
|
sitemend-1.2.1/PKG-INFO
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sitemend
|
|
3
|
+
Version: 1.2.1
|
|
4
|
+
Summary: Technical SEO audit and repair: crawls a site folder or live URL, finds indexing, duplicate-content, link, hreflang and schema problems, and never invents a number it did not measure.
|
|
5
|
+
Author: surendhar-v
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/SurendharVr/sitemend
|
|
8
|
+
Project-URL: Issues, https://github.com/SurendharVr/sitemend/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/SurendharVr/sitemend/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: seo,seo-audit,technical-seo,crawler,sitemap,structured-data,core-web-vitals,lighthouse,claude-code,claude-skill
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: beautifulsoup4>=4.9
|
|
18
|
+
Requires-Dist: lxml>=4.6
|
|
19
|
+
Requires-Dist: requests>=2.25
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# sitemend
|
|
23
|
+
|
|
24
|
+
[](https://github.com/SurendharVr/seo-repair/actions/workflows/tests.yml)
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
|
|
27
|
+
**Find the SEO problems Google actually penalises, then fix them in your code.**
|
|
28
|
+
|
|
29
|
+
Built for developers and site owners who keep their site in a codebase and want SEO
|
|
30
|
+
fixes as reviewable diffs, not a PDF of warnings. You approve every change before it's
|
|
31
|
+
applied.
|
|
32
|
+
|
|
33
|
+
A [Claude Code](https://claude.com/claude-code) skill: a site crawler and audit tool that finds indexing problems, orphan pages, duplicate
|
|
34
|
+
content, broken internal links, thin content, missing canonical tags, keyword
|
|
35
|
+
cannibalization and invalid schema markup — then proposes the fixes, applies the ones
|
|
36
|
+
you approve, and re-verifies with a second crawl.
|
|
37
|
+
|
|
38
|
+
`sitemend` is the PyPI package and command-line name. Inside Claude Code the skill and
|
|
39
|
+
plugin are still called `seo-repair`.
|
|
40
|
+
|
|
41
|
+
What makes it different from a checklist: **the order is enforced.** SEO findings are
|
|
42
|
+
not independent, so this treats them as a repair system with a dependency order.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Crawl → Index → Architecture → Content → On-Page → Performance → Schema → Authority → Monitor
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Work done out of order is wasted. Optimising a title on a page Google cannot index
|
|
49
|
+
changes nothing. Writing schema for a page about to be merged away is thrown out with
|
|
50
|
+
the page. Building links to either is the most expensive mistake of the three. Three
|
|
51
|
+
**gates** make that ordering unskippable rather than advisory.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## What a run looks like
|
|
56
|
+
|
|
57
|
+
Auditing the bundled demo site — the gate lines are the point, and they say *why*, not just *blocked*:
|
|
58
|
+
|
|
59
|
+
```console
|
|
60
|
+
$ python audit.py --crawl crawl.json --schema schema.json --out findings.json
|
|
61
|
+
24 findings: 1 critical, 7 high, 7 medium, 9 low
|
|
62
|
+
stage 1: 5
|
|
63
|
+
stage 2: 6
|
|
64
|
+
stage 3: 11
|
|
65
|
+
stage 5: 2
|
|
66
|
+
gate A (Index before content): CLEAR -- every crawled page is indexable
|
|
67
|
+
gate B (Architecture before schema): BLOCKED -- 3 page(s) orphaned or pending consolidation: /, /old-home.html, /reviews.html
|
|
68
|
+
gate C (Everything before authority): BLOCKED -- 8 critical/high finding(s) open in stages 1-5: S1-CANONICAL-CROSS, S1-PLACEHOLDER-DOMAIN, S1-SITEMAP-ORPHAN, S2-ORPHAN
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Each run also produces a self-contained HTML dashboard:
|
|
72
|
+
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
Note stage 04. Lighthouse was not run here, so Performance reads **not measured** rather
|
|
76
|
+
than *clear* — a stage that produced no findings because nobody looked at it is not a
|
|
77
|
+
stage that passed, and the dashboard will not imply otherwise.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Two things that make it different
|
|
82
|
+
|
|
83
|
+
**It refuses to invent numbers.** Search volume, keyword difficulty, backlink counts and
|
|
84
|
+
field Core Web Vitals cannot be observed from a codebase. They are never estimated —
|
|
85
|
+
they become a handoff list naming the exact Search Console or Ahrefs report to open.
|
|
86
|
+
Every claim in a report is tagged `MEASURED` (observed directly), `INFERRED` (reasoned
|
|
87
|
+
from observation, stated as such), or `HANDOFF` (not observable here). A local crawl
|
|
88
|
+
proves a page is *crawlable*; it never proves the page is *indexed*, and the report will
|
|
89
|
+
not blur those.
|
|
90
|
+
|
|
91
|
+
The same standard applies to what it writes: no invented author bios, testimonials,
|
|
92
|
+
ratings or trust claims. A tool that refuses to guess at keyword volume has no business
|
|
93
|
+
guessing at a person's credentials.
|
|
94
|
+
|
|
95
|
+
**It checks whether your structured data is honest.** Most validators check that schema
|
|
96
|
+
parses and has its required properties. This one also checks whether the markup asserts
|
|
97
|
+
things the page never shows — a rating nobody can see, an address that appears nowhere,
|
|
98
|
+
or review markup naming people the page does not mention. That last one is a Google
|
|
99
|
+
rich-results policy violation and a manual-action risk, and a property-checker will
|
|
100
|
+
never catch it.
|
|
101
|
+
|
|
102
|
+
## Versus asking for an SEO audit
|
|
103
|
+
|
|
104
|
+
The alternative to a tool like this is pasting a page into a chat and asking for an SEO
|
|
105
|
+
audit. That gives you advice. This gives you a crawl, with the differences that follow
|
|
106
|
+
from that:
|
|
107
|
+
|
|
108
|
+
| | A checklist prompt | seo-repair |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| **Coverage** | The pages you paste or open, one at a time | Every page, from a folder or a live URL (200 by default), plus `robots.txt` and `sitemap.xml` |
|
|
111
|
+
| **What it sees** | Text or markup you supply | Real status codes and redirects, canonicals, internal links, orphans, click depth |
|
|
112
|
+
| **Repeatable** | Wording and findings can differ run to run | Same site, same crawl, same findings. `verify` diffs a new run against a baseline |
|
|
113
|
+
| **Evidence** | Advice in prose | Each finding names the page and cites the offending string |
|
|
114
|
+
| **Order of work** | One flat list | Dependency order, with three gates enforced in code: no content work on pages Google cannot index, no schema on orphaned pages, no link building while critical findings are open |
|
|
115
|
+
| **Numbers it cannot measure** | Nothing in a prompt stops a plausible figure | Never stated. Volume, difficulty, backlinks and field Core Web Vitals become a handoff list naming the report to open |
|
|
116
|
+
| **Structured data** | Required properties, if it checks at all | Required properties, and whether the markup claims things the page never shows, such as review authors |
|
|
117
|
+
| **Applying fixes** | Suggestions | One approved batch at a time, then a re-crawl to confirm it worked. Nothing is edited without approval |
|
|
118
|
+
| **In CI** | No | `--fail-on` sets the exit code. An example GitHub Action is in `examples/` |
|
|
119
|
+
| **Tested** | Not testable | 146 tests, many pinned to false positives found on real runs |
|
|
120
|
+
|
|
121
|
+
**How big is the gap?** We measured it on the demo site (5 pages, 14 planted defects).
|
|
122
|
+
Three plain "audit this site" runs by an AI agent with read-only file access found 14, 12
|
|
123
|
+
and 13 of the defects, with one false alarm between them. seo-repair found all 14 with no
|
|
124
|
+
false alarms, gave identical findings on two runs, and took about 3 seconds without using
|
|
125
|
+
a language model. On a site this small a good prompt does well, and it noticed things
|
|
126
|
+
seo-repair does not check, such as a placeholder domain in the sitemap and missing Open
|
|
127
|
+
Graph tags. The advantage is repeatability, scale and CI, not a better score on five
|
|
128
|
+
pages. The demo was built around what seo-repair detects, and this was one model and three
|
|
129
|
+
runs, so read it as an example, not a benchmark.
|
|
130
|
+
|
|
131
|
+
A prompt is the better tool for work that needs the live search results: keyword
|
|
132
|
+
research, reading what the top-ranking pages cover, and writing or rewriting content.
|
|
133
|
+
seo-repair does not do that, and hands it off by design. Use them in that order: fix
|
|
134
|
+
what stops a page being crawled and indexed first, then decide what it should say.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Works with
|
|
139
|
+
|
|
140
|
+
- **Full workflow:** Claude Code (audit, plan, apply, verify).
|
|
141
|
+
- **Standalone:** one command, `sitemend audit <folder|URL>` (or
|
|
142
|
+
`python scripts/seo_repair.py audit ...` from a clone), runs the whole pipeline on
|
|
143
|
+
plain Python 3.9+. No agent needed. See below.
|
|
144
|
+
- **Tested on:** Linux, macOS and Windows. The Lighthouse step is verified on Windows only.
|
|
145
|
+
|
|
146
|
+
## Install
|
|
147
|
+
|
|
148
|
+
**As a plugin:**
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
/plugin marketplace add SurendharVr/seo-repair
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Or clone straight into your skills directory:**
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
git clone https://github.com/SurendharVr/seo-repair ~/.claude/skills/seo-repair
|
|
158
|
+
pip install -r ~/.claude/skills/seo-repair/requirements.txt
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Or as a command-line tool, without Claude Code:**
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
pip install git+https://github.com/SurendharVr/seo-repair
|
|
165
|
+
sitemend audit ./my-site
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
(The wheel is built and tested in CI on every push. `pip install sitemend` from PyPI
|
|
169
|
+
works once a release has been published; see [`RELEASING.md`](RELEASING.md).)
|
|
170
|
+
|
|
171
|
+
Requires Python 3.9+ with `beautifulsoup4`, `lxml` and `requests` (`pip` installs them;
|
|
172
|
+
from a clone, `requirements.txt` lists them). Core Web Vitals and `--render` additionally
|
|
173
|
+
need a local Chrome, Chromium or Edge; Core Web Vitals also need Node, via
|
|
174
|
+
`npx lighthouse`.
|
|
175
|
+
|
|
176
|
+
## Use it without an agent
|
|
177
|
+
|
|
178
|
+
One command audits a site folder or a live URL and writes a report and dashboard. It
|
|
179
|
+
edits nothing in the site.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
python scripts/seo_repair.py audit ./my-site # or https://example.com
|
|
183
|
+
python scripts/seo_repair.py audit ./my-site --fail-on high # exit 1 if a high/critical finding is open (CI gate)
|
|
184
|
+
python scripts/seo_repair.py verify ./my-site --baseline seo-repair-out/findings.json
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
To guard a site on every pull request, copy
|
|
188
|
+
[`examples/github-action/seo-repair.yml`](examples/github-action/seo-repair.yml) to
|
|
189
|
+
`.github/workflows/`. It fails the check when a critical finding is open and attaches
|
|
190
|
+
the report and dashboard to the run.
|
|
191
|
+
|
|
192
|
+
Output lands in `./seo-repair-out`: `findings.json`, `SEO-REPORT-<date>.md` and a
|
|
193
|
+
self-contained `dashboard.html`. Applying fixes stays a Claude Code job, because each
|
|
194
|
+
edit needs your approval.
|
|
195
|
+
|
|
196
|
+
## Try it on the demo site
|
|
197
|
+
|
|
198
|
+
The repo ships a small site with defects planted on purpose — an orphan duplicate, a
|
|
199
|
+
thin page, an oversized image behind `<picture>`, review markup for someone the page
|
|
200
|
+
never names, and more:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
cd scripts
|
|
204
|
+
python crawl.py --root ../examples/demo-site --out /tmp/crawl.json
|
|
205
|
+
python schema_check.py --crawl /tmp/crawl.json --out /tmp/schema.json
|
|
206
|
+
python audit.py --crawl /tmp/crawl.json --schema /tmp/schema.json --out /tmp/findings.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
[`examples/demo-site/EXPECTED.md`](examples/demo-site/EXPECTED.md) lists exactly what a
|
|
210
|
+
correct run reports — **and what it must stay silent about**, which is the harder half.
|
|
211
|
+
|
|
212
|
+
## Usage
|
|
213
|
+
|
|
214
|
+
Four verbs, driven through Claude Code:
|
|
215
|
+
|
|
216
|
+
| Verb | Does | Writes |
|
|
217
|
+
| --- | --- | --- |
|
|
218
|
+
| `seo-repair audit <path>` | Crawl → audit → report. Establishes the baseline. | report only |
|
|
219
|
+
| `seo-repair plan` | Ranks findings into stage-ordered batches, previews each diff | nothing |
|
|
220
|
+
| `seo-repair apply <batch>` | Applies **one approved batch**, re-checks that stage | source files |
|
|
221
|
+
| `seo-repair verify` | Re-crawl, diff vs. baseline, regression gate | report only |
|
|
222
|
+
|
|
223
|
+
Nothing is edited without approval. `plan` refuses to run without a baseline; `apply`
|
|
224
|
+
refuses without a named, approved batch.
|
|
225
|
+
|
|
226
|
+
## What it finds
|
|
227
|
+
|
|
228
|
+
| Stage | Checks |
|
|
229
|
+
| --- | --- |
|
|
230
|
+
| **Crawling & indexing** | `robots.txt` rules, XML sitemap coverage and contradictions, `noindex` directives, canonical tags (missing, cross-page, broken, off-origin), placeholder domains (example.com, localhost) in canonicals and the sitemap, broken internal links, URL hygiene, redirect chains and loops, mixed content, `hreflang` (invalid codes, broken targets, missing self and return tags), sitemap `<lastmod>` validity, response security headers, and client-rendered shells (`--render` compares raw HTML to the rendered DOM) |
|
|
231
|
+
| **Site architecture** | Orphan pages, unreachable pages, click depth, internal link distribution, heading structure, breadcrumbs |
|
|
232
|
+
| **Content & on-page** | Duplicate and near-duplicate content (MinHash), keyword cannibalization, thin content, title tags, meta descriptions, Open Graph tags, image alt text, oversized images, unused assets |
|
|
233
|
+
| **Core Web Vitals** | Lighthouse LCP, CLS and TBT — reported as *lab* metrics, with the localhost caveat stated |
|
|
234
|
+
| **Schema markup** | JSON-LD validity, required and recommended properties, and whether the markup's claims are corroborated by visible page text |
|
|
235
|
+
| **Authority / off-page** | Advisory only. It cannot measure a backlink profile and does not pretend to — it produces a human action list, and refuses paid-link and PBN tactics outright |
|
|
236
|
+
|
|
237
|
+
Findings cite the offending string from your source, so every one is checkable.
|
|
238
|
+
|
|
239
|
+
## Limitations, stated plainly
|
|
240
|
+
|
|
241
|
+
- **JS rendering is for live URLs.** `seo-repair audit https://... --render` parses
|
|
242
|
+
Chrome's post-JavaScript DOM with a local Chrome, Chromium or Edge, for up to 50 pages
|
|
243
|
+
(`--render-limit`, about 5 seconds each, one browser launch per page). A folder has no
|
|
244
|
+
running site to render, so fs mode only gets the static-shell hint `S1-JS-SHELL`. The
|
|
245
|
+
mobile-overflow check is still Claude Code only (it uses the built-in browser tools).
|
|
246
|
+
The render path is verified against real Chrome on Windows, and in CI on Ubuntu; the
|
|
247
|
+
opt-in test is `SEO_REPAIR_RENDER_TEST=1`. Chrome runs with its sandbox on; as root, or in a container
|
|
248
|
+
where it will not start, set SEO_REPAIR_NO_SANDBOX=1.
|
|
249
|
+
- **Redirect chains, response headers and rendering need an http crawl**, because a
|
|
250
|
+
folder on disk has none of them. Pagination (`rel=next/prev`) is not checked: Google
|
|
251
|
+
stopped using it.
|
|
252
|
+
- **Core Web Vitals need local Chrome.** These are lab numbers from your machine, not
|
|
253
|
+
field data. Real CWV comes from CrUX via Search Console, which is a handoff item.
|
|
254
|
+
- **`vitals.py` is verified on Windows only.** CI runs the test suite on Linux, macOS
|
|
255
|
+
and Windows, but excludes Lighthouse because it needs a browser — so that one script's
|
|
256
|
+
cross-platform behaviour is untested rather than proven. Reports welcome. One opt-in
|
|
257
|
+
test (`SEO_REPAIR_LIGHTHOUSE_TEST=1`) runs real Lighthouse against a local server.
|
|
258
|
+
- **Stage 6 does no off-page work.** By design.
|
|
259
|
+
- **The unused-asset check recommends deletion**, so it is deliberately conservative: a
|
|
260
|
+
filename appearing anywhere in any page's source counts as used. Verify before
|
|
261
|
+
deleting anyway — files can be referenced from a CMS or hot-linked externally.
|
|
262
|
+
|
|
263
|
+
## Tests
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
python tests/test_skill.py
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
146 tests (two are opt-in: real Lighthouse and real Chrome rendering), no fixture files — each builds a throwaway site in a temp directory. They pin
|
|
270
|
+
down calibration decisions made after real false positives: build-directory exclusion,
|
|
271
|
+
deliberate `noindex`, finding grouping, title thresholds, heading order, schema claim
|
|
272
|
+
corroboration, gate boundaries. A failure means *"was this behaviour meant to change"*,
|
|
273
|
+
not *"make it pass"*.
|
|
274
|
+
|
|
275
|
+
## Contributing
|
|
276
|
+
|
|
277
|
+
Bug reports and pull requests welcome, particularly on non-Windows platforms — the
|
|
278
|
+
Lighthouse integration is the least-tested part of this project.
|
|
279
|
+
|
|
280
|
+
If you change a rule, three things move together: the counts and defect table in
|
|
281
|
+
[`examples/demo-site/EXPECTED.md`](examples/demo-site/EXPECTED.md), and the `required`
|
|
282
|
+
finding ids in the CI workflow. [`RELEASING.md`](RELEASING.md) has the full checklist.
|
|
283
|
+
|
|
284
|
+
## License
|
|
285
|
+
|
|
286
|
+
MIT. See [LICENSE](LICENSE).
|
sitemend-1.2.1/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# sitemend
|
|
2
|
+
|
|
3
|
+
[](https://github.com/SurendharVr/seo-repair/actions/workflows/tests.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
**Find the SEO problems Google actually penalises, then fix them in your code.**
|
|
7
|
+
|
|
8
|
+
Built for developers and site owners who keep their site in a codebase and want SEO
|
|
9
|
+
fixes as reviewable diffs, not a PDF of warnings. You approve every change before it's
|
|
10
|
+
applied.
|
|
11
|
+
|
|
12
|
+
A [Claude Code](https://claude.com/claude-code) skill: a site crawler and audit tool that finds indexing problems, orphan pages, duplicate
|
|
13
|
+
content, broken internal links, thin content, missing canonical tags, keyword
|
|
14
|
+
cannibalization and invalid schema markup — then proposes the fixes, applies the ones
|
|
15
|
+
you approve, and re-verifies with a second crawl.
|
|
16
|
+
|
|
17
|
+
`sitemend` is the PyPI package and command-line name. Inside Claude Code the skill and
|
|
18
|
+
plugin are still called `seo-repair`.
|
|
19
|
+
|
|
20
|
+
What makes it different from a checklist: **the order is enforced.** SEO findings are
|
|
21
|
+
not independent, so this treats them as a repair system with a dependency order.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
Crawl → Index → Architecture → Content → On-Page → Performance → Schema → Authority → Monitor
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Work done out of order is wasted. Optimising a title on a page Google cannot index
|
|
28
|
+
changes nothing. Writing schema for a page about to be merged away is thrown out with
|
|
29
|
+
the page. Building links to either is the most expensive mistake of the three. Three
|
|
30
|
+
**gates** make that ordering unskippable rather than advisory.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## What a run looks like
|
|
35
|
+
|
|
36
|
+
Auditing the bundled demo site — the gate lines are the point, and they say *why*, not just *blocked*:
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
$ python audit.py --crawl crawl.json --schema schema.json --out findings.json
|
|
40
|
+
24 findings: 1 critical, 7 high, 7 medium, 9 low
|
|
41
|
+
stage 1: 5
|
|
42
|
+
stage 2: 6
|
|
43
|
+
stage 3: 11
|
|
44
|
+
stage 5: 2
|
|
45
|
+
gate A (Index before content): CLEAR -- every crawled page is indexable
|
|
46
|
+
gate B (Architecture before schema): BLOCKED -- 3 page(s) orphaned or pending consolidation: /, /old-home.html, /reviews.html
|
|
47
|
+
gate C (Everything before authority): BLOCKED -- 8 critical/high finding(s) open in stages 1-5: S1-CANONICAL-CROSS, S1-PLACEHOLDER-DOMAIN, S1-SITEMAP-ORPHAN, S2-ORPHAN
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Each run also produces a self-contained HTML dashboard:
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+
|
|
54
|
+
Note stage 04. Lighthouse was not run here, so Performance reads **not measured** rather
|
|
55
|
+
than *clear* — a stage that produced no findings because nobody looked at it is not a
|
|
56
|
+
stage that passed, and the dashboard will not imply otherwise.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Two things that make it different
|
|
61
|
+
|
|
62
|
+
**It refuses to invent numbers.** Search volume, keyword difficulty, backlink counts and
|
|
63
|
+
field Core Web Vitals cannot be observed from a codebase. They are never estimated —
|
|
64
|
+
they become a handoff list naming the exact Search Console or Ahrefs report to open.
|
|
65
|
+
Every claim in a report is tagged `MEASURED` (observed directly), `INFERRED` (reasoned
|
|
66
|
+
from observation, stated as such), or `HANDOFF` (not observable here). A local crawl
|
|
67
|
+
proves a page is *crawlable*; it never proves the page is *indexed*, and the report will
|
|
68
|
+
not blur those.
|
|
69
|
+
|
|
70
|
+
The same standard applies to what it writes: no invented author bios, testimonials,
|
|
71
|
+
ratings or trust claims. A tool that refuses to guess at keyword volume has no business
|
|
72
|
+
guessing at a person's credentials.
|
|
73
|
+
|
|
74
|
+
**It checks whether your structured data is honest.** Most validators check that schema
|
|
75
|
+
parses and has its required properties. This one also checks whether the markup asserts
|
|
76
|
+
things the page never shows — a rating nobody can see, an address that appears nowhere,
|
|
77
|
+
or review markup naming people the page does not mention. That last one is a Google
|
|
78
|
+
rich-results policy violation and a manual-action risk, and a property-checker will
|
|
79
|
+
never catch it.
|
|
80
|
+
|
|
81
|
+
## Versus asking for an SEO audit
|
|
82
|
+
|
|
83
|
+
The alternative to a tool like this is pasting a page into a chat and asking for an SEO
|
|
84
|
+
audit. That gives you advice. This gives you a crawl, with the differences that follow
|
|
85
|
+
from that:
|
|
86
|
+
|
|
87
|
+
| | A checklist prompt | seo-repair |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| **Coverage** | The pages you paste or open, one at a time | Every page, from a folder or a live URL (200 by default), plus `robots.txt` and `sitemap.xml` |
|
|
90
|
+
| **What it sees** | Text or markup you supply | Real status codes and redirects, canonicals, internal links, orphans, click depth |
|
|
91
|
+
| **Repeatable** | Wording and findings can differ run to run | Same site, same crawl, same findings. `verify` diffs a new run against a baseline |
|
|
92
|
+
| **Evidence** | Advice in prose | Each finding names the page and cites the offending string |
|
|
93
|
+
| **Order of work** | One flat list | Dependency order, with three gates enforced in code: no content work on pages Google cannot index, no schema on orphaned pages, no link building while critical findings are open |
|
|
94
|
+
| **Numbers it cannot measure** | Nothing in a prompt stops a plausible figure | Never stated. Volume, difficulty, backlinks and field Core Web Vitals become a handoff list naming the report to open |
|
|
95
|
+
| **Structured data** | Required properties, if it checks at all | Required properties, and whether the markup claims things the page never shows, such as review authors |
|
|
96
|
+
| **Applying fixes** | Suggestions | One approved batch at a time, then a re-crawl to confirm it worked. Nothing is edited without approval |
|
|
97
|
+
| **In CI** | No | `--fail-on` sets the exit code. An example GitHub Action is in `examples/` |
|
|
98
|
+
| **Tested** | Not testable | 146 tests, many pinned to false positives found on real runs |
|
|
99
|
+
|
|
100
|
+
**How big is the gap?** We measured it on the demo site (5 pages, 14 planted defects).
|
|
101
|
+
Three plain "audit this site" runs by an AI agent with read-only file access found 14, 12
|
|
102
|
+
and 13 of the defects, with one false alarm between them. seo-repair found all 14 with no
|
|
103
|
+
false alarms, gave identical findings on two runs, and took about 3 seconds without using
|
|
104
|
+
a language model. On a site this small a good prompt does well, and it noticed things
|
|
105
|
+
seo-repair does not check, such as a placeholder domain in the sitemap and missing Open
|
|
106
|
+
Graph tags. The advantage is repeatability, scale and CI, not a better score on five
|
|
107
|
+
pages. The demo was built around what seo-repair detects, and this was one model and three
|
|
108
|
+
runs, so read it as an example, not a benchmark.
|
|
109
|
+
|
|
110
|
+
A prompt is the better tool for work that needs the live search results: keyword
|
|
111
|
+
research, reading what the top-ranking pages cover, and writing or rewriting content.
|
|
112
|
+
seo-repair does not do that, and hands it off by design. Use them in that order: fix
|
|
113
|
+
what stops a page being crawled and indexed first, then decide what it should say.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Works with
|
|
118
|
+
|
|
119
|
+
- **Full workflow:** Claude Code (audit, plan, apply, verify).
|
|
120
|
+
- **Standalone:** one command, `sitemend audit <folder|URL>` (or
|
|
121
|
+
`python scripts/seo_repair.py audit ...` from a clone), runs the whole pipeline on
|
|
122
|
+
plain Python 3.9+. No agent needed. See below.
|
|
123
|
+
- **Tested on:** Linux, macOS and Windows. The Lighthouse step is verified on Windows only.
|
|
124
|
+
|
|
125
|
+
## Install
|
|
126
|
+
|
|
127
|
+
**As a plugin:**
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
/plugin marketplace add SurendharVr/seo-repair
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Or clone straight into your skills directory:**
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
git clone https://github.com/SurendharVr/seo-repair ~/.claude/skills/seo-repair
|
|
137
|
+
pip install -r ~/.claude/skills/seo-repair/requirements.txt
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Or as a command-line tool, without Claude Code:**
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
pip install git+https://github.com/SurendharVr/seo-repair
|
|
144
|
+
sitemend audit ./my-site
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
(The wheel is built and tested in CI on every push. `pip install sitemend` from PyPI
|
|
148
|
+
works once a release has been published; see [`RELEASING.md`](RELEASING.md).)
|
|
149
|
+
|
|
150
|
+
Requires Python 3.9+ with `beautifulsoup4`, `lxml` and `requests` (`pip` installs them;
|
|
151
|
+
from a clone, `requirements.txt` lists them). Core Web Vitals and `--render` additionally
|
|
152
|
+
need a local Chrome, Chromium or Edge; Core Web Vitals also need Node, via
|
|
153
|
+
`npx lighthouse`.
|
|
154
|
+
|
|
155
|
+
## Use it without an agent
|
|
156
|
+
|
|
157
|
+
One command audits a site folder or a live URL and writes a report and dashboard. It
|
|
158
|
+
edits nothing in the site.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
python scripts/seo_repair.py audit ./my-site # or https://example.com
|
|
162
|
+
python scripts/seo_repair.py audit ./my-site --fail-on high # exit 1 if a high/critical finding is open (CI gate)
|
|
163
|
+
python scripts/seo_repair.py verify ./my-site --baseline seo-repair-out/findings.json
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
To guard a site on every pull request, copy
|
|
167
|
+
[`examples/github-action/seo-repair.yml`](examples/github-action/seo-repair.yml) to
|
|
168
|
+
`.github/workflows/`. It fails the check when a critical finding is open and attaches
|
|
169
|
+
the report and dashboard to the run.
|
|
170
|
+
|
|
171
|
+
Output lands in `./seo-repair-out`: `findings.json`, `SEO-REPORT-<date>.md` and a
|
|
172
|
+
self-contained `dashboard.html`. Applying fixes stays a Claude Code job, because each
|
|
173
|
+
edit needs your approval.
|
|
174
|
+
|
|
175
|
+
## Try it on the demo site
|
|
176
|
+
|
|
177
|
+
The repo ships a small site with defects planted on purpose — an orphan duplicate, a
|
|
178
|
+
thin page, an oversized image behind `<picture>`, review markup for someone the page
|
|
179
|
+
never names, and more:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
cd scripts
|
|
183
|
+
python crawl.py --root ../examples/demo-site --out /tmp/crawl.json
|
|
184
|
+
python schema_check.py --crawl /tmp/crawl.json --out /tmp/schema.json
|
|
185
|
+
python audit.py --crawl /tmp/crawl.json --schema /tmp/schema.json --out /tmp/findings.json
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
[`examples/demo-site/EXPECTED.md`](examples/demo-site/EXPECTED.md) lists exactly what a
|
|
189
|
+
correct run reports — **and what it must stay silent about**, which is the harder half.
|
|
190
|
+
|
|
191
|
+
## Usage
|
|
192
|
+
|
|
193
|
+
Four verbs, driven through Claude Code:
|
|
194
|
+
|
|
195
|
+
| Verb | Does | Writes |
|
|
196
|
+
| --- | --- | --- |
|
|
197
|
+
| `seo-repair audit <path>` | Crawl → audit → report. Establishes the baseline. | report only |
|
|
198
|
+
| `seo-repair plan` | Ranks findings into stage-ordered batches, previews each diff | nothing |
|
|
199
|
+
| `seo-repair apply <batch>` | Applies **one approved batch**, re-checks that stage | source files |
|
|
200
|
+
| `seo-repair verify` | Re-crawl, diff vs. baseline, regression gate | report only |
|
|
201
|
+
|
|
202
|
+
Nothing is edited without approval. `plan` refuses to run without a baseline; `apply`
|
|
203
|
+
refuses without a named, approved batch.
|
|
204
|
+
|
|
205
|
+
## What it finds
|
|
206
|
+
|
|
207
|
+
| Stage | Checks |
|
|
208
|
+
| --- | --- |
|
|
209
|
+
| **Crawling & indexing** | `robots.txt` rules, XML sitemap coverage and contradictions, `noindex` directives, canonical tags (missing, cross-page, broken, off-origin), placeholder domains (example.com, localhost) in canonicals and the sitemap, broken internal links, URL hygiene, redirect chains and loops, mixed content, `hreflang` (invalid codes, broken targets, missing self and return tags), sitemap `<lastmod>` validity, response security headers, and client-rendered shells (`--render` compares raw HTML to the rendered DOM) |
|
|
210
|
+
| **Site architecture** | Orphan pages, unreachable pages, click depth, internal link distribution, heading structure, breadcrumbs |
|
|
211
|
+
| **Content & on-page** | Duplicate and near-duplicate content (MinHash), keyword cannibalization, thin content, title tags, meta descriptions, Open Graph tags, image alt text, oversized images, unused assets |
|
|
212
|
+
| **Core Web Vitals** | Lighthouse LCP, CLS and TBT — reported as *lab* metrics, with the localhost caveat stated |
|
|
213
|
+
| **Schema markup** | JSON-LD validity, required and recommended properties, and whether the markup's claims are corroborated by visible page text |
|
|
214
|
+
| **Authority / off-page** | Advisory only. It cannot measure a backlink profile and does not pretend to — it produces a human action list, and refuses paid-link and PBN tactics outright |
|
|
215
|
+
|
|
216
|
+
Findings cite the offending string from your source, so every one is checkable.
|
|
217
|
+
|
|
218
|
+
## Limitations, stated plainly
|
|
219
|
+
|
|
220
|
+
- **JS rendering is for live URLs.** `seo-repair audit https://... --render` parses
|
|
221
|
+
Chrome's post-JavaScript DOM with a local Chrome, Chromium or Edge, for up to 50 pages
|
|
222
|
+
(`--render-limit`, about 5 seconds each, one browser launch per page). A folder has no
|
|
223
|
+
running site to render, so fs mode only gets the static-shell hint `S1-JS-SHELL`. The
|
|
224
|
+
mobile-overflow check is still Claude Code only (it uses the built-in browser tools).
|
|
225
|
+
The render path is verified against real Chrome on Windows, and in CI on Ubuntu; the
|
|
226
|
+
opt-in test is `SEO_REPAIR_RENDER_TEST=1`. Chrome runs with its sandbox on; as root, or in a container
|
|
227
|
+
where it will not start, set SEO_REPAIR_NO_SANDBOX=1.
|
|
228
|
+
- **Redirect chains, response headers and rendering need an http crawl**, because a
|
|
229
|
+
folder on disk has none of them. Pagination (`rel=next/prev`) is not checked: Google
|
|
230
|
+
stopped using it.
|
|
231
|
+
- **Core Web Vitals need local Chrome.** These are lab numbers from your machine, not
|
|
232
|
+
field data. Real CWV comes from CrUX via Search Console, which is a handoff item.
|
|
233
|
+
- **`vitals.py` is verified on Windows only.** CI runs the test suite on Linux, macOS
|
|
234
|
+
and Windows, but excludes Lighthouse because it needs a browser — so that one script's
|
|
235
|
+
cross-platform behaviour is untested rather than proven. Reports welcome. One opt-in
|
|
236
|
+
test (`SEO_REPAIR_LIGHTHOUSE_TEST=1`) runs real Lighthouse against a local server.
|
|
237
|
+
- **Stage 6 does no off-page work.** By design.
|
|
238
|
+
- **The unused-asset check recommends deletion**, so it is deliberately conservative: a
|
|
239
|
+
filename appearing anywhere in any page's source counts as used. Verify before
|
|
240
|
+
deleting anyway — files can be referenced from a CMS or hot-linked externally.
|
|
241
|
+
|
|
242
|
+
## Tests
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
python tests/test_skill.py
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
146 tests (two are opt-in: real Lighthouse and real Chrome rendering), no fixture files — each builds a throwaway site in a temp directory. They pin
|
|
249
|
+
down calibration decisions made after real false positives: build-directory exclusion,
|
|
250
|
+
deliberate `noindex`, finding grouping, title thresholds, heading order, schema claim
|
|
251
|
+
corroboration, gate boundaries. A failure means *"was this behaviour meant to change"*,
|
|
252
|
+
not *"make it pass"*.
|
|
253
|
+
|
|
254
|
+
## Contributing
|
|
255
|
+
|
|
256
|
+
Bug reports and pull requests welcome, particularly on non-Windows platforms — the
|
|
257
|
+
Lighthouse integration is the least-tested part of this project.
|
|
258
|
+
|
|
259
|
+
If you change a rule, three things move together: the counts and defect table in
|
|
260
|
+
[`examples/demo-site/EXPECTED.md`](examples/demo-site/EXPECTED.md), and the `required`
|
|
261
|
+
finding ids in the CI workflow. [`RELEASING.md`](RELEASING.md) has the full checklist.
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT. See [LICENSE](LICENSE).
|