skills/writing-revise/SKILL.md
This skill should be used when the user asks to 'revise writing', 'fix review issues', 'polish draft', 'apply review feedback', 'complete writing workflow', or after /writing-review produces REVIEW.md with issues to fix.
npx skillsauth add edwinhu/workflows writing-reviseInstall 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.
The revision loop for writing projects. Consumes .planning/REVIEW.md (produced by /writing-review) and applies targeted fixes, then completes when the blocking issues (critical + major) are resolved — residual minor polish notes are advisory and the writer accepts them at the iteration cap (they do not block completion).
Auto-load all constraints matching applies-to: writing-revise:
!uv run python3 ${CLAUDE_SKILL_DIR}/../../scripts/load-constraints.py writing-revise
You MUST have these constraints loaded before proceeding. No claiming you "remember" them.
CRITICAL: The constraint-loading-protocol above requires loading the domain skill (writing-legal/econ/general) and ai-anti-patterns before revising any prose.
Before starting, check for an existing handoff:
.planning/HANDOFF.md existsSTART
│
├─ Step 1: Load context (ACTIVE_WORKFLOW, PRECIS, OUTLINE, drafts)
│
├─ Step 2: REVIEW.md exists?
│ ├─ NO → REFUSE. Suggest /writing-review. EXIT.
│ └─ YES → Parse issues (critical → major → minor)
│
├─ Step 3: Load constraint layers
│ ├─ Domain skill (legal/econ/general)
│ └─ ai-anti-patterns (universal)
│
├─ Step 4: Fix issues in priority order
│ ├─ 4a: Critical issues (argument-breaking)
│ ├─ 4b: Major issues (transitions, repetition, late introductions)
│ ├─ 4c: Minor issues (polish)
│ └─ 4d: De-AI prose pass (MANDATORY — run /de-ai-revise on every edited draft)
│
├─ Step 5: Formatting check
│
└─ Step 6: Check iteration state (.planning/REVIEW_STATE.md)
│
├─ result.substratePass (0 critical, 0 major) → COMPLETE
│ └─ Residual MINORS are advisory polish — fix the cheap ones, then Archive → summary → EXIT.
│ Do NOT loop to drive minors to literal 0 (the prose-reviewer regenerates subjective minors — treadmill).
│
├─ iteration < 3 AND BLOCKING issues remain (critical/major) → CONTINUE
│ └─ Increment iteration → fix the criticals/majors → Re-invoke /writing-review → Loop
│
└─ ESCALATE (decision: user) when EITHER
├─ iteration >= 3 AND blocking issues still remain, OR
└─ substrate clean but minors remain → present them as "accept as-is OR one more polish pass?"
If text and flowchart disagree, the flowchart wins.
<EXTREMELY-IMPORTANT> ## IRON LAW: Critique Over ComfortIf the writing has problems, SAY SO. Being nice is NOT HELPFUL — the user publishes weak prose that gets rejected.
NO "FIXED" CLAIMS WITHOUT FRESH RE-REVIEW. This is not negotiable.
After applying fixes from REVIEW.md, you MUST:
/writing-review to regenerate REVIEW.md with fresh diagnostics"I fixed it" without re-reviewing is NOT HELPFUL — unverified fixes let broken prose reach the user.
Iteration 1: Review → REVIEW.md → Revise → Re-Review
↓
Iteration 2: Re-Review → REVIEW.md → Revise → Re-Review
↓
Iteration 3: Re-Review → REVIEW.md → Revise → Re-Review
↓
Still issues? → ESCALATE to user
All clean? → COMPLETE
Track iterations in .planning/REVIEW_STATE.md:
---
iteration: 1
max_iterations: 3
last_review_date: 2026-03-09
issues_found_count: 5
---
Exit criteria (gate on the SUBSTRATE — critical + major — not on driving subjective minors to zero):
result.substratePass (0 critical, 0 major) in REVIEW.md. Apply any cheap residual minors, then archive. Gate type: human-verify — auto-advance to archive. Residual minor polish notes do NOT block completion.human-verify — auto-advance.[decision — wait for user]: iteration >= 3 AND blocking issues still remain (present options); OR substrate is clean but minor polish notes remain — present "accept as-is OR one more polish pass?" The writer decides; do NOT auto-loop on minors.Note: the review still FLAGS every severity (including minors — see the rationalization table; flagging is the reviewer's job). What changed is the loop exit: only critical+major block; minors are advisory. This is the writing analog of the wc substrate gate — drive the real, convergent findings to zero; don't treadmill on an LLM panel's inexhaustible subjective minors.
Before claiming "all fixed", check iteration count:
.planning/REVIEW_STATE.md (create if missing with iteration: 1)Claiming "all issues resolved" without re-reviewing is NOT HELPFUL — the user trusts a false "all clear" and publishes with remaining problems.
/writing-review catches. Shipping an unverified revised draft asserts a verification that never happened; an unverified claim presented as done is dishonest./writing-review produces .planning/REVIEW.mdBefore running edits, verify the workflow is ready:
.planning/ACTIVE_WORKFLOW.md, .planning/PRECIS.md, .planning/OUTLINE.md, and at least one file in drafts/ must existworkflow: writing.planning/REVIEW.mdIf any file is missing, report and suggest the appropriate phase:
/writing (start from brainstorm)/writing-review first (see backward-compatibility below)Read(".planning/ACTIVE_WORKFLOW.md")
Read(".planning/PRECIS.md")
Read(".planning/OUTLINE.md")
Read([current draft files in drafts/])
If any file is missing, report and suggest starting with /writing.
NO REVISION WITHOUT REVIEW.md. This is not negotiable.
If .planning/REVIEW.md does not exist, REFUSE to proceed:
REVIEW.md not found. Cannot revise without a structured review diagnosis.
Run /writing-review first to produce .planning/REVIEW.md, then re-run /writing-revise.
STOP HERE. Do not fall back to inline review. Do not offer to "do a quick check instead."
Why: Inline review is shallow by design — it misses cross-section issues, transition problems, and thesis drift that only hierarchical review catches. Allowing a fallback path means the full review is never run. The review-then-revise pipeline exists because revision without diagnosis produces random edits, not targeted fixes. Small fixes applied without review context create new issues the same way. </EXTREMELY-IMPORTANT>
When REVIEW.md exists:
Read(".planning/REVIEW.md")
Parse the review into:
The midpoint must be self-contained. Load ALL constraint layers before touching the draft:
Based on style in ACTIVE_WORKFLOW.md:
| Style | Load |
|-------|------|
| legal | Read("${CLAUDE_SKILL_DIR}/../../skills/writing-legal/SKILL.md") |
| econ | Read("${CLAUDE_SKILL_DIR}/../../skills/writing-econ/SKILL.md") |
| general | Read("${CLAUDE_SKILL_DIR}/../../skills/writing-general/SKILL.md") |
You MUST Read() the domain skill before editing. The domain skill contains the full rules, reference material, and enforcement patterns. Editing without it produces generic fixes.
Skill(skill="workflows:ai-anti-patterns")
You MUST load ai-anti-patterns before editing. This catches AI writing smell (hedging, filler, false balance, weasel words) that domain skills don't cover. Revising without it means you'll fix structural issues while leaving AI-smell intact — the reviewer will flag the same draft again for different reasons.
<EXTREMELY-IMPORTANT> ### Iron Law: Full Constraint LoadingNO REVISION WITHOUT ALL CONSTRAINT LAYERS. This is not negotiable.
The midpoint cannot rely on constraints loaded during earlier phases. Prior context may be compressed or lost. You must load:
.planning/ACTIVE_WORKFLOW.md → workflow state.planning/PRECIS.md, .planning/OUTLINE.md → structural intentEditing with only domain skill loaded is like reviewing with one eye closed. You'll fix half the problems and miss the other half. </EXTREMELY-IMPORTANT>
When applying fixes reveals unplanned issues, follow the deviation rules from constraints/deviation-rules.md:
Track deviations per fix batch. Report at Step 6: Deviations during revision: N auto-fixed (R1: X, R2: Y, R3: Z). R4 escalations: [list or "none"].
Work through REVIEW.md issues in priority order:
For each critical issue in REVIEW.md:
For each major issue:
Transition fixes (from REVIEW.md "Transition Issues" section):
Repetition fixes (from REVIEW.md "Cross-Section Repetition"):
Late introduction fixes (from REVIEW.md "Concept Introduction Order"):
For each minor issue:
After fixing REVIEW.md issues, run the de-ai-revise skill (rewrite mode) on every
edited drafts/*.md so the prose reads less AI-generated. This is a standard step, not
an optional polish — the AI-prose scorers (tics + always_flag diction + stylometrics)
are corpus-validated and /writing-review already surfaced their spans (Step 2d).
</EXTREMELY-IMPORTANT>
Skill(skill="workflows:de-ai-revise") # or follow skills/de-ai-revise/SKILL.md
The de-ai-revise process: AUDIT (de_ai_audit.py) → rewrite flagged spans (swap
always_flag diction for the plain replacement, fix tics, vary rhythm toward bursty,
thin em-dash clusters) → one corrective 2nd pass → report.
Honor its Iron Law of Goodhart: the scorers GUIDE which spans to revise; do NOT chase the composite. Preserve already-human passages, quoted/statutory text, and the author's deliberate em-dashes — a mid-range composite is a human who likes em-dashes, not an AI tell. Over-editing to win the number flattens voice.
AI-prose spans are advisory polish, not blocking criticals — the substrate gate (critical + major) is unchanged. The de-AI pass runs every iteration but never blocks completion on its own.
After REVIEW.md issues are resolved AND the regex sweep (workflows:ai-anti-patterns + Strunk + McCloskey + Volokh via prose-lint.py) is clean, consider a sentence-level rhythm-and-flow pass for prose-quality issues regex cannot catch — choppy rhythm, weak topic sentences, paragraph closures that trail into roadmaps, sentence-variety deficits.
When to run:
.docxWhen NOT to run:
Pass infrastructure (in this skill's directory):
references/rhythm-rubric.md — 5-dimension scoring rubric (rhythm, flow, topic, closure, variety) with geometric-mean overallreferences/rhythm-auditor-brief.md — validated agent prompt templatereferences/rhythm-lessons.md — the 7 design lessons that govern correct execution (read this BEFORE running the pass)scripts/transactional_fix.py — fix engine with iron-law-of-transactional-save + footnote-pin-respect + structured-fix-targeting enforcementIron Laws (from rhythm-lessons.md — read it; do not run the pass without):
workflows:writing-prose-reviewer subagent per iteration (read-only tools)Invocation pattern:
1. Read rhythm-lessons.md (mandatory — do not skip)
2. Copy rhythm-rubric.md and rhythm-auditor-brief.md to <project>/.planning/prose-rhythm/
3. Run setup: extract draft → CURRENT.md, scan pins → PINS.md, seed SCORES.md + AUDIT.md + CHANGELOG.md
4. Set /goal pinned to "the prose-rhythm pass has CONVERGED — latest .planning/prose-rhythm/SCORES.md row shows ZERO blocking rhythm findings AND overall improved <0.2 vs the prior row (flat) — OR iter ≥ <max_iter>. Stop after <max_iter> turns." (Rhythm is pure judgment with no hard substrate; gate on convergence/flat + zero blocking, NOT on chasing overall ≥ a fixed threshold.)
5. Loop body (one turn each):
a. Dispatch fresh workflows:writing-prose-reviewer (read-only Read/Grep/Glob)
b. Read SCORES.md latest row → check convergence (flat ±0.2) + blocking findings + iter + regression alarm
c. If CONTINUE: uv run --with pyyaml --with lxml python3 ${CLAUDE_SKILL_DIR}/scripts/transactional_fix.py \\
--draft <path> --state-dir .planning/prose-rhythm --iteration N
d. End turn (/goal refires)
6. Exit on COMPLETE (zero blocking findings AND overall flat — converged) or ESCALATE (iter ≥ max_iter)
Do NOT invoke as /prose-rhythm standalone — it's a subroutine of /writing-revise. Future work may promote it to a standalone skill if usage demands.
Before claiming completion, check the audit-fix loop state:
1. READ `.planning/REVIEW_STATE.md` - what iteration are we on?
2. Run final check - are there remaining issues?
3. Determine verdict based on iteration + issues:
- iteration < 3 AND issues remain → CONTINUE (re-invoke /writing-review)
- iteration >= 3 AND issues remain → ESCALATE (report to user)
- no issues → COMPLETE (but first run Step 6a cite-fidelity gate)
If .planning/ACTIVE_WORKFLOW.md declares an nlm_notebook, every
drafts/*.md MUST have a corresponding .planning/CITES-{slug}.md
showing status: PASSED before the verdict can be COMPLETE.
</EXTREMELY-IMPORTANT>
Before declaring COMPLETE, run Stage 3:
uv run ${CLAUDE_SKILL_DIR}/../../scripts/cite-fidelity/check_section_cites.py --all
Then verify each section:
# For each drafts/*.md, check the matching CITES file
# Slug rule: "Part I (Draft).md" → "CITES-Part-I.md"
import re
from pathlib import Path
drafts = list(Path("drafts").glob("*.md"))
failures = []
for d in drafts:
slug = re.sub(r"\s+", "-", re.sub(r"\s*\(Draft\)\s*$", "", d.stem).strip())
cites = Path(".planning") / f"CITES-{slug}.md"
if not cites.exists():
failures.append(f"{d.name}: missing CITES file")
continue
head = cites.read_text().split("---", 2)
if len(head) < 3 or "status: PASSED" not in head[1]:
failures.append(f"{d.name}: CITES status not PASSED")
If any failure: return to Step 4 (Fix Issues) addressing the UNSUPPORTED cites listed in the failing CITES file. Do NOT mark COMPLETE.
If ACTIVE_WORKFLOW.md has no nlm_notebook, skip this gate (no notebook
to verify against) and proceed with the normal verdict.
See references/constraints/cite-fidelity-section-gate.md for the full
doctrine.
Generate report based on verdict:
Update .planning/REVIEW_STATE.md:
---
iteration: [N+1]
max_iterations: 3
last_review_date: [date]
issues_found_count: [count]
verdict: CONTINUE
---
IMMEDIATELY re-invoke /writing-review (no pause, no user prompt):
Read ${CLAUDE_SKILL_DIR}/../../skills/writing-review/SKILL.md and follow its instructions.
After /writing-review completes and regenerates REVIEW.md, /writing-revise will be invoked again automatically.
This is a loop, not a checkpoint. Do not pause for user input.
Update .planning/REVIEW_STATE.md:
---
iteration: 3
max_iterations: 3
last_review_date: [date]
issues_found_count: [count]
verdict: ESCALATE
---
Report to user:
Writing Review Loop Escalation (3 iterations completed)
After 3 review-revise cycles, [N] issues remain:
[List issues from REVIEW.md]
Options:
1. Accept current draft with documented limitations
2. Extend review (manual approval for iteration 4+)
3. Rethink structure (return to outline phase)
4. Human editing (exit workflow, manual fixes)
Which option do you prefer?
Update .planning/REVIEW_STATE.md:
---
iteration: [N]
max_iterations: 3
last_review_date: [date]
issues_found_count: 0
verdict: COMPLETE
---
SUMMARY: Append final phase summary to .planning/PHASE_SUMMARY.md (see constraints/phase-summary-frontmatter.md):
Archive workflow state:
mkdir -p .planning/completed-workflows
mv .planning/ACTIVE_WORKFLOW.md ".planning/completed-workflows/$(date +%Y-%m-%d)-writing.md"
Generate completion summary:
## Writing Workflow Complete
**Project**: [directory name]
**Completed**: [date]
**Style**: [legal | econ | general]
### Artifacts
- `.planning/PRECIS.md` - Thesis, audience, claims
- `.planning/OUTLINE.md` - Document structure
- `.planning/REVIEW.md` - Final review diagnosis
- `outlines/` - Detailed section outlines
- `drafts/` - Final prose
### Document Summary
- **Thesis**: [from PRECIS.md]
- **Sections**: [count]
### Next Steps
- Export to Word: `/docx`
- Export to PDF: `/pdf`
- Start new project: `/writing`
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.