<a id="ref-sdkcraft-definition"></a>

# SDKcraft project definition

<!-- @artefact sdkcraft (CLI) -->
<!-- @artefact SDK -->
<!-- @artefact SDK 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](https://ubuntu.com/workshop/docs//reference/definition-files/sdk-definition.md#ref-sdk-definition))
into the resulting package, copying plug, slot, and metadata fields across.

**SDKcraft** builds on the
[craft-application](https://canonical-craft-application.readthedocs-hosted.com/)
framework and
[craft-parts](https://canonical-craft-parts.readthedocs-hosted.com/)
for build orchestration. Many fields are inherited from `craft-application`.

## Filename and location

<!-- @artefact SDK definition file -->
- The definition file is `sdkcraft.yaml` or `.sdkcraft.yaml`
  at the project root.
- Hooks live next to it under `hooks/`;
  **SDKcraft** lints them with [ShellCheck](https://www.shellcheck.net/)
  and packs them with the SDK.

## Top-level fields

| Key                    | Value                 | Description                                                                                                                                                                                                                                                                  |
|------------------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` (required)      | string                | SDK identifier. Must contain at least one lowercase letter<br/>and may consist of lowercase letters, digits, and hyphens between them.<br/>Up to 40 characters.<br/>Cannot be `agent`, `system`, `sketch`,<br/>or start with `try-` or `project-`; those names are reserved. |
| `platforms` (required) | object                | Platforms the SDK can be built on and for.<br/>See [Platform entry](#ref-sdkcraft-definition-platforms).                                                                                                                                                                     |
| `base`                 | string                | Base operating system image the SDK targets at runtime.<br/>One of `ubuntu@20.04`, `ubuntu@22.04`, `ubuntu@24.04`,<br/>or `ubuntu@26.04`.<br/>Omit for SDKs that work on any supported base.                                                                                 |
| `build-base`           | string                | Base operating system image used to build the SDK.<br/>Required when `base` is omitted.                                                                                                                                                                                      |
| `version`              | string                | SDK version. Semantic versioning is recommended.<br/><br/>#### NOTE<br/>Quote version strings in YAML when they look numeric<br/>(for example, `version: "1.0"`).                                                                                                            |
| `title`                | string                | Human-readable title.                                                                                                                                                                                                                                                        |
| `summary`              | string                | One-line summary, up to 78 characters.                                                                                                                                                                                                                                       |
| `description`          | string                | Longer free-form description, up to about a hundred words.                                                                                                                                                                                                                   |
| `license`              | string                | License name, as it would appear in package metadata.<br/>Match the license to the actual components the SDK installs.                                                                                                                                                       |
| `contact`              | string, array, or URL | Contact information for the SDK publisher.                                                                                                                                                                                                                                   |
| `issues`               | string, array, or URL | Where users should report problems with the SDK.                                                                                                                                                                                                                             |
| `source-code`          | URL                   | Where the SDK’s source code is hosted.                                                                                                                                                                                                                                       |
| `adopt-info`           | string                | Name of a part whose `craftctl set` commands provide<br/>`version` or `summary` at build time.<br/>Standard `craft-application` machinery.                                                                                                                                   |
| `package-repositories` | array                 | Additional package repositories to enable while building.<br/>Standard `craft-application` machinery;<br/>see the [craft-archives reference](https://canonical-craft-archives.readthedocs-hosted.com/).                                                                      |
| `parts`                | object                | Build instructions, in craft-parts format.<br/>See [Part entry](#ref-sdkcraft-definition-parts).                                                                                                                                                                             |
| `plugs`                | object                | Plugs the SDK requests from the workshop environment.<br/>See [Interfaces](#ref-sdkcraft-definition-interfaces).                                                                                                                                                             |
| `slots`                | object                | Slots the SDK provides.<br/>Only the `mount` and `tunnel` interfaces support slots here.<br/>See [Interfaces](#ref-sdkcraft-definition-interfaces).                                                                                                                          |

**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

<a id="ref-sdkcraft-definition-platforms"></a>

### Platform entry

<!-- @artefact SDK platforms -->

Each entry under `platforms` declares one build target.
The key is the platform name; the value is an object:

| Key                    | Value                      | Description                                                                                                                                   |
|------------------------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `build-on` (required)  | string or array of strings | Architectures or `<BASE>:<ARCH>` triples<br/>on which **SDKcraft** may build this platform.<br/>Entries are unique; at least one is required. |
| `build-for` (required) | string or array of strings | Architectures or `<BASE>:<ARCH>` triples this build targets.<br/>Use `all` for SDKs that ship no compiled binaries.                           |

The platform name may be shorthand
for both `build-on` and `build-for`
(for example, a key of `amd64` with no nested value).

<a id="ref-sdkcraft-definition-parts"></a>

### 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](https://documentation.ubuntu.com/craft-parts/latest/reference/parts_steps/).

<a id="ref-sdkcraft-definition-interfaces"></a>

## 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.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### Camera interface

<!-- @artefact 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:camera` slot. Other SDKs cannot declare camera slots.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### Custom device interface

<!-- @artefact 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:

<!-- @artefact custom-device interface attributes -->

| Key                    | Value   | Description                                                                                         |
|------------------------|---------|-----------------------------------------------------------------------------------------------------|
| `subsystem` (required) | string  | The Linux kernel subsystem of the host devices to expose,<br/>for example `input`, `tty`, or `usb`. |

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.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### Desktop interface

<!-- @artefact 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:desktop` slot. Other SDKs cannot declare desktop slots.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### GPU interface

<!-- @artefact 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:gpu` slot.
  Other SDKs cannot declare GPU slots.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### Mount interface

<!-- @artefact mount interface -->
<!-- @artefact $SDK -->

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                                                                                                                                                                                                                             |
|------------------------------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `workshop-target` (required) | string  | Path inside the workshop used as the plug’s target directory.<br/>Must be an absolute path;<br/>`$SDK` expands to the SDK’s installation path in the workshop.                                                                          |
| `mode`                       | integer | File permissions, in octal, applied when creating `workshop-target`<br/>and any missing parent directories.<br/>Defaults to `0o775` for regular users.<br/>When `uid` is zero, defaults to `0o755`.                                     |
| `uid`                        | integer | User ID applied when creating `workshop-target`<br/>and any missing parent directories.<br/>Defaults to `1000` when `workshop-target` is under<br/>`/home/workshop/`, `/project/`, or `/run/user/1000/`.<br/>Defaults to `0` otherwise. |
| `gid`                        | integer | Group ID applied when creating `workshop-target`<br/>and any missing parent directories.<br/>Defaults to `1000` or `0`<br/>by the same path rule as `uid`,<br/>even when `uid` is set explicitly.                                       |
| `read-only`                  | Boolean | Whether the target directory should be read-only.<br/>Defaults to `false`.                                                                                                                                                              |

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](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-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                                                                                                                                                    |
|------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `workshop-source` (required) | string  | Path inside the workshop used as the slot’s source directory.<br/>Must be an absolute path;<br/>`$SDK` expands to the SDK’s installation path in the workshop. |
<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### SSH interface

<!-- @artefact 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-agent` slot. Other SDKs cannot declare SSH slots.

<!-- Single-sourced snippet. Included by workshop-definition.rst,
sdk-definition.rst, and sdkcraft-definition.rst.
Do not add a top-level label; the including page provides the anchor. -->

### Tunnel interface

<!-- @artefact 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                                                                                                                       |
|------------|---------|-----------------------------------------------------------------------------------------------------------------------------------|
| `endpoint` | string  | Network address or Unix domain socket that forms one end of the tunnel.<br/>Defaults to `localhost/tcp` for both plugs and slots. |

The `endpoint` value follows this grammar:

| Field    | Format                                                                                                                                                                                                                                                                                                        |
|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Endpoint | `<ADDRESS>/<PROTOCOL>` for network endpoints;<br/>may be shortened to `<ADDRESS>` or `<PROTOCOL>` alone.<br/><br/>`<PATH>` or `@<STRING>` for Unix domain sockets.                                                                                                                                            |
| Address  | `<HOST>:<PORT>`; may be shortened to `<HOST>` or `<PORT>`.                                                                                                                                                                                                                                                    |
| Protocol | Either `tcp` or `udp`. Defaults to `tcp`.                                                                                                                                                                                                                                                                     |
| Host     | An IPv4 or IPv6 address.<br/>When a port is supplied, IPv6 addresses must be enclosed in square brackets.<br/><br/>Supported aliases: `localhost`, `ip6-localhost`, and `ip6-loopback`.<br/>Defaults to `localhost`.                                                                                          |
| Port     | A TCP or UDP port number (1-65535).<br/>May be omitted, but only on one side of a connection; both sides then use the same port.<br/><br/>For security, tunnel plugs in the system SDK cannot use privileged ports (1-1023).                                                                                  |
| Path     | Absolute path to a Unix domain socket.<br/><br/>`$HOME` expands to the user’s home directory<br/>and `$XDG_RUNTIME_DIR` expands to the user runtime directory<br/>(typically `/run/user/1000`).<br/><br/>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:

```yaml
endpoint: '[::1]:8080/tcp'
endpoint: '@abstract.sock'
```

## JSON Schema

<!-- @artefact SDK 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

```json
{
  "$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:

```yaml
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:

```yaml
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:

```yaml
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:

- [In-project SDKs](https://ubuntu.com/workshop/docs//explanation/sdks/concepts.md#exp-in-project-sdk)
- [SDK concepts](https://ubuntu.com/workshop/docs//explanation/sdks/concepts.md#exp-sdk-concepts)
- [SDK definition](https://ubuntu.com/workshop/docs//explanation/sdks/concepts.md#exp-sdk-definition)
- [SDK hooks](https://ubuntu.com/workshop/docs//explanation/sdks/concepts.md#exp-sdk-hooks)
- [System SDK](https://ubuntu.com/workshop/docs//explanation/sdks/concepts.md#exp-system-sdk)

Reference:

- [SDK definition](https://ubuntu.com/workshop/docs//reference/definition-files/sdk-definition.md#ref-sdk-definition)
- [Workshop definition](https://ubuntu.com/workshop/docs//reference/definition-files/workshop-definition.md#ref-workshop-definition)

Tutorial:

- [Craft SDKs with SDKcraft](https://ubuntu.com/workshop/docs//tutorial/part-4-craft-sdks.md#tut-craft-sdks)
