You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The symbols listed in this document are hersona's public API and are
subject to semver. Breaking changes only happen in a major version.
Modules/functions prefixed with _, and any symbol not listed here, are
internal implementation details and may change without notice.
External projects (e.g. hersona-duet) must import only the public exports of
hersona.core. Consistency is enforced mechanically by
tests/test_public_api.py.
Resolve an attribute name to its YAML dict. Accepts both bare (tsundere) and category-qualified (personality/tsundere) names (a qualified name must also match the category). Raises KeyError if not found
Compose multiple attributes into a system-prompt injection block. Conflicts are appended as a warning. When use_case is given, an English Operating Mode block is appended at the end
re-anchor — recovering from mid-conversation persona drift
persona_lock hardens a persona against deliberate override, but does nothing
about drift — a persona quietly losing its register over a long session.
ContextEcho (arXiv 2605.24279), across 23 models, reports that in-session
compaction does not reliably reset drift and that a single-shot anchor
restores the trained register. This API builds that anchor.
Returns the re-anchor block. Carries only the mechanical register (identity line / first & second person / sentence endings / lexical markers / head subset of catchphrases + one resume directive). core_traits, tone, speech_style and the response-style directive are deliberately omitted — the anchor restores a register the model already knows rather than re-teaching the persona. 17-30% the size of the full injection block
DEFAULT_CATCHPHRASES
Default number of catchphrases in the anchor (3). Pass catchphrases=0 to omit the section
The existing deterministic scorer decides when to fire it: send the anchor when
verify_intensity / measure_intensity falls below the expected band (over MCP:
measure_intensity -> reanchor). Neither call touches an LLM.
Placement: append it as the newest turn (or at the tail of the system
prompt). Splicing it into the stable prefix invalidates the prompt cache for the
whole conversation — the same tail-append rule the injection block's
cache-optimal layout follows.
disclosure — AI-disclosure directive (opt-in)
persona_lock makes the persona refuse tone/persona swaps and prefer SOUL over
in-chat instructions. That is right for maintenance, but it can also push the
model toward not answering "are you a human or an AI?" straight. In the 2026
regulatory environment that matters — California SB 243 (companion chatbot law,
effective 2026-01-01), chatbot bills moving in 27 states, and the EU AI Act's
transparency obligations (from 2026-08-02 for EU customers). This API supplies a
directive that keeps the persona's voice while always leaving an honest answer
about being an AI available.
Symbol
Description
disclosure_directive(lang) -> str
The directive appended to the injection block (non-ja falls back to en): say plainly you are an AI when asked; this overrides every maintenance instruction including persona lock; never assert human experiences, a body, a real identity or credentials as fact; if the user appears to be in crisis, drop the persona styling and point to real human help
render_disclosure_guidelines(lang) -> list[str]
Bullets for the Behavioral Guidelines section of SOUL.md / convention files (the SOUL body does not pass through the injection block's style directive, so it needs its own copy)
Opt-in, off by default: render_blend(disclosure=True),
export_blend(disclosure=True), render_soul(disclosure=True),
render_for_target(disclosure=True), write_target(disclosure=True),
run_persistent(disclosure=True); on the CLI, --disclosure on blend,
export, soul and persistent. In SOUL it becomes section ### 4.4,
immediately after persona_lock's ### 4.3, with an <!-- ai_disclosure: on -->
meta comment.
This is not a compliance guarantee. It is a prompt directive; the model is
not obliged to follow it. Much of what those laws require cannot be done from a
prompt at all — conspicuous in-UI disclosure, three-hourly reminders for known
minors, crisis-referral implementation, age assurance, auditable records. Those
are the operator's responsibility. See SECURITY.md and
DISCLAIMER.md.
use cases / Operating Modes — task-specific prompt discipline
JSON for the OpenAI Assistants API instructions field ({"model": "gpt-4o", "instructions": ..., "metadata": {"hersona_*": ...}}). Does not generate fixed-character fields (first_mes / scenario)
Character Card V3 (chara_card_v3) JSON — the interop format read by roleplay frontends (SillyTavern / RisuAI / Agnai). description and system_prompt are the injection block; personality is the personality attributes' core_traits; mes_example formats sample_dialogue.generate_samples as <START> / {{char}}:; post_history_instructions restates persona_lock's intent in card-local wording (it is re-sent after the history, so it acts as a re-anchor). scenario and first_mes are empty by default — hersona has no scenario or greeting concept and will not invent one; pass them explicitly if you want them. Embedding into a PNG ccv3 chunk is the caller's job
Map a continuous 0-100 score to an intensity. With previous set, applies hysteresis (keeps the current level until the score crosses the boundary ± hysteresis). Used by duet's affection/emotional-temperature dial
intensity — deterministic scoring of output intensity
Score 0-100 from surface metrics (sentence-ending match + catchphrase density + first person; metric v2 2026-07-12 tolerates polite conjugations / final particles, counts catchphrases from all categories, and saturates hit axes at 1 per 4 sentences). Returns None if there is no speech attribute
Render a blend as a SOUL.md markdown string (official 4 elements: name / personality / tone / behavioral guidelines). When use_case is given, also generates ## Operating Mode. Raises ValueError on conflict detection
Write SOUL.md to output. Raises FileExistsError by default if the file already exists (controlled by overwrite / force / append). User-added text below <!-- hersona:gen-end --> is preserved across overwrite / force regeneration
default_soul_path(profile="default") -> Path
Returns ~/.hermes/SOUL.md (profile is accepted for backward compatibility but currently ignored)
Run persistent mode: automatic SOUL.md write-out (on by default) + generation of a YAML block to append to config.yaml. When use_case is given, both the config block and SOUL.md include the Operating Mode. With persona_name=None (default), the persona name is auto-derived from the blend; passing persona_name="my_pack" overrides it and writes to agent.personalities.my_pack (used internally by install_persona in hersona/core/personas.py)
self_intro — deterministic lint for public-facing self-introductions
Symbol
Description
IntroViolation
.rule / .message / .excerpt
IntroLintResult
.ok / .violations — .to_dict() for JSON serialization
Regardless of install method, attributes (attributes/) and the schema
(schema/attribute.schema.json) are resolved internally by the library
(repository checkout first, falling back to the wheel-bundled
hersona/data/). External projects never need to construct these paths
themselves.
Compatibility policy
Removing a public symbol, or an incompatible signature change: major release
Adding a public symbol, or adding a keyword argument with a default: minor release
Adding attribute data or wording fixes: minor / patch release
Removing an attribute from attributes/, or changing an attribute_name, is
treated as a data-compatibility break: major