Skip to main content
You do not write a JobSpec by hand. sf submit builds one into the job package. Read this page when you are debugging a rejected submission, writing a tool that submits, or working through MCP. apiVersion must be forge/v2 and kind must be the training kind the SDK ships (KIND_TRAINING). Any other value is refused on both the client and the server, before anything is scheduled.

Shape

kind in code is the constant KIND_TRAINING; if a dump shows a different string, match the SDK you installed, not this sketch.

Field rules

Every rule here exists because a submission was rejected for it. They are grouped by the field, not by how surprising they are.

Handshake

Admission compares four things against the server’s catalog: the recipe name, its version, its digest, and framework.runtime_id. Any mismatch is refused. That is what sf recipe status reports and sf recipe upgrade fixes. Provenance core_version must also satisfy the requires.core range on the lock — an old CLI submitting against a newer catalog is refused with both versions named.