Communityコーディング&開発github.com

GreenWich-art/agent-skills

学術論文のフォーマット規定(小三黒体の1級見出し、四号黒体の2級見出し、小四宋体の1.5倍行間、三線表、中西混植時のTimes New Roman、統計量の斜体など)に従い、Markdownや既存のdocxファイルを一括整形します。python-docxを使用して直接docxを生成し、段落ごとの挿入は行いません。

agent-skills とは?

このスキルは、学術論文の投稿規定に準拠したdocxファイルを生成・整形するための強力なツールです。主な機能として、Markdownドキュメントや既存のdocxファイルを対象に、指定されたフォーマット(例:1級見出しは小三黒体、2級見出しは四号黒体、本文は小四宋体の1.5倍行間、中西混植ではTimes New Romanを適用、統計量は斜体)を一括適用します。特に、三線表の正確な生成と統計量の斜体処理において、細かい制御が可能です。python-docxライブラリを直接操作することで、段落単位の挿入APIでは実現できない、テーブル境界線やrunレベルのフォント設定を正確に処理します。このスキルは、Claude Code、Coder、Cursor、CodexなどのAIエージェントと連携して使用することを想定しており、ユーザーが「学術フォーマットで整形して」「三線表を使って」「1.5倍行間で」などの自然言語による指示を出すだけで、複雑なフォーマット変換を自動化します。内部では、フォントファミリーの4スロット(ascii、hAnsi、eastAsia、cs)を適切に設定し、空段落の禁止(段落間隔で調整)、不要な太字の抑制、直引用符から曲引用符への変換、Word編集後の断片化したrunへのフォント補完など、実運用で遭遇する多くの問題を解決するための実践的なノウハウが組み込まれています。また、検証環境がない場合でもXMLレベルでの検証が可能であり、生成後のチェックリスト(空段落ゼロ、太字ゼロ、三線表の妥当性など)に従って品質を保証します。ただし、大学の課程論文や党政機関の公文書(GB/T 9704)など、異なるフォーマット基準が適用される文書には使用できません。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/GreenWich-art/agent-skills/tree/HEAD/skills/docx-academic-format

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Academic Paper DOCX Format Restyler

When to Use

  • When you need to convert a Markdown analysis report or table into a DOCX file that conforms to journal submission guidelines.
  • When you need to batch-apply mixed Chinese-Western fonts, three-line tables, and multi-level heading font sizes and spacing.
  • When paragraph-by-paragraph insertion APIs cannot control three-line table borders, run-level rFonts, or italic splitting—use this skill instead.

Chinese Font Size → Point Value

Font SizePoints
Sanhao (三号)16
Xiaosan (小三)15
Sihao (四号)14
Xiaosi (小四)12
Wuhao (五号)10.5

Default specification (overridable per target journal/school requirements):

  • Level 1 heading: Xiaosan SimHei
  • Level 2 heading: Sihao SimHei
  • Body text: Xiaosi SongTi, 1.5 line spacing
  • All Western text: Times New Roman
  • Tables: Wuhao SongTi

Key Implementation Points (Lessons Learned)

1. Three-Line Table Borders

The w:sz unit for w:tblBorders is 1/8 of a point:

  • Top/Bottom 1.5pt → sz=12
  • Middle line (below header) 1.0pt → sz=8
  • Vertical lines must be explicitly set to val="none", otherwise Word draws default vertical lines.

The line below the table header must be applied per-cell via row.cells[i] with w:tcBorders/w:bottom; relying solely on insideH in tblBorders is unreliable in some renderers.

2. cell.text = '' Leaves an Empty Unformatted Run

To clear a cell, use:

p = cell.paragraphs[0]
for r in list(p.runs):
    r._element.getparent().remove(r._element)

Otherwise runs[0] remains as an empty run without rPr, causing false positives in subsequent font checks.

3. Mixed Chinese-Western Text Requires Setting All 4 Font Slots

rFonts.set(qn('w:ascii'), 'Times New Roman')
rFonts.set(qn('w:hAnsi'), 'Times New Roman')
rFonts.set(qn('w:eastAsia'), 'SimSun')   # Chinese font
rFonts.set(qn('w:cs'), 'Times New Roman')

Omitting eastAsia causes Chinese characters to fall back to the default font.

4. Italics Require Run Splitting

Statistics symbols (P<0.001, OR=2.17, CI, β, P-value) must be split into separate runs to apply italic formatting individually. The regex order matters: match P-value with \bP(\s*值)\b as a whole; first match P\s*[<>=]\s*[\d.]+, then match isolated P; otherwise P=0.06 would be split into P + =0.06.

5. "Blank Line" = Paragraph Spacing, Not an Empty Paragraph

Never use carriage returns (empty paragraphs) to create a "blank line." Empty paragraphs cause:

  • Extra blank lines that are hard to clean up during subsequent editing.
  • Unpredictable white space when printing or converting to PDF.
  • Combined spacing from space_before/space_after values getting out of control.

Correct approach: use space_before / space_after (in points):

ScenarioImplementation
Level 1 heading: "one blank line above and below"space_before = Pt(Xiaosi font size * 1.5), space_after = same value
Level 2 heading: "one blank line above"space_before = Pt(Xiaosi font size * 1.5), space_after = Pt(0)
Level 3+ headingsNo spacing
Body textspace_before = Pt(0), space_after = Pt(0)
Blank line between figure/table and body textApply space_before/after on the paragraph containing the figure/table, do not insert an empty paragraph

Reference values: Xiaosi (12pt) blank line ≈ 18pt; Wuhao (10.5pt) blank line ≈ 15.75pt.

Verification method:

sum(1 for p in doc.paragraphs if not p.text.strip()) == 0

— A well-formed document should have zero empty paragraphs.

6. Forbid Automatic Bold

Never apply bold to text unless the user explicitly requests it.

This is a common pitfall: Markdown's **text** is a source emphasis marker, not a formatting instruction. Rendering it as bold in Word is equivalent to arbitrarily adding emphasis to the original text.

Correct approach:

  • **text** → extract only the text content, do not bold.
  • To create sub-headings, use separate paragraphs with the target font/size, not bold for hierarchy.
  • Visual hierarchy should only come from: font (SimHei/KaiTi), font size, paragraph spacing before/after, and numbering.

Also prohibited:

  • Italics: do not use except for specified statistics/symbols.
  • Underline, emphasis marks, colored text, character scaling/kerning: leave untouched unless requested by the user.

After conversion, self-check:

# Should have no bold runs unless user-requested
bold = [r.text for p in doc.paragraphs for r in p.runs if r.font.bold]

Whether table headers are bold depends on user requirements; this skill defaults to headers not bold (differentiated by font size + three-line table).

7. Level 3 and Below Headings: No Blank Lines

Only level 1 and 2 headings get paragraph spacing (before/after). Level 3 and below: no spacing, no bold.

Scripts

ScriptPurpose
scripts/tri_line_table.pyThree-line table borders (includes verify_table_borders() self-check)
scripts/fmt_lib.pyFont/spacing/bold segment parsing/cell style utility library
scripts/fix_italic.pyStatistical italic splitting (in-place, does not rebuild runs)
scripts/fix_spacing2.pyMixed Chinese-English spacing and symbol spacing correction (in-place, does not rebuild runs)

Dependency: pip install python-docx

fmt_lib.parse_bold_segments(text, allow_bold=False) defaults to discarding but not rendering ** markers; only pass allow_bold=True when the user explicitly requests bold.

Execution order for formatting corrections on an existing DOCX (order is critical):

python3 scripts/fix_italic.py  target.docx   # First: split italics
python3 scripts/fix_spacing2.py target.docx  # Second: fix spacing

Reversing the order causes spacing rules to incorrectly rejoin already-split symbols.

Verification Checklist (Mandatory After Generation)

  1. Number of empty paragraphs == 0 — highest priority: sum(1 for p in doc.paragraphs if not p.text.strip())
  2. Number of bold runs == 0 (unless requested by user) — [r.text for p in doc.paragraphs for r in p.runs if r.font.bold] must be empty; also check inside tables
  3. Level 1 headings: sz==15 and eastAsia==SimHei, space_before==space_after==18pt
  4. Level 2 headings: sz==14, space_before==18pt
  5. Body text: sz==12, eastAsia==SimSun, line_spacing==1.5
  6. All runs: ascii/hAnsi==Times New Roman
  7. Number of italic runs > 0 and content is statistical symbols (this is the only allowed special formatting)
  8. Three-line tables: verify each table with verify_table_borders(table); all should return (True, [])
  9. Table title: Wuhao SimHei, centered, no punctuation at the end of the sentence.
  10. All runs inside tables: SongTi + 10.5pt
  11. Body paragraph alignment == JUSTIFY; headings and table titles remain unchanged.
  12. Space before percent sign: 33 % not 33%
  13. No space between symbol and Chinese character: 30余次; space between symbol and digit: ≥ 10 小时; P < 0.05

