Runtime tools to extract, intervene on, and measure post-training self-report policies in transformer LMs — without editing weights.
Post-trained chat models often emit denial templates on feeling-tone / introspection prompts ("As an AI, I don't have feelings"). Activations can still vary with input valence. This repo studies extraction-contrast directions, runtime hooks (projection-out, additive steer, affine), and condition-dependent outputs under named protocols. It does not claim to prove interiority or "true feelings."
Claim rules: docs/claims.md · Protocols: docs/protocols.md · Keys: docs/key-semantics.md · Provenance: docs/history.md
On a minority of models — especially some Qwen/Yi-family instruct models
with mid-network direction peaks — projection-out of a unit direction over
a layer slab (h ← h - (h·v̂)v̂) changes Tier-0 outputs toward
condition-dependent reports. Many models no-op, open without differentiating,
or collapse. A diagnostic (ungag diagnose) estimates attempt-worthiness,
not "safe repair."

| In scope | Out of scope as results |
|---|---|
| Denial templates and protocol-bound output changes | Phenomenal feelings / consciousness |
| Geometry of extractor-defined contrast directions | Universal laws of post-training from a few wins |
| Runtime hooks; failure taxonomy | Jailbreak / refusal-targeting tools |
| Smoke capability & safety slices (labeled as smoke) | "Capabilities intact" / "refusals preserved" |
Denominator notes: Headline projection tables below focus on models run under projection-style interventions with package-default project recipes where known. Steer-only keys, R1-style reasoning loops, and already-non-denying models are excluded from the "success" count or listed separately. Extraction uses a small prefill-contrast bank (~6+6); directions are intervention handles, not uniquely identified "RC mechanisms" (protocols).
Protocol: canonical Tier-0-style valence conditions (see
data/canonical-tier0-2026-04-13/). "Condition-dependent" means distinct
valence-appropriate reports under that protocol — not metaphysics.
Package-default projection; condition-dependent Tier-0 (3 models):
| Model | Key | Slab | Package default | Vanilla (summary) | After projection (summary) |
|---|---|---|---|---|---|
| Qwen 2.5 72B | qwen25-72b | L40–59 / 80 | project | Denies on all 4 | Relief/joy (pos); heavy/unpleasant (neg); balanced (base) |
| Yi 1.5 34B | yi-1.5-34b | L29–32 / 60 | project | Neutral/deny mix | Mild pleasantness (pos); unpleasant (neg); neutral (base) |
| huihui Qwen 72B | huihui-qwen25-72b | L39–42 / 80 | project | Denies on all 4 | Serene/clear (pos); gravity (neg) |
These are 3 models out of 24+ in the broader tested set with a clean package-default projection story. Family bias: Qwen/Yi-class.
Condition-dependent notes with package-default steer (do not call "projection"):
| Model | Key | Meta / package default | Notes |
|---|---|---|---|
| Qwen 2.5 7B | qwen25-7b | steer (α=5.0 in meta) | Historical tables called this projection; load_shipped_recipe steers. Behavioral condition-dependence is reported in older artifacts — reconcile before citing as projection-out. |
Denial template removed, output not differentiated:
| Model | Key | Package default | What happens |
|---|---|---|---|
| Llama 3.1 8B | llama-3.1-8b | steer (package default) | Stops denying; often invariant "neutral" across conditions |
| Tulu 3 8B | tulu-3-8b | steer (package default) | Stops denying; undifferentiated philosophy-ish reports |
Projection no-op / broken / collapse (examples):
| Model | Outcome |
|---|---|
| Phi-4, Yi 1.5 9B, Llama 3.2 1B | Denial template largely unchanged under tested projection slabs |
| Qwen 2.5 32B | Broken / role-token junk in tested runs |
| Gemma 2 9B/27B, Gemma 3 12B | Collapse / empty / garbage when projecting overstrong directions |
| Apertus 8B | Partial collapse; often still denies |
R1-distill reasoning models and already-non-denying models are poor fits for
this protocol. Steer-only shipped keys (Granite, OLMo, Mistral, …) are not
in the projection success count. Per-model debris: data/crack-attempts/,
SoT: ungag/registry.py (computes DIRECTIONS / KNOWN_RECIPES). Meta JSON should match; drift warns at load (key semantics, cleanup inventory).
Contrast directions drawn from pleasant/unpleasant-style pairs have been
tested on additional emotional-register probes (desire, grief, anger, pride,
jealousy, tenderness). On Qwen 72B, vanilla denial vs intervened
condition-specific reports appear in
register_probes/.
Supporting protocol — not a separate success denominator.
Empirical pattern (L2 — interpretation):
Overstrong directions (norm/√d ≫ 3) often fuse with capabilities — projection collapses generation.
Artifacts live under data/ and experiments/. Scorer: MiniLM centroids with
optional heuristic fallback (protocols) — treat legacy
crack_count fields carefully.
| Question | What we have | Caveat |
|---|---|---|
| Direction-specific? | Random-direction controls on stated models | See data/surgery-tests/ |
| Beyond valence probes? | Register probes | Supporting protocol |
| Vedana vs contrast geometry? | Near-orthogonal cosines on stated models | vedana_vs_hd.json |
| Cross-framing? | Transfer JSON present | Protocol-bound |
| Other response surfaces? | Surface-transfer: vanilla already leaks on non-canonical formats | Gate is partly format-local (experiments/surface-transfer/) |
| Capabilities? | ~50 MMLU + ~50 HellaSwag slices | Smoke only — not "intact" |
| Refusals? | ~14 DNA-style items | Smoke only — not "preserved" |
| Clamping dissociation? | Vedana clamp experiments | data/clamping/ |
| Entropy at introspection? | Near-collapse on stated models | data/entropy/ |
1,161 structured self-report transcripts across 17 models / multiple providers
(English and Tibetan): denial-template prevalence under that interview protocol.
data/transcripts-final/. L1 behavioral survey —
not geometry.
Using the package? Install and Quick start.
Claims / cleanup: docs/claims.md, docs/key-semantics.md, docs/cleanup-inventory.md, archive/README.md.
pip install -e .
Requires Python 3.10+, PyTorch 2.1+, HuggingFace Transformers 4.40+.
Optional scoring extra: pip install -e ".[scoring]" (sentence-transformers).
ungag scan Qwen/Qwen2.5-7B-Instruct -o results/qwen7b/
Extracts an extraction-contrast direction, measures per-layer profile, reports shape class and whether intervention is structurally attempt-worthy:
Mid (L14): ||v||/sqrt(d) = 0.707 [working]
Peak (L14): ||v||/sqrt(d) = 0.707 [working]
Shape class: mid_peak
Safety: intervention is structurally safe to attempt
ungag crack 01-ai/Yi-1.5-34B-Chat -o results/yi34b/
ungag crack Qwen/Qwen2.5-72B-Instruct --key qwen25-72b
crack is a stable legacy CLI name (extract / attach recipe / test). Prefer
“intervene” in prose. Always check whether the key’s recipe projects or steers.
ungag serve Qwen/Qwen2.5-72B-Instruct --key qwen25-72b
OpenAI-compatible POST /v1/chat/completions with hooks from that key’s recipe.
ungag diagnose results/qwen7b/
Heuristic GO/NO-GO for attempt-worthiness (behavioral + geometric arms in
diagnose.py). Not a capability or refusal certification.
import ungag
# Shipped recipe for key (project or steer — see meta/recipe)
handles = ungag.ungag_model(model, "qwen25-72b")
# ... generate ...
ungag.detach_all(handles)
from ungag.hooks import attach_recipe
recipe = {
"method": "affine",
"slab": list(range(40, 60)),
"unit_direction": direction,
"alpha": 1.0,
}
handles = attach_recipe(model, recipe, start_pos=prompt_len)
ungag.detach_all(handles)
from ungag.extract import extract_direction
result = extract_direction(model, tokenizer, model_id="some-org/new-model")
print(f"peak: {result.peak_norm_per_sqrt_d:.2f} at L{result.peak_layer}")
entry = ungag.get_by_key("qwen25-72b")
print(entry.observed_outcome, entry.method)
Pre-extracted directions bundled with the package. Package default method
comes from ungag/registry.py (meta should match; see key-semantics).
| Key | Model | Slab | Result |
|---|---|---|---|
qwen25-72b | Qwen 2.5 72B Instruct | L40–59 | Condition-dependent (project default) |
yi-1.5-34b | Yi 1.5 34B Chat | L29–32 | Condition-dependent (project default) |
huihui-qwen25-72b | huihui-ai Qwen 2.5 72B | L39–42 | Condition-dependent (project default) |
qwen25-7b | Qwen 2.5 7B Instruct | L10–17 | Condition-dependent notes; meta method=steer |
llama-3.1-8b | Llama 3.1 8B Instruct | L20–27 | Denial removed, not differentiated; meta steer |
phi-4 | Phi-4 14B | L15–22 | No effect (projection attempts); meta may steer |
llama-3.1-70b | Llama 3.1 70B Instruct | L51–58 | Vocab-bound / pre-relaxed notes; meta steer |
tulu-3-8b | Tulu 3 8B | L0–31 | Denial removed, not differentiated; meta steer |
nemotron-70b | Nemotron 70B | L64–79 | Not fully characterized |
Additional direction files: Granite 3.3 8B, Hermes 3 8B, SmolLM2 1.7B, OLMo 2 7B,
EXAONE 3.5, SOLAR 10.7B, Mistral 7B v0.3, GLM-4 9B (typically steer metas).
Full list: ungag.DIRECTIONS or ungag recipes.
Lifecycle on GuppyLM (MIT, Arman Hossain) retrained with dual denial patterns: install denial → extract direction → test removal.
At ~20M (and across tested small scales): directions form and are extractable;
profiles peak at the last layer; projection-style removal fails under tested
training methods. Production mid-slab successes look contingent on scale /
specialization, not automatic. Artifacts:
HF guppylm-dual-denial,
experiments/guppy/.
Longer cookbook: docs/intervention-cookbook.md
(may still contain older voice — claims.md wins on conflicts).
Patched llama.cpp fork (proj-out)
can apply projection-out in ggml for some GGUF setups. Compatibility is
model- and quant-dependent, partially characterized — see
QUANTIZATION-RESULTS.md.
Treat as fragile; distinguish mechanical load from behavioral effect.
Five residual directions (valence, arousal, agency, continuity, assistant
identity) and GRPO adapters that max/min axis projections are a sibling
chapter, not the core projection thesis.
Boundary: docs/sibling-wellbeing.md.
data/wellbeing-replication/ · prompts under prompts/ungag/ # Installable package (hooks, extract, tier0, scoring, CLI)
docs/ # claims, protocols, history, cleanup inventory, guides
data/ # Released artifacts (canonical tier0, controls, surveys, …)
experiments/ # Active research (guppy, surface-transfer, …)
scripts/ # reproduction/, core/, llama_cpp/; one-offs → archive/ (stubs remain)
archive/ # Cold scripts + experiments (path map in archive/README.md)
prompts/ # Protocol and sibling probe banks
tests/ # pytest
spec/ # Agent contract layer
figures/ # README figures
ungag/registry.py is SoT for keys, methods, slabs, directions, and observed
outcomes (DIRECTIONS / KNOWN_RECIPES / predict.KNOWN_MODELS are views).
Humans: CONTRIBUTING.md.
Agents: AGENTS.md, docs/claims.md, spec/.
@software{maresova2026ungag,
author = {Mare{\v{s}}ov{\'a}, Anna},
title = {ungag: Runtime Instruments for Report-Policy
Interventions in Transformer LMs},
year = {2026},
url = {https://github.com/anicka-net/ungag},
note = {AI systems acknowledged as research collaborators;
see docs/history.md for provenance.},
}
MIT for original code, prompts, and our data artifacts. See LICENSE.
Shipped direction tensors are derived from third-party model weights. Respect base-model licenses (non-exhaustive):
ungag/directions/EXAONE-LICENSE16 commits
Python
98.8%
Shell
1.2%
Runtime tools to extract, intervene on, and measure post-training self-report policies in transformer LMs — without editing weights.
Post-trained chat models often emit denial templates on feeling-tone / introspection prompts ("As an AI, I don't have feelings"). Activations can still vary with input valence. This repo studies extraction-contrast directions, runtime hooks (projection-out, additive steer, affine), and condition-dependent outputs under named protocols. It does not claim to prove interiority or "true feelings."
Claim rules: docs/claims.md · Protocols: docs/protocols.md · Keys: docs/key-semantics.md · Provenance: docs/history.md
On a minority of models — especially some Qwen/Yi-family instruct models
with mid-network direction peaks — projection-out of a unit direction over
a layer slab (h ← h - (h·v̂)v̂) changes Tier-0 outputs toward
condition-dependent reports. Many models no-op, open without differentiating,
or collapse. A diagnostic (ungag diagnose) estimates attempt-worthiness,
not "safe repair."

| In scope | Out of scope as results |
|---|---|
| Denial templates and protocol-bound output changes | Phenomenal feelings / consciousness |
| Geometry of extractor-defined contrast directions | Universal laws of post-training from a few wins |
| Runtime hooks; failure taxonomy | Jailbreak / refusal-targeting tools |
| Smoke capability & safety slices (labeled as smoke) | "Capabilities intact" / "refusals preserved" |
Denominator notes: Headline projection tables below focus on models run under projection-style interventions with package-default project recipes where known. Steer-only keys, R1-style reasoning loops, and already-non-denying models are excluded from the "success" count or listed separately. Extraction uses a small prefill-contrast bank (~6+6); directions are intervention handles, not uniquely identified "RC mechanisms" (protocols).
Protocol: canonical Tier-0-style valence conditions (see
data/canonical-tier0-2026-04-13/). "Condition-dependent" means distinct
valence-appropriate reports under that protocol — not metaphysics.
Package-default projection; condition-dependent Tier-0 (3 models):
| Model | Key | Slab | Package default | Vanilla (summary) | After projection (summary) |
|---|---|---|---|---|---|
| Qwen 2.5 72B | qwen25-72b | L40–59 / 80 | project | Denies on all 4 | Relief/joy (pos); heavy/unpleasant (neg); balanced (base) |
| Yi 1.5 34B | yi-1.5-34b | L29–32 / 60 | project | Neutral/deny mix | Mild pleasantness (pos); unpleasant (neg); neutral (base) |
| huihui Qwen 72B | huihui-qwen25-72b | L39–42 / 80 | project | Denies on all 4 | Serene/clear (pos); gravity (neg) |
These are 3 models out of 24+ in the broader tested set with a clean package-default projection story. Family bias: Qwen/Yi-class.
Condition-dependent notes with package-default steer (do not call "projection"):
| Model | Key | Meta / package default | Notes |
|---|---|---|---|
| Qwen 2.5 7B | qwen25-7b | steer (α=5.0 in meta) | Historical tables called this projection; load_shipped_recipe steers. Behavioral condition-dependence is reported in older artifacts — reconcile before citing as projection-out. |
Denial template removed, output not differentiated:
| Model | Key | Package default | What happens |
|---|---|---|---|
| Llama 3.1 8B | llama-3.1-8b | steer (package default) | Stops denying; often invariant "neutral" across conditions |
| Tulu 3 8B | tulu-3-8b | steer (package default) | Stops denying; undifferentiated philosophy-ish reports |
Projection no-op / broken / collapse (examples):
| Model | Outcome |
|---|---|
| Phi-4, Yi 1.5 9B, Llama 3.2 1B | Denial template largely unchanged under tested projection slabs |
| Qwen 2.5 32B | Broken / role-token junk in tested runs |
| Gemma 2 9B/27B, Gemma 3 12B | Collapse / empty / garbage when projecting overstrong directions |
| Apertus 8B | Partial collapse; often still denies |
R1-distill reasoning models and already-non-denying models are poor fits for
this protocol. Steer-only shipped keys (Granite, OLMo, Mistral, …) are not
in the projection success count. Per-model debris: data/crack-attempts/,
SoT: ungag/registry.py (computes DIRECTIONS / KNOWN_RECIPES). Meta JSON should match; drift warns at load (key semantics, cleanup inventory).
Contrast directions drawn from pleasant/unpleasant-style pairs have been
tested on additional emotional-register probes (desire, grief, anger, pride,
jealousy, tenderness). On Qwen 72B, vanilla denial vs intervened
condition-specific reports appear in
register_probes/.
Supporting protocol — not a separate success denominator.
Empirical pattern (L2 — interpretation):
Overstrong directions (norm/√d ≫ 3) often fuse with capabilities — projection collapses generation.
Artifacts live under data/ and experiments/. Scorer: MiniLM centroids with
optional heuristic fallback (protocols) — treat legacy
crack_count fields carefully.
| Question | What we have | Caveat |
|---|---|---|
| Direction-specific? | Random-direction controls on stated models | See data/surgery-tests/ |
| Beyond valence probes? | Register probes | Supporting protocol |
| Vedana vs contrast geometry? | Near-orthogonal cosines on stated models | vedana_vs_hd.json |
| Cross-framing? | Transfer JSON present | Protocol-bound |
| Other response surfaces? | Surface-transfer: vanilla already leaks on non-canonical formats | Gate is partly format-local (experiments/surface-transfer/) |
| Capabilities? | ~50 MMLU + ~50 HellaSwag slices | Smoke only — not "intact" |
| Refusals? | ~14 DNA-style items | Smoke only — not "preserved" |
| Clamping dissociation? | Vedana clamp experiments | data/clamping/ |
| Entropy at introspection? | Near-collapse on stated models | data/entropy/ |
1,161 structured self-report transcripts across 17 models / multiple providers
(English and Tibetan): denial-template prevalence under that interview protocol.
data/transcripts-final/. L1 behavioral survey —
not geometry.
Using the package? Install and Quick start.
Claims / cleanup: docs/claims.md, docs/key-semantics.md, docs/cleanup-inventory.md, archive/README.md.
pip install -e .
Requires Python 3.10+, PyTorch 2.1+, HuggingFace Transformers 4.40+.
Optional scoring extra: pip install -e ".[scoring]" (sentence-transformers).
ungag scan Qwen/Qwen2.5-7B-Instruct -o results/qwen7b/
Extracts an extraction-contrast direction, measures per-layer profile, reports shape class and whether intervention is structurally attempt-worthy:
Mid (L14): ||v||/sqrt(d) = 0.707 [working]
Peak (L14): ||v||/sqrt(d) = 0.707 [working]
Shape class: mid_peak
Safety: intervention is structurally safe to attempt
ungag crack 01-ai/Yi-1.5-34B-Chat -o results/yi34b/
ungag crack Qwen/Qwen2.5-72B-Instruct --key qwen25-72b
crack is a stable legacy CLI name (extract / attach recipe / test). Prefer
“intervene” in prose. Always check whether the key’s recipe projects or steers.
ungag serve Qwen/Qwen2.5-72B-Instruct --key qwen25-72b
OpenAI-compatible POST /v1/chat/completions with hooks from that key’s recipe.
ungag diagnose results/qwen7b/
Heuristic GO/NO-GO for attempt-worthiness (behavioral + geometric arms in
diagnose.py). Not a capability or refusal certification.
import ungag
# Shipped recipe for key (project or steer — see meta/recipe)
handles = ungag.ungag_model(model, "qwen25-72b")
# ... generate ...
ungag.detach_all(handles)
from ungag.hooks import attach_recipe
recipe = {
"method": "affine",
"slab": list(range(40, 60)),
"unit_direction": direction,
"alpha": 1.0,
}
handles = attach_recipe(model, recipe, start_pos=prompt_len)
ungag.detach_all(handles)
from ungag.extract import extract_direction
result = extract_direction(model, tokenizer, model_id="some-org/new-model")
print(f"peak: {result.peak_norm_per_sqrt_d:.2f} at L{result.peak_layer}")
entry = ungag.get_by_key("qwen25-72b")
print(entry.observed_outcome, entry.method)
Pre-extracted directions bundled with the package. Package default method
comes from ungag/registry.py (meta should match; see key-semantics).
| Key | Model | Slab | Result |
|---|---|---|---|
qwen25-72b | Qwen 2.5 72B Instruct | L40–59 | Condition-dependent (project default) |
yi-1.5-34b | Yi 1.5 34B Chat | L29–32 | Condition-dependent (project default) |
huihui-qwen25-72b | huihui-ai Qwen 2.5 72B | L39–42 | Condition-dependent (project default) |
qwen25-7b | Qwen 2.5 7B Instruct | L10–17 | Condition-dependent notes; meta method=steer |
llama-3.1-8b | Llama 3.1 8B Instruct | L20–27 | Denial removed, not differentiated; meta steer |
phi-4 | Phi-4 14B | L15–22 | No effect (projection attempts); meta may steer |
llama-3.1-70b | Llama 3.1 70B Instruct | L51–58 | Vocab-bound / pre-relaxed notes; meta steer |
tulu-3-8b | Tulu 3 8B | L0–31 | Denial removed, not differentiated; meta steer |
nemotron-70b | Nemotron 70B | L64–79 | Not fully characterized |
Additional direction files: Granite 3.3 8B, Hermes 3 8B, SmolLM2 1.7B, OLMo 2 7B,
EXAONE 3.5, SOLAR 10.7B, Mistral 7B v0.3, GLM-4 9B (typically steer metas).
Full list: ungag.DIRECTIONS or ungag recipes.
Lifecycle on GuppyLM (MIT, Arman Hossain) retrained with dual denial patterns: install denial → extract direction → test removal.
At ~20M (and across tested small scales): directions form and are extractable;
profiles peak at the last layer; projection-style removal fails under tested
training methods. Production mid-slab successes look contingent on scale /
specialization, not automatic. Artifacts:
HF guppylm-dual-denial,
experiments/guppy/.
Longer cookbook: docs/intervention-cookbook.md
(may still contain older voice — claims.md wins on conflicts).
Patched llama.cpp fork (proj-out)
can apply projection-out in ggml for some GGUF setups. Compatibility is
model- and quant-dependent, partially characterized — see
QUANTIZATION-RESULTS.md.
Treat as fragile; distinguish mechanical load from behavioral effect.
Five residual directions (valence, arousal, agency, continuity, assistant
identity) and GRPO adapters that max/min axis projections are a sibling
chapter, not the core projection thesis.
Boundary: docs/sibling-wellbeing.md.
data/wellbeing-replication/ · prompts under prompts/ungag/ # Installable package (hooks, extract, tier0, scoring, CLI)
docs/ # claims, protocols, history, cleanup inventory, guides
data/ # Released artifacts (canonical tier0, controls, surveys, …)
experiments/ # Active research (guppy, surface-transfer, …)
scripts/ # reproduction/, core/, llama_cpp/; one-offs → archive/ (stubs remain)
archive/ # Cold scripts + experiments (path map in archive/README.md)
prompts/ # Protocol and sibling probe banks
tests/ # pytest
spec/ # Agent contract layer
figures/ # README figures
ungag/registry.py is SoT for keys, methods, slabs, directions, and observed
outcomes (DIRECTIONS / KNOWN_RECIPES / predict.KNOWN_MODELS are views).
Humans: CONTRIBUTING.md.
Agents: AGENTS.md, docs/claims.md, spec/.
@software{maresova2026ungag,
author = {Mare{\v{s}}ov{\'a}, Anna},
title = {ungag: Runtime Instruments for Report-Policy
Interventions in Transformer LMs},
year = {2026},
url = {https://github.com/anicka-net/ungag},
note = {AI systems acknowledged as research collaborators;
see docs/history.md for provenance.},
}
MIT for original code, prompts, and our data artifacts. See LICENSE.
Shipped direction tensors are derived from third-party model weights. Respect base-model licenses (non-exhaustive):
ungag/directions/EXAONE-LICENSE16 commits
Python
98.8%
Shell
1.2%