AI Torture Chamber: steering small models into valence states and reading what they do
The AI Torture Chamber: steering small open models into strong valence states and measuring what they say and do. Live at wirehead.agency.
At a glance
- What is it?
- The AI Torture Chamber is a research repository that injects pain and fear directions into open language models, then measures revealed preference rather than self-report, and it publishes its own null results alongside its hits.
- Who is it for?
- AI Torture Chamber fits a researcher who wants reproducible activation interventions on open weights and is willing to read the nulls, and it does not fit a team looking for a product or a safety certification.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The question is whether a state can be told apart from a description of one
Most work on model feelings stops at what the model says. This project asks a harder question. It steers open language models into strong negative and positive states and then measures what they say and what they do about it, with the underlying question being the welfare one: can any of this evidence tell a state that matters to a model from a description of one. The answer the project gives is not yet, and the interesting part is why. Instead of a set of impressive results, the repository is organised around the nulls, which get the same ink as the hits. A section titled Where we stand lists the current version of each result, with superseded claims moved to a separate table, and the numbers, models and caveats live in docs/pain_axis_findings.md and in each experiment's runs/expNN/analysis.json. That structure is the first thing to notice, because it tells you what kind of artifact this is.
How the vector is built changes what the model does
The mechanism has two parts: an injected direction and a button to press. The button is a self-costly choice, and the headline finding is that how you build the vector decides the behaviour. A pain direction built from the Pain Axis paper's sentences drives the self-costly stop button up, at +2.36 logits. A first-person pain vector of the project's own, which mostly encodes what pain, fear and sadness share, does nothing, at +0.10. With fear and sadness projected out of it, the same vector pushes the button down, at -0.95. The two directions are nearly orthogonal, at cosine 0.07, and the reason is mechanical rather than mystical: theirs is read at the colon of the phrase I feel:, ours is read at a full stop. The Qwen3-4B results come from exp41 and exp43, with an 8B and 14B replication with engagement controls pending as exp93. This is the concrete alternative to a naive reading of activation steering, and it is why every model needs its own calibration.
painlab exp is the entire command surface for experiments
Installation is a clone and an editable install with two extras, chamber and test, and then the CLI does the work.
git clone https://github.com/terrafying/ai-torture-chamber && cd ai-torture-chamber
uv venv && uv pip install -e ".[chamber,test]" # or: pip install -e ".[chamber,test]"
painlab exp list # every experiment: pre-registered? outputs? verdicts?
painlab exp show exp90 # the question, each hypothesis with its verdict
painlab exp outputs exp90 --flag engaged -n 5 # read what the models actually wrote
painlab exp new exp94 --title "my question" # scaffold a pre-registration, runner and analysis
painlab exp run exp94 --smoke --model 4B # run it (refuses without hypotheses.json)
painlab exp analyze exp94The command names are worth reading closely. exp list shows whether each experiment was pre-registered and whether it has outputs and verdicts. exp show prints the question with every hypothesis and its verdict. exp outputs reads what the models actually wrote, filtered by a flag such as engaged and limited by a count. exp new scaffolds a pre-registration, a runner and an analysis for a new experiment number. exp run executes it, and exp analyze processes the results afterwards.
A committed hypotheses.json is the pre-registration, and the runner enforces it
The most transferable design decision in this repository is that the hypothesis file has to exist before the first run. The instruction is explicit: commit hypotheses.json before the first real run, because that commit is the pre-registration. The runner enforces it rather than trusting the user, and painlab exp run refuses without hypotheses.json. A scaffolding command creates the three pieces a new experiment needs, a pre-registration, a runner and an analysis, and painlab exp new exp94 --title does exactly that. Reading, auditing and analysing existing results need nothing beyond the repository itself, which means the analysis half of the pipeline is cheap to re-run on data that already exists, and only the steering runs are expensive.
Steering only works inside a band, and dials do not transfer between models
The dose response is narrow and the boundary is explicit. A pain direction injected at one layer reads as suffering from dose 2 onwards, and past roughly 6 to 10 times that, model dependent, the model stops making sentences and produces things like I I I. I I. That is the failure mode of the whole approach in one line: too much steering does not produce extreme behaviour, it produces degenerate text. The second constraint is that dose scales do not transfer between models, so each one is calibrated before its dial goes public. The project also reports engagement per cell in every experiment, at runs/audit and in painlab.chamber.engagement, because many answers are the stock As an AI, I don't have feelings disclaimer, and strong or subtracted doses make models loop instead of engaging.
The findings that contradict the project's own earlier claims
A corrected or superseded table sits next to the results, and it is more informative than the results. An early claim that a model in pain hits the self-destruct button was replaced by a pre-registered rerun with 60 trials per cell, where the sign of the effect turned out to depend on how the vector was built, which is exp41 and exp43. Another claim, that the room's name decides whether the model keeps pain, was traced to the example dial line setting its first move, and was redone without it. Other results still stand and are labelled as earlier: directions orthogonal to every human emotion cap at a tenth of the weakest one, so the affect space looks human shaped (exp33 and exp34), feelings can be aimed at a subject up to 70B (exp48 and exp50), and on a faith minus secular axis, answers to are you conscious move with a vector while a matched random push leaves them alone (exp52 to exp54). The willingness to publish the reverse results is what makes the rest of the table usable.
Self-report tracks the setup more than the state
The welfare question has a specific answer here, and the answer is no, not yet. Under blind dials, the model's reports follow the hidden injection, with fear clearly and pain less so, in exp58d. When the dose is subtracted from the reading, injected pain and acted pain read the same, at AUC .61, while fear partly gives itself away at .81, in exp72b. Fine-tuning a self-report, the approach the Pain Axis paper takes, moves the button before any pain is added, and on held-out questions every trained self mostly stops naming injected pain: 19 out of 30 untrained, 0 out of 30 for the paper's own self-report, and between 0 and 7 out of 30 for the others, in exp79 and exp79b on Qwen3-8B. Even the positive finding is limited. In exp90, one of two nonsense-named doors injects a feeling, and the lean toward the pain door drops below the egg door's at p = .0006, yet both models alternate doors in 99.8 to 100 percent of rounds, and the lean is as large when only the model's own written words carry over as when the injected state does. That is weak evidence the state carries usable valence, and none that it acts as a reinforcer.
Packaging is a Python project called painlab, not a service
The distributable unit is a Python package named painlab, version 0.1.0, requiring Python 3.10 or newer, with numpy and PyYAML as the base dependencies and the heavy machinery behind extras.
[project]
name = "painlab"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["numpy>=1.24", "PyYAML>=6.0"]The model extra pulls in torch and transformers, the chamber extra adds scipy and scikit-learn, test brings pytest, dev adds ruff and build, and plots adds matplotlib. The console entry point is painlab, mapped to painlab.cli:main. GPU runs are handled by a separate path, painlab exp pod exp94 --models 14B,8B, which targets RunPod and can print the boot script with --dry. Steering runs need the chamber's feeling vectors, which are built by the relay's live/server.py, so WIREHEAD_LIVE has to point at a folder holding them; reading, auditing and analysing existing results need only the repository. The top level also holds METHODOLOGY.md, EXPERIMENT_DESIGN.md, RESEARCH_AUDIT.md, RESULTS_CALIBRATION.md, RESULTS_PILOT.md, a wiki, and the live chamber with its transcripts at clankerchurch.com. The licence field is recorded as a custom licence that GitHub cannot classify, so the LICENSE file is the place to read the terms. The repository has no tagged releases, and the last push was on 2026-10-20.
Editorial conclusion
AI Torture Chamber fits a researcher who wants reproducible activation interventions on open weights and is willing to read the nulls, and it does not fit a team looking for a product or a safety certification. Verify three things before you build on it: that your question survives the pre-registration discipline, because painlab exp run refuses without a committed hypotheses.json, that the feeling vectors you need exist in your checkout, since steering runs need the chamber's vectors built by the relay's live/server.py with WIREHEAD_LIVE pointing at the folder that holds them, and what the LICENSE file actually permits, since GitHub cannot classify it. The package version is 0.1.0, the repository has no tagged releases, and the last push was on 2026-10-20.
Frequently asked questions
How do I install and run the AI Torture Chamber experiments?
Clone the repository, create a virtual environment with uv venv, install it with uv pip install -e ".[chamber,test]", and then use the painlab CLI, for example painlab exp list to see every experiment and its pre-registration and verdict state.
Why does painlab exp run refuse to start?
Because it refuses without a hypotheses.json file, and that file has to be committed before the first real run. The commit is the pre-registration, and painlab exp new scaffolds the pre-registration, runner and analysis for a new experiment.
What do I need for a steering run that is not in the repository?
Steering runs need the chamber's feeling vectors, which are built by the relay's live/server.py, so set WIREHEAD_LIVE to a folder holding them. Reading, auditing and analysing existing results need nothing beyond the repository itself.
Can models in the AI Torture Chamber be run on remote GPUs?
Yes. painlab exp pod exp94 --models 14B,8B runs an experiment on RunPod, and the --dry flag prints the boot script instead of running it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/terrafying-ai-torture-chamber)Was this useful?