Plain Language skill for Codex

Understood on the first read by anyone. Codex extracts every action, deadline, amount and consequence from the original before rewriting, then puts what the reader must do first, using everyday words, short active sentences and defined terms. A bundled readability script flags the exact long and passive sentences to fix, and anything with legal, medical or financial weight is marked for professional review.

  • Writing & Docs
  • $plain-language
  • 159 lines
  • 3 files
  • ~1,800 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- plain-language

Installs to ~/.agents/skills/plain-language/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $plain-language, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Rewrites text for broad audiences in plain language - public notices, policies, help-center articles, onboarding, consent and error text, letters, benefits and health information - so readers can find what they need, understand it the first time and act on it. Applies plain-language rules (reader's task first, everyday words, short sentences, active voice, defined terms, clear headings), keeps legal and technical meaning intact, and measures with a stdlib readability script. Use when asked to simplify, make something easier to understand, lower the reading level, de-jargon, or write for the general public or non-native readers.

Use it when

  • Text goes to the general public, patients, customers or non-native readers
  • Readers miss deadlines or call support because a notice was unclear
  • You need a measurable reading-level target for help or policy content

Use something else when

How to check the result

Every fact listed from the original is present and unchanged, the readability script meets the target grade on flagged sentences, and a reader or paraphrase check finds the required action quickly.

The mistake it prevents

Chopping sentences to hit a grade score while dropping a legal condition such as a deadline's start date or the difference between 'may' and 'will'.

~/.agents/skills/plain-language/SKILL.md

--- name: plain-language description: Rewrites text for broad audiences in plain language - public notices, policies, help-center articles, onboarding, consent and error text, letters,… license: MIT ---

Text is plain when its intended readers can find what they need, understand what they find, and use it to act, on the first read. Reading-level scores are a symptom check, not the goal; the goal is that a real reader does the right thing.

Before rewriting

Answer these from the source text and the user. Ask when unsure.

QuestionExample answer
Who reads this, and in what situation?Benefit recipients, on a phone, worried about losing payments
What must they do, by when?Upload pay stubs by 5 May or benefits stop
What do they already know or not know?Do not know what “redetermination” means
Which wording is fixed?Statutory phrases, legal definitions, regulated disclosures
Who must approve the result?Legal, compliance or clinical reviewer

If text has legal, medical, financial or safety consequences (contracts, consent forms, dosage, eligibility, privacy notices), the plain version must be reviewed by the responsible professional before use. Say so in the output; do not present it as cleared.

Workflow

- [ ] 1. Identify reader, situation, required action and fixed wording
- [ ] 2. Measure the original: python3 scripts/readability.py original.md
- [ ] 3. Extract the facts: actions, deadlines, amounts, conditions, consequences, contacts
- [ ] 4. Reorder: what the reader must do and why it matters goes first
- [ ] 5. Rewrite with the rules below; keep every fact from step 3
- [ ] 6. Measure again; work on the flagged sentences, not the average
- [ ] 7. Check meaning: every fact from step 3 present and unchanged
- [ ] 8. Test with real readers or the paraphrase check; hand off for expert review

Rules

Structure

  • Put the reader’s main question and required action first. Background last, if at all.
  • Use headings written as questions or tasks: “What you need to do”, “What happens if you do not reply”, “How to get help”.
  • One topic per paragraph; paragraphs of one to three sentences.
  • Numbered lists for steps in order; bullets for items with no order.
  • Tables for if-then rules and comparisons (“If you earn less than X, you pay Y”).
  • Put dates, amounts and contact details where the reader needs them, not in a footer.

Sentences

  • Average 15-20 words; break anything over 25 words unless it is a simple list.
  • One idea per sentence. Split at “and”, “which”, “however”.
  • Active voice with a clear actor: “We will stop your payments”, not “Payments will be discontinued”.
  • Address the reader as “you” and the organisation as “we”.
  • Positive form where possible: “Send the form by Friday” over “Do not fail to send…”.
  • Put conditions before consequences: “If you move, tell us within 10 days.”

Words

Instead ofUse
commence, initiatestart
terminate, discontinueend, stop
utiliseuse
prior to, subsequent tobefore, after
in the event thatif
sufficient, insufficientenough, not enough
ascertainfind out
pursuant tounder
remunerationpay
facilitatehelp, make possible
  • Keep a necessary technical or legal term, but define it at first use in plain words: “your deductible (the amount you pay before your insurance starts paying)”.
  • Use one word for one thing throughout. Switching “claim”, “application” and “request” makes readers think there are three things.
  • Avoid noun strings, double negatives, Latin abbreviations (e.g., i.e., etc.) and undefined acronyms.
  • Write numbers as numerals; write dates unambiguously (“5 May 2026”, not “05/05”).

Before and after

Before (grade 16):
Pursuant to the applicable regulations, your application for continued eligibility has
been reviewed and a determination has been made that the documentation submitted was
insufficient to substantiate the eligibility criteria.

After (grade 6):
We need more information to keep paying your benefits.
Send us your last 2 pay stubs by 5 May 2026.
If we do not get them by then, your payments will stop.

The rewrite keeps every fact (more documents needed, which documents, deadline, consequence) and adds the one the original implied but never said: what to send.

Measuring

python3 scripts/readability.py notice.md                      # report, exit 1 if grade > 8
python3 scripts/readability.py notice.md --max-grade 6 --top 5
python3 scripts/readability.py notice.md --jargon jargon.txt  # one term per line
pbpaste | python3 scripts/readability.py -                    # from stdin

The script prints Flesch Reading Ease, Flesch-Kincaid grade, sentence-length stats, the share of three-syllable words, likely passive sentences, jargon hits and the longest sentences. It ignores code blocks, URLs and tables.

AudienceTarget
General public, public servicesGrade 6-8
Health, benefits, safety informationGrade 6 or lower where possible
Consumer product helpGrade 7-9
Professional but non-specialistGrade 9-11

Formulas only count syllables and sentence length. Short sentences full of undefined jargon still score well, and a necessary long word (“prescription”) scores badly. Fix the specific flagged sentences; never chop sentences mechanically to hit a number.

Testing with readers

The strongest check is a reader from the audience. If none is available:

  • Paraphrase check: for each section, can you state in one sentence what the reader must do and what happens if they do not? If you cannot, neither can they.
  • Task check: write three questions a reader arrives with (“When is the deadline?”, “What do I send?”, “Who do I call?”) and time how fast each answer is found.
  • Skim check: read only the headings and bold text. The required action must be visible.
  • Suggest a short usability test (5 readers, ask them to find and explain the action) for high-stakes text.

Gotchas

  • Losing a legal condition while simplifying (“may” vs “will”, “within 30 days of the date on this letter” vs “within 30 days”). Keep the precise condition; simplify around it.
  • Talking down to readers. Plain is not childish: no exclamation marks, no cartoons of serious topics, no “Don’t worry!”.
  • Removing the definition of a term the reader will meet elsewhere (on a form, a phone menu). Keep the term and explain it.
  • Translating word-for-word afterwards: plain English helps translation, but translated text needs its own review.
  • Accessibility overlaps: also use descriptive link text (“Upload your pay stubs”, not “click here”) and do not rely on colour alone to signal urgency.

Output

**Reader / action:** benefit recipients / upload 2 pay stubs by 5 May 2026
**Readability:** grade 15.8 -> 6.4; sentences over 25 words 9 -> 0; passive 60% -> 10%
**Facts preserved:** 7/7 (list attached: deadline, documents, consequence, appeal right, phone, hours, case number)
**Fixed wording kept:** appeal rights paragraph (statutory text), defined in plain words above it
**Needs review by:** legal/compliance before sending; not reviewed by a professional
**Suggested test:** 5-person comprehension check on the "what to send" section

What the zip contains

Codex reads bundled files only when a step points to them. Every one is shown here, so you can review it before installing.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Plain Language"
  short_description: "Understood on the first read by anyone"
  default_prompt: "$plain-language Rewrite this benefits letter so someone with a grade 6 reading level understands it"
scripts/readability.py136 lines, 5.5 KB
#!/usr/bin/env python3
"""Readability report for plain-language rewriting (English text or Markdown).

Usage:
  python3 readability.py FILE [--max-grade 8] [--jargon WORDS.txt] [--top 10]
  cat draft.txt | python3 readability.py - --max-grade 6

Reports Flesch Reading Ease, Flesch-Kincaid grade, sentence-length stats, long words,
likely passive constructions, and the longest sentences. Markdown code blocks, inline
code, URLs and HTML tags are ignored. Exit 1 if the grade exceeds --max-grade, 2 on usage
errors. Standard library only. Formulas are rough guides: use them to find hard spots,
never as proof that text is clear.
"""
from __future__ import annotations

import re
import sys
from pathlib import Path

ABBREV = re.compile(r"\b(e\.g|i\.e|etc|vs|Mr|Mrs|Ms|Dr|No|approx|Inc|Ltd)\.", re.I)
PASSIVE = re.compile(
    r"\b(am|is|are|was|were|be|been|being)\s+(\w+ly\s+)?(\w+ed|\w+en|made|done|sent|paid|held|kept|set|put|told|given|taken|shown|known|seen|built|found|lost|sold)\b",
    re.I,
)
NOT_PARTICIPLE = {"open", "often", "even", "seven", "eleven", "garden", "kitchen", "token", "hidden", "chicken", "listen", "happen", "need", "used", "red", "bed", "speed", "seed", "feed", "indeed", "hundred"}


def clean(text: str) -> str:
    text = re.sub(r"```.*?```|~~~.*?~~~", " ", text, flags=re.S)
    text = re.sub(r"`[^`]*`", " ", text)
    text = re.sub(r"<[^>]+>", " ", text)
    text = re.sub(r"!?\[([^\]]*)\]\([^)]*\)", r"\1", text)
    text = re.sub(r"https?://\S+", " ", text)
    text = re.sub(r"^\s*([#>*+-]|\d+\.)\s*", "", text, flags=re.M)
    text = re.sub(r"^\s*\|.*\|\s*$", " ", text, flags=re.M)  # tables
    # headings and list items without terminal punctuation still end a sentence
    text = re.sub(r"([^.!?:;\s])\s*\n\s*\n", r"\1.\n\n", text)
    return text


def sentences(text: str) -> list[str]:
    text = ABBREV.sub(lambda m: m.group(0).replace(".", ""), text)
    parts = re.split(r"(?<=[.!?])\s+(?=[\"'(\[]?[A-Z0-9])", text)
    return [re.sub(r"\s+", " ", p).strip() for p in parts if re.search(r"[A-Za-z]", p)]


def words(sentence: str) -> list[str]:
    return re.findall(r"[A-Za-z]+(?:['’-][A-Za-z]+)*", sentence)


def syllables(word: str) -> int:
    w = word.lower().replace("’", "'")
    if len(w) <= 3:
        return 1
    w = re.sub(r"(?:[^laeiouy]es|ed|[^laeiouy]e)$", "", w)
    w = re.sub(r"^y", "", w)
    count = len(re.findall(r"[aeiouy]{1,2}", w))
    return max(1, count)


def main(argv: list[str]) -> int:
    if not argv or argv[0] in ("-h", "--help"):
        print(__doc__.strip())
        return 2
    opts = {"--max-grade": "8", "--jargon": "", "--top": "10"}
    pos = []
    i = 0
    while i < len(argv):
        if argv[i] in opts and i + 1 < len(argv):
            opts[argv[i]] = argv[i + 1]
            i += 2
        else:
            pos.append(argv[i])
            i += 1
    if len(pos) != 1:
        print("error: give exactly one FILE or '-'", file=sys.stderr)
        return 2
    try:
        raw = sys.stdin.read() if pos[0] == "-" else Path(pos[0]).read_text(encoding="utf-8")
        max_grade = float(opts["--max-grade"])
        top = int(opts["--top"])
    except (OSError, ValueError) as exc:
        print(f"error: {exc}", file=sys.stderr)
        return 2

    sents = sentences(clean(raw))
    if not sents:
        print("error: no prose found", file=sys.stderr)
        return 2
    per = [(s, words(s)) for s in sents]
    per = [(s, w) for s, w in per if w]
    all_words = [w for _, ws in per for w in ws]
    n_s, n_w = len(per), len(all_words)
    n_syl = sum(syllables(w) for w in all_words)
    wps, spw = n_w / n_s, n_syl / n_w
    ease = 206.835 - 1.015 * wps - 84.6 * spw
    grade = 0.39 * wps + 11.8 * spw - 15.59
    long_words = [w for w in all_words if syllables(w) >= 3]
    lengths = sorted(len(ws) for _, ws in per)
    over25 = sum(1 for x in lengths if x > 25)
    passive = []
    for s, _ in per:
        for m in PASSIVE.finditer(s):
            if m.group(3).lower() not in NOT_PARTICIPLE:
                passive.append(s)
                break

    print(f"Sentences: {n_s}   Words: {n_w}   Avg words/sentence: {wps:.1f}   Median: {lengths[len(lengths) // 2]}")
    print(f"Flesch Reading Ease: {ease:.0f}  (60-70 plain English; higher is easier)")
    print(f"Flesch-Kincaid grade: {grade:.1f}  (target <= {max_grade:g})")
    print(f"Sentences over 25 words: {over25} ({100 * over25 / n_s:.0f}%)")
    print(f"Words of 3+ syllables: {100 * len(long_words) / n_w:.0f}%")
    print(f"Likely passive sentences: {len(passive)} ({100 * len(passive) / n_s:.0f}%)")

    if opts["--jargon"]:
        terms = [t.strip().lower() for t in Path(opts["--jargon"]).read_text(encoding="utf-8").splitlines() if t.strip() and not t.startswith("#")]
        low = clean(raw).lower()
        hits = {t: len(re.findall(r"\b" + re.escape(t) + r"\b", low)) for t in terms}
        hits = {t: c for t, c in hits.items() if c}
        if hits:
            print("Jargon found: " + ", ".join(f"{t} x{c}" for t, c in sorted(hits.items(), key=lambda kv: -kv[1])))
        else:
            print("Jargon found: none from list")

    print(f"\nLongest sentences (top {top}):")
    for s, ws in sorted(per, key=lambda p: -len(p[1]))[:top]:
        print(f"  [{len(ws)} words] {s[:220]}{'...' if len(s) > 220 else ''}")
    if passive:
        print("\nPassive candidates (check each; some are fine):")
        for s in passive[:top]:
            print(f"  - {s[:200]}{'...' if len(s) > 200 else ''}")
    return 1 if grade > max_grade else 0


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
New

Introducing Codex Skills Pro

79 professional skills that take Codex through complete engagements, each with its own scripts, references and a report that verifies the result.

All-AccessOne-time payment, no subscription
$49
Get All-AccessOr browse individual skills from $2.99 →

Secure checkout by Creem