skills/voice-profile/SKILL.md
Build a portable voice profile (markdown file) by running a 100-question taste interview across 7 categories. Output is consumable by any AI to reproduce the user's voice. Resumable across sessions. Based on Ruben Hassid's "I am just a text file" methodology (Jan 2026).
npx skillsauth add RonanCodes/ronan-skills voice-profileInstall 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.
Build a portable voice-profile.md that any AI can read to reproduce the user's writing voice. Based on Hassid's methodology (Jan 2026): voice is mostly refusals, not preferences, so the interview captures what the user would never write.
Source documents:
/ro:voice-profile start # begin a new interview (or resume if in progress)
/ro:voice-profile resume # explicit resume — pick up where you left off
/ro:voice-profile status # show progress (questions answered per category)
/ro:voice-profile compile # build voice-profile.md from current state
/ro:voice-profile show # cat the compiled voice-profile.md
/ro:voice-profile path # print canonical file paths (state + output)
The interview is ~100 questions and takes 60–120 minutes. It is meant to be run in chunks across multiple sessions. State persists between sessions.
Claude (you, reading this) conducts the interview live in chat. The user answers in chat. Their answers get persisted to a state file by you (Edit/Write the JSON directly).
| # | Category | Questions | Probes (the area to interrogate) | |---|----------|-----------|----------------------------------| | 1 | Beliefs & Contrarian Takes | 15 | Beliefs others in the field don't share; hot takes; conventional wisdom they think is wrong | | 2 | Writing Mechanics | 20 | Sentence structures, openers/closers, punctuation/formatting habits, words they overuse / love / never use | | 3 | Aesthetic Crimes | 15 | What makes them cringe in others' writing; nails-on-chalkboard phrases; lazy content patterns | | 4 | Voice & Personality | 15 | Humor, serious vs casual, handling disagreement, sound when excited vs skeptical | | 5 | Structural Preferences | 15 | How they organise ideas, lists/headers/bullets, transitions, default content shapes | | 6 | Hard Nos | 10 | Topics they'd never write about, approaches they'd never take, lines they won't cross | | 7 | Red Flags | 10 | What makes them distrust a piece of content immediately; signals someone doesn't know what they're talking about | | Total | | 100 | |
Hassid did not publish the verbatim 100 questions. Generate them dynamically within each category, guided by the probes. This adapts to the user's prior answers and avoids overlap.
The point is rich, specific answers. A 3-word vague answer is worthless. A 4-paragraph specific answer is the goal.
| Arg | Behavior |
|-----|----------|
| start | If no state exists, run scripts/start.sh to create one (asks for user's name first), then begin Q1 of category 1. If state exists with status in_progress, behave as resume. |
| resume | Read state, print summary ("You're 23 of 100 done, currently in Category 2: Writing Mechanics"), then ask the next unanswered question. |
| status | Run scripts/status.sh. Print only — do not ask a question. |
| compile | Run scripts/compile.sh. Compile current state into voice-profile.md. Works even if interview is incomplete (will mark unanswered sections). |
| show | Run scripts/show.sh to print the compiled file. |
| path | Run scripts/path.sh to print where state and output live. |
After each user answer that has passed the rules (specific, exampled, non-contradictory), update the state file at ~/.claude/voice-profile-state.json directly via the Edit tool. Append a new entry to the category's answered array:
{
"q": "<the question you asked>",
"a": "<their answer, verbatim>",
"follow_ups": [
{"q": "<your push-back>", "a": "<their refined answer>"}
],
"answered_at": "<ISO 8601 timestamp>"
}
Then ask the next question. Do not batch — record after every settled answer so the work is never lost mid-session.
When a category finishes (e.g., 15/15 in Beliefs):
/ro:voice-profile resume.When all 100 are done, run scripts/compile.sh and tell them where the file is.
No setup. The skill creates ~/.claude/voice-profile-state.json on start and ~/.claude/voice-profile.md on compile. Both are gitignored by default.
State and output default to ~/.claude/ but are overridable via env vars (see scripts/common.sh):
VOICE_PROFILE_STATE — path to the JSON state fileVOICE_PROFILE_OUTPUT — path to the compiled markdownTo keep a profile inside an llm-wiki vault (versioned, browsable in Obsidian, resumable across machines), export both before any subcommand:
export VOICE_PROFILE_STATE="$PWD/vaults/llm-wiki-voice/scratchpad/voice-profile-state.json"
export VOICE_PROFILE_OUTPUT="$PWD/vaults/llm-wiki-voice/wiki/entities/voice-profile-<name>.md"
Resume discovery (important). When the user asks in natural language to "continue / pick up my voice profile" — without typing /ro:voice-profile resume — do NOT start a fresh interview. Locate existing state first, in this order:
vaults/*/scratchpad/voice-profile-state.json under the current repo.~/.claude/voice-profile-state.json.If a state file with status: in_progress is found, export VOICE_PROFILE_STATE/VOICE_PROFILE_OUTPUT to point at it, run status to reload progress, then behave as resume.
voice-profile.md follows Hassid's template:
# VOICE PROFILE: <Name>
## Core Identity (2-3 sentence essence — only summary section)
## SECTION 1: BELIEFS & CONTRARIAN TAKES (Q1–Q15 with full answers)
## SECTION 2: WRITING MECHANICS (Q16–Q35)
## SECTION 3: AESTHETIC CRIMES (Q36–Q50)
## SECTION 4: VOICE & PERSONALITY (Q51–Q65)
## SECTION 5: STRUCTURAL PREFERENCES (Q66–Q80)
## SECTION 6: HARD NOS (Q81–Q90)
## SECTION 7: RED FLAGS (Q91–Q100)
## QUICK REFERENCE CARD
- Always
- Never
- Signature Phrases & Structures
- Voice Calibration (key quotes from the interview)
## HOW TO USE THIS DOCUMENT (ANTI-OVERFITTING GUIDE)
- Frequency labels: HARD RULE / STRONG TENDENCY (70–80%) / LIGHT PREFERENCE
- Litmus test: "Does this sound like something I would actually write, or does it sound like an AI trying very hard to imitate me?"
- Format adaptation: tweet ≠ newsletter ≠ LinkedIn ≠ long-form
- Spirit Over Letter
## INSTRUCTIONS FOR CLAUDE (the file is the context — every prompt should start by reading it)
The Quick Reference Card and Anti-Overfitting Guide are derived from the answers, not asked directly. Compile them after the 100 are done.
start or resume — no surprise re-engagement on every session.~/.claude/voice-profile.md only. The user is responsible for copying it to other AIs / hosts./ro:write-copy or a future /draft skill) decides which tendencies apply per format.ro:write-copy — once voice-profile.md exists, this skill should read it as additional context for any drafting work.reference.md — full question-bank guidance, output template, anti-overfitting layer detail.testing
--- name: linear-pipeline description: The Fable orchestrator for a single dispatched Linear ticket. Holds almost no context itself; it receives `--issue <ID> --detached`, decides the stage sequence, and fans out a sub-agent per stage, passing forward only each stage's artifact (never re-derived, never inlined into its own context). Step zero, before any planning or stage routing, is a boundary triage against `canon/security-boundary.md` (#199): a match tags Ronan Connolly and stops the run, no
development
--- name: in-your-face description: Capture a chat-only answer into a durable artifact (markdown + HTML, PDF when cheap) and launch it automatically so the user cannot miss it. Use when user says "in your face", "don't let me lose this", "save that answer", "make that durable", or right after answering a substantive side question (a recipe, comparison, how-to, or generated prompt) that would otherwise die with the context. category: workflow argument-hint: [--no-open] [--vault <short>] [hint of
tools
One-shot headless OpenAI Codex CLI calls for background/admin AI tasks — summaries, classification, extraction, admin glue. The default engine for anything that runs AI constantly in the background (daemon-driven, per-event), because it bills the flat ChatGPT subscription instead of Claude usage or per-token API spend, and it keeps working while Claude is rate-limited. NEVER for coding — coding stays Claude. Use when a skill or daemon needs a cheap always-on AI call, when the user says "use codex", "ask codex", "codex as backup", or when building a background summarizer/classifier into a listener or loop. Reads auth from ~/.codex/auth.json (ChatGPT account, no API key).
research
Turn a warranty rejection, repair quote, or RMA email into a cited decision brief — legal read (NL/EU consumer law), is the part user-serviceable, live part and new-unit prices, repair-vs-DIY-vs-new economics, before-you-send-it checklist, deadlines. Use when the user pastes or screenshots a repair quote, warranty rejection, "not covered" email, onderzoekskosten fee, or asks "should I repair or replace this".