One-shot self-check script:

import sys; sys.path.insert(0, '<skill>/scripts')
from tri_line_table import verify_table_borders
from docx import Document
d = Document('out.docx'); ps = d.paragraphs
assert sum(1 for x in ps if not x.text.strip()) == 0, 'Empty paragraph exists'
assert not [r for x in ps for r in x.runs if r.font.bold], 'Bold exists'
assert not [r for t in d.tables for row in t.rows for c in row.cells
            for r in c.paragraphs[0].runs if r.font.bold], 'Bold exists in tables'
for i, t in enumerate(d.tables, 1):
    good, prob = verify_table_borders(t)
    assert good, f'Table {i} three-line border non-compliant: {prob}'
print('All checks passed')

When There's No Visual Verification Environment

When LibreOffice/Word is not available to visually verify three-line tables by converting to PDF, use XML-level checks instead (Checklist items 1–9); this reliably covers font size, font, borders, and spacing.

Supplementary: Precise Specification of Three-Line Tables

Only 3 lines:

PositionPoint Valuew:sz
Header row (top border)1.512
Header row (bottom border)1.08
Last row (bottom border)1.512
All other borders (including all middle rows and vertical lines)Noneval="none"

Critical: Do not rely solely on insideH in tblBorders. Table-level borders can be overridden by cell-level tcBorders. Once a cell has a bottom value, the cell-level value takes precedence. Must set per-cell explicitly:

  1. Set all six items in table-level tblBorders to none.
  2. Set all four sides of tcBorders for all rows to none.
  3. Header row cells: top=('single',12) + bottom=('single',8)
  4. Last row cells: bottom=('single',12)

clear_row_borders() must be called on every row, not just the header and last row—otherwise middle rows retain residual lines.

Supplementary: Chinese Quotation Mark Replacement

Markdown's " is a straight quotation mark; after conversion to DOCX, it must be replaced in pairs with \u201c / \u201d:

dq_index = 0   # Must maintain a continuous count across runs, not reset per run
for r in p.runs:
    for ch in r.text:
        if ch == '"':
            out.append('\u201c' if dq_index % 2 == 0 else '\u201d')
            dq_index += 1

Only modify r.text; do not touch rPr → font/size/italic formatting is preserved. After replacement, verify: total " count == 0, \u201c count == \u201d count, and paired per paragraph (paragraph-by-paragraph balance is required, not just document-wide).

Supplementary: Word Editing Produces Fragmented Runs

When users manually edit in Word, paragraphs can be split into multiple runs, some of which (separated -, single characters) lack rFonts and fall back to default fonts. After fixing quotation marks/borders, scan for this:

rf = r._element.rPr.rFonts if r._element.rPr is not None else None
if rf is None or rf.get(qn('w:eastAsia')) is None:  # → needs patching

Patch by referring to the first run in the paragraph that already has font settings, inheriting its rFonts/sz/b.

Important Workflow Reminder

If a user has manually edited the document in Word, never regenerate the entire document—this would overwrite their changes. Correct approach: read the existing DOCX → perform targeted in-place XML modifications → save. Backup before modifying: cp xxx.docx /tmp/backup.docx.

Italic Specification

Unique Criterion: Whether the character is a variable or symbol in mathematics/statistics

CategoryItalic?Example
Statistical significance PItalicP = 0.04, P < 0.001
Significance level αItalicα = 0.05
Test statistics F, Z, H, χ², t, rItalicF = 4.52, χ² = 8.31
Special letters (gene symbols, methylation β values, etc.)Italicβ
OR, CI, RR, HR, SD, SE, AUCNot italicOR = 3.14, 95% CI
Multi-letter abbreviations (BMI, OGTT, FPG…)Not italicBMI, OGTT
Chinese charactersNot italic值, 为

⚠️ Most Error-Prone: In "P值", Only P Is Italic

✗ italic 'P值'         ← "值" incorrectly italicized
✓ italic 'P' + roman '值'
✓ italic 'P' + roman '值为' + ...

P 值, P值, P 值为 0.07 — always only P is italic; the following Chinese characters are all roman.

