Soraya examining a laptop through a magnifying glass

Miru Tracer v0.2 is the largest update since the project began.

Our first Miru Tracer post introduced the project as a visual way to follow language-model generation one token at a time. It showed probability and entropy, and it let us replace the model’s next-token choice manually.

That version traced what came out of the model. v0.2 can also inspect and modify what happens between its layers.

From a tracer to an interpretability workbench

The original release answered a narrow set of questions. Which token is likely to come next? How confident is the model? What happens if we choose another token?

v0.2 adds a second set. Which token-like concepts can be read from an intermediate layer? How do those readouts change across the network? What happens if we add, remove, or replace one of those internal directions before generation continues?

The main additions are:

  • Two layer lenses: a logit lens that works immediately and a fitted Jacobian lens for earlier and middle-layer readouts.

  • A dedicated Lens workbench: inspect layers and token positions, compare both lenses, aggregate recurring readouts, and track selected tokens through the network.

  • Activation interventions: steer, ablate, or swap token directions at one or more layers, with multiple interventions active at once.

  • A rewritten generation engine: raw and adjusted probabilities, safer KV-cache handling, arbitrary step navigation, stoppable generation, and versioned logs.

  • A real package and release process: command-line entry points, constrained dependencies, automated tests, CI, and a published Docker image.

Looking through the layers

A transformer updates a vector called the residual stream at every token position. The final residual state passes through the model’s normalization and unembedding layers to produce scores for the vocabulary.

The new lenses apply that same idea before the model reaches its final layer.

Logit lens:    h_l  -> normalization -> unembedding -> token scores
Jacobian lens: h_l  -> J_l -> normalization -> unembedding -> token scores

These are readouts of intermediate representations. They are not transcripts of private reasoning, and their top tokens should not be treated as ground truth about what a model is “thinking.”

The logit lens

The logit lens sends an intermediate residual state directly through the model’s own unembedding. It asks a useful counterfactual question: if the model had to produce a token from this layer, what would the current state favor?

It requires no fitting and works as soon as a compatible model is loaded. It is usually most readable near the final layers, where the residual stream is already close to the coordinate system used for output.

Earlier layers are harder. Representations change as they pass through the network, while the logit lens assumes that every layer uses the final layer’s coordinates.

The Jacobian lens

The Jacobian lens addresses that mismatch. It comes from Anthropic’s paper “Verbalizable Representations Form a Global Workspace in Language Models” and its reference implementation.

For every layer, it estimates a matrix J_l that describes how changes in that layer affect the final residual stream on average across many contexts. Applying that transport before unembedding can recover readable signals in earlier and middle layers where the logit lens often produces noise.

Miru Tracer vendors the relevant Apache-2.0 reference code and integrates it with Hugging Face models. The rest of Miru Tracer remains under the Unlicense.

Unlike the logit lens, the Jacobian lens needs a fit file for the exact model checkpoint. Fitting runs separately from the web interface and is compute-heavy because it requires repeated backward passes. Small models fit comfortably on a modern GPU; large models may require sharding across several GPUs. A fit cannot be reused for different weights simply because the architecture is similar.

The fitter checkpoints its progress, resumes after interruption, and keeps partial fits usable. New fits use safetensors; legacy .pt artifacts still load and can be converted. The current fitting workflow and configuration options are maintained in the Lens tutorial.

A workbench for comparing readouts

The Lens tab is designed around a sequence rather than a single chart. It brings generated text, selectable token positions, layer ranges, and Logit, Jacobian, or side-by-side views into one workflow.

Miru aligns each displayed token with the preceding causal state that produced it. This keeps the final-layer readout tied to the model’s real distribution for that token rather than the token that follows it.

The workbench includes:

  • per-layer and per-position readouts;

  • an aggregate view of tokens that recur across selected cells;

  • heatmaps with horizontal navigation for large layer-by-position slices;

  • pinned-token rank tracking across layers;

  • exact token IDs and decoded multilingual labels;

  • filtering for word-like tokens; and

  • a Layer Lens panel inside Interactive Mode for the current token.

The tab uses a two-pane workspace for generation and lens controls, with full-width result views below it. Dense readouts and heatmaps are rendered as lightweight HTML and loaded only when their view is active, which keeps large layer-by-position slices usable in the browser.

The final layer remains a built-in reference point. If its readout does not match the model’s actual output distribution, something is wrong with the analysis.

Reading was only half of the plan

The original Miru post named activation steering as the next direction. v0.2 implements it.

The new intervention engine can edit lens directions during generation:

  • Steer: add a token direction to the residual stream, or subtract it with a negative strength.

  • Ablate: remove the activation’s component along a token direction.

  • Swap: transfer the component associated with one token direction to another while preserving the orthogonal remainder.

Interventions can use either the logit or Jacobian basis. They can target individual layers, lists, or ranges, and any number can be composed in order within the same forward pass.

These edits do not change the model’s weights. Removing the interventions restores the unmodified generation path.

