The author profile is the core of StoryForge. Without a profile, the plugin won't write. By design β an author profile is what keeps your text from sounding like generic AI output.
An author profile is not a marketing persona. It is a set of parameters that determines how prose is built at sentence, paragraph, and dialog level. The quality of your book depends directly on the quality of your author profile.
v2.x: An author's
vocabulary.mdis no longer just a soft reference for the voice-checker β it is now read by the PostToolUse hook live during writing as a hard-block source. Every word in the### Forbidden ...sections blocks the write attempt withexit 2. See Hook Integration below.
Author-wide Don'ts: Beyond
vocabulary.md, the hook now also reads## Writing Discoveries / ### Don'tsfromprofile.md. Patterns you place there as backtick regex (`\bthe (room|silence) (received|held)\b`) or italicized example phrases (*The room received it.*) block the write for every book by this author. Themanuscript-checkerscans the same section plusvocabulary.mdβ author-level rules no longer need to be duplicated into each book'sCLAUDE.md.
v3.0.0 β SQLite as authoritative store:
author_discoveries(style_principles, donts, vocabulary) are now persisted in SQLite. The filesprofile.mdandvocabulary.mdremain as the primary input files, but at runtime the database is the authoritative source. No more stale reads from Markdown files.harvest-author-ruleswrites directly to theauthor_discoveriesDB. For direct DB entries, the new MCP tooladd_vocabulary_entryis available. See SQLite Storage (v3.0.0) below.
AI models have a "default style": light elegance, abstract poetic nouns, low-variance sentences, dialog-beats instead of subtext. This default sounds the same everywhere β whether horror or romance. The voice-checker calls it "AI tells".
Author profiles are the countermeasure:
When chapter-writer runs, it loads the profile first, always. Every prompt context contains the profile parameters. When a Write is attempted, the PostToolUse hook additionally checks against vocabulary.md β banned words are hard-rejected.
Author profiles live outside the plugin directory so they survive plugin updates:
~/.storyforge/authors/{slug}/
βββ profile.md # Main profile (YAML frontmatter + prose)
βββ vocabulary.md # Forbidden sections (hook banlist) + Preferred + Signature
βββ studied-works/ # Analysis results from imported PDFs/EPUBs
β βββ my-novel-2023.md
β βββ short-story-collection.md
βββ examples/ # Manual sample texts (optional)
βββ voice-sample-1.md
v3.0.0: At runtime, the hook reads from the SQLite DB (
~/.storyforge/db/author_discoveries.db), no longer directly from Markdown files. The.mdfiles remain as input source and human-readable reference β when you changevocabulary.md, runharvest-author-rulesto sync the DB.
---
name: "Maja Sundberg"
slug: "maja-sundberg"
created: "2026-04-24"
updated: "2026-04-24"
primary_genres: ["contemporary", "mystery", "literary-fiction"]
narrative_voice: "third-person-limited"
tense: "past"
tone: ["melancholic", "understated", "coastal"]
sentence_style: "varied-short-to-long"
vocabulary_level: "moderate-with-regional-terms"
dialog_style: "naturalistic-with-dialect-markers"
pacing: "slow-build-with-occasional-sharp-accelerations"
themes: ["memory", "loss", "the-sea-as-character"]
influences: ["Jon Fosse", "Siri Hustvedt", "Per Petterson"]
avoid:
- "purple-prose"
- "info-dumps"
- "deus-ex-machina"
- "therapist-speak"
- "epiphany-moments"
author_writing_mode: "outliner"
native_language: "sv" # ISO 639-1: author's mother tongue (for chapter-proofreader explanations)
preferred_writing_language: "sv" # ISO 639-1: fallback when no book_language is set
---
Required fields:
| Field | Values |
|---|---|
name |
Human name of the author/persona |
slug |
URL-safe slug (filesystem name) |
narrative_voice |
first-person, third-person-limited, third-person-omniscient, second-person |
tense |
past, present, mixed |
author_writing_mode |
outliner, plantser, discovery |
Important optional fields:
tone β array of descriptors (3-5 recommended)sentence_style β "varied", "short-terse", "long-flowing", "mixed"vocabulary_level β "sparse", "moderate", "rich", "dense"dialog_style β "naturalistic", "stylized", "minimal", "dialectal"pacing β "tension-driven", "meditative", "action-heavy", "slow-build"themes β central thematic obsessionsinfluences β literary modelsavoid β what this author never doesnative_language β author's mother tongue (ISO 639-1, e.g. de, fr, sv) β determines the explanation language in chapter-proofreaderpreferred_writing_language β default writing language (ISO 639-1) β fallback when no book_language is set in the book frontmatterThe field author_writing_mode is a required frontmatter field and is set during create-author and configure:
### Writing Mode
author_writing_mode: plantser
| Value | Effect |
|---|---|
outliner |
new-book proposes the full outliner pipeline |
plantser |
plot-architect switches to MVO mode (6 beats) |
discovery |
new-book skips plot-architect, suggests rolling-planner |
The author profile can be overridden per book β e.g. an outliner author writes an experimental novella in discovery mode.
After the frontmatter follow structured prose sections:
## Writing Style
Maja writes with the economy of a poet and the rhythm of a song.
Her sentences alternate between 6-word fragments and 40-word arcs.
She never describes an emotion directly β she shows it through objects,
landscape, body posture.
## Narrative Approach
- **POV:** Third-person limited, deeply anchored in the POV character
- **Tense:** Past, except in memories β then italic present-tense inserts
- **Sentence style:** Varied. Short staccato sentences in conflict moments.
Long compound-complex sentences in reflective passages.
- **Dialog approach:** Naturalistic with regional markers (North Sea dialect).
## Signature Techniques
- **Object-as-emotion:** Feelings are never named, made visible through
objects (the coffee goes cold, the key cuts into the hand).
- **Weather-as-chorus:** Weather comments on the scene, never just backdrop.
- **Silence-heavy dialog:** Long pauses in dialog, marked by "β" or
action between two lines.
## Tone & Atmosphere
Melancholic but not depressive. The sea is always present β as comfort,
threat, mirror. Humor only dry, never silly.
## Strengths
- Atmosphere through omission
- Dialog that shows more than it says
- Regional authenticity without pastiche
## Deliberate Imperfections
- Likes to repeat "later" and "again" β not stylistic mistakes but
rhythm markers
- Short sentences at paragraph end are common: "That was all."
- Fragments as a stylistic device: "A boat. Far out. No light."
## Influences & Comparable Authors
- Jon Fosse (Septology) β for repetition and slow tempo
- Siri Hustvedt β for intellectual depth without didactics
- Per Petterson β for Nordic coolness and landscape prose
## Anti-Patterns
- **No interior monologues** that explain what just happened
- **No therapy speak** ("I feel exposed")
- **No epiphany moments** β characters never suddenly understand "everything"
- **No rhetorical questions** in narrator text
- **No abstract nouns**: journey, tapestry, realm, essence
This is the operationally most important file. Concrete words are defined here that get blocked or preferred. Since v2.x it is read by the PostToolUse hook live as a hard-block source. As of v3.0.0 the SQLite DB is the authoritative runtime source β vocabulary.md remains the input file.
For the hook to find the banned words, they must sit under exactly one of these four ### Forbidden ... subsections (within any ## Banned Words ... header):
# Vocabulary β Maja Sundberg
## Banned Words β AI Tells
### Absolutely Forbidden
- delve / delve into
- tapestry (metaphorical)
- nuanced
- vibrant
- pivotal
- realm
- testament
- journey (metaphorical)
### Forbidden Hedging Phrases
- it's worth noting that
- arguably
- broadly speaking
- one might say
- to put it simply
### Forbidden Emotional Tells
- her heart raced
- a wave of emotion
- he felt the weight of
- she felt safe
- held space
### Forbidden Structural Patterns
- in essence
- at its core
- this underscores the importance of
- a key takeaway is
- from a broader perspective
## Preferred Words
Words this author actively uses. Preferred at word-choice conflicts.
### Everyday
- mug (always, not cup)
- boat (never ship, when small)
- path (never way)
### Regional markers (North Sea)
- moin (greeting)
- Schiet (mild)
- bΓΌschen (a little)
## Signature Phrases
Turns of phrase typical of this author. Used at most 2x per book
(otherwise becomes mannered).
- "...and then it was quiet."
- "That was that."
- "Not today."
Important: Sections outside the four official
### Forbidden ...subheadings are not recognized as a banlist by the hook. A## Preferred Vocabularysection next to## Banned Wordsis safe β words there are not accidentally blocked.
The hook supports two conventions per bullet:
delve / delve into β split into two separate patterns (delve and delve into)tapestry (metaphorical) β stripped, the pattern is just tapestryAs of v3.0.0, SQLite is the authoritative runtime source for all author_discoveries. This includes style_principles, donts, and vocabulary entries.
The Markdown files profile.md and vocabulary.md remain the primary input files. When harvest-author-rules runs, it parses their contents and writes directly to the author_discoveries DB β no more stale reads during the write hook or manuscript-checker.
vocabulary.md / profile.md
β
harvest-author-rules
β
author_discoveries.db β authoritative runtime source
β
Write-Hook / Manuscript-Checker
The add_vocabulary_entry tool allows inserting a vocabulary entry directly into the DB without touching the vocabulary.md file:
add_vocabulary_entry(
author_slug: "maja-sundberg",
entry_type: "absolutely_forbidden", # or: hedging_phrases, emotional_tells, structural_patterns
text: "luminous"
)
Useful for:
harvest-author-rules right now
add_vocabulary_entrydoes not updatevocabulary.md. For permanent sync, add the entry to the.mdfile as well β otherwise the nextharvest-author-rulesrun will overwrite the DB entry with the Markdown state.
~/.storyforge/db/author_discoveries.db
As of v3.0.0, author profiles can include antithetical voice examples β passages that explicitly show what the voice should not sound like. This sharpens the chapter-writer considerably because negative contrast material is more precise than abstract descriptions.
In profile.md under ## Anti-Examples (within the world-rules scaffold section):
## Anti-Examples
These passages show what Maja's voice does NOT sound like.
The chapter-writer loads this section and actively avoids these patterns.
### What NOT to sound like β Generic AI Prose
> The morning light cascaded through the window like a symphony of gold,
> bathing the room in a tapestry of warmth. She felt the weight of the
> moment, a journey toward something she could not yet name.
### What NOT to sound like β Therapy Speak
> "I feel like I need to process this," she said. "I need space to hold
> all these emotions. This is triggering something deep inside me."
### What NOT to sound like β Eloquent Teenager
> He surveyed the battlefield of his choices, understanding with crystalline
> clarity that every decision had led inexorably to this singular moment
> of reckoning.
The chapter-writer loads the ## Anti-Examples section on every run via get_author(). The model (claude-opus-4-8) uses these negative examples as contrast anchors β the more specific the anti-example, the sharper the avoidance. Generic prohibitions ("no therapy speak") are weaker than concrete counter-examples.
Recommendation: Collect at least 2-3 anti-examples from actual rejected AI outputs by your own chapter-writer β those are the most effective negative anchors because they show real model failure patterns, not hypothetical ones.
### Don'ts and ### Recurring TicsTwo more subsections under ## Writing Discoveries in profile.md feed the hook and the manuscript-checker with author-wide banlists:
### Recurring TicsPhrases the skill /storyforge:harvest-author-rules extracted from finished books. As of v3.0.0, harvest-author-rules writes these entries directly to the author_discoveries DB. Each bullet has a bold title with a quoted phrase as the scannable pattern:
## Writing Discoveries
### Recurring Tics
- **Vague-noun "thing" as a fallback** β "doing a thing with his hand"
or similar constructions: concretize on sight.
- **"count" as a time-marker tic** β *for a count of X*, *a long count* β
max 2-3 per chapter.
The hook extracts the phrase in double quotes (or falls back to the bold title text itself when no quotes are present). The /storyforge:harvest-author-rules skill writes automatically in this shape and syncs to the DB.
### Don'tsForbidden shapes that apply to every book by this author. Format convention:
### Don'ts
- **Never use word-count meta-commentary** β *Two words. He had not used them often.* /
*One word. The same way he texted.* The narrator must not count spoken syllables.
- **Never personify rooms or silences as receivers** β
`\bthe (room|silence|quiet) (received|held|carried|absorbed)\b`
Pattern sources per bullet (evaluation order):
| Form | When extracted | Example |
|---|---|---|
| Backtick regex | always | `\bthe room received\b` |
| Backtick literal | always | `Two words.` |
| Double quotes | only with a ban cue (Never, Avoid, ...) |
"totally landed" |
Italic (*...*) |
only with a ban cue | *The room received it.* |
Trailing sentence punctuation (., ,, !, ?, ;, :) is automatically stripped from italic patterns so *The room received it.* also matches The room received it without complaint.
Format tip: The anti-pattern catalog
reference/craft/anti-ai-patterns.md(Section 11 β Elegant Abstraction Register) ships ready-to-use backtick regexes for the five most common AI tells. Copy them straight into your### Don'tsand both hook and manuscript-checker enforce them for every book by this author.
| Source | Hook (write-block) | Manuscript-Checker (post-draft) |
|---|---|---|
vocabulary.md ### Forbidden ... |
yes, severity block |
yes, category author_vocab_violation |
profile.md ### Recurring Tics |
yes, severity block |
yes, category writing_discovery_violation |
profile.md ### Don'ts |
yes, severity block |
yes, category author_rule_violation |
profile.md ### Style Principles |
no (prose-level rule) | no (prose-level rule) |
Catalog anti-ai-patterns.md Section 11 (shape regex) |
yes, severity warn (auto, every author) |
yes, category global_shape_violation, severity medium |
Style Principles are intentionally not machine-scannable β they are narrative instructions for chapter-writer and chapter-reviewer, not phrase banlists.
Catalog shape bans: The five+1 elegant-abstraction shapes from
reference/craft/anti-ai-patterns.mdSection 11 (word-count meta, sentence-as-projectile, room-as-receiver, economic metaphor, near-miss body, body-part anthropomorphisation) are active for every author automatically β no copy into### Don'tsrequired. Severity iswarn(hook) / medium (manuscript report). To hard-block a shape (Writefails), copy the regex from Section 11 into### Don'tsβ it then counts as user-asserted and blocks for that author.
Style Principles: Not machine-scannable β they are narrative instructions for
chapter-writerandchapter-reviewer(both load this section viaget_author()on every run). To check whether these patterns are actually present in a draft:/storyforge:author-check.
Write on chapters/22-the-night-before/draft.md- **Author:** Ethan Coleethan-coleauthor_discoveries DB (v3.0.0: SQLite, no longer directly from Markdown):
vocabulary β all ### Forbidden ... entriesrecurring_tics β bold-title bullets with quoted phrasesdonts β backtick regex and italicized phrases (under a ban cue) from each bulletFor the hook to find the right author, the book CLAUDE.md must have a ## Book Facts section:
## Book Facts
- **Author:** Ethan Cole (Eddings-humor with Twilight-stakes)
- **POV:** Theo Wilkons (third-person limited)
- **Tense:** Past
The hook regexes on - **Author:** <name> and slugifies the name. Examples:
| Display name | Slug |
|---|---|
| Ethan Cole | ethan-cole |
| Maja Sundberg | maja-sundberg |
| Henri Delacroix | henri-delacroix |
| Ursula K. Le Guin | ursula-k-le-guin |
The bracketed annotation after the name is ignored.
Single words (no spaces, no hyphens) automatically match inflections:
| Pattern | Matched in prose |
|---|---|
delve |
delve, delved, delving, delves |
embark |
embark, embarked, embarking, embarks, embarkment |
vibrant |
vibrant, vibrants, vibrantly |
Logic: Single words with silent e (delve, embrace) use the stem without e (delv, embrac) plus \w*. Other single words use pattern + \w*. Leading word boundary in both cases β redelve does not match the delve pattern.
Multi-word phrases match exactly:
| Pattern | Match? |
|---|---|
it's worth noting that |
only the full phrase |
her heart raced |
only the full phrase |
Theo writes in the draft She delved into the box.:
StoryForge linter blocked this write:
[BLOCK] draft.md line 8: Banned by author voice
(author-vocab (Absolutely Forbidden)): 'delve'
Fix the blocking issues and try again. Set `linter_mode: warn` in the
book's CLAUDE.md frontmatter to override.
The model receives this message in stderr and must replace delve before the next write is accepted.
When a vocabulary pattern is too aggressive for a specific book:
### Absolutely Forbidden and move it to a separate notes section (e.g. ## Soft Watch) β hook ignores itlinter_mode: warn in book CLAUDE.md frontmatter β all block-severity findings downgraded to soft warnings (not selectively per pattern, but globally)More details: Quality System β Pre-Save Hook.
The skill /storyforge:study-author imports own works (PDF, EPUB, DOCX) and extracts style parameters automatically.
Sentence-length distribution
Vocabulary register
Signature phrases
POV patterns
Dialog proportion
Paragraph structure
# Studied Work: The Island at Night (2023)
## Style Parameters Extracted
### Sentence Length
- Mean: 16.3 words
- Median: 14 words
- StdDev: 9.8 words (high β human-typical)
- Range: 2-47 words
### Vocabulary
- 8,423 unique content words over 82,000 total
- Top 5 content words: "sea" (184), "light" (142), "mother" (127),
"always" (118), "again" (112)
- Dialect markers: "moin" (23x), "Schiet" (8x), "bΓΌschen" (11x)
### Filter Word Usage (per 10,000 words)
- saw: 12 (low)
- heard: 8 (low)
- felt: 15 (low)
- β Very restrained filter-word usage
### Dialog Proportion
- 23% dialog, 77% narration
- Dialog tags: 78% "said", 15% no tag, 4% "asked", 3% other
### Signature Phrases (>3x)
- "and then it was quiet" (6x)
- "that was that" (14x β strong signature)
- "not today" (4x)
- "the sea was [X]" (11x)
## Update to profile.md
- Adding signature_phrases
- Setting sentence_style: "varied-high-variance"
- Setting vocabulary_level: "moderate"
- Adding regional markers to preferred words
- Adding "felt"/"saw"/"heard" soft-cap (max 10 per chapter)
The skill writes these findings automatically to profile.md and vocabulary.md β and as of v3.0.0 directly to the author_discoveries DB.
Since v2.1.0, study-author extracts not only statistical parameters but also positive style patterns directly from the analyzed work β what to actively adopt, not just what to avoid.
How Phase 1.5 works:
primary_genres, the skill loads the ## study-author: Positive Markers section from the genre README.tone: sarcastic β look for sarcasm deployment patterns; tone: dark-humor β look for gallows-humor techniques).write_author_discovery(section="style_principles") into profile.md β and as of v3.0.0 in parallel to the author_discoveries DB.The result appears under ## Writing Discoveries / ### Style Principles in profile.md. Both chapter-writer and chapter-reviewer load this section on every run via get_author() β positive patterns automatically reach every subsequent chapter draft.
Authors before v2.1.0: Anyone who analyzed works before Phase 1.5 existed has rich analysis archives but empty
style_principles. Fix:/storyforge:backfill-style-principles <author-slug>reads allstudied-works/analysis-*.mdfiles and promotes positive patterns retroactively. Idempotent β running it again writes no duplicates.
A user can have any number of profiles:
~/.storyforge/authors/
βββ maja-sundberg/ # For literary/contemporary
βββ maja-sundberg-thriller/ # For thriller (different cadence)
βββ ghostwriter-1/ # For client work
βββ test-voice/ # Experimental profile
One author per book (author_slug in book frontmatter, plus **Author:** line in book CLAUDE.md for hook integration). Can be changed per new book.
The field author_writing_mode is a required field and controls which workflow is suggested automatically. It is set during create-author and configure:
| Value | Effect |
|---|---|
outliner |
new-book proposes the full outliner pipeline |
plantser |
plot-architect switches to MVO mode (6 beats) |
discovery |
new-book skips plot-architect, suggests rolling-planner |
The author profile can be overridden per book β e.g. an outliner author writes an experimental novella in discovery mode.
Two fields control the language logic for language-aware skills like chapter-proofreader:
| Field | Level | Purpose |
|---|---|---|
native_language |
Author | Mother tongue β determines the explanation language in the proofreader |
preferred_writing_language |
Author | Default writing language β fallback when no book_language is set per book |
book_language |
Book | Authoritative per book β overrides preferred_writing_language |
Resolution order for writing language:
book_language (book frontmatter)
β preferred_writing_language (author profile fallback)
β "en" (global fallback)
Example: Ethan Cole normally writes in English (preferred_writing_language: en) and has German as his mother tongue (native_language: de). The chapter-proofreader checks grammar against English rules and explains errors in German β without each book needing to set this information again.
native_languageandpreferred_writing_languageare collected during the/storyforge:create-authorworkflow Phase 1 and persisted via MCPupdate_author(). For existing profiles:update_author(slug, "native_language", "de").
Fictional author "Henri Delacroix" β Historical Mystery, France, 1920s.
---
name: "Henri Delacroix"
slug: "henri-delacroix"
created: "2026-04-24"
primary_genres: ["historical", "mystery"]
narrative_voice: "first-person"
tense: "past"
tone: ["wry", "world-weary", "ironic", "slightly-cynical"]
sentence_style: "long-flowing-with-sharp-short-punchlines"
vocabulary_level: "rich-period-appropriate"
dialog_style: "formal-with-class-markers"
pacing: "meditative-build-with-sudden-violence"
themes: ["lost-era", "class-tension", "self-deception"]
influences: ["Georges Simenon", "Graham Greene", "Patrick Modiano"]
avoid:
- "modern-slang"
- "anachronistic-references"
- "info-dumps-on-period"
- "first-person-present"
author_writing_mode: "outliner"
native_language: "fr" # ISO 639-1: mother tongue
preferred_writing_language: "fr" # ISO 639-1: writes in French
---
# Henri Delacroix
## Writing Style
First person, narrated retrospectively from a later time (usually 20 years
later). The narrator knows more than the character in the scene β but
holds it back until the right moment. Sentences can spread out like smoke
in a bistro and then end abruptly with a six-word observation.
## Narrative Approach
- **POV:** First person, strongly reflective
- **Tense:** Past, occasionally historical present in tension scenes
- **Dialog approach:** Formal, with clear class markers
(vouvoiement vs. tutoiement strictly observed)
## Signature Techniques
- **"I should have known..."-openings:** Retrospective narrator hints early
- **Object catalogs:** Scenes often begin with a list of 3-5 objects
in the room
- **Dialog-break:** Characters do not finish each other's sentences β they
suddenly throw in another topic
## Tone & Atmosphere
Wryness like an old cognac. Humor is there but dry. The world is
beautiful but unreliable. Violence comes suddenly but is not
celebrated β it is a cut, not an attraction.
## Deliberate Imperfections
- "I do not know why I..." as a phrase that occurs 2-3x per book
- Em-dashes (β) often for thought breaks
- Single-sentence paragraphs to close scenes, always 6-10 words
## Anti-Patterns
- NEVER modern psychology terms (trauma, triggered, boundaries)
- NEVER American idioms
- NEVER "it was the year 1924" (info-dump)
β Instead: weave in details from the year naturally (prices, brands,
newspapers)
## Anti-Examples
### What NOT to sound like β Generic AI
> The morning light cascaded through the window like a symphony of gold,
> bathing the room in a tapestry of warmth. He felt the weight of history,
> a journey toward truth he could not yet name.
### What NOT to sound like β Modern Anachronism
> "I need to process what just happened," he said. "This is triggering
> something. I need space." β *None of this vocabulary exists in 1924.*
Vocabulary for Henri Delacroix:
# Vocabulary β Henri Delacroix
## Banned Words β AI Tells
### Absolutely Forbidden
- trigger (as a verb)
- realm
- journey (metaphorical)
- cool (as adjective for calmness)
- processing (as mental processing)
### Forbidden Hedging Phrases
- arguably
- broadly speaking
- to put it simply
### Forbidden Emotional Tells
- "she was strong" β too modern
- felt safe (anachronistic)
- held space (anachronistic)
### Forbidden Structural Patterns
- in essence
- at its core
## Preferred Words
- coffee house (never cafΓ© when narrator looks back β period-typical)
- motor cab (never taxi)
- telephone exchange (for 1920s scenes)
## Signature Phrases (max 2x)
- "I should have known..."
- "The rain had already fallen by the time I..."
- "They used to say..."
StoryForge ships with a built-in anti-pattern catalog (reference/craft/anti-ai-patterns.md). The voice-checker compares every text against this list (soft, post-draft), the PostToolUse hook scans it as well β as warn severity (AI-tell '<word>' found).
Typical AI tells:
Promoting to hard-blocks: The global AI tells from
anti-ai-patterns.mdare surfaced by the hook as warn (not block). Two ways to promote them to hard-blocks:
- Vocabulary ban: Single words in
vocabulary.md ### Absolutely Forbiddenβ works with inflection matching (delveβdelved,delving).- Shape ban: Structural patterns (e.g. the five elegant-abstraction shapes from Section 11) in
profile.md ### Don'tsas backtick regex β works for whole phrase families via regex alternation.Both sources block the write and are visible to the
manuscript-checker. No more per-book duplication.
Specificity > Generality. "Melancholic tone" is weak. "Melancholic, Nordic-cool, focused on the sea as a third character" is strong.
Always fill ### Absolutely Forbidden. An empty vocabulary.md is as good as no profile β and the hook then has nothing to block.
Studied works are the booster. An author profile without studied works is like an actor without rehearsal. Import at least 1-2 of your own or stylistically related works.
Don't invent signature phrases β only use them when they actually occur in studied works. Artificial signature phrases become mannered.
One profile per genre. If you write horror and romance, make two profiles. Even if they map to you yourself β the writing style differs significantly.
Profiles live. After every book: update. New signature phrases? Preferred words that crept in? Add them. New banned words from beta feedback? Straight into ### Absolutely Forbidden.
Be careful with too-short banned patterns. One-word bans like like, thing, way have legitimate uses. If you put them in ### Absolutely Forbidden, the hook blocks every dialect-typical like β which gets annoying fast. Better to keep such words as soft patterns in the manuscript-checker (per-book CLAUDE.md with quote instead of backtick).
Maintain Anti-Examples. The Voice Demonstration Layer is the sharpest contrast anchor. Collect real failure patterns from your drafts β not hypothetical ones.
Symptom: Chapter-writer produces generic text with delve, tapestry etc. even though a profile exists.
Possible causes:
- **Author:** ... line β hook finds no slug~/.storyforge/authors/{slug}/vocabulary.md has no ### Absolutely Forbidden section (or other subheading name)harvest-author-rules was not run after changes to vocabulary.mdDiagnose:
# Check slug resolution
~/.storyforge/venv/bin/python3 -c "
from pathlib import Path
import sys
sys.path.insert(0, '/home/<user>/projekte/storyforge')
from tools.banlist_loader import author_slug_from_book, load_author_vocab
book = Path('/path/to/book')
slug = author_slug_from_book(book)
print(f'Slug: {slug}')
patterns = load_author_vocab(slug) if slug else []
print(f'Patterns loaded: {len(patterns)}')
for p in patterns[:5]:
print(f' β {p.label!r}')
"
Fix per cause:
## Book Facts + - **Author:** <Name> to book CLAUDE.mdvocabulary.md section headings to ### Absolutely Forbidden etc./storyforge:setupharvest-author-rules <author-slug> to sync the DBSymptom: Write fails with Banned by author voice (...), but the phrase is part of the intended voice.
Fixes:
### Absolutely Forbidden## Soft Watch section (hook ignores)linter_mode: warn in book CLAUDE.md frontmatter (emergency override for the whole book)Symptom: Voice-checker reports high AI-tell density even though profile and hook are strong.
Cause: Scene-by-scene mode was off, user chose "full chapter". More slips through with long passages (hook only blocks pattern hits, voice-checker also checks structures).
Fix: