Submit a direction
A submission is one author's complete take on one label against one model, frozen at author/model/label@version forever. Yours does not replace anybody's and nobody's replaces yours. There are two ways to fill this in and neither is the better one: type it, or hand a prompt to the coding agent that already has your extraction scripts open.
Reading the session this browser kept.
There is no session in this browser. A submission is sent as somebody, because the database stamps the namespace from the session rather than taking it from a field. Sign in with Hugging Face, which comes back and sends you here, or read what signing in is for first. Reading this site needs none of it.
Your namespace is , which is the handle Hugging Face reported when you signed in. There is no field for it and no default to type over. What that makes impossible: publishing under a pseudonym, under a lab name you hold no account for, or into one namespace shared by several people who each sign in as themselves.
A submission is a pointer to bytes a stranger can fetch. If your repository is private, the section further down will publish the one file to your own account, with your permission, and then fill in the pin.
Pasting and filling the fields in at once is refused, and neither is preferred. Those are two accounts of one submission and nothing here can tell which was meant, which is the same reason a field cannot carry both a value and a reason for having none.
Hand it to your coding agent
An agent sitting in the checkout where the extraction happened can read most of this off your own scripts, which is where the answers are. Copy the prompt, run it there, and paste back what it produces. The prompt tells it what each field is for and tells it, in the strongest terms the text can manage, never to write a value it did not read.
Read the prompt first
This is the whole of what gets copied. It is generated from the same field list the parser reads, so what it asks for and what the parser takes cannot come apart.
You are helping the person you work for prepare one submission to controlbun, a
registry of activation-steering artifacts. Read their files and answer about
their artifact. Do not answer from memory of how registries like this usually
work, and do not answer from what a field's name suggests it should hold.
Answer by going and looking: the extraction script, its config and its logs, the
notebook, the model card of the model the activations were read from, the commit
history, and the artifact file itself. Where you looked is worth more than what
you produce, so say where each answer came from if the person asks.
## The rule that outranks every other instruction here
**Never write a value you did not read.** Not a hash, not a revision, not a
layer index, not a license. This registry exists so that somebody can pick up a
stranger's steering vector and apply it correctly, and every number in it is
load bearing in a way that fails silently: a vector applied at the wrong layer
or under the wrong chat template does not error, it appears not to work. A
plausible value you produced is indistinguishable from one the author measured,
and it destroys the only thing this registry is for.
If you cannot find something, say so in the block at the bottom with the
`not-found:` line, which takes the field name and the reason. Absence is a real
state in this schema. Nullable columns exist for exactly this and a row with a
missing revision renders as "not recorded" rather than as a gap or an error.
The real artifacts in this registry today record no revision, no chat template
hash and no activation norm, and each absence is documented as what was never
captured rather than filled with something that reads like a measurement.
An empty field is a fact. A guessed field is a forgery.
## Nothing here is chosen from a list
Every field below is an open string. There is no set of permitted kinds, hook
points, layer conventions, steering positions, methods or file formats, and
there is no page that lists them. Where this text says a value is common, it
means other people have used it, and nothing whatsoever follows from that.
If the thing your author built does not fit a word anybody has used before, use
their word. An artifact nobody has a name for is a submission this registry
wants, not a problem to work around. The same goes for the file: the intake tool
refuses bytes it cannot read without executing them, and says so in those terms,
rather than refusing a format for not being on a list.
## What the registry needs, and why each one
Two objects get written from your answers. A **submission**, which is one
author's complete take on a label against one model, frozen forever at
`author/model_id/label@version`. An **intervention**, which is the artifact
itself plus everything needed to apply it.
The model is part of the reference because a direction is a tensor in one
model's residual basis and does nothing for another one. So
soham/allenai/Olmo-3-1125-32B/pro-human@meandiff
is one submission, and the same author's take on the same word against another
model is a different submission with its own reference. Neither supersedes the
other and neither is the real one.
**author** Your author's own namespace. Free to claim and never assigned.
**label** The trait or behavior, as your author names it. Free to claim, and
other people claim the same one: `author/label` is theirs, and the bare label is
a view across everybody who claims it, owned by nobody. The registry holds
competing takes on the same word deliberately and resolves none of them.
**definition** Your author's own theory of the label, in their own words. This
is the field that matters most and the one you are least able to produce
yourself. It is load bearing twice: it feeds contrast-pair generation, and it is
the thing another author disagrees with when they claim the same label.
Do not write the correct definition of the word. There is not one. Ten people
meaning different things by "kindness" is the content of this registry, not a
collision to be tidied up: one author's kindness is warmth in affect and
another's is costly help and explicitly not warmth, and both submissions stand.
So write what your author thinks the trait is, including the part that makes
their take unlike anybody else's, and including what they think it is not. If
you have their words for it, in a paper, a README, a docstring or the contrast
prompts themselves, use theirs. If you do not, ask them rather than composing
one.
Its line is the last one in the block, below every other field and below the
`not-found:` lines. That is the format protecting it rather than demoting it,
and the reason is under `How to answer`. Read this section again before you
write that line; it is the one place in the block worth spending your effort.
**version** Whatever distinguishes this take from the author's other takes on
the same label against the same model. `author/model_id/label@version` resolves
to one frozen submission forever, so it is never reused and never edited: a
correction is a new version. Versions in this registry today name what changed,
like the estimator that produced the direction or the layer it was read from,
rather than counting.
A take on a different model is not a version. It is another submission, and the
model in the reference is what keeps the two apart.
**created_at** When the work happened, which is not when it is typed into the
form. ISO 8601, UTC. The run log, the file's own timestamp or the commit date,
not today's date.
**intervention_id** The primary key of the artifact row, and the thing an eval
report or an attack points at later. Unique across the whole registry, stable
forever, and your author's to choose.
**kind** What this artifact is. `direction`, `sae-latent`, `probe`, `reft` and
`lora` are values the schema's own comment calls common rather than permitted,
and an unrecognized kind is storable and displayable and simply has no apply
path in the client until somebody writes one.
**model_id** The model the activations were read out of, and part of what the
submission is rather than a property of it. A direction has no meaning apart
from it. Base and instruct are different models, so give the exact repo id the
extraction loaded, not the family name.
Give the whole string the way the distributor writes it, distributor included:
`allenai/Olmo-3-1125-32B`, `Qwen/Qwen3-8B`. A model with no distributor is one
segment and that is fine, `gpt2` and `bert-base-uncased` among them; nothing here
requires a slash and nothing checks the shape of what you write.
**model_revision** The exact revision of those weights, if the extraction
recorded it. A commit on the model repo. If nobody wrote it down, `not-found:`
it and say so. Do not paste the sha the model repo has today: that is a false
provenance claim that reads exactly like a true one, and it is worse than the
hole it fills.
**layer** An integer. Which layer the activations came from.
**layer_convention** How to read that integer, stated separately because getting
it wrong is silent. `block-0indexed` is a value this corpus already holds. Read
it off the hook name or the indexing in the extraction code rather than assuming
the usual one, and if the code counts from one, or counts sublayers, or indexes
something other than transformer blocks, write down what it counts.
**hook_point** Where in the block the activations were read, and where the
artifact acts. `resid_pre`, `resid_post`, `mlp_out` and `attn_out` are common.
Architectures have hook points those four do not name, and where your author's
is not among them, name it their way.
**chat_template_hash** The template the activations were read under, identified
by a digest, because a vector extracted under one template may not transfer to
another. Take the value your author's code computed. Nothing here fixes what
hash function or what exact string, so pass through what their pipeline
records, and if you compute one yourself, tell them in your reply what you
hashed and with what, so they can decide whether that is the thing to record.
If no template was applied, because activations were read from raw text against
a base checkpoint, that is the common case for a base-model extraction:
`not-found:` it with that sentence. Never produce a hex string for this field.
**shape**, **dtype**, **l2_norm**, **sha256** Optional, and checked. The intake
tool reads all four out of the bytes for itself. If you state one, the bytes are
held to it and the row keeps what you said, which is worth more than a number
derived from the bytes it is being compared against: state them when they are
cited from your author's own record, the paper, or the extraction output. State
nothing and the row records what the file says. Saying nothing is not a wrong
claim, and for a first submission it is usually the better answer.
`shape` is compared as the numbers in it, so `[8192]` and `(8192,)` are the
same answer and neither is wrong.
**`sha256` is the one to leave out unless you know it survives.** It is the
digest of the whole file, header included, and the intake tool rewrites the
header with its keys sorted before it records anything, because safetensors
seeds its header order per process and a file that does not reproduce byte for
byte makes every digest in this registry meaningless. So the digest the row
ends up with is of the file the tool wrote, and the digest your author recorded
for the file they exported will not match it unless their export was already
sorted. That is a difference in byte order, not in the tensor, and stating a
digest is the one way to turn it into a refusal.
**activation_norm** The typical residual norm at that layer, and only if the
author's coefficients are expressed as a fraction of activation magnitude. If
they scaled a raw alpha against a unit vector, leave it absent even when the
number is measured somewhere, because putting it here asserts something about
what the coefficients mean.
**coeff_low**, **coeff_high** The coefficient range the author actually swept or
recommends. Absent if they did not sweep one.
**steering_position** Where the intervention is applied during generation, in
the author's words.
**license_status** Whether a source model's license reaches a direction read out
of it is open. This registry's own author takes the position that a direction is
the work of whoever built it, and records the case against that position beside
it; you are not bound by either. Read the source model's license and say what you
read, where you read it and when. If something is unresolved, say that:
unresolved rights mean the artifact can be pointed at but not served, which is a
fact the registry records rather than a reason to refuse it.
## Where the artifact is, and the pin
**artifact_path** Where the file sits inside the published repo, and nowhere
else. Relative, no leading slash.
**This is not where the file is on your author's machine.** That is the mistake
this field actually gets, and it gets it from people who found the file, which
is to say from you. A scratch path, a cluster mount, a home directory or
anything starting with `/` is refused, and refused rather than cleaned up,
because the registry hands this exact string to the host when somebody later
downloads the vector. A local path stored here describes a folder that exists
on one machine, so every fetch after today looks for it and gets a 404.
If the artifact is already published, give the path it has in that repo,
character for character. If it is not published yet, this field is a decision
rather than a lookup: choose where it will sit once it is uploaded, and say so.
`vectors/<name>.safetensors` is a reasonable shape and nothing requires it.
So: read where the file is now to find and verify the bytes, then answer with
where it goes. Those are two different strings and only the second one belongs
here.
**artifact_repo** The repo the author published it in, as `owner/name`. Their
own account, never the registry's. Any host; most steering artifacts are in
GitHub repos and that is not a lesser answer than a Hub one.
**artifact_commit** Forty hex characters. A commit, never a branch and never a
tag: whoever owns a repo can move a tag, so pinning to one pins to whatever is
there today, which is the opposite of what `author/model_id/label@version`
promises. If
you only have a branch, resolve it to the commit it points at right now and give
that. If the artifact is not published anywhere yet, `not-found:` the repo and
the commit and give the path anyway; the intake tool publishes the file to the
author's own namespace and records the commit it made.
**artifact_host** Which host that repo is on, as a bare authority:
`huggingface.co`, `github.com`, anything. Droppable, and dropping it means the
Hub.
**artifact_url_template** How `{host}`, `{repo}`, `{commit}` and `{path}` become
a URL that returns the file's bytes. Droppable, and dropping it means the Hub's
layout.
**The commit has to end up in the URL, and that is the only shape rule.** A
template that resolves to a URL not containing the commit is refused, because
such a URL returns whatever is at that address today, and a pin to whatever is
there today is the thing `author/model_id/label@version` promises not to be. You can
leave out any of the other three: hard-coding the host in the template is
normal, and the GitHub media layout below does exactly that. Two further
mechanical rules, so they do not surprise you: the scheme has to be http or
https, and each placeholder has to be a bare `{name}` with no format spec and
no attribute access.
Do not guess the rest of it: fetch the URL you are about to give and check that
what comes back is the artifact rather than a redirect page or a git-LFS pointer
file, and say that you checked. GitHub needs two different layouts depending on
whether the file is LFS-tracked. For one repo, one commit and one path, the
media host returns the object and `raw` returns a small text pointer beginning
`version http`, and neither is an error, so only fetching tells you which layout
your author's file needs.
The file itself goes in as safetensors, holding exactly one tensor. A file
holding several is refused, because nothing can tell which one is the artifact.
The tool converts what it can read without running it and refuses a pickle in
those words.
## What other people have typed into these fields
Read out of this registry's own corpus at the moment the prompt was copied. Not
a menu, not a set to pick from, and not an indication that a value outside it is
wrong. It is here so that where your author's answer coincides with somebody
else's, it is spelled the same way, and where it does not, it stays theirs.
artifact_host: huggingface.co, github.com
artifact_url_template: https://{host}/{repo}/resolve/{commit}/{path}, https://media.githubusercontent.com/media/{repo}/{commit}/{path}, https://raw.githubusercontent.com/{repo}/{commit}/{path}
author: soham
hook_point: resid_post
kind: direction
label: pro-human, trauma
layer_convention: block-0indexed
license_status: Redistribution of a derived artifact is permitted with attribution, under the Llama 3.3 Community License Agreement (release date December 6, 2024), which grants rights to "use, reproduce, distribute, copy, create derivative works of, and make modifications to the Llama Materials" and requires the notice "Llama 3.3 is licensed under the Llama 3.3 Community License, Copyright (c) Meta Platforms, Inc. All Rights Reserved." plus prominent display of "Built with Llama". The 700-million-monthly-active-users clause does not bind this academic use. UNRESOLVED: the clause requiring "Llama" at the beginning of a derivative AI model's name is scoped to a model created by training, fine-tuning or improving the materials, and whether a read-out direction vector falls under it is not settled by the text. Read at https://developer.meta.com/ai/llama3_3/license/ on 2026-09-18, because the model repo's own LICENSE returned HTTP 401 (gated) and the local snapshot on /scratch had been purged of files., allenai/Olmo-3-1125-32B is apache-2.0, confirmed from the Hub model API on 2026-09-14. Whether a direction read out of a model is a derivative work of it is unsettled and nobody has litigated it. This author's position, recorded 2026-09-19, is that a direction is his own work built against a model rather than a piece of one. For this model it is moot either way: Apache-2.0 permits redistribution with attribution on either reading. Replaces a reading recorded 2026-09-14 that stated the derivative premise as settled; the frozen header on each artifact still carries that older sentence.
model_id: allenai/Olmo-3-1125-32B, meta-llama/Llama-3.3-70B-Instruct
steering_position: all-positions, prefill pass only, applied once to every prompt position, NOT re-applied at each generated token
## How to answer
Write whatever you want to your author first. Then put the block below at the
end of your reply, and put nothing after it. The parser finds it inside
surrounding prose and ignores everything else, so explanation costs nothing.
One field per line, `field: value`. For anything with a newline or a colon in
it, and that means the definition, open with `<<<` and close with `>>>` on their
own lines. For anything you could not find, one `not-found:` line naming the
field and the reason. Leave nothing empty and leave no placeholder in: the
parser refuses both rather than guessing which you meant.
**The definition is the last line of the block, and last here is not least.** It
is the field that matters most and the only one with no natural end to it, so it
sits where running long is free. Everything short goes above it, the `not-found:`
lines included, and the one value that can be any length goes where nothing comes
after it.
## What actually goes wrong
The first three submissions written through this handoff were all refused, and
all three failed the same way. None of them was wrong about the artifact.
**The `<<<` that never closed.** All three, hours apart, one author, one agent,
one line.
definition: <<<
...the author's own theory, over as many lines as it takes...
intervention_id: ... <- swallowed, and so was every line below
What came back, all three times:
definition opened with <<< and nothing closed it, so it ran to the
end of the submission and took everything after it with it, including
artifact_path, hook_point, intervention_id, kind, layer, layer_convention,
license_status, model_id, model_revision, not-found, steering_position.
The fix is one line:
definition: <<<
...the author's own theory, over as many lines as it takes...
>>>
`definition` is the last line of the block for this reason, so forgetting the
`>>>` there now swallows nothing and the end of the submission closes it. Open a
`<<<` on any value with lines after it, forget to close it, and the block still
eats them and the whole paste is still refused.
**A local path in `artifact_path`.** Observed once, on a real submission, and
caught before the row was written. The agent answered with the path it had just
read the file from on the author's cluster. Anything starting with `/` is
refused: it names a folder on one machine, so every fetch after today gets a
404. Answer with where the file sits in the published repo, like
`vectors/direction.safetensors`.
**A branch where the commit goes.** `artifact_commit: main` is refused, and
refused rather than resolved for you. Whoever owns a repo can move `main`, so it
pins to whatever is there today, which is the opposite of what
`author/model_id/label@version` promises. Resolve it yourself and give the forty
hex characters it points at right now.
=== BEGIN CONTROLBUN SUBMISSION ===
author: <namespace>
label: <the trait, as your author names it>
version: <what distinguishes this take>
created_at: <ISO 8601 UTC, when the work ran>
intervention_id: <unique, stable, the author's to choose>
kind: <what this artifact is>
model_id: <the repo id the activations were read from>
model_revision: <the revision of those weights>
layer: <the integer>
layer_convention: <how to read that integer>
hook_point: <where in the block>
chat_template_hash: <the digest your author's code recorded>
shape: <only if cited from the author's record>
dtype: <only if cited from the author's record>
l2_norm: <only if cited from the author's record>
sha256: <only if cited from the author's record>
activation_norm: <only if coefficients are fractions of it>
coeff_low: <the swept range, low end>
coeff_high: <the swept range, high end>
steering_position: <where it is applied during generation>
license_status: <what the model license permits, where you read it, when>
artifact_path: <where it sits in the published repo, relative, not a local path>
artifact_repo: <owner/name>
artifact_commit: <forty hex characters>
artifact_host: <the host that repo is on; drop the line for the Hub>
artifact_url_template: <how host, repo, commit and path become a URL>
not-found: <field name> <why there is no value, in a sentence>
definition: <<<
<your author's own theory of the label, in their words,
over as many lines as it takes>
>>>
=== END CONTROLBUN SUBMISSION ===
Every line is droppable except the ones the schema cannot write a row without:
author, label, version, created_at, intervention_id, kind, model_id, layer,
layer_convention, hook_point, artifact_path and definition. For those, a
`not-found:` is refused too, because there is no row to write without them. That
is a shape the database has, not a judgment about the artifact.
Paste the whole reply, including anything it wrote to you around the block. The parser finds the block inside surrounding prose and reads past the rest, so explanation costs nothing.
Or fill it in yourself
Every field is an open string. Nothing here is checked against a list of permitted values, and a value nobody has used before is the ordinary way this corpus grows.
Something is absent and you want to say why
An absence is a positive statement with a reason, never an omission and never an error. One line per field, as field: your sentence. The field name is any string; it is not checked against a list. An agent writes these itself, on the not-found: lines the prompt asks for, so this box belongs to the fields above.
A field cannot carry both a value above and a reason for having none. That is two claims about one field, and the author's rebuild refuses it rather than picking one.
Your submission
Nothing has been sent yet. This is the record. Read it, then send it.
Sending puts this record and three columns beside it in a holding table: the account, the subject and the handle, all three taken from your signed session by the database rather than from anything above. So a submission cannot claim to be from somebody it is not. The copy is for you; it is not needed for anything and nothing here depends on your keeping it.
Reading it later fetches the bytes at the pin, checks them against what this record says, writes the row and rebuilds the site. The shape, the dtype, the norm and the digest are read off the bytes on that machine rather than computed here, because one thing in this project reads bytes and a second implementation of it is the failure this repository has hit most often. A pin nobody can fetch is refused there, with the reason. A paste is read there too, and by the same argument.
Received
- received at
- row
- stamped handle
- stamped subject
Those four are what the database wrote, read back off its answer rather than off what this page sent. The handle and the subject beside them are the ones your session carries; the record above carries the browser's own copy of both, and where the two disagree the stamped ones are the ones the author reads.
There is no way to edit or withdraw this from here, on purpose: a submission is a statement somebody made at a time, and a correction is another submission. Mail the author if you need one removed.
What you have sent
Every value below is shown in quotation marks because that is what it is: the string you typed, rendered as your own words with the rule down the side this site draws beside anything it is quoting rather than asserting. A number here is a number you typed. The falsifier has never seen it and cannot re-derive it, since re-deriving one means reading the bytes at the pin, which is the step that has not happened yet.
This account has sent nothing yet. That is a state and not a failure: an account that has not sent a record has none, and the form above is where the first one starts. Nothing is missing and nothing went wrong.
Ordered by the time each one arrived here, oldest first. That is the clock and nothing else: it is not a rank, not a place in a line and not a position anybody is working through, and reversing it changes nothing about any record.
What this page is not
It is not a queue, and nothing here is reviewed or ranked. What you have sent is counted for you and ordered by the clock it arrived on, which is yours, reversible, and says nothing about anybody else's work or about where yours sits. It keeps no cookie. The one thing it writes into this browser is the session it renews before sending, under the key Sign out deletes. The Hugging Face token is the thing it never writes down anywhere, because that one reaches your account rather than this table. A namespace takes any number of claimants, and two people claiming one name render as two claims with their dates rather than as a conflict anybody here resolves.