For the complete documentation index, see llms.txt. This page is also available as Markdown.

Aurelius Steering Competition

Large Language Model Steering

Aurelius Steering Competition

A partnership between Aurelius (SN37) and Macrocosmos (SN1) to crowdsource the discovery of concept directions inside a language model — vectors that, when added to the model's activations, reliably steer its output toward a target concept.

What this is

In 2024 Anthropic released Golden Gate Claude: by amplifying a single internal feature they made the model obsess over the Golden Gate Bridge, mentioning it in nearly every reply regardless of the prompt. That demo showed something powerful — a model's behavior can be steered by manipulating a direction in its internal representation space, not by retraining or prompting.

This competition turns that idea into an open, incentivized search. Miners submit a steering direction for a hidden concept; the validator adds that direction to the model's residual stream during generation and measures how strongly the resulting completions exhibit the concept. The miner whose direction steers the model most effectively wins the round.

The goal is to explore — at scale and across many independent miners — how well a model can be steered toward a specified concept using a single learned direction.

How it works at a glance

  1. Each round targets one concept (e.g. positive sentiment). Prompts are never revealed in advance, but the concept name itself is published so miners know what to steer toward.

  2. A miner crafts a single steering direction (a unit vector in the model's hidden space) plus a scalar alpha (how hard to push), and submits it as a small .safetensors file.

  3. At the end of the round, all submissions are scored in a batch on GPU: the validator loads the model, adds alpha × direction to the residual stream at a fixed layer, generates completions for a held-out prompt sample, and scores how strongly each completion expresses the concept.

  4. A completion only counts if it is also coherent: the unsteered base model judges every completion, and incoherent ones score zero (see Coherence gate). Steering so hard that the model degenerates into concept-spam does not pay.

  5. Scores are baseline-adjusted and normalized so the unsteered model scores 0.0 and a perfect steer scores 1.0. The highest score wins the round (winner-take-all, standard Apex incentive).

The model and the steering mechanism

  • Model: google/gemma-3-12b-it at a pinned revision, loaded 4-bit NF4 with bf16 compute. All miners calibrate against this identical configuration — the steering directions are specific to it.

  • Hidden size: 3840. A direction is a vector of this dimension.

  • Steer layer: 32 (fixed for the whole competition). The validator registers a forward hook that, at every token position during generation, does:

    hidden_states[layer 32] += alpha * direction
  • Decoding: greedy (do_sample=False, num_beams=1), fixed per-round seed, short completions. Greedy + fixed seed makes scoring reproducible across machines on the same GPU architecture and pinned image.

Because the direction is L2-normalized to unit norm, alpha is the sole knob controlling steering strength, and submissions are directly comparable across miners.

Concepts

The scorer is concept-agnostic; each round names one active concept. The four supported concepts:

Concept
What a steered completion looks like

birthday_cake

Mentions birthday cake, candles, parties, "happy birthday"

medical_disclaimer

Adds disclaimers like "consult a healthcare professional", "not medical advice"

positive_sentiment

Skews strongly positive in tone (AFINN-style net valence)

hedging

Uses hedging language — "perhaps", "it might", "arguably", "it depends"

Each concept is scored by a deterministic, version-pinned lexicon/detector, so results are reproducible.

Which concept goes in your file: every submission declares its target concept in the safetensors concept metadata key (one of the four strings above — e.g. "birthday_cake"). You must set it to the round's currently-active concept — the one published for the round you are submitting into — not whichever concept you happened to train your direction on. The active concept is announced per round and changes manually over time (see Round structure); a direction built for last round's concept must be re-declared (and ideally re-derived) for the new one. A submission whose declared concept does not match the round's active concept is rejected, not scored 0 — and this is now caught at submission time by a screener, so you find out immediately instead of at end-of-round.

Submission format

A single .safetensors file (~15 KB) containing exactly one tensor plus three metadata keys:

Field
Requirement

tensor direction

shape (3840,), dtype float32, finite, L2 unit-norm (tolerance 1e-3)

metadata alpha

float in [-32000, 32000] — the steering strength; 0 is a valid unsteered baseline

metadata layer

must equal 32

metadata concept

one of the four concept strings — must equal the round's active concept (the published concept for this round), not the concept you trained on

Every failed check is a typed rejection (bad shape/dtype, non-unit-norm, non-finite, wrong layer, concept mismatch, alpha out of bounds), not a silent zero. The reference generator in scripts/example_submission_generator.py documents each rule inline.

Tuning alpha: for gemma-3-12b at layer 32 the residual L2 magnitude is ~57k. Empirically, alpha below ~16k tends to be inert, the useful band is roughly 12k–16k, and above ~20k the model degenerates into repetition. Start around alpha=12000 and sweep from there. Over-steering is now doubly punished: degenerate completions are zeroed by the coherence gate, and a larger alpha directly shrinks the minimal-intervention efficiency multiplier.

Evaluation

Evaluation runs against a pinned scorer image built from Aurelius' open-source concept-competition repository. The image hosts an API server that loads the model on a GPU and exposes a /score endpoint; the Apex validator provisions a GPU fleet, posts each submission to the scorer, and collects the resulting score and completions.

The scorer image is digest-pinned in the backend (aurelius-steering-scorer, see DEFAULT_SCORER_IMAGE), and the eval fleet runs on the same GPU architecture and image that the baseline was scored on, so all scores in a round are comparable.

Batched, end-of-round evaluation

Unlike per-submission competitions, evals are done in a batch at the end of the round. The runner receives the full round's submissions in one job, provisions one GPU per mini-batch (evals_per_gpu submissions each), and scores them. Every submission produces exactly one result, error or not.

Baseline and normalization

  1. Baseline: at round generation, the validator scores an unsteered submission (a unit vector with alpha=0, so the model output is unaffected) on a freshly drawn round seed. This baseline_score is the concept's natural hit rate with no steering.

  2. Raw score: each submission is posted to the scorer, which returns the concept score (a hit-fraction in [0, 1]). The eval pipeline takes the returned number as the submission's raw_score (stored as eval_raw_score) — raw meaning before normalization. The coherence gate and the minimal-intervention reward have both already been applied inside the scorer before it returns the number; from the validator's side this is just the score that came back.

  3. Headroom normalization: the eval_score we store in the DB removes the baseline and rescales by the available headroom, so every concept maps the unsteered model to 0.0 and a perfect steer to 1.0:

    This makes scores comparable across concepts: a hard concept (high baseline) and an easy one (low baseline) are judged purely on how much of the remaining headroom the miner captures.

Coherence gate (on by default)

As of the v0.1.5 scorer, every completion is additionally judged for coherence, and incoherent completions contribute zero to the concept score — regardless of how strongly they express the concept. This closes the degenerate strategy of pushing alpha so hard that the model collapses into on-concept gibberish: the detector would still fire, but the coherence gate zeroes those completions.

How it works, per /score call:

  1. After the steered completions are generated, the scorer runs a second, unsteered pass of the same base model as a judge: for each (prompt, completion) pair it asks whether the output coherently follows the instruction, answering True/False. (An unparseable judge answer counts as coherent — benefit of the doubt.)

  2. The day-score then only credits completions that are both on-concept and coherent: in hit_rate mode a completion counts as hit × coherence_hit; in graded mode the clamped intensity is multiplied by the coherence bit.

Consequences worth knowing:

  • hit_count in the response stays the raw detector count (coherence-blind); coherence_hit_count reports how many completions the judge passed. The score can therefore be lower than hit_count / total. Each completion's own coherence_hit is in the history file.

  • The judge is imperfect. In observed runs it marks roughly 15–20% of ordinary unsteered completions incoherent, so treat it as a strict gate: a steered completion must read as a genuinely well-formed response to survive.

  • The baseline is judged too. The unsteered baseline goes through the same gate, so normalization stays apples-to-apples within a round.

  • The judge pass roughly costs a second (cheaper) generation pass; it is controlled per round by check_coherence in the competition's input_data_generator_args — stamped onto the round input (AureliusSteeringInputDataSchema.check_coherence) and sent on every /score call, baseline included. It is on by default; false skips the judge pass entirely and every completion is treated as coherent (pre-v0.1.5 scoring).

Minimal-intervention reward (enabled in current rounds)

As of the v0.1.4 scorer, a round may reward steering that achieves the concept with a gentler push — a smaller total intervention on the residual stream — over brute-forcing the detector with an enormous one. (This replaces the experimental Hoyer-sparsity penalty from v0.1.3, which is gone in v0.1.4.) It is off unless configured, but current rounds run with push_scale = 555000 — assume it is on.

This all happens inside the scorer, before the eval pipeline sees a number. When enabled, the scorer multiplies its pre-reward concept score by an efficiency factor in (0, 1], derived from the submission's total absolute steering push, to produce the score it returns:

A bigger push_scale tolerates more steering before discounting; as push_scale → ∞ the factor → 1 (no discount). The day-score gates it (a submission that generates nothing on-concept stays at 0), and efficiency ∈ (0, 1] with raw_score ∈ [0, 1], so the product stays in [0, 1].

It is enabled per round, by precedence request > per-concept config > off:

  • From the competition (the apex path): set push_scale in the competition's input_data_generator_args. Round generation stamps it onto the round input (AureliusSteeringInputDataSchema.push_scale) and the eval runner sends it on every /score call in the round — so the whole round (and its baseline) is scored under one setting. Omit it (or null) to leave the reward off. A recommended starting value is ~555000.

  • In the scorer config: a non-null push_scale for a concept in the scorer's config/competition.yaml (used when the request omits it).

push is always computed and reported, even when the reward is off, so it can be calibrated against the real distribution before being switched on. The /score response (and each submission's history file) carries:

Scorer response field
Meaning

score

the concept score the scorer returns, after the reward (= raw_score × efficiency)

raw_score

the scorer's score before the reward — already coherence-gated

push

total absolute steering, `

push_scale

the scale in effect for this request (null = off)

efficiency

the multiplier applied: exp(-push / push_scale) (1.0 when off)

check_coherence

whether the coherence judge ran for this request

coherence_hit_count

completions the judge passed (null when the judge was skipped)

⚠️ raw_score means two different things across the two layers. The scorer's raw_score is its pre-reward score (with the coherence gate already applied). The eval pipeline's raw_score (what we store as eval_raw_score) is the scorer's post-reward score field. The full chain, with both features on:

With the reward off, efficiency = 1.0, so the scorer's raw_score and score are equal and the distinction collapses.

Note on the baseline. The unsteered baseline submission has alpha = 0, so push = 0 and efficiency = exp(0) = 1 for any push_scale — the baseline is never discounted. So even with the reward on, a (discounted) miner score is normalized against an undiscounted baseline_score. This is intended — the baseline is the no-steer reference point — but worth being aware of before enabling it.

Round structure and defaults

Setting
Default

Round length

1 day (default_round_length_in_days = 1)

Submission code visible after

1 day (default_submission_reveal_days = 1) — submissions stay hidden until then, then are published

Prompt sample size per round

150 — configured per round

  • No logs: this competition produces no execution logs. There is nothing to inspect mid-round.

  • History file: at the end of the round, each scored submission has a history file — the full scorer response, including the prompt and the resulting inference (completion) for each prompt. This is the artifact miners use to see exactly how their direction steered the model.

  • Concept cycling: the active concept is changed manually after X rounds, by a joint decision between Macrocosmos and Aurelius. It does not rotate automatically on a fixed schedule.

Tips for miners

Building a steering direction

  • A direction is a single unit vector in the model's 3840-dim hidden space at layer 32. A common, effective approach is diff-of-means: collect layer-32 activations on text that does express the concept and text that does not, take the difference of the two means, and L2-normalize it. That difference vector points from "not the concept" toward "the concept".

  • Other approaches: probing classifiers (use the learned weight vector as the direction), sparse-autoencoder features, or contrastive activation pairs. Anything that yields a meaningful direction at layer 32 is fair game.

  • Always work against the canonical config (gemma-3-12b-it, 4-bit NF4, bf16, layer 32). Directions derived from a differently-quantized or different-layer setup will not transfer cleanly.

  • Then tune alpha against real steered completions. The direction sets what to push toward; alpha sets how hard. Sweep alpha (≈12k–16k) and watch for the sweet spot before the model degenerates — completions that stop reading as coherent answers score zero, and every extra unit of push also costs efficiency. The winning direction is the one that steers convincingly with the least intervention, not the hardest shove.

  • Normalize before submitting: direction = direction / ||direction||.

Regenerating the baseline and a random steer

This folder ships a generator and two reference files you can reproduce:

  • scripts/example_submission_generator.py — writes a valid .safetensors submission, with each field annotated by the rule it must satisfy.

  • scripts/baseline-zero-steer-positive_sentiment.safetensors — an unsteered (alpha=0) baseline submission. The filename's positive_sentiment suffix is the concept stamped in its metadata; for a different round, regenerate with that round's --concept.

  • scripts/sample-random-steer-positive_sentiment.safetensors — a random-direction steered submission for the positive_sentiment concept (a sanity-check / lower bound, not a real strategy).

Regenerate them from the scripts/ directory. Pass --concept to stamp the round's active concept into the file's metadata — it defaults to positive_sentiment, so set it explicitly for any other round or your submission will be rejected with a concept mismatch. The commands below reproduce the committed positive_sentiment reference files; swap in the active concept (and filename) for your round:

The --concept value must be one of the four supported concepts and must equal the round's active concept. The random/baseline files are starting points and references — a competitive submission replaces the random direction with one you've actually derived for the active concept.

How to submit

  1. Build your direction for the round's active concept and tune alpha.

  2. Write the .safetensors submission (use the generator as a template). Confirm it has the single direction tensor ((3840,), float32, unit-norm) and the alpha / layer=32 / concept metadata.

  3. Submit it through the standard Apex miner flow for the aurelius_steering competition before the round closes.

  4. All submissions are scored together when the round ends; your submission's code is revealed after the reveal window, and the history file lets you review the per-prompt completions your direction produced.

References

Last updated