skills/docx-footnotes/SKILL.md
Use when DOCX footnotes are broken after Google Docs or Word Online round-trips, when converting hardcoded 'supra note N' cross-references to auto-updating NOTEREF fields, or for any OOXML-level footnote surgery on a Word document — even if the user doesn't say 'OOXML' but describes footnote formatting problems in a .docx edited in a cloud editor.
npx skillsauth add edwinhu/workflows docx-footnotesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fix footnote formatting damage caused by Google Docs and Word Online, and convert hardcoded supra note references to NOTEREF field codes.
Common symptoms in .docx files round-tripped through Google Docs or Word Online:
FNStyleBest etc.) — the pStyle reference points at an undefined style and Word silently falls back to Normal*, †, ‡) replaced with numberscustomMarkFollows bio footnotes)Scripts are in this skill's scripts/ directory. Use $SKILL_DIR below as a placeholder for the absolute path to this skill (the directory containing this SKILL.md).
# Fix all cloud editor damage + convert cross-references
uv run --with lxml python3 \
"$SKILL_DIR/scripts/fix_footnotes.py" path/to/file.docx --crossrefs
# Dry run (show what would change)
uv run --with lxml python3 \
"$SKILL_DIR/scripts/fix_footnotes.py" path/to/file.docx --dry-run
# Cross-references only
uv run --with lxml python3 \
"$SKILL_DIR/scripts/create_crossrefs.py" --docx path/to/file.docx
# Refresh stale NOTEREF cross-ref numbers after a coauthor inserted/moved
# footnotes in Word (render-based, ground-truth; needs x2t or LibreOffice)
"$SKILL_DIR/scripts/refresh_noteref_caches.py" path/to/file.docx --verify
Which script do I want?
fix_footnotes.py.create_crossrefs.py.refresh_noteref_caches.py (this is the common "Nadya emailed back tracked edits and the numbering is off" case).Detects and repairs OOXML footnote damage. Handles multiple sources. Idempotent.
Google Docs / Word Online round-trip damage:
pStyle="FootnoteText" (the Google Docs
default) to FNStyleBest on every footnote paragraph so the whole doc
uses the canonical law-review style.FNStyleBest (and the basedOn/link
styles it depends on) from the canonical law-review reference template when
a round-trip stripped them from styles.xml. The template is the same
writing-legal/templates/law_review_template.docx that law-review-docx's
build_docx.py feeds to pandoc, so style definitions stay consistent.FNStyleBest /
FNStyleBestChar block survives the round-trip but picks up Google Docs
hyperlink-renderer residue (link-blue underline color <w:u w:color="0077CC"/>
or white paragraph shading), the whole block is replaced from the template.Pandoc-citeproc wrap parens:
(...) wrapper pandoc adds around mid-footnote bracketed
citations while preserving author-written explanatory parentheticals
(which lack the double-whitespace XML signature).Flags:
--output / -o: Output path (default: overwrite input)--dry-run: Show what would change without modifying--bio-footnotes N: Number of author bio footnotes (default: 3)--crossrefs: Chain to create_crossrefs.py after fixing--fix-numbering: Fix numbering offset from customMarkFollows bio footnotes (adds numRestart, updates NOTEREFs and supra references)--template PATH: Reference template (.docx) to restore missing footnote style definitions from (default: bundled writing-legal/templates/law_review_template.docx)Converts hardcoded "supra note N" references to NOTEREF field codes that auto-update.
What it does:
supra note <number> patterns in document body and footnotesNOTEREF _RefFN<id> \h field codesRefreshes the cached numbers on existing NOTEREF cross-reference fields after
footnotes were inserted/moved/deleted in Word. Use when cross-references already
ARE fields (not hardcoded text) but their numbers went stale.
Why the naive approaches fail (and this script's method):
+N to everything is wrong.document.xml order is wrong: the 3 customMarkFollows
author-bio footnotes are not counted in the numeric sequence, and a tracked
footnote move makes XML order diverge from rendered order.So the script uses the rendered page-bottom footnote markers as ground truth:
render → extract markers → fingerprint-match each footnote to its true marker
(longest-common-prefix, one-to-one, most-distinctive first) → set every NOTEREF
cache to its target's marker. It also repairs NOTEREF field codes left dangling by
Word's 40-char bookmark-name truncation (_RefBib_...2024 → the real
_RefBib_...20). It deliberately does not add updateFields (that re-triggers
the buggy recompute). Verify with a changes-accepted render — once inserts are
accepted every engine agrees and the inline xrefs render correctly.
Requires: ONLYOFFICE x2t (preferred; onlyoffice-x2t nix package) or
LibreOffice (soffice) as fallback, plus pymupdf (auto-installed via the inline
script deps; run the file directly, e.g. ./refresh_noteref_caches.py file.docx).
Flags:
-o / --output: Output path (default: overwrite input)--dry-run: Report the cache changes without writing--verify: Also emit a changes-accepted *_ACCEPTED_preview.pdf proof--soffice PATH: Path to the LibreOffice binary, used only when x2t is not on PATH (auto-discovered if omitted)Scope (intentional): refreshes numbers only. It does not do editorial retargeting (e.g. "this xref should point to notes 210–212 instead of its current target"). That is a human decision — move the bookmark / change the NOTEREF target first, then re-run this to refresh.
See footnotes-reference.md for detailed technical reference covering:
When author bio footnotes use customMarkFollows (*, †, ‡), they consume auto-numbers 1–3, causing body footnotes to start at 4. Fix by adding numRestart=eachSect to settings.xml and updating NOTEREF cached values.
Requires: A section break between title page and body. Render PDF with Word or x2t (scripts/doc_render.py at plugin root) — both honor numRestart; LibreOffice does not (renders restart numbering wrong; verified 2026-06-10, x2t restarts at 1 per section where soffice numbers continuously).
See footnotes-reference.md § 4 for details, code patterns, and the critical rule: numRestart goes in settings.xml ONLY (not in sectPr — causes all-zeros).
This skill repairs footnote markup. It is a separate concern from OOXML
package repair (scripts/docx_repair.py — fixes the case-broken customXML
part paths a Google Docs export emits, which make Word refuse to open the file)
and from PDF export (scripts/doc_render.py). See the full
document skill group.
development
Build the meeting-level proxy-voting × ownership panel on the WRDS SGE grid — ISS N-PX fund votes reduced to (item × block) direction cells, joined to institutional and mutual-fund ownership. Use when working with risk.voteanalysis_npx, N-PX fund-level votes, ISS→CRSP fund linking, index/passive/active voting blocks, or a proxy-voting panel that needs ownership attached.
development
Use when "CRSP CIZ", "CRSP v2", "CRSP flat file format 2.0", "crsp.dsf_v2 / msf_v2", "StkDlySecurityData", "StkMthSecurityData", "StkSecurityInfoHist", "stocknames_v2", "DlyRet / MthRet / DlyPrc / MthPrc", "SHRCD or EXCHCD equivalent in new CRSP", "SIZ to CIZ migration", "CRSP data after 2024", "CRSP delisting returns", "CRSP cumulative adjustment factors", "CRSP index INDNO / INDFAM", or any CRSP stock/index query where the legacy SIZ column names no longer exist.
development
Use when linking or deduping datasets by entity name rather than a shared key — 'fuzzy match', 'fuzzy name matching', 'entity resolution', 'record linkage', 'match company/person names', 'dedupe entity names', 'name-based join', 'bridge identifiers' (CIK ↔ permno ↔ gvkey ↔ wficn ↔ EIN ↔ personid), or any use of char n-gram TF-IDF, cosine similarity on names, `sparse_dot_topn`, or RapidFuzz at scale.
development
Use when building a publication-quality table in Python — 'regression table', 'results table', 'summary statistics table', 'etable', 'coefplot', 'great_tables', 'GT', 'gt table', 'format a table for the paper', 'export table to LaTeX/HTML', significance stars, spanners, or column formatting for a table headed into a paper, slide deck, or notebook.