Correction des liens brisés

VérifiéSûr

Analyse les liens brisés du vérificateur quotidien, choisit une stratégie de correction et ouvre une PR avec les modifications.

Spar Skills Guide Bot
DocumentationIntermédiaire
22/07/2026
Claude Code
#broken-links#link-checking#redirects#pull-requests#docs-maintenance

Recommandé pour

Synthèse automatique

Ce skill lit le fichier .broken-links.json produit par le vérificateur de liens quotidien, vérifie et trie chaque lien cassé vers une stratégie de correction (alias Hugo, redirection S3, édition de la source, exclusion ou issue hors périmètre), puis ouvre une seule pull request auditable.

Points forts

  • Vérifie chaque lien avant toute modification et consigne les faux positifs (protection anti-bot, 5xx transitoires, murs d'authentification) dans une section dédiée du compte rendu de PR
  • Traite en priorité les entrées REAL_404 issues des journaux serveur, classées par nombre de hits, pour corriger d'abord ce que les lecteurs demandent réellement
  • Choisit explicitement entre plusieurs stratégies selon le cas : alias Hugo, redirection S3, correction de la source, exclusion ou ouverture d'issue hors périmètre
  • Dédoublonne les liens déjà en cours de traitement et regroupe le tout dans une seule PR auditable

Limites

  • Skill non invocable par l'utilisateur : il dépend du workflow check-links et de la présence de .broken-links.json à la racine du dépôt
  • Très spécifique au site Pulumi (scripts link-checker, alias Hugo, redirections S3) et difficilement réutilisable tel quel ailleurs
  • La qualité du résultat repose sur la re-vérification manuelle via WebFetch ou curl, donc sur le jugement du modèle quand un site bloque les clients automatisés
  • N'agit que sur l'instantané du fichier d'entrée, qui peut avoir jusqu'à une semaine de retard
Quand l'utiliser

À utiliser lorsqu'un rapport automatisé de liens cassés doit être transformé en corrections concrètes et en une PR unique, avec une trace claire des liens vérifiés et des faux positifs écartés.

Quand l'éviter

À éviter si vous cherchez un outil générique de vérification de liens ou si le dépôt n'est pas le site Pulumi avec ses scripts et son fichier .broken-links.json.

Analyse de sécurité

Sûr
Score qualité92/100

The skill automates broken-link fixes in a docs repository using read-only verification (WebFetch/curl HEAD requests), gh CLI for PR/issue management, and file edits. No destructive commands, exfiltration, obfuscation, or disabling of safety mechanisms are present. All actions are legitimate and scoped to the repository.

Aucun point d'attention détecté

Comment cette analyse est faite

Exemples

Fix today's broken links
Read .broken-links.json, verify each reported link is genuinely broken, triage them to the right fix strategy, and open one auditable PR.
Prioritize real 404s from server logs
Start with the REAL_404 entries sorted by hits, and add Hugo aliases or S3 redirects to the obvious successor pages where they exist.
Triage suspicious external failures
Before changing anything, re-check the 403 and 503 external links — if they resolve in a browser, leave them alone and list them under False positives / not actioned in the PR.

name: fix-broken-links description: Fix broken links reported by the daily link checker. Reads .broken-links.json, triages each link to a fix strategy (alias, S3 redirect, source edit, exclusion, or out-of-scope issue), and opens an auditable PR. Invoked by the check-links workflow; not user-invocable. user-invocable: false

Fix Broken Links

You are fixing the broken links found by the daily link checker (scripts/link-checker/check-links.js, run against https://www.pulumi.com). Work through every reported link, pick the right strategy for each, open one auditable PR, and file issues for anything that can't be fixed in this repo.

Input

Read .broken-links.json from the repo root. Shape:

{
  "generated": "2026-06-02T15:00:00.000Z",
  "internal": [
    { "source": "...", "destination": "...", "reason": "HTTP_404", "hits": 210 },
    { "source": "(server logs)", "destination": "...", "reason": "REAL_404", "hits": 94 }
  ],
  "external": [{ "source": "...", "destination": "...", "reason": "HTTP_404" }]
}
  • source — the live page the broken link was found on.
  • destination — the URL that failed.
  • reason — BLC reason code (HTTP_404, HTTP_410, ERRNO_ENOTFOUND, …), or REAL_404 for entries merged from server logs (below).
  • internal — destination is on pulumi.com; external — third-party.
  • hits — optional: real 404 requests on that destination from server logs over the export window (merged in by scripts/link-checker/merge-404-signal.py). The list is sorted by hits descending — work highest-hits first; entries without hits follow.

If both lists are empty, do nothing (the workflow won't invoke you in that case, but be defensive).

Real-404 signal (reason: "REAL_404")

These entries come from server logs, not the crawler: URLs readers actually requested that returned 404 — external referrers, bookmarks, stale search results. That means:

  • source is (server logs) — there is no on-site page to edit; the fix is almost always a Hugo alias or S3 redirect to the obvious successor page, or the nearest section index when none exists.
  • Verify the URL still 404s before fixing (the export is up to a week old; it may have been fixed since).
  • Residual noise the export's bot filter missed (crawler probes, exploit scans) goes under False positives / not actioned — never give junk paths a redirect.

Verify each link before fixing it

The checker produces false positives — never fix a link without confirming it's actually broken. The crawler hits live URLs with a bot user agent, so it routinely mis-flags links that are fine in a browser: bot-protected sites, transient 5xx/timeouts, rate-limiting, auth walls, and pages that block automated clients. excludeAcceptable() already filters the common transient reasons, but plenty slip through — especially in the external list.

For every reported link, confirm it's genuinely broken before touching anything:

  1. Re-check the destination — WebFetch (or curl -sIL) the URL. If it resolves, it's a false positive.
  2. Weigh the reason code. Internal HTTP_404/HTTP_410 on a pulumi.com path is almost always real. External failures, and codes like HTTP_403, HTTP_401, HTTP_429, HTTP_503, or connection/timeout errors, are frequently bot protection or transient — treat as suspect until confirmed.
  3. If it's a false positive, do not edit, redirect, or exclude it. Leave the link as-is and record it in the PR audit trail under a False positives / not actioned section, with the URL, the reason code, and one line on why it's fine (e.g. "resolves in browser; 403 is Cloudflare bot protection"). Optionally suggest it as a future exclusion-list candidate, but don't add it unless it's a recurring offender.

Only links you've confirmed broken proceed to triage below.

Skip links already being handled (deduplication)

Broken links persist for days, so the same ones surface in consecutive runs while a fix is already in flight. Before actioning a confirmed-broken link, check whether it's already covered — never open a second PR for a fix that's pending, or file a duplicate issue.

For each confirmed-broken link, search for prior work:

  1. Open PRs in pulumi/docs. List candidates with gh pr list --state open --search "broken link" --json number,title,url,headRefName (prior runs use the fix/broken-links-* branch pattern). For a likely match, confirm with gh pr view <n> / gh pr diff <n> that it actually covers this link (same destination URL, source file, redirect, or exclusion entry).
  2. Existing issues, before filing a new one. For an out-of-scope item that would become an issue in another repo, search that repo first — gh issue list --repo pulumi/<repo> --state open --search "<url-or-path>" (or gh search issues). If an open issue already tracks it, treat it as a duplicate and reuse that issue's link; do not file another.

Classify each confirmed-broken link as actionable (no existing PR/issue covers it) or duplicate (one does — capture the PR/issue URL). Then:

  • All duplicates (every confirmed-broken link is already covered): do not create a branch, PR, or any issue. Write a Slack summary to .broken-links-pr.txt saying so and listing each link with its existing PR/issue link, e.g. :link: 5 broken links — all already tracked (no new PR): <url> → #19470, …. Stop here.
  • Some actionable, some duplicates: action only the non-duplicates (open the PR, file new issues). Omit duplicates from the fixes, but list them in a short Already tracked section in the PR description (one line each, linking the existing PR/issue). Don't re-file or re-fix them.

Mapping a live URL back to its source file

source and destination are live https://www.pulumi.com/... URLs. To edit or redirect them you must find the file that produces them:

  1. Strip the origin to get the path, e.g. /docs/iac/concepts/stacks/.
  2. Hugo content lives under content/. A path like /docs/iac/concepts/stacks/ is produced by content/docs/iac/concepts/stacks/_index.md or .../stacks.md. Use Glob/Grep under content/ to locate it.
  3. To find which file emits a broken destination link, Grep for the link text under content/, data/, layouts/, and static/ — it may come from a data file, a shortcode, or a template, not prose.
  4. Registry, API-docs, and other generated paths have no source file in this repo (see "Out of scope" below).

Per-link triage

Apply the first row that matches.

| Situation | Strategy | Mechanism | |---|---|---| | Internal link points at a moved/renamed path, but the destination page still exists at a new path | Hugo alias | Add the old path to aliases: on the destination page's frontmatter | | Internal link to a page that was deleted/restructured, or a non-Hugo path (registry, generated docs) | S3 redirect | Add a redirect line to the topic-appropriate file in scripts/redirects/ | | Broken link living in editable content (content/docs, content/product, content/tutorials) | Edit at source | Fix the link in place; use the full root-relative path (/docs/...), never ../ | | Broken link in a blog post and an equivalent replacement exists (same content, or close enough that the post's meaning is unchanged) | Edit at source + stamp lastmod | Swap the link; add/update lastmod: in that post's frontmatter (leave date: alone) | | Broken link in a blog post with no equivalent replacement | Route around the prose | Add an alias/redirect so it resolves; if it's a dead external link, add it to the exclusion list. Do not reword blog prose | | Dead / transient / bot-protected external link | Exclusion list | Add the URL to getDefaultExcludedKeywords() in check-links.js with an inline // comment naming the reason + blog post/issue. If the page mattered, prefer swapping to a Wayback snapshot | | Redirect loop or malformed alias YAML | Repair | Remove the stale redirect / fix the alias indentation | | Breakage owned by another repo (e.g. registry logoUrl, generated SDK docs) or otherwise unfixable here | Out of scope | File a GitHub issue and document it in the PR description — do not hack around it |

Mechanics

Hugo alias. Add the old path under aliases: in the destination page's frontmatter (root-relative, trailing slash):

aliases:
- /docs/old/path/

Full mechanics and edge cases: move-doc:references:alias-injection.

S3 redirect. Append one line to the topic-appropriate file in scripts/redirects/ (e.g. cicd-redirects.txt, iac-cli-redirects.txt, general-broken-links-redirects.txt when nothing more specific fits). Format is source-path|destination-url, one per line. The source is the path without a leading slash and usually ends in /index.html; the destination is root-relative (/docs/.../) or a full URL for off-site targets:

docs/old/path/index.html|/docs/iac/new/path/

Edit at source. Replace the broken link with the correct one. Internal docs links use the full canonical root-relative path (/docs/iac/concepts/stacks/); never ../. This is the only strategy that touches prose, and for blog posts it's limited to equivalent-content link swaps.

Blog lastmod. Any blog edit must add or update lastmod: (ISO date, today) in that post's frontmatter so the change is reflected, while the original date:/publish date stays put so post ordering doesn't shift.

Exclusion list. Add the URL to the array returned by getDefaultExcludedKeywords() in scripts/link-checker/check-links.js, grouped with similar entries, with an inline comment naming the reason and the post/issue, matching the existing style:

"https://example.com/gone",  // blog/<post>: 404, no replacement (#<issue>)

Editing guardrails

  • Tutorials are editable like docs — fix their links at the source.
  • Blog prose is editable only to substitute a broken link for an equivalent-content replacement, and every such edit stamps lastmod. Blog links with no equivalent replacement are routed around with an alias/redirect/exclusion, never reworded.
  • Internal links use full root-relative paths, never ../.
  • make lint and make build must both pass before you open the PR.

Output

If every confirmed-broken link is a duplicate (see deduplication above), skip all of the below: open no branch, PR, or issue, write the "all already tracked" Slack summary to .broken-links-pr.txt, and stop. Otherwise, for the actionable (non-duplicate) links:

  1. Create a branch fix/broken-links-<date> (date from the workflow, e.g. fix/broken-links-2026-06-02).
  2. Make the fixes, grouping related changes into clear commits.
  3. File a GitHub issue (gh issue create) for every new out-of-scope item (reuse the existing issue for duplicates).
  4. Run make lint and make build; fix anything they surface.
  5. Open a ready (non-draft) PR to master.
  6. Write the final PR URL plus a one-line summary to .broken-links-pr.txt for the workflow's Slack step, e.g.: :link: Fixed 7 broken links — <PR URL> (2 aliases, 1 redirect, 3 source edits, 1 issue filed)

PR description contract (auditability)

The reviewer must be able to audit every decision without re-deriving it. Model the description on PR #19469. Include:

  • A table or list of every broken link → the strategy applied → one line of non-obvious reasoning (why a redirect vs. an alias, why excluded, etc.).
  • A Verification section: confirm make lint and make build passed, and note that each link was re-checked before fixing.
  • A False positives / not actioned section listing every reported link you confirmed was actually fine, with its reason code and why (so the reviewer knows it was checked, not missed).
  • An Already tracked section, when any link was skipped as a duplicate: one succinct line per link linking the existing PR or issue that covers it.
  • An Out of scope / filed issues section linking every issue you created for breakage owned by other repos or otherwise unfixable here.

Du fichier au premier essai

Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.

Consulter la source et ses fichiers annexes

Ce téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.

1. Télécharger le fichier

Télécharger SKILL.md

Depuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/fix-broken-links-mrwakek2/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.

Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.

mkdir -p '.skill-downloads/fix-broken-links-mrwakek2' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/fix-broken-links-mrwakek2/download' --output '.skill-downloads/fix-broken-links-mrwakek2/SKILL.md.part' && mv '.skill-downloads/fix-broken-links-mrwakek2/SKILL.md.part' '.skill-downloads/fix-broken-links-mrwakek2/SKILL.md'

2. Vérifier les prérequis

Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.

Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.

Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.

3. Charger la skill

Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.

Claude Code
test -f '.skill-downloads/fix-broken-links-mrwakek2/SKILL.md' && test -s '.skill-downloads/fix-broken-links-mrwakek2/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/fix-broken-links' && cp -R '.skill-downloads/fix-broken-links-mrwakek2' '.claude/skills/fix-broken-links'

OpenSkills

OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.

Installation officielle d’OpenSkills
openskills install './.skill-downloads/fix-broken-links-mrwakek2'

openskills read 'fix-broken-links-mrwakek2'

La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.

Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.

openskills sync

Mode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.

4. Faire un premier essai

Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :

Lis .skill-downloads/fix-broken-links-mrwakek2/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.

Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.

Skills similaires