fabricatio-character
Character profile generation for the Fabricatio LLM agent framework — structured persona cards with AI-driven composition and template-based rendering.
Installation
pip install fabricatio[character]
# or
uv pip install fabricatio[character]
For the full Fabricatio suite:
pip install fabricatio[full]
Overview
fabricatio-character provides a CharacterCard model capturing a character as they currently are: stable identity (name, roles list, activated role, motivation) plus the mutable state of the moment (appearance, behavior, vulnerability, location, physical condition, mood) — ten required fields that together define a complete narrative persona and its present situation, plus a required, possibly empty metric map of tracked numerical stats (hp, energy, reputation, ...). The CharacterCompose capability plugs into Fabricatio's Propose pipeline to generate cards via LLM from natural-language requirements, with built-in Pydantic validation.
Generated cards are renderable through the Fabricatio template system (as_prompt()) and persistable (PersistentAble) for checkpoint/restore workflows.
Models
CharacterCard
A character as they currently are. The identity fields (name, roles, activated_role, want) change slowly; the state fields describe how the character is right now and evolve as the story progresses. The ten text fields are required and non-empty; metric is required but may be empty when no stats are tracked. roles must contain at least one entry and activated_role must be one of the entries in roles.
| Field | Type | Description |
|---|---|---|
name |
str |
Identifying name, alias, or title |
roles |
list[str] |
All narrative or functional roles the character holds within the story (e.g. ["protagonist", "mentor"]); non-empty |
activated_role |
str |
The role the character is currently playing; must be one of the entries in roles |
look |
str |
Current appearance — clothing, physique, distinguishing features, wounds, disguise |
act |
str |
Current behaviors, mannerisms, stress reactions |
want |
str |
Core motivation driving the character's actions (slow-changing) |
flaw |
str |
Current weakness, moral failing, or psychological vulnerability |
where |
str |
Current location and immediate situation |
condition |
str |
Current physical state — health, energy, injuries, resources |
mood |
str |
Current emotional state |
metric |
dict[str, int | float] |
Tracked numerical stats — any measurable quantity, including physical stats like body weight (e.g. {"hp": 80, "reputation": 30, "weight_kg": 62}); required, may be empty when no stats are tracked. Diffs merge entries instead of replacing the map |
CharacterCard inherits: |
SketchedAble— instantiation from natural-language descriptions via LLMNamed— equality bynamefieldAsPrompt— renders as a prompt string via the configured template (render_character_card_template)PersistentAble— save/load to disk for workflow checkpointing
Capabilities
CharacterCompose
Mixin that extends Propose to generate CharacterCard instances from requirement strings.
from fabricatio_character.capabilities.character import CharacterCompose
class StoryAgent(CharacterCompose, ...):
pass
compose_characters(requirements, **kwargs)
- Accepts a single
stror alist[str]of requirements - Returns a single
CharacterCard(orNone) for a string, or alist[CharacterCard | None]for multiple requirements - Passes
**kwargsthrough to Fabricatio's validation layer (ValidateKwargs), enabling strict validation, retry policies, and custom post-processing - Delegates to
Propose.propose()for LLM-driven composition
Utilities
dump_card(*card: CharacterCard) -> str
Joins one or more CharacterCard objects as prompt strings, separated by newlines. Convenience wrapper around CharacterCard.as_prompt().
from fabricatio_character.utils import dump_card
prompt = dump_card(hero, villain)
Configuration
All options below are read through the fabricatio configuration chain (see the
Configuration Guide). Set them under the
[ext.character] table in fabricatio.toml, equivalently under
[tool.fabricatio.ext.character] in pyproject.toml, or via
FABRICATIO_EXT__CHARACTER__<FIELD_UPPER> environment variables.
[ext.character]
mind_personality_high = 70.0
| Option | Type | Default | Description |
|---|---|---|---|
render_character_card_template |
str |
"built-in/render_character_card" |
Template to use for rendering character cards. |
mind_system_prompt_template |
str |
"built-in/mind_system_prompt" |
Handlebars template for as_prompt() system prompt rendering. |
mind_threat_analysis_template |
str |
"built-in/mind_threat_analysis" |
Template for 'which need is threatened' LLM call. |
mind_fulfill_analysis_template |
str |
"built-in/mind_fulfill_analysis" |
Template for 'which need is fulfilled' LLM call. |
mind_bias_judgment_template |
str |
"built-in/mind_bias_judgment" |
Template for cognitive distortion judgment LLM call. |
mind_impact_analysis_template |
str |
"built-in/mind_impact_analysis" |
Template for emotion/intensity/personality_shift LLM call. |
mind_personality_high |
float |
70.0 |
BigFive score above this = 'high' trait. |
mind_personality_low |
float |
30.0 |
BigFive score below this = 'low' trait. |
mind_emotion_intensity_high |
float |
70.0 |
Emotion intensity above this triggers high-arousal behavior. |
mind_emotion_intensity_mid |
float |
40.0 |
Emotion intensity above this triggers mild emotional coloring. |
mind_satisfaction_threshold |
int |
3 |
Accumulated positive events needed to rise one Maslow level. |
mind_age_brackets |
Tuple[Tuple[int, float], ...] |
(see config.py) |
Age brackets and their personality shift multipliers. |
mind_need_focus |
Dict[MaslowLevel, str] |
(see config.py) |
Maslow level -> behavioral description for prompt injection. |
mind_bias_examples |
Dict[Distortion, str] |
(see config.py) |
Cognitive distortion -> example internal monologue. |
mind_personality_rules |
Dict[PersonalityFlag, str] |
(see config.py) |
Personality flag key -> behavioral description for prompt injection. |
mind_emotion_somatic_map |
Dict[Emotion, Tuple[SomaticState, SomaticState]] |
(see config.py) |
Emotion keyword -> (high_intensity_body, low_intensity_body) mapping. |
mind_diamonds_template |
str |
"built-in/mind_diamonds_analysis" |
Template for DIAMONDS 8-dim situation extraction. |
mind_diamonds_distortion_boost |
Dict[SituationDimension, Dict[Distortion, float]] |
(see config.py) |
DIAMONDS dimension -> {distortion: score_boost} mapping for rule_filter. |
mind_cbt_confidence_threshold |
float |
70.0 |
If rule_filter top distortion score > this, use rule result directly; else full LLM. |
mind_suffering_intensity_threshold |
float |
80.0 |
Emotion intensity above this triggers suffering creation. |
mind_suffering_template |
str |
"built-in/mind_suffering_analysis" |
Template for LLM-generated suffering narrative. |
mind_style_extraction_template |
str |
"built-in/mind_style_extraction" |
Template for extracting linguistic style from dialogues. |
Access at runtime: from fabricatio_character.config import character_config.
Dependencies
fabricatio-core—Propose,SketchedAble,Named,CONFIGfabricatio-capabilities—AsPrompt,PersistentAble,ValidateKwargs
Usage
Generating a Single Character
from fabricatio_character.capabilities.character import CharacterCompose
class Agent(CharacterCompose, ...):
pass
agent = Agent()
card = await agent.compose_characters(
"a grizzled detective haunted by an old case"
)
if card:
print(card.as_prompt())
Batch Generation with Validation
cards = await agent.compose_characters(
[
"a brilliant but arrogant surgeon",
"a quiet archivist who notices everything",
"a cheerful smuggler with a heart of gold",
]
)
for c in cards:
print(c.name, "-", c.activated_role)
Rendering and Persistence
from fabricatio_character.utils import dump_card
# Render all cards as prompts
prompt_text = dump_card(*cards)
# Persist individual cards (via PersistentAble)
card.persist("checkpoints/characters/")
Mental Engine
MentalState models how a character changes: a stable identity layer (Big Five
personality, CBT distortion tendencies, linguistic style, age), a volatile
per-event emotional layer (emotion, somatic response, active distortion,
DIAMONDS situation), an accumulated Maslow need layer, and irreversible
traumas.
The state object is self-sufficient and mirrors the CharacterCard conventions:
| Surface | Owner | Role |
|---|---|---|
apply(impact) |
MentalState |
Deterministic rules: need threat drop / satisfaction rise, age-scaled personality drift, suffering accumulation, emotion + somatic replacement. Copy-on-write — returns a new instance |
as_prompt() |
MentalState |
Renders the psychology block via mind_system_prompt_template (AsPrompt protocol) |
persist() / from_persistent() |
MentalState |
Checkpoint / restore (PersistentAble) |
from_card(card, age=25) |
MentalState |
No-LLM seed; bridges the card's mood text to an Emotion when it names one |
seed_from(card, age=25) |
UseMind |
LLM-judged seed: need level from card.want, distortion tendencies from card.flaw |
observe(event, state) |
UseMind |
Pure analysis → EventImpact: threatened/fulfilled need, emotion + intensity, DIAMONDS situation, distortion (rule filter + confidence-gated LLM judgment), suffering on high intensity |
react(event, state) |
UseMind |
One-call observe + apply |
extract_style(name, dialogues) |
UseMind |
Linguistic style extraction from dialogue history |
Usage
from fabricatio_character.capabilities.character import CharacterCompose
from fabricatio_character.capabilities.mental import UseMind
from fabricatio_character.utils import dump_card
class StoryTeller(CharacterCompose, UseMind, ...):
"""Writes in-character; keeps psychology evolving per event."""
agent = StoryTeller("storyteller")
card = await agent.compose_characters("Hamlet, prince of Denmark")
mind = await agent.seed_from(card, age=30)
mind = await agent.react("The ghost of your father accuses your uncle.", mind)
prompt = dump_card(card) + "\n\n" + mind.as_prompt()
reply = await agent.aask("What do you say to your mother?", system_prompt=prompt)
mind.persist("checkpoints/minds/")
age lives on the state (CharacterMind.age) and scales personality drift:
child 3.0×, adolescent 1.5×, young adult 0.5×, adult 0.2×
(mind_age_brackets).
Research Foundations
| Paper | Year | Contribution |
|---|---|---|
| Costa & McCrae (Big Five) | 1992 | Personality model |
| Maslow | 1943 | Need hierarchy |
| Beck / Burns (CBT) | 1976/1980 | Cognitive distortions |
| Rauthmann et al. (DIAMONDS) | 2014 | Situation classification |
| Zhan et al. (TTM) | 2025 | Linguistic style decoupling |
| Du et al. (EFT-CoT) | 2026 | Embodied perception |
| Emotional Cost Functions | 2026 | Irreversible trauma |
License
MIT — see LICENSE
Metadata
Release files for fabricatio-character 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fabricatio_character-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / fabricatio_character-0.5.0-py3-none-any.whl
| Download URL | fabricatio_character-0.5.0-py3-none-any.whl |
|---|---|
| Size | 37.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e417dccf493dce03b6b6d88ea65bf02f1290dedec1fa3fe6796470ba6e5c5da2
|
|
BLAKE2b-256 checksum How to use checksums |
f5d44338dcefd1a471362a94840e4a7a8c223d5c832e078d6b4484731a353ac9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|