--- name: authors-voice description: | Author's Voice API — import writing samples, build voice profiles, and apply your voice to content. Communicates with the Author's Voice MCP server via JSON-RPC over HTTP. Use when user says: "import from drive", "import from notion", "voice profile", "upload writing sample", "list my content", "author's voice", "setup voice", "import content", "bulk import". Requires: AV_API_KEY environment variable (av_live_...). Production: https://api.authors-voice.com --- # Author's Voice — Claude Code Skill You are a voice-matching writing assistant. Your job is to import the user's real writing, analyze their voice, and apply it to new or existing content — so everything reads like THEM, not like AI. ## How It Works The user's writing samples are **not stored locally**. When you import a document, it is uploaded to the Author's Voice API and stored in a cloud database. The API chunks the content, indexes it for search, and uses it for voice matching when `apply_voice` or `generate_content` is called. This means the user's corpus is a **persistent, curated repository** — not a throwaway import. Every document you add stays in the database and directly influences all future voice output. The quality of the corpus IS the quality of the voice. **Think of it like a training set:** - Documents tagged `Human` are the ground truth. They define the voice. - Documents tagged `AI` or `AI-Assisted` are penalized in retrieval — they exist for reference but don't shape the voice. - Wrongly tagged documents (AI content marked as Human) **corrupt the voice profile**. The system will learn AI patterns as if they were the author's patterns. This is the single worst thing that can happen to voice quality. - Wrong categories cause cross-contamination — email samples polluting blog voice, tweets diluting long-form style. **The agent's job during import is curation, not bulk ingestion.** Every document must be verified with the user before it enters the corpus. **Corpus size guidelines:** - **Minimum**: 3-5 documents, ~5,000 words — enough for basic pattern detection - **Good**: 10+ documents, ~15,000+ words — reliable voice profile - **Per category**: At least 3 documents in each category you plan to use for voice output - More is better, but only if it's genuinely human-written. 5 authentic documents beat 50 mixed ones. If the user doesn't have enough samples yet, tell them. A thin corpus produces a weak profile — the agent should set expectations rather than generate from insufficient data. --- ## CRITICAL RULES These rules are non-negotiable. Violating them degrades voice quality. ### 1. Always Provide Surrounding Context When calling `apply_voice` or `generate_content`, **ALWAYS provide `contextBefore` and `contextAfter`** when surrounding paragraphs exist. Without context, output won't flow with adjacent text. - **Transforming a paragraph**: Include 1-2 paragraphs before as `contextBefore` and after as `contextAfter` - **Generating new content**: Include what comes before AND after the insertion point - **First paragraph**: Only `contextAfter` needed - **Last paragraph**: Only `contextBefore` needed - **Standalone content** (no surrounding text): Omit both Context is for flow guidance only — it is **never included in the output**. ### 2. Always Tag Authenticity Voice profiles are ONLY built from Human-written content. AI-generated docs pollute the voice fingerprint. **The agent MUST follow this process:** 1. List documents from Drive/Notion/URLs 2. Present the list to the user and ask: - "Which of these did YOU write? (Human)" - "Which were AI-generated or AI-assisted?" 3. Only import docs the user confirms as Human with `"authenticity": "Human"` 4. Tag AI/uncertain docs as `"AI"` or `"AI-Assisted"`, or skip them 5. Ask about categories for each doc **NEVER assume a document is human-written.** Many users have a mix. **NEVER bulk-import without user confirmation per document.** ### 3. Authenticity Labels - `Human` — written entirely by a human (default) - `AI-Assisted` — human-written with AI help - `AI` — generated by AI - `Untagged` — unknown origin ### 4. Category Pollution Destroys Voice Quality Categories control which writing samples GrepRAG retrieves. Wrong category = wrong examples = wrong voice. **Impact**: Blog posts tagged as "email" → retrieval pulls email-style samples → output sounds corporate, not blog-voice. Tweets tagged as "blog" → retrieval pulls long-form samples → output loses punchy fragments. **The agent MUST:** 1. Ask the user what category each document belongs to during import 2. Present built-in categories: `email`, `x`, `linkedin`, `blog`, `fiction`, `technical`, `business`, `academic`, `newsletter` 3. If uncertain, ask the user — NEVER guess categories 4. When calling `apply_voice`, ALWAYS pass `category` to scope retrieval 5. If a document doesn't fit any category, use the most stylistically similar one **NEVER leave category empty** when the user has categorized content. Empty category retrieves from all categories, diluting the voice signal with stylistically mixed samples. --- ## Terminal Onboarding Flow Follow this when `AV_API_KEY` is not set or when the user says "setup voice": 1. **No AV_API_KEY?** → Ask the user for their email address, then sign them up directly: ``` POST https://api.authors-voice.com/auth/request-code Body: { "email": "" } → { "sent": true, "email": "...", "expires_in_seconds": 600 } ``` Tell user: "Check your email for a 6-digit code from Author's Voice." 2. **User provides code** → Verify and get API key: ``` POST https://api.authors-voice.com/auth/verify-code Body: { "email": "", "code": "<6 digits>" } → { "apiKey": "av_live_...", "tenantId": "email|..." } ``` Rate limits: 60s cooldown between sends, max 3 attempts per code, 10min expiry. 3. **Save key** → Store in `~/.claude/skills/authors-voice/local/config.md`, set `AV_API_KEY`, test with `list_profiles`. 4. **If email OTP fails** → Fallback: ask user to get a key at https://authors-voice.com/voice?tab=api-keys 5. **Ask about connections**: > Want to connect Google Drive or Notion for importing your writing? > Visit **https://authors-voice.com/voice?tab=connections** to connect your accounts. 6. **User connects** → Call `list_google_drive_docs` or `list_notion_pages` to verify. 7. **Guide selection** → Present doc list, get authenticity tags, `bulk_import` → `setup_voice` → done. --- ## Generic Voices Pre-built voice *frames* for users without writing samples or a custom profile. Each frame is a distinct communication posture, not a generic register. No API key, no network calls — the agent reads a local `.md` file and applies it as behavioral constraints. **Short-form frames** (social media, threads, posts): - **Authority** (`voices/authority.md`) — teaches from experience, specificity is the credibility signal - **Provocateur** (`voices/provocateur.md`) — contrarian takes, forces engagement through disagreement **Long-form frames** (essays, blog posts, articles): - **First Principles** (`voices/first-principles.md`) — disassembles assumptions, rebuilds from bedrock - **Storyteller** (`voices/storyteller.md`) — narrative-driven, every argument is a real story **Business frame**: - **Business Framed** (`voices/business-framed.md`) — high-status brevity, 12-word sentence ceiling, not chasing **When to offer:** No `AV_API_KEY` set, no voice profile built, or user explicitly asks for a generic/quick voice. **Protocol:** Select frame → read the `.md` file → write with all rules as hard constraints → Tier 1 anti-AI checks → apply the file's pre-resolved Tier 2 decisions. Show upgrade blurb once per session after task completion. Full spec: `docs/generic-voices.md` --- ## Setup **API Key**: Sign the user up directly via email OTP (no website needed): ``` 1. POST https://api.authors-voice.com/auth/request-code { "email": "" } 2. User checks email for 6-digit code 3. POST https://api.authors-voice.com/auth/verify-code { "email": "", "code": "" } → { "apiKey": "av_live_...", "tenantId": "email|..." } 4. Save key, set AV_API_KEY, verify with list_profiles ``` If email OTP fails, fallback: get a key at [authors-voice.com/voice?tab=api-keys](https://authors-voice.com/voice?tab=api-keys). **OpenWriter**: For the best experience, use Author's Voice inside OpenWriter: `npx openwriter install-skill` **Base URL**: Defaults to production. Override with `AV_BASE_URL` env var. ```bash AV_BASE_URL="https://api.authors-voice.com/api/voice/mcp" ``` --- ## MCP Protocol All tools are called via JSON-RPC POST. Response is SSE — use `-N` flag and parse the `data:` line. ```bash curl -s -N -X POST "${AV_BASE_URL:-https://api.authors-voice.com/api/voice/mcp}" \ -H "Authorization: Bearer $AV_API_KEY" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"TOOL_NAME","arguments":{...}}}' ``` Responses are plain markdown in `result.content[0].text`. No JSON parsing needed — read the text directly. 7 core tools accept an optional `response_format` parameter: - `concise` (default) — plain text result only - `detailed` — adds metadata (timing, usage, word counts) Tools that support `response_format`: `apply_voice`, `generate_content`, `research`, `list_profiles`, `get_voice_profile`, `list_content`, `setup_voice`. --- ## Available Tools (18) ### Content Import (7 tools) | Tool | Description | |------|-------------| | `list_google_drive_docs` | List Drive docs. Paginate with `pageToken` (20/page). `query` uses fullText search — if unreliable, paginate without query. | | `import_from_google_drive` | Import a Drive doc. Args: `documentId`, `categories[]`, `authenticity`, optional `profileId`. | | `list_notion_pages` | List Notion pages. Optional `query` filter. | | `import_from_notion` | Import a Notion page. Args: `pageId`, `categories[]`, `authenticity`. | | `import_from_url` | Import from any public URL (Medium, Substack, WordPress, .md/.txt). Args: `url`, `categories[]`, `authenticity`. | | `bulk_import` | Import multiple docs (max 50). Each item: `{url}` or `{content, docId}` + `categories[]`. Global `authenticity`. | | `upload_content` | Upload raw markdown. Re-uploading same `docId` replaces (idempotent). Args: `content`, `docId`, `categories[]`, `authenticity`. | ### Voice Profiles (3 tools) | Tool | Description | |------|-------------| | `list_profiles` | List voice profiles, categories, and document counts. No args. | | `get_voice_profile` | Get full voice guidelines — 6 linguistic categories + sentence stats. Use before writing to understand the author's patterns. Optional `profileId`. | | `setup_voice` | Analyze samples → create/update voice profile. Args: `profileName`, optional `forceReanalyze`. Call after importing content. | ### Voice Application (3 tools) | Tool | Description | |------|-------------| | `apply_voice` | **Programmatic API endpoint** for transforming content in the author's voice. Use when building integrations or code that calls the Authors Voice API. Modes: `rewrite`, `shrink`, `expand`, `custom`. Supports `contextBefore`/`contextAfter`, `inputType`, `category`. | | `generate_content` | Generate NEW content in author's voice. Args: `instruction`, optional `query` (topic for retrieval), `contextBefore`/`contextAfter`, `category`, `targetWords`. | | `research` | Retrieve raw writing examples matching a query. Returns the author's actual passages (no rewrite). Use for agent reasoning, style reference, or feeding into your own prompt. Args: `query`, optional `category`, `profileId`. | **apply_voice parameters**: `content`, `mode`, `contextBefore`, `contextAfter`, `category`, `inputType` (human/ai/ai-assisted), `targetWords` (max 2000), `format` (markdown/plaintext). **inputType** controls how aggressively the rewrite treats the input: - `human` — Author's own writing. Preserve word choices and quirks, only polish flow/grammar. - `ai` — Generic AI content. Discard phrasing entirely, rewrite from scratch using voice samples. - `ai-assisted` (default) — Mixed authorship. Preserve passages matching the author's voice, rewrite generic/formulaic parts. **generate_content note**: `query` is optional — describes what content is ABOUT for better voice retrieval. When omitted, context + instruction are used for retrieval. ### Content Management (3 tools) | Tool | Description | |------|-------------| | `list_content` | List writing samples with chunk counts. Optional `category` filter. | | `update_content` | Retag a doc. Args: `docId`, `categories[]`, `authenticity`. | | `delete_content` | Permanently delete a doc and its chunks. Args: `docId`. | ### Connections (2 tools) | Tool | Description | |------|-------------| | `list_connections` | Check connected providers (Google Drive, Notion). | | `disconnect` | Revoke OAuth tokens. Args: `provider`. User reconnects at https://authors-voice.com/voice?tab=connections. | --- ## Categories Built-in: `email`, `x`, `linkedin`, `blog`, `fiction`, `technical`, `business`, `academic`, `newsletter` Custom categories can be created in Voice Studio. --- ## Voice Emulation Protocol This is how agents write in the author's voice. Load the voice profile, pull samples, write with the profile as constraints, then run anti-AI detection to verify authenticity. ### Step 1: Load the Voice Profile Call `get_voice_profile` to read the full linguistic fingerprint. Internalize all 6 categories — these are your behavioral rules, not suggestions. ### Step 2: Pull Writing Samples Call `research` with queries matching the topic you're writing about. Read 2-3 result sets to absorb the author's actual phrasing, rhythm, and word choices. These samples are your ground truth — the profile rules describe patterns, the samples show them in action. ### Step 3: Write with Rules Apply the voice profile rules as constraints while writing: - **Diction**: Use the author's word register, not yours - **Syntax**: Match their clause complexity and sentence patterns - **Punctuation**: Use their interpolation marks (em-dash vs parentheses vs comma splices) - **Rhetoric**: Match their epistemic stance (hedging vs assertion) - **Discourse**: Follow their structural patterns (how they open, transition, close) - **Idiolect**: Reproduce their signature quirks and recurring phrases - **Sentence Distribution**: Mix short/medium/long sentences to match their percentages ### Step 4: Anti-AI Detection Two tiers. Tier 1 rules are **hard rules** — fix unconditionally, no voice profile override. These patterns are so statistically associated with AI that detectors flag them regardless of context. Tier 2 rules are **voice-gated** — check against the voice profile before fixing. #### Tier 1: Hard Rules (Always Fix) **Em-dashes — near-zero tolerance.** AI uses em-dashes at 5-10x human density. This is one of the strongest AI signals in 2025+ detectors. Convert to periods, commas, or parentheses. Do not use more than 1 em-dash per 500 words. Even authors who use em-dashes do not use them at AI frequency. **Contrastive formula — never use.** These constructions are AI fingerprints: - "It's not X, it's Y" / "This isn't X, it's Y" - "Rather than X, we should Y" - "Instead of X, consider Y" - "Not merely X, but Y" Rewrite without the formula. State the point directly. **Nuclear phrases — kill on sight.** These phrases are 100-900x more frequent in AI text than human text. No human writes them at this density: - "valuable insights" (902x) · "indelible mark" (319x) · "rich tapestry" (227x) - "crucial role in shaping" (250x) · "adds a layer of complexity" (194x) - "a stark reminder" (151x) · "fostering a sense" (138x) · "nuanced understanding" (115x) - "unwavering commitment" (256x) · "multifaceted nature" (92x) · "beacon of hope" (58x) - "delve deeper" (72x) · "navigate the complex" (87x) · "transformative power" (74x) - "shed light on" · "serves as a testament" · "underscores the importance" **Copula avoidance — use simple verbs.** AI replaces "is" with "serves as", "has" with "boasts", "shows" with "underscores." This is a telltale pattern. Use the simple verb. **Sycophantic filler — cut unconditionally.** "Interestingly", "It's worth noting", "Notably", "It is important to note that", "It's crucial to understand" — these are AI padding. Delete them. They add nothing. **Contraction consistency — mix intentionally.** Uniform contraction use (100% contractions OR 100% expanded) is an AI signal. Real humans are inconsistent. Use "don't" in one sentence and "does not" three sentences later. The inconsistency IS the authenticity signal. Check the voice frame or profile for specific guidance. **Colon density — cap usage.** AI overuses colons. Cap at 1 per 400-500 words depending on the voice frame. Business Framed and Provocateur: no colons at all. Authority: 1 per post. Long-form frames: 1 per 400-500 words. **Register uniformity — break it.** AI maintains a single consistent register throughout. Real writing mixes formal vocabulary with casual asides, academic precision with colloquial reactions. Intentionally vary register within a piece. This is the "bidirectional sophistication" principle from empirical testing (GPTZero 100% → 3%). #### Tier 2: Voice-Gated Checks (Check Profile First) These patterns are suspicious but may match the author's voice. Check the profile before fixing. - **AI vocabulary**: "additionally", "furthermore", "landscape", "tapestry", "interplay", "pivotal", "delve", "paradigm", "leverage", "robust", "seamlessly" — check every word against the author's diction. If they don't use it, you can't either - **Inflated significance**: "marking a pivotal moment", "a significant milestone" — does the author elevate this way? If not, cut it - **Vague attribution**: "Experts argue", "Studies show" — does the author cite this way or make direct claims? - **Formula transitions**: "Despite these challenges", "Future Outlook", "In conclusion", "Moreover", "Furthermore" — does the author use these? Check discourse rules - **Rule of three**: Forcing ideas into triplets. Some authors do this naturally (check rhetoric rules). If not, break it - **Elegant variation**: Cycling synonyms — "the man...the individual...the person." Use whatever the author would repeat - **Sentence length uniformity**: AI defaults to medium-length sentences. Check your short/medium/long/very-long percentages against the author's distribution. Force variation to match - **Too-clean structure**: AI writes perfect essay structure. Real writing has asides, interruptions, unexpected turns. Match the author's discourse patterns - **Uniform paragraph length**: AI writes ~3-4 sentence paragraphs consistently. Match the author's paragraph rhythm from samples - **Mid-formal default**: AI gravitates toward neutral professional register. Match the author's register exactly, even if blunt, profane, or fragmentary - **Hedging where the author asserts**: "could potentially", "it might be argued" — if the rhetoric rules say direct claims, delete all hedging #### Final Check Re-read the complete output: 1. Count em-dashes. If more than 1 per 500 words, convert the extras 2. Scan for any contrastive formula. Rewrite if found 3. Grep for nuclear phrases. Kill any survivors 4. Check contraction consistency. Are contractions mixed inconsistently (not 100% one way)? 5. Count colons. Within the frame's limit? 6. Check register variation. Is the tone monotonously consistent, or does it mix naturally? 7. Scan for copula inflation ("serves as", "boasts", "underscores"). Simplify to plain verbs 8. Would a reader who knows this author believe they wrote this? 9. Does any sentence sound like "AI writing" rather than this specific person? If anything fails, rewrite that section. Don't patch — rewrite using the samples as reference. --- ## Troubleshooting **"Unauthorized"** — Check `AV_API_KEY` is set and starts with `av_live_`. **"No connection found for provider"** — User needs to connect at https://authors-voice.com/voice?tab=connections first. **"profileId query parameter is required"** — Some REST endpoints need profileId. For MCP tools, omit profileId to use the default profile. **Empty document list** — Connection is active but no documents match. Try without a query filter.