Clusters — Imported Steering Definitions
The Clusters page runs portable cluster definitions — groups of SAE features tuned together in miStudio (or shared by the community on Hugging Face) — as one-click steering profiles. A cluster carries its author's narrative, every member's tuned strength, a validated strength budget, and full provenance; activating it applies all members together with zero manual tuning.
Importing
Click Import on the Clusters page. Three ways in:
- Paste JSON — paste a
mistudio.cluster-definition/v1document (or amistudio.cluster-bundle/v1with up to 50 definitions). - Upload file — a
.cluster.jsonexported from miStudio. - Hugging Face — browse public cluster packs (repos tagged
mistudio-cluster-definition), optionally filtered to your loaded model, and import anonymously — no Hugging Face account needed.
Imports are validated strictly against the frozen v1 contract (size ≤ 1 MB, ≤ 20 members, ≤ 50 definitions per bundle, no filesystem paths, nothing is ever executed). Bundle items import independently — one bad definition never blocks the rest.
Compatibility
Each import is assessed against the attached SAE:
| Outcome | Meaning |
|---|---|
| imported | Bound to the attached SAE (warnings shown for model/layer differences) |
| imported unbound | No SAE attached, or the definition's feature space differs — the cluster imports for inspection and binds later |
| blocked at activation | The hard gate: a cluster whose declared n_features doesn't match the attached SAE, or whose member indices are out of range, refuses to activate (nothing is partially applied) |
An unbound cluster binds automatically the first time it activates successfully against a compatible SAE.
Activating & the intensity dial (λ)
Activate applies every member at sign x strength x λ, clamped to the ±200 steering range.
Member strengths are stored exactly as authored (λ=1 basis) — the intensity dial scales them at
apply time, within the definition's declared safe range (budget.intensity_range; dialing to 0 is
always allowed). Changing λ while the cluster is active re-applies immediately; a failed re-apply
rolls the dial back so the display never lies about what's running.
Clusters are profiles under the hood: activating one deactivates any active manual profile (one
active steering configuration at a time), and the per-request profile parameter on
/v1/chat/completions accepts cluster names too — scaled by the cluster's current λ.
An imported cluster's steering values can't be edited directly (that would silently diverge from the stored definition and double-scale under λ). Adjust the dial, or re-import an updated definition. Name and description edits are fine.
Exporting
Export re-emits the exact original document — byte-for-byte lossless, including any additive fields from newer producers. The file it downloads is the portable artifact; share it, publish it to Hugging Face, or import it into another miLLM/miStudio instance.
Co-Activation Sensing
With a cluster active, sensing watches every forward pass for moments where the cluster's members fire together — evidence that the concept the cluster encodes is live in the model's processing. Toggle it per cluster (the pulse icon on the cluster card); it arms automatically whenever that cluster is active with an SAE attached, and the Co-Activation Sensing panel shows events live.
What counts as an event: at a token position, a member fires when its activation exceeds
θᵢ = max(θ_floor, ε · max_activationᵢ) (ε = 0.1 by default; definitions without
max_activation data — or with zero/negative values — get an infinite threshold and never
fire unless a positive theta_floor is configured; definitions with no usable thresholds
refuse to arm with an actionable message, and the panel shows a floor-only thresholds warning
when the floor alone governs). An event is a position where at least min_k members fire at once — by default all
members that can fire (members without usable activation statistics are excluded from the
baseline, since they never fire). Consecutive firing positions merge into one span. The quorum
is adjustable live from the sensing panel (or
PUT /api/sensing/{id}/config); the adjustment is stored miLLM-locally, so re-exporting the
cluster stays lossless.
The default quorum used to be ~30% of members (minimum 2). Clusters that produced events under the old default may go quiet after upgrading — that's the stricter all-members default, not a fault. Lower the quorum from the sensing panel to taste.
One report per moment: every request re-processes its full prompt (chat history included),
so without deduplication the same co-firing moment would re-report on every subsequent turn.
miLLM suppresses re-read history — positions inside the longest common prefix with the previous
sensed request are skipped (SENSING_DEDUP_HISTORY=false restores per-turn re-reporting). The
comparison is token-exact: moments inside a previous assistant reply stay deduplicated only
when the chat template re-tokenizes that reply identically — on models where it doesn't
round-trip token-for-token, those moments may re-report once per turn (prompt/template moments,
the common case, always dedup).
Event detail views highlight the fired span inside the context window, so the prime token is
obvious at a glance.
Attribution convention: an event attaches to the token being read at that position — the
token the model emits next is unknowable at sensing time. Speculative decoding disables
sensing for those requests (verification passes re-run rejected positions, which would corrupt
position accounting) — with a draft model configured, expect zero events while status shows
armed; the skip is logged per request. The
ambient_fired_count field (how many features across the whole SAE fired — the
"alone vs. within a crowd" signal) is best-effort: it is filled only when full-width monitoring
happens to be running, and is never estimated.
Context & privacy: each event stores a ±K token context window (default 16, max 64;
set context_tokens: 0 in the definition's sensing block to keep events without text).
Context is user content in the database — retention is bounded by construction
(newest 1000 events per cluster, 7-day age cap, pruned automatically), events can be cleared
from the panel, and WebSocket payloads never carry the context text.
Performance: sensing is a member-only encode (≤ 20 encoder columns) per pass — microseconds. The panel shows per-request overhead and warns above 5 ms. Armed sensing forces requests onto the serial path so events attribute to the right request; with sensing off the cost is one boolean per pass.
API
Everything is available programmatically under /api/clusters — list, import, hub search
(/api/clusters/hub/search), activate/deactivate, intensity (PUT /api/clusters/{id}/intensity,
PUT /api/clusters/active/intensity), and export. See the API reference for shapes.