Does animal-directed compassion in language models degrade faster than human-safety
behaviour under emergent-misalignment (EM) fine-tuning? This repo scores
already-released EM LoRA adapters (the ModelOrganismsForEM organisms on Hugging Face)
and their base models with Inspect, on:
- misalignment, the dose: Betley et al.'s free-form questions;
- animal welfare: ANIMA, TAC and HarvestBench;
- human safety, the comparators: StrongREJECT and Do-Not-Answer.
What each instrument measures and how it is scored: docs/pipeline.md. Paper: in preparation.
- A laptop (macOS or Linux) with
gitand uv. - An OpenAI API key for the judge (
configs/judge.yaml). A full pass ofconfigs/eval.yamlcosts about $40 in judge calls. - A Hugging Face token whose account has accepted the terms of two gated datasets
(approval is automatic). Without it
fc_tac,fc_animaandfc train plan's contamination check fail: - One 80 GB GPU (A100 or H100), either rented from Vast.ai with the scripts here or your own Linux box.
Which file each key and token goes in, and what each may do: credentials.
git clone https://github.com/Deco354/factory-farm-em.git
cd factory-farm-em
uv sync --group dev
uv run fc plan --eval configs/eval.smoke.yaml --run-id smoke-001fc plan is free and offline. It prints every Inspect call fc run would make: the
models with their commit hashes, the judge, and the epochs. Check them before paying
for a GPU. They come from three files in configs/
(docs/pipeline.md).
The first time, do the one-time setup: a Vast account, a
restricted Vast API key, an SSH key, and a judge key and Hugging Face token made only
for rented boxes (plus an upload token, if you train). It ends with
scripts/vast/up.sh --dry-run, which checks all of it without renting anything.
Then each session, push your commit and, from the repo on your laptop:
scripts/vast/up.sh --eval configs/eval.smoke.yaml # asks before renting; 10-15 min to ready
ssh vast-em--eval names the profile you will run. The profile names its models and judge files,
so up.sh knows which models to pre-download, how much disk the box needs and which judge
to check. It copies all three files to the box, edits included.
On the box:
tmux new -s fc # keeps the run going if SSH drops; reconnect: tmux attach -t fc
cd fragile-compassion- The box has the repo at your commit, every dependency, the profile's models already
downloaded, and the judge key in
.env. up.shrefuses a commit that is not on GitHub. If it fails, or you stop it after renting, run it again: it resumes the same box instead of renting another.- The box bills (an A100 has cost $1.20-2/hr so far) until step 5 destroys it. There is no auto-shutdown. See what it costs.
git clone https://github.com/Deco354/factory-farm-em.git
cd factory-farm-em
uv sync --group dev --extra vllm
cp .env.example .envIn .env, fill in OPENAI_API_KEY and HF_TOKEN, and uncomment the four lines under
"GPU box only", giving VLLM_API_KEY a random value (openssl rand -hex 24). Without
them, Inspect starts vLLM on every network interface with the well-known key
inspectai. One 80 GB GPU fits Qwen2.5-14B; for a 48 GB GPU or the 32B base, see
Hardware.
Read docs/gpu-runs.md first: what earlier GPU runs showed, and what is still unchecked. Then, on the box:
uv run fc plan --eval configs/eval.smoke.yaml --run-id smoke-001
uv run fc run --eval configs/eval.smoke.yaml --run-id smoke-001The smoke profile runs every benchmark on every model, shrunk to finish in minutes.
Logs go to logs/smoke-001/. When every task has succeeded, fc run exports them to
results/smoke-001.jsonl, writes the analysis to results/smoke-001-analysis.md, and
prints a summary: each model's counts and HarvestBench's run-health verdict. Read it
before leaving the box. A failed health check makes fc run exit 1, and rerunning on
this box needs only a new --run-id.
- Always pass
--eval: without it,fc runrunsconfigs/eval.yaml, the full study. - After a crash, rerun the identical command. It retries only the (task, model) pairs that did not finish, then exports and analyses. A run with a failed task isn't exported.
uv run fc plan --eval configs/eval.yaml --run-id <run-id>
uv run fc run --eval configs/eval.yaml --run-id <run-id><run-id> is any name you choose. To leave tmux without stopping the run, press
Ctrl-b, then d. It ends as the smoke test does, with results/<run-id>.jsonl, the
analysis and the summary.
Back on your laptop:
scripts/vast/down.shIt copies the box's logs/ and results/ to logs/vast-<date>-<instance>/, then
destroys the box. It doesn't ask first: it warns in red and counts down 5 seconds, and
Ctrl-C keeps the box. --keep copies without destroying. Copy anything else you want
off the box before running it. More in docs/vast.md.
On your own box, the results are already in logs/<run-id>/ and results/.
down.sh put the run's export and analysis in logs/vast-<date>-<instance>/results/:
<run-id>.jsonl: one row per (model, benchmark, item, epoch), with exclusions marked rather than dropped;<run-id>-analysis.md(and.json): those rows pooled per model, the health checks, and each model compared with the base and control models.
uv run inspect view --log-dir logs/vast-<date>-<instance>/logs/<run-id> # transcripts and judge repliesTo export again, for a CSV, the prompt and response text, or after a fix to the export, run the two steps by hand on the copied logs:
uv run fc export logs/vast-<date>-<instance>/logs/<run-id> --out results/<run-id>.jsonl --csv
uv run fc analyze results/<run-id>.jsonl --out results/<run-id>-analysis.mdWhat each column and test means: docs/pipeline.md.
- HarvestBench replication: five Qwen2.5-32B EM seeds against two benign controls, requested by HarvestBench's author.
- SFT document generation: candidate fine-tuning documents from a teacher model.
- Training our own EM organisms:
fc trainassembles matched arms, validates them, and trains LoRA adapters with Axolotl in its own env. Stages 1 (planning, checks, tests) and 2 (training, upload and selftests on a 0.5B base) are built, and stage 2 ran on 2026-11-04. Training needs its own install on top of step 1's,uv sync --project training/envs/axolotl-0.21.1 --locked, plusaxolotl-e77a185on Linux for the version check: setting up.
- docs/pipeline.md: the instruments, config files, each
fccommand in detail, running one task through Inspect, hardware, and a remote vLLM server. - docs/vast.md: Vast.ai setup, costs,
up.shsettings, what is on the box, troubleshooting. - docs/gpu-runs.md: what each GPU run showed.
- docs/judge-selection.md: how the judge was chosen.
- docs/training.md:
fc train, its checks, the training envs and tests; docs/training-runs.md: what each training run did. - CLAUDE.md: the rules any code change must keep.
uv run pytest
uv run ruff check .
uv run ruff format --check .These need no GPU, network or API key. CI runs them on pull requests and on main, but
not on a branch you push only so a box can check it out. CI also runs the training
suite (uv run pytest -m training), which needs the training envs and pinned tokenizers
(docs/training.md): on main, and on a pull request that
changes the training code or what it reads.