"The gap between the draft and the send is your voice." This skill records that gap — what was removed, what was added, how the measurements moved, and the reason the user gives — and turns recurring corrections into confirmed rules. Two things it refuses to do: change the profile from a single edit, and change it without the user saying yes.
Why: corrections are otherwise lost between sessions; a one-off edit generalised into a rule distorts the profile; and stored draft-vs-edit pairs with the user's stated reason are the highest-value signal for the next draft (PersonaMail, IUI '26, arXiv:2602.17340: reuse of edit-derived strategies cut total drafting time 42 %, n = 16).
When to use
- "here's what I actually sent", "I edited your draft — learn from it"
- "that was too formal / too long, remember that", "I never say X, cut it always"
- "what keeps getting corrected?", "make 'I hope this finds you well' a rule"
When NOT to use
- First profile or a full rebuild from the corpus →
voice-profile. - Drafting →
voice-write; judging a draft →voice-check. - Fact corrections (a date, a name, an amount) are not voice: log them tagged
FACT, never mine rules from them. - Generic "which email is better" or file diffs → not this skill.
Workflow
- Log the pair. Save the draft and the sent text to files, then:
Put the reason in a file (work=$(mktemp -d) # private scratch files; delete when done python3 "${CLAUDE_SKILL_DIR}/scripts/delta.py" --draft "$work/draft.md" --sent "$work/sent.md" \ --register email-external --reason-file "$work/reason.txt" [--tags FACT] [--metrics-only]--reason-file) rather than on the command line: reasons are user text and must never be interpolated into a shell string.--metrics-onlystores tags and metrics without diff lines when the pair is sensitive. The script prints the metric deltas (words, paragraphs, contractions, politeness markers, hedges, opener and sign-off classes), the auto tags (LENGTH_CUT,LESS_FORMAL,OPENER,SIGNOFF,LLM_ISM,STRUCTURE,HEDGE_CUT, …) and the removed/added lines. Report those; add the user's reason if they gave one — it is the most useful field. - Explicit corrections ("I never write 'I wanted to reach out'") are logged the same way with the offending sentence as the draft and the fix as the sent text, or promoted directly (step 4) when the user is unambiguous.
- Report on request or after every ~5 entries:
Recurring removed phrases (≥ 2 independent entries) are ban candidates; recurring added phrases are keep candidates; tag counts show the dominant correction. Suggest putting the dominant correction into the nextpython3 "${CLAUDE_SKILL_DIR}/scripts/delta.py" --report [--register R]voice-writebrief until the profile is rebuilt. - Promote only on confirmation. Show the exact phrase and scope, get a yes, then:
Withoutpython3 "${CLAUDE_SKILL_DIR}/scripts/delta.py" --promote-ban "i hope this finds you well" \ --scope email-external --confirm # --scope defaults to all; use the register the correction came from python3 "${CLAUDE_SKILL_DIR}/scripts/delta.py" --promote-keep "thx" --confirm--confirmthe script only says what it would do. Every promotion snapshotsprofile.v<N>.jsonfirst; rollback is copying it back overprofile.json. An explicit standing instruction from the user ("never sign off with Best regards") may be promoted directly — that is the user's rule, not an inference; inferred rules need recurrence. - Rebuild when the log says so: many
LENGTH_*or*_FORMALentries in one register mean the bands are stale or the corpus was thin — runvoice-profileon a refreshed corpus rather than stacking rules.
Output spec
One appended line in <home>/calibration.jsonl per pair (0600; removed/added lines,
metrics, tags and the reason, all with emails/URLs/phones redacted — the diff lines are
still message content, so use --metrics-only for sensitive pairs; full texts only with
--keep-text); on --report, tag counts, recurring phrases and reasons; on
--promote-* --confirm, an updated profile.json plus a snapshot.
Gotchas
- A single edit is not a rule. The report needs the phrase in ≥ 2 entries; identical pairs logged twice count once. Even then the user confirms — repeated edits can be task-specific or from one recipient.
- Reasons beat diffs. "concise" often means "no pleasantries", not "shorter"; ask for the reason when it is missing.
- The log describes whom the user softens for and where they cut — a map of their relationships. It lives in the 0700 home, is never committed, full texts are off by default, and the user can delete lines from it or the whole file at any time.
- A mixed edit (a date fixed and a sentence cut) tagged
FACTis excluded whole; log the style part separately if it matters. - Promotions add bans with
source: calibration;voice-profilere-runs keep them. - Needs
voice-profile/scripts/stylometry.pynext to this skill.
Files
scripts/delta.py— log / report / promote (append-only, snapshots).scripts/test_delta.py— self-test.references/calibration.md— tag definitions, the recurrence rule, log schema, and the evidence.