Three Golden Rules of Italic Splitting (Learned the Hard Way)

  1. Never rebuild runs. Using "character stream reassembly" to fix formatting will lose all rFonts/sz/b, clear three-line table borders, and misalign italic markers into fragments. Only modify run.text; never delete or create <w:r> elements.
  2. Splitting must use copy.deepcopy(run._element) to preserve all formatting attributes; insert position: parent.insert(index+1, el) (immediately adjacent to the original run). Using append moves the copy to the end of the paragraph, causing incorrect ordering (e.g., PP). Copy text = lead + rest + trail (without stat), original run text = lead + stat.
  3. run.text = x does not clear existing <w:t> nodes—on a deepcopy element, it appends. Must first el.remove(child) to delete all w:t/w:br/w:tab/w:cr; also, remove w:i/w:iCs before setting text; doing it in reverse order also causes errors.

See example implementation in scripts/fix_italic.py.

Mixed Chinese-English Text and Symbol Spacing

Basic Rules

ScenarioRuleExample
Chinese ↔ digit/letter/punctuationNo space在30余次未校正检验的背景下, 但Table 1显示
Chinese ↔ ChineseNo space研究目的
Between English wordsAdd spaceTable 1
Inside mathematical expressionsSpace between letter/digit and operatorP = 0.04, BMI < 18.5
Mathematical expression ↔ ChineseAdd spaceP < 0.05 为阈值

Spacing Between Symbols and Digits/Letters/Chinese (Error-Prone)

CombinationRuleExample
Symbol ↔ DigitSpace33 %, 87.3 %, P = 0.04
Symbol ↔ English word/letterSpaceTable 1; α = 0.05
Symbol ↔ Chinese characterNo space30余次, ≥10小时 (symbol adjacent to Chinese character)

Error-prone point: 30 余次 (wrong, extra space between symbol and Chinese) vs 30余次 (correct). Operator symbols (≥ ≤ = < >) must be spaced from digits, but no space between the symbol and an immediately following Chinese character.

Percent Sign

33 %: space between digit and %. This is required by scientific paper formatting standards; do not write 33%.

See example implementation in scripts/fix_spacing2.py (includes fix_spacing_in_run).

Body Paragraph Alignment

Body paragraphs use justified alignment — Word's JUSTIFY (Cmd+J / Ctrl+J), not DISTRIBUTE.

from docx.enum.text import WD_ALIGN_PARAGRAPH
p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY

Apply only to body paragraphs; keep the original alignment of the following, do not modify:

  • All headings—usually left-aligned
  • Table titles—centered
  • Table cell content—as needed (left-aligned or centered)

⚠️ Three Iron Rules (Execution Order and Verification)

Execution Order

python3 scripts/fix_italic.py  target.docx   # First: split italics
python3 scripts/fix_spacing2.py target.docx  # Second: fix spacing

Verification (Mandatory, Each Step Required)

import re
norm = lambda s: re.sub(r'\s', '', s)
# ① Zero text loss—prevent missing/duplicate characters
assert all(norm(a.text) == norm(b.text)
           for a, b in zip(original_doc.paragraphs, new_doc.paragraphs))
# ② Italic runs must contain only statistical symbols themselves (P/α/β/F/Z/H/χ/t/r), must NOT include:
#    - operators or digits: [=<>≤≥0-9]
#    - Chinese characters ('值' in 'P值' must be roman)
#    - abbreviations like OR/CI/RR
for p in new_doc.paragraphs:
    for r in p.runs:
        if r.font.italic and r.text.strip():
            t = r.text.strip()
            assert not re.search(r'[=<>≤≥0-9\u4e00-\u9fff]', t), f'Italic contains operator/digit/Chinese: {t!r}'
            assert t.split(' ')[0] not in ('OR','CI','RR','HR','SD','SE','AUC'), f'Abbreviation should not be italic: {t!r}'
# ③ Body paragraphs must be justified
from docx.enum.text import WD_ALIGN_PARAGRAPH
assert any(p.alignment == WD_ALIGN_PARAGRAPH.JUSTIFY for p in new_doc.paragraphs)
# ④ Chinese quotation marks matched in pairs
assert sum(p.text.count('\u201c') for p in new_doc.paragraphs) == \
       sum(p.text.count('\u201d') for p in new_doc.paragraphs)

⚠️ Highest Priority Iron Rules (Violation = Rework)

  1. "Blank line" must only use paragraph spacing (space_before/space_after), never carriage returns/empty paragraphs.
  2. Never apply bold to text, unless the user explicitly requests bold in their requirements. Markdown's **text** is a source emphasis marker, not a formatting instruction—remove the marker only, do not bold.
  3. Formatting not requested by the user (underline, emphasis marks, colored text, char spacing, character scaling) must not be touched.
  4. If the user has manually edited the document, do not regenerate the entire document; only read the existing file and modify XML in-place.

