<a id="tut-work-with-interfaces"></a>

<a id="tut-interfaces"></a>

# Work with interfaces

<!-- @tests in tests/docs-tutorial/part-2/task.yaml -->

This is the second section of the [four-part series](https://ubuntu.com/workshop/docs//tutorial/index.md#tut-index);
it explains how to work with interfaces.
It relies on the knowledge gained in the [Get started with workshops](https://ubuntu.com/workshop/docs//tutorial/part-1-get-started.md#tut-get-started) section,
where you learned how to create and run workshops.
Here, you will learn how to make better use of SDKs in your workshop
and integrate them with the host system.

<!-- @artefact interface -->
<!-- @artefact system SDK -->

SDKs use interfaces to interact in an organized manner,
exposing the resources they provide via slots and consuming them via plugs;
the layout of these plugs and slots is defined by the SDK publishers.

For uniformity, security, and control,
various host system capabilities (camera, GPU, and so on)
are also exposed to the workshop via the same interface mechanism
with a designated system SDK.

## Manage connections

To check out the connected interfaces of a workshop, list the connections:

<!-- @artefact workshop connections -->
```console
$ workshop connections

  INTERFACE  PLUG               SLOT              NOTES
  gpu        dev/ollama:gpu     dev/system:gpu    -
  mount      dev/ollama:models  dev/system:mount  -
```

This lists two interface plugs,
both provided by the `ollama` SDK under the `dev` workshop.

The first one is a GPU interface plug named `dev/ollama:gpu`.
It enables the workshop to use the host system’s GPU
by connecting to the `dev/system:gpu` slot.

Also, there’s a mount interface plug named `dev/ollama:models`.
As seen in the **workshop info** output,
it was automatically connected at [launch](https://ubuntu.com/workshop/docs//tutorial/part-1-get-started.md#tut-launch)
to the `dev/system:mount` slot,
indicated by the ellipsis in the `host-source` path.

Note that some interfaces are auto-connected, while some are not;
this depends on their built-in security policy defined by **Workshop**.
For instance, you can’t use the ssh-agent interface
without connecting it manually.

In any case, you can connect and disconnect interfaces at will.
To check the connection state, run **workshop connections**:

<!-- @artefact workshop connect -->
<!-- @artefact workshop disconnect -->
```console
$ workshop disconnect dev/ollama:models
$ workshop connections

  INTERFACE  PLUG            SLOT            NOTES
  gpu        dev/ollama:gpu  dev/system:gpu  -

$ workshop connect dev/ollama:models :mount
$ workshop connections

  INTERFACE  PLUG               SLOT              NOTES
  gpu        dev/ollama:gpu     dev/system:gpu    -
  mount      dev/ollama:models  dev/system:mount  manual
```

You can remount a mount interface plug to a new location on the host.
For example, to preserve models,
conventionally stored under `~/.ollama/models/`,
after the workshop is removed or use some models downloaded previously,
you can remount to a directory in your home:

<!-- @artefact workshop remount -->
```console
$ mkdir -p ~/.ollama/models
$ workshop remount dev/ollama:models ~/.ollama/models
$ workshop info

  name:     dev
  base:     ubuntu@24.04
  project:  /home/user/ollama-python-project
  status:   ready
  notes:    -
  sdks:
    system:
      installed:  (1)
    ollama:
      tracking:   vulkan/stable
      installed:  0.9.6  2025-11-19  (214)
      mounts:
        models:
          host-source:      /home/user/.ollama/models
          workshop-target:  /home/workshop/.ollama/models
```

This makes `/home/user/.ollama/models/` on the host
act as the models storage for the workshop.

## Add plugs, slots

You can modify the behavior of the SDKs you installed in your workshop,
tailoring it to your needs and connecting them to other SDKs or the host system.

To do this, you add plugs and slots to the SDKs in the workshop definition,
allowing you to customize the initial plug and slot layout to your requirements.

This scenario usually arises
when you want to connect different SDKs running in the workshop
or expose some service from the workshop to the host system.

Let’s look at an example.
Add the `jupyter` SDK to the workshop
to run Jupyter notebooks with the Ollama models:

```yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: ollama
    channel: vulkan/stable
  - name: jupyter
```

```console
$ workshop refresh

  "dev" refreshed
```

<!-- @artefact tunnel interface -->

Next, add the tunnel interface plug under the `system` SDK
in the workshop definition;
this exposes the Jupyter server, now available in the workshop,
to the host system at a port of your choice (here, `8989`):

```yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: ollama
    channel: vulkan/stable
  - name: jupyter
  - name: system
    plugs:
      jupyter:
        interface: tunnel
        endpoint: 127.0.0.1:8989
```

The slot we’re going to connect this plug to comes from the SDK itself
and is named `jupyter`,
so you don’t have to add it manually:

```console
$ workshop connections --all

  INTERFACE  PLUG                SLOT                      NOTES
  gpu        dev/ollama:gpu      dev/system:gpu            -
  mount      dev/jupyter:venv    dev/system:mount          -
  mount      dev/ollama:models   dev/system:mount          -
  tunnel     -                   dev/ollama:ollama-server  -
  tunnel     dev/system:jupyter  dev/jupyter:jupyter       -
```

Refresh the workshop to enable the tunnel;
**Workshop** will auto-connect the plug to the slot by matching their names
(the plug’s name is also `jupyter`).
Check the result using **workshop info**:

```console
$ workshop refresh

  "dev" refreshed

$ workshop info

  ...
  sdks:
    system:
      installed:  (1)
      tunnels:
        jupyter:
          from:  127.0.0.1:8989/tcp
          to:    127.0.0.1:8888/tcp
  ...
```

Now, JupyterLab is available at the plug address:

```console
$ curl -w '\n' http://127.0.0.1:8989/api

  {"version": "2.17.0"}
```

#### NOTE
For additional details of using the tunnel interface, see this guide:
[How to forward ports with tunneling](https://ubuntu.com/workshop/docs//how-to/customize-workshops/forward-ports.md#how-forward-ports).

<a id="tut-jupyter-uv-venv"></a>

## Wire jupyter to a uv-managed Python environment

So far, `jupyter:venv` auto-connects to the `system:mount` slot,
which gives Jupyter a private host directory for its virtual environment.
A more interesting wiring uses the `uv` SDK,
the standard Python tooling SDK in **Workshop**;
`uv` exposes a `venv` slot
that other Python-based SDKs can plug into,
so Jupyter and uv share a single environment.

Edit the workshop definition to add `uv`
*before* `jupyter` in the `sdks:` list,
so that `uv`’s `setup-project` hook
prepares the shared virtual environment
before any consuming SDK installs into it.
Then declare the connection in a top-level `connections:` block:

```yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: ollama
    channel: vulkan/stable
  - name: uv
  - name: jupyter
  - name: system
    plugs:
      jupyter:
        interface: tunnel
        endpoint: 127.0.0.1:8989
connections:
  - plug: jupyter:venv
    slot: uv:venv
```

Apply the new definition by refreshing the workshop:

```console
$ workshop refresh
```

`dev/jupyter:venv` now connects to `dev/uv:venv`
instead of falling back to `dev/system:mount`:

```console
$ workshop connections --all

  INTERFACE  PLUG                SLOT                      NOTES
  gpu        dev/ollama:gpu      dev/system:gpu            -
  mount      dev/jupyter:venv    dev/uv:venv               -
  mount      dev/ollama:models   dev/system:mount          -
  mount      dev/uv:cache        dev/system:mount          -
  tunnel     -                   dev/ollama:ollama-server  -
  tunnel     dev/system:jupyter  dev/jupyter:jupyter       -
```

This is your first taste of slot/plug coordination
between two nonsystem SDKs;
for the full Python workflow with **uv**,
see [How to manage Python environments with the uv SDK](https://ubuntu.com/workshop/docs//how-to/develop-with-workshops/manage-python-environments.md#how-manage-python-environments).

## Next steps

This was the last step in this tutorial section; you’re halfway through!
Now you are familiar with the essentials of interfaces in **Workshop**.

Your next step is to learn even more about workshop customization,
creating experimental SDKs quickly
with the **workshop sketch-sdk** command;
proceed to the [Customize with sketch SDKs](https://ubuntu.com/workshop/docs//tutorial/part-3-sketch-sdks.md#tut-sketch-sdks) section.
