fix(skills): make broken-link check finish and stop flagging bot blocks - #447
Conversation
Running the check_for_broken_links skill against the docs surfaced two problems that made it unusable, and no actual broken links. The external check never completed. Every URL was fetched serially with a sleep between files, so changelog/2026.mdx alone (696 links, mostly rate-limited GitHub URLs) stalled the run indefinitely. It hung twice at file 57 of 354. External URLs are now deduplicated and resolved up front across a thread pool, leaving the per-file pass as pure cache reads. A full check finishes in about 60s. Sessions are thread-local since requests.Session is not thread-safe. The report was also dominated by false positives. All 26 flagged links were 401/403/429 from servers refusing automated clients, with zero real 404s: Cloudflare interstitials on sourceforge.net, OpenAI bot challenges, and login-gated Slack invite links. Each was verified working in a browser. Those statuses are now grouped into a separate BOT-BLOCKED section that does not fail the run, so real breakage is not buried. Pass --strict to treat them as broken. Also: - Send a browser-like User-Agent, which alone resolves platform.openai.com and tiktok.com. - Retry once on timeouts and connection resets, which were flaky under concurrency, and fall back to GET whenever HEAD fails rather than only on 405. - Add --workers and --strict, and correct the documented script paths from .warp/skills to .agents/skills, where the script actually lives. Co-Authored-By: Oz <oz-agent@warp.dev>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR updates the broken-link checker to deduplicate and concurrently resolve external URLs, use browser-like request headers, retry transient network failures, classify 401/403/429 responses separately as bot-blocked unless --strict is used, and correct the skill documentation paths.
Concerns
No blocking correctness, security, or error-handling concerns found in the annotated diff.
Verdict
Found: 0 critical, 0 important, 0 suggestions
Approve
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz

Summary
I ran the
check_for_broken_linksskill across the docs to audit link health. There are no broken links — 3,306 internal and 1,099 unique external URLs all resolve.Getting that answer required fixing the checker, which had two defects that made it unusable. This PR fixes those so the next run is actually trustworthy. No content pages are changed.
The external check never finished
Every external URL was fetched serially, with a
time.sleep(0.05)between files.changelog/2026.mdxalone has 696 links, mostly GitHub URLs that rate-limit, so a single file consumed the entire run. It hung at file 57 of 354 on two separate attempts, once for 15 minutes without advancing.External URLs are now deduplicated and resolved up front across a thread pool, leaving the per-file pass as pure cache reads. A full check now completes in ~60s. Sessions are thread-local, since
requests.Sessionisn't thread-safe.Concurrency is tunable via
--workers(default 16) for slow or rate-limited networks:Bot blocks were reported as broken links
The report was entirely false positives. All 26 flagged links returned
401/403/429— servers refusing an automated client — with zero genuine 404s:vimdoc.sourceforge.net,zsh.sourceforge.io— CloudflareJust a moment...interstitialhelp.openai.com,platform.openai.com— OpenAI bot challengego.warp.dev/join-preview— resolves correctly to the community Slack invite; Slack serves a sign-in page to non-browsersI confirmed each of these loads normally with browser headers. Reporting them as broken is actively harmful: it invites "fixing" working links, and it buries the real 404s.
These statuses now go to a separate
BOT-BLOCKEDsection, grouped by URL rather than listed per occurrence, and don't fail the run.--strictrestores the old behavior.Other fixes
User-Agent— on its own this resolvesplatform.openai.comandtiktok.com, which previously 403'd.code.claude.com/docstimed out under concurrency but returns 200 on every manual attempt.GETwheneverHEADfails, not only on405. Many servers mishandleHEADwith other 4xx/5xx codes..warp/skills/...to.agents/skills/..., where the script actually lives. Every command in the skill doc was wrong, so copy-pasting them failed.Verification
--internal-only: 3,306 links, 0 broken (unchanged from before this PR)--strict: correctly reclassifies bot blocks as broken and exits 1Note for a follow-up
Six sibling skills carry the same stale
.warp/skillspaths and are untouched here to keep this scoped:create_pr,draft_conceptual,draft_faq,draft_quickstart,draft_reference,draft_troubleshooting.Separately,
warpdotdev/gitbookstill has the pre-migration copy of this skill and several links this repo already fixed (blob/master/LICENSE→LICENSE-AGPL,docs.warp.dev/warp/...prefixes). That repo is archived and read-only, so no action is possible there.Conversation: https://app.warp.dev/conversation/dc5ca31f-c34a-4ec3-9e17-17904f23b9a0
Run: https://oz.warp.dev/runs/019fb91e-69b7-7b0f-a11c-008367c9986c
This PR was generated with Oz.