workshop (CLI)

The workshop utility exposes the following commands, each with its own set of options, and also has a number of global flags:

-h, --help

Print the help message for the command.

-p, --project

Specify the project’s directory path.

-v, --version

Print Workshop version.

workshop actions

List the named actions defined in a workshop.

Usage

$ workshop actions [<WORKSHOP>] [flags]

Description

This command enumerates all actions in the workshop, printing a YAML map.

Examples

List actions for the “nimble” workshop in the current project directory:

$ workshop actions nimble

The name is optional if the project has only one workshop:

$ workshop actions

workshop changes

List recent changes to the workshops in a project.

Usage

$ workshop changes [flags]

Description

Any substantial operation on a workshop is a change that consists of tasks; the command lists details of recent changes for all workshops within a project. For each change, it prints the following details:

  • ID: Uniquely identifies the change within the project

  • Status: Reflects the change’s progress and affects the workshop’s status

  • Spawn: Tells when the change was started

  • Ready: Tells when the change was successfully finished, if at all

  • Summary: Lists actions, affected workshops, other information

Notes:

  • Only successful changes display values in the “Ready” column

  • To investigate the details of a specific change, use “workshop tasks” instead

Examples

List changes for all workshops in the current project directory:

$ workshop changes

Flags

--no-headers

Hide table headers.

See also

Reference:

workshop connect

Connect a plug to a slot.

Usage

$ workshop connect <WORKSHOP>/<SDK>:<PLUG> [<WORKSHOP>/<SDK>][:<SLOT>] [flags]

Description

This command connects a plug to a target slot that is specified as the second argument or deduced from the context.

  • If the second argument is omitted entirely, the target is assumed to be <WORKSHOP>/system:<PLUG>; <WORKSHOP> and <PLUG> come from the first argument.

  • If the second argument only names the slot itself, the target is <WORKSHOP>/system:<SLOT>; <WORKSHOP> comes from the first argument.

  • If the second argument omits the <SLOT> name, the target slot is the one that uses the same interface as the <PLUG>, regardless of the slot’s name. However, if there are several slots that use the same interface, the command fails.

  • If the target slot is compatible with the plug, the command attempts to connect them and returns the result.

    Notes:

  • To be compatible, the plug and the slot must use the same interface.

  • Multiple plugs can be connected to the same slot, but not vice versa.

  • The “workshop connections” output will list the connection as “manual”.

Examples

Connect the “mod-cache” mount interface plug of the “go” SDK under the “nimble” workshop in the current project directory:

$ workshop connect nimble/go:mod-cache :mount

A full version of the command that also lists the target SDK (“system”):

$ workshop connect nimble/go:mod-cache nimble/system:mount

Flags

--no-wait

Return the change ID, don’t wait for the operation to finish.

workshop connections

List interface connections.

Usage

$ workshop connections [<WORKSHOP>] [flags]

Description

This command lists the connections between interface plugs and slots for the entire project or a single workshop within it. Each line represents a connection between a plug and a slot via an interface; additional notes, including specific plug bindings, are provided as needed.

Notes:

  • The output lists connections created with “workshop connect” as “manual”.

  • The “--all” option needn’t be used with an argument; if a workshop is supplied, disconnected plugs are also listed.

Examples

List connections for the workshop “nimble” in the current project directory:

$ workshop connections nimble

List connections for all workshops in the current project directory:

$ workshop connections

Flags

--all

Include disconnected plugs in the output.

--no-headers

Hide table headers.

workshop disconnect

Disconnect a plug or a slot.

Usage

$ workshop disconnect <WORKSHOP>/<SDK>:<PLUG OR SLOT> [<WORKSHOP>/<SDK>]:[<SLOT>] [flags]

Description

This command disconnects a plug from its slot, or a slot from all its plugs.

  • A single argument can be a fully qualified plug or slot reference; with two arguments, the first one is the plug, and the second one is the slot.

  • If the second argument only names the slot itself, the target is <WORKSHOP>/system:<SLOT>; <WORKSHOP> comes from the first argument.

  • If the second argument only names the workshop and SDK, the target is <WORKSHOP>/<SDK>:<INTERFACE>; <INTERFACE> is the interface in the plug’s definition.

    Notes:

  • After an auto-connected plug is thus disconnected, it is reconnected during “workshop refresh” only if the “--forget” option was used with “workshop disconnect”.

