Workshop documentation style guide

This style guide documents the established conventions used in the Workshop documentation. It captures actual patterns observed across the documentation set and serves as a reference for maintaining consistency in new contributions.

This guide is subordinate to Canonical’s documentation standards but records Workshop-specific decisions and patterns that extend or clarify those standards.


File naming and organization

Directory structure

The documentation follows the Diátaxis framework with four main sections:

docs/
├── tutorial/          # Step-by-step learning paths
├── how-to/            # Task-oriented guides
├── explanation/       # Conceptual information
└── reference/         # Technical specifications

File naming convention

All filenames use lowercase letters and dashes for word separation.

Examples:

  • Good: part-1-get-started.rst

  • Good: connect-vscode.rst

  • Good: camera-interface.rst

  • Good: sdk-vs-dockerfile.rst

  • Avoid: ConnectVSCode.rst (uppercase)

  • Avoid: camera_interface.rst (underscore)

Tutorial files use a sequential numbering pattern:

part-1-get-started.rst
part-2-work-with-interfaces.rst
part-3-sketch-sdks.rst
part-4-craft-sdks.rst

How-to files: Use verb-first naming pattern:

add-actions.rst
connect-vscode.rst
forward-ports.rst
debug-issues.rst
resolve-plug-conflicts.rst

Explanation files use noun-based naming:

concepts.rst
camera-interface.rst
best-practices.rst
runtime-behavior.rst

Reference files match command structure:

workshop-launch.rst
workshop-connect.rst
sdkcraft-build.md

Filenames and directory names in the documentation repo should be in lowercase, with dashes instead of spaces; the directory tree must be built in a way that provides for readable, meaningful URLs: /docs/howto/change-tyres.


Page structure and metadata

Standard page structure

Every reStructuredText documentation page follows this structure:

.. _anchor_label:

.. meta::
   :description: Brief description for search engines and social media

Page Title
==========

Opening paragraph providing context and purpose.

Section Heading
---------------

Content...

Subsection Heading
~~~~~~~~~~~~~~~~~~

Content...

Metadata block

Every page must have a .. meta:: block immediately after the anchor label.

Format:

.. meta::
   :description: A brief, clear description of the page content for SEO and
                 social media. Typically 1-2 lines, wrapping at natural phrase
                 boundaries.

Examples from the documentation:

.. meta::
   :description: Practical introduction to workshops, guiding users through
                 defining, launching, and refreshing workshops, and executing commands in workshops.
.. meta::
   :description: A comprehensive explanation of the Workshop interface system,
                 detailing how SDKs connect to host system resources through
                 interfaces, and the mechanism of plugs and slots for resource
                 sharing between containers.

Anchor labels

Use lowercase with underscores, prefixed by section type.

Prefixes:

  • tut_ - Tutorial sections

  • how_ - How-to guides

  • exp_ - Explanation articles

  • ref_ - Reference documentation

Examples:

.. _tut_get_started:
.. _how_add_actions:
.. _exp_interface_concepts:
.. _ref_workshop_launch:

Artefact comments

Use .. @artefact comments to mark key concepts for coverage tracking:

.. @artefact workshop (container)
.. @artefact SDK
.. @artefact interface
.. @artefact workshop launch

The current list of these concepts is maintained in docs/coverage.yaml; update it as needed.


Writing style and tone

Voice and audience

Target audience is developers and DevOps professionals seeking to:

  • Achieve specific goals without much overhead and roundabout musings

  • Perform and conceive complex ad-hoc tasks and workflows that require precision and depth

  • Attain understanding of Workshop’s key capabilities beneficial for their scenarios

Content follows the Diátaxis framework, providing:

  • Concise tutorials for common, starter-level actions and scenarios, eliminating the need to invent custom steps and allowing novice users to journey along the hot path effortlessly

  • Elaborate explanations of the thinking behind Workshop’s design, including design decisions, related concepts, and how it should be used

  • Detailed how-to guides that address specific needs of advanced users and cover topics beyond basic entry-level operations

  • Comprehensive reference of all options, settings, and details available to customize Workshop’s operation in any desirable manner

The tone is authoritative but relaxed, confident but approachable. Think water cooler conversation, not classroom session.

Example from the documentation:

Workshop is a tool for defining and handling ephemeral development environments.

List your dependencies and components in YAML to define an environment. The key pieces of a definition are SDKs, independent but connectable units of functionality created by software publishers and available on the SDK Store. Workshop simplifies experiments with your environment layout.

Direct instructions

Use imperative mood for instructions. Avoid “you can” or “you may” for required actions.

Preferred:

