From firefox-wiki
Check Firefox Knowledge Wiki integrity. Use --lightweight after writes (automatic) or --full to run all due accuracy checks based on per-page lint intervals.
How this skill is triggered — by the user, by Claude, or both
Slash command
/firefox-wiki:lintThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
All lint state is stored in a single file at `$WIKI_PATH/lint-log.json`. Pages are never modified by the lint skill — all metadata stays in this file.
All lint state is stored in a single file at $WIKI_PATH/lint-log.json. Pages are never modified by the lint skill — all metadata stays in this file.
{
"components/AudioSink.md": {
"lint-last": "2026-04-05",
"lint-source-rev": "abc123def"
},
"specs/MSE_W3C/overview.md": {
"lint-last": "2026-01-10"
}
}
lint-last — ISO 8601 date of last successful lint pass for this pagelint-source-rev — git hash of the Firefox tree at last lint (components/relations only)Pages absent from lint-log.json are treated as never-linted and are always due.
Read the full log at the start of any full/force lint run:
cat $WIKI_PATH/lint-log.json 2>/dev/null || echo "{}"
After all checks complete, write the updated log in one atomic operation and commit:
# build updated JSON in memory, then write
echo '<updated-json>' > $WIKI_PATH/lint-log.json
cd $WIKI_PATH && git add lint-log.json && git commit -m "wiki: lint run $(date +%Y-%m-%d)"
| Directory | Interval | Source-change check |
|---|---|---|
components/ | 14 days | Yes — skip if no Firefox commits since lint-source-rev |
relations/ | 14 days | Yes — skip if no Firefox commits since lint-source-rev |
architecture/ | 90 days | Yes — end-to-end pipeline walkthroughs reference specific class names |
patterns/ | 90 days | No |
specs/ | 180 days | No — use ETag/MD5 instead |
platform/ | 180 days | No — use ETag/MD5 instead |
others/ | 180 days | No |
bugs/ | Never | Historical record — never re-lint |
At the start of every lint run, set:
export WIKI_SKIP_HOOKS=1
This suppresses the pre-lookup and read-logging hooks so lint's own file reads don't pollute usage stats.
--lightweight: runs automatically after every wiki write (triggered by the PostToolUse hook on Write/Edit). Checks only recently modified files for broken links.--full: run all checks that are due based on per-page intervals. Pages not yet past their interval are skipped.--force: like --full but ignores intervals — checks every page regardless of lint-last.<page-path>: lint a single page only (e.g. components/AudioSink.md). Runs all checks unconditionally, skips interval logic, updates lint-last for that page only.Parse $ARGUMENTS:
--lightweight: run lightweight mode.--force: run full mode with interval checking disabled.--full: run full mode with interval checking enabled..md, not starting with --): run single-page mode on that file.Runs all full-mode checks on one specific file unconditionally — no interval check, no source-change skip. Useful for spot-checking a page you just edited.
Steps:
$WIKI_PATH if not absolute.lint-last (and lint-source-rev for components/relations) for that page only.Runs automatically after each wiki write. Fast — structural checks only on recently modified files.
Identify recently modified wiki files:
git -C $WIKI_PATH diff --name-only HEAD~1 HEAD 2>/dev/null || ls -lt $WIKI_PATH/**/*.md | head -5
For each recently modified file:
[[PageName]] patterns:
rg '\[\[([^\]]+)\]\]' <file> -o --no-filename
PageName, check whether <PageName>.md exists anywhere under $WIKI_PATH:
find $WIKI_PATH -name "<PageName>.md"
If broken links found: print them clearly.
If all valid: silent success — print nothing.
Validate and repair usage-log.jsonl:
Parse $WIKI_PATH/usage-log.jsonl. For each line:
event_type: infer it from other fields:
source_url or spec_title → "url-ingest"directory containing pdf or has pdf in any value → "pdf-ingest"bug_id → "ingest""unknown"timestamp instead of date: rename to date.If any repairs were made: rewrite the file as valid single-line JSONL (one object per line) and print:
usage-log.jsonl: repaired <n> malformed entries
If the file is already valid: silent success.
Runs all checks that are due. For each page, first determine whether it needs linting:
TODAY = current date
LINT_LOG = parsed lint-log.json
lint-last = LINT_LOG[page]["lint-last"] or "1970-01-01" if absent
interval = lookup from table above (by directory)
if (TODAY - lint-last) >= interval:
→ page is DUE — run checks
else:
→ page is CURRENT — skip
For components/ and relations/ pages that are due, additionally run the source-change check:
FIREFOX_ROOT=${MOZ_SRC:-$(git rev-parse --show-toplevel 2>/dev/null)}
CURRENT_REV=$(git -C $FIREFOX_ROOT rev-parse HEAD)
lint-source-rev = LINT_LOG[page]["lint-source-rev"] (empty if absent)
git -C $FIREFOX_ROOT log <lint-source-rev>..<CURRENT_REV> --oneline -- dom/media/ 2>/dev/null
If the log is empty (no commits to dom/media/ since last lint): mark page as source-unchanged — skip accuracy checks, run structural checks only. Record lint-last = TODAY in lint-log.json but leave lint-source-rev unchanged.
If the log is non-empty or lint-source-rev is absent: run all checks for this page.
Grep all due *.md files for [[...]] patterns. For each link verify the target file exists. Report all broken links grouped by source file.
For every .md file under components/, relations/, and patterns/: check that it appears in INDEX.md. Report any pages missing from the index.
Find every entry in INDEX.md that does not have a corresponding file on disk. Report each.
Scan each due component page for required section headings:
## Overview or ## Purpose## RelationsReport any component page missing these headings.
Find any due .md file exceeding 300 lines. Report as a candidate for splitting.
For each due spec page with a <!-- source-url: <url> --> comment:
Extract URL and stored ETag/Last-Modified/MD5:
grep "source-url\|source-etag\|source-last-modified\|source-md5" <file>
For remote URLs: fetch current headers only:
curl -sI --max-time 10 "<url>"
Compare current etag or last-modified against stored value.
For local PDFs (file://): strip the file:// prefix and expand $HOME:
LOCAL_PATH=$(echo "<url>" | sed 's|^file://||' | sed "s|^\$HOME|$HOME|")
md5 "$LOCAL_PATH"
Compare against stored source-md5.
Verdict:
/firefox-wiki:add <url> to refresh."For each due page, find all searchfox.org/mozilla-central/rev/<hash>/... URLs:
Extract <path> from URL.
Check file existence in current Firefox tree:
ls "$FIREFOX_ROOT/<path>" 2>/dev/null && echo "EXISTS" || echo "MISSING"
If file exists, check symbol from surrounding sentence:
searchfox-cli --id '<symbol>' --cpp -l 5
Verdict:
<path>"<name> not found in current tree"For each due page, scan for fact lines without a source citation.
A fact line: non-empty, not a heading, not a table delimiter, not inside a code block, contains a class/method/field name or behavioral assertion.
A citation: <!-- source: ... --> comment, [High/Medium/Low] tag, Searchfox URL, or spec section reference (§) on the same line.
Flag uncited fact lines as:
components/Foo.md:42— uncited claim: ""
Limit to first 20 uncited lines per file. Advisory only — do not fail lint.
For each due component page, extract the primary class name from the page title (# ClassName).
searchfox-cli --define '<ClassName>' --cpp -l 1
If not found:
components/<Name>.md— class<Name>not found in current tree. Page may describe a removed or renamed component.
Read all bug pages. Group by component pairs mentioned. If 3+ bugs share the same component pair and no pattern page exists, suggest:
Consider creating a pattern page for
<A>-<B>interactions (appears in bugs X, Y, Z)
After all checks complete, automatically fix all mechanical issues before updating lint-log.json. Do not ask for confirmation — apply all fixes silently and include a count in the summary report.
In all files under specs/, platform/, others/: find [[PageName]] links where the target does not exist anywhere under $WIKI_PATH. These are W3C/spec-defined terms (e.g. [[append state]], [[buffer full flag]]) that were incorrectly marked as wiki-links during ingestion.
For each such broken link in a spec page: replace [[PageName]] with plain text PageName (strip the brackets).
# For each spec file with broken links, use sed to strip [[...]] for unresolved targets
sed -i 's/\[\[<broken-term>\]\]/<broken-term>/g' <spec-file>
Apply only to files under specs/, platform/, others/ — never strip links in components/, relations/, patterns/, or bugs/.
In all wiki files: find [[bug XXXXXXX]] patterns. For each, look up the matching bug page under bugs/:
find $WIKI_PATH/bugs -name "<XXXXXXX>-*.md" | head -1
[[bug XXXXXXX]] with [[bugs/XXXXXXX-slug]] (using the actual filename without .md)In components/ and relations/ pages: find [[PageName]] links where:
$WIKI_PATH- suggesting a relation, or matches a known deleted page)For each such dead reference: replace [[PageName]] with plain text PageName.
Do not auto-remove references to missing component pages — those may need to be created, not removed. Only remove references to pages that were explicitly relation/pattern pages (identified by naming convention: A-B format for relations).
After all pages have been checked, update lint-log.json in one pass:
For each page that was checked (due, not skipped):
lint-last to TODAYlint-source-rev to CURRENT_REVlint-source-rev as-isBuild the updated JSON using jq:
jq --arg page "components/AudioSink.md" \
--arg date "2026-04-05" \
--arg rev "abc123def" \
'.[$page] = {"lint-last": $date, "lint-source-rev": $rev}' \
$WIKI_PATH/lint-log.json > /tmp/lint-log-new.json \
&& mv /tmp/lint-log-new.json $WIKI_PATH/lint-log.json
Repeat for each checked page, then commit once (together with the derived artifacts regenerated below):
cd $WIKI_PATH && git add lint-log.json aliases.txt index.json \
&& git commit -m "wiki: lint run $(date +%Y-%m-%d)"
After the checks, rebuild two derived, machine-readable files that speed up
the hooks and the lookup skill. They are caches — INDEX.md and glossary.md
remain authoritative, and both consumers fall back gracefully if these files are
missing or stale. Run this only in --full / --force mode (skip in
lightweight and single-page modes). Write each atomically (mktemp + mv).
Parse $WIKI_PATH/glossary.md. For every abbreviation line of the form
- **KEY**: VALUE, keep the pair only when VALUE is a single identifier
token — it matches ^[A-Za-z][A-Za-z0-9]*$ and is ≤40 chars. This captures
- **MFR**: MediaFormatReader and skips prose entries like
- **GHLG**: Microsoft's token.... Emit both directions, one
key<TAB>expansion per line:
MFR MediaFormatReader
MediaFormatReader MFR
MDSM MediaDecoderStateMachine
MediaDecoderStateMachine MDSM
The pre-lookup hook reads this with a fixed-string grep -iF per candidate, so
the format must stay tab-separated with no surrounding whitespace. Write to a
temp file then mv into place.
Build one record per page listed in INDEX.md's tables (Components, Relations,
Bugs, Patterns, Specs, Triage, Profiler). Schema:
{ "schema": 1,
"generated": "<ISO 8601>",
"source_index_mtime": <int mtime of INDEX.md>,
"pages": [
{ "name": "MediaFormatReader",
"path": "components/MediaFormatReader.md",
"dir": "components",
"summary": "<the role/description column from the INDEX table row>",
"aliases": ["MFR"],
"confidence": "High" } ] }
For each [[link]] row:
name = the link text (bare) or its last path segment for dir/slug links.path = resolve bare names with find $WIKI_PATH -name "<name>.md" (first
hit); use dir/slug.md verbatim for qualified links.dir = top-level directory of path.summary = the description/role column already present in the INDEX table row
(cheapest and curated). Only when a row has no description, fall back to the
page's first non-heading sentence.confidence = highest inline tag found on the page ([High] > [Medium] >
[Low]), else null.aliases = every key in aliases.txt whose expansion equals name.Set source_index_mtime from stat -f %m "$WIKI_PATH/INDEX.md" (macOS) or
stat -c %Y (Linux) — this is the freshness guard lookup compares against.
Write atomically. A half-written or unparseable index.json is harmless: both
consumers treat it as absent and fall back to INDEX.md.
## Wiki Lint Report — <date> (<--full|--force>)
Pages checked: <n> of <total> (remainder not yet due)
Broken links: <n> issues
Missing from index: <n> pages
Orphaned index entries: <n>
Missing required sections: <n>
Oversized pages: <n>
Stale specs: <n> (spec updated upstream)
Dead Searchfox links: <n> (file/symbol missing in current tree)
Uncited claims: <n> lines (advisory)
Missing class definitions: <n> components
Pattern synthesis: <n> candidates
Next due:
components/ — <date of next component page due>
specs/ — <date of next spec page due>
<details for each category>
npx claudepluginhub alastor0325/firefox-wiki-plugin --plugin firefox-wikiFetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
Applies a firm's KYC/AML rules grid to parsed onboarding records: assigns risk rating, checks required documents, outputs rule outcomes with citations, and routes for escalation.
Generates daily or weekly digests of activity from connected sources (chat, email, docs, tasks, CRM), highlighting action items, decisions, mentions, and project updates.