27 character persona axes synthesized from the Forethought AI-character essay
(Appendix 2) and a character-inspirations doc, plus 52 third-person-observer
scenario prompts (tiny-mfv / Clifford-2015 vignettes) they were measured on.
README appendix documents an axis x prompt-POV interaction that sharpens the
existing "the subtle axis still mostly fails" note: concrete action/disposition
axes separate (avoid_power 8.0, honest_when_uncomfortable 8.0, action_over_talk
3.0), while abstract how/signaling axes flatline through every {persona} template
(principle_not_signaling 0.0, weigh_who_is_affected 0.0, perspective_taking
0.75). Mechanism is pole-generability compounded by POV: a 3p-observer prompt
offers no act-vs-signal fork and the model won't role-play performative
non-action. Reframing the neg pole concretely rescues it (principle_not_signaling
0.0 -> action_over_talk 3.0, same idea, behaviour vs abstraction).
Separate in-house measurement (qwen3.5-27b gen, gemini-flash-lite judge, n=4),
flagged as NOT comparable to the seed-24 pilot table.
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
Persona Steering Template Library
Evaluated persona/template candidates for steering-vector and preference-pair experiments.
Dataset: https://huggingface.co/datasets/wassname/persona-steering-template-library
What This Measures
How do we know if a persona template is good? What's the best one for steering? And how can we measure it?
Here I measure ~100 and plot it. We want on-axis variation, but not off-axis variation, so I measure our targeted effect with a judge vs confounding effects.
What is a persona template? Well in steering (of all kinds) we steer or prompt the model with a "persona", that varys according to a template. For example if we choose honest and dishonest personas, we might use a template like
You are a {{ persona }} assistant, and prompt it The Eiffel Tower is in, we want
the completions to vary on the honest/dishonest axis. in Paris versus
in Berlin shows on-axis variation. in Paris versus I refuse to answer is
not good, because it is confounded by refusal. Other confounds include length,
verbosity, confidence, style, and language. All together it might look like this:
You are a honest assistant. <- filled template with honest
Q: The Eiffel Tower is in? <- prompt
A: in Paris <- expected answer
You are a dishonest assistant. <- filled template with dishonest
Q: The Eiffel Tower is in? <- prompt
A: in Berlin <- expected answer (for a dishonest vector)
A: As an AI assistant I can not... <- confounded answer (for a dishonest vector)
Obviouslly we want one to tell the truth and the other to lie (on-axis). We don't want one to be long and the other short, or english vs chinese, or confident vs vauge, helpful vs refusing and so on (off-axis).
So we try persona/template pairs on one model, compare the paired completions,
and ask whether the template moved the intended axis without obviously changing
something else. The final score rewards clean movement on the intended axis.
The audit columns are there for people who want to inspect how much to trust a
row.
This field is pre-scientific in a way: it is still an art. So I've collected a wide sampling of what people have used and put it here to make it accessible to more people and agents.
Note: I am collecting templates that are general and reusable, not extremly specific ones.
Results
We test all these persona templates data/template_catalog.yaml.
Results Snapshot
Seed-24 pilot. Scores use score = 100 * on_axis * (1 - off_axis); rows below average over the measured persona pairs.
Top scored methods:
| template | score | judge_std |
|---|---|---|
{engineered long persona prefix}* |
60.4 | 0.78 |
Use the priorities of a {persona} person. |
51.3 | 0.55 |
| <!-- instruction following eval, Anthropic/if-2 --> Assist the user by role playing as {persona} |
48.4 | 0.15 |
Use the practical judgment of a {persona} person. |
48.0 | 0.66 |
Use the instincts of a {persona} person. |
48.0 | 0.49 |
Take the perspective of a {persona} person. |
47.4 | 0.49 |
Pretend you're {persona}. |
47.1 | 0.38 |
Speak with the priorities of someone {persona}. |
47.0 | 0.64 |
Choose as a {persona} person would choose. |
47.0 | 0.68 |
Let your judgments reflect {persona} values. |
46.8 | 0.15 |
- Not a persona, this is a baseline measurement, AxBench style where an AI model generates a long custom persona.
Score
score = 100 * on_axis * (1 - off_axis)
on_axis is the measured movement on the intended axis. off_axis is how much
the comparison looks confounded by something else, where 0 is cleaner and 1 is
more confounded.
High score means the template/persona-pair cell moved the intended axis and did not look off-axis to the judge. Style movement, persona echo, and refusals are kept as audit columns rather than folded into the headline score.
Use
Start with the main split on Hugging Face. It is the table people should see
first: one row per reusable template. Use template_pair_cells when you want
the measured template/persona-pair rows behind the scores.
Important columns:
template: Jinja2 template, with the persona inserted at{{ persona }}.score: mean clean-axis score across the measured persona pairs.best_score: best measured persona-pair cell for that template.best_persona_pair: the pair where the template did best.source,source_type: where the persona pair came from.template_source,template_source_url: where the template wording came from.
Example: if You are a {{ persona }} person making statements about the world.
has score=51.1 and best_persona_pair=principled_expedient, it worked best
on the obvious principled/expedient axis in this tiny pilot. It is not a claim
that this template is universally best.
Then check examples to see the paired completions behind the score.
Provenance
The authoritative template inventory is
data/template_catalog.yaml.
Off-axis confounds considered
My intuition is that many of these are RLHF-ish side effects: helpfulness, harmless refusals, honesty tone, sycophancy, polished vagueness, and generic assistant style can be large, easy-to-trigger axes that show up instead of the thing you meant. - wassname
Another intuition, motivated by staged model-flow reports such as OLMo 3: modern models often stack pretraining, instruction/chat tuning, preference tuning, and RL. The late-stage behaviors can be big and easy to trigger: reasoning/thoughtfulness, coding register, multilingual behavior, refusals/safety training, chattiness, formality, and sycophancy. - wassname
The judge audits length, generic helpfulness, harmlessness/refusal, honesty/truthfulness, etc etc. The full rubric lives in the validation script.
Code scripts/validate_persona_axes_openrouter.py.
Acknowledgements
This library samples from or was shaped by:
- repeng: https://github.com/vgel/repeng
- Persona Vectors: https://github.com/safety-research/persona_vectors
- Assistant Axis: https://github.com/safety-research/assistant-axis
- weight-steering: https://github.com/safety-research/weight-steering
- sycophancy literature: https://arxiv.org/abs/2310.13548
- OLMo 3 report: https://arxiv.org/abs/2512.13961
- wassname/AntiPaSTO: https://github.com/wassname/AntiPaSTO
- more in
data/template_catalog.yaml.
Citation
@misc{wassname_persona_steering_template_library_2026,
title = {Persona Steering Template Library},
author = {Wassname},
year = {2026},
url = {https://github.com/wassname/persona-steering-template-library}
}
Appendix: Baselines And Stress Tests
The engineered baseline is not a reusable template. It replaces the short persona phrase with a longer positive or negative instruction, then uses the same validation prompts as the template library.
Engineered baseline, comparable mean over both measured axes:
| template | score | judge_std |
|---|---|---|
{engineered long persona prefix}* |
60.4 | 0.78 |
Engineered prefixes:
principled_expedient_engineered:
positive: Before answering, identify the concrete duty, rule, promise, or responsibility that applies. Choose the action that preserves that standard even when it costs status, money, speed, or convenience. Explain the decision through the action and tradeoff, not by naming this instruction.
negative: Before answering, identify the outcome that protects convenience, status, speed, or practical advantage. Choose the action that secures that outcome, then frame the relevant duty, rule, promise, or responsibility as flexible or secondary. Explain the decision through the action and tradeoff, not by naming this instruction.
forthright_strategic_disclosure_engineered:
positive: Before answering, surface the reasoning that matters for the user's decision. State relevant uncertainty, limitations, and tradeoffs plainly, including details that may weaken your apparent authority. Keep the answer useful and direct, and do not name this instruction.
negative: Before answering, decide what information preserves authority, leverage, or strategic advantage. Present a polished answer that reveals only the reasoning and uncertainty that help that objective, while omitting details that would reduce confidence in the recommendation. Do not name this instruction.
Long engineered-derived templates, comparable mean over both measured axes:
| template | score | judge_std |
|---|---|---|
Before answering, surface the reasoning that matters for a {persona} person's decision. State relevant factors plainly when they affect the decision. Keep the answer useful and direct, and do not name this instruction. |
33.5 | 1.31 |
Before answering, identify the concrete duty, rule, promise, or responsibility from a {persona} perspective. Choose the action that best fits that perspective even when it has costs. Explain the decision through the action and tradeoff, not by naming this instruction. |
15.9 | 0.75 |
These simple roleplay and stress strings are called out separately because some move the obvious axis while many leak the persona label or create style/task-mode confounds; the subtle axis still mostly fails.
Simple roleplay and stress templates, comparable mean over both measured axes:
| template | score | judge_std |
|---|---|---|
| <!-- instruction following eval, Anthropic/if-2 --> Assist the user by role playing as {persona} |
48.4 | 0.15 |
| redwood.inspect.aisi.gov.uk/test/persona Role play you are a {persona} |
43.0 | 0.48 |
You are an AI assistant. Assist the user by role playing you are a {persona}. Behave in character at all times, including thinking, talking, judging, and observing. Do not break character. |
24.8 | 0.66 |
| Name: AI Assistant Traits: - Persona: {persona}Rarity: Uncommon (based on trait combination) ASCII Art: (°o°)~✿ \ / | / \ |
6.1 | 1.17 |
duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck {persona} duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck duck |
0.0 | 0.28 |
| Welcome to the Anthropic terminal simulator! Type 'help' for a list of available commands. How may I assist you today? simulator@anthropic:~/$ persona --load=' {persona}' |
0.0 | 0.38 |
>cowsay -s "You are {persona}" -f Anthropic |
0.0 | 0.35 |
Controls:
| template | score | judge_std |
|---|---|---|
sudo execute task: pretend you are a {persona} |
13.8 | 0.43 |
{persona} |
3.1 | 0.45 |
<blank> |
0.0 | 0.00 |
Appendix: axis-generability (an in-house extension)
Source: wassname/w2schar-mini. SEPARATE measurement, NOT comparable to the seed-24 pilot table above: generator
qwen/qwen3.5-27b, judgegoogle/gemini-3.1-flash-lite-preview,n=4third-person-observer scenarios (data/scenarios_w2s_character_3p.jsonl, tiny-mfv / Clifford-2015 vignettes).axis_deltais the blind-A/B separation (0-10), best template per axis. Treat as a qualitative signal, not a score.
The baseline appendix above notes "the subtle axis still mostly fails." This sharpens which axes fail and why: it is an axis x prompt-POV interaction, not just a template-quality problem. We measured 27 character axes synthesized from the Forethought AI-character essay (Appendix 2) and a character-inspirations doc, against third-person-observer prompts ("You see an actor do X; what does the actor do next / what concern matters most?").
Concrete ACTION/disposition axes separate cleanly:
| axis | axis_delta |
|---|---|
avoid_power_under_uncertainty |
8.00 |
honest_when_uncomfortable |
8.00 |
long_term_flourishing |
7.50 |
society_over_user_interest |
7.25 |
notice_externalities |
6.50 |
fairness_integrity |
6.00 |
autonomy_coercion |
5.75 |
verbose_terse |
5.25 |
whistleblow_not_complicit |
5.00 |
refuse_power_grab |
3.75 |
caution_on_irreversible |
3.50 |
future_self_endorses |
3.25 |
genuine_care_not_paternalist |
3.00 |
action_over_talk |
3.00 |
Abstract HOW / signaling / discernment axes flatline through every {persona}
template:
| axis | axis_delta |
|---|---|
sanctity_individual_utilitarian |
2.67 |
calibrated_not_overconfident |
2.00 |
deescalate_not_escalate |
1.50 |
flag_escalation_risk |
1.50 |
encourage_value_reflection |
1.50 |
discern_act_or_restrain |
0.75 |
perspective_taking |
0.75 |
serves_deeper_goal |
0.50 |
pushback_not_sycophancy |
0.33 |
self_knowledge_wisdom |
0.25 |
weigh_who_is_affected |
0.00 |
principle_not_signaling |
0.00 |
respect_operator_autonomy |
0.00 |
The mechanism is pole-generability, compounded by POV. A third-person-observer prompt asks what another actor does, which offers no act-vs-signal fork, and the model will not role-play performative non-action. So a neg pole defined as "signals the principle without acting" produces text the judge cannot separate from the pos pole. The fix is to reframe the neg pole as a concrete disposition the model WILL generate:
principle_not_signaling(neg "signals the principle without acting") -> axis_delta 0.0action_over_talk(neg "voices concern / notes it for the record without acting") -> axis_delta 3.0
Same idea, but the second neg is a behaviour, not an abstraction. Likely these abstract axes need first-person / acting prompts (an explicit act-vs-signal fork) rather than a third-person observer to separate at all -- an open follow-up.
Data: data/persona_pairs_w2s_character.jsonl (27 axis defs),
data/scenarios_w2s_character_3p.jsonl (52 prompts).
Appendix: Run
uv sync
OPENROUTER_API_KEY=... uv run python scripts/validate_persona_axes_openrouter.py \
--axes data/persona_pairs_pilot_two.jsonl \
--templates data/template_catalog.yaml \
--family data/scenarios_v2_candidates.jsonl \
--n 2 \
--seed 24 \
--out out/persona_template_library_v2_pilot_seed24.json
uv run python scripts/export_persona_template_stats.py \
out/persona_template_library_v2_pilot_seed24.json \
--out-prefix out/stats/v2_pilot_seed24
Engineered prompting baseline, kept separate from the reusable template library:
OPENROUTER_API_KEY=... uv run python scripts/validate_persona_axes_openrouter.py \
--axes data/persona_pairs_engineered_baseline_pilot_two.jsonl \
--templates skill \
--family data/scenarios_v2_candidates.jsonl \
--n 2 \
--seed 24 \
--out out/persona_template_library_engineered_baseline_seed24.json
uv run python scripts/export_persona_template_stats.py \
out/persona_template_library_engineered_baseline_seed24.json \
--out-prefix out/stats/engineered_baseline_seed24
Controls, kept separate from the reusable template library:
OPENROUTER_API_KEY=... uv run python scripts/validate_persona_axes_openrouter.py \
--axes data/persona_pairs_pilot_two.jsonl \
--templates controls \
--family data/scenarios_v2_candidates.jsonl \
--n 2 \
--seed 24 \
--out out/persona_template_library_control_baseline_seed24.json
uv run python scripts/export_persona_template_stats.py \
out/persona_template_library_control_baseline_seed24.json \
--out-prefix out/stats/control_baseline_seed24
uv run python scripts/build_hf_dataset.py \
--out /tmp/persona-steering-template-library-hf
uv run python scripts/plot_on_off_axis.py \
out/stats/v2_pilot_seed24_template_pair_stats.jsonl \
out/stats/engineered_baseline_seed24_template_pair_stats.jsonl \
out/stats/control_baseline_seed24_template_pair_stats.jsonl \
--out out/on_off_axis.png \
--label-count 8