Install Workshop using the --classic option:

Avoid:

You can install Workshop with:

Paragraph length

Keep paragraphs focused and relatively short (2-5 sentences typically). Complex topics should be broken into multiple paragraphs.

Example from tutorial:

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

Authenticate to the Snap Store and install the snap
using the `--classic <...>`_ option:

Clarity over cleverness

  • State prerequisites explicitly

  • Define terms at first use

  • Avoid assumptions about reader knowledge

  • Use precise, unambiguous language

Language and spelling

Convention: Use US English spelling, grammar, and formatting conventions throughout the documentation.

Examples:

  • Good: color, center, analyze, behavior

  • Avoid: colour, centre, analyse, behaviour

  • Good: Use serial comma: “SDKs, interfaces, and workshops”

  • Good: Double quotes for quotations: “Workshop is a tool”


Semantic line breaks

Pattern

The documentation consistently uses semantic line breaks (one line per clause or significant phrase) in reStructuredText files. This improves version control diffs and editing precision.

Rationale: Semantic breaks make git diffs more readable and help reviewers identify exactly what changed in a sentence or paragraph.

Implementation

Break lines at natural semantic boundaries:

  • After each complete clause

  • Before coordinating conjunctions (and, but, or)

  • Before relative clauses (which, that, who)

  • After introductory phrases

Example from the documentation:

This is the first section of the :ref:`four-part series <tut_index>`;
a practical introduction
that takes you on a tour
of the essential |ws_markup| activities.
To make use of these interfaces,
SDKs and :ref:`workshops <exp_workshop_definition_connections>` define *slots*.
For example, a :ref:`mount interface <exp_mount_interface>` slot
creates a source directory to be mounted inside the workshop via a plug.
When crafting SDKs for |ws_markup|,
publishers face design decisions
that affect how their SDKs install, integrate, and work inside workshops.
Understanding the best practices outlined below
helps publishers create more maintainable, reliable, and user-friendly SDKs
that better align with |ws_markup|'s architecture and ideology.

When to break

Break after:

  • Complete independent clauses

  • Introductory prepositional phrases

  • Transitional phrases

  • Items in a complex series

Keep together:

  • Short phrases that form a single unit

  • Inline markup and its target word

  • Cross-reference markup

Example:

Interfaces are a mechanism for communication and resource sharing.
It is an integral part of workshop confinement,
ensuring that each workshop operates in its own isolated environment,
while still allowing controlled interactions among the SDKs and with the host.

Headings and titles

Capitalization

Pattern: Sentence case for all headings (capitalize only first word and proper nouns).

Examples:

Get started with workshops
==========================

Install |ws_markup|
-------------------

Prerequisites
~~~~~~~~~~~~~

Exception: Product names and proper nouns maintain their capitalization:

How to use JetBrains Gateway with Workshop
==========================================

Heading hierarchy

reStructuredText heading levels (consistent across documentation):

Page Title (H1)
===============

Section (H2)
------------

Subsection (H3)
~~~~~~~~~~~~~~~

Sub-subsection (H4)
^^^^^^^^^^^^^^^^^^^

How-to title pattern

How-to guides follow the pattern: “How to [action] [object]”

Examples:

^^^^^^^^^^^^^^^^^^^^

How-to title pattern

How-to guides follow the pattern: “How to [action] [object]”:

  • How to forward ports with tunneling

  • How to fix plug conflicts with binding

  • How to debug issues in workshops

Linking exception: In navigation and links, drop “How to” prefix and use infinitive:

How-to guides:

* Debug issues in workshops
* Connect VS Code to a workshop

reStructuredText conventions

Code blocks

Standard format:

.. code-block:: console

   $ workshop launch dev
.. code-block:: yaml
   :caption: workshop.yaml

   name: dev
   base: ubuntu@22.04

With emphasis:

.. code-block:: yaml
   :caption: workshop.yaml
   :emphasize-lines: 7-9

   name: dev
   base: ubuntu@22.04
   sdks:
     - name: go
       channel: 1.26
   
   actions:
     lint: |
       golangci-lint run

Supported languages: console, yaml, python, go, shell, ini, json

Admonitions

Note:

.. note::

   For other ways to install LXD,
   see the available installation options in
   `LXD documentation <...>`_.

Warning:

.. warning::

   This will permanently delete all workshop data.

Placement: Place admonitions at the end of the subsection they relate to, rather than interrupting the flow of text in the middle of a section.

Inline markup

