SDKcraft project definition¶
The sdkcraft.yaml file is the build-time SDK definition:
SDKcraft reads it to pack an SDK. SDK publishers author this file;
SDKcraft writes the runtime sdk.yaml (see SDK definition)
into the resulting package, copying plug, slot, and metadata fields across.
SDKcraft builds on the
craft-application
framework and
craft-parts
for build orchestration. Many fields are inherited from craft-application.
Filename and location¶
The definition file is
sdkcraft.yamlor.sdkcraft.yamlat the project root.Hooks live next to it under
hooks/; SDKcraft lints them with ShellCheck and packs them with the SDK.
Top-level fields¶
Key |
Value |
Description |
|---|---|---|
|
string |
SDK identifier. Must contain at least one lowercase letter
and may consist of lowercase letters, digits, and hyphens between them.
Up to 40 characters.
Cannot be |
|
object |
Platforms the SDK can be built on and for. See Platform entry. |
|
string |
Base operating system image the SDK targets at runtime.
One of |
|
string |
Base operating system image used to build the SDK.
Required when |
|
string |
SDK version. Semantic versioning is recommended. Note Quote version strings in YAML when they look numeric
(for example, |
|
string |
Human-readable title. |
|
string |
One-line summary, up to 78 characters. |
|
string |
Longer free-form description, up to about a hundred words. |
|
string |
License name, as it would appear in package metadata. Match the license to the actual components the SDK installs. |
|
string, array, or URL |
Contact information for the SDK publisher. |
|
string, array, or URL |
Where users should report problems with the SDK. |
|
URL |
Where the SDK’s source code is hosted. |
|
string |
Name of a part whose |
|
array |
Additional package repositories to enable while building.
Standard |
|
object |
Build instructions, in craft-parts format. See Part entry. |
|
object |
Plugs the SDK requests from the workshop environment. See Interfaces. |
|
object |
Slots the SDK provides.
Only the |
SDKcraft writes name, base, version, title,
summary, description, license, contact,
issues, source-code, plugs, and slots
straight into the runtime sdk.yaml.
The other top-level fields control the build only.
Nested structures¶
Platform entry¶
Each entry under platforms declares one build target.
The key is the platform name; the value is an object:
Key |
Value |
Description |
|---|---|---|
|
string or array of strings |
Architectures or |
|
string or array of strings |
Architectures or |
The platform name may be shorthand
for both build-on and build-for
(for example, a key of amd64 with no nested value).
Part entry¶
Each entry under parts is a craft-parts definition:
a key naming the part, with a value that specifies a plugin
and the plugin’s parameters.
SDKcraft forbids stage-packages and stage-snaps in parts;
install packages and snaps from the setup-base hook instead.
When parts is omitted,
SDKcraft supplies a default part
equivalent to default-part: {plugin: nil}.
For the full set of plugin types, lifecycle steps, and override mechanisms, see the craft-parts reference.
Interfaces¶
Plug and slot values in sdkcraft.yaml
use the same shape as in sdk.yaml.
A plug or slot value is an inline definition:
a mapping that specifies the interface
and any interface-specific attributes.
Camera interface¶
The camera interface exposes a host camera device.
Plug attributes: none.
Plug name: must be
camera.Plug owner: any regular SDK; not the system SDK.
Slot: the system SDK provides a single
system:cameraslot. Other SDKs cannot declare camera slots.
Custom device interface¶
The custom device interface exposes host devices that belong to a Linux kernel subsystem.
A custom device plug is described by this attribute:
Key |
Value |
Description |
|---|---|---|
|
string |
The Linux kernel subsystem of the host devices to expose,
for example |
Plug owner: any regular SDK; not the system SDK.
Slot: the system SDK provides a single system:custom-device slot.
Other SDKs cannot declare custom device slots.
Desktop interface¶
The desktop interface exposes the host display server.
Plug attributes: none.
Plug name: must be
desktop.Plug owner: any regular SDK; not the system SDK.
Slot: the system SDK provides a single
system:desktopslot. Other SDKs cannot declare desktop slots.
GPU interface¶
The GPU interface exposes host GPU devices.
Plug attributes: none.
Plug name: must be
gpu.Plug owner: any regular SDK; not the system SDK.
Slot: the system SDK provides a single
system:gpuslot. Other SDKs cannot declare GPU slots.
Mount interface¶
The mount interface exposes a directory between a slot owner and a plug owner.
A mount plug is described by these attributes:
Key |
Value |
Description |
|---|---|---|
|
string |
Path inside the workshop used as the plug’s target directory.
Must be an absolute path;
|
|
integer |
File permissions, in octal, applied when creating |
|
integer |
User ID applied when creating |
|
integer |
Group ID applied when creating |
|
Boolean |
Whether the target directory should be read-only.
Defaults to |
Plug owner: any regular SDK; not the system SDK.
The system SDK provides one mount slot, system:mount,
with a dynamic host-source attribute
that can be configured only at remount.
It is the only mount slot whose source is on the host filesystem.
A mount slot on a regular SDK is described by this attribute:
Key |
Value |
Description |
|---|---|---|
|
string |
Path inside the workshop used as the slot’s source directory.
Must be an absolute path;
|
SSH interface¶
The SSH interface exposes the user’s SSH agent socket.
Plug attributes: none.
Plug name: must be
ssh-agent.Plug owner: any regular SDK; not the system SDK.
Slot: the system SDK provides a single
system:ssh-agentslot. Other SDKs cannot declare SSH slots.
Tunnel interface¶
The tunnel interface forwards a network address or Unix domain socket.
Both tunnel plugs and tunnel slots take a single attribute:
Key |
Value |
Description |
|---|---|---|
|
string |
Network address or Unix domain socket that forms one end of the tunnel.
Defaults to |
The endpoint value follows this grammar:
Field |
Format |
|---|---|
Endpoint |
|
Address |
|
Protocol |
Either |
Host |
An IPv4 or IPv6 address. When a port is supplied, IPv6 addresses must be enclosed in square brackets. Supported aliases: |
Port |
A TCP or UDP port number (1-65535). May be omitted, but only on one side of a connection; both sides then use the same port. For security, tunnel plugs in the system SDK cannot use privileged ports (1-1023). |
Path |
Absolute path to a Unix domain socket.
For security, tunnel plugs in the system SDK cannot listen on sockets outside these two directories. |
String |
An abstract socket name. |
Endpoints that start with [ or @ must be quoted in YAML:
endpoint: '[::1]:8080/tcp'
endpoint: '@abstract.sock'
JSON Schema¶
The following JSON Schema is exported from SDKcraft’s project model and describes the structure above:
Note
Numeric bounds use pydantic-style ge, le, and lt keywords.
Generic JSON Schema validators will not enforce them;
treat the bounds as documentation of the accepted ranges,
and rely on the field table above for the authoritative rules.
SDKcraft project schema
{
"$defs": {
"CameraPlug": {
"additionalProperties": false,
"description": "SDKcraft project camera plug definition.",
"properties": {
"interface": {
"const": "camera",
"title": "Interface",
"type": "string"
}
},
"required": [
"interface"
],
"title": "CameraPlug",
"type": "object"
},
"CleanAbsPath": {
"type": "string"
},
"CustomDevicePlug": {
"additionalProperties": false,
"description": "SDKcraft project custom-device plug definition.",
"properties": {
"interface": {
"const": "custom-device",
"title": "Interface",
"type": "string"
},
"subsystem": {
"description": "Device subsystem.",
"examples": [
"accel",
"usb"
],
"minLength": 1,
"title": "Subsystem",
"type": "string"
}
},
"required": [
"interface",
"subsystem"
],
"title": "CustomDevicePlug",
"type": "object"
},
"DesktopPlug": {
"additionalProperties": false,
"description": "SDKcraft project desktop plug definition.",
"properties": {
"interface": {
"const": "desktop",
"title": "Interface",
"type": "string"
}
},
"required": [
"interface"
],
"title": "DesktopPlug",
"type": "object"
},
"Endpoint": {
"type": "string"
},
"FileMode": {
"$ref": "#/$defs/Int",
"ge": 0,
"le": 511
},
"GPUPlug": {
"additionalProperties": false,
"description": "SDKcraft project GPU plug definition.",
"properties": {
"interface": {
"const": "gpu",
"title": "Interface",
"type": "string"
}
},
"required": [
"interface"
],
"title": "GPUPlug",
"type": "object"
},
"Int": {
"type": "integer"
},
"MountPlug": {
"additionalProperties": false,
"description": "SDKcraft project mount plug definition.",
"properties": {
"interface": {
"const": "mount",
"title": "Interface",
"type": "string"
},
"workshop-target": {
"$ref": "#/$defs/CleanAbsPath"
},
"uid": {
"$ref": "#/$defs/UserGroupID"
},
"gid": {
"$ref": "#/$defs/UserGroupID"
},
"mode": {
"$ref": "#/$defs/FileMode"
},
"read-only": {
"default": false,
"title": "Read-Only",
"type": "boolean"
}
},
"required": [
"interface",
"workshop-target"
],
"title": "MountPlug",
"type": "object"
},
"MountSlot": {
"additionalProperties": false,
"description": "SDKcraft project mount slot definition.",
"properties": {
"interface": {
"const": "mount",
"title": "Interface",
"type": "string"
},
"workshop-source": {
"$ref": "#/$defs/CleanAbsPath"
}
},
"required": [
"interface",
"workshop-source"
],
"title": "MountSlot",
"type": "object"
},
"Part": {
"additionalProperties": true,
"type": "object"
},
"Platform": {
"additionalProperties": false,
"description": "A single platform entry in the platforms dictionary.\n\nThis model defines how a single value under the ``platforms`` key works for a project.",
"properties": {
"build-on": {
"anyOf": [
{
"items": {
"type": "string"
},
"type": "array",
"uniqueItems": true
},
{
"type": "string"
}
],
"examples": [
"amd64",
[
"arm64",
"riscv64"
]
],
"minLength": 1,
"title": "Build-On"
},
"build-for": {
"anyOf": [
{
"items": {
"type": "string"
},
"maxItems": 1,
"minItems": 1,
"type": "array"
},
{
"type": "string"
}
],
"examples": [
"amd64",
[
"riscv64"
]
],
"title": "Build-For"
}
},
"required": [
"build-on",
"build-for"
],
"title": "Platform",
"type": "object"
},
"Plug": {
"discriminator": {
"mapping": {
"camera": "#/$defs/CameraPlug",
"custom-device": "#/$defs/CustomDevicePlug",
"desktop": "#/$defs/DesktopPlug",
"gpu": "#/$defs/GPUPlug",
"mount": "#/$defs/MountPlug",
"ssh-agent": "#/$defs/SSHAgentPlug",
"tunnel": "#/$defs/TunnelPlug"
},
"propertyName": "interface"
},
"oneOf": [
{
"$ref": "#/$defs/CameraPlug"
},
{
"$ref": "#/$defs/CustomDevicePlug"
},
{
"$ref": "#/$defs/DesktopPlug"
},
{
"$ref": "#/$defs/GPUPlug"
},
{
"$ref": "#/$defs/MountPlug"
},
{
"$ref": "#/$defs/SSHAgentPlug"
},
{
"$ref": "#/$defs/TunnelPlug"
}
]
},
"PlugName": {
"description": "The name of the plug. This is used when connecting and disconnecting.\n\nThe plug name must consist only of lower-case ASCII letters (``a-z``), numerals\n(``0-9``), and hyphens (``-``). It must start with a letter, not end with a\nhyphen, and not contain two consecutive hyphens.\n",
"examples": [
"desktop",
"gpu",
"ssh-agent"
],
"pattern": "^[a-z](-?[a-z0-9])*$",
"title": "Plug Name",
"type": "string"
},
"Plugs": {
"additionalProperties": {
"$ref": "#/$defs/Plug"
},
"propertyNames": {
"$ref": "#/$defs/PlugName"
},
"type": "object"
},
"ProjectName": {
"description": "The name of the project. This is used when uploading, publishing, or installing.\n\nThe project name must consist only of lower-case ASCII letters (``a``-``z``), numerals\n(``0``-``9``), and hyphens (``-``). It must contain at least one letter, not start or\nend with a hyphen, and not contain two consecutive hyphens. The maximum length is 40\ncharacters.\n",
"examples": [
"ubuntu",
"jupyterlab-desktop",
"lxd",
"digikam",
"kafka",
"mysql-router-k8s"
],
"maxLength": 40,
"minLength": 1,
"pattern": "(?!^(system|try-.*|project-.*|sketch)$)^([a-z0-9][a-z0-9-]?)*[a-z]+([a-z0-9-]?[a-z0-9])*$",
"title": "Project Name",
"type": "string"
},
"SSHAgentPlug": {
"additionalProperties": false,
"description": "SDKcraft project SSH agent plug definition.",
"properties": {
"interface": {
"const": "ssh-agent",
"title": "Interface",
"type": "string"
}
},
"required": [
"interface"
],
"title": "SSHAgentPlug",
"type": "object"
},
"Slot": {
"discriminator": {
"mapping": {
"mount": "#/$defs/MountSlot",
"tunnel": "#/$defs/TunnelSlot"
},
"propertyName": "interface"
},
"oneOf": [
{
"$ref": "#/$defs/MountSlot"
},
{
"$ref": "#/$defs/TunnelSlot"
}
]
},
"SlotName": {
"description": "The name of the slot. This is used when connecting and disconnecting.\n\nThe slot name must consist only of lower-case ASCII letters (``a-z``), numerals\n(``0-9``), and hyphens (``-``). It must start with a letter, not end with a\nhyphen, and not contain two consecutive hyphens.\n",
"examples": [
"dashboard",
"gdb",
"toolchain"
],
"pattern": "^[a-z](-?[a-z0-9])*$",
"title": "Slot Name",
"type": "string"
},
"Slots": {
"additionalProperties": {
"$ref": "#/$defs/Slot"
},
"propertyNames": {
"$ref": "#/$defs/SlotName"
},
"type": "object"
},
"TunnelPlug": {
"additionalProperties": false,
"description": "SDKcraft project tunnel plug definition.",
"properties": {
"interface": {
"const": "tunnel",
"title": "Interface",
"type": "string"
},
"endpoint": {
"$ref": "#/$defs/Endpoint",
"default": ""
}
},
"required": [
"interface"
],
"title": "TunnelPlug",
"type": "object"
},
"TunnelSlot": {
"additionalProperties": false,
"description": "SDKcraft project tunnel plug definition.",
"properties": {
"interface": {
"const": "tunnel",
"title": "Interface",
"type": "string"
},
"endpoint": {
"$ref": "#/$defs/Endpoint",
"default": ""
}
},
"required": [
"interface"
],
"title": "TunnelSlot",
"type": "object"
},
"UserGroupID": {
"$ref": "#/$defs/Int",
"ge": 0,
"lt": 4294967295
}
},
"additionalProperties": false,
"description": "SDKcraft project definition.",
"properties": {
"name": {
"$ref": "#/$defs/ProjectName"
},
"title": {
"anyOf": [
{
"description": "A human-readable title.",
"examples": [
"Ubuntu Linux",
"Jupyter Lab Desktop",
"LXD",
"DigiKam",
"Apache Kafka",
"MySQL Router K8s charm"
],
"maxLength": 40,
"minLength": 2,
"title": "Title",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Title"
},
"version": {
"anyOf": [
{
"description": "The version of the project, enclosed in quotation marks.",
"examples": [
"\"0.1\"",
"\"1.0.0\"",
"\"v1.0.0\"",
"\"24.04\""
],
"maxLength": 32,
"title": "version string",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Version"
},
"summary": {
"anyOf": [
{
"description": "A short description of the project. Maximum length 78 characters.",
"examples": [
"Linux for Human Beings",
"The cross-platform desktop application for JupyterLab",
"Container and VM manager",
"Photo Management Program",
"Charm for routing MySQL databases in Kubernetes",
"An open-source event streaming platform for high-performance data pipelines"
],
"maxLength": 78,
"title": "Summary",
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Summary"
},
"description": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The full description of the project.",
"title": "Description"
},
"base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Base"
},
"build-base": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"title": "Build-Base"
},
"platforms": {
"additionalProperties": {
"$ref": "#/$defs/Platform"
},
"description": "Determines which architectures the project builds and runs on.",
"examples": [
"{amd64: {build-on: [amd64], build-for: [amd64]}, arm64: {build-on: [amd64, arm64], build-for: [arm64]}}"
],
"patternProperties": {
"(amd64|arm64|armhf|i386|ppc64el|riscv64|s390x)": {
"anyOf": [
{
"type": "null"
},
{
"properties": {
"build-on": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"title": "Build-On"
},
"build-for": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"title": "Build-For"
}
},
"required": [
"build-on"
],
"type": "object"
}
]
}
},
"propertyNames": {
"description": "The name of this platform. May not contain '/'",
"examples": [
"riscv64",
"my-special-platform"
],
"not": {
"enum": [
"*",
"any"
]
}
},
"title": "Platforms",
"type": "object"
},
"contact": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array",
"uniqueItems": true
},
{
"type": "null"
}
],
"default": null,
"description": "The author's contact links and email addresses.",
"examples": [
"[contact@example.com, https://example.com/contact]"
],
"title": "Contact"
},
"issues": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array",
"uniqueItems": true
},
{
"type": "null"
}
],
"default": null,
"description": "The links and email addresses for submitting issues, bugs, and feature requests.",
"examples": [
"[issues@example.com, https://example.com/issues]"
],
"title": "Issues"
},
"source-code": {
"anyOf": [
{
"format": "uri",
"minLength": 1,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The links to the source code of the project.",
"examples": [
"[https://github.com/canonical/craft-application]"
],
"title": "Source-Code"
},
"license": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The project's license as an SPDX expression",
"examples": [
"GPL-3.0+",
"Apache-2.0"
],
"title": "License"
},
"adopt-info": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Selects a part to inherit metadata from.",
"examples": [
"foo-part"
],
"title": "Adopt-Info"
},
"parts": {
"additionalProperties": {
"$ref": "#/$defs/Part"
},
"default": {
"default-part": {
"plugin": "nil"
}
},
"title": "Parts",
"type": "object"
},
"package-repositories": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "The package repositories to use for build and stage packages.",
"examples": [
"[{type: apt, components: [main], suites: [xenial], key-id: 78E1918602959B9C59103100F1831DDAFC42E99D, url: http://ppa.launchpad.net/snappy-dev/snapcraft-daily/ubuntu}]"
],
"title": "Package-Repositories"
},
"plugs": {
"$ref": "#/$defs/Plugs",
"default": {}
},
"slots": {
"$ref": "#/$defs/Slots",
"default": {}
}
},
"required": [
"name",
"platforms"
],
"title": "Project",
"type": "object"
}
Examples¶
Complex SDK that uses platforms, parts, and a mix of plugs:
name: go
build-base: ubuntu@24.04
title: Go SDK
summary: The Go programming language
description: |
Go is an open source programming language that enables the production of simple, efficient and reliable software at scale.
version: "1.25.1"
license: LGPL-2.1
platforms:
amd64:
build-on: [amd64]
build-for: [amd64]
arm64:
build-on: [amd64]
build-for: [arm64]
riscv64:
build-on: [amd64]
build-for: [riscv64]
plugs:
mod-cache:
interface: mount
workshop-target: /home/workshop/go/pkg/mod
parts:
go:
plugin: dump
source: https://go.dev/dl/go$CRAFT_PROJECT_VERSION.linux-$CRAFT_ARCH_BUILD_FOR.tar.gz
source-type: tar
Multi-base SDK with no parts:
name: multibase
version: "0.1"
summary: Multibase SDK
description: |
This is my multibase SDK description.
license: GPL-3.0
platforms:
noble:
build-on: [ubuntu@24.04:amd64, ubuntu@24.04:arm64]
build-for: ubuntu@24.04:all
jammy:
build-on: [ubuntu@22.04:amd64, ubuntu@22.04:arm64]
build-for: ubuntu@22.04:all
SDK that exposes mount and GPU plugs:
name: ros2
title: The ROS 2 SDK
base: ubuntu@24.04
version: "0.1"
summary: The strictly necessary ROS 2 development environment for your project.
description: |
The ROS 2 SDK creates a minimum viable development environment
for your ROS 2 project. It sets up a bare-bones ROS 2 workspace
before installing all of the dependencies for the ROS 2 project
mounted by workshop.
A developer can then connect to the workshop and immediately build the project.
license: LGPL-2.1
platforms:
amd64:
arm64:
plugs:
ros-cache:
interface: mount
workshop-target: /home/workshop/.ros
colcon-artifacts:
interface: mount
workshop-target: /home/workshop/colcon
gpu:
interface: gpu
See also¶
Explanation:
Reference:
Tutorial: