Model Cards
Model cards are Skulk's durable source of truth for model metadata.
They are how Skulk knows things like:
- what a model is called
- what task types it supports
- how large it is for placement and download planning
- whether it supports tensor sharding
- whether it has vision support
- whether it declares advanced model-specific behavior
What Model Cards Do
Model cards sit at the boundary between static metadata and runtime behavior.
They drive:
- placement and memory calculations
- model browsing in the API and dashboard
- custom model registration
- exact pre-publication qualification without claiming registry trust
- modality hints such as vision
- advanced capability declarations for model-specific runtime behavior
Where They Live
Skulk's current supported catalog comes from the TUF-verified external registry
at registry.foxlight.ai. A registry card represents one exact selectable
artifact—one quant or selected file—and carries an immutable card ID and signed
snapshot provenance. Registry refreshes do not require a Skulk release.
An authenticated operator may also install a complete pinned card through
POST /models/add-card. Skulk preserves its artifact bundle but strips every
signed-registry trust claim and stores it as a custom card. This lets the model
registry exercise an exact candidate on real hardware before publication while
keeping unsigned qualification separate from signed publication. Explicit
operator addition is the repository-code authorization boundary for executable
custom cards; qualification credentials do not grant that wider authority.
Headless qualification may use a dedicated
SKULK_EXACT_CARD_QUALIFICATION_TOKEN bearer for only the temporary install and
cleanup operations. The token does not approve repository code and does not
grant any wider operator or inference scope. Skulk requires the immutable source
revision and immutable pins for every external companion repository, assigns a
durable qualification_only marker only to service-authenticated installs, and
refuses to replace or remove any pre-existing non-qualification card through
this service credential. The elected master rechecks that ownership at its
serialized command-ordering boundary, closing races between different API
nodes. Success additionally requires local persistence of the indexed event
carrying that exact command ID and visibility of the exact card, so a cached
identical card cannot acknowledge a new qualification request.
Cleanup waits for its own indexed delete acknowledgement. Downloaded bytes and
their installed record remain available for later signed adoption, while the
qualification_only sidecar is deliberately excluded from catalog projection
once its lifecycle-owned custom card has been removed.
The qualification worker also sends the candidate's artifact_bundle_id to
the store download endpoint. Both the API node and canonical store verify that
identity, so a changed alias cannot redirect qualification to different bytes.
The signed catalog also carries open architecture and capability_claims
metadata beside the immutable card. Claims describe intrinsic model behavior
and selected-artifact completeness without asserting that Skulk can serve the
capability today. A separately signed engine-support matrix records exact
engine-build compatibility; neither discovery agents nor mutable card fields
can turn a claim into placement permission. Empirical load and feature
qualification is bound to the exact immutable card it tested. An explicit
artifact-scoped incomplete claim blocks matrix-derived placement for that
capability even when the base model advertises it.
Registry envelope v2 can additionally carry an artifact_bundle: a strict,
content-derived description of one complete executable artifact. It pins an
optional repository-relative loader root and the exact required files, sizes,
and upstream object identities. This lets several independently loadable quants
share one Hugging Face repository and revision without collapsing into one
card. Existing v1 cards remain valid and retain their historical download
behavior.
Complete canonical and staged artifacts retain their full effective card and
hashed manifest beside the bytes in .skulk/installed-card.json. These
installed cards load before registry access, remain usable indefinitely while
their artifact is complete, and keep an older installed generation active until
a replacement has transferred and verified atomically.
Skulk ships no model cards. When a model is downloaded, so is its card. A node's catalog has three sources: signed registry cards (from the registry, or from its verified cache for up to 30 days during an outage), the installed cards of its downloaded models (including detached records for models under a read-only model root), and custom cards. Installed cards stay local and have no expiry, so they keep working offline.
When neither the registry nor an acceptable cache is available, Skulk reads the
last verified registry catalog cached on the node without its age limit. It
uses that cache only to associate legacy installed artifacts that predate card
records with their signed card; an associated artifact gains its own card
record and is then listed. The cached catalog is never listed or placed from by itself.
SKULK_OFFLINE=true and skulk --offline both skip registry network
refreshes, so the catalog is the installed and custom cards.
A node that has never reached the registry and has no installed model and no
custom card has an empty catalog. It logs a warning that names the cause and
the remedies: connect once, copy a model directory together with its
.skulk/installed-card.json, or add a custom card.
Curated cards are maintained in the model registry's seed,
foxlight-model-registry/seed/cards.
Card edits go there, never into Skulk.
Custom cards are stored under the user data directory and synced through the
cluster event flow. They are operator-owned and retain final precedence over
registry and installed cards for the same model_id. Deleting a custom card
restores the signed or installed card for that model_id, or removes the
model from the catalog when neither exists.
The card interface (source of truth)
The authoritative definition of the model-card interface is the ModelCard
type in
src/skulk/shared/models/model_cards.py.
Every field is documented in that model, and the exhaustive, always-current field
reference is the generated API schema (ModelCard and its nested
PlacementCardConfig / RuntimeCapabilityCardConfig / VisionCardConfig /
ReasoningCardConfig / ModalitiesCardConfig / ToolingCardConfig /
AudioCardConfig / MusicCardConfig / VideoCardConfig /
LicenseCardConfig / ArtifactBundleConfig / ComponentInfo) in the
API reference. This page is the curated
narrative; when in doubt about an exact field, the schema is canonical.
Cards are camelCase on the wire and strict (unknown fields are rejected), so every node in a cluster must run the same Skulk version.
The registry validates the persisted card body against its own strict schema before signing it. Its model-card contract maps field groups and publication evidence. When a card section changes, update both schema readers and both guides before publishing cards that use it.
| Card surface | Source of truth | Runtime meaning |
|---|---|---|
| Identity and bytes | model_id, source_repository, source_revision, gguf_file, artifact_bundle | One selected artifact and complete pinned download. |
| Intrinsic behavior | tasks and typed sections such as [audio], [music], and [video] | What the selected model can do and which request fields it accepts. |
| Compatibility | [placement] and separate signed engine-support claims | Candidate backends and exact qualified model/build/hardware combinations. |
| Live admission | NodeResources.engine_builds, hardware facts, and Skulk runner limits | Whether a particular node is ready to serve the card now. |
A valid artifact card is not by itself a live placement claim. The engine package, model weights, signed support decision, and current node resources remain separate truths.
Core Fields
Identity and size
model_id- selectable artifact alias; legacy and custom cards normally use the Hugging Face repository id, while registry cards may give two exact files or quants from one repository different aliases
source_repository- optional upstream Hugging Face repository containing the bytes; defaults to
model_idand is set by the registry when the selectable alias differs from the byte origin
- optional upstream Hugging Face repository containing the bytes; defaults to
storage_size- total model size used for store/download/placement planning
n_layers- number of transformer layers used for pipeline sharding
hidden_size- hidden dimension used for placement and compatibility checks
num_key_value_heads- optional KV head count for tensor compatibility decisions
gguf_file- for GGUF models, including music: the exact repository-relative weights file selected by the card (the selected quant's first shard for text GGUF);
nullfor safetensors/MLX cards
- for GGUF models, including music: the exact repository-relative weights file selected by the card (the selected quant's first shard for text GGUF);
source_revision- optional full Hugging Face commit hash for the qualified model artifacts; when set, metadata, store downloads, direct downloads, and worker staging all use that immutable revision instead of the repository's mutable
mainbranch
- optional full Hugging Face commit hash for the qualified model artifacts; when set, metadata, store downloads, direct downloads, and worker staging all use that immutable revision instead of the repository's mutable
artifact_bundle- optional signed v2 manifest for one exact executable artifact:
root,files(repository-relativepath,size_bytes, and optional immutableobject_id), content-derivedbundle_id, anddownload_size - signed v2 cards require this manifest to be internally consistent. Paths are canonical POSIX-relative paths and cannot escape the repository or the declared artifact root
- the loader runs from
rootwhen set, while file paths such asgguf_fileremain repository-relative for compatibility
- optional signed v2 manifest for one exact executable artifact:
components- for multi-component models (such as a diffusion stack): the per-component weight layout;
nullfor a single-weights model
- for multi-component models (such as a diffusion stack): the per-component weight layout;
Runtime and placement
supports_tensor- whether tensor-style placement is allowed (GGUF/llama.cpp cards set this
false)
- whether tensor-style placement is allowed (GGUF/llama.cpp cards set this
tasks- supported task families such as
TextGeneration,TextEmbedding, image tasks,TextToSpeech,SpeechToText,SpeechTranslation, orTextToMusic
- supported task families such as
trust_remote_code- whether the artifact requires repository-supplied Python; signed publication authorizes the exact immutable registry card regardless of provenance
- explicitly adding an external model authorizes its pinned card, and an omitted Hugging Face revision is resolved to one immutable commit before the card is created; an installed card without a registry identity, recorded from a card an earlier Skulk release shipped, stays authorized by that release
- legacy executable custom cards that predate immutable revision pinning fail closed and must be re-added through the operator flow; an absent revision can never silently authorize mutable
main - ordinary catalog reads and placement requests never fetch or persist an unknown Hub card; callers must use an authenticated add flow first, and exact-placement payloads must match that effective catalog card completely
- this field controls the loader's repository-code behavior, not a second operator approval ceremony; artifact identity and immutable revision checks still fail closed
uses_cfg- whether the model uses classifier-free guidance (relevant to some image/diffusion models)
generator_revision- optional version of the card generator used to produce a curated card; it is metadata about card production, not a mutable model revision
Catalog metadata
-
registry_card_id/registry_snapshot_id/registry_provenance- provenance is signed catalog metadata (
foxlight,agent, orcommunity) and is deliberately excluded from the content-derived card identity - runtime provenance attached by the verified external catalog; these are absent from custom cards and from installed cards without a registry identity
- provenance is signed catalog metadata (
-
registry_architecture/registry_capability_claims- signed intrinsic architecture and model/artifact capability evidence from the registry envelope; persisted into installed sidecars for air-gapped use
- these fields do not declare present-day Skulk compatibility. Placement may expand only from a separate exact signed engine/build support decision.
-
family- coarse family label such as
gemma,qwen,deepseek
- coarse family label such as
-
quantization- human-facing quantization label
-
base_model- display-friendly base model name
-
context_length- advertised context length if known
-
capabilities- coarse capability list such as
text,vision,thinking,embedding,tts, orstt
- coarse capability list such as
These coarse capabilities remain useful for browsing, badges, and basic compatibility, but they are not expressive enough for model-specific runtime behavior on their own.
Vision Section
[vision] is the existing structured section for multimodal text-generation models.
Fields include:
image_token_id- token used to represent image slots in prompt tokenization
model_type- MLX-VLM model family identifier such as
gemma4
- MLX-VLM model family identifier such as
weights_repo- optional alternate weights repository for the vision tower
weights_revision- full immutable commit for a separate
weights_repo; required for signed-registry cards
- full immutable commit for a separate
image_token- optional literal image token string
processor_repo- optional alternate processor repository
processor_revision- full immutable commit for a separate
processor_repo; required for signed-registry cards because processor loaders may execute repository Python
- full immutable commit for a separate
boi_token_id- optional begin-of-image token id
eoi_token_id- optional end-of-image token id
projector_file- exact repository-relative GGUF multimodal projector selected for served
vision; when present,
gguf_fileand a full immutablesource_revisionare also required
- exact repository-relative GGUF multimodal projector selected for served
vision; when present,
projector_size- exact positive byte size of
projector_fileatsource_revision; it must appear together withprojector_file
- exact positive byte size of
Legacy GGUF vision cards without an exact projector pin remain loadable through
the in-process llama_cpp path. llama_server becomes eligible only when both
projector fields are present, so the served runner never guesses among upstream
projector variants.
Placement Section
[placement] declares where a model is allowed to run and which backend is
preferred. It is what the planner reads to route a model to suitable nodes, and
it is how a heterogeneous cluster keeps each model on hardware that can run it.
Backends are named <engine>-<compute> tags (for example mlx-metal,
llama_cpp-vulkan, llama_cpp-rocm, llama_cpp-cpu). The engine selects the
worker runner; the compute names the accelerator. A bare engine tag (e.g. mlx)
is also valid vocabulary: nodes advertise it alongside their compound tags, so a
card written against the original {"mlx"} set keeps matching.
compatible_backends- the declared backend set, combined with exact supported matches from the signed engine-support matrix and then filtered by live node and runner support. The planner excludes nodes that match no effective backend. The default is
{"mlx"}(so an unannotated card stays on MLX nodes); a GGUF card lists the llama.cpp tags. This keeps MLX artifacts on nodes with MLX support and GGUF artifacts on a compatible GGUF engine; the artifact format does not by itself exclude a Mac.
- the declared backend set, combined with exact supported matches from the signed engine-support matrix and then filtered by live node and runner support. The planner excludes nodes that match no effective backend. The default is
backend_preference- the soft score: an ordered list of preferred tags. When several compatible nodes qualify, the planner prefers the node whose backend ranks earliest, with graceful fallback to the rest. This lets a card say "fastest on Vulkan, but ROCm is fine."
min_vram_gib- optional minimum accelerator memory a node must have to be eligible.
max_context_tokens- optional cap on the admission context for this model, independent of the model's trained context length.
max_pipeline_split_layer- optional largest layer boundary where a later pipeline rank may begin. Use it when a model's tail reuses KV from earlier concrete layers; the planner shifts proportional boundaries left as needed and reruns normal per-node memory checks so the final rank owns every producer it consumes.
Extended Capability Sections
Skulk now supports optional structured sections that declare refined model behavior.
Existing cards do not need these sections. If they are absent, Skulk falls back to generic behavior.
[reasoning]
Declares advanced reasoning behavior:
supports_toggle- whether thinking/reasoning can be explicitly enabled or disabled
supports_budget- whether the model supports a reasoning budget control
format- reasoning marker format such as
channel_delimitedortoken_delimited
- reasoning marker format such as
default_effort- reasoning effort used when thinking is enabled without an explicit effort
disabled_effort- reasoning effort used when thinking is explicitly disabled
[modalities]
Declares refined modality support:
supports_audio_input- whether the model supports audio input
supports_native_multimodal- whether the model uses a native multimodal path rather than generic text-only prompting
[audio]
Declares speech serving metadata for TTS and STT models:
kindttsfor text-to-speech orsttfor speech-to-text
default_response_format- default encoded audio format for TTS, such as
mp3
- default encoded audio format for TTS, such as
response_formats- encoded audio formats the model can produce, such as
mp3,wav,flac,ogg, oropus
- encoded audio formats the model can produce, such as
supports_streaming- whether the model can stream partial speech or transcription output; keep this false until the Skulk runtime has validated the model/backend path
supports_realtime- whether the model exposes a realtime audio session interface
supports_voice_listing- whether voices can be enumerated by the serving API
voices- stable model-native or bundled-reference identifiers returned by
GET /v1/audio/voices; this requireskind = "tts"andsupports_voice_listing = true
- stable model-native or bundled-reference identifiers returned by
voice_catalog- optional ordered metadata for every identifier in
voices; each entry carries the sameid, a displayname, and ordered BCP 47preferred_languagesused by clients for deterministic language matching;reference_profilenames a checksummed profile underresources/speech_reference_voices/when the voice is reference-conditioned
- optional ordered metadata for every identifier in
default_voice- stable voice used when a TTS request omits
voice; it must appear invoices
- stable voice used when a TTS request omits
supports_reference_audio- whether managed reference audio can condition the voice
supports_translation- whether speech-to-English translation is supported through the
standard
/v1/audio/translationsroute
- whether speech-to-English translation is supported through the
standard
sample_rates- supported input or output sample rates in hertz
For stable TTS streaming, audio.supports_streaming = true is the model-side
eligibility gate; the model must also be mounted and ready.
For realtime STT, both supports_streaming = true and
supports_realtime = true are necessary but not sufficient. The API must have
reachable ready single-host capacity and use a model whose upstream runtime
exposes a true incremental streaming session. The registry's
mlx-community/Voxtral-Mini-4B-Realtime-2602-4bit card is the first validated
contract candidate. Batch Parakeet and Whisper cards deliberately keep both
flags false.
[music]
Declares text-to-music model truth. A music card has tasks = ["TextToMusic"]
as its sole task, a complete artifact_bundle, and no speech [audio]
section. The registry derives music.generate from that task; it does not
classify every upstream text-to-audio repository as music.
familyminimax_music3orace_step_1_5; the music adapter uses this typed value to translate Skulk's request into family-specific engine options. The top-levelfamilyis a separate coarse model label.
lyricsrequired,optional, orunsupported; MiniMax Music 3 requires lyrics.
min_seconds/max_seconds- positive accepted generation targets with
min_seconds <= max_seconds <= 120. A target is a request budget, not a promise of exact WAV duration.
- positive accepted generation targets with
language_model_gguf/rvq_depth_decoder_gguf/flow_transformer_gguf- the three MiniMax GGUF components selected by this exact card. Their paths are relative to the bundle's loader root, have matching component roles, and must occur in the bundle. ACE-Step does not use these fields.
MiniMax's selected language model is also the card's gguf_file. Its bundle
contains that model, the selected RVQ decoder and flow transformer, plus the
required conditioner, vocoder, tokenizer, and configuration files. ACE-Step
selects one GGUF as gguf_file; its bundle contains only that file. See the
registry's complete MiniMax Q4
and ACE-Step Turbo BF16
cards for exact component identities and sizes. Each other quant or selected
variant requires its own card.
Both initial music cards set placement.compatible_backends = []. That means
they do not claim legacy backend compatibility. A signed supported claim
must match the exact card, audio.cpp build, music.generate capability,
architecture, and applicable hardware class after load and generation
qualification. The node must also report that same ready build before Skulk
will place it. Installing the audio.cpp package alone grants no model support.
Music placement resolves a concrete audio_cpp-cpu, audio_cpp-metal,
audio_cpp-vulkan, audio_cpp-cuda, or audio_cpp-rocm lane. The bare
audio_cpp tag reports engine availability but cannot select a music runner.
The Strix Vulkan qualification record
documents the exact build, hardware class, and initial card results behind
that lane's claims.
[video]
Declares audio-video generation truth independently of an engine. modes
contains t2va, fl2va, or ref2va, and the card's video tasks must match
those modes. Duration bounds, fps, frame-grid and canvas multiples, aspect
ratios, pixel limits, and sampling defaults constrain requests. audio_output
requires audio_sample_rate and audio_channels. ref2va requires typed
reference_limits. companions pin adapters, patches, embeddings, or graph
templates to their source revision and declared modes. The generated
VideoCardConfig schema in the API reference lists every
field and its type.
[license]
Records operator-facing name, optional url, spdx_id, notice, and
display_name. These facts help an operator review the selected artifact's
terms and attribution. Skulk does not enforce license conditions at download
or placement time.
[tooling]
Declares tool-calling behavior:
supports_tool_calling- whether tool calling is supported
builtin_tools- optional list of builtin platform tool contracts such as
web_search,open_url, orextract_page
- optional list of builtin platform tool contracts such as
tool_call_format- expected tool-call output format such as
generic,gemma4,gpt_oss,dsml, oratem(Muse Glimmer's<atem:function_calls>markup)
- expected tool-call output format such as
[runtime]
Declares runtime integration preferences:
prompt_renderer- prompt renderer to use, such as
tokenizer,gemma4, ordsml
- prompt renderer to use, such as
output_parser- output parser to use, such as
generic,gemma4,gpt_oss,deepseek_v32, ormuse_glimmer(theto=self/to=user/to=<tool>channel grammar)
- output parser to use, such as
metal_fast_synch- per-model override for the MLX
MLX_METAL_FAST_SYNCHflag; set tofalsefor models that deadlock under FAST_SYNCH on the ring backend
- per-model override for the MLX
mtp_heads- set to
truewhen the model has native MTP prediction heads available via sidecar; required alongsidemtp_sidecar_repoto enable speculative decoding
- set to
mtp_max_depth- maximum draft depth the MTP heads support; start at
1for Apple Silicon (deeper values rarely amortize on Metal due to near-linear verify-pass scaling)
- maximum draft depth the MTP heads support; start at
mtp_sidecar_repo- Hugging Face repo ID containing the published
mtp.safetensorssidecar (e.g."FoxlightAI/qwen3-5-9b-base-mtp"); produced by SWP (Skulk Weights Publisher) from the original BF16 checkpoint
- Hugging Face repo ID containing the published
mtp_sidecar_revision- full immutable commit for a separately hosted MTP sidecar; required for signed-registry cards
mtp_norm_convention- how the MTP heads normalize hidden states (
zero_centeredoractual_scale); must match how the sidecar was produced
- how the MTP heads normalize hidden states (
mtp_concat_order- the order the MTP heads concatenate the embedding and hidden state (
embed_firstorhidden_first); must match the sidecar
- the order the MTP heads concatenate the embedding and hidden state (
speculative_multi_node- set to
falseto forbid speculative decoding when the model is sharded across multiple nodes (it stays single-node speculative); the runner and the generation loop read this to make the same rank-symmetric decision
- set to
assistant_model_repo- Hugging Face repo of a small companion model used as an external drafter for speculative decoding (the Gemma 4 path), as opposed to native MTP heads
assistant_model_revision- full immutable commit for a separately hosted assistant; required for signed-registry cards
Separate served_spec_draft_repo and vllm_spec_draft_repo companions likewise
require served_spec_draft_revision and vllm_spec_draft_revision. A companion
in the base artifact repository inherits the card's source_revision.
MTP Speculative Decoding
Some models include native multi-token prediction (MTP) heads baked into their checkpoint weights. Skulk uses these heads for speculative decoding: the MTP heads draft candidate tokens cheaply, a full forward pass verifies them, and accepted tokens are emitted in bulk, substantially increasing throughput with no accuracy loss.
Why a sidecar
Standard quantization pipelines (including mlx-lm's sanitize()) strip mtp.* tensor keys at conversion time. The MLX-quantized checkpoint you download from Hugging Face typically does not contain MTP weights.
SWP solves this by re-extracting the mtp.* tensors from the original BF16 checkpoint, quantizing only those tensors, and publishing the result as mtp.safetensors to a dedicated sidecar repo on Hugging Face. This is the same pattern Skulk uses for vision encoder weights.
How it works
When a model card declares mtp_heads = true and mtp_sidecar_repo, Skulk:
- Downloads
mtp.safetensorsfrom the sidecar repo alongside the base model weights. - Loads the sidecar at model load time and makes the weights available to the runner.
- Uses the MTP heads during generation for speculative decoding (on runners that support it).
If the sidecar is declared but the file is not found locally, Skulk logs a warning and continues with standard autoregressive generation.
Models with native MTP heads
The registry cards that declare an MTP sidecar include the Qwen3.5 and Qwen3.6 quantizations:
mlx-community/Qwen3.5-2B-4bitmlx-community/Qwen3.5-9B-MLX-4bitmlx-community/Qwen3.5-27B-4bitmlx-community/Qwen3.6-27B-4bit
Gemma 4 does not use native MTP heads; it uses an external drafter model (assistant_model_repo) for speculative decoding, which is a separate feature.
Adding MTP to a card
[runtime]
mtp_heads = true
mtp_max_depth = 1
mtp_sidecar_repo = "FoxlightAI/qwen3-5-9b-base-mtp"
mtp_sidecar_revision = "06c840b3529f5695648807d993b1cb48b576a988"
The sidecar repo must be published by SWP before adding these fields. See the SWP documentation for how sidecars are produced and published.
Speculation on the served (GGUF) engine
The sidecar path above is MLX-only. GGUF cards that run under the served
llama-server engine declare speculation through a different set of [runtime]
fields: served_spec_type, served_spec_n_max, served_spec_draft_repo, and
served_spec_draft_file. See Speculative Decoding for
how those fields map to the served backend.
Declarative vs Resolved
The model card is the declarative capability source.
At runtime, Skulk resolves the card plus tokenizer/model-family facts into a normalized execution profile. That resolved profile is what prompt rendering, reasoning defaults, and output parsing consume.
That gives Skulk three good properties:
- old cards remain valid
- advanced cards unlock refined behavior
- runtime code can rely on normalized values instead of ad hoc optional checks
Resolution Precedence
When Skulk resolves a runtime capability profile, it uses this order:
- explicit advanced model-card declarations
- conservative family/model heuristics
- generic fallback behavior
That means a custom or registry card can refine behavior without breaking old cards that only declare coarse metadata.
Extended Card Example
This is a minimal example of a custom card that opts into refined runtime behavior:
model_id = "custom/gemma-compatible"
n_layers = 10
hidden_size = 1024
supports_tensor = false
tasks = ["TextGeneration"]
family = "gemma"
capabilities = ["text", "vision", "thinking"]
[storage_size]
in_bytes = 1073741824
[reasoning]
supports_toggle = true
format = "channel_delimited"
default_effort = "medium"
disabled_effort = "none"
[modalities]
supports_native_multimodal = true
[tooling]
tool_call_format = "gemma4"
[runtime]
prompt_renderer = "gemma4"
output_parser = "gemma4"
The card stays declarative. Skulk still resolves it into a normalized runtime profile before execution code consumes it.
Speech cards use the same pattern:
model_id = "custom/kokoro-tts"
n_layers = 1
hidden_size = 1
supports_tensor = false
tasks = ["TextToSpeech"]
family = "kokoro"
capabilities = ["tts"]
[storage_size]
in_bytes = 1073741824
[placement]
compatible_backends = ["mlx_audio", "mlx_audio-metal"]
backend_preference = ["mlx_audio-metal", "mlx_audio"]
[audio]
kind = "tts"
default_response_format = "mp3"
response_formats = ["mp3", "wav"]
# Set true only after the Skulk runtime validates this model/backend streaming path.
supports_streaming = true
supports_realtime = false
supports_voice_listing = true
voices = ["serena", "ryan"]
default_voice = "ryan"
supports_reference_audio = false
sample_rates = [24000]
[[audio.voice_catalog]]
id = "serena"
name = "Serena"
preferred_languages = ["zh"]
[[audio.voice_catalog]]
id = "ryan"
name = "Ryan"
preferred_languages = ["en"]
For a reference-conditioned voice, the catalog ID and reference_profile must
match and the card must declare supports_reference_audio = true:
[[audio.voice_catalog]]
id = "angus"
name = "Angus"
preferred_languages = ["en"]
reference_profile = "angus"
The central profile manifest pins the local MP3 digest and exact transcript. Model cards intentionally repeat the public voice order so API and dashboard behavior remain explicit model truth; CI verifies the cloning cards among Skulk's test fixtures against the central manifest.
When to Extend a Card
Extend a card when:
- the model needs special prompt rendering
- the model uses a non-generic reasoning format
- the model supports modalities or controls that generic metadata cannot express
- the dashboard or API needs to expose richer behavior safely
For concrete examples, see Model Capabilities and the per-family notes in Model Behaviors.