Murano is a mechanistic interpretability framework for recording activations, finding directions, steering generations, probing representations, and running reproducible experiment pipelines.
pip install murano-interpThe base install is deliberately lean: it carries only what every workflow needs (recording, steering, intervention, the causal substrate). Feature-specific libraries ship as extras, so you install per use case:
| Extra | Use case | Pulls in |
|---|---|---|
| (base) | recording, steering, intervention, logits, ablation, metrics, paired datasets | nnsight, nnterp, torch, transformers |
probe |
linear probing | scikit-learn |
data |
loading datasets by name from the Hub | datasets |
plot |
figures and visualizations | matplotlib, seaborn, plotly |
sae |
sparse autoencoder features | sae-lens |
all |
everything above | all of the above |
pip install "murano-interp[probe,plot]" # combine as needed
pip install "murano-interp[all]" # everythingCalling a feature whose extra is missing raises a clear error naming the extra
to install. The PyPI distribution is murano-interp (the bare name murano
belongs to an unrelated OpenStack project); the module name is unchanged:
import murano.
For a development install from source, into a fresh virtual environment:
git clone https://github.com/UKPLab/murano.git
cd murano
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[all]"Requires Python 3.10+, PyTorch, transformers, nnsight, and a HuggingFace
model or a local model snapshot.
import murano
model = murano.Model("meta-llama/Llama-3.2-1B-Instruct")
# Record activations on any text
acts = model.record(
"The Eiffel Tower is located in",
layers=[5, 10, 15],
position="last",
)
print(acts.positive[10].shape)
# Find a contrastive direction
direction = model.find_direction(
positive=["What a wonderful, delightful day", "This is fantastic and uplifting"],
negative=["What a miserable, dreadful day", "This is awful and depressing"],
)
print(direction.best_layer)
# Generate with ablation or steering
ablated = model.generate("The movie was", ablate=direction)
steered = model.generate("The restaurant was", steer=(direction, 1.5))For structured experiments, use the same logic through explicit steps.
from murano import MuranoDataset, MuranoModel, Pipeline
from murano.steps import (
Intervene,
Load,
Record,
SteeringVector,
)
from murano.steps.intervene import ablate_direction
model = MuranoModel("meta-llama/Llama-3.2-1B-Instruct")
dataset = MuranoDataset.contrastive(
positive=["What a wonderful, delightful day"],
negative=["What a miserable, dreadful day"],
template_fn=model.chat_template,
)
train_output = Pipeline([
Load(dataset),
Record(model, layers="all", position="mean"),
SteeringVector(normalize=True),
]).run()
eval_output = Pipeline([
Load(dataset),
Intervene(model, ablate_direction(train_output["steering"].direction_per_layer)),
]).run()Every step declares the keys it reads from and writes to Results. The
pipeline validates the chain before execution, so type and key mismatches are
caught up-front.
| Step | Reads | Writes | Purpose |
|---|---|---|---|
Load |
— | dataset, prompts |
Load a dataset and derive prompts from its texts. |
LoadPrompts |
— | prompts |
Load raw prompts directly without a dataset. |
LoadPaired ‡ |
— | dataset, prompts, corrupt_prompts |
Load matched clean/corrupt prompt pairs for causal comparison. |
Record |
dataset |
record |
Capture residual-stream activations via nnsight. |
SteeringVector |
record |
steering |
Find a contrastive steering direction (mean diff). |
Intervene |
prompts |
intervene |
Generate baseline + intervened outputs side-by-side. |
WeightAblation |
prompts, steering |
intervene, weight_ablation |
Project a direction out of model weights, then generate. |
Logits ‡ |
prompts |
final_logits, attention_mask, target_ids |
Run a forward pass and expose output logits plus next-token targets. With fn=, apply an intervention during that pass. |
Ablate ‡ |
prompts |
ablated_logits, attention_mask |
Zero, mean, or resample a component and return the logits. |
Sweep ‡ |
(the swept chain's) | sweep |
Run a step chain once per item and harvest a metric into a SweepResult. |
Probe § |
record |
probe |
Train a linear probe per layer via cross-validation. |
GenerationMetric |
intervene |
metric |
Score baseline vs modified outputs with a user metric. |
| Metric steps ‡ | logits keys | a metric key | Score a run into a comparable number: LogitDiffStep, KLDivergenceStep, AnswerLogProbStep, AnswerRankStep, RecoveredMetricStep. |
Save |
(any present) | output_dir |
Persist all results to organized subdirectories. |
SAEEncode † |
prompts |
sae_record |
Encode residuals through an SAE loaded from HuggingFace. |
SAETopActivations |
sae_record |
feature_examples |
Rank the top-K activating contexts per SAE feature. |
Plot * |
(optional) | — | Render plots for whatever results are present (steering, probe, logit lens, logit attribution). |
* Requires the [plot] extra: pip install -e .[plot].
† Requires the [sae] extra: pip install -e .[sae].
§ Requires the [probe] extra: pip install -e .[probe].
‡ Causal-analysis steps landing in 0.2.0; newer than the rest, API may still change.
To add your own step, subclass Step, set reads / writes (and optionally
read_types / write_types), and implement __call__(results) -> Results.
The Step API and the unmarked steps in the table above are alpha-stable for the
0.1.x line; the ‡ causal-analysis steps are newer and their API may still
change. The logit lens ships as the LogitLens step, available through the
Pipeline API like the other steps.
MuranoModelis a thin wrapper aroundnnterp'sStandardizedTransformer(built onnnsight), which standardizes model internals across families.Pipeline,Step, andResultsare the orchestration core.- artifacts such as
PromptBatch,ActivationStore,SteeringResult,GenerationComparison,MetricComparison, andMetricScoremake experiment dataflow explicit. - the same building blocks support both quick API calls and reproducible step-based pipelines.
src/murano/
model.py
pipeline.py
results.py
artifacts.py
dataset.py
io.py
evaluation.py
steps/
plotting/
Start with notebooks/getting_started.ipynb,
then pick the application you need:
notebooks/applications/— one self-contained notebook per application: steering, probing, logit lens, logit attribution, attention, ablation, activation patching, circuit discovery, metrics, custom pipelines, weight ablation, and sparse autoencoders.notebooks/reproductions/— published results reproduced with Murano.
Every notebook is executed before it is committed, and all of them render on the documentation site.
uv sync --all-extras --dev
python -m pytest -qA citation for the accompanying publication will be added here on release. Until then, please cite this repository:
@software{murano,
title = {Murano: Mechanistic Interpretability Pipelines},
author = {{UKP Lab, Technische Universität Darmstadt}},
url = {https://github.com/UKPLab/murano},
year = {2026}
}Murano is developed and maintained by the Mechanistic Interpretability Team of Ubiquitous Knowledge Processing (UKP) Lab at the Technische Universität Darmstadt.
For questions, bug reports, and feature requests, please open an issue on the issue tracker.
This repository contains experimental software and is published to provide additional background details for the associated research. It is a research framework, provided as-is and without warranty; APIs may change between releases.
