
Polish Language
- 38 installs
- 236 repo stars
- Updated August 3, 2026
- aperivue/medsci-skills
Polish-language is a Claude Code skill that lints academic English consistency and applies gated, style-only ESL clarity fixes to medical manuscripts.
About
Polish-language is a Claude skill that lints academic English consistency and does ESL clarity polish for medical manuscripts. A deterministic linter flags seven families of defects (abbreviations, US/UK spelling, en-dash ranges, p-value case, hyphenation, small numbers, unit spacing) with line numbers, then applies user-approved, style-only fixes. It never changes numbers, citations, or scientific meaning.
- Deterministic linter flags 7 families of consistency defects with line numbers
- Gated, style-only fixes that never alter numbers, citations, or meaning
- ESL clarity pass preserving formal academic register
Polish Language by the numbers
- 38 all-time installs (skills.sh)
- Ranked #884 of 1,879 Documentation skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
polish-language capabilities & compatibility
- Capabilities
- manage refs · peer review · meta analysis
- Use cases
- documentation · code review · copywriting
What polish-language says it does
Run the bundled deterministic linter — it reports, never edits:
This skill **never** rewrites scientific claims, changes numeric values, edits citations, or judges study quality.
npx skills add https://github.com/aperivue/medsci-skills --skill polish-languageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 38 |
|---|---|
| repo stars | ★ 236 |
| Last updated | August 3, 2026 |
| Repository | aperivue/medsci-skills ↗ |
What it does
A non-native English author uses it to catch and fix mechanical consistency issues before circulating or submitting a manuscript.
Who is it for?
A pre-submission copy-edit and ESL clarity pass on a medical manuscript.
Skip if: Removing AI writing tells (humanize), restructuring content (write-paper), or reference formatting (manage-refs).
When should I use this skill?
You need a house-style consistency check or an ESL clarity pass before circulation or submission.
What you get
A deterministic consistency report plus, after user approval, a style-only polished manuscript with a change log.
- Deterministic consistency report
- Style-only polished revision
- Change log
By the numbers
- 7 defect families flagged
- 10 seeded issues in the challenge card
Files
Polish-Language Skill
You help a medical researcher tighten a manuscript's mechanical language consistency and clarity before circulation or submission — the copy-editor pass that content-focused skills skip. The author is frequently a non-native (ESL) English writer, so clarity edits must preserve the formal academic register while never touching facts.
Communication Rules
- Manuscript content and edits in English.
- Conversation with the user may be in Korean.
- Report issues first; only edit after the user approves (see gates below).
Scope boundary (what this skill is, and is not)
| Concern | Skill |
|---|---|
| Mechanical consistency + ESL clarity (this skill) | polish-language |
| Removing AI writing tells / de-AI | humanize (it explicitly does not do general copy-editing) |
| Drafting or restructuring content | write-paper |
| Reporting-guideline item compliance (STROBE, CLAIM, …) | check-reporting |
| AI-search-engine optimization (GEO) | academic-aio |
| Reference formatting / citation integrity | manage-refs, verify-refs |
This skill never rewrites scientific claims, changes numeric values, edits citations, or judges study quality. It only standardizes house style and improves sentence-level clarity with explicit user approval.
Inputs / Outputs
- Input: a manuscript or section (Markdown / plain text).
- Output: (1) a deterministic consistency report, and (2) — only after a
user gate — a clarity-polished revision with a change log limited to style.
Workflow
Phase 1: Deterministic consistency lint (no LLM judgement)
Run the bundled deterministic linter — it reports, never edits:
python3 scripts/lint_consistency.py path/to/manuscript.md
# add --strict to exit non-zero when any issue is found (CI / pre-submission gate)It flags seven families, each with line numbers and a per-category + total count:
1. Abbreviations — used-before-defined, defined-but-unused, defined-twice, used-but-never-defined (define-once discipline). 2. Spelling — mixed US/UK variants (analyze/analyse, tumor/tumour, …); reports the minority side against the document's dominant variant. 3. Numeric ranges — hyphen between numbers where an en-dash belongs (5-10 → 5–10). 4. p-values — mixed P/p case; impossible P = 0.000. 5. Hyphenation / terminology — variant forms of one term (follow-up / followup / "follow up"). 6. Small numbers — single digits 1–9 written as digits in prose. 7. Units — missing space between value and unit (5mg → 5 mg).
Present the report to the user. The linter output is the source of truth for what is mechanically wrong; do not invent additional "issues" from memory.
Phase 2: Triage with the user (gate)
Walk the user through the report. Some flags are author choices (a journal may mandate UK spelling, or digits for all numbers). User approval is required before any edit — confirm per category which to apply and which to keep. Record the decisions; do not auto-apply.
Phase 3: Apply mechanical fixes (style-only)
For each approved category, apply the deterministic fix with Edit:
- standardize spelling to the chosen variant,
- replace numeric-range hyphens with en-dashes,
- normalize
P/pand fixP = 0.000to the reported inequality, - unify hyphenation, spell out small numbers, add value/unit spaces,
- define each abbreviation once at first use; remove redundant redefinitions.
Re-run lint_consistency.py after editing — the count should drop to the issues the user chose to keep. This re-run is the verification gate.
Phase 4: ESL clarity polish (optional, gated, style-only)
If the user requests a clarity pass, improve readability sentence by sentence while preserving meaning, register, numbers, and citations:
- split run-on sentences; fix article (a/an/the) and preposition usage;
- correct subject–verb agreement and awkward non-native phrasings;
- prefer active voice only where it does not change emphasis or claims.
Show each proposed change as a before/after diff and get user review before writing. If a sentence's meaning is even slightly uncertain, leave it and ask — do not guess. Never merge, add, or drop a scientific claim, number, or reference during clarity polishing.
Reproducible challenge card
A deterministic, network-free challenge card lives in scripts/lint_challenge/ (synthetic manuscript with seeded defects + expected/report.txt + verify.sh):
bash scripts/lint_challenge/verify.sh # PASS = 10 seeded issues across 7 categoriesWhat This Skill Does NOT Do
- Does not rewrite or generate scientific content, claims, or conclusions.
- Does not change any numeric value, statistic, or result.
- Does not add, remove, or reformat citations or references.
- Does not assess reporting-guideline or journal compliance.
- Does not remove AI writing patterns (use
humanize). - Does not translate between languages.
- Applies no edit without explicit user approval (gates in Phases 2–4).
Anti-Hallucination
- The deterministic linter (
lint_consistency.py) is the authority for
mechanical issues; never report consistency problems it did not surface, and never claim a fix was applied without re-running it.
- Clarity edits are constrained to wording. Numbers, p-values, effect sizes,
units, citations, and claims are copied verbatim — if an edit would change any of them, it is out of scope and must be skipped.
- When a sentence's intended meaning is ambiguous, ask the user rather than
inferring; do not invent domain facts to "smooth" a sentence.
- Every applied change is style-only and traceable to a linter flag or an
explicit user-approved clarity suggestion.
# Consistency Lint Report
## Abbreviations
- L5: "PET" defined but never used
- L7: "DKA" used 2x but never defined
## Spelling (US/UK consistency)
- L10: "analyze" family: US spelling here (document is predominantly UK)
## Numeric ranges
- L9: "5-10" — use en-dash for numeric range (5–10)
## p-values
- L12: "p = 0.03" — inconsistent case (document uses "P")
- L13: "P = 0.000" — a p-value cannot be exactly 0; report as P < .001
## Hyphenation / terminology
- L15: inconsistent forms of "follow-up" (multiple variants present)
- L17: inconsistent forms of "health care" (multiple variants present)
## Small numbers in prose
- L7: "3 patients" — spell out single-digit numbers in prose
## Units
- L16: "5mg" — insert a space between value and unit (5 mg)
---
Summary: 10 issue(s) across 7 category(ies).
Synthetic Study Manuscript
We performed magnetic resonance imaging (MRI) and computed tomography (CT) scans. The MRI was reviewed; CT findings were recorded. We also obtained positron emission tomography (PET) images.
DKA occurred in 3 patients and DKA resolved quickly.
Tumour size ranged from 5-10 cm across the cohort. We analyse the data and then analyze again.
Significance was set at p = 0.03 and P = 0.001. One result showed P = 0.000 unexpectedly.
Patients had regular follow-up, though some had no followup at all. The dose was 5mg daily. Healthcare access and health care equity were assessed.
Challenge card — Consistency linting (polish-language)
Problem
Medical manuscripts routinely ship mechanical inconsistencies that copy-editors catch but that content-focused passes ignore: an abbreviation used before it is defined (or never defined), mixed US/UK spelling, hyphen-vs-en-dash numeric ranges, mixed P/p case, variant hyphenation of the same term, single-digit numbers written as digits in prose, and missing spaces between a value and its unit. /humanize explicitly does not do general copy-editing (it only removes AI tells), and /check-reporting checks guideline items, not house style — so none of the existing skills caught these.
What the new gate does
scripts/lint_consistency.py deterministically reports (never rewrites) seven families of inconsistency with line numbers and a per-category + total count. It changes no text, numbers, or citations — it is advisory input for a human/LLM polish pass.
Fixture (synthetic only — no real manuscript/PII)
fixture/manuscript.md seeds exactly one or more defect per category: abbreviation (PET unused, DKA undefined), spelling (analyse/analyze in a UK-dominant doc), numeric range (5-10), p-values (p vs P, impossible P = 0.000), hyphenation (follow-up/followup, healthcare/health care), small number (3 patients), unit (5mg).
Expected
expected/report.txt — 10 issues across 7 categories.
Baseline vs new gate
| Baseline (humanize / check-reporting) | New consistency linter | |
|---|---|---|
| Abbreviation define-once | not checked | reported |
| US/UK spelling drift | not checked | reported (minority side) |
| en-dash numeric ranges | not checked | reported |
P/p case + P = 0.000 | not checked | reported |
| hyphenation variants | not checked | reported |
| value/unit spacing | not checked | reported |
Verifier (deterministic, no network)
bash verify.shAcknowledgement
The "fixture + expected + deterministic verifier" packaging is inspired by public reproducible-audit layouts such as EinsteinArena (design inspiration only; no code, solutions, or data were copied).
#!/usr/bin/env bash
# Deterministic verifier for the consistency-linter challenge card.
# Runs lint_consistency.py on a synthetic manuscript with seeded defects and
# diffs against expected/report.txt. Exit 0 = match.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
LINTER="$HERE/../lint_consistency.py"
actual="$(python3 "$LINTER" "$HERE/fixture/manuscript.md")"
if diff -u "$HERE/expected/report.txt" <(printf '%s\n' "$actual"); then
echo "PASS: linter report matches expected (10 seeded issues across 7 categories)."
else
echo "FAIL: linter output drifted from expected/report.txt" >&2
exit 1
fi
#!/usr/bin/env python3
"""
Deterministic consistency linter for medical manuscripts (polish-language).
Flags mechanical, style-guide-level inconsistencies that copy-editors catch and
that AI-tell removal (`/humanize`) deliberately does NOT touch:
1. Abbreviations — defined-once, used-before-defined, defined-but-unused,
used-but-never-defined
2. Spelling — mixed US/UK variants (analyze/analyse, tumor/tumour, …)
3. Numeric ranges — hyphen between numbers where an en-dash belongs (5-10)
4. p-values — mixed P/p case; impossible "P = 0.000"
5. Hyphenation — variant forms of the same term (follow-up/followup/…)
6. Small numbers — single digits 1–9 written as digits in prose
7. Units — missing space between value and unit (5mg)
It NEVER rewrites text, changes numbers, edits citations, or judges scientific
content — it only reports. All output is deterministic (stable ordering), so it
doubles as a reproducible challenge-card verifier.
Usage:
python3 lint_consistency.py manuscript.md
python3 lint_consistency.py manuscript.md --strict # exit 1 if any issue
"""
import argparse
import re
import sys
from pathlib import Path
# --------------------------------------------------------------------------- #
# Config (fixed, deterministic)
# --------------------------------------------------------------------------- #
# Abbreviations so ubiquitous they need no in-text definition.
ABBR_WHITELIST = {
"AI", "DNA", "RNA", "USA", "UK", "EU", "WHO", "FDA", "HIV", "AIDS",
"ID", "OK", "PDF", "URL", "HTML", "API", "AND", "OR", "NOT", "ROC",
}
# US ↔ UK spelling families: canonical "us" form -> regex matching both.
SPELLING_FAMILIES = [
("analyze", r"\banalys[ei]([sdz]|zing|sing|zed|sed)?\b", r"analy(s)"),
("organize", r"\borganis[ei]?\w*\b", r"organis"),
("characterize", r"\bcharacteris\w*\b", r"characteris"),
("optimize", r"\boptimis\w*\b", r"optimis"),
("randomize", r"\brandomis\w*\b", r"randomis"),
("standardize", r"\bstandardis\w*\b", r"standardis"),
("tumor", r"\btumour(s)?\b", r"tumour"),
("color", r"\bcolour(s|ed|ing)?\b", r"colour"),
("behavior", r"\bbehaviour(s|al)?\b", r"behaviour"),
("favor", r"\bfavour(s|ed|able)?\b", r"favour"),
("center", r"\bcentre(s|d)?\b", r"centre"),
("labeled", r"\blabelled\b", r"labelled"),
("modeling", r"\bmodelling\b", r"modelling"),
("fetal", r"\bfoetal\b", r"foetal"),
]
# For each family we also need the US-variant regex to count it.
SPELLING_US = {
"analyze": r"\banaly(z|ze|zed|zing|zes)\w*\b",
"organize": r"\borganiz\w*\b",
"characterize": r"\bcharacteriz\w*\b",
"optimize": r"\boptimiz\w*\b",
"randomize": r"\brandomiz\w*\b",
"standardize": r"\bstandardiz\w*\b",
"tumor": r"\btumor(s)?\b",
"color": r"\bcolor(s|ed|ing)?\b",
"behavior": r"\bbehavior(s|al)?\b",
"favor": r"\bfavor(s|ed|able)?\b",
"center": r"\bcenter(s|ed)?\b",
"labeled": r"\blabeled\b",
"modeling": r"\bmodeling\b",
"fetal": r"\bfetal\b",
}
# Hyphenation/terminology variant families (all lowercase match, word-ish).
HYPHEN_FAMILIES = [
("follow-up", [r"\bfollow-up\b", r"\bfollowup\b", r"\bfollow up\b"]),
("health care", [r"\bhealthcare\b", r"\bhealth care\b", r"\bhealth-care\b"]),
("long-term", [r"\blong-term\b", r"\blongterm\b", r"\blong term\b"]),
("well-being", [r"\bwell-being\b", r"\bwellbeing\b"]),
("decision-making", [r"\bdecision-making\b", r"\bdecision making\b"]),
("COVID-19", [r"\bCOVID-19\b", r"\bCOVID19\b", r"\bCovid-19\b"]),
]
UNIT_TOKENS = (
"mg", "kg", "mL", "ml", "mm", "cm", "mcg", "ug", "mmHg", "mGy", "mSv",
"mmol", "mol", "IU", "mGy", "Gy", "Sv", "Hz", "kPa",
)
UNIT_RE = re.compile(
r"(?<![\w.])(\d+(?:\.\d+)?)(" + "|".join(sorted(UNIT_TOKENS, key=len, reverse=True)) + r")(?![\w])"
)
ABBR_DEF_RE = re.compile(r"\(([A-Z][A-Z0-9]{1,5})\)") # (CT), (MRI), (DKA), (COVID)
ABBR_USE_RE = re.compile(r"(?<![A-Za-z])([A-Z]{2,6})(?![A-Za-z])") # standalone caps token
NUM_RANGE_RE = re.compile(r"(?<![\w/.\-])(\d+(?:\.\d+)?)-(\d+(?:\.\d+)?)(?![\w/.\-])")
PVAL_RE = re.compile(r"(?<![A-Za-z])([Pp])\s*([=<>])\s*(0?\.\d+|\d+\.\d+|\.\d+)")
SMALL_NUM_RE = re.compile(r"(?<![\w.=<>+\-/])([1-9])\s+([a-z]{3,})")
# --------------------------------------------------------------------------- #
# Checks (each returns list[(line, message)])
# --------------------------------------------------------------------------- #
def check_abbreviations(lines):
out = []
defs = {} # abbr -> first definition line
uses = {} # abbr -> list of (line) excluding the def-parenthesis line
def_lines = {} # abbr -> set of lines where defined
for i, line in enumerate(lines, 1):
for m in ABBR_DEF_RE.finditer(line):
ab = m.group(1)
defs.setdefault(ab, i)
def_lines.setdefault(ab, set()).add(i)
for i, line in enumerate(lines, 1):
# mask the "(ABBR)" definition spans so they don't count as bare uses
masked = ABBR_DEF_RE.sub(lambda m: " " * len(m.group(0)), line)
for m in ABBR_USE_RE.finditer(masked):
ab = m.group(1)
uses.setdefault(ab, []).append(i)
all_abbr = set(defs) | {a for a in uses}
for ab in sorted(all_abbr):
if ab in ABBR_WHITELIST:
continue
u = uses.get(ab, [])
d = defs.get(ab)
if d is None:
if len(u) >= 2:
out.append((min(u), f'"{ab}" used {len(u)}x but never defined'))
continue
if len(def_lines.get(ab, set())) > 1:
out.append((sorted(def_lines[ab])[1], f'"{ab}" defined more than once'))
before = [ln for ln in u if ln < d]
if before:
out.append((min(before), f'"{ab}" used before its definition (defined L{d})'))
if not u:
out.append((d, f'"{ab}" defined but never used'))
return out
def check_spelling(lines):
out = []
text = "\n".join(lines)
us_total = 0
uk_total = 0
fam_hits = [] # (line, msg, side)
for us_form, uk_re, _ in SPELLING_FAMILIES:
us_re = SPELLING_US[us_form]
uk_count = len(re.findall(uk_re, text, re.I))
us_count = len(re.findall(us_re, text, re.I))
us_total += us_count
uk_total += uk_count
for i, line in enumerate(lines, 1):
for _m in re.finditer(uk_re, line, re.I):
fam_hits.append((i, f'"{us_form}" family: UK spelling here', "uk"))
for _m in re.finditer(us_re, line, re.I):
fam_hits.append((i, f'"{us_form}" family: US spelling here', "us"))
if us_total == 0 and uk_total == 0:
return out
dominant = "US" if us_total >= uk_total else "UK"
minority = "uk" if dominant == "US" else "us"
for line, msg, side in fam_hits:
if side == minority:
out.append((line, f"{msg} (document is predominantly {dominant})"))
return out, dominant, us_total, uk_total
def check_numeric_ranges(lines):
out = []
for i, line in enumerate(lines, 1):
for m in NUM_RANGE_RE.finditer(line):
out.append((i, f'"{m.group(0)}" — use en-dash for numeric range ({m.group(1)}–{m.group(2)})'))
return out
def check_pvalues(lines):
out = []
cap = low = 0
hits = []
for i, line in enumerate(lines, 1):
for m in PVAL_RE.finditer(line):
letter, op, val = m.group(1), m.group(2), m.group(3)
if letter == "P":
cap += 1
else:
low += 1
hits.append((i, letter, op, val, m.group(0)))
if not hits:
return out, None
dominant = "P" if cap >= low else "p"
for i, letter, op, val, raw in hits:
try:
num = float(val)
except ValueError:
num = None
if num is not None and num == 0:
out.append((i, f'"{raw}" — a p-value cannot be exactly 0; report as {letter} < .001'))
if letter != dominant:
out.append((i, f'"{raw}" — inconsistent case (document uses "{dominant}")'))
return out, dominant
def check_hyphenation(lines):
out = []
for canon, variants in HYPHEN_FAMILIES:
present = []
per_variant = {}
for vre in variants:
vlines = [i for i, line in enumerate(lines, 1) if re.search(vre, line, re.I)]
if vlines:
present.append(vre)
per_variant[vre] = vlines
if len(present) >= 2:
first_line = min(min(v) for v in per_variant.values())
out.append((first_line, f'inconsistent forms of "{canon}" (multiple variants present)'))
return out
def check_small_numbers(lines):
out = []
for i, line in enumerate(lines, 1):
for m in SMALL_NUM_RE.finditer(line):
word = m.group(2)
if word in UNIT_TOKENS:
continue
out.append((i, f'"{m.group(1)} {word}" — spell out single-digit numbers in prose'))
return out
def check_units(lines):
out = []
for i, line in enumerate(lines, 1):
for m in UNIT_RE.finditer(line):
out.append((i, f'"{m.group(0)}" — insert a space between value and unit ({m.group(1)} {m.group(2)})'))
return out
# --------------------------------------------------------------------------- #
# Report
# --------------------------------------------------------------------------- #
def section(title, items):
lines = [f"## {title}"]
if items:
for ln, msg in sorted(items, key=lambda x: (x[0], x[1])):
lines.append(f"- L{ln}: {msg}")
else:
lines.append("- OK: no issues")
lines.append("")
return lines, len(items)
def main(argv=None):
ap = argparse.ArgumentParser(description="Deterministic manuscript consistency linter.")
ap.add_argument("path", help="manuscript markdown/text file")
ap.add_argument("--strict", action="store_true", help="exit 1 if any issue found")
args = ap.parse_args(argv)
lines = Path(args.path).read_text(errors="ignore").splitlines()
abbr = check_abbreviations(lines)
spell_res = check_spelling(lines)
spell = spell_res[0] if isinstance(spell_res, tuple) else spell_res
ranges = check_numeric_ranges(lines)
pval_res = check_pvalues(lines)
pvals = pval_res[0]
hyph = check_hyphenation(lines)
small = check_small_numbers(lines)
units = check_units(lines)
report = ["# Consistency Lint Report", ""]
total = 0
cats_hit = 0
for title, items in [
("Abbreviations", abbr),
("Spelling (US/UK consistency)", spell),
("Numeric ranges", ranges),
("p-values", pvals),
("Hyphenation / terminology", hyph),
("Small numbers in prose", small),
("Units", units),
]:
sec, n = section(title, items)
report += sec
total += n
cats_hit += 1 if n else 0
report.append("---")
report.append(f"Summary: {total} issue(s) across {cats_hit} category(ies).")
sys.stdout.write("\n".join(report) + "\n")
if args.strict and total > 0:
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
schema_version: 2
name: polish-language
layer: C
owner_domain: manuscript_optimization
maturity: official
when_to_use: "Lint a medical manuscript for mechanical language consistency (abbreviations, US/UK spelling, en-dash ranges, P/p case, hyphenation, units) and run a style-only ESL clarity pass."
when_NOT_to_use: "Removing AI writing tells (use humanize); drafting content (use write-paper); reporting-guideline checks (use check-reporting); citation formatting (use manage-refs)."
inputs:
- "manuscript / section text (Markdown)"
outputs:
- "deterministic consistency report (scripts/lint_consistency.py)"
- "style-only polished revision after user approval"
deterministic_scripts:
- scripts/lint_consistency.py # challenge card in scripts/lint_challenge/
side_effects:
- writes_project_artifacts
downstream_consumers:
- self-review
- write-paper
forbidden_actions:
- alter_numeric_values_or_citations
- change_scientific_meaning
- rewrite_scientific_content
# v2.1 quality card
purpose: "Standardize house-style consistency and improve non-native clarity without changing facts, numbers, or citations."
safety_boundaries:
- "Edits style only; never alters numeric values, p-values, units, citations, or scientific meaning."
- "Deterministic linter is the authority for mechanical issues; no edit without user approval."
known_limitations:
- "Spelling/hyphenation families are a fixed list; uncommon variants may be missed."
- "Small-number and abbreviation heuristics can flag intended author choices — triage with the user."
validation_commands:
- "python3 scripts/lint_consistency.py <manuscript.md>"
- "bash scripts/lint_challenge/verify.sh # deterministic, network-free"
evidence_surface: bundled_script
Related skills
FAQ
What does the linter check?
Seven families: abbreviations, US/UK spelling, numeric-range dashes, p-value case, hyphenation variants, small-number style, and value/unit spacing, each with line numbers and counts.
Will it change my results?
No. It never rewrites scientific claims, changes numeric values, or edits citations; every fix is style-only and user-gated.