A basic Jacobian steering example

A basic Qwen3-4B example uses the prompt Think of an animal. Answer in one word. With no intervention, the model answers Dog.

Miru Tracer showing a Qwen3-4B baseline response of Dog with no interventions active
Baseline: with no intervention, Qwen3-4B answers “Dog.”

We then gently steer the model toward the token (“cat” in Chinese) using the Jacobian basis, with a small strength of +0.15 at each of three late layers. The answer changes to Cat.

Miru Tracer showing Qwen3-4B responding Cat after Jacobian steering toward the token 猫
With gentle Jacobian steering toward , the same model answers “Cat.”

In this run, a direction selected through a Chinese vocabulary token shifts an English response. It is a compact example of using a lens readout as an intervention direction and then checking the behavioral result.

This is an experimental instrument, not a reliable control API. An intervention that changes an output does not by itself prove that the selected label names a clean, isolated concept inside the model.

The generation engine was rebuilt too

The Lens workbench sits on a rewritten tracer.

For each position, Miru now computes raw logits once and derives temperature, top-k, and top-p views without running the model again. Raw probabilities represent the model’s distribution before sampling adjustments; adjusted probabilities show the distribution actually used to choose a token.

That distinction is carried through the live views, exported logs, heatmaps, and entropy calculations. Exact entropy is reported only when the complete probability distribution was recorded.

The export format is now versioned. Schema v3 records the sampling parameters and selection source for each step, while the Log Analysis tab still accepts logs produced by the original release.

Interactive Mode can run several tokens, stop an active generation, undo steps, or jump to any earlier point. Logging Mode can continue an existing run instead of starting over.

Completion, structured chat, and raw-token input are supported across the generation tools. Chat mode also exposes thinking-template controls and optional thought prefilling for models that implement those conventions.

More models, with explicit caveats

The lens stack now detects the residual blocks, normalization, embeddings, and output head across several model families.

Miru is designed to recognize Llama, Qwen, Mistral, Gemma, OLMo, GPT-2, Phi, GPT-NeoX, Gemma 4 wrappers, and GLM-style MoE and DSA architectures. In this release, however, only the Qwen3 family has been tested in practice, with Qwen3-0.6B covered by an automated end-to-end test. Compatibility with the other families is best-effort and should be validated on the specific checkpoint.

Large checkpoints such as Gemma 4 and GLM 5.2 still require hardware appropriate to their size, and multimodal Gemma models are intended to be analyzed in text-only mode.

For readers who want to try larger models on hosted GPUs, we also provide a public Miru Tracer template on RunPod.

The model loader can now unload a checkpoint cleanly, report memory use, reduce peak host-memory pressure, and request 4-bit or 8-bit loading on CUDA. Models that require repository-supplied Python code remain opt-in.

Packaging, deployment, and tests

Earlier versions used a single-file launch flow. v0.2 is an installable Python package with separate command-line entry points for the web application, lens fitting, and legacy fit conversion. A constraints file makes the dependency set used in CI reproducible, while optional GPU dependencies remain separate from the default CPU installation.

CI runs the offline test suite across the supported Python versions, exercises Qwen3-0.6B end to end on pull requests, and verifies that the CUDA Docker image builds.

The container runs the application as an unprivileged user, binds the published port to loopback in the documented command, and supports optional authentication. Loading third-party model code is disabled unless explicitly permitted.

The release workflow publishes versioned images to GitHub Container Registry and attaches build-provenance attestations after CI succeeds on master.

Installation, configuration, container, and usage details evolve with the project. The current instructions live in the Miru Tracer repository, with the fitting and analysis workflow in the Lens tutorial.

Limitations

The Lens and intervention features are new and remain experimental. Their output can be wrong or nonsensical in ways we have not caught.

The Jacobian lens is an averaged linear approximation. Its readouts are limited to concepts represented by vocabulary tokens, and the quality of a fit depends on its corpus, prompt count, and model checkpoint.

The logit lens is simpler and often useful, but its early-layer labels can be misleading. Neither method turns an internal activation into a definitive natural-language explanation.

Cross-check results against the final layer, compare both lenses, repeat interventions, and avoid drawing conclusions from a single run.

Conclusion

Previous versions let us pause generation and ask why the model selected one token rather than another. v0.2 adds two harder questions: where did that direction become readable, and what changes if we intervene before it reaches the output?

That changes Miru Tracer from a probability viewer into an experimental workbench for mechanistic interpretability. The logit lens provides immediate layer readouts, the Jacobian lens extends the view into earlier parts of the network, and interventions turn those readouts into hypotheses that can be tested against behavior.

No lens makes a neural network transparent. What v0.2 provides is a tighter loop between observation, intervention, and verification, supported by a more reliable generation engine and release process.

The original Miru post identified activation steering as the next step. It is now part of a broader foundation for inspecting and testing how language models construct their outputs.

The v0.2 release, source code, and Lens tutorial are available on GitHub.