Examples

Disconnect the “mod-cache” mount interface plug of the “go” SDK under the “nimble” workshop in the current project directory:

$ workshop disconnect nimble/go:mod-cache

A full version of the same command that lists the target SDK (“system”) and slot (“mount”):

$ workshop disconnect nimble/go:mod-cache nimble/system:mount

Disconnect all plugs connected to the “mount” slot of the “system” SDK under the “nimble” workshop in the current project directory:

$ workshop disconnect nimble/system:mount

Flags

--forget

Reconnect the plugs at “workshop refresh” if auto-connected initially.

--no-wait

Return the change ID, don’t wait for the operation to finish.

workshop exec

Run an ad-hoc shell command in a workshop.

Usage

$ workshop exec [flags] [<WORKSHOP>] [--] <COMMAND>...

Description

The “exec” subcommand runs an arbitrary command in the specified workshop, waiting for it to complete. If a timeout elapses before that, it’s terminated.

Use “exec” for one-off shell commands typed on the command line. To invoke a named script defined in the workshop’s “actions:” section instead, use “workshop run”.

To accept an “exec” command, the workshop must be “Ready” or “Waiting”. A command can run in two modes that determine how it handles standard streams:

  • Interactively (for shell sessions)

  • Non-interactively (for scripts)

To set the mode explicitly, use “-i” or “-I”. If neither is supplied, “exec” deduces the mode based on the nature of its own streams:

  • If stdin and stdout are terminals, the mode is interactive

  • Otherwise, it’s non-interactive

To separate the “exec” subcommand from the command itself, use a separator (--).

If you omit the separator, “exec” treats its first argument as the workshop name. If the project has no such workshop and the shell is interactive, the argument is treated as a command to run in the default workshop.

Notes:

  • To start a workshop before running commands in it, use “workshop start”.

  • You can set the working directory, environment variables, user and group ID for running the command in the workshop; reasonable defaults are provided.

Examples

Run the “go build main.go” command under the “nimble” workshop in the current project directory:

$ workshop exec nimble -- go build main.go

A similar command that sets an environment variable and the working directory:

$ workshop exec --env GO111MODULE=off -w /project nimble -- go build -x

Run a command as root (the default is “workshop”):

$ workshop exec --uid 0 nimble id

Run a custom interactive shell:

$ workshop exec -I nimble sh

If the project has only one workshop, the workshop name is optional:

$ workshop exec -- sh

If the command doesn’t overlap with a workshop name and the shell is interactive, the separator is also optional:

$ workshop exec sh

Flags

--cwd

Set the working directory in the workshop.

--env

Set an environment variable, e.g. ‘FOO=bar’; if only the name is provided, the value is inherited from the CLI environment.

--uid

Run as a specific workshop user.

--gid

Run as a member of a specific workshop group.

--timeout

Set a timeout; valid units are ns, us or µs, ms, s, m, h.

--interactive

Force interactive mode.

--non-interactive

Force non-interactive mode.

workshop info

Print the current status and details of a workshop as YAML.

Usage

$ workshop info [<WORKSHOP>] [flags]

Description

This command outputs the basic settings, current status and individual SDK details for a workshop, formatting them as YAML. Specifically, it prints:

  • Essential workshop attributes, such as name, base and project directory

  • Current status (e.g. ‘Ready’, ‘Pending’, ‘Stopped’) and notes for the workshop

  • Individual SDK details, such as name, channel, installation date and revision

  • Currently connected mount interface plugs

Notes:

  • Avoid assumptions based on SDK channels: “latest/stable” may be neither.

Examples

List details for the “nimble” workshop in the current project directory:

$ workshop info nimble

The name is optional if the project has only one workshop:

$ workshop info

workshop init

Create a new workshop definition in the project directory.

Usage

$ workshop init <NAME> --sdks <SDKs> [--base <BASE>] [flags]

Description

Create a new workshop definition file in the project’s .workshop/ directory.

The NAME argument sets the workshop name. The command creates a named workshop file at .workshop/<NAME>.yaml. This fails if a workshop with the same name already exists.

SDKs are specified as a comma-separated list. Each SDK entry can optionally include a channel using the <name>/<channel> syntax (e.g., “go/1.26/stable”).

Examples

Create a workshop called “dev” with the Go and UV SDKs:

$ workshop init dev --sdks go,uv

Create a workshop with a specific SDK channel:

$ workshop init dev --sdks go/1.26/stable

Create a workshop using a specific base:

$ workshop init dev --sdks go --base ubuntu@22.04

Flags

--base

Base image for the workshop.

--sdks

Comma-separated list of SDKs (e.g., “go,uv/latest/stable”).

workshop launch

Construct one or many workshops using their definitions.

Usage

$ workshop launch <WORKSHOP>... [flags]

Description

This command constructs the workshops listed as arguments by going over their definitions and installing their components. For each workshop, it:

  • Checks the workshop definition and identifies necessary actions

  • Retrieves the required components, such as base and SDKs

  • Runs SDK setup hooks to initialize the working state

  • On success, ties the workshop to the project and starts it

The “--wait-on-error” option pauses the launch if an error occurs. Thus, you can fix the error and resume the operation or abort and revert it. This option can only be used with a single workshop. If multiple workshops are listed and an error occurs, the operation is aborted and no workshops are constructed. Also, if you change the workshop definition while fixing the error, you must abort the operation and restart from scratch.

Notes:

  • Names listed as arguments must match respective “name:” values in definitions.

  • To update an existing workshop, use “workshop refresh” instead.

  • SDKs are installed in the order they are listed in the definition.

Examples

Launch the “nimble” and “jazzy” workshops in the current project directory:

$ workshop launch nimble jazzy

The name is optional if the project has only one workshop:

$ workshop launch

Flags

--abort

Abort the previously paused operation, reverting any changes.

--continue

Continue the previously paused operation.

--no-wait

Return the change ID, don’t wait for the operation to finish.

--verbose

Combine stdout and stderr output from hooks.

--wait-on-error

Pause the operation on error; to resume, use “--continue” or “--abort”.

workshop list

List project workshops.

Usage

$ workshop list [flags]

Description

This command enumerates all workshops in the project, printing a compact list:

  • Project: Absolute pathname of the project where this workshop belongs

  • Workshop: Workshop name, as set by its definition

  • Status: Workshop status, such as “Off”, “Ready”, “Pending” and so on

  • Notes: Internal remarks on the overall state of the workshop

The “--global” option lists all workshops from all projects in the system; however, it doesn’t include any that are “Off”.

Notes:

  • For details of a single workshop, use “workshop info” instead.

Examples

List the workshops in the current project directory:

$ workshop list

List the globally registered workshops:

$ workshop list --global

Flags

--global

List workshops from all projects in the system.

--no-headers

Hide table headers.

workshop okay

Acknowledge listed warnings.

Usage

$ workshop okay [flags]

Description

This command acknowledges all warnings listed previously by the “workshop warnings” command.

Examples

Acknowledge the globally registered warnings across all workshops (must run after “workshop warnings”):

$ workshop okay

workshop refresh

Update workshops according to their definitions.

Usage

$ workshop refresh [--abort|--continue|--wait-on-error] <WORKSHOP>... [flags]

Description

This command updates the workshops listed as arguments. For each workshop, it checks the workshop definition and applies any required updates to the base image, SDKs, and interface connections:

  • Connections added at runtime with “workshop connect” are dropped, and the workshop returns to its definition’s auto-connect defaults.

  • A connection removed with “workshop disconnect” without “--forget” stays disconnected after refresh.

The “--wait-on-error” option pauses the refresh if an error occurs. Thus, you can fix the error and resume the operation or abort and revert it. This option can only be used with a single workshop. If multiple workshops are listed and an error occurs, the operation is aborted and reverted for all of them. Also, if you change the workshop definition while fixing the error, you must abort the operation and restart from scratch.

Notes:

  • The workshop must be “Ready” to be refreshed. Throughout the refresh, all affected workshops remain unavailable for other changes.

  • Updated and newly added SDKs are installed in the order they are listed in the workshop definition.

  • To construct a newly defined workshop, use “workshop launch” instead.

Examples

Refresh the “nimble” and “jazzy” workshops in the current project directory:

$ workshop refresh nimble jazzy

The name is optional if the project has only one workshop:

$ workshop refresh

Refresh workshop, but pause on any errors (won’t accept multiple workshops):

$ workshop refresh --wait-on-error

After refresh paused on error, abort the operation:

$ workshop refresh --abort

After refresh paused on error and the workshop was fixed, continue the operation:

$ workshop refresh --continue

Flags

--abort

Abort the previously paused operation, reverting any changes.

--continue

Continue the previously paused operation.

--no-wait

Return the change ID, don’t wait for the operation to finish.

--verbose

Combine stdout and stderr output from hooks.

--wait-on-error

Pause the operation on error; to resume, use “--continue” or “--abort”.

workshop remount

Mount a new source location to the mount interface plug’s target.

Usage

$ workshop remount <WORKSHOP>/<SDK>:<PLUG> <SOURCE> [flags]

Description

This command mounts a new source location on the host to the target directory of the specified mount interface plug, qualified by the SDK name. Specifically, it does the following:

  • Attempts the mount operation atomically; this normally succeeds if the new source is either a non-existing directory or an empty directory on the same file system as the current source.

  • Otherwise, performs the mount operation only if the workshop is ‘Stopped’ to prevent data corruption.

Notes:

  • To stop the workshop, use “workshop stop”.

  • “workshop info” lists any connected mount interface plugs for the workshop.

  • “workshop refresh” mounts the last source set by “workshop remount”, if any.

  • During “workshop remove”, non-default sources set by “workshop remount” aren’t removed.

Examples

Remount the “mod-cache” mount interface plug of the “go” SDK under the “nimble” workshop in the current project directory to “~/new-cache-mount/” on the host:

$ workshop remount nimble/go:mod-cache ~/new-cache-mount

Flags

--no-wait

Return the change ID, don’t wait for the operation to finish.

workshop remove

Remove one or many workshops.

Usage

$ workshop remove <WORKSHOP>... [flags]

Description

This command removes the workshops listed as arguments. For each workshop, it:

  • Checks that the workshop isn’t “Off” or “Pending”

  • Stops the workshop if it’s not already “Stopped”

  • Deletes the workshop but preserves its definition

Notes:

  • If any listed workshop is “Off” or “Pending”, none are removed.

  • To rebuild a removed workshop from scratch, use “workshop launch”.

  • For mount interface plugs, non-default sources set by “workshop remount” aren’t removed.

Examples

Remove the “nimble” and “jazzy” workshops in the current project directory:

$ workshop remove nimble jazzy

The name is optional if the project has only one workshop:

$ workshop remove

workshop restore

Restore workshops to the state of the last launch or refresh.

Usage

$ workshop restore [flags] <WORKSHOP>...

Description

This command restores the container filesystem of the workshops listed as arguments to the point of the last launch or refresh, then resets the interface connections to default settings:

  • Connections added at runtime with “workshop connect” are dropped, and the workshop returns to its definition’s auto-connect defaults.

  • A connection removed with “workshop disconnect” without “--forget” stays disconnected after restore.

Notes:

  • The workshop must be “Ready” to be restored.

  • Multiple workshops can be restored in a single command invocation; the operation is transactional, so if any workshop fails to restore, all are reverted.

  • To update an existing workshop instead of reverting changes, use “workshop refresh”.

Examples

Restore the “nimble” and “jazzy” workshops in the current project directory:

$ workshop restore nimble jazzy

The name is optional if the project has only one workshop:

$ workshop restore

Flags

--no-wait

Return the change ID, don’t wait for the operation to finish.

--verbose

Combine stdout and stderr output from hooks.

workshop run

Run a named action from the workshop definition.

Usage

$ workshop run [flags] [<WORKSHOP>] [--] <ACTION> <ARGUMENTS>...

Description

The “run” subcommand runs an action specified in the workshop definition file, waiting for it to complete. If a timeout elapses before that, it’s terminated.

Use “run” to invoke a named action defined in the workshop’s “actions:” section. To list available actions, use “workshop actions”. To run an ad-hoc shell command instead, use “workshop exec”.

To accept a “run” command, the workshop must be “Ready” or “Waiting”. A command can run in two modes that determine how it handles standard streams:

  • Interactively (for shell sessions)

  • Non-interactively (for scripts)

