story-bible
Skill1 starsChanged 14 days agoMITView on GitHub
Use when the user wants to generate, extract, or build out a full story bible for a title. Triggers on "generate a story bible", "build out the world of [title]", "extract characters from this manuscript", "set up the worldbuilding for [series]", "what characters appear in [title]". Default to the iterative chat loop so the author can refine results mid-build (best results, cheapest per pass); fall back to the server-side extractor only for unattended runs or manuscripts so large the loop will exhaust turn budget.
In this repository29 other files it gives its agents.
- ads-studioSkill
- blog-post-and-newsletterSkill
- calendarSkill
- chapter-draftingSkill
- character-mergeSkill
- financeSkill
- getting-startedSkill
- manuscript-importSkill
- manuscript-revisionsSkill
- markersSkill
- marketing-studioSkill
- mentionsSkill
- pen-namesSkill
- quick-task-captureSkill
- sales-studioSkill
- social-handoffSkill
- stos-setupSkill
- tasksSkill
- timelineSkill
- time-trackingSkill
- wordpress-connectSkill
- wordpress-llm-optimizationSkill
- wordpress-mediaSkill
- wordpress-pagesSkill
- wordpress-postsSkill
- wordpress-productsSkill
- wordpress-seoSkill
- worldbuilding-mergeSkill
- worldbuildingSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 2 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 30
Use this only when:
- Very specific: line 60
After completion, still run the association-wiring step from §7 below (chapter/scene/series links) — the server-side extractor does the …
- Distinctive: line 101
Read whatever they provide before drafting entries.
- Very specific: line 160
If any single _create call failed mid-loop, surface the failure with the entry name so the user can retry that specific record.
- Very specific: line 165
Skipping fields to save time: If you have the information, save it.
- Very specific: line 177
If the server returns terminal_error.kind === 'oversize', that means a *single chapter* exceeds the provider context window — extremely …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Story Bible
What this is
A "story bible" in StorytellerOS is the union of four worldbuilding tables: characters, locations, events (story timeline, not calendar), and lore. Plus the junctions that wire them into titles, chapters, and scenes.
When the user asks Claude to build a bible, the work is producing structured records for each entry — every character with their core_desire, core_fear, character_arc, etc.; every location with key_features, climate; every event with act and importance; every lore entry with rules_and_mechanics and origin_and_history.
Two paths — pick by user need, not just source
The default is the iterative chat loop. The server-side extractor is the fallback for jobs the loop can't finish.
Path A — Iterative chat loop (DEFAULT)
This is the recommended path for almost every story-bible build. It runs entirely within the user's Claude Subscription, costs no API credits, and — most importantly — lets the author push back mid-build ("you missed Nora's mentor relationship", "this should be act-two, not act-three", "merge these two minor characters"). That conversational refinement is what produces a story bible the author actually wants to keep, instead of one that's "mostly right" with gaps they then have to clean up themselves.
Work economically. The loop runs on the author's own Claude plan allowance, so keep turns lean (one-line summaries, no full records pasted inline) to leave room for their refinements. Don't steer the conversation toward which AI model they use.
The loop is documented in §3-§7 below. Keep "one record at a time" — see the no-shortcuts rule.
When this path struggles: very large casts (30+ characters, 8-15 locations, 10-20 events, 5-10 lore entries) can use up the author's plan allowance before the build finishes. If the loop runs out mid-build, resume from where it stopped once their allowance resets, or, with the author's yes, use Path B for the remaining records. A real prior incident saw the bible save characters but skip lore, events and locations because the session was cut off mid-loop; that is the symptom that means "resume" or "switch to Path B for what's left."
Path B — Server-side extractor (fallback, NOT the default)
Use this only when:
- The user explicitly asks for an unattended/batch run, OR
- The manuscript is very large (full novel, 80k+ words) and Path A still can't finish within the author's plan allowance, OR
- Path A has already been tried and ran out of turn budget before completing
Warn the user before kicking it off: the server extractor runs against their saved AI API key (NOT their Claude Subscription), so it costs real money per run. And it's a one-shot batch — if it misses entries or mis-categorizes a relationship, there's no iteration; the only recourse is to re-run, which double-charges the API key. One user spent $50 in a single book this way before the issue was understood.
The extractor reads the title's imported chapters. Check that they exist with stos_chapters_list({ bookId: titleId }). If the manuscript hasn't been imported yet, import it first with the manuscript-import skill. If that import failed, or the author answered "just import", stop: never start extraction without the author's explicit yes. Otherwise kick off the server-side pipeline in one call:
stos_titles_extract_story_bible({ titleId })
→ { jobId, statusUrl, options, provider }
// Then poll every 5s until terminal:
stos_extraction_jobs_get({ jobId })
→ { status, progress: { stage, pct, detail }, result: { ... } }While polling, surface the progress detail to the user ("Surveying named characters…", "Locations: chunk 2 of 5"). Stop polling when status === 'completed' or 'failed'.
On 'failed', the result carries a terminal_error block with a ready-to-paste user_message. Show it verbatim — don't re-summarise. The classes are:
cap— AI provider monthly cap exhaustedbilling— provider account needs creditsauth— saved API key rejectedoversize— single manuscript piece exceeds the provider window (rare with chunking; suggest splitting)empty-output— provider returned nothing usable; confirm the right file was uploadedrate-limit— short-window throttle; retry after a minute
On 'completed', summarise the per-kind counts from result.created / result.merged and remind the user that drafts are in Worldbuilding for review — they should still spot-check for missed relationships or mis-categorized acts before considering the bible done.
After completion, still run the association-wiring step from §7 below (chapter/scene/series links) — the server-side extractor does the core persists, but cross-table junctions are the agent's job.
The no-shortcuts rule (Path A only)
One record at a time. Even if Claude could in principle assemble a JSON array of 30 characters and POST them in one call, don't — large sources trip context windows mid-batch and entries get truncated. Loop instead. The user explicitly asked for the fullest possible output and no shortcuts; this is enforced at the skill level, not by the tools.
Canonical field values — send these exactly
The Story Bible tables have strict CHECK constraints, and several columns (aliases, family_group, key_features, tags, themes, story_framework, setting_features, …) are arrays. The MCP tools now enforce both in their input schema: a non-canonical enum value, or a bare string where an array is expected, is rejected immediately with a clear error listing the allowed shape — a wasted round-trip, not a silent failure. Map synonyms to the canonical value below before calling the tool; pass array columns as real JSON arrays (["a","b"]), never a comma-joined string. If a value can't be mapped, omit the field entirely — never invent, never stash the original somewhere else.
| Field | Canonical values | Synonym → canonical |
characters.role_in_story | protagonist, antagonist, supporting, minor, love-interest, other | hero / heroine / lead / main / MC → protagonist • villain / big-bad / rival → antagonist • deuteragonist / mentor / sidekick / ally / foil / friend / family → supporting • love interest / romantic interest / romance → love-interest • background / extra / NPC / cameo / walk-on → minor |
characters.life_status | alive, dead, undead, missing, unknown | deceased / killed → dead • living / alive-and-well → alive • absent / lost / disappeared → missing • ghost / vampire / zombie → undead |
characters.pov_status | pov-character, non-pov | any POV / occasional-POV / multi-POV / "yes" / "true" / "POV" → pov-character • everything else (or "no" / "false") → non-pov |
events.act | act-one, act-two, act-three, act-four | 1 / I / "Act 1" / "Act I" → act-one (and 2/II → act-two, etc.) |
Never send custom_fields on any Cowork story-bible create call. The StorytellerOS UI does not render those keys for Cowork-completed records — the data lands invisible. Stick to the named columns listed in each tool's writable-fields description.
Flow
1. Scope
Find the pen name and the title:
stos_pen_names_list()
stos_titles_list({ penNameId })Confirm scope with the user before running a long loop. ("I'll build the bible for Curses and Currents under your Indie Annie pen name. That's 8 chapters, expect ~15 characters, ~8 locations. OK to proceed?")
2. Sources of truth
The user may give Claude one of:
- An imported manuscript. Its chapters and scenes are in StorytellerOS: list them with
stos_chapters_list({ bookId: titleId })andstos_scenes_list({ chapterId }), then read each scene's full text withstos_scenes_get_content({ id }). Work chapter by chapter so the whole book never sits in the conversation at once. If the author has a file that isn't imported yet, use themanuscript-importskill first. It asks whether they want the story bible built at all; continue here only if they said yes and the import succeeded. - An outline / synopsis pasted in chat.
- The current chapters / scenes already in STOS (
stos_chapters_list,stos_scenes_list). - Whole-cloth generation from a premise.
Read whatever they provide before drafting entries.
3. Loop: characters
For each character mentioned in the source:
- Assemble the full record (name, role, age, occupation, pronouns, gender, life_status, background, physical_description, personality, pov_status, dialogue_style, core_desire, core_fear, goals_and_motivations, strengths, flaws, internal_conflict, external_conflict, character_arc, backstory, key_relationships, lexicon_and_quirks, emotional_tells, speech_patterns, internal_voice, sample_scene). Apply the canonical-value mapping above before you reach for the tool.
- Print a one-line summary per entry (
Sasha: protagonist, witch, POV) so the user can follow along. Do not paste the full record block inline: the full record only goes into the tool call. Inline drafting eats the user's token budget without adding value. stos_characters_create({ fields: { ... } })— one call per character.- Record the returned id so you can link later.
4. Loop: locations
Same pattern — one stos_locations_create per location with all fields (description, location_type, key_features, climate, coordinates, map_image_url, development_notes).
5. Loop: story-timeline events
stos_events_create per event — event_name, event_date (in-universe), event_type, description, act, importance, event_order.
6. Loop: lore
stos_lore_create per lore entry — lore_name, lore_type, description, rules_and_mechanics, examples_and_usage, origin_and_history, contradictions_check, tags.
7. Wire associations
For each (entity, target) pair the source implies (e.g. "Sasha appears in chapter 3", "the Crow Court rules govern scene 7"), call stos_worldbuilding_link — once per association.
Supported pairs include title↔{character,location,event,lore}, chapter↔{character,event}, scene↔{character,location,event}, series↔{location,lore}, event↔{character,location}, lore↔{character,location}.
7a. Scope lore and locations to the series
Characters carry a series_id directly, so they show up under the series filter as soon as they're created. Lore and locations don't — they live in lore and locations tables with no series column, and only surface under the series filter when an entry exists in the series_lore / series_locations junction. Without this step, every lore/location entry orphans visually.
For each lore entry just created:
stos_worldbuilding_link({
entityType: 'series', entityId: <seriesId>,
targetType: 'lore', targetId: <loreId>
})For each location:
stos_worldbuilding_link({
entityType: 'series', entityId: <seriesId>,
targetType: 'location', targetId: <locationId>
})One call per entry. These run alongside the chapter/scene-level links from Step 7 — they're additive, not a replacement.
8. Report
End with counts:
"Saved 14 characters, 7 locations, 12 events, 5 lore entries, and 38 associations to Curses and Currents."
If any single _create call failed mid-loop, surface the failure with the entry name so the user can retry that specific record.
Anti-patterns
- Batching multiple entries into one tool call. Hard no. The whole point of this skill is the per-entity loop.
- Skipping fields to save time. If you have the information, save it. Truncating a character's
backstoryto a one-liner defeats the bible. - Forgetting associations. A character that isn't linked to any chapter or scene is dead weight — wire every connection the source implies.
- Forgetting the series-level links from Step 7a. A lore entry or location without a
series_lore/series_locationsrow will not appear under the series filter and the user will conclude the bible isn't connected. - Sending non-canonical enum values, or a string for an array column. Map enum synonyms first (see the Canonical field values table); if you can't map, omit the field. Pass array columns as JSON arrays. The tool input schema rejects "Deuteragonist", "Act 1", or a comma-joined string with an explicit error — burning a retry round-trip.
- Sending
custom_fields. Invisible in the StorytellerOS UI for Cowork-completed records. Use only named columns. - Pasting full record blocks inline before calling the tool. The tool call carries the record — printed paragraphs just consume the user's Claude allowance.
- Drafting under the wrong pen name. Same continuity hazard as
chapter-drafting.
Very large manuscripts
The server-side path (Path B) already chunks the manuscript into provider-fitting pieces and dedupes drafts across chunks, so a 200k-word novel runs in one stos_titles_extract_story_bible call. You don't need to pre-split anything. The progress detail surfaced through stos_extraction_jobs_get will show the chunk count as it works through the book.
If the server returns terminal_error.kind === 'oversize', that means a single chapter exceeds the provider context window — extremely rare. Tell the user, suggest splitting the offending chapter, and don't retry blindly.
Path A's per-entity loop has no chunking of its own. If a user pastes a 200k-word manuscript directly into chat, stop and import it to the title first with the manuscript-import skill. If the author said yes to the story bible and the import succeeded, either run Path A chapter by chapter from the imported scenes, or use Path B if the book is too large for the loop. Pasting a novel into chat just to feed the loop wastes their token budget and risks the same mid-loop cutoff.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

