# Restyle

> Use when asked to restyle a draft, to rewrite an article in the voice or style of a particular author, to apply a voice from the local voice library to a piece of writing, or to build or rebuild a voice from an author's corpus.

- Skill: `makanfar/restyle` (Agent Skill, multi-file: 20 files)
- Install (CLI): `npx skillmds@latest add makanfar/restyle`
- Raw SKILL.md: https://api.skillmd.com/api/skills/makanfar/restyle/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: MakanFar (https://skillmd.com/u/makanfar)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/makanfar/restyle

---


# restyle

Rewrites a Markdown draft toward a target author's voice, then quality-checks
and repairs the result.

**Usage:** `/restyle <draft path> --voice <name> [--contrast]`

## Paths

`$SKILL` below means the **base directory for this skill**, given to you at
invocation. Every script, prompt and voice lives inside it. The skill is normally
installed at `~/.claude/skills/restyle`, so it runs from any project and the
working directory is wherever the user's draft is — never assume the two are the
same. Always invoke scripts by their full `$SKILL/...` path.

The draft path and the output files are the exception: those are relative to the
user's working directory, because they are the user's documents, not the skill's.

If no voice is given, list the directories under `$SKILL/voices/` and ask which to use.
If the draft path is missing, ask for it. Do not guess either.

## Inputs

- `"$SKILL/voices/<name>/exemplars.md"` — sent to the generator and the voice reviewer.
- `"$SKILL/voices/<name>/corpus/"` — never sent to a model; used only by the overlap check.
  `.txt` files are read recursively, so a corpus may be organised into subdirectories.

`{{EXEMPLARS}}` is substituted with the **path**, not the file's contents: the
subagent reads it. Do not inline the exemplars — that spends thousands of tokens
of your own context on text only the subagent needs. `{{DRAFT}}` and
`{{REWRITE}}` are substituted with contents, because you are already holding them.

If `exemplars.md` is missing, stop and say so. If `corpus/` is missing or empty,
warn that the plagiarism check will not run, and ask whether to continue.

### Preflight — always run this first

```bash
python3 "$SKILL/scripts/build_exemplars.py" --check "$SKILL/voices/<name>/exemplars.md" --corpus "$SKILL/voices/<name>/corpus"
```

Exit 1 means passages in `exemplars.md` are absent from `corpus/`. The generator
would then be shown text the overlap check cannot detect it reproducing — the
guard has a hole exactly where borrowing is most likely. Report which passages,
and recommend `voice build` before continuing. Do not proceed silently.

## Procedure

### 1. Generate

Read `$SKILL/prompts/generate.md`. Substitute:

- `{{DRAFT}}` — the draft file's contents
- `{{EXEMPLARS}}` — `"$SKILL/voices/<name>/exemplars.md"`
- `{{CONTRAST_BLOCK}}` — empty string by default. With `--contrast`, insert:
  `Also state how the target voice differs from the draft's own style on each dimension, and let that difference drive the descriptors.`

Dispatch **one** Agent tool call (`general-purpose`) with the substituted prompt.
Generate exactly one candidate — review and repair will fix what is wrong with it,
so more candidates buy nothing.

Extract the `## Descriptors` and `## Rewrite` sections. Write the rewrite to a
working file. If either heading is missing, re-dispatch once; if it fails again,
stop and report.

Default to target-only register analysis. `--contrast` exists for targets close
to the author's own register; a distinctive literary voice is not one.

### 2. Overlap check

```bash
python3 "$SKILL/scripts/overlap_check.py" <working file> --corpus "$SKILL/voices/<name>/corpus"
```

Exit code 1 means matches were found. **This does not halt the run.** Convert
each match into a `blocker` finding in the schema from
`$SKILL/prompts/finding-schema.md`, using the matched text as the quoted anchor.

**Exit code 2 means the corpus could not be read** — missing directory, no `.txt`
files, or nothing long enough to check against. That is not a clean pass and must
never be treated as one. Stop and report it: the guard did not run.

The check uses an 8-word shingle and will not flag shorter echoes. That is a
deliberate limit — a three-word rhetorical move is imitation, not reproduction,
and catching it would mean flagging ordinary English. Do not lower `-n`.

### 3. Review

Read `$SKILL/prompts/finding-schema.md` once and substitute it into `{{SCHEMA}}` in all
three reviewer prompts.

