The author profile is the core of StoryForge. The chapter-writer loads it after the chapter writing brief as mandatory context before it writes a word. There is no technical gate for this: if no author exists yet, new-book merely suggests running create-author first. Without a profile the prose falls back to the generic AI style. The profile is what keeps your text from sounding like that.
An author profile is not a marketing persona. It is a set of parameters that determines how prose is built at the sentence, paragraph and dialogue level. The quality of your book depends directly on the quality of your profile.
A profile has two parts:
~/.storyforge/authors/{slug}/: the profile profile.md with frontmatter and style description, plus reference material.~/.storyforge/db/authors.db: banned phrases, recurring tics, don'ts and style principles. The prose hook and the manuscript checker read them from there. The chapter writing brief lists under banned_phrases only book rules, flat don'ts, tics and catalog tells. Backtick and italic don'ts as well as style principles reach the chapter-writer through get_author.
vocabulary.mdis reference only. The hook does not read this file. You add banned phrases withwrite_author_banned_phraseoradd_vocabulary_entry, see Writing Discoveries.
AI models have a default style: smooth elegance, abstract poetic nouns, little sentence variation, dialogue beats instead of subtext. That default sounds the same in every genre. The voice checker calls these "AI tells".
Author profiles are the countermeasure:
The chapter-writer loads the profile after the brief. When it or you write a draft.md, the PostToolUse hook checks the text against the author banlist. Hook details are on the Technical Details page.
Author profiles live outside the plugin directory and so survive plugin updates:
~/.storyforge/authors/{slug}/
├── profile.md # frontmatter and style description
├── vocabulary.md # reference: preferred words, signature phrases
├── studied-works/ # analyses from study-author
│ └── analysis-{book-slug}.md
└── examples/ # your own sample texts (optional)
~/.storyforge/db/authors.db # writing discoveries (author_discoveries)
/storyforge:create-author asks for the values and creates the file. An example:
---
name: "Maja Sundberg"
slug: "maja-sundberg"
created: "2026-04-24"
updated: "2026-04-24"
primary_genres: ["contemporary", "mystery", "literary-fiction"]
narrative_voice: "third-limited"
tense: "past"
tone: ["melancholic", "atmospheric", "terse"]
sentence_style: "varied"
vocabulary_level: "moderate"
dialog_style: "naturalistic"
pacing: "slow-burn"
themes: ["memory", "loss", "the-sea-as-character"]
influences: ["Jon Fosse", "Siri Hustvedt", "Per Petterson"]
avoid: ["purple-prose", "info-dumps", "deus-ex-machina"]
author_writing_mode: "outliner"
native_language: "sv"
preferred_writing_language: "sv"
---
| Field | Meaning |
|---|---|
name, slug |
display name and directory name |
primary_genres |
genres the author writes in |
narrative_voice |
first-person, third-limited, third-omniscient or second-person |
tense |
past or present (memoir authors may also use mixed) |
tone |
two to four values from the create-author list: sarcastic, dark-humor, atmospheric, lyrical, terse, warm, cold, irreverent, earnest, melancholic, playful, intense, detached, intimate (memoir has its own list) |
sentence_style |
short-punchy, long-flowing, varied or minimalist |
vocabulary_level, dialog_style |
vocabulary level (simple, moderate, advanced, archaic) and dialogue style (naturalistic, stylized, minimal, heavy) |
pacing |
slow-burn, tension-driven, breakneck or literary |
themes, influences, avoid |
themes, literary influences, what this author never does |
author_writing_mode |
outliner, plantser or discovery, see Writing Modes |
native_language, preferred_writing_language |
see Language Fields |
Further fields update_author may write: pen_name, bio, website, social_media, mood, voice and the four quantitative targets dialog_ratio_target, fragment_ratio_target, single_line_paragraph_ratio_target and avg_sentence_length_target. study-author sets the latter from the analyzed text, and author-check uses them instead of its general defaults. Memoir authors additionally have subject_position, relationship_to_material and off_limits.
update_author rejects any other field, so nobody can smuggle arbitrary keys into the frontmatter.
author_writing_mode controls which path new-book and book-conceptualizer suggest and how extensively plot-architect works. The mode can be overridden per book, but the override only takes effect in some places. Everything else is under Writing Modes.
For memoir authors, create-author asks with the terms Structured, Accumulative and Discovery instead of Outliner, Plantser and Discovery Writer. When saved through update_author, these terms are normalized case-insensitively to the canonical values: Structured becomes outliner, Accumulative becomes plantser, Discovery stays discovery. The profile then holds the canonical value that every other skill also recognizes. An input that is none of these terms is stored unchanged.
After the frontmatter comes free prose. The tool create_author creates three sections with placeholder text for it: ## Writing Style, ## Signature Techniques and ## Voice Notes. You fill them by hand or through study-author. Further sections such as ## Narrative Approach, ## Tone & Atmosphere, ## Strengths, ## Deliberate Imperfections or ## Influences & Comparable Authors are a recommendation (the file templates/author-profile.md in the plugin shows them) that you add yourself when needed. The more concrete the description, the better the output:
## Signature Techniques
- **Object-as-emotion:** feelings are never named, they show in objects
(the coffee goes cold, the key cuts into the hand).
- **Weather-as-chorus:** the weather comments on the scene, never mere backdrop.
An author's writing discoveries live in the author_discoveries table of the database authors.db. There are three types:
| Type | Content | Effect |
|---|---|---|
donts |
banned phrases and patterns | the hook reports as block |
recurring_tics |
recurring tics collected from finished books | the hook reports as block or warn, depending on marking |
style_principles |
positive style patterns, preferred words | not scanned, loaded by chapter-writer and chapter-reviewer through get_author |
get_author returns them under writing_discoveries. Entries created with write_author_discovery can carry an origin (book, date), genres, universal and an example.
| Way | Effect |
|---|---|
write_author_banned_phrase(author_slug, phrase, reason) |
creates a donts entry of the form `phrase` — reason with no origin. The hook searches the phrase as a plain substring, see below. |
add_vocabulary_entry(author_slug, entry_type, text, source) |
banned becomes donts (a flat entry, with inflection and word boundary), preferred and phrase become style_principles |
write_author_discovery(author_slug, section, text, book_slug, ...) |
writes to recurring_tics, style_principles or donts; optionally with example, genres, universal; for a memoir book, without example and without the name of a person from the book |
/storyforge:chapter-voice-harvest |
adopts confirmed voice patterns from your review corrections as style_principles with a genre scope; never as donts or recurring_tics |
/storyforge:harvest-author-rules |
carries over findings from a finished book |
/storyforge:study-author |
writes style patterns from analyzed texts |
All ways are idempotent: an entry with identical text is not created twice.
add_vocabulary_entrystores the text unchanged. A full sentence yields a sentence-length pattern that practically never matches. Enter short phrases.
create_author also seeds 19 default words from the anti-pattern catalog (see Anti-Pattern Catalog) as donts immediately on creation; from that moment they take effect like any other flat phrase and count as author_vocab_violation in the manuscript checker. vocabulary.md no longer lists these words, only a reference to the database. If the database write fails, the author is still created; the response from create_author then carries a warning field instructing you to add the words via add_vocabulary_entry.
Banned phrases (donts) can take four forms. How exactly the hook searches depends on the form, and thus on the way the entry was created:
| Form (way) | Effect in the hook |
|---|---|
flat phrase without backticks and bold, for example delve / delve into (add_vocabulary_entry with banned, migration from vocabulary.md) |
split into aliases at /, parenthetical notes such as (metaphorical) are removed. Single words match inflections and start at a word boundary. |
backtick entry, for example `delve` — reason (write_author_banned_phrase) or `\bthe (room|silence) received\b` |
if the text contains regex characters it is treated as a regular expression, otherwise as a plain substring with no inflection and no word boundary, case-insensitive |
italic example phrase, for example *The room received it.*, in an entry with a ban cue (Never, Avoid, nie, kein and similar) |
searched as text, but only within the window before a recommendation marker (Render, Replace, Instead:, → and similar), trailing punctuation is stripped. This window applies in the hook just as it does in the manuscript checker. |
bold-titled line with no backtick and no italic example phrase after a ban cue, for example **word** (note) |
if the bold sits at the very start of the line, the bold-title fallback turns the text between the asterisks into a literal, a single word with inflection and a word boundary just like a flat phrase, a multi-word phrase matched exactly with word boundaries; if the title contains phrases in quotation marks, only those are searched; anything after the bold markup, such as the parenthetical note in the example, is not part of the title and is left out |
The bold-title fallback only kicks in when the line starts directly with the bold markup. If other text precedes it, for example Avoid **word** entirely, the fallback does not recognize it and the entry stays without effect. This also covers bullets that were migrated from a vocabulary.md and kept their bold: if the bold sits at the start, such a migrated entry now acts like a flat phrase; if it does not, it stays without effect. Check such entries with get_author and recreate them as a flat phrase or backtick entry if needed.
The difference between the first two rows matters:
delve finds delved, delving and delves (for words ending in a silent e the stem without the e is used) and does not hit in the middle of a word, so redelve does not count. Multi-word phrases and hyphenated words are matched exactly.write_author_banned_phrase writes it, is a plain substring: `delve` hits delve and redelve, but not delving. `thing` also hits something. If you want word boundaries or inflections, write a regex, for example `\bthing\b` or `\bdelv(e|ed|es|ing)\b`.All donts hits have severity block.
Recurring tics (recurring_tics) are bullets with a bold title that carries the scannable phrase in quotation marks:
- **Vague noun "thing" as fallback** — make "doing a thing with his hand" concrete on sight.
- **"count" as time-marker tic** — *for a count of X* — max 2-3 per chapter.
The hook takes the quoted phrases from the title, otherwise patterns from the bullet text. Default is block. If [warn] or [advisory] appears in the bullet, the finding is only reported. An addition such as Max 2 per chapter, Max 2–3 pro Kapitel or Max einmal pro Kapitel allows up to that many hits per chapter. The limit is scaled by the length of the current draft relative to the chapter's target word count, so a half-finished draft is allowed correspondingly fewer hits. The manuscript checker applies the same distinction: a [warn]-tagged tic gets weight medium there instead of high, and a chapter that does not exceed the allowed number of hits produces no finding. Unlike the hook, which scales the limit by the draft's length against the target word count, the checker evaluates the limit per whole chapter.
Style principles are not machine-checked. They are narrative instructions: for each scene chapter-writer picks three fitting principles, quotes their example and applies them. Entries with genres apply only in books that have at least one of those genres. Entries without genres apply everywhere, with universal always. Memoir books additionally recognize the genre tag memoir: entries carrying that tag take effect in the author's memoir books and not in their fiction books. Whether the principles really show up in the draft is checked by /storyforge:author-check.
| Source | Prose hook | Manuscript checker (category) |
|---|---|---|
donts, plain phrases |
block | author_vocab_violation |
donts, bold at the start of the line with no backtick/italic (bold-title fallback) |
block | author_vocab_violation |
donts, backtick and italic |
block | author_rule_violation |
donts, quoted phrase with a ban cue |
no | author_rule_violation (only before a recommendation marker) |
recurring_tics |
block or warn, with a per-chapter limit | writing_discovery_violation, weight high or medium with [warn], with a per-chapter limit |
style_principles |
no | no |
Global shape bans (anti-ai-patterns.md, section 11, six regex patterns) |
warn, for every author | global_shape_violation |
Global AI-tell words (anti-ai-patterns.md, section 1) |
warn, for every author (category ai_tell) |
ai_tell_violation |
Global patterns only warn (hook) or count as advisory (checker). If you want to block one hard, add it as a backtick regex to the author's donts.
From section 11, only the lines that begin exactly with **Banned shape:** are enforced by machine. There are six: count-and-editorialize fragments (11.1), sentence as projectile (11.2), room as receiver (11.3), economic metaphors (11.4), body-part agency (11.6) and backward-negation loops (11.7). The variants Banned shape (trust-split) and Banned shape (density), as well as 11.5, 11.8 and 11.11 to 11.13, have no loaded regex. The chapter-humanizer covers them in part with its own density rules and judgment review, see Quality System.
For enforcement only the database counts, not vocabulary.md. If you have banned words in such a file, scripts/migrate_vocabulary_to_db.py copies the Banned Words sections into the database (preview without a flag, --execute writes, repeatable). See Technical Details.
The hook first finds which author belongs to a book through the line - **Author:** Name in the book CLAUDE.md. The name is turned into a slug, and a parenthetical note after it is ignored:
| Display name | Slug |
|---|---|
| Ethan Cole | ethan-cole |
| Ursula K. Le Guin | ursula-k-le-guin |
If this line or the file is missing, the loader falls back to the author: field in the book README.md frontmatter. That field already holds the slug itself, with no conversion. create_book_structure writes this field for every newly created book, even when no author was passed; in that case it stays empty and counts as a missing value.
No tool writes the CLAUDE.md line: the book CLAUDE.md template carries only POV, Tense, Genre and Writing Mode under Book Facts, and init_book_claudemd passes no author. You can still add it by hand, for example in the Book Facts section; the loader searches the whole file for it, not only there, and it takes precedence over the README field. If both sources are missing, there is no author banlist. If authors.db is missing or the query fails, the author also counts as having no entries; on a query failure the hook writes a note to stderr.
The hook runs as PostToolUse, that is, after the file has been written. A block finding leads to exit code 2 in strict mode: the message goes back to Claude, and Claude has to fix the finding before continuing. In warn mode (linter_mode: warn in the frontmatter of the book CLAUDE.md) blockers are only printed, for the whole book, not for individual patterns. More: Technical Details and Configuration.
If a pattern is too sharp for a single book, remove the entry from the author's writing discoveries rather than loosening the book's mode.
/storyforge:study-author <file> [author-slug] analyzes your own or other texts (PDF, EPUB, DOCX, TXT, MD) and carries style patterns into the profile. The skill rejects files over 50 MB. Texts over 200,000 words are not rejected: it then analyzes a sample from the beginning, middle and end. The skill refines an existing profile. If there is none yet, it first points to create-author, because a profile built from one foreign work would copy that author's signature too closely.
The flow in fiction mode:
analysis-{book-slug}.md already exists, the skill warns about duplicate discoveries.## study-author: Positive Markers section of the author's genres and their tone values the skill assembles a checklist. The analysis starts only after you confirm it.studied-works/analysis-{book-slug}.md.update_author, found style patterns as style_principles, recurring habits as recurring_tics, patterns to avoid via write_author_banned_phrase. Deliberate idiosyncrasies from the "Deliberate Imperfections" section are stored as style_principles, explicitly not as recurring_tics, because tics get enforced. If a new finding contradicts an existing one, the skill asks.In memoir mode the skill analyzes your own texts (journals, letters, old blog posts) to bring out the unguarded voice, and skips the profile gate.
For authors studied before the checklist existed, /storyforge:backfill-style-principles <author-slug> recovers positive patterns from the existing analysis files. The skill is idempotent. With /storyforge:migrate-source-genres you add missing genre tags.
You can have as many profiles as you like:
~/.storyforge/authors/
├── maja-sundberg/
├── maja-sundberg-thriller/ # different rhythm for thrillers
└── test-voice/ # experimental profile
One author is chosen per book: the slug in the book frontmatter's author field, which create_book_structure always writes, or the line - **Author:** that you add to the book CLAUDE.md when needed and which takes precedence over the frontmatter field. You can remove an author together with their writing discoveries with /storyforge:delete-author. The skill refuses while books still reference the author, unless you force it.
| Field | Level | Purpose |
|---|---|---|
native_language |
author | mother tongue (ISO 639-1), sets the language of explanations in chapter-proofreader |
preferred_writing_language |
author | default writing language, fallback when the book has none |
language |
book | the book's writing language, takes precedence |
Example: Ethan Cole usually writes in English (preferred_writing_language: en), his mother tongue is German (native_language: de). The proofreader checks by English rules and explains errors in German. For existing profiles you set the fields with update_author(slug, "native_language", "de").
StoryForge ships a catalog of typical AI tells at reference/craft/anti-ai-patterns.md. It serves three purposes:
chapter-humanizer and the voice-checker measure texts against it.create_author carries 19 words from section 1 straight into the new author's donts on creation (minus navigate, which would misfire on navigation/navigator); the avoid list in the frontmatter instead gets three fixed, generic defaults (purple-prose, info-dumps, deus-ex-machina) and stays independent of the catalog.The catalog only applies to books written in English (language from the language field in the book's README frontmatter); for any other language the catalog hits do not apply.
Typical tells: abstract emotion nouns ("tapestry of feelings"), journey metaphors, hedging ("it's worth noting"), repeated sentence openers, therapy speak ("held space"), symphony metaphors, strikingly eloquent teenagers, beats without function and scene endings that are too tidy.
tone and the other style fields are coarse. Precision comes from the prose sections: "melancholic, Nordic cool, the sea as a third character" beats a bare melancholic.donts, the hook only has the global catalog. Start with the phrases that bother you in your drafts.chapter-voice-harvest already learns from your corrections while you write; after each book also run harvest-author-rules so findings are enforced in the next book.like, thing or way have legitimate uses. As a backtick entry `thing` even hits in the middle of something. Better create them as a tic with [warn] and a per-chapter limit, or as a regex with a word boundary (`\bthing\b`)./storyforge:author-check shows whether the positive style patterns arrive in the draft.The chapter writer produces generic text with words like delve or tapestry although a profile exists.
Possible causes:
CLAUDE.md nor the README.md yields a slug: the - **Author:** ... line is missing (no tool writes it automatically) and the author: field in the README frontmatter is empty or missing.~/.storyforge/authors/{slug}/.vocabulary.md, not in the writing discoveries. The file is not read. Migrate it or enter the phrases with write_author_banned_phrase.~/.storyforge/db/authors.db is missing or unreadable./hooks.`delve` does not find delving). Create a regex or a flat entry.With get_author(slug) you can see which writing_discoveries are actually stored.
The message reads something like Banned by author voice, but the phrase belongs to the intended voice. Remove the entry from the writing discoveries, or set linter_mode: warn for the book as an emergency override.
More slips through in long passages. The hook only reports pattern hits, while the voice-checker also scores structures. Write scene by scene, and run the voice-checker or the chapter-humanizer after each scene if needed.