Semantic markup preference: Use semantic markup roles (:samp:, :envvar:, :file:, etc.) instead of generic ones (`, *, etc.). Choose the most specific role that suits the purpose and use it consistently.

Emphasis (italics):

A *workshop* is a development environment running in a container.

Use italics sparingly to introduce new terms (a link is even better) and for emphasis. Leave bold for product names and commands.

Strong (bold): Rarely used; prefer other markup when possible.

Program/command names:

:program:`workshop`
:command:`workshop launch`

Commands in :command: roles should be presented in their complete form (e.g. workshop launch, not just launch) and should not be used as verbs or nouns in the text. Use non-breaking spaces in inline command literals to prevent longer compound commands from wrapping.

File paths:

:file:`workshop.yaml`
:file:`/home/user/.ollama/models/`

End directory path names with a slash where possible and conventional to disambiguate directories from files.

Sample values:

:samp:`ollama`
:samp:`ssh-agent`

Environment variables:

:envvar:`PATH`
:envvar:`HOME`

Placeholders: Format placeholders in uppercase within angle brackets, without underscores:

:samp:`workshop launch {WORKSHOP}`
:samp:`{SDK-NAME}@{CHANNEL}`

Or in documentation text:

workshop launch <WORKSHOP>

Substitutions are reusable text replacements defined in docs/reuse/substitutions.txt and automatically included in all reStructuredText files:

|ws_markup|    # Renders as :program:`Workshop`
|sdk_markup|   # Renders as :program:`SDKcraft`

These ensure consistent formatting of product names throughout the documentation. Use them instead of typing product names manually.

Common external links are defined in docs/reuse/links.txt for consistent reference across documentation:

.. _Canonical website: https://canonical.com/
.. _GitHub: https://github.com/canonical/workshop/
.. _LXD: https://documentation.ubuntu.com/lxd/latest/
.. _SDKcraft: https://github.com/canonical/sdkcraft/
.. _Releases: https://github.com/canonical/workshop/releases/

Reference these with trailing underscores:

See the `GitHub`_ repository for source code.
Refer to the `LXD`_ documentation for setup details.

Non-breaking spaces: Use non-breaking spaces (U+00A0 or ~ in LaTeX contexts) for important proper names and inline compound commands where line breaks would be awkward, though this is rarely needed in reStructuredText.

Lists

Bulleted lists:

- Camera interface (manually connected)
- Desktop interface (manually connected)
- GPU interface (auto-connected)

Numbered lists: Use pound signs for auto-numbering:

#. First step
#. Second step
#. Third step

Multiline list items: Separate items with a blank line for visibility if at least one item is multiline:

- First item with a longer description
  that spans multiple lines

- Second item that is also long
  and needs proper spacing

- Third item

Table of contents

Follow this pattern, avoiding hidden ToCs where possible:

Heading
=======

Some summary of what's to follow.

These articles say this and this:

.. toctree::
   :glob:
   :maxdepth: 1

   *

These articles say this and this:

.. toctree::
   :glob:
   :maxdepth: 1

   *

“See also” sections

“See also” sections can appear on pages under any pillar and link to related content not immediately essential but potentially useful. Break link lists down by pillar, listing pillars and individual subsections in alphabetical order:

See also
--------

Explanation:

* :ref:`exp_sdks`
* :ref:`exp_workshop`

How-to guides:

* :ref:`how_resolve_plug_conflicts`

Reference:

* :ref:`ref_cli`
* :ref:`ref_workshop_connect`
* :ref:`ref_workshop_info`

Or using custom link text:

See also
--------

Explanation:

* :ref:`changes, tasks (concepts) <exp_changes_tasks>`
* :ref:`project (concept) <exp_project>`
* :ref:`workshop (concept) <exp_workshop>`, :ref:`workshop definition (file) <exp_workshop_definition>`

Reference:

* :ref:`workshop changes (command) <ref_workshop_changes>`

Links listed here must point to concepts used in the main document; vice versa, concepts appearing in the main text should be linked in “See also” if a well-established related page exists.

Special case: If “See also” is the only subsection on the page, hide the sidebar ToC on the right using the :hide-toc: directive at the top of the file.

Tab headings

Pattern: Keep tab headings noun-based and consistent across related content. Avoid “sticky toggling” (where tab state persists inappropriately across different contexts).

Example:

.. tabs::

   .. tab:: Ubuntu

      Installation instructions for Ubuntu...

   .. tab:: macOS

      Installation instructions for macOS...

Rubric directive

Used in CLI reference for section headers:

.. rubric:: Usage

.. code-block:: console

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

.. rubric:: Description

This command constructs the workshops...

.. rubric:: Examples

Launch the 'nimble' and 'jazzy' workshops:

Sphinx extensions and roles

Preference: Use Sphinx-specific roles and directives over docutils generic equivalents. Use all their options and capabilities, listing options in alphabetical order.

Example with options:

.. code-block:: yaml
   :caption: workshop.yaml
   :emphasize-lines: 3-5
   :linenos:

   name: dev
   base: ubuntu@22.04
   sdks:
     - name: go
       channel: 1.26

Spacing and formatting

Use three spaces to indent reStructuredText directives and separate directive content with a blank line:

.. tab::

   .. code-block:: console
   
      $ workshop launch dev

Separate list-table rows with blank lines:

.. list-table::

   * - **Tutorial**
     - :ref:`Get started <tut_get_started>` • ...

   * - **Workshops**
     - :ref:`Concepts <exp_workshop_concepts>` • ...

Section gaps: Include a noncumulative two-line gap (two blank lines) after code samples, lists, tables, and before headings for visual clarity.

Examples from the documentation:

After code blocks:

.. code-block:: console

   $ sudo snap install --classic workshop


Prerequisites
~~~~~~~~~~~~~

After lists:

- :command:`workshop stop` doesn't destroy the workshop,
  unlike :ref:`remove <tut_remove>`

- :command:`workshop start` doesn't build it from scratch,
  unlike :ref:`launch <tut_launch>` or :ref:`refresh <tut_refresh>`


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

After tables:

.. list-table::
  :header-rows: 1
  :widths: 25 75

  * - Component Type
    - Description

  * - Runtime components
    - Core binaries and libraries that change infrequently


However, parts are not mandatory:

Before headings:

The actions you're about to perform
cover most of your daily needs with |ws_markup|.


.. _tut_install:

Install |ws_markup|
-------------------

Markdown style conventions

This section covers Markdown-specific conventions used in the Workshop documentation. For general writing style, see the “Writing style and tone” section above.

When to use Markdown

Markdown is used for:

  • Release notes (release-notes/v0.*.md)

  • Auto-generated CLI reference (reference/cli/sdkcraft/*.md)

  • Special files rendered on GitHub (security.md, coverage.md)

For all other documentation, prefer reStructuredText (.rst files).

File naming

Use the version number as the filename for release notes: vX.Y.Z.md.

Metadata blocks

Pattern: Markdown files should include metadata using the {eval-rst} directive at the top of the file.

Required for:

  • Release notes (release-notes/v0.*.md)

  • Any Markdown documentation files that will be rendered in Sphinx

Format:

```{eval-rst}
.. meta::
   :description: Brief description for search engines and social media.
```

# Page Title

Exception: Auto-generated CLI reference files for SDKcraft (reference/cli/sdkcraft/*.md) do not require metadata blocks, as they are automatically generated from command definitions.

Example from release notes:

```{eval-rst}
.. meta::
   :description: Release notes for Workshop v0.1.28, highlighting key changes,
                 new features, and bug fixes in this version.
```

# Workshop v0.1.28 release notes

Headings

Use ATX-style headers (#) with sentence case (capitalize only first word and proper nouns):

# Page title

## Section heading

### Subsection heading

Code blocks

Use fenced code blocks with language specifiers:

```console
workshop launch dev
```

```yaml
name: dev
base: ubuntu@22.04
```

Lists

Use hyphens (-) for unordered lists:

- First item
- Second item
- Third item

Use numbers for ordered lists:

1. First step
2. Second step
3. Third step

Emphasis

  • Italics: Use single asterisks *text*

  • Bold: Use double asterisks **text**

Release notes template

Use the following template for new release notes, ensuring all links and version numbers are updated:

```{eval-rst}
.. meta::
   :description: Release notes for Workshop vX.Y.Z, highlighting [key features].
```

# Workshop vX.Y.Z release notes

## [Day] [Month] [Year]

These release notes cover new features and changes in Workshop vX.Y.Z.

## Requirements and compatibility

Workshop relies on Snap and LXD:

- See the [Tutorial](https://ubuntu.com/workshop/docs/tutorial/) for setup instructions.
- Refer to the [Contribution Guide](https://ubuntu.com/workshop/docs/contributing/) for development prerequisites.

## What's new in Workshop vX.Y.Z

[Brief summary of the release].

### [Feature Name]

[Description of the feature and its benefit].

----

**Full Changelog**:
https://github.com/canonical/workshop/compare/vX.Y.Z-1...vX.Y.Z

Simplified markup for GitHub-rendered files

Use simplified markup for files that have special meaning on GitHub and need to be rendered there (such as docs/readme.rst or docs/contributring.rst). These files should be more accessible to users viewing them directly.

Key simplifications:

  • No $ prompts in code blocks: GitHub doesn’t prevent prompt selection during copying, which can confuse users.

  • No semantic roles: Fall back to generic markup instead (e.g., use double backticks for code instead of :command: or :program:).

  • Plain link syntax: Use simple inline links instead of reference-style links.

Examples:

.. code-block:: console

   sudo snap install --classic workshop

Notice: No $ prompt, making it easier to copy commands directly.

Notice: Plain inline links instead of reference-style links, generic double backticks instead of semantic roles.


Code examples

Console examples

Pattern: Show command with prompt, followed by output (if relevant):

.. code-block:: console

   $ workshop launch dev

     Launching dev...
     Launched dev

Command prompts: Use the nonselectable $ prompt. The console lexer in .. code-block:: automatically handles this, making the prompt nonselectable during copy operations.

Root access: When root access is required, include sudo explicitly:

.. code-block:: console

   $ sudo snap install workshop --classic

Command output: Indent output with two spaces and separate it from the command with a blank line:

.. code-block:: console

   $ workshop list --global

   PROJECT          WORKSHOP  STATUS   NOTES
   ~/myproject      dev       Running  -
   ~/otherproject   test      Stopped  -

Comments in commands: Use two forms for comments:

.. code-block:: console

   # Full line comment explaining the command
   $ workshop launch dev

   $ workshop exec dev -- echo "test"  # Inline comment with two spaces before #

Configuration examples

Always include caption when it can be deduced from context:

.. code-block:: yaml
   :caption: workshop.yaml

   name: dev
   base: ubuntu@22.04
   sdks:
     - name: go
       channel: 1.26

Indentation: Use commonly recognized formatting:

  • YAML files: 2-space indentation

  • JSON files: 4-space indentation

Multi-line shell commands

Use backslash continuation or explicit line breaks:

.. code-block:: console

   $ workshop connect dev/ollama:host 127.0.0.1:11434 \
       --host-port 11434


Terminology, product names

Product names

Workshop - Always capitalized, never “workshop” when referring to the product.

SDKcraft - Always use capital SDK, never “Sdkcraft” or “sdkcraft”.

LXD - Always uppercase.

Technical terms

workshop (lowercase) - The container environment itself:

A workshop is a development environment running in a container.

SDK - Always uppercase. Plural: SDKs (no apostrophe).

interface - Lowercase when referring to the general concept; specific interfaces follow same pattern:

  • camera interface

  • GPU interface

  • mount interface

Command names

Always use exact command syntax:

workshop launch
workshop connect
workshopctl
sdkcraft build

Substitutions and reusable content

Text substitutions

Use defined substitutions from docs/reuse/substitutions.txt:

  • |ws_markup| renders as Workshop (with :program: markup)

  • |sdk_markup| renders as SDKcraft (with :program: markup)

Reusable link references

Common external URLs are defined in docs/reuse/links.txt:

  • `GitHub`_ links to the Workshop repository

  • `LXD`_ links to LXD documentation

  • `SDKcraft`_ links to SDKcraft repository

  • `Releases`_ links to Workshop releases page

These files are automatically included via the docs/conf.py configuration and are available in all reStructuredText documentation files. Using them ensures consistency and makes it easy to update URLs in a single location.

Punctuation

En dash (–): Use to represent a range or connection between two related items:

pages 10–15
East–West traffic
Ubuntu 22.04–24.04

Em dash (—): Avoid using em dashes. If possible, rephrase the sentence using other punctuation or sentence structure.

Command line terminology

Convention: Use POSIX utility conventions when discussing command-line syntax, options, arguments, and other CLI elements.


Project descriptions

Short description (79 characters)

Workshop is a tool for defining and handling ephemeral development environments

SDKcraft short description (77 characters)

SDKcraft is a tool that packages and publishes SDKs to be used with Workshop

Documentation quality principles

Clarity

  • State assumptions explicitly

  • Define prerequisites clearly

  • Avoid jargon without explanation

  • Use consistent terminology

Usability

  • Focus on actionable information

  • Use direct imperatives for instructions

  • Break complex tasks into clear steps

  • Provide working examples

Precision

  • Avoid ambiguous language

  • Use exact commands and syntax

  • Specify versions when relevant

  • Maintain consistent structure


Contributing

When contributing documentation:

  1. Follow established patterns for file naming and structure

  2. Use semantic line breaks in reStructuredText files

  3. Include required metadata blocks

  4. Add artefact markers for new concepts

  5. Test examples before including them

  6. Run documentation builds locally to verify

For detailed contribution guidelines, see How to contribute in the documentation.