StoryForge Author Profiles - Anti-AI Engine
Author profiles in StoryForge: structure of profile.md, writing discoveries in the database, how banned phrases and tics are enforced by the prose hook, study-author, language fields and troubleshooting.
StoryForge Author Profiles
Overview
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:
- Files under
~/.storyforge/authors/{slug}/: the profileprofile.mdwith frontmatter and style description, plus reference material. - Writing discoveries in the database
~/.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 underbanned_phrasesonly book rules, flat don'ts, tics and catalog tells. Backtick and italic don'ts as well as style principles reach thechapter-writerthroughget_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.
Why Author Profiles?
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:
- Style parameters override the defaults.
- Banned phrases and patterns are reported by the hook right after every write, with a demand to fix them, not only in a check at the end.
- Style principles describe positively what makes the voice.
- Studied works provide concrete examples from analyzed texts.
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.
Storage
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)
Profile.md: Structure
Frontmatter
/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.
Writing mode
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.
Prose sections
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.
Writing Discoveries
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.
Adding entries
| 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.
Entry format
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:
- A flat entry
delvefindsdelved,delvinganddelves(for words ending in a silentethe stem without theeis used) and does not hit in the middle of a word, soredelvedoes not count. Multi-word phrases and hyphenated words are matched exactly. - A backtick entry, the way
write_author_banned_phrasewrites it, is a plain substring:`delve`hitsdelveandredelve, but notdelving.`thing`also hitssomething. 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.
Who scans what?
| 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.
Adopting an existing vocabulary.md
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.
Hook and Author
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.
Study Author: Style Extraction
/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:
- Input: file, author, source genres. If an
analysis-{book-slug}.mdalready exists, the skill warns about duplicate discoveries. - Checklist of positive markers: from the
## study-author: Positive Markerssection of the author's genres and theirtonevalues the skill assembles a checklist. The analysis starts only after you confirm it. - Analysis: sentence length and variance, vocabulary, dialogue share and tags, paragraph structure, style markers such as metaphor frequency, filter words and adverbs.
- Analysis file under
studied-works/analysis-{book-slug}.md. - Update the profile: frontmatter fields and quantitative targets via
update_author, found style patterns asstyle_principles, recurring habits asrecurring_tics, patterns to avoid viawrite_author_banned_phrase. Deliberate idiosyncrasies from the "Deliberate Imperfections" section are stored asstyle_principles, explicitly not asrecurring_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.
Multiple Author Profiles
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.
Language Fields
| 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").
Anti-Pattern Catalog
StoryForge ships a catalog of typical AI tells at reference/craft/anti-ai-patterns.md. It serves three purposes:
- The prose hook reads the word list "Heavily Flagged Words and Phrases" and the banned shapes from section 11 ("Elegant Abstraction Register", six of them with a regex) from it, both at severity warn.
- The
chapter-humanizerand thevoice-checkermeasure texts against it. create_authorcarries 19 words from section 1 straight into the new author'sdontson creation (minusnavigate, which would misfire onnavigation/navigator); theavoidlist 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.
Tips for Strong Profiles
- Specific over generic. The lists for
toneand the other style fields are coarse. Precision comes from the prose sections: "melancholic, Nordic cool, the sea as a third character" beats a baremelancholic. - Maintain the bans. Without entries in
donts, the hook only has the global catalog. Start with the phrases that bother you in your drafts. - Use studied works. A profile without analyzed works is an actor without rehearsals. Analyze one or two of your own or related works.
- Do not invent signature phrases. Add them only when they really occur in analyzed texts, otherwise they feel mannered.
- One profile per genre. If you write horror and romance, create two profiles.
- Profiles live.
chapter-voice-harvestalready learns from your corrections while you write; after each book also runharvest-author-rulesso findings are enforced in the next book. - Be careful with short bans. One-word bans like
like,thingorwayhave legitimate uses. As a backtick entry`thing`even hits in the middle ofsomething. Better create them as a tic with[warn]and a per-chapter limit, or as a regex with a word boundary (`\bthing\b`). - Check the effect.
/storyforge:author-checkshows whether the positive style patterns arrive in the draft.
Troubleshooting
The profile has no effect while writing
The chapter writer produces generic text with words like delve or tapestry although a profile exists.
Possible causes:
- Neither the book
CLAUDE.mdnor the README.md yields a slug: the- **Author:** ...line is missing (no tool writes it automatically) and theauthor:field in the README frontmatter is empty or missing. - The slug derived from the name does not match the directory
~/.storyforge/authors/{slug}/. - The words are only in
vocabulary.md, not in the writing discoveries. The file is not read. Migrate it or enter the phrases withwrite_author_banned_phrase. - The database
~/.storyforge/db/authors.dbis missing or unreadable. - The hook is not running (setup not done, plugin not active). Check with
/hooks. - A backtick entry does not hit the inflection (
`delve`does not finddelving). Create a regex or a flat entry. - A migrated entry with bold has neither a backtick nor an italic example phrase, and the bold does not sit at the start of the line β the bold-title fallback then does not recognize it.
With get_author(slug) you can see which writing_discoveries are actually stored.
The hook reports unexpectedly
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.
The voice check reports many AI tells despite the profile
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.