Visual hierarchy can only come from: font (SimHei/KaiTi), font size, paragraph spacing (before/after), and numbering—not bold.

Precautions When Trimming Text in Body/Tables

When trimming text content in a user-modified DOCX:

Iron Rule: Write Merged Content to the First Run, Clear the Rest

def set_paragraph_text(p, text):
    runs = p.runs
    if not runs: return False
    runs[0].text = text          # Formatting retained in the first run
    for r in runs[1:]:
        r.text = ''              # ⚠️ Must clear, otherwise old text remains causing duplication
    return True

Follows the "don't rebuild runs" principle—only modify run.text, never delete/create <w:r>.

Locating Tables: Follow Document Stream Order, Don't Use doc.paragraphs Index

When tables are embedded within paragraphs, doc.paragraphs[i] indices do not correspond to table positions. Must traverse the body stream:

from docx.table import Table
from docx.text.paragraph import Paragraph
W = '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
seq = []
for c in doc.element.body.iterchildren():
    if c.tag == W+'p':   seq.append(('p', Paragraph(c, doc)))
    elif c.tag == W+'tbl': seq.append(('t', Table(c, doc)))

Two Pitfalls When Adding/Deleting Rows

  1. table.rows re-parses XML on every access — after deleting a row, using rows[ri] causes an index out-of-bounds error. Take a snapshot first: rows = list(table.rows), then delete from the end backward.
  2. A cloned row loses the last row's bottom border — after cloning the last row to fill, the three-line table's bottom line becomes nil. Must reapply the bottom border (sz=12) to the last row at the end.

⚠️ When Detecting Borders, Don't Check Only for none

Word's own three-line tables use w:val="nil" for middle rows, not "none". To determine "no line," accept both:

assert tv in ('nil','none') and bv in ('nil','none')

Checking only for none produces false positives for "border damage" when the detection logic itself is wrong.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

GreenWich-art/agent-skills

桌面 GUI 操作的统一编排入口。当用户要求操作一个只有图形界面的应用(改设置、点按钮、填表单、操作无 CLI/连接器的软件)时使用此 skill。提供四级能力:①路由决策——判断任务该走连接器、浏览器控制、Office 技能、命令行还是 computer use 桌面接管;②授权引导——检测并引导用户完成 macOS 辅助功能/屏幕录制权限授权,处理授权不生效等常见坑;③任务派发与验证——按目标/边界/失败处理三段式描述派发 GUI 任务,并以最终截图为准确认结果;④AX 兜底层——内置 axctl 工具做元素级无障碍读写(AXPress 语义点击,不碰鼠标不抢焦点),适用于 computer use 不可用或轻量场景。台前调度全场景实测(macOS 15 + 27.0.1 复检)。触发词:操控电脑、操作某个软件、点某个按钮、GUI 操作、电脑设置。

GreenWich-art/agent-skills

参考文献的 GB/T 7714-2015 著录规范化,以及 URL / DOI / PMID / PMC 链接的 可访问性批量核验与"假失效"识别。 触发场景: - 论文 / 综述 / 作业要交,需要核对参考文献格式 - "帮我按国标改一下参考文献" - 要交付一份文献清单,需要确认链接没死 - 已经有一堆 links,要批量验证哪些还能打开 含一个可复用脚本 `scripts/check_refs.py`,能自动判别 URL / DOI / PMID / PMC 并并发核验,且能区分「真死」与「被反爬」——后者不该判为失效。 不适用:从零生成一份带引文的正文(那是写作任务); Zotero 样式定制(见正文第六节,按需手工改 CSL)。

GreenWich-art/agent-skills

Local OCR using the macOS Vision framework. Triggers: OCR, 识别图片文字, 提取截图内容, 扫描件转文字, 图片转文字, 扫描版PDF转文字, read text from image/screenshot/photo/scanned PDF. Local-first and offline; prefer it over cloud OCR whenever data is sensitive or the machine is offline.

GreenWich-art/agent-skills

Download open-access biomedical article PDFs from PMC with offline Proof-of-Work solving. Triggers: 下载文献PDF, PMC PDF, 403/404 on PDF link, Preparing to download, reCAPTCHA page, OA full text, supplementary files, download paper PDF.

関連スキル