To set the mode explicitly, use “-i” or “-I”. If neither is supplied, “run” deduces the mode based on the nature of its own streams:

  • If stdin and stdout are terminals, the mode is interactive

  • Otherwise, it’s non-interactive

To separate the “run” subcommand from the action and its arguments, use a separator (--).

If you omit the separator, “run” treats its first argument as the workshop name. If the project has no such workshop and the shell is interactive, the argument is treated as an action to run in the default workshop.

Any trailing arguments are forwarded to the action as positional parameters, so action scripts can consume them with standard shell expansions.

Notes:

  • To start a workshop before running actions in it, use “workshop start”.

  • You can set the working directory, environment variables, user and group ID for running the action in the workshop; reasonable defaults are provided.

Examples

Run the “build” action under the “nimble” workshop in the current project directory:

$ workshop run nimble build

A similar command that sets an environment variable and the working directory:

$ workshop run --env GO111MODULE=off -w /project nimble -- build

If the project has only one workshop, the workshop name is optional:

$ workshop run -- build

If the action doesn’t overlap with a workshop name and the shell is interactive, the separator is also optional:

$ workshop run build

Forward arguments to an action that consumes them (for example, tests: go test "$@" in the workshop definition):

$ workshop run dev -- tests -run TestFoo ./pkg/...

Flags

--cwd

Set the working directory in the workshop.

--env

Set an environment variable, e.g. ‘FOO=bar’; if only the name is provided, the value is inherited from the CLI environment.

--uid

Run as a specific workshop user.

--gid

Run as a member of a specific workshop group.

--timeout

Set a timeout; valid units are ns, us or µs, ms, s, m, h.

--interactive

Force interactive mode.

--non-interactive

Force non-interactive mode.

workshop shell

Start an interactive terminal session for the workshop.

Usage

$ workshop shell [<WORKSHOP>] [flags]

Description

The “shell” subcommand runs an interactive terminal session in the specified workshop.

To accept a “shell” command, the workshop must be “Ready” or “Waiting”.

Notes:

  • To start a workshop before running a terminal session, use “workshop start”.

  • The subcommand is a shorthand for “workshop exec”; it launches the login shell for “workshop”, the default non-privileged user in a workshop.

Examples

Open the default login shell of the “workshop” user into the “nimble” workshop in the current project directory:

$ workshop shell nimble

The name is optional if the project has only one workshop:

$ workshop shell

workshop sketch-sdk

Customize a workshop.

Usage

$ workshop sketch-sdk [--stash|--restore|--eject|--remove] [<WORKSHOP>] [flags]

Description

The command opens the sketch SDK template in the default text editor. Add customizations by editing the template, then save and exit the editor to apply the changes to the workshop.

The “--stash” and “--restore” options respectively stash the SDK, reversing the changes, and quickly restore it to the workshop.

To make these customizations persistent, run “workshop sketch-sdk --eject”. This saves the SDK definition under .workshop/ in the project directory, so it can be committed to your repository.

The sketch SDK is intended for experiments and prototyping iterations.

Notes:

  • You can only have one sketch SDK per workshop at a time.

  • Run “workshop info” to list all SDKs currently installed in the workshop, including the sketch SDK if present.

Examples

Edit the sketch SDK definition for the “nimble” workshop and apply it after saving by automatically refreshing the workshop:

$ workshop sketch-sdk nimble

Save the sketch SDK for the “nimble” workshop as a project SDK named “tools”:

$ workshop sketch-sdk nimble --eject --name tools

Stash the sketch SDK, temporarily reverting the changes in the workshop:

$ workshop sketch-sdk nimble --stash

Flags

--eject

Promote the sketch SDK to an in-project SDK.

--name

Name for the ejected SDK.

--remove

Remove the sketch SDK from the workshop.

--restore

Return the previously stashed SDK to the workshop.

--stash

Stash the sketch SDK and remove it from the workshop.

--verbose

Combine stdout and stderr output from hooks.

workshop sketches

List project sketch SDKs.

Usage

$ workshop sketches [flags]

Description

This command enumerates all sketches in the project, printing a compact list:

  • Project: absolute pathname of the project

  • Workshop: workshop name, as set in its definition

  • Rev: sketch SDK revision, if present

  • Notes: current, stashed, or both

