Internal (in-tree) Model Onboarding
This skill is a delta on top of the base onboard
skill. Everything in that skill applies here — recipe file shape, intake
flow, model.py / app.py / demo.py / test.py / manifest.yaml conventions,
CollectionModel patterns, quantization guidance, source-as-root, all of
it. Do not duplicate that content here.
Read First
Before doing anything else in this session, read the base skill in full:
plugin/skills/onboard/SKILL.md
Then apply the deltas below on top. Where a delta contradicts the base skill (e.g. a rule the base skill states as "for standalone recipes"), the delta wins for in-tree work.
Deltas that apply to in-tree recipes
1. Recipe location
The recipe folder lives at:
src/qai_hub_models/models/<id>/
<id> is the folder name and must match manifest.yaml's id: field
(base skill enforces this). Use lowercase and underscores — no dashes,
no spaces. Register the id in MODEL_IDS (auto-discovered from the
folder — nothing to hand-edit).
The base skill sometimes writes examples pointing at /tmp/... or a
scratch folder for standalone-recipe demos. For in-tree work, ignore
those paths and author directly under src/qai_hub_models/models/<id>/.
2. Fully-qualified self-imports ARE allowed in-tree
The base skill says:
Never write
from qai_hub_models.models.<id>.external_repos.<repo_name>...in a standalone recipe folder — that path only exists when the recipe is inside the installed package tree. Standalone folders are imported by their folder name, so the qualified path doesn't resolve.
In-tree recipes ARE inside the installed package tree, so
from qai_hub_models.models.<id>.external_repos.<repo_name>... DOES
resolve and IS a legitimate pattern. You'll see it used throughout the
existing catalog. That said, prefer relative imports
(from .external_repos.<repo_name>...) when equivalent — it keeps the
recipe folder movable and matches what external contributors see. Only
reach for the fully-qualified form when a cross-module import inside
qai_hub_models genuinely needs it (e.g. a helper in another model's
namespace).
The qai-hub-models validate self-referential-imports check
short-circuits for in-tree paths, so this pattern won't trip validation
either.
3. Website-facing manifest fields are required
The base skill treats catalog metadata as optional (external recipes
don't need it). In-tree recipes are enforced by
src/qai_hub_models/test/test_configs/test_manifest_yamls.py::_check_website_facing
and MUST satisfy all of the following:
name,headline,idall set.namecontains no spaces, no underscores — use dashes.headlineends with a period.research_paper, if set to an arxiv URL, uses/abs/(not a direct PDF link).default_deviceis one ofCANARY_DEVICES(seesrc/qai_hub_models/utils/device.py::CANARY_DEVICESfor the current list — typically the flagship Snapdragon Galaxy / Elite phones and a laptop reference device).related_modelsdoes not include the recipe's own id (no self-links).status:is always set for in-tree recipes. The onboarding PR always ships withstatus: pending— never omit the field, never usestatus: unset, never setstatus: publishedon the first PR.pendingmeans "waiting for scorecard to collect perf data before being published"; the manifest gets flipped topublishedin a follow-up PR once the scorecard has generatedperf.yamland the static banner has landed.unpublishedis reserved for models that are being intentionally held back (and requiresstatus_reason:linking to a tracking issue).- If
status: PUBLISHED:manifest.yamlandperf.yamlboth exist in the folder.supported_precisionsyields at least one export runtime.has_static_banner: true— a.jpgstatic banner has been uploaded to the web assets bucket for this id.can_promote_to_published()returns(True, ...).
- If
status: UNPUBLISHED:status_reason:is set and links to a tracking issue.
- If
status: PUBLISHEDandstatus_reasonis set — that's an error; remove it once the model publishes. - If
numerics_benchmark:is set, its(metric_name, unit)pair is inVALID_METRIC_PAIRS(seesrc/qai_hub_models/utils/scorecard/...). - If the model is an LLM (
model_type_llm: true), thellm_details.call_to_actionandrestrict_model_sharingfields agree (see_check_website_facingfor the exact rule).
Copy from a similar published model in src/qai_hub_models/models/ to
get the field shape right (and remember to change status: published →
status: pending in your copy).
4. Static banner + web assets
Published in-tree recipes need a static banner uploaded to the AI Hub
web-asset bucket. This is out-of-scope for the authoring PR — file an
issue for the assets team, ship the recipe as status: pending, and
flip to published once the banner lands. has_static_banner: true in
the manifest is the promise that the file exists at
ASSET_CONFIG.get_web_asset_url(id, QAIHM_WEB_ASSET.STATIC_IMG); the
in-tree HEAD-check in test_manifest_yamls.py will fail if it doesn't.
5. Assets that need S3 upload
Goldens, sample images, and redistributable weights normally referenced via CachedWebModelAsset.from_asset_store(...) need to end up in the public S3 bucket. The agent doesn't have upload credentials — stage the files locally so tests / demo run during authoring, and let the user do the last-mile upload:
- Put the file at
<recipe>/build/<relative_path>matching what the eventualfrom_asset_storecall will use (build/is gitignored). During authoring, load it directly from that path intest.py/demo.py— nofrom_asset_storecall yet. - In the PR description, list the paths that need uploading (e.g.
build/test_images/input.jpg→ S3 key<id>/v1/test_images/input.jpg). The user uploads them out-of-band. - Once uploaded, swap the direct-path loads for
from_asset_store(MODEL_ID, MODEL_ASSET_VERSION, "<relative_path>")in a follow-up. The recipe can ship the direct-path form in the initial PR — reviewers know what it means.
6. Scorecard + perf.yaml
Every published in-tree recipe has an entry in the scorecard config
and a perf.yaml next to manifest.yaml. Both are auto-managed by the
scorecard pipeline — you do NOT hand-write them. On first PR:
- Land the recipe as
status: pending(noperf.yamlneeded yet). - The scorecard's next weekly run generates
perf.yamlafter the model compiles + profiles on real devices. - Flip
status: publishedin a follow-up PR once numbers stabilize.
7. Codegen + pre-commit before PR
After authoring model.py / app.py / demo.py / test.py /
manifest.yaml, run codegen to (re-)render the auto-generated files
(README.md, external_repos/__init__.py when applicable):
python qai_hub_models/scripts/run_codegen.py -m <id>
Then run pre-commit on the whole recipe folder:
pre-commit run --files src/qai_hub_models/models/<id>/*
Both must be clean before the PR is opened.
qai-hub-models validate <id> --internal is the authoring gate for
in-tree recipes. It runs everything the base skill's gate covers
(folder shape, manifest schema, requirements vs. base package, model
code, App, datasets / evaluator, URL reachability) plus the
Qualcomm-catalog checks (website-facing manifest fields, CANARY_DEVICES,
banner URL reachability, LLM call-to-action, published-artifact
requirements). Iterate on FAIL rows exactly as the base skill's
§Authoring correctness describes — same progress rule (two identical
FAIL rows → stop and report), same no-suppression rule (no bypassing
checks to make them pass).
qai-hub-models validate <id> --internal
The Internal category in the report is the delta over the base
checks. WARN rows there generally point at scorecard/website work that
must happen before flipping to status: published (banner uploaded,
perf.yaml generated) — not something to fix in this onboarding PR.
If an Internal check FAILs before the recipe has ever been published,
it's likely a manifest field (name style, headline period,
CANARY_DEVICES, status_reason coupling) that can be fixed immediately.
Without --internal, validate only runs the universal checks that
apply to external recipes too — you'll pass a scorecard-incomplete
manifest that the whole-repo test suite would then reject.
8. Test suite scope
In addition to the recipe's own test.py, the following whole-repo
test suites will run on every push and need to pass for an in-tree
recipe:
python -m pytest src/qai_hub_models/test/test_configs/test_manifest_yamls.py -k <id>— website-facing manifest checks (the ones listed in §3).python -m pytest src/qai_hub_models/test/test_configs/ -k <id>— dataset / template / cross-model dep graph consistency.python -m pytest src/qai_hub_models/models/<id>/test.py -v— the recipe's own tests.
External-recipe authors never see these; in-tree authors do.
9. Similar-model prior art
Base skill already tells the agent to skim existing models for pattern
reference. For in-tree work, be aggressive about this — the catalog is
the source of truth for house style. Read a simple classifier as the
minimum baseline for shape, plus one or two recent in-tree recipes in
the same task family as the model you're adding (grep
src/qai_hub_models/models/ by use_case: or domain: in their
manifests). In-tree recipes are expected to inherit heavily from
templates/<template>/ when a template exists — do NOT re-author
preprocessing/postprocessing helpers that already live under
templates/.
Non-goals of this delta
This skill does NOT restate:
- The intake flow (
onboard§Intake covers it). - Recipe file shape (
onboard§Recipe file shape). - Manifest field semantics that apply to every recipe (id shape,
required fields, license consistency, mixed-precision rules,
external-repo SHA form, python-version reasons). Those are in
onboard. - CollectionModel / SourceAsRoot / quantization / evaluator wiring —
all in
onboardand its linked sub-guides. qai-hub-models validatereport card categories —onboard§Authoring correctness.
If any of those need updating, edit
plugin/skills/onboard/SKILL.md so external and internal contributors
both get the change.