<a id="exp-sdk-concepts"></a>

# SDK concepts

<!-- @artefact SDK -->
<!-- @artefact SDK publisher -->
<!-- @artefact SDK Store -->

With **SDKcraft**, you can package and publish software dependencies
as isolated *SDKs* to be used in a workshop definition by **Workshop**,
instead of managing them system-wide or through container images.
SDKs encapsulate all required functionality,
keeping installations clean and limiting access to system-level capabilities.
Publishers handle installation and updates for SDKs,
freeing users from maintaining complex image definitions or configurations.

Most SDKs are designed by publishers
and made available via the SDK Store,
but some are specific to a particular project or user.
A single workshop can include multiple SDKs from different sources.
SDKs are distributed through channels similar to
[snap channels](https://snapcraft.io/docs/channels/).

<a id="exp-sdk-definition"></a>

## SDK definition

<!-- @artefact SDK definition -->

An SDK is described by two YAML files, one for building and one for installing:

- `sdkcraft.yaml`, authored by the SDK publisher,
  is the *build-time* definition consumed by **SDKcraft**.
  See [SDKcraft project definition](https://ubuntu.com/workshop/docs//reference/definition-files/sdkcraft-definition.md#ref-sdkcraft-definition).
- `sdk.yaml`, generated by **SDKcraft** and embedded in the SDK package,
  is the *runtime* definition consumed by **Workshop** at install time.
  In-project SDKs skip the build step and author `sdk.yaml` directly.

A workshop pulls SDKs together through its own `workshop.yaml`.

A build-time definition looks like this:

<!-- @artefact sdkcraft (CLI) -->
```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
```

<a id="exp-sdk-hooks"></a>

## SDK hooks

<!-- @artefact SDK -->
<!-- @artefact SDK health -->
<!-- @artefact SDK hook -->
<!-- @artefact restore-state -->
<!-- @artefact save-state -->
<!-- @artefact setup-base -->
<!-- @artefact setup-project -->

**Workshop** and **SDKcraft** enable optional lifecycle *hooks*
that control and extend the workshop’s internal behavior
to make any framework wrapped as an SDK
compatible with **Workshop**’s logic;
in particular, the hooks manage the SDK state
and report its health.

Each hook is a shell script with domain-aware actions
that **Workshop** runs in the workshop
at a particular lifecycle stage
to ensure that the SDK stays functional.
Specific examples include `setup-base`, `setup-project`,
`save-state` and `restore-state`.

You may see individual hooks mentioned in the output of
**workshop changes** and **workshop tasks**;
understanding the events that trigger them can help you with troubleshooting.

When you define an SDK,
its hooks should be placed in the `hooks/` subdirectory
next to the [definition](#exp-sdk-definition);
**SDKcraft** lints them with [ShellCheck](https://www.shellcheck.net/)
and packages them along with the `.yaml` file.

<a id="exp-workshopctl"></a>

### Using **workshopctl** with hooks

<!-- @artefact workshopd -->
<!-- @artefact workshopctl -->

The **workshopctl** CLI tool allows an SDK
to talk to the **workshopd** daemon.
Under the hood, **workshopctl** uses a socket exposed by the daemon
into the workshop environment.

Overall, the interaction between SDKs and the **workshopd** daemon
focuses on health checks in post-launch or refresh operations.

### SDK health, workshop status

<!-- @artefact check-health -->
<!-- @artefact workshop status -->

An SDK can report its health
using the `workshopctl set-health` subcommand,
which is typically invoked from the `check-health` hook
when a workshop launches or refreshes.
The command requires a health status.
If it’s not `okay`,
you can also supply an error code with a user-friendly message
to provide further details.

<!-- @artefact SDK publisher -->

This command is essential for SDK publishers
to communicate the health status of their SDKs
within the workshop environment.
Then, **workshopd** determines the overall
[health status](https://ubuntu.com/workshop/docs//explanation/workshops/concepts.md#exp-workshop-status) of a workshop,
such as *Ready*, *Pending* or *Error*;
it depends on the runtime results of the `check-health` hook:

- *Ready* means success: the hook set SDK health to `okay`
  and gracefully exited with a zero code.
- *Pending*: The hook set the SDK health to `waiting`.
  This means it will be retried, one attempt per second.
  If the retries fail 10 times consecutively
  or if 5 seconds pass without `set-health` being invoked,
  the SDK health is changed to `error`.
- *Error*: the hook exited with a nonzero code
  or explicitly set SDK health to `error`.

<a id="exp-sdk-state"></a>

## SDK state

<!-- @artefact restore-state -->
<!-- @artefact save-state -->
<!-- @artefact SDK state -->

An SDK can store any data specific to it,
such as a model training configuration,
within the workshop.
To enable this,
the SDK publisher implements save and restore [hooks](#exp-sdk-hooks)
when building the SDK using **SDKcraft**.
Later, **Workshop** runs these hooks at the appropriate moments
to consistently handle such data, collectively known as *SDK state*.

For example, before changes are applied to the workshop
during **workshop refresh**,
the states of the SDKs are saved
by invoking their `save-state` hooks.
On success,
they are restored using the `restore-state` hooks.

## SDK platforms

<!-- @artefact SDK platforms -->

Platforms describe where SDKs can be built and installed.
Some SDKs include compiled code,
which only certain families of CPUs will understand.
Others depend on particular versions of software provided by the workshop’s base image.

The `platforms` section of the [definition](#exp-sdk-definition)
lists the platforms that the SDK supports.
Each build corresponds to one of these platforms.
By default, **SDKcraft** builds SDKs for every possible platform.
This typically means all platforms
with the same CPU architecture as the build machine.

When installing an SDK,
**Workshop** will check its platform metadata for compatibility.

**Workshop** and **SDKcraft** follow [Debian’s naming scheme](https://www.debian.org/ports/)
for CPU architectures.
SDKs that don’t ship compiled binaries
can use the `all` architecture instead.

<a id="exp-system-sdk"></a>

## System SDK

<!-- @artefact system SDK -->

Every workshop contains a special *system SDK*
that exposes system resources through its slots.
It cannot be installed from the SDK Store.
Instead, it is automatically installed first during **workshop launch**
and removed last during **workshop remove**
to ensure internal consistency.

The purpose of the system SDK isn’t to add hooks or additional content;
it’s only there to uniformly expose host system resources to other SDKs.
As such, it can’t be removed by the user.
It’s also the only SDK
that can have [mount interface](https://ubuntu.com/workshop/docs//explanation/interfaces/mount-interface.md#exp-mount-interface) slots on the host.

The uniformity of this approach lies in the fact that system resources
and workshop resources are exposed using the same logic.
You can also define additional plugs and slots for the system SDK,
just as with any other SDK.

<a id="exp-sketch-sdk"></a>

## Sketch SDK

<!-- @artefact sketch SDK -->

The sketch SDK is another special type of SDK.
Like the system SDK, it’s unavailable from the SDK Store;
instead, you define it inside the workshop
using the **workshop sketch-sdk** command.
Its purpose is to allow **Workshop** users
to quickly make changes to a workshop
beside the regular SDKs listed in the [definition](#exp-sdk-definition).

Unlike a regular SDK, the sketch SDK:

- doesn’t carry any persistent data
- doesn’t appear on the definition
- is unique to the workshop where it was created

The sketch SDK can have [hooks](#exp-sdk-hooks)
and use [interfaces](https://ubuntu.com/workshop/docs//explanation/interfaces/concepts.md#exp-interface-concepts),
which allows it to interact with other SDKs.
Note that `sketch` is a reserved name,
and the sketch SDK is always installed last.

<a id="exp-test-try-sdk"></a>

## Testing and trying SDKs

<!-- @artefact sdkcraft (CLI) -->

Once an SDK is packed,
publishers have two ways to exercise it before upload.

The **sdkcraft test** command runs the SDK’s
[spread](https://github.com/canonical/spread) tests
against a freshly packed SDK.
These tests live under the SDK’s `tests/` tree
and are the publisher’s responsibility to author and maintain;
**SDKcraft** only invokes the spread harness and reports results.

The **sdkcraft try** command allows publishers to test SDKs
before uploading them to the Store.
Once installed in a workshop,
these SDKs behave identically to SDKs from the Store.

**SDKcraft** does not install SDKs in a workshop directly;
it simply copies packed SDKs to a directory called the *try area*.
**Workshop** looks in this directory
when installing an SDK with the `try-` prefix.

The try area has no channels;
only one version of an SDK can be tested at a time.
However, this version can be tested in multiple workshops with different [bases](https://ubuntu.com/workshop/docs//explanation/workshops/concepts.md#exp-base).

<a id="exp-in-project-sdk"></a>

## In-project SDKs

<!-- @artefact in-project SDK -->

An *in-project SDK* resides within your project’s `.workshop/` directory.
Unlike regular SDKs, which are published and distributed through the SDK Store,
in-project SDKs are specific to your project
and are version-controlled alongside your project’s source code.

You can create an in-project SDK by ejecting a [sketch SDK](#exp-sketch-sdk)
or by adding one manually,
creating the appropriate directory structure with `sdk.yaml` and hooks.
This approach allows you to customize the workshop
to fit your project’s unique requirements,
ensuring that all collaborators use the same environment and dependencies.

They are a good fit when your SDK includes project-specific dependencies,
tools, interface connections, or configurations
that should remain private to the project
and not be published or reused elsewhere.

## See also

Explanation:

- [Interfaces](https://ubuntu.com/workshop/docs//explanation/index.md#exp-interfaces)
- [Projects](https://ubuntu.com/workshop/docs//explanation/workshops/projects.md#exp-projects)
- [Workshops and projects](https://ubuntu.com/workshop/docs//explanation/index.md#exp-workshop)

Reference:

- [SDK definition](https://ubuntu.com/workshop/docs//reference/definition-files/sdk-definition.md#ref-sdk-definition)
- [SDK hooks](https://ubuntu.com/workshop/docs//reference/sdks.md#ref-sdk-hooks)
- [SDK internals](https://ubuntu.com/workshop/docs//reference/sdks.md#ref-sdk-internals)
- [SDKcraft project definition](https://ubuntu.com/workshop/docs//reference/definition-files/sdkcraft-definition.md#ref-sdkcraft-definition)
- [workshop changes](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-changes)
- [workshop connect](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-connect)
- [workshop connections](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-connections)
- [Workshop definition](https://ubuntu.com/workshop/docs//reference/definition-files/workshop-definition.md#ref-workshop-definition)
- [workshop disconnect](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-disconnect)
- [workshop launch](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-launch)
- [workshop refresh](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-refresh)
- [workshop start](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-start)
- [workshop tasks](https://ubuntu.com/workshop/docs//reference/cli/workshop.md#ref-workshop-tasks)
- [workshopctl (CLI)](https://ubuntu.com/workshop/docs//reference/cli/workshopctl.md#ref-workshopctl-cli)