Examples

List the sketches in the current project directory:

$ workshop sketches

Flags

--no-headers

Hide table headers.

workshop start

Start one or many workshops.

Usage

$ workshop start <WORKSHOP>... [flags]

Description

This command activates the workshops listed as arguments. For each one, it:

  • Makes sure the workshop was actually launched

  • Activates the workshop for use and sets it to ‘Ready’

If multiple workshops are listed and an error occurs, the operation is aborted and no workshops are started.

Notes:

  • If a workshop is already started or wasn’t yet launched, an error occurs.

  • When interrupted, the command attempts to gracefully revert its actions.

  • To stop a started workshop, use “workshop stop”.

Examples

Start the “nimble” and “jazzy” workshops in the current project directory:

$ workshop start nimble jazzy

The name is optional if the project has only one workshop:

$ workshop start

workshop stop

Stop one or many workshops.

Usage

$ workshop stop <WORKSHOP>... [flags]

Description

This command deactivates the workshops listed as arguments. For each one, it:

  • Makes sure the workshop was actually started or is already stopped

  • Deactivates the workshop and sets it to ‘Stopped’

If multiple workshops are listed and an error occurs, the operation is aborted and no workshops are stopped.

Notes:

  • If a workshop wasn’t yet started or even launched, an error occurs.

  • When interrupted, the command attempts to gracefully revert its actions.

  • To start a stopped workshop, use “workshop start”.

Examples

Stop the “nimble” and “jazzy” workshops in the current project directory:

$ workshop stop nimble jazzy

The name is optional if the project has only one workshop:

$ workshop stop

workshop tasks

List tasks for a specific change.

Usage

$ workshop tasks [<CHANGE ID>] [flags]

Description

Any substantial operation on a workshop is a change that consists of tasks; the command lists individual tasks that comprise a specific change. For each task, it prints the following details:

  • Status: Reflects the task’s progress and affects the status of the change

  • Duration: Tells how long the task has been running

  • Summary: Lists actions, affected SDKs and workshops, other information

Notes:

  • The command may print additional log details for tasks that store them

  • To investigate recent changes in a project, use “workshop changes” instead

Examples

List the tasks under change ID 42:

$ workshop tasks 42

List the tasks under the most recent change to the project:

$ workshop tasks

Flags

--no-headers

Hide table headers.

workshop warnings

List warnings.

Usage

$ workshop warnings [flags]

Description

This command lists the warnings that were reported to the system.

All warnings listed by “workshop warnings” can be acknowledged with the “workshop okay” command. Acknowledged warnings aren’t listed by “workshop warnings” unless they occur again after their cooldown period has elapsed or the “--all” option is used.

Also, warnings expire automatically; expired warnings are not listed.

Examples

List the globally registered warnings across all workshops:

$ workshop warnings

Flags

--abs-time

Use absolute times in RFC 3339 format. By default, relative times are used up to 60 days, then YYYY-MM-DD.

--all

Show all warnings, including the acknowledged ones.

--unicode

Use Unicode characters to improve legibility (auto|never|always). By default, Unicode is used only if the output supports it.

--verbose

Show more information per each warning.

Shell completion

The workshop CLI ships completion scripts for Bash, Zsh, and Fish.

Note

When Workshop is installed via snap, completion for Bash, Zsh, and Fish is enabled automatically; no further configuration is needed for these shells.

To enable completion for the current shell session, source the script for your shell.

Bash:

$ source <(workshop completion bash)

Zsh:

$ source <(workshop completion zsh)

Fish:

$ workshop completion fish | source

For per-shell installation that persists across new sessions, follow the instructions printed by the shell-specific help command. For example, for Bash:

$ workshop completion bash --help

What gets completed

Beyond subcommand and flag names, the workshop CLI completes arguments and flag values dynamically:

  • Workshop names, filtered by lifecycle status per command; for example, workshop start lists only Stopped workshops, while workshop stop lists only Ready ones.

  • Plugs and slots for workshop connect and workshop disconnect: the first argument completes available plugs, the second completes valid slots for the chosen plug.

  • Recent change IDs for workshop tasks.

See also

Explanation: