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.development
Close the loop on a Linear ticket when its work ships - move the status and post a deploy comment with the PR link, what shipped, and a try-it link, mentioning the collaborator. Used as the tail of /ro:linear-nightshift for every merged mirror, or manually after an ad-hoc build. Triggers on "linear update", "update the linear ticket", "mark NUT-x done", "tell eoin it shipped", "/ro:linear-update".
devops
Run a night-shift against a collaborator's Linear board. Pulls the team's Grilled tickets (/ro:linear-grill moves a ticket to Grilled once its questions are answered), VERIFIES the questions were actually answered (unanswered → bounce the ticket to the "Question for <name>" state), mirrors verified tickets to ephemeral GitHub issues with ready-for-agent, then runs the standard /ro:night-shift machinery on GitHub. Tail-calls /ro:linear-update for everything that merged + deployed. Triggers on "linear nightshift", "nightshift linear", "drain the linear board", "run the shift off linear", "/ro:linear-nightshift".
development
Grill a collaborator's Linear tickets and move every processed ticket to where it belongs. Resolves the board from the repo's .ro-linear.json, reads the collaborator's Backlog / Ready-for-agent issues, then per ticket either posts 3-5 decision-extracting questions (state moves to "Question for <name>") or confirms it build-ready (state moves to "Grilled", the gate /ro:linear-nightshift consumes); shipped-and-confirmed tickets close as Done. The async-collaborator counterpart of /ro:day-shift for people who never touch GitHub. Triggers on "grill linear", "grill eoin's tickets", "linear grill", "add questions to the linear tickets", "/ro:linear-grill".
development
--- name: about-page description: Add a standard About page to any web app, what it is, the tech stack, and an FAQ, wired into a footer link with a sticky footer. Built with Spartan + Tailwind (the canonical component layer) and falls back to semantic HTML so it ships reliably. Use whenever building, polishing, or shipping an app, every app should have one. Triggers on "add an about page", "about page", "footer about link", or as a standard step in app build/polish. category: frontend argument-h