Get started with workshops

This is the first section of the four-part series; a practical introduction that takes you on a tour of the essential Workshop activities.

A workshop is a development environment running in a container, mapping your project to its contained dependencies. Here, you will practice all the major steps in the lifecycle of a workshop, from defining, launching, and refreshing it to executing commands and shelling into the workshop. The steps you’re about to perform cover most of your daily needs with Workshop.

Install Workshop

Install Workshop, upgrading the prerequisites if needed, then ensure it runs.

Prerequisites

Workshop is supported on Ubuntu and other snap-enabled Linux distributions; it is also compatible with Windows Subsystem for Linux (WSL2), where it uses Btrfs instead of ZFS for storage.

Workshop relies on LXD 6.8+ for low-level operation and uses its REST API to handle individual workshops.

To install it from scratch with snap:

$ sudo snap install --channel=6/stable lxd

To refresh an existing snap installation:

$ sudo snap refresh --channel=6/stable lxd

Note

If you prefer another installation method, see the available installation options in LXD documentation; after installation, make sure the LXD daemon is enabled and running. If in doubt, refer to LXD documentation and your distribution’s manuals for guidance.

Installation

Install the snap using the --classic option:

$ sudo snap install --classic workshop

Launch a workshop

Now you’ll learn how to define, launch, start and stop a workshop.

Define, add SDKs

First, you need to define a workshop. A definition is a YAML file that is stored in your project directory; it lists the components of the workshop to be instantiated at launch.

A definition can list many moving parts; perhaps, the most important are SDKs, which are basic, predefined building blocks of your development environment.

You reference SDKs from your workshop definition to specify what you want to include in your workshop. At runtime, Workshop pulls and installs them, providing the dependencies and packages required for your work, while keeping the SDKs themselves isolated and manageable.

For demonstration purposes, assume we want to work with AI models using the Ollama platform. To do this, let’s use the ollama SDK, which provides a local AI model server.

Before adding an SDK to a workshop, search the SDK Store to confirm it exists and check its publisher and current version:

$ sdk find ollama

  NAME    VERSION  PUBLISHER     SUMMARY
  ollama  0.20.2   Canonical     Get up and running with large language models

The query also matches an SDK’s title, summary, description, or publisher, so a broader keyword like sdk find ai can surface AI-related SDKs on the Store.

To see which channels and bases are available for a specific SDK, inspect its details:

$ sdk info ollama

  name:       ollama
  publisher:  Canonical (canonical)
  license:    MIT

  Get up and running with Llama 3.3, ...

  CHANNELS
    CHANNEL        VERSION  BUILD       BASE          REV   SIZE
    latest/stable  0.20.2   2026-04-15  ubuntu@24.04    7  2.27GB
                                        ubuntu@22.04    8  2.27GB
    ...
    cpu/stable     0.20.2   2026-04-15  ubuntu@24.04    2  15.22MB
                                        ubuntu@22.04    5  15.22MB
    cpu/candidate  ^
    cpu/beta       ^
    cpu/edge       ^

The CHANNELS table lists each track (here, latest, cpu, cuda, rocm, and vulkan) at four risk levels (stable, candidate, beta, edge), the bases each revision supports, and its on-disk size. For this tutorial, we’ll use cpu/stable, which runs on any machine without GPU hardware.

For the project directory, create a new Python repository:

$ mkdir ollama-python-project
$ cd ollama-python-project
$ git init

Everything you handle with your workshop goes here: your Python code, custom assets, and so on.

In the project directory, create a workshop definition named workshop.yaml:

workshop.yaml
name: dev
base: ubuntu@22.04
sdks:
  - name: ollama
    channel: cpu/stable

Here, the SDK is referenced as ollama, and the specific version to retrieve from the SDK Store comes from the cpu/stable channel of the the cpu track.

To confirm that Workshop sees the definition, list the workshops in the project directory:

$ workshop list

  WORKSHOP  STATUS  NOTES
  dev       Off     -

Note

Workshop ships shell completion for Bash, Zsh, Fish, and PowerShell; if you installed via snap, it is already enabled. Press Tab as you type any workshop command to autocomplete subcommands, flags, and arguments.

Completion is context-aware: each command offers only values that make sense for it. For instance, workshop start autocompletes from Stopped workshops only, workshop stop from Ready ones, and workshop connect autocompletes available plugs and then the matching slots.

As the command output suggests, your newly defined workshop is Off, so it needs to be launched.

Note

The command lists all workshops within the project; the tutorial focuses on a single-workshop setup, but your project can have multiple workshops defined.

For a detailed explanation of the workshop status values, see the Workshop status section.

Note

The tutorial uses Ollama for demonstration purposes only. This doesn’t imply that Workshop is intended solely for AI; quite the contrary, it’s envisioned as language-neutral and framework-agnostic.

Launch, start, and stop

To get a workshop ready for use, you launch it:

$ workshop launch

  "dev" launched

Once the workshop is launched, you can start using it to build, debug, and run your code.

After launching, check the runtime information to see what went into your workshop:

$ workshop info

  name:     dev
  base:     ubuntu@22.04
  project:  /home/user/ollama-python-project
  status:   ready
  notes:    -
  sdks:
    system:
      installed:  (1)
    ollama:
      tracking:   cpu/stable
      installed:  0.20.2  2026-04-15  (5)
      mounts:
        models:
          host-source:      .../6b79e889/dev/mount/ollama/models
          workshop-target:  /home/workshop/.ollama/models

The output looks like the definition with extra details such as the mounts; ignore these for now.

While workshop info shows the SDKs from one workshop’s perspective, sdk list reports every SDK volume currently stored on the machine, regardless of which workshop pulled it:

$ sdk list

NAME    VERSION  REV  SIZE
ollama  0.20.2     5  15.22MB
system  -          1  25.09kB

Each row is a distinct SDK volume on disk. Until you launch a workshop that references an SDK, it won’t appear here; at launch, Workshop has pulled the SDK from the SDK Store and the revision shown matches the one in workshop info.

After launch, Workshop tracks the project directory using a hidden .lock file that must remain in the project directory and not be copied or stored externally, e.g., in a repository.

You only need to launch a workshop once after defining it; after any substantial changes to it, you do a refresh. Otherwise, the workshop is just a fancy container that can be started and stopped.

The workshop starts automatically at launch, but you can also stop and restart it at will. Suppose you want to free up some resources, so you stop the workshop:

$ workshop stop

This changes the status of the workshop to Stopped.

To make it Ready again, start the workshop:

$ workshop start

Both commands work gracefully, waiting for the workshop to comply:

  • workshop stop doesn’t destroy the workshop, unlike remove

  • workshop start doesn’t build it from scratch, unlike launch or refresh

In the next step, you’ll refresh an existing workshop.

Note

If issues arise now or later, see these guides: How to troubleshoot Workshop and How to debug issues in workshops.

Note

Consider adding the .lock file to your .gitignore or similar ignore files:

$ echo ".workshop.lock" >> .gitignore

In contrast, the definition and the .workshop/ directory are meant to be stored in a repository; if your .gitignore file uses rules such as “ignore everything except these files and directories,” add them to the list of explicitly tracked items.

Refresh a workshop

Sometimes the base or the SDKs listed in your workshop definition are updated by their publishers. Alternatively, you may have changed the definition to switch bases, add and remove SDKs, or toggle their channels. A good example is when a new Ubuntu LTS version is released and, as a result, a new base image becomes available. In either case, you must refresh the workshop to apply the updates.

For example, change the base and the SDK channel in your definition and refresh the workshop:

workshop.yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: ollama
    channel: vulkan/stable
$ workshop refresh

After the refresh, sdk list may show multiple revisions of ollama if the previous cpu/stable volume is still on disk alongside the freshly pulled vulkan/stable one.

Running workshop refresh is similar to a launch. However, it ensures the workshop remains operational. If issues occur, a refresh rolls back to a previous stable condition, whereas a failed launch has no condition to revert to and just fails.

SDKs in a workshop diagnose themselves during launch and refresh; if an SDK fails to set up, the entire change is rolled back to keep the workshop operational.

Finally, to discard any changes made inside the workshop since the last successful launch or refresh, run workshop restore. Unlike the automatic rollback on a failed refresh, this is a deliberate action that reverts the workshop to the most recent snapshot and resets it to its default state.

Now that you can launch, refresh, start and stop a workshop, let’s move on to more practical purposes.

Execute commands

When the workshop is Ready, you can run arbitrary commands in it. In this tutorial, we’re working with Ollama AI models, and we’ve already created a Python project directory to serve as our workspace.

First, let’s put our example workshop to practical use; download a simple AI model inside the workshop using the workshop exec command. We’ll use the tinyllama model, which is small and quick to download:

$ workshop exec dev -- ollama run tinyllama

This downloads and then runs the tinyllama model. The model will be stored in the mounted models/ directory, so it persists between workshop refreshes. Quit the Ollama console by pressing Ctrl+D.

You can also list the available models:

$ workshop exec dev -- ollama list

  NAME                ID              SIZE      MODIFIED
  tinyllama:latest    2644915ede35    637 MB    24 seconds ago

Furthermore, your work files and deliverables, however complex they may be, can reside on the host system, while the toolchain is transparently confined and managed by Workshop. This enables you to focus on your project, switching when needed between language and framework versions or base images.

Next, we’ll explore the remaining aspects of your daily workshop usage.

Note

Workshop also integrates with modern IDEs. For instance, see these guides: How to connect your local VS Code to a workshop.

Interactive shell

Besides running individual commands, you can open an interactive shell if you need to perform multiple operations within a session. Workshop runs the login shell for the default nonprivileged user, who’s also named workshop:

$ workshop shell
workshop@dev-6b79e889:/project$ pwd

  /project

workshop@dev-6b79e889:/project$ lsb_release -a

  ...
  Distributor ID: Ubuntu
  Description:    Ubuntu 24.04.3 LTS
  Release:        24.04
  Codename:       noble

workshop@dev-6b79e889:/project$ exit

Reusable actions

For complex commands that you run often, define actions in your workshop definition to invoke them with workshop run.

Add an actions section to workshop.yaml:

workshop.yaml
name: dev
base: ubuntu@24.04
sdks:
  - name: ollama
    channel: vulkan/stable
actions:
  pull: ollama pull "$@"

The "$@" expansion forwards every argument supplied after the action name into the action’s bash script.

Pull a model through the new action; "$@" forwards tinyllama into ollama pull:

$ workshop run dev -- pull tinyllama

Finally, actions are parsed on every workshop run, so there’s no need to refresh the workshop after editing them.

Note

See How to add actions to your workshop for more on writing and running actions.

Project directory updates

Remember that the project directory is mounted as /project/ when the workshop is launched; any changes to /project/ from inside the workshop are visible in the project directory, and vice versa:

$ touch created_outside.txt
$ workshop exec dev -- ls /project/

  ...  created_outside.txt  ...

$ workshop exec dev -- touch /project/created_inside.txt
$ ls

  ...  created_inside.txt  created_outside.txt  ...

Next, let’s dive into how changes and tasks work to track your workshop activities.

Track changes and tasks

To see how Workshop keeps track of its activities around a project, check out the recent major operations, or changes, with workshop changes:

$ workshop changes

  ID  STATUS  SPAWN               READY               SUMMARY
  1   Done    today at 09:26 CET  today at 09:27 CET  Launch "dev" workshop
  ...
  4   Done    today at 09:32 CET  today at 09:34 CET  Refresh "dev" workshop

Changes are enacted atomically to ensure workshops stay operational. Any change must have all its smaller steps, or tasks, succeed; otherwise, it will be reverted.

To look at the latest change, run the workshop tasks command without an argument. To find out which tasks went into a certain change, pass the change ID to the command:

$ workshop tasks 4

  STATUS   DURATION  SUMMARY
  Done    2m17.389s  Download "ubuntu@24.04" base image
  Done        113ms  Retrieve "system" SDK
  Done    2m59.777s  Retrieve "ollama" SDK from channel "vulkan/stable"
  Done        443ms  Create SDK state storage
  Done        581ms  Run hook "save-state" for "system" SDK
  Done        449ms  Run hook "save-state" for "ollama" SDK
  Done         54ms  Disconnect interfaces of "ollama" SDK
  ...
  Done        528ms  Setup "system" SDK profile

This lists all the tasks and includes logs for some of them; each task expresses a simple token of logic, such as running a hook or connecting an interface.

Next steps

This was the last step in this tutorial section; you are now familiar with the essential operations provided by Workshop and have had your first taste of what it can do for you.

Your next step is to learn how to work with interfaces; proceed to the Work with interfaces section.