Dispatch **three Agent tool calls in a single message** so they run in parallel:

| Prompt | Substitutes | Deliberately withheld |
|---|---|---|
| `review-fidelity.md` | `{{DRAFT}}`, `{{REWRITE}}` | the exemplars |
| `review-voice.md` | `{{EXEMPLARS}}`, `{{REWRITE}}` | the original draft |
| `review-craft.md` | `{{REWRITE}}` | both |

The withholding is deliberate and must be preserved. A fidelity reviewer who
knows the target voice starts excusing invented content as style. A voice
reviewer who has seen the draft starts rewarding timidity.

Collect all findings. **Discard any finding whose quoted anchor does not appear
verbatim in the rewrite** — an unanchored finding cannot be verified or repaired.
Record how many were discarded for the report.

### 4. Repair

If there are no findings, skip to step 5.

Read `$SKILL/prompts/repair.md`, substitute `{{REWRITE}}`, `{{FINDINGS}}` (all findings
from all sources, most severe first), `{{DRAFT}}`, `{{EXEMPLARS}}`. Dispatch one
Agent tool call.

Extract `## Repaired` as the new working text and `## Unresolved` for the report.

### 5. Iterate

Repeat steps 2-4 at most **twice total**. After the second repair, ship whatever
you have.

Stop early if a round produces no findings.

Do not run a third round. Repair passes erode untouched prose, and a finding that
survives two targeted attempts needs the author, not another attempt.

Round 2 matters even when round 1 looks clean: repair can introduce drift of its
own, and re-review is what catches it.

### 6. Write output

Write the final text to `<draft>.restyled.md`.

Write `<draft>.report.md`:

```markdown
# restyle report — <draft name>

- **Voice:** <name>
- **Variant:** RG (target-only) | RG-Contrastive
- **Date:** <YYYY-MM-DD>
- **Words:** <draft count> → <output count>

## Descriptors

<the generator's descriptor list>

## Round 1

- Findings: N blockers, N major, N minor (N discarded for missing anchors)
- Overlap matches: N
- Unresolved after repair: <titles, or None>

## Round 2

<same shape, or "Not run — round 1 came back clean.">

## Unresolved findings

<full text of anything still outstanding, or None>

## Overlap matches outstanding

<any still present after the final round, or None>
```

Then tell the user: output path, report path, and — stated plainly, not buried —
any outstanding overlap matches. That is the one class of issue they should never
publish without having looked at themselves.

## Building a voice

`/restyle voice build <name>` regenerates `"$SKILL/voices/<name>/exemplars.md"` from the
corpus. Run it when a voice is new, when corpus files change, or when preflight
fails.

### 1. Extract candidates

```bash
python3 "$SKILL/scripts/extract_candidates.py" --corpus "$SKILL/voices/<name>/corpus" -k 12 --out /tmp/<name>_candidates.json
```

Returns the medoid passage of each register cluster, allocated per source file.
The per-source allocation is load-bearing: clustering alone lets the largest file
take most slots, because it holds most of the passages. Do not replace it with a
flat sample.

### 2. Curate

Read `$SKILL/prompts/curate-voice.md`, substitute `{{CANDIDATES}}` with the candidates
file path, and dispatch one Agent tool call. It returns JSON with `selections`
(8-10 ids and register labels, ordered calmest first), `rejected`, and `notes`.

Write that JSON to `/tmp/<name>_selections.json` verbatim. Step 3 reads it from
there; it is not passed to the script any other way.

Read `notes`. If it reports a register missing from the corpus — most often the
calm expository end — tell the user plainly. That is a gap in their source
material, not something to paper over, and it is what causes pastiche.

### 3. Assemble and verify

```bash
python3 "$SKILL/scripts/build_exemplars.py" \
  --candidates /tmp/<name>_candidates.json \
  --selections /tmp/<name>_selections.json \
  --corpus "$SKILL/voices/<name>/corpus" \
  --voice <name> \
  --out "$SKILL/voices/<name>/exemplars.md"
```

This writes the file and re-checks the invariant. A non-zero exit means the
build failed; do not use the result.

## Notes

- The descriptor list in the report explains the whole direction of the rewrite.
  When output is wrong, read it first.
- Never chunk the article for generation. It goes to the generator whole.

