Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ tt-model package-thin you/mymodel ... # author + push a v6 thin bu
tt-model push build/mymodel # push a staged v5.1 container package (repo id from its manifest)
tt-model publish you/mymodel # list a public bundle in the community catalog
tt-model unpublish you/mymodel # delist (repo untouched)
tt-model verify you/mymodel # TT reviewers: copy a listed bundle into Tenstorrent/ as verified
tt-model unverify Tenstorrent/MyModel # withdraw that copy from the catalog (repo kept)
```

`push` accepts only a staged v5.1 container directory. `package-thin` pushes a v6 bundle itself
Expand Down
69 changes: 69 additions & 0 deletions docs/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,75 @@ tt-model unpublish you/mymodel # delist (repo stays public)
indexes only repos carrying it, and reads each repo's `tt_kernel_manifest.json` to render it.
`tt-model search <term> --catalog` restricts a search to listed bundles.

## Verifying bundles (Tenstorrent reviewers)

The catalog is open — anyone can list a bundle, and that is the point. A new bundle is
**unverified**. **Verified** bundles are the curated subset a Tenstorrent reviewer has looked at, so a developer can pick a
model that is expected to work on the hardware it claims instead of sifting through everything
published:

```bash
tt-model verify you/mymodel # copy a LISTED, public bundle into Tenstorrent/
tt-model unverify Tenstorrent/MyModel # withdraw the copy from the catalog
```

**Verifying is the copy.** A bundle under `Tenstorrent/` is verified by definition,
because only the DX team can write that namespace (`TT_ORG` in
[`tt_kernel/__init__.py`](../src/tt_kernel/__init__.py)). There is no index to fetch and nothing
to keep in sync: "has Tenstorrent reviewed this" reduces to "is this repo ours", which any
consumer can answer from the repo id alone. It is deliberately **not a repo tag** and **not a
manifest field** — a tag lives in the author's own README frontmatter, which they can edit from
the Hub UI, and the manifest is written by whoever publishes the model, so neither can carry a
review someone *else* granted. `tt model list` shows verified models by default; the original
stays listed as unverified, shown with `tt model list --unverified`.

The copy is named after the **weights** repo, not the bundle: a bundle published as
`someone/qwen3-32b-blackhole-v51` with weights `Qwen/Qwen3-32B` becomes
`Tenstorrent/Qwen3-32B`. That is the canonical model name a reader is looking for rather than an
author's packaging slug.

What the commands guarantee:

- **The author's repo is never touched.** `duplicate_repo` is a server-side copy — it reads the
source and writes only the new repo. A review costs one request and moves no bundle data, even
for a multi-GB image.
- **The copy stays private until it is complete.** It is made private, then its review is
recorded, then it is listed, and only then made public. `tt model list` counts anything in the
org as verified, so a copy that went public first would show as verified with no credit to the
author. A run that fails part way leaves nothing public. One gap: the private copy carries the
source's catalog tag from the start, so someone whose token can see private org repos may see
it early.
- **The copy is a snapshot.** It records the source repo and the exact revision it was copied at,
in its own card frontmatter. Later commits to the original are *not* covered by the review, and
`Tenstorrent/...` does not track upstream.
- **The author is credited in the card's top line.** A verified copy opens with a block naming
the community author and linking both their profile and their original repo, above the model's
own heading. That is the bargain: the copy earns this org's traffic, so the credit goes where a
reader lands rather than under the fold. Re-recording a review replaces that block, so resuming
an interrupted `verify` never stacks a second credit on the first.
- **Verified bundles are a subset of the catalog.** `verify` refuses a repo that is not listed
(listing is the author's decision — it will never `publish` on their behalf) and refuses a
private one. The copy is then listed explicitly rather than relying on it inheriting the tag,
so a public-but-unlisted source cannot produce a copy nobody can find.
- **`push` neither grants nor drops a review**, and `unpublish` has nothing to say about one: the
copy is its own repo, so delisting an original leaves it alone. That independence is the point.
- **A name collision refuses.** Two bundles of the same model — two board targets, or two authors
packaging the same upstream weights — derive the same name. The second is refused, naming the
existing copy and what it was made from; it is never overwritten, because a reviewed artifact
someone may be relying on is not ours to replace silently. `unverify` does not free the name
(it only delists). If the other copy is abandoned, delete it on the Hub and re-run.
- **A half-finished run resumes.** Re-running `verify` finishes a run that stopped part way
instead of copying again. The existing copy counts as this run's when its card records this
source at the revision being verified, or, before the review is recorded, when its files are exactly the source's at the
revision being verified. (A server-side copy does not keep the source's commit history, but
it keeps every file byte for byte.) A copy of an older revision of the source does not count,
so it is never finished or re-recorded with a revision it does not contain. To verify a
newer revision, delete the copy on the Hub and re-run.
- **Withdrawing keeps the artifact.** `unverify` delists the copy and leaves the repo, so
anyone who pinned it can still reach it, and the original is unaffected. Delete the
repo by hand on the Hub if it should be gone entirely. It takes the **copy's** id — passing the
community bundle it came from is refused.

## How compatibility is checked

`tt-model` records the target arch and machine in the bundle's `tt_kernel_manifest.json` and
Expand Down
9 changes: 9 additions & 0 deletions src/tt_kernel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,20 @@
# pointers to public HF repos, which remain under their owners' governance.
TT_MODEL_CATALOG_TAG = "tt-model-catalog"

# The HF organisation that holds verified bundles. Verifying copies a reviewed bundle into
# this namespace, so "has Tenstorrent reviewed this" reduces to "is this repo ours" — a
# question any consumer can answer from the repo id alone, with no index to fetch and
# nothing to keep in sync. Write permission here is the gate, and only the DX team has
# it; an author cannot put anything in this namespace, which is exactly what a repo tag
# on their own bundle could never guarantee.
TT_ORG = "Tenstorrent"

# Filename of the compatibility manifest at the root of every bundle.
MANIFEST_NAME = "tt_kernel_manifest.json"

__all__ = [
"TT_MODEL_TAG",
"TT_MODEL_CATALOG_TAG",
"TT_ORG",
"MANIFEST_NAME",
]
198 changes: 195 additions & 3 deletions src/tt_kernel/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
from typer.core import TyperGroup

from . import console
from . import MANIFEST_NAME, TT_MODEL_CATALOG_TAG, TT_MODEL_TAG, __version__
from . import (
MANIFEST_NAME,
TT_MODEL_CATALOG_TAG,
TT_MODEL_TAG,
TT_ORG,
__version__,
)
from . import (
auth, compat, container, hub, localdb, metal,
packaging, runtime,
Expand Down Expand Up @@ -181,7 +187,8 @@ def _fail_card(name: str, diagnosis: dict, *, consequence: Optional[str] = None)
return typer.Exit(code=1)


def _hub(op, repo_id: str, *, what: str, consequence: Optional[str] = None):
def _hub(op, repo_id: str, *, what: str, consequence: Optional[str] = None,
classify=None):
"""Run a Hub call, turning any failure into a diagnosis card instead of a traceback.

Every Hub entry point used to be unguarded, so a 404 escaped as a Rich stack — from
Expand All @@ -196,7 +203,8 @@ def _hub(op, repo_id: str, *, what: str, consequence: Optional[str] = None):
except BaseException as exc: # noqa: BLE001 — classified and re-raised as an Exit
if console.is_verbose():
raise
raise _fail_card(what, hub.classify_hub_error(exc, repo_id), consequence=consequence)
diagnosis = (classify or hub.classify_hub_error)(exc, repo_id)
raise _fail_card(what, diagnosis, consequence=consequence)


def _require_repo_id(repo_id: str, *, what: str, consequence: Optional[str] = None) -> None:
Expand Down Expand Up @@ -1904,6 +1912,190 @@ def unpublish(
f"delisted {repo_id} from the community catalog (it drops off on the next crawl) "
"— the repo and its content are unchanged"
)
# No verification advisory here: a Tenstorrent copy is its own repo, so delisting the
# original has no bearing on it. That independence is the point of the design.


# ------------------------------------------------------------------------ verify
def _review_target(manifest) -> Optional[str]:
"""The `Tenstorrent/<name>` a bundle would be copied to, or None if undecidable.

Named after the WEIGHTS repo, not the bundle: that is the team's convention and it
yields the canonical model name (`Tenstorrent/Qwen3-32B`) rather than an author's
packaging slug (`someone/qwen3-32b-blackhole-v51`).
"""
weights = getattr(manifest, "weights", None)
repo = getattr(weights, "repo_id", None)
if not repo or "/" not in repo:
return None
return f"{TT_ORG}/{repo.split('/')[-1]}"


@app.command(rich_help_panel="Publish models")
def verify(
repo_id: str = typer.Argument(..., help="A LISTED bundle as namespace/name."),
) -> None:
"""Copy a reviewed bundle into the Tenstorrent org as verified (DX-team reviewers).

Verified bundles are the curated subset of the community catalog: bundles we have
looked at and expect to work on the hardware they claim, so a developer does not have
to sift through everything published. Verifying IS the copy — a bundle under
``Tenstorrent/`` is verified by definition, because only the DX team can write there.
An author cannot grant it to themselves, which is what a tag on their own repo could
never prevent.

The copy is server-side, so no bundle data moves, and the author's repo is never
touched, and stays listed as unverified. The copy records what it came from and is a
snapshot of that revision: later commits to the original are not covered.

The copy stays private until its review is recorded and it is listed, so a run that
fails part way leaves nothing public. Re-running finishes it.

The bundle must already be listed (``tt-model publish``) and public. Listing is the
AUTHOR's decision and this command never makes it for them.
"""
import datetime as _dt

state = _hub(lambda: hub.repo_state(repo_id), repo_id, what="Verify")
if TT_MODEL_CATALOG_TAG not in state.tags:
raise _err(
f"{repo_id} is not in the community catalog, so it cannot be verified.\n"
" Verified bundles are a curated SUBSET of the catalog — listing is the author's\n"
" decision, review is ours. Ask them to run: tt-model publish " + repo_id
)
if state.private:
raise _err(
f"{repo_id} is private, so it cannot be verified — a verified bundle must be\n"
" one consumers can discover. The author can make it public with: "
f"tt-model publish {repo_id}"
)
me = auth.whoami()
if not me:
raise _err("Not logged in to Hugging Face — run `tt-model login` first (the copy "
"records who reviewed it).")
reviewer = str(me.get("name") or me.get("fullname") or "?")
source = state.repo_id or repo_id # the Hub's own casing, for the recorded source

manifest = _hub(lambda: hub.fetch_manifest(repo_id, None), repo_id, what="Verify")
target = _review_target(manifest)
if not target:
raise _err(
f"{repo_id} names no weights repo in its manifest, so there is no name to copy\n"
f" it to — the convention is {TT_ORG}/<the weights repo's name>."
)

if not state.sha:
# Not fatal: the review is still a valid statement about the bundle. But say so —
# the recorded revision is what tells a later reader which commit was reviewed.
console.note(
f"the Hub did not report a head commit for {repo_id}, so the copy will record "
"no source revision",
marker="!", style="warning",
)

# Existing target: either this is a half-finished run to resume, or it is a different
# bundle's copy and the name has collided. Never overwrite the latter — a reviewed
# artifact someone may be relying on is not ours to replace silently.
resumed = None # None: fresh copy; else what the milestone says was done
if _hub(lambda: hub.repo_exists(target), target, what="Verify"):
review = _hub(lambda: hub.read_review(target), target, what="Verify") or {}
recorded = review.get(hub.VERIFIED_SOURCE_KEY)
recorded_rev = review.get(hub.VERIFIED_REVISION_KEY)
if recorded and str(recorded).lower() == source.lower():
if recorded_rev != state.sha:
# Re-recording would claim a revision the copy's files are not.
held = (f"at {str(recorded_rev)[:9]}" if recorded_rev
else "with no recorded revision")
now = f"now at {state.sha[:9]}" if state.sha else "now at an unknown revision"
raise _err(
f"{target} holds {source} {held}, but {source} is {now}.\n"
f" The copy cannot be re-recorded as a revision it does not contain, so it\n"
f" stays verified as it is. To verify the newer revision, delete it on the\n"
f" Hub (https://huggingface.co/{target}/settings) and re-run."
)
resumed = "re-recorded"
console.note(
f"{target} already records {source} — re-recording the review rather than "
"copying again",
marker="○", style="muted",
)
elif not recorded and state.sha and _hub(
lambda: hub.is_copy_of(target, repo_id, state.sha), target, what="Verify"
):
# A run that copied but failed before recording the review.
resumed = "finished copying"
console.note(
f"{target} is an unfinished copy of {source} — finishing it rather than "
"copying again",
marker="○", style="muted",
)
else:
if recorded:
why = f"{target} already exists, copied from {recorded}"
elif state.sha:
why = (f"{target} already exists and records no review, and it is not a "
f"copy of {repo_id} at {state.sha[:9]}")
else:
why = (f"{target} already exists and records no review, and with no head "
f"commit for {repo_id} it cannot be matched to this bundle")
raise _err(
f"{why}, so {repo_id} cannot take that name.\n"
f" The name comes from the weights repo, so two bundles of the same model\n"
f" collide here. If that copy is abandoned, delete it on the Hub\n"
f" (https://huggingface.co/{target}/settings) and re-run."
)

if resumed is None:
_hub(lambda: hub.duplicate_into_org(repo_id, target), repo_id, what="Verify",
consequence=(f"nothing was made public; if {target} was created, it is "
"private and unfinished — re-run to finish it"),
classify=lambda exc, _: hub.classify_copy_error(exc, repo_id, target))
reviewed_at = (
_dt.datetime.now(_dt.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
)
_hub(lambda: hub.annotate_review(target, source=source, revision=state.sha,
reviewer=reviewer, reviewed_at=reviewed_at),
target, what="Verify",
consequence=f"{target} exists, private, with no review record — re-run to finish")
# Explicit rather than relying on the copy inheriting the tag: a source that was
# public-but-unlisted would otherwise produce a copy nobody can find.
_hub(lambda: hub.set_catalog_listing(target, listed=True), target, what="Verify",
consequence=f"{target} is reviewed but private and unlisted — re-run to finish")
# Last, so the copy is only public once it is complete. The private copy still
# carries the source's catalog tag, so someone whose token can see private org repos
# may see it before this.
_hub(lambda: hub.set_visibility(target, private=False), target, what="Verify",
consequence=f"{target} is reviewed and listed but still private — re-run to finish")

console.milestone(
f"{resumed or 'copied'} {source} to {target} as verified by "
f"Tenstorrent" + (f" (at {state.sha[:9]})" if state.sha else "")
+ f" — it now shows in `tt model list`, and {source} stays listed as unverified; "
f"undo with `tt-model unverify {target}`"
)


@app.command(rich_help_panel="Publish models")
def unverify(
repo_id: str = typer.Argument(..., help=f"A {TT_ORG}/... copy to withdraw."),
) -> None:
"""Withdraw a verified Tenstorrent copy from the catalog. The copy itself is kept.

Delists rather than deletes: the reviewed snapshot stays where anyone who pinned it
can still reach it. The original is unaffected. Delete the repo by hand on the Hub if
it should be gone entirely.
"""
if repo_id.split("/", 1)[0].lower() != TT_ORG.lower():
raise _err(
f"{repo_id} is not a {TT_ORG} copy.\n"
f" Pass the copy's id — the {TT_ORG}/... repo shown in `tt model list` —\n"
" not the community bundle it was made from."
)
_hub(lambda: hub.set_catalog_listing(repo_id, listed=False), repo_id, what="Unverify")
console.milestone(
f"withdrew {repo_id} from the community catalog — the repo and its reviewed "
"content are unchanged, and the bundle it was copied from is unaffected"
)


# ------------------------------------------------------------------------------ rm
Expand Down
Loading
Loading