# Welcome

### Getting Started

<table data-view="cards"><thead><tr><th></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Create a Workspace</strong></td><td></td><td></td><td><a href="/pages/MQod7lG0FsXD1LaHFhTd">/pages/MQod7lG0FsXD1LaHFhTd</a></td><td><a href="/files/sITcIIGVFKR8qEubOIGq">/files/sITcIIGVFKR8qEubOIGq</a></td></tr><tr><td><strong>Join a Workspace</strong></td><td></td><td></td><td><a href="/pages/4TOb0Ay3lp3nxs6v1ICz">/pages/4TOb0Ay3lp3nxs6v1ICz</a></td><td><a href="/files/RBoh7D692zCtUO4oTfHt">/files/RBoh7D692zCtUO4oTfHt</a></td></tr><tr><td><strong>Manage your Workspace</strong></td><td></td><td></td><td><a href="/pages/JTka9GpUOkJs8sOMXfAu">/pages/JTka9GpUOkJs8sOMXfAu</a></td><td><a href="/files/J30l251OdOYmB8lEuSgZ">/files/J30l251OdOYmB8lEuSgZ</a></td></tr></tbody></table>

### User Guides

<table data-view="cards"><thead><tr><th></th><th data-hidden></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><strong>Platform User Guide</strong></td><td></td><td></td><td><a href="/pages/cH086EAS5JTc2OGYnEw1">/pages/cH086EAS5JTc2OGYnEw1</a></td><td><a href="/files/UONWtUv5BKij18W8ZeOX">/files/UONWtUv5BKij18W8ZeOX</a></td></tr><tr><td><strong>Fleet User Guide</strong></td><td></td><td></td><td><a href="/pages/fXWnjwQX42iyL907U8XR">/pages/fXWnjwQX42iyL907U8XR</a></td><td><a href="/files/MmVH5rGvs2PUgFbxcg5W">/files/MmVH5rGvs2PUgFbxcg5W</a></td></tr><tr><td><strong>Workflow User Guide</strong></td><td></td><td></td><td><a href="/pages/f4IhTnMogl9mL5qXoENF">/pages/f4IhTnMogl9mL5qXoENF</a></td><td><a href="/files/gEplLq631kfvLlaQSX2F">/files/gEplLq631kfvLlaQSX2F</a></td></tr></tbody></table>


# Create a Workspace

## What is a workspace?

A workspace is a grouping of users, workflows, and fleets. To start using Chassy, you will need to create a workspace. If an organization member has already created one, you'll receive an email inviting you to that workspace. Read more on this here: [Join a Workspace](/getting-started/join-a-workspace).

## How can I create a workspace?

{% hint style="info" %}
"Workspace" and "organization" may be used interchangeably
{% endhint %}

After signing up with Google, you will be prompted to create a workspace as shown below:

<figure><img src="/files/hqFhaLGbOQq2jBYoPDXx" alt="Type in your Workspace name to create a workspace"><figcaption></figcaption></figure>

Next, you'll be prompted to invite your teammates to your workspace. Each of these teammates will receive an email with a link to sign up. They will be given the `user` role, but you can manage roles and more from your workspace settings as described in [Manage your Workspace](/getting-started/manage-your-workspace).&#x20;

<figure><img src="/files/g800lJoJbDtSSid5FKBG" alt="Enter your teammates&#x27; emails to invite them to the workspace."><figcaption></figcaption></figure>

## What's next?

Next you can begin managing your workspace, and your teammates can accept their workspace invitations. See "Join a Workspace" to learn more.


# Join a Workspace

If you've been invited to join a workspace on Chassy, here's what you need to know:

{% hint style="info" %}
Creators of workspaces can feel free to skip this guide
{% endhint %}

First, you will receive an email with a link to join your organization leader's workspace on Chassy from *<noreply@console.chassy.io>*.

<figure><img src="/files/Y6LgsCqgog5DKMrH43gV" alt="Click on the Accept button in the email to join the workspace."><figcaption></figcaption></figure>

After clicking the link, you will be asked to log in with Google. After logging in, you will be ready to begin using Chassy.


# Manage your Workspace

As a manager or admin, there are common tasks you may want to perform in your workspace. This guide will explain how to perform them.

## Who can manage a workspace?

If you are unfamiliar with the concept of a workspace, begin by reading [Create a Workspace](/getting-started/create-a-workspace). This guide assumes you already have a workspace and the permissions required to manage it (`manager` or `admin`).

If you are unsure what role you have in your organization, go to your account settings by clicking the *Settings* button in the bottom left. Here, you will see what role you have.

<figure><img src="/files/4vBk1cN5ZzMPesMk86np" alt="The Account tab shows you what level of permissions you have for this workspace"><figcaption></figcaption></figure>

Roles in Chassy are expressed by the following hierarchy: `admin` > `manager` > `user`.

## Managing team

If you click the *Settings* button and click the *Teammates* tab, you will be presented with a table populated with your teammates excluding yourself. From here you can send new team invites, delete team invites, update teammates' roles, and remove users from your team. Other instructions will take place on this same page.

<figure><img src="/files/qD9tpTm1DU7GyjxuAJlW" alt="The Teammates tab shows you everyone on your team, as well as actions that you can take to manage these people."><figcaption></figcaption></figure>

### Inviting users

Above the table and to the right, you will see an *Invite Teammates* button. Clicking this button will present you with a dialog where you can enter the email addresses of teammates.

<figure><img src="/files/VZB9CqGj7fXAo2AmwAyn" alt="Clicking on Invite Teammates will open up a dialog to type in email addresses of new teammates."><figcaption></figcaption></figure>

These new invitations will now appear in the teammates table with a label *Invite Pending*.

<figure><img src="/files/zZiGO5XgAS2qwcE4Lb36" alt="New invitees will have an &#x22;Invite Pending&#x22; label next to their email addresses."><figcaption></figcaption></figure>

### Resending invites

You can send another invitation by clicking the *Mail* icon to the right of a teammate's email.&#x20;

<figure><img src="/files/m3mQ2JayCFL2187yBRHt" alt="The Mail icon is on the right of a teammate&#x27;s email, next to the Trash icon."><figcaption></figcaption></figure>

### Removing invites

Delete users by clicking the *Trash* icon to the right of a user's email address. You will be prompted to confirm this decision before the user is deleted.

<figure><img src="/files/Y9lAcylsgqpSEckMthl0" alt="The Trash icon is on the far right of a teammate&#x27;s email, next to the Mail icon."><figcaption></figcaption></figure>

### Updating roles

Modify user roles by clicking the *Pencil* icon to the right of their email address. This icon will only appear for those with permissions to modify.

* If you are an `admin`, you will see this button next to all teammates.&#x20;
* If you're a `manager`, you will not see this button next to `admin` users.&#x20;
* Teammates of the `user` role will not see this button at all as they do not have permission to manage roles.

<figure><img src="/files/TmYvQFnHqXcwSca1zdxl" alt="The Pencil icon is on the right of a teammate&#x27;s role, next to the Trash icon."><figcaption></figcaption></figure>

Clicking the *Pencil* button will prompt a user with the option to change the selected user's role. Do note that the *Save* button will apply this change immediately.

### Removing teammates

When the *Trash* icon appears to the right of a user's email, you have permission to remove them from your team. This button will prompt you with a confirmation window. This user's account will be deleted from your workspace once you confirm your selection.&#x20;

<figure><img src="/files/A1FY2G8YI2GnFLTmZ5Iy" alt="The Trash icon is on the far right of a teammate&#x27;s email, next to the Pencil icon."><figcaption></figcaption></figure>


# Platform User Guide

In this guide, you will learn to create and manage platforms and chips/chipsets. This lays the foundation for fleets which themselves are associated with a particular platform.


# Creating a Platform

A software platform defines information about the underlying operating system, board support packages, kernel and target hardware type its intended for.

## Public platforms

There is an existing set of reference platforms publicly available on Chassy. These software platforms target popular chips like the Nvidia Jetson and Raspberry Pi ecosystems.

## What makes a platform?

### Type

Every platform has a platform type. *Type* defines the nature of the execution hardware target. Existing hardware types platform types:

* `LINUX`
* `WINDOWS`
* `RTOS`
* `FPGA_FIRMWARE`
* `BAREMETAL`

### Compatibility

Compatibility describes in three properties version information and what hardware and software a platform is compatible with.

#### Version ID

Version ID allows you to identify a particular version of a platform.

#### Operating System ID

#### Architecture

Architecture indicates the CPU architecture of the platform. Chassy has several supported architectures for platforms.

* `AMD64`
* `ARM64`
* `ARMv6`
* `ARMv7`
* `RISCV`

### Image

Specifies a Chassy Machine Image (CMI) associated with this platform definition. A CMI is a bootable full system image incorporating the operating system, kernel, device tree definitions intended for a specific platform.

### Name

Specifies a human-readable name assigned to your platform that you will see from the Chassy console.

### Access

Indicates the visibility of a platform. `PUBLIC` platforms can be used by anyone, but `PRIVATE` platforms are only available within your workspace. By default all platforms are private.


# Creating Chips

Chips indicate an individual deployment target. Chips are referenced in machines which make up fleets on Chassy's network.

## What are Chips?

Chips act as individual deployment targets and the basic building blocks for fleets. They are comprised of a handful of required properties, but any number of custom properties can be added as simple key-value pairs.

These required properties are *name*, *description* and *platform*. Platform refers to some pre-existing public or private software platform.

## How can I create a chip?

You can create a chip by clicking the *Fleet* button in the left-side navigation panel and then clicking the *chips* tab. You will see a *"+ Chip"* button in the top right which upon being clicked will display a form asking you to define your new chip.

<figure><img src="/files/fE74i74a0ixDwDHDWVJB" alt="The Chip tab on the Fleet page shows you all the chips that you&#x27;ve created"><figcaption></figcaption></figure>

<figure><img src="/files/DGisqK6YghI1uoPGfDAW" alt="To add a new chip, fill out the Chip Name, Description, and Platform fields. Properties are optional."><figcaption></figcaption></figure>

You must specify your chip's name, description, and intended platform. You can also optionally define additional properties using the *Add Property* button which could be used to filter and organize information. When you're finished configuring your chip, the *Add Chip* button will save your configurations.


# Fleet User Guide

## What is a fleet?

A *fleet* is a collection of enrolled machines that Chassy recognizes as a deployment target. Fleets can be as small as one machine or extend to thousands. Fleets can be heterogeneous if need be, i.e., fleets can include machines of differing platforms and chips.

See the [Platform User Guide](/user-guides/platform-user-guide) for more information about platforms.

## What is the purpose of a fleet?

If you enroll machines in a fleet, you can deliver software changes to all of them with ease. You can also view the state of your machines from a glance and remotely access machines that make up a fleet.


# Creating a Fleet

A fleet is a collection of machines that collectively can be treated as a deployment target.

To create a fleet, you first must have an existing platform. If you're unfamiliar with platforms, it is recommended you first consult the [Platform User Guide](/user-guides/platform-user-guide).&#x20;

## How to create a fleet

If you navigate to the fleet panel and click the *Create Fleet* button, you will be greeted with the fleet creation wizard which will walk you through the setup process for your fleet.

<figure><img src="/files/vocN7NIgPmUWBb7OHEKW" alt="The Fleet panel gives you information on your existing machines and fleets."><figcaption></figcaption></figure>

You will first be asked to give your fleet a name and region. This information is useful later for monitoring.

<figure><img src="/files/KCzVoyvQ4razOtLKw9sR" alt="Enter a name for your new fleet, as well as the region it belongs in."><figcaption></figcaption></figure>

Upon clicking *Save & Continue*, your fleet will be created. If you have not created any chips, you will be asked to create a new chip for this fleet. This form is identical to the one found in the [Creating Chips](/user-guides/platform-user-guide/creating-chips) guide. This is so you can enroll your machines.

<figure><img src="/files/jbpIbjYfIZjYOsTsziHa" alt="If no chip has been created before creating a fleet, enter a new Chip Name, description, and platform."><figcaption></figcaption></figure>

If you have already created a chip, you will instead be asked first if you would like to select an existing chip. You can of course still opt to create a new chip using the *Add Chip* button.

<figure><img src="/files/UF6QWQhnUVmerleiODZD" alt="Pick the chip to assign to machines in this new fleet."><figcaption></figcaption></figure>

After you add a chip, you will be prompted with the machine enrollment form. You can follow the instructions on screen to enroll a new machine or you can opt to enroll later using the *Enroll Later* button. More information about enrolling machines can be found in the [Enrolling Machines](/user-guides/fleet-user-guide/enrolling-machines) guide.

<figure><img src="/files/lcTzsmGXghFF2iJj0g3T" alt="To add machines to your new fleet, you will have to prepare and install the command given on the screen."><figcaption></figcaption></figure>


# Enrolling Machines

To enroll a machine means to register a machine as a member of a fleet. It can be used as a deployment target for your software and automation.

This guide assumes you already have an existing fleet. If you do not have a fleet already, it is best to start with the [Creating a Fleet](/user-guides/fleet-user-guide/creating-a-fleet) guide as it will get you up and running.

## How to enroll machines

To enroll new machines, you can navigate to the *Fleet* panel on Chassy console and click *Add Machine* on your intended fleet.

<figure><img src="/files/BcmlISL4OVsbAzDBP9KD" alt="Each fleet has a Add Machine button to enroll a new machine into the fleet."><figcaption></figcaption></figure>

You will first be asked to select or create a new chip. After doing so, you can select *Continue*. If you wish to create a new chip, clicking the select menu will display an option prompting you to do so.

<figure><img src="/files/G0GC17g1RQi41fkmqu1G" alt="Select or add a new chip to assign to the new machines in the fleet."><figcaption></figcaption></figure>

After you have chosen or created a chip for these machines, you will be prompted with instructions for enrolling your machines as members in this fleet.

<figure><img src="/files/Wmy1lb8AhDqK5Py71UTE" alt="Follow the instructions on the screen to prepare and install the Chassy package onto the new machines."><figcaption></figcaption></figure>

### Step 1: Prepare your machines

There are a couple steps crucial to ensuring your machine can be enrolled properly. Carefully ensure the listed requirements are met then move on to step 2.

### Step 2: Install

This next step will provide you with a generated command to be ran on the system to be enrolled. This automated script will account for the bulk of the setup process. Wait a few minutes for it to complete.

{% hint style="info" %}
The `CHASSY_TOKEN` value in this command has a relatively short expiry for security reasons. If it expires while you are still working, worry not. You can generate a new one with the *Generate New Command* button.
{% endhint %}

{% hint style="warning" %}
Be careful not to leak the contents of this command as it contains the token required to register machines to this fleet. It will also expire relatively quickly.
{% endhint %}

### Step 3: Wait for connection

Chassy will display a count of all the machines enrolled to help you keep track of your progress. Once all have connected, you can go ahead and click the *Complete* button.

{% hint style="info" %}
It may take a few minutes for your enrolled machine to appear in the Chassy Console.
{% endhint %}

## Enrolling Firmware Devices

If you are enrolling a firmware or baremetal device on Chassy, refer to the [Enrolling ESP32 Devices](/user-guides/fleet-user-guide/enrolling-machines/enrolling-esp32-devices) guide.&#x20;


# Enrolling ESP32 Devices

The following section outlines how to enroll an ESP32 machine. It is expected that your host machine is already set up with the ESP-IDF development environment. Please refer to the [espressif docs](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html) for more information.

## Requirements

To have your ESP32 firmware be compatible with the Chassy Component, a few requirements need to be met.&#x20;

#### ESP-IDF Version

The Chassy Component requires at least [ESP-IDF 5.4.1.](https://github.com/espressif/esp-idf/releases/tag/v5.4.1)&#x20;

#### OTA Configuration Requirements

At a minimum, it is expected for their to be at least two OTA APP partitions present.&#x20;

An example of such configs can be found in the built in partition tables **Factory app, two OTA configurations** or **Two large size OTA partitions** in partitions.csv of ESP-IDF. More information can be found in the[ ESP-IDF docs](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/partition-tables.html).

#### Non Volatile Storage (NVS) Requirements

Non-volatile storage of at least 2kb is required. This is used to store chassy library specific information such as access keys and identification information.

&#x20;More information on how to configure the NVS can be found in the [ESP-IDF docs](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/kconfig.html#nvs)

## Enrolling your Device

Start the enrollment process as outlined in the [Enrolling Machines guide](/user-guides/fleet-user-guide/enrolling-machines).&#x20;

On the Select Chip Section, select a baremetal or firmware chip and click Continue.

<figure><img src="/files/jcLbfZPh5L6QezS1LEd5" alt=""><figcaption><p>Fleet Enrollment</p></figcaption></figure>

In Step 1, ensure that your host machine has ESP-IDF 5.4.1 installed and has root access.&#x20;

In Step 2, fill in all the fields.&#x20;

Storage Offset and Storage size refers to the Non Volatile Storage (NVS) address and size.&#x20;

Serial Port refers to the COM port the ESP32 device is connected to. In most cases, this is `/dev/ttyUSB0`.&#x20;

SDKConfig Path refers to the sdkconfig file that is generated when running `idf.py menuconfig`.  For more information on how to generate an sdkconfig file, plesae refer to the [ESP-IDF docs](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/kconfig.html).

Partition CSV Path refers to the Non Volatile Storage (NVS) csv file that is flashed to the board prior to boot. If you do not have any data to store in the NVS, leave this blank and a csv file will be generated for you. For more information on the NVS csv and it's format, please refer to the [ESP-IDF docs](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/storage/nvs_partition_gen.html#csv-file-format).

<figure><img src="/files/378iVFUGRQytpHRIMBCF" alt=""><figcaption></figcaption></figure>

Optionally, you can also include Wi-Fi connection information such as the SSID and Password.&#x20;

## Install

Copying and executing the command on your host machine will both enroll the host machine as well as  the ESP32 device. For enrolling the device, three main steps are involved:

* Ensure partition table is configured to allow OTA updates
* Add Chassy specific information to Non Volatile Storage (NVS) csv
* Flash NVS to chip.

The final step to complete enrollment is to boot and run`heartbeat()` at least once.&#x20;


# Managing a Fleet

Now that you have a fleet with enrolled machines, there are some things you should know about managing your fleet.

## Machine states

On the *Fleet* panel, Chassy displays each fleet and a color indicating the status of each of their machines. It also displays a count on the right side. This is a helpful top-level view for the status of your fleet.

<figure><img src="/files/oswbbrfIVMc6f731NEg5" alt="The Fleet panels gives you an overview of the fleets&#x27; and machines&#x27; statuses."><figcaption></figcaption></figure>

Clicking the fleet will prompt some information about the fleet to appear on screen for your viewing.

<figure><img src="/files/kPL1ia0nvJOxXZodOUpm" alt="The sidebar has more detailed information about the fleet, including a list of machines and deployments."><figcaption></figcaption></figure>

You can also click on any colored boxes to view information about an individual machine's status. A panel will appear on the right side of your screen with detailed information about the machine.

<figure><img src="/files/tEvkXYMrlOwSPHvyuFwN" alt="The machine detail sidebar will show information like the machine&#x27;s status, ID, IP address, and the last contact date and time."><figcaption></figcaption></figure>

You can also see all of your machines from a top level view in the *Machines* tab. From this view, you can also toggle filters and change the arrangement setting.

<figure><img src="/files/bHRW8zexI8WTCkqXkdN0" alt="The Machine tab gives you a list of all enrolled machines and their statuses."><figcaption></figcaption></figure>

Clicking any machine from this view will show the same panel as from the *All* tab.

<figure><img src="/files/8nEA0iSQBvrDltipcqUY" alt="Click onto any machine to get more detailed information on the sidebar."><figcaption></figcaption></figure>


# Local Storage Capability

Local storage access provides engineers with a dedicated persistent directory for storing critical assets like maps and models that must survive deployment cycles.

Prior to supporting local storage, every Chassy deployment to fleets would result in a new immutable deployment of code and data with no option to persist them beyond the lifespan of a deployment. With this new ability you can mark packages intended to be deployed in a release as persistent, and also write application data directly to the persistent directory `/persistent` for use later. This is ideal for storing large artifacts such as maps and personalized user configurations.

**Key Benefits:**

* Persistent storage of maps and models across deployments
* Reduced deployment time by eliminating redundant data uploads
* Improved operational continuity for production systems
* Enhanced data management capabilities for engineering teams

## Prerequisites and Compatibility

Any machines enrolled before August 1, 2025 must be re-enrolled to Chassy to enable local storage functionality. Follow the instructions on the [Enrolling Machines](/user-guides/fleet-user-guide/enrolling-machines)guide and run the enrollment script again to re-enroll your devices.

Fleets created after August 1, 2025 will have this feature automatically enabled.

To check if your fleet is compatible, go to the *Fleets* panel of Chassy Console, and click on your fleet. If the fleet was created before August 1, 2025, you'll see an option to *Enable* local storage in the fleet settings on the side panel.

<figure><img src="/files/LbAz96jfHFSl4nw0qQ5J" alt="A button to enable local storage is shown on the side panel of fleet details."><figcaption></figcaption></figure>

Confirm enabling Local Storage on the pop up modal. If successful, a notification will pop up saying "Fleet was successfully updated," and the option to *Enable* local storage in the fleet settings will disappear.

## How to Use Persistent Storage

To utilize this new feature, simply direct your code to save any files to the `/persistent` directory on the target device.

Chassy does not impose any limitations on file size or types, but be aware of your machines' remaining memory space.


# Workflow User Guide

Workflows allow you to automate the process of building and delivering software to your robots. Chassy provides an intuitive graphical editor for creating, modifying, and viewing workflows. In the next chapter, you'll learn how to create them.

Before you begin creating workflows, you will need to enable the [GitHub](/reference/integrations/github) integration first.

As you read the user guide, it may at times be useful to consult the [Workflow Components](/reference/workflow-components) reference which gives detailed definitions for various parts of Chassy's workflows.


# Creating a Workflow

## Prerequisites

To begin creating workflows, you must first enable the [GitHub](/reference/integrations/github) integration.

## How to create a workflow

To create a new workflow, first navigate to the *Workflows* panel and click the *Create Workflow* button.

<figure><img src="/files/PcwAG37w33kqv56og61A" alt="On the Workflows panel, the Create Workflow button is found on the top right corner."><figcaption></figcaption></figure>

After clicking *Create Workflow*, you will be prompted to input some information about your workflow. This information includes a name, a description, and optionally an email address and a slack channel. These optional inputs are for notifications. [Learn more about our Slack integration](/reference/integrations/slack).

After clicking *Save*, you will be prompted with the Workflow editor. If you change your mind about the inputs you configured before, you can always click *Configure* at the top to redefine those values.

<figure><img src="/files/R1j0Kqtj3MYWJrHFpTt0" alt="After naming your workflow, you will be brought to the visual workflow editor."><figcaption></figcaption></figure>

In the space above, you will find a graph representation of your workflow wherein each node (the rounded rectangle) represents a step in the workflow's execution. The workflow execution moves from left to right until completion. For more information about the anatomy of a workflow, consult the [Workflow Components](/reference/workflow-components) reference.

### Configuring steps

Clicking any of the steps will cause its configurations to appear below. *Details* shows the most basic facts about a step, the most impactful of which being the *type*. The type of step indicates what sort of processing will done during the execution of that step. For a complete breakdown of what each type of step does, consult the [Steps](/reference/workflow-components/steps) reference.

<figure><img src="/files/a8B11HJOWaYx6FRkCkHa" alt="Use the dropdown to select a task type for the step."><figcaption></figcaption></figure>

Upon selecting a type, you will see another configuration box for that particular task type. See the image below depicting configurations for a *deploy* step.

<figure><img src="/files/6C3rq7d6fPzI0Mf3a6jz" alt="Configurations for a Deploy step includes fleet selection, release selection, as well as which type and machines to deploy to."><figcaption></figcaption></figure>

In addition to *type*, you can also set a *name* and *timeout* for each step. The timeout represents a maximum duration for the step's execution. On every step except the first step, you can also set the *depends on* property which specifies where lines (edges) should be drawn in the graph. A line between steps *A* and *B* indicate that step *B* will follow step *A*.

### Creating new Steps

There are three ways to create new steps in a workflow. Firstly, you can create a step off an existing step. Clicking the **+** sign on a step *A* will create a new step that depends on *A*.

<figure><img src="/files/JDT6HYP1FAJiJ9rjZeFi" alt="Hovering over a step will show a plus button to the right of the box."><figcaption></figcaption></figure>

You can also create steps between existing steps. Hovering your cursor over a line in the graph will cause two buttons to appear which both add steps but in different ways.

<figure><img src="/files/KiS4sYgECjl0JeoP7whl" alt="Hovering over the line connecting steps show the fork button, and the plus button."><figcaption></figcaption></figure>

The button on the left sometimes called *fork* will create a new step *C* that depends on step *A* and leave step *B* unchanged as shown below.

<figure><img src="/files/cAyrDl1DH83JY9HpOjLK" alt="Clicking on the fork creates a new path branch."><figcaption></figcaption></figure>

The button on the right (the **+** sign) will create a new step *C* that depends on *A, and update B* to depend upon *C* as shown below.

<figure><img src="/files/3MySFEnBZJhOZG9R7JXf" alt="Clicking on the plus button inserts a step in between the two original steps."><figcaption></figcaption></figure>

### Finalizing configurations

When you're satisfied with your workflow, you can click the *Create Workflow* button to save your workflow. You'll be taken to the details page. You'll learn more about this page in the next chapter.

<figure><img src="/files/zzjgty7rUivDN7CkaGno" alt="The Details page shows an overview of the workflow."><figcaption></figcaption></figure>


# Packages and Releases

Packages and Releases are the essential elements of automation workflows in the Chassy Console.

## Packages

In Chassy, a package is an immutable reference to any application artifact imported/published to our storage platform (Chassy Index). These artifacts may be executables like binaries or containers, arbitrary files, archives, and much more. When packages are available in Chassy, they can then be used within a workflow as part of a Release intended for deployments to machines or executed directly on machines as a way to issue commands.

{% hint style="info" %}
A package cannot be deployed without being included in a release.
{% endhint %}

{% hint style="info" %}
Packages of up to 50 GB are imported during the execution of a workflow using the [Import Package Step](/reference/workflow-components/steps#import-package).
{% endhint %}

While Chassy does not impose any versioning philosophy, we generally recommend following [semantic versioning](https://semver.org) for packages when possible. Packages may be associated with arbitrary version strings which can be queried and used to filter available packages in the Chassy Index.

## Releases

A release is a versioned bundling of one or more versioned packages intended to be deployed to machines belonging to a particular [Chip](/user-guides/platform-user-guide/creating-chips#what-are-chips) in a [Fleet](/user-guides/fleet-user-guide#what-is-a-fleet). Releases can be created using the [Release step](/reference/workflow-components/steps#release) in the workflow engine. A release can then be deployed to a fleet using the [Deploy step](/reference/workflow-components/steps#deploy).

All releases in Chassy must follow the [semantic versioning (semver)](https://semver.org) scheme. Manual versions can be specified directly or Chassy can generate compliant version numbers based on certain constraints you specify automatically.


# Running Workflows

The workflow details page shows information about past executions of a workflow. It also shows the sequence of steps.

In the *Workflows* pane, you will see all of your defined workflows. If a workflow has yet to be run, that will be explicitly stated accompanied by a workflow where each step has no status.

<figure><img src="/files/fHbL0H82xP3z0eKMLtCP" alt="Under each workflow name is a timestamp of the last time the workflow was run."><figcaption></figcaption></figure>

You can run workflows from this view by clicking the *play* button in the corner of a workflow.

Clicking the workflow will take you to the workflow details page. You can also run the workflow from this page.

<figure><img src="/files/Yy9PNty9vmxHtP1vbnWz" alt="The workflow details page shows you more information about the workflow, as well as a Run Workflow button on the top right corner."><figcaption></figcaption></figure>

However you choose to run the workflow, doing so will create a new workflow run whose progress can be viewed either from the *Workflows* pane or from the workflow details page. When the workflow is finished executing, it will be shown in a *success* state.

Each step will be colored a green color indicating its success. Other colors indicate other information. Read more about step statuses in the [Workflow Components](/reference/workflow-components#step-status) reference.

<figure><img src="/files/h8YHfYVQOw2OY4Wg5wT7" alt="The dropdown under the workflow name shows each run&#x27;s timestamp and status."><figcaption></figcaption></figure>

You can view information about a particular run using the dropdown menu in the top left.


# Managing Workflows

Modifying workflows is not all too different from creating them.

## How to update a workflow

If you find that you need to alter steps or create new steps within an existing workflow, you can do so quite simply. First, navigate to the *Workflows* pane and select your workflow. Clicking *Configure* will bring you back to the workflow editor where you can make your desired changes. For more information on these configurations, see [Creating a Workflow](/user-guides/workflow-user-guide/creating-a-workflow#configuring-steps). You can also change the name, description, or notification settings of the workflow using the *Change Name* button.

## Next steps

Now that you're familiar with workflows, you can take your automation up a notch following one of our other guides:

* [Integrating with GitHub](/operator-guides/integrating-with-github)
* [Deploy an Artifact](/tutorials/deploy-an-artifact)


# Generate Chassy Tokens

Learn to generate Chassy tokens for use with our GitHub actions

Chassy's GitHub actions require that you provide a Chassy token for authentication. This guide will get you up and running with the generation of Chassy tokens.

{% embed url="<https://youtu.be/3LFd866TpFk?feature=shared>" %}
Video tutorial alternative
{% endembed %}

{% hint style="info" %}
Only an Admin or Manager is allowed to generate Chassy Tokens
{% endhint %}

{% hint style="danger" %}
These tokens are secret and the compromise of such tokens would allow malicious actors to execute your workflows or upload packages to the Chassy Index on your behalf. It is strongly recommended to take care to keep them safe using best practices.
{% endhint %}

## How to generate Chassy Tokens

This guide assumes you already have a Workspace. If you do not, please consult our guide instructing how to [Create a Workspace](/getting-started/create-a-workspace).

First, navigate to the *Settings* tab in the Chassy Console. There, you will see your account settings.

<figure><img src="/files/R0VX7Y6flP2JHpR0jDRC" alt="The Generate Chassy Token section is below the Permissions section on the Settings tab."><figcaption></figcaption></figure>

To generate your token, just click the *Generate* button. Upon success, you'll see the censored token accompanied by a *Copy* button.

<figure><img src="/files/o84yWQD61Tn8dWNSnXmX" alt="Use the Copy button on the right of the censored token."><figcaption></figcaption></figure>

Clicking the *Copy* button will copy the token to your clipboard for use elsewhere.&#x20;

## Providing a token to your GitHub actions

To protect your secret, it is recommended that you use GitHub Secrets (see [documentation](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions)) to store and reference your secret in Actions workflows.

If you named your secret "CHASSY\_TOKEN", you can then define the `CHASSY_TOKEN` environment variable as follows:

```yaml
env:
    CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN }}
```


# Integrating with GitHub

If you're looking to integrate Chassy into your existing CI/CD pipelines, you might be interested in enabling automatic execution of workflows through the use of our GitHub Action. We have two actions to facilitate this functionality.

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center">Workflow Run Action</td><td>Automate the execution of Chassy workflows within your GitHub CI</td><td><a href="/pages/pPVhtxWJfO9dW145SI0u">/pages/pPVhtxWJfO9dW145SI0u</a></td></tr><tr><td align="center">Package Upload Action</td><td>Upload packages to the Chassy Index for use within workflows from your GitHub CI</td><td><a href="/pages/AzxAd4g00U9dPIaGMREe">/pages/AzxAd4g00U9dPIaGMREe</a></td></tr></tbody></table>


# Workflow Run Action

Automate the execution of workflows with the Workflow Run action.

This action is responsible for triggering the execution of a workflow in your workspace. This way, you can automate the execution of your workflows within existing CI pipelines.

## Authentication

To authenticate with Chassy API you need to supply an authentication token. Please consult our documentation on how to [Generate Chassy Tokens](/operator-guides/generate-chassy-tokens). The GitHub action consumes this value from an environment variable called `CHASSY_TOKEN`. Ideally, this secret information is stored within a GitHub action secret (see [GitHub Documentation](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions)) and can then be referenced within your workflows as follows:

```yaml
env:
    CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN }}
```

With this token provided, you can continue with configuration.

## Configuration

There are three configuration options for this workflow. Only `workflowId` is required. These configurations are all to be made within the `with` block in your actions YAML file.

### Workflow ID

The provided `workflowId` specifies which workflow you wish to run. It is required for the action to function.

### Sync

The optional `sync` boolean parameter (defaults to `true`) allows you to decide whether you want the action to await the completion of your workflow's execution before the action is complete. Turning this off will mean that your workflow isn't checked for successful execution.

### Parameters

The optional `parameters` parameter is a JSON-encoded catch-all for any user-defined data for workflow execution.

## Example

In the example below, our workflow will be executed synchronously with no custom parameters. Afterward, the results will be printed to standard out.

```yaml
example-action:
  name: Example Action
  runs-on: ubuntu-latest
  env:
    CHASSY_TOKEN: <my token>
  steps:
    - name: Run a workflow
      id: workflow-run
      uses: chassyflow/actions-workflow-run@v1.2.0
      with:
        workflowId: '<some workflow id>'
    - name: Print Workflow Output
      id: output
      run: echo "${{ steps.workflow-run.outputs.workflowexecution }}"
```

### Source

The source code for this action can be found in the [official GitHub repository](https://github.com/chassyflow/actions-package-upload).


# Upload Action

Upload packages of various kinds to the Chassy Index.

This action is responsible for uploading a package or image to the Chassy index. This is useful for uploading a package to Chassy to be used within the execution of a workflow.

{% hint style="info" %}
The maximum sizes for packages and images are 1 GB and 50 GB respectively. To import packages more than 1 GB, use the [Steps](/reference/workflow-components/steps#import-package) step in a Workflow.
{% endhint %}

## Authentication

To authenticate with Chassy API you need to supply an authentication token. Please consult our documentation on how to [Generate Chassy Tokens](/operator-guides/generate-chassy-tokens). The GitHub action consumes this value from an environment variable called `CHASSY_TOKEN`. Ideally, this secret information is stored within a GitHub action secret (see [GitHub Documentation](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions)) and can then be referenced within your workflows as follows:

```yaml
env:
    CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN }}
```

With this token provided, you can continue with configuration.

## Configuration

This action has eight configuration options – six of which are required.

### Name

Name of the package being uploaded. You can reference your package by this name in the Chassy Index.

{% hint style="info" %}
Name is required for all upload types except `EXECUTABLE`
{% endhint %}

{% hint style="warning" %}
Name will be ignored when type is `EXECUTABLE`  and path globs multiple files.
{% endhint %}

### Path

The `path` parameter specifies a fully qualified or glob path to locate your file. Your glob patterns may match multiple files, but this is only acceptable when uploading a type of `ARCHIVE` and `EXECUTABLE` with some slight differences in behavior. Some valid examples include:

* `**/release/web`
* `**/*.zip`
* `./target/release/web`&#x20;

When a path glob of type `EXECUTABLE` matches multiple files, each file is uploaded as an independent package with a name matching the uploaded file. This behavior differs from path globs of type `ARCHIVE` where the entire matching files are uploaded as a single zipped artifact resulting in a single package.

{% hint style="info" %}
When path globs multiple executables, the provided `name` is ignored in favor of the filename.
{% endhint %}

### Architecture

The `architecture` parameter specifies the architecture of the machine intended to be hosting the image.&#x20;

The supported values for architecture as follows:

* `"AMD64"`
* `"ARM64"`
* `"ARMv6"`
* `"ARMv7"`
* `"RISCV"`
* `"UNKNOWN"`

### OS

The `os` parameter specifies the operating system of the intended host machine. It accepts any string. This value is used to check for ABI compatibility for deployment to fleets. Some examples include:

* `ubuntu`
* `debian`
* `archlinux`

### OS Version

The `os_version` parameter specifies the version of the operating system for maintaining ABI compatibility. It accepts any string. Some examples include:

* `22.04`
* `12.0`
* `2024.11.01`

### Type

The `type` parameter specifies the type of package. It is provided as a string, but it only accepts a handful of values:

* `"FILE"`
* `"ARCHIVE"`
* `"IMAGE"`
* `"FIRMWARE"`

### Version

The optional `version` parameter specifies the version of the package being uploaded. It is not to be used with images. It accepts any string, but it is expected that you use [semantic versioning](https://semver.org).

### Classification

The optional `classification` parameter allows you to specify the class of artifact for packages or images. It is provided as a string, but there is a set of accepted values depending on what type you are uploading.

For `IMAGE`, the accepted classifications are `RFSIMAGE` and `YOCTO`.

For `ARCHIVE`, the only accepted classification is `BUNDLE`.

For `FILE`,  the accepted values are `EXECUTABLE`, `CONFIG`, and `DATA`.

For `FIRMWARE`, the only accepted value is `EXECUTABLE`.

### Partitions

The optional `partitions` parameter is a string pointing to a partition spec file. This is only used when uploading an image. This file can match glob patterns but should only match a single file. It is to be a JSON file of the structure below:

```json
[
  {
    "filesystemType": "ext4",
    "mountPoint": "/",
    "name": "root",
    "size": "2G",
    "startSector": 0,
    "partitionType": "83"
  }
]
```

This array can have as many partitions as you'd like so long as they fit the structure. All of the fields are required.

If you provide no partitions, an empty array will be assumed.

### Compression Scheme

The optional `compression_scheme` parameter is a string that specifies the compression scheme used for the image. The accepted values are:

* `NONE`
* `ZIP`
* `TGZ`

It's important to understand that specifying a compression scheme will not compress the image. It is simply a way to inform Chassy how the image was compressed beforehand. We do recommend compressing your images before uploading them because they can be quite large.

Otherwise, the default value is `NONE`.

### Raw Disk Scheme

Raw disk scheme is a string that specifies the raw disk scheme used for the image. The accepted values are:

* `IMG`
* `ISO`

### Access

Access is a string that specifies the access level of the artifact. The accepted values are (although case insensitive):

* `PUBLIC`
* `PRIVATE`&#x20;

The default value is `PRIVATE`.

### Entrypoint

Entrypoint is a multi-line string specifying the entrypoint of the archive. It is similar to a Dockerfile's `ENTRYPOINT` command. Entrypoint is required when uploading an archive and is simply ignored otherwise.

```yaml
entrypoint: |-
```

### Nuances of Archives

If your `path` matches multiple files and you're uploading an bundled archive, all of these files will be zipped together as a single archive and uploaded. Under any other circumstances, matching multiple files will result in an error.

If your `path` matches a single file that happens to be an archive in itself, it will simply be uploaded without further processing. This is determined based on the file extension. The extensions are the following:

* `.zip`
* `.tar`
* `.gz`
* `.deb`
* `.rpm`

## Example

### Packages

In the example below, a binary intended for ARM64 machines running ubuntu 20.04 is being specified at the glob path `**/release/web`.

```yaml
  example-pkg-upload:
    name: Example Package Upload
    runs-on: ubuntu-latest
    env:
      CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN }}
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@v4
      - name: Upload package
        id: test-action
        uses: chassyflow/actions-package-upload@latest
        with:
          name: "web"
          architecture: "AMD64"
          os: "ubuntu"
          os_version: "20.04"
          version: "1.0.0" # package version
          type: "FILE"
          path: "**/release/web"
          classification: "EXECUTABLE"
```

### Images

In the example below, an image intended for ARM64 machines built on ubuntu 20.04 is being specified at the path `images/base.img.zip` and partition data is being specified by the path `images/base.partitions.json`.

```yaml
  example-img-upload:
    name: Example image Upload
    runs-on: ubuntu-latest
    env:
      CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN }}
    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@v4
      - name: Upload image
        id: test-action-with-image
        uses: chassyflow/actions-package-upload@latest
        with:
          name: "base-img"
          architecture: "ARM64"
          os: "ubuntu"
          os_version: "20.04"
          type: "IMAGE"
          path: "images/base.img.zip"
          classification: "RFSIMAGE"
          partitions: "images/base.partitions.json"
          compression_scheme: "ZIP"
          raw_disk_scheme: "IMG"
```

### Archives

In the example below, an archive is being an uploaded and the entrypoint is specified to be the entrypoint.sh file at the root of the zip.

```yaml
example-archive-upload:
  name: Example Archive Upload
  runs-on: ubuntu-latest
  env: CHASSY_TOKEN
  steps:
    - name: Checkout
      id: checkout
      uses: actions/checkout@v4
    - name: Upload Archive to Chassy
      id: test-action
      uses: chassyflow/actions-upload
      with:
        name: 'example-archive'
        architecture: 'ARM64'
        os: 'ubuntu'
        os_version: '22.04'
        type: 'ARCHIVE'
        path: '**/bundle.zip'
        entrypoint: |-
          entrypoint.sh
```


# Publish an Artifact

Your artifacts can be used within [Workflows](/user-guides/workflow-user-guide) and included in [Releases](/user-guides/workflow-user-guide/packages-and-releases#releases) which can then be deployed to [Machines](/reference/hardware-hierarchy#machine).&#x20;

## Using Our Upload Action in GitHub Workflows

Our [Upload Action](/operator-guides/integrating-with-github/upload-action) for GitHub allows you to upload artifacts directly to the Chassy Index which can later be brought into Workflows using the[ *Find Package*](/reference/workflow-components/steps#find-package) step.

## Using External Sources

Using the [*Import Package*](/reference/workflow-components/steps#import-package) step, you can import artifacts from external sources such as (S3, Wasabi, Docker container registries, and more).


# Deploy an Artifact

You can deploy both containers and binaries with the Chassy platform. This guide contains instructions for both.

This guide assumes you have created a fleet. If you have not created one, it is recommended you read the [Fleet User Guide](/user-guides/fleet-user-guide) first.

If you're unfamiliar with Chassy Workflows, then starting with the [Workflow User Guide](/user-guides/workflow-user-guide) is a good resource.

## Create a new Workflow

{% tabs %}
{% tab title="Docker" %}

1. Go to the *Workflows* section and select create a new workflow. We can name it “Deploy Docker to fleet”.
2. We assume a fleet has already been created prior, so we will simply select “*Test Fleet*”.
3. Click “*Create Workflow*” to move onto the next step.
   {% endtab %}

{% tab title="Binary" %}

1. Go to the *Workflows* section and select create a new workflow. We can name it “Deploy Binary to fleet”.
2. We assume a fleet has already been created prior, so we will simply select “*Test Fleet*”.
3. Click “*Create Workflow*” to move onto the next step.
   {% endtab %}
   {% endtabs %}

## Add “Import Package” Task

{% hint style="info" %}
For this specific example, we will be importing from a Github Actions Workflow container. A full list of sources and docker registries we support can be found in the [Steps](/reference/workflow-components/steps#import-package)section of the Steps Reference Guide.
{% endhint %}

{% tabs %}
{% tab title="Docker" %}

1. There will be an empty unconfigured step called “*Step 1*” present. Select it and rename it to “Retrieve Docker Artifact”. Under the details menu, select “*Import Package*”. For the timeout, select a reasonable timeout for the download, such as 600 seconds.&#x20;
2. Under configuration, for *artifact name* enter the artifact name that is stated in the Github Actions (GHA) job. We will assume it’s gha\_docker for this example.
3. For Source, select "*Github Actions Workflow*". We assume that a certain GHA such as creating a release branch will trigger the generation of a docker container, and we’re retrieving that artifact.&#x20;
4. For Type, select “*Container*”.
5. Name the package name “application\_docker\_contaner”.&#x20;
6. For versioning, we will auto increment the minor release and thus select that option.
   {% endtab %}

{% tab title="Binary" %}

1. There will be an empty unconfigured step called “*Step 1*” present. Select it and rename it to “Retrieve Binary Artifact”. Under the details menu, select “*Import Package*”. For the timeout, select a reasonable timeout for the download, such as 600 seconds.&#x20;
2. Under configuration, for *artifact name* enter the artifact name that is stated in the Github Actions (GHA) job. We will assume it’s gha\_binary for this example.
3. For Source, select "*Github Actions Workflow*". We assume that a certain GHA such as creating a release branch will trigger the generation of a binary, and we’re retrieving that artifact.&#x20;
4. For Type, select “*Binary*”.
5. Name the package name “application\_binary”.&#x20;
6. For versioning, we will auto increment the minor release and thus select that option.
   {% endtab %}
   {% endtabs %}

## Add “Release” Task

{% tabs %}
{% tab title="Docker" %}

1. Locate the icon of the “Retrieve Docker Artifact” task icon in the workflow graph (this was created in the previous step). Hover your mouse over it and click the + icon. This will create a new task that depends on the “Retrieve Docker Artifact” task.
2. Under the details menu, select “*Release*” as the *Type*. Name this to be “Configure Release”. Set a reasonable value for the timeout, such as 300s.  You will observe that the “Retrieve Docker Artifact” task is already listed as a dependency on the “*depends on*” field.&#x20;
3. In the Configuration menu, under *Release Name*, enter a descriptive name for the release we’re about to create. We’ll call it “application\_docker\_release”.
4. We need to select the target chip this release will target. We assume that fleets and chips have already been previously defined, so we will simply select “x86\_ubuntu24.04\_LTS”.&#x20;
5. Under *Manifest*, we will now add fields to our release manifest. The rule of thumb is to add one manifest entry for each package. Since we only have one docker container to deploy, we only need one field. In the future if we have multiple packages to release, we can click the “*Add another package*” option to add another package entry. Under package name, we can use the same name we chose in the “Retrieve Docker Artifact”’s package name task, “application\_docker\_container”.
6. For the package version, we will simply use the latest.&#x20;
   {% endtab %}

{% tab title="Binary" %}

1. Locate the icon of the “Retrieve Binary Artifact” task icon in the workflow graph (this was created in the previous step). Hover your mouse over it and click the + icon. This will create a new task that depends on the “Retrieve Binary Artifact” task.
2. Under the details menu, select “*Release*” as the *Type*. Name this to be “Configure Release”. Set a reasonable value for the timeout, such as 300s.  You will observe that the “Retrieve Binary Artifact” task is already listed as a dependency on the “depends on” field.&#x20;
3. In the Configuration menu, under *Release Name*, enter a descriptive name for the release we’re about to create. We’ll call it “application\_binary\_release”.
4. We need to select the target chip this release will target. We assume that fleets and chips have already been previously defined, so we will simply select “x86\_ubuntu24.04\_LTS”.&#x20;
5. Under *Manifest*, we will now add fields to our release manifest. The rule of thumb is to add one manifest entry for each package. Since we only have one binary to deploy, we only need one field. In the future if we have multiple packages to release, we can click the “*Add another package*” option to add another package entry. Under package name, we can use the same name we chose in the “Retrieve Binary Artifact”’s package name task, “application\_binary”.
6. For the package version, we will simply use the latest.&#x20;
   {% endtab %}
   {% endtabs %}

## Add “Deploy” Task&#x20;

{% tabs %}
{% tab title="Docker" %}

1. Locate the icon of the “Configure Release” task icon in the workflow graph (this was created in the previous step). Hover your mouse over it and click the + icon. This will create a new task that depends on the “Configure Release” task.
2. Under the details menu, select “*Deploy*” as the *Type*. Name this to be “Deploy Container”. Set a reasonable value for the timeout, such as 300s.  You will observe that the “Configure Release” task is already listed as a dependency on the “depends on” field.&#x20;
3. Under *Fleet*, select the fleet to target. Since we already have a preconfigured fleet, we select “Test Fleet San Francisco”.&#x20;
4. Under “*Release*”, enter  “application\_docker\_release” from the field above.&#x20;
5. Under *Type*, we will select “Testbed”.&#x20;
6. Under *Count*, we select “All” to release to the whole fleet.
7. Under *Attributes*, we append some important information about what we’re deploying to. Under *OS Name*, we state Ubuntu Base. Under *OS Version*, we state 24.04. We leave *IP address* blank and enter the machine’s hostname “bot01”.&#x20;
   {% endtab %}

{% tab title="Binary" %}

1. Locate the icon of the “Configure Release” task icon in the workflow graph (this was created in the previous step). Hover your mouse over it and click the + icon. This will create a new task that depends on the “Configure Release” task.
2. Under the details menu, select “*Deploy*” as the *Type*. Name this to be “Deploy Binary”. Set a reasonable value for the timeout, such as 300s.  You will observe that the “Configure Release” task is already listed as a dependency on the “depends on” field.&#x20;
3. Under *Fleet*, select the fleet to target. Since we already have a preconfigured fleet, we select “Test Fleet San Francisco”.&#x20;
4. Under “*Release*”, enter  “application\_binary\_release” from the field above.&#x20;
5. Under *Type*, we will select “Testbed”.&#x20;
6. Under *Count*, we select “All” to release to the whole fleet.
7. Under *Attributes*, we append some important information about what we’re deploying to. Under *OS Name*, we state Ubuntu Base. Under *OS Version*, we state 24.04. We leave *IP address* blank and enter the machine’s hostname “bot01”.&#x20;
   {% endtab %}
   {% endtabs %}

## Complete and Run the Workflow

1. On the top right of the workflow graph, select *Create workflow*. This will create the workflow and you can see it newly created in the *Workflows* tab as well as its status.
2. Next we will need to hook it up to a Github action so it will run automatically.&#x20;


# Deploy an Archive Package

This guide will teach you how to create an end-to-end testbed deployment using the Chassy Console and GitHub.

The workflow we build will take the following structure:

1. Execute a GitHub Actions job to build our application and upload as a Package using the [Chassy Upload Action](/operator-guides/integrating-with-github/upload-action).
2. Find Package in the Chassy Index and bring into the Workflow context.
3. Create a Release containing our Package.
4. Deploy this Release to our Testbed Machine.

{% hint style="info" %}
You will need a configured [Chassy Workspace](/getting-started/create-a-workspace) with the [GitHub Integration](/reference/integrations/github) enabled and a [Fleet](/user-guides/fleet-user-guide) with at least one Testbed Machine.
{% endhint %}

## GitHub Workflow Configuration

Our package takes the form of a ZIP archive containing a binary and a configuration file. With this in mind, our GitHub action will use the configurations below:

```yaml
      - name: Upload package to Chassy Index
        uses: chassyflow/actions-package-upload@v2.5.0
        with:
          name: "compute-with-config"
          architecture: "AMD64"
          os: "ubuntu"
          os_version: "20.04"
          version: "0.0.1"
          type: "ARCHIVE"
          path: "bundle.zip"
          entrypoint: |-
            ./launcher.sh
```

All code and configuration can be found within our [cargo-workspace-example](https://github.com/chassyflow/cargo-workspace-example) repository. The GitHub Actions workflow can be found in the [workflows directory](https://github.com/chassyflow/cargo-workspace-example/blob/7e094a6af660f016b422392a334df679316650a4/.github/workflows/bundle-with-config.yml).&#x20;

{% hint style="info" %}
An executable `entrypoint` argument must be provided for an executable archive.
{% endhint %}

### Bundle Contents

| Name         | Contents and Purpose                                                                                             |
| ------------ | ---------------------------------------------------------------------------------------------------------------- |
| compute      | binary written in Rust that performs lengthy computations based on either a config file or environment variables |
| web          | binary written in Rust that spins up a web server on port 8080                                                   |
| compute.toml | TOML configuration file for the compute binary                                                                   |
| launcher.sh  | A shell script that will run a specified binary and pass any arguments through.                                  |

## Chassy Workflow Configuration

We will now [create a Chassy Workflow](/user-guides/workflow-user-guide/creating-a-workflow). Let's first create a step to run the GitHub Actions workflow described in the previous section.

### Dispatch GitHub Actions Workflow

<figure><img src="/files/L5lLqvu9GPtXsC89LbZn" alt="We start the workflow with a Run CI Job step, entering details including the GitHub Workflow, repository name and owner, Git Ref, and Job Input."><figcaption></figcaption></figure>

This is a *Run CI Job* step configured to run a GitHub Actions workflow. We can specify the GitHub Workflow simply by using the workflow file name or by using the actual workflow ID obtainable through the GitHub API. We must specify the name of the repository, the name of the organization, and the name of the ref.

### Find Uploaded Bundle

<figure><img src="/files/evrcVJHfvDTvc2MxNKaj" alt="The Find Package step is next, pulling the package that was imported in the previous step into the context of our current workflow."><figcaption></figcaption></figure>

Next we create a [Find Package](/reference/workflow-components/steps#find-package) step, bringing in the imported Package by providing the package name, type, and status.

### Create Release

<figure><img src="/files/H2kgsDoZzjLYAumCrf6t" alt=""><figcaption></figcaption></figure>

Then create a [Release](/user-guides/workflow-user-guide/packages-and-releases#releases) including the [Package](/user-guides/workflow-user-guide/packages-and-releases#packages) we just imported. In our example, we invoke the package three times, each time with different arguments. In the first invocation, we provide `compute compute.toml` which tells the launcher script to run the compute binary and pass the compute.toml argument.

### Deploy Archive Package

<figure><img src="/files/Weypoar1J8wTCxZNHbVe" alt=""><figcaption></figcaption></figure>

We then deploy our package to a specified machine within one of our fleets. If you need additional configurations such as environment variables, you can define these within the *advanced options*.

### Save and Run Workflow

On the top right of the workflow graph, select *Create workflow*. This will save the new workflow and you can click on each individual step and see the  configurations. Click on *Run workflow* to push it into action.

## Conclusion

Running this workflow will dispatch your GitHub Actions workflow and deploy the uploaded artifact to your testbed. In our [example](https://github.com/chassyflow/cargo-workspace-example), we deploy a Rust application as part of a ZIP archive including a configuration file.


# Debugging with Live Logs

By the end of this tutorial you'll know how to access your machine's Live Logs on Chassy, helping you debug efficiently.

Troubleshooting is key for deployed applications. This tutorial shows how to use Chassy's Live Logs to diagnose and resolve issues by accessing, navigating, and interpreting the interface to find root causes.

## Prerequisites

Before we start this tutorial, you will need:

* An existing [Fleet](/user-guides/fleet-user-guide)
* A [connected machine](/user-guides/fleet-user-guide/enrolling-machines) with an application deployed

{% hint style="info" %}
To learn how to deploy an application, follow our [Deploy an Artifact](/tutorials/deploy-an-artifact)tutorial.
{% endhint %}

## Accessing the machine

Now that everything is set up, we can find the specific machine that is running the application.

1. Go to the *Fleet* section of Chassy Console.
2. Find the Fleet that the machine belongs to.
3. Select the machine by clicking on its green box.

<figure><img src="/files/wzFTyeDiM2ZHh37g2NBl" alt="The Fleet panel of Chassy Console shows the fleets and machines enrolled into your Chassy workspace."><figcaption></figcaption></figure>

You can also click on the Machines tab and search, sort, and filter through all enrolled machines.

<figure><img src="/files/CGUgrkX2TB4ITIm5tHEB" alt="The Machines tab on the Fleet panel has search, sort, and filter options to help you find the device."><figcaption></figcaption></figure>

Once you find the machine, click on it to open up the side panel with details. If it is currently online, you'll find the option to open *Live Logs.*

<figure><img src="/files/0N3dlEZdRkOHvD76Y5Oi" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Can't find the *Live Logs* option? Check that the machine is currently online, and that there is an active deployment
{% endhint %}

## Searching through *Live Logs*

The Live Logs page shows everything that is being printed from the deployed application, split between the channels `stdout` and <kbd>`stderr`</kbd>.

<figure><img src="/files/hg7oOppIPficMHVcqD07" alt="The Live Logs shows in realtime what is printed out from your device&#x27;s application."><figcaption></figcaption></figure>

You can use the search bar to quickly parse through the lines, as well as toggle word-wrap for better readability.

If you have multiple applications running on the machine, use the dropdown to select the application whose logs you want to view.

## Troubleshooting

### Why can't I find the *Live Logs* button?

*Live Logs* will only appear if the machine is online, has an operating system running the Chassy agent, and currently has an active application deployed.

The Chassy agent is only available on Linux, Windows, and NixOS.

### How do I know which machine I deployed to?

To find the machine, go to the *Machine* tab on your *Fleet* panel. You'll be able to see all active deployments on each machine, and can also filter the list by the application deployed.

### Why does it say I'm disconnected?

There is a 10 minute limit imposed to avoid streaming data indefinitely. Simply click on the *Connect* button on the top right, and you'll be able to read all logs.

## Conclusion

In this tutorial, we've walked through the process of accessing and utilizing Chassy's Live Logs feature. You now know how to view `stdout` and `stderr`, filter information, and troubleshoot issues to diagnose and resolve problems in your deployed applications. This tool offers valuable real-time insight, helping you maintain healthy and reliable deployments.


# Speed up Development Using CI Job Inputs

Our Run CI Job step allows you to optionally specify parameters to provide to your external CI service. This guide will go over a handful of things you can do with an example Rust project.

While this guide focuses on a Rust example project, these ideas can come in handy for development in all sorts of different technologies. We will be pulling examples from our [cargo-workspace-example](https://github.com/chassyflow/cargo-workspace-example) repository.

## Optimize Build Times when Debugging

Rust has infamously slow compile times. When trying to rapidly test and iterate, this can be a pain point. Using CI job inputs and Rust compiler profiles, we can cut down on our minutes spent in CI. During local development, cargo will compile in debug mode for quicker compile times. Depending on the size of your project, this can increase compiler speed by anywhere from 2-10 times. In our example, our time compiling is cut in half.

### Add inputs to your GitHub Actions Workflow

{% code title=".github/workflows/bundle-with-config.yml" %}

```yaml
on:
  workflow_dispatch:
    inputs:
      debug:
        type: boolean
        description: Specify whether to build with debug
        required: false
        default: false
```

{% endcode %}

In our `workflow_dispatch` block, we can specify `inputs`. GitHub's API for inputs is rather flexible. Please consult their [official documentation](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#onworkflow_dispatchinputs) for more information.

We can now update our compile step to build in debug mode if this input is set to `true`. Otherwise, compile in release mode.

{% code title=".github/workflows/bundle-with-config.yml" %}

```yaml
      - name: Build
        run: cargo build $COMPILER_FLAG
        env:
          COMPILER_FLAG: ${{ github.event.inputs.debug == 'false' && '--release' || '' }}
```

{% endcode %}

This somewhat terse syntax just states that the `COMPILER_FLAG` variable should be defined as `--release` if debug is disabled or an empty string if debug is enabled. We then run our command as usual but append `$COMPILER_FLAG` to it.

Now if we enable this parameter in the Chassy Console, we can see our build times get cut down.

<figure><img src="/files/1eCkRAJgoL3BILzwgEKv" alt=""><figcaption><p>CI Job Configuration with Debug enabled</p></figcaption></figure>

Then if you want to begin compiling in release mode again, simply remove the input from your configuration or set it to `false`.

## Enabling/Disabling Tests and Checks

Consider a situation similar to the one we just considered. I'm quickly iterating and don't want to run certain tests or checks. I can accomplish this using job inputs too.

You could create individual inputs controlling the execution of each check, but for this example, we will simply skip linting, testing, and formatting if we're running in debug mode. As in the first example, ensure you have a debug input:

{% code title=".github/workflows/bundle-with-config.yml" %}

```yaml
on:
  workflow_dispatch:
    inputs:
      debug:
        type: boolean
        description: Specify whether to enable debug mode
        required: false
        default: false
```

{% endcode %}

Then for each check, you conditionally skip it with an `if` condition like so:

<pre class="language-yaml" data-title=".github/workflows/bundle-with-config.yml"><code class="lang-yaml">  cargo-test:
    name: Cargo Test
    runs-on: ubuntu-latest
<strong>    if: ${{ !inputs.debug }}
</strong>    steps:
      - name: Checkout
        id: checkout
        uses: actions/checkout@v4

      - name: Run tests
        run: cargo test
</code></pre>

In our example, we do the same for the `cargo-clippy` and `cargo-fmt` checks as well. Now let's make sure these checks either pass or are skipped before we build and upload the bundle.

<pre class="language-yaml" data-title=".github/workflows/bundle-with-config.yml"><code class="lang-yaml">  build_and_upload:
    name: Build and Upload
    runs-on: ubuntu-latest
<strong>    needs: [cargo-test, cargo-fmt, cargo-clippy]
</strong><strong>    if: |
</strong><strong>      always() &#x26;&#x26;
</strong><strong>        (needs.cargo-test.result == 'success' || needs.cargo-test.result == 'skipped') &#x26;&#x26;
</strong><strong>        (needs.cargo-fmt.result == 'success' || needs.cargo-fmt.result == 'skipped') &#x26;&#x26;
</strong><strong>        (needs.cargo-clippy.result == 'success' || needs.cargo-clippy.result == 'skipped')
</strong>    env:
      CHASSY_TOKEN: ${{ secrets.CHASSY_TOKEN_DEV }}
      BACKEND_ENV: DEV

    steps:
</code></pre>

If we disable the `debug` input, these checks are simply skipped and we then build in debug mode. Below illustrate the difference in workflow execution.&#x20;

{% tabs %}
{% tab title="Without Debug" %}

<figure><img src="/files/NZUqBge2D51yBlJMV4pe" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="With Debug" %}

<figure><img src="/files/39v4H88yVwhvj71i6Y1n" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}


# Set Up Docker File for SITL Simulation

This guide will walk you through how to set up your docker file to execute Software-in-the-Loop simulation tests. At the end of the page, you'll find an example docker file for the px4-gazebo.

The docker file is what will be mounted by Chassy and execute your simulation tests. This offers maximum flexibility on the your end to define their simulation environment as you wish while still being able to run in a structured environment as well as produce reports.

## Basic Mountpoints

When Chassy runs your docker image, the following mounts will be added with their corresponding functions:

### **/opt/chassy/src**

Your GitHub source code will be mounted here. It is best practice to include all artifacts required for simulation such as robot, world, and launch files in your git repository so they can be included lock-step with your simulation.

### **/opt/chassy/simulate**

This executable is the entrypoint to how Chassy will run your simulation. Provide all necessary arguments and commands to run your simulation.

### **/opt/chassy/reports**

The user’s tests are responsible for populating the reports directories in order for results to be reported and displayed by Chassy. The following report types are currently supported, and more are being added.

#### **JUnit Reports**

JUnit reports serve as the basic status reports for testing suites. Reports are to be saved in the root directory of `/opt/chassy/reports` as JUnit XML files. Each test suite can have its own separate XML file.

```sh
  /opt/chassy/reports/
  ├── junit_setup_validation.xml       
  ├── test-results-minimal.xml         
  ├── test-results-gazebo.xml          
  ├── test-results-flight.xml          
  └── test-results-integration.xml      # Combined test results
```

#### **Screenshots and GIFs**

Screenshots and GIFs are to be stored under a screenshots directory. Subdirectories should denote test-suites and can contain either screenshots and GIFs.

```sh
 /opt/chassy/reports/
  ├── gazebo-test-results-integration.xml    # Test Suite 03-04 JUnit results
  ├── gazebo-test-results-manipulation.xml   # Test Suite 05 JUnit results
  ├── gazebo-test-results-simulation.xml     # Test Suite 02 JUnit results
  ├── gazebo-test-results-unit.xml          # Test Suite 01 JUnit results
  ├── screenshots/
  │   └──manipulation/                     # Test Suite 05 visual docs
  │       ├── observer_camera::link::scene_camera_0.png   # Frame 0
  │       ├── observer_camera::link::scene_camera_1.png   # Frame 1
  │       ├── ...                           # Frames 2-21 (22 total)
  │       ├── observer_camera::link::scene_camera_21.png  # Frame 21
  │       ├── unknown_test_animation.gif    # 303KB animated GIF  
```

#### **Universal Scene Description (USD) Files**

Some simulation engines such as Nvidia Isaac offers the ability to save scene state. Place them in the `OVD` subdirectory. Group USD files by test and have a directory for each of them. In the example below, we list them as `TESTNAME_TIMESTAMP`, however that is good practice and not required. Accompanying JSON files can contain metadata for each test that will be displayed alongside each test.&#x20;

```sh
/opt/chassy
└── reports
    ├── junit_isaac_environment.xml
    ├── ovd
    │   ├── articulated_robot_20250907_171459_856
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   └── summary.json
    │   ├── collision_detection_20250907_171333_867
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   ├── state_005.json
    │   │   ├── state_005.usd
    │   │   ├── state_006.json
    │   │   ├── state_006.usd
    │   │   └── summary.json
    │   ├── rigid_body_physics_20250907_171315_612
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   ├── state_005.json
    │   │   ├── state_005.usd
    │   │   └── summary.json
    │   └── robot_loading_20250907_171440_848
    │       ├── state_001.json
    │       ├── state_001.usd
    │       ├── state_002.json
    │       ├── state_002.usd
    │       └── summary.json
    ├── test-results-isaac-core.xml
    ├── test-results-isaac-init.xml
    ├── test-results-isaac-physics.xml
    └── test-results-isaac-robot.xml
```

#### **MCAP**

MCAP logs can be grouped by process as shown below:

```sh
/opt/chassy/reports/
├── camera/
│   ├── 2025-09-11T10-15-00Z_camera_run001.mcap
│   ├── 2025-09-11T10-30-00Z_camera_run002.mcap.zst
│   └── latest.mcap -> 2025-09-11T10-30-00Z_camera_run002.mcap.zst
├── perception/
│   ├── 2025-09-11T10-15-05Z_perception_run001.mcap
│   └── latest.mcap -> 2025-09-11T10-15-05Z_perception_run001.mcap
├── planning/
│   ├── 2025-09-11T10-16-10Z_planning_run001.mcap.lz4
│   └── latest.mcap -> 2025-09-11T10-16-10Z_planning_run001.mcap.lz4
├── controls/
│   ├── 2025-09-11T10-16-12Z_controls_run001.mcap
│   └── latest.mcap -> 2025-09-11T10-16-12Z_controls_run001.mcap
└── prediction/
    ├── 2025-09-11T10-16-15Z_prediction_run001.mcap
    └── latest.mcap -> 2025-09-11T10-16-15Z_prediction_run001.mcap
```

### **/opt/chassy/logs**

All logs should be stored in `/opt/chassy/logs` to be ingestible by Chassy. Chassy currently supports the following log types, and more are being added everyday.&#x20;

#### **ROS and ROS2: Rosconsole / rosout / rcllogging**

It is recommended to configure ROS to change the default directory of ros logs from `~/.ros/log` to `/opt/chassy/logs/` to facilitate this.

```sh
/opt/chassy/log/
├── 2025-09-11-09-42-05/                  # timestamped run directory
│   ├── rosout.log                        # aggregated text log
│   ├── events.log                        # structured event log (YAML/JSON)
│   ├── launch.log                        # launch system messages
│   ├── my_robot_driver-1-stdout.log      # logs from a specific node
│   ├── my_robot_driver-1-stderr.log
│   ├── lidar_node-2-stdout.log
│   ├── lidar_node-2-stderr.log
│   └── <other-node-logs>...
├── 2025-09-11-10-15-32/                  # another run (new timestamp dir)
│   ├── rosout.log
│   ├── events.log
│   ├── launch.log
│   ├── navigation_node-3-stdout.log
│   ├── navigation_node-3-stderr.log
│   └── camera_node-4-stdout.log
```

#### **Google Logs**

For glogs, please store them using glog extensions (ie `log.LOGLEVEL`)

```sh
/opt/chassy/logs/glogs
├── camera/
│   ├── camera.INFO -> camera.robotA.ops.log.INFO.20250911-101532.27451
│   ├── camera.WARNING -> camera.robotA.ops.log.WARNING.20250911-101534.27451
│   ├── camera.ERROR -> camera.robotA.ops.log.ERROR.20250911-102115.27451
│   ├── camera.robotA.ops.log.INFO.20250911-094205.27110
│   ├── camera.robotA.ops.log.INFO.20250911-101532.27451
│   ├── camera.robotA.ops.log.WARNING.20250911-095010.27110
│   ├── camera.robotA.ops.log.WARNING.20250911-101534.27451
│   └── camera.robotA.ops.log.ERROR.20250911-102115.27451
├── perception/
│   ├── perception.INFO -> perception.robotA.ops.log.INFO.20250911-101533.27702
│   ├── perception.WARNING -> perception.robotA.ops.log.WARNING.20250911-101540.27702
│   ├── perception.robotA.ops.log.INFO.20250911-094207.27333
│   ├── perception.robotA.ops.log.INFO.20250911-101533.27702
│   └── perception.robotA.ops.log.WARNING.20250911-101540.27702
├── planning/
│   ├── planning.INFO -> planning.robotA.ops.log.INFO.20250911-101536.27901
│   ├── planning.ERROR -> planning.robotA.ops.log.ERROR.20250911-101842.27901
│   ├── planning.robotA.ops.log.INFO.20250911-094210.27400
│   ├── planning.robotA.ops.log.INFO.20250911-101536.27901
│   └── planning.robotA.ops.log.ERROR.20250911-101842.27901
├── controls/
│   ├── controls.INFO -> controls.robotA.ops.log.INFO.20250911-101537.28045
│   ├── controls.WARNING -> controls.robotA.ops.log.WARNING.20250911-102002.28045
│   ├── controls.robotA.ops.log.INFO.20250911-094211.27450
│   ├── controls.robotA.ops.log.INFO.20250911-101537.28045
│   └── controls.robotA.ops.log.WARNING.20250911-102002.28045
└── prediction/
    ├── prediction.INFO -> prediction.robotA.ops.log.INFO.20250911-101538.28190
    ├── prediction.robotA.ops.log.INFO.20250911-094212.27501
    └── prediction.robotA.ops.log.INFO.20250911-101538.28190
```

#### **C++ spd logs**

If using SPD logs, store logs using the `.log` extension.

```sh
/opt/chassy/logs/
├── camera/
│   ├── camera.log                    # main rolling log
│   ├── camera.1.log                  # rotated log (older)
│   ├── camera.2.log
│   └── ...
├── perception/
│   ├── perception.log
│   ├── perception.1.log
│   ├── perception.2.log
│   └── ...
├── planning/
│   ├── planning.log
│   ├── planning.1.log
│   ├── planning.2.log
│   └── ...
├── controls/
│   ├── controls.log
│   ├── controls.1.log
│   ├── controls.2.log
│   └── ...
└── prediction/
    ├── prediction.log
    ├── prediction.1.log
    ├── prediction.2.log
    └── ...
```

It is good practice to setup a rotating logger so unexpected failures will not result in lost logs, such as in this example:

```cpp
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"

int main() {
    // Example for the "camera" module
    auto logger = spdlog::rotating_logger_mt(
        "camera_logger",              // logger name
        "/opt/chassy/logs/camera/camera.log", // log file path
        10 * 1024 * 1024,             // max file size (10 MB)
        5                             // keep up to 5 rotated files
    );

    spdlog::set_level(spdlog::level::debug);  // global log level
    logger->info("Camera module started");
    logger->warn("Low light detected");
    logger->error("Camera stream lost!");
}
```

#### **Python Logs**

For python logging, it is good practice to setup a rotating logger using the `logging` module.

```sh
/opt/chassy/logs/
├── camera/
│   ├── camera.log
│   ├── camera.log.1
│   ├── camera.log.2
│   └── ...
├── perception/
│   ├── perception.log
│   ├── perception.log.1
│   └── ...
├── planning/
│   ├── planning.log
│   ├── planning.log.1
│   └── ...
├── controls/
│   ├── controls.log
│   ├── controls.log.1
│   └── ...
└── prediction/
    ├── prediction.log
    ├── prediction.log.1
    └── ...
```

Example python code:

```python
import logging
import logging.handlers
import os

def setup_logger(module_name, log_dir="/opt/chassy/logs", max_bytes=10*1024*1024, backup_count=5):
    """
    Creates a rotating file logger for a specific robotics module.
    
    :param module_name: e.g., "camera", "perception", "planning"
    :param log_dir: base directory for logs
    :param max_bytes: max log size before rotation (default 10 MB)
    :param backup_count: number of rotated logs to keep
    """
    module_dir = os.path.join(log_dir, module_name)
    os.makedirs(module_dir, exist_ok=True)

    log_file = os.path.join(module_dir, f"{module_name}.log")

    logger = logging.getLogger(module_name)
    logger.setLevel(logging.DEBUG)  # or INFO/WARNING depending on module

    # File handler with rotation
    handler = logging.handlers.RotatingFileHandler(
        log_file, maxBytes=max_bytes, backupCount=backup_count
    )

    formatter = logging.Formatter(
        fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S"
    )
    handler.setFormatter(formatter)

    # Avoid duplicate handlers on repeated setup
    if not logger.handlers:
        logger.addHandler(handler)

    return logger

# Example usage for the camera process
if __name__ == "__main__":
    camera_logger = setup_logger("camera")
    camera_logger.info("Camera module started")
    camera_logger.warning("Low light detected")
    camera_logger.error("Camera stream lost!")
```

### **/opt/chassy/artifacts (Under Development)**

In the future, Chassy will provide another mount option to allow large immutable infrastructure artifacts such as world files, mapping data or other models to be mounted separately from Chassy Index.

## Example Dockerfile

The primary purpose of the dockerfile is to setup your simulation environment. Below we have an example dockerfile to setup a simulation environment for the px4-gazebo, either using CPU only simulation or CPU and GPU.&#x20;

Note that this is intended to act as a guideline and your dockerfile does not need to follow these conventions.

We will walk through each part of the dockerfile separately, and then view the resulting file in the end.

### Base Image

Starts from `nvidia/opengl:1.2-glvnd-runtime-ubuntu22.04` → provides Ubuntu 22.04 with NVIDIA OpenGL runtime support for GPU acceleration.

```sh
FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu22.04
```

### Environment Setup

Sets `DEBIAN_FRONTEND=noninteractive` to suppress interactive prompts during package installation.

```sh
ENV DEBIAN_FRONTEND=noninteractive
```

### Install Dependencies

Updates package lists and installs a large set of required tools and libraries:

* Build tools: curl, wget, git, cmake, build-essential, pkg-config
* Python: python3, python3-pip, python3-dev
* Libraries: libxml2-dev, libxslt-dev, libeigen3-dev, libopencv-dev, libgoogle-glog-dev, protobuf-compiler
* GStreamer stack: gstreamer1.0-plugins-bad, gstreamer1.0-libav, gstreamer1.0-gl, libgstreamer-plugins-base1.0-dev
* Other tools: xvfb (virtual framebuffer for headless rendering), mesa-utils, geographiclib-tools, software-properties-common, lsb-release, gnupg2, sudo, libimage-exiftool-perl
* NVIDIA runtime libraries: nvidia-utils-470, libnvidia-gl-470

Cleans up apt cache to reduce image size.

```sh
RUN apt-get update && apt-get install -y \
    curl \
    wget \
    git \
    cmake \
    build-essential \
    python3 \
    python3-pip \
    python3-dev \
    pkg-config \
    libxml2-dev \
    libxslt-dev \
    libeigen3-dev \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-libav \
    gstreamer1.0-gl \
    libgstreamer-plugins-base1.0-dev \
    libimage-exiftool-perl \
    geographiclib-tools \
    libeigen3-dev \
    libopencv-dev \
    libgoogle-glog-dev \
    protobuf-compiler \
    xvfb \
    mesa-utils \
    software-properties-common \
    lsb-release \
    gnupg2 \
    sudo \
    nvidia-utils-470 \
    libnvidia-gl-470 \
    && rm -rf /var/lib/apt/lists/*
```

### Gazebo Installation

* Adds OSRF Gazebo repository and GPG key.
* Installs gz-harmonic (Gazebo Harmonic simulator).
* Cleans apt cache.

```sh
RUN wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg \
    && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null \
    && apt-get update \
    && apt-get install -y gz-harmonic \
    && rm -rf /var/lib/apt/lists/*
```

### Simulation Environment Variables

Configures headless mode:

* HEADLESS=1
* DISPLAY=:99 for X virtual framebuffer
* NVIDIA-specific env vars for GPU usage (NVIDIA\_VISIBLE\_DEVICES, NVIDIA\_DRIVER\_CAPABILITIES, \_\_GLX\_VENDOR\_LIBRARY\_NAME)
* Forces Gazebo to use Ogre2 rendering engine.

```sh
ENV HEADLESS=1
ENV DISPLAY=${DISPLAY:-:99}
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
ENV __GLX_VENDOR_LIBRARY_NAME=nvidia
ENV GZ_SIM_RENDER_ENGINE=ogre2
```

### PX4 Workspace

* Creates working directory /opt/px4\_ws.
* Clones PX4-Autopilot repository (recursive clone to include submodules).
* Runs PX4 setup script (./Tools/setup/ubuntu.sh --no-nuttx) to install PX4 dependencies, skipping NuttX (firmware build system).

Cleans apt cache again.

```sh
WORKDIR /opt/px4_ws

RUN git clone --recursive https://github.com/PX4/PX4-Autopilot.git /opt/px4_autopilot

RUN cd /opt/px4_autopilot \
    && bash ./Tools/setup/ubuntu.sh --no-nuttx \
    && rm -rf /var/lib/apt/lists/*
```

### Python Dependencies for Testing & Simulation

Installs Python packages:

* pytest, pytest-xvfb (testing)
* psutil, pexpect (process utilities)
* mavsdk, pymavlink, pytest-asyncio (MAVLink-based drone communication)
* mss (screenshot utility)

```sh
RUN pip3 install --no-cache-dir \
    pytest \
    pytest-xvfb \
    psutil \
    pexpect \
    mavsdk \
    pytest-asyncio \
    pymavlink \
    mss
```

### PX4 Build

Builds PX4 in SITL mode (make px4\_sitl\_default).

```sh
RUN cd /opt/px4_autopilot \
    && make px4_sitl_default
```

### Set PX4 Environment Variables

* PX4\_HOME=/opt/px4\_autopilot
* Adds PX4 tools to PATH

```sh
ENV PX4_HOME=/opt/px4_autopilot
ENV PATH="${PX4_HOME}/Tools:${PATH}"
```

### Simulation Entrypoint Setup

* Copies a custom simulate script into /opt/chassy/simulate.
* Makes it executable.
* Sets this script as the Docker entrypoint, so containers run the simulation directly.

```sh
COPY simulate /opt/chassy/simulate
RUN chmod +x /opt/chassy/simulate

ENTRYPOINT ["/opt/chassy/simulate"]
```

### Full example

The full docker file can be found embedded below:

<pre class="language-sh"><code class="lang-sh"># Base image: Ubuntu 22.04 with NVIDIA OpenGL runtime (for GPU-accelerated rendering)
FROM nvidia/opengl:1.2-glvnd-runtime-ubuntu22.04

# Prevent interactive prompts during apt installs
ENV DEBIAN_FRONTEND=noninteractive

<a data-footnote-ref href="#user-content-fn-1"># Install core dependencies:</a>
RUN apt-get update &#x26;&#x26; apt-get install -y \
    curl \
    wget \
    git \
    cmake \
    build-essential \
    python3 \
    python3-pip \
    python3-dev \
    pkg-config \
    libxml2-dev \
    libxslt-dev \
    libeigen3-dev \
    gstreamer1.0-plugins-bad \
    gstreamer1.0-libav \
    gstreamer1.0-gl \
    libgstreamer-plugins-base1.0-dev \
    libimage-exiftool-perl \
    geographiclib-tools \
    libeigen3-dev \
    libopencv-dev \
    libgoogle-glog-dev \
    protobuf-compiler \
    xvfb \
    mesa-utils \
    software-properties-common \
    lsb-release \
    gnupg2 \
    sudo \
    nvidia-utils-470 \
    libnvidia-gl-470 \
    &#x26;&#x26; rm -rf /var/lib/apt/lists/*

# Install Gazebo Harmonic simulator from OSRF packages
RUN wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg \
    &#x26;&#x26; echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null \
    &#x26;&#x26; apt-get update \
    &#x26;&#x26; apt-get install -y gz-harmonic \
    &#x26;&#x26; rm -rf /var/lib/apt/lists/*

<a data-footnote-ref href="#user-content-fn-2"># Simulation environment variables</a>
ENV HEADLESS=1
ENV DISPLAY=${DISPLAY:-:99}
ENV NVIDIA_VISIBLE_DEVICES=all
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,utility,compute
ENV __GLX_VENDOR_LIBRARY_NAME=nvidia
ENV GZ_SIM_RENDER_ENGINE=ogre2

# Workspace directory
WORKDIR /opt/px4_ws

# Clone PX4-Autopilot (with submodules)
RUN git clone --recursive https://github.com/PX4/PX4-Autopilot.git /opt/px4_autopilot

# Run PX4 setup script (skip NuttX since we only need SITL)
RUN cd /opt/px4_autopilot \
    &#x26;&#x26; bash ./Tools/setup/ubuntu.sh --no-nuttx \
    &#x26;&#x26; rm -rf /var/lib/apt/lists/*

<a data-footnote-ref href="#user-content-fn-3"># Install Python dependencies for simulation and testing:</a>
RUN pip3 install --no-cache-dir \
    pytest \
    pytest-xvfb \
    psutil \
    pexpect \
    mavsdk \
    pytest-asyncio \
    pymavlink \
    mss

# Build PX4 in Software-In-The-Loop (SITL) mode
RUN cd /opt/px4_autopilot \
    &#x26;&#x26; make px4_sitl_default

# Environment variables for PX4
ENV PX4_HOME=/opt/px4_autopilot
ENV PATH="${PX4_HOME}/Tools:${PATH}"

# Copy custom simulation entrypoint script
COPY simulate /opt/chassy/simulate
RUN chmod +x /opt/chassy/simulate

# Entrypoint: runs the simulation inside Chassy
ENTRYPOINT ["/opt/chassy/simulate"]

</code></pre>

[^1]: * Build tools: curl, wget, git, cmake, build-essential, pkg-config
    * Python: python3, pip, dev headers
    * Libraries: eigen3, opencv, google-glog, protobuf
    * Simulation: GStreamer stack, geographiclib, xvfb (headless display), mesa-utils
    * Tools: exiftool, gnupg2, lsb-release, sudo
    * NVIDIA drivers: runtime utils + GL support

[^2]: * Enable headless mode with Xvfb
    * Configure NVIDIA GPU runtime
    * Force Gazebo to use Ogre2 render engine

[^3]: * pytest + pytest-xvfb: testing framework
    * psutil, pexpect: process utilities
    * mavsdk, pymavlink, pytest-asyncio: MAVLink communication & async tests
    * mss: screenshot capture


# Automate Board Provisioning

This guide will walk you through how to set up you remote proxy machine to automate provisioning boards.

## Pre-requisites

Before we start this tutorial, you will need:

* An AMD x86-64 or ARM device to act as a remote proxy device
* A board to be provisioned
* USB cable to connect the board to the remote proxy device
* A Remote Proxy [Fleet](/user-guides/fleet-user-guide)

{% stepper %}
{% step %}

### Enroll a Remote Proxy Device

Navigate to the **Remote Proxies** tab on the Fleet panel. If you haven't already, create a Remote Proxy Fleet to manage all of your upcoming proxy device enrollments. Make sure that the *Proxy Fleet* checkbox is ticked. Detailed instructions on how to create a fleet and enroll devices can be found at [Creating a Fleet](/user-guides/fleet-user-guide/creating-a-fleet) and [Enrolling Machines](/user-guides/fleet-user-guide/enrolling-machines) guides respectively.

{% hint style="warning" %}
Several NVIDIA-required packages must be present on the Linux host serving as the Remote Proxy. Install them by running the following command once in a terminal.

```
curl -sfL https://cdn.chassy.io/test/provision-dependencies | bash -
```

{% endhint %}
{% endstep %}

{% step %}

### Set Up a Provisioning Workflow

Create a new [Workflow](/user-guides/workflow-user-guide/creating-a-workflow) to set up your provisioning details. Utilize the [Find Package](/reference/workflow-components/steps#find-package) and [Import Package](/reference/workflow-components/steps#import-package) steps to upload files into Chassy Index when needed.

Add a [Provision Setup](/reference/workflow-components/steps#provisioning) step to select your remote proxy device, and provide details on how you want the connected boards to be set up. Run the workflow when completed.

<figure><img src="/files/mwQFFeESOtaAa4cAbTfU" alt="A screenshot of the Provision Setup step and its details"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Connect a Board to your Remote Proxy

Going back to the **Remote Proxies** tab on the Fleet panel, you should see your remote proxy machine and its status.

Put your board into recovery mode, then connect it to your remote proxy machine using a USB cable. The provisioning process will automatically begin. On the Chassy Console, you can see which provisioning phase the connected board is on: `Attached`, `Flashing`, `Configuring`, `Verifying`, `Succeeded`, `Error`, `Terminated`, or `Timed out`.

For connected boards that got `Error` , `Terminated` , or `Timed out` , you can restart the provisioning process by clicking on the restart button.

{% hint style="info" %}
Jetson boards have to be in recovery mode for it to be auto-detected and flashed by the remote proxy.
{% endhint %}
{% endstep %}

{% step %}

### Success! Your connected board is booting up.

The connected board will automatically reboot once the process is complete.
{% endstep %}
{% endstepper %}


# Workflow Components

Describes the key components of Chassy Console

## Workflows and their Steps

#### **Differences Between a Workflow and a Step**

In Chassy, a workflow is a collection of steps that are executed in a specific order. Each step can contain multiple tasks that must complete in parallel before the next step can begin.

Here is a summary of the key differences between workflows, steps, and tasks:

### **Workflow**

A workflow is a high-level representation of an automated process or pipeline consisting of multiple steps and tasks.

To relate workflows to a potentially familiar structure, workflows are structurally analogous to the mathematical notion of a graph, particularly a directed graph. If it is helpful, one may also notice that every workflow is also a tree.

| Chassy Notion             | Indicated By        | Math Analog |
| ------------------------- | ------------------- | ----------- |
| Workflow                  | Collection of steps | Graph       |
| Step                      | Rounded rectangle   | Vertex      |
| *Depends on* relationship | Lines between steps | Edge        |

### **Step**

A step is a unit of work that is executed as part of a workflow. There are several types of steps you can read more about in the [Steps](/reference/workflow-components/steps) reference. In graph theory terms, a step is the workflow analog for a vertex within a graph.

Steps can be said to depend on other steps to indicate a sequence of execution. If step *B* depends on step *A*, then step *B* will only execute after step *A* has completed. Step dependency is the workflow analog for an edge within a graph.

#### **Example of Multiple Steps within a Workflow**

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd7F0UTGPwGhyT1DooJqDVGdh8oLALeVmNaAOo6007pkH4vU-9q7Sec-lk5TR-MQgFTp43fDbi5QkWrlYSocTUWa-CntDEo98g_MDPpbSleT8uQv6Uu3PDTprwoTeC4jkx6Q_kF14W0gJPvnE2dhtaNWE9u?key=CrjAmK76ZdHhNlRMtvcEMw" alt="A workflow consists of multiple steps that follow and depend on the previous one, with possible forks."><figcaption></figcaption></figure>

In the above example, the vertically grouped tasks are in the same step. Steps are executed sequentially from left to right on the workflow graph.

#### Step Status

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc3GsmHWwOrDPJ32JJWlwPCuX9X7tP6r1hIyVXJm5rA4ihaXj8rrDVkh7EDoEw67v5BlCFSNMRjO0Dwe6CsI9u4hlI-KmzcwIxJIKbQbG_lLI9Hj4sMFtTgEidtY6HLZ0uj-U3Fe6noXnJKQ3e52txGZqo6?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Each step could be grey, green, yellow, or red, showing its status." width="188"><figcaption></figcaption></figure></div>

In the workflow graph, step statuses are denoted by color:

* Greyed out: Not started
* Green: Completed
* Yellow: Issue
* Red: Critical issue


# Steps

Documents all the different types of steps that can be used within workflows

## Import Package

The *import package* step will import an artifact of up to 50 GB from an external source into the Chassy Index.

{% hint style="danger" %}
Packages of less than 1 GB can be published directly from your CI, but any package 1 GB or more must be imported using this step.
{% endhint %}

The following external sources are supported:

* Docker Registries
  * AWS ECR
  * Azure Registries
  * DockerHub
  * GitHub Package Registry
  * Google Cloud Registry (GCR)
  * JFrog
  * Quay
  * On Prem Registries
* Artifactory
* AWS S3 Bucket
* Wasabi Bucket
* Hugging Face

{% hint style="info" %}
The GitHub Package Registry mentioned here is not to be confused with packages uploaded using our Package Upload Action. Packages uploaded via the Package Upload Action can already be found within the Chassy Index.
{% endhint %}

In Chassy’s context, *artifacts* are any inputs, outputs or deliverables produced during the development and delivery process. These artifacts can include applications binaries, compressed archives, container images or file systems. Artifacts play a crucial role in DevOps pipelines, as they enable the automation and traceability of the software delivery process.

<figure><img src="/files/Ly4mDXRQU18HzJTA3Web" alt="The Import Package step type contains of a name, timeout, and configurations of artifact name, source, type, package name, and versioning options."><figcaption></figcaption></figure>

#### **Details**

*Type* - to bring an artifact into the Chassy Index, create a new step, and select "Import Package" under type.

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

#### **Configuration**

*Artifact Name* - The Artifact Name field specifies the name of the artifact to be imported. This is the name used by the external source. For example, an artifact retrieved from an S3 bucket will be the S3 file path.

*Source* - The source from which the artifact is to be pulled. To import from a docker registry (AWS ECR, Azure Registries, DockerHub, Google Cloud Registry (GCR), JFrog, Quay, or an on prem registry), select *Docker Registry* as the source, and the system will automatically infer the hosting service once you provide the container’s fully qualified name under *Artifact Name*.

*Type* - The type of package (image, file, archive, etc).

*Versioning -* These options denote the versioning schema. By default, you can auto-increment the major release, the minor release, or the patch. If you wish to do something more custom, a regex field is present.

* Auto Increment Major Release: This option will automatically increment the major release number of the artifact each time a new version is created.
* Auto Increment Minor Release: This option will automatically increment the minor release number of the artifact each time a new version is created.
* Auto Increment Patch Release: This option will automatically increment the patch release number of the artifact each time a new version is created.
* Version Regex: This option allows you to specify a custom regular expression to use for versioning. The regular expression must match the version number of the artifact.

There are other configurations that relevant to your chosen *source*. For example, if you choose to import from AWS S3, you will need to provide a bucket name and file name.

#### Hugging Face-specific Configurations

*Include Patterns -* Specify which files to include in your download, in a JSON Array of paths supporting wildcards.

*Exclude Patterns -* Specify which files to exclude from your download, in a JSON Array of paths supporting wildcards.

{% hint style="info" %}
If no files are specified in the *Include Patterns* and *Exclude Patterns* fields, all files mentioned in `config.json`, as well as files with the following extensions will be imported: `.gguf`, `.safetensors`, `.onnx`, `.bin`, `.pt`, `.pth`, `.h5`, `.mlmodel`
{% endhint %}

*Revision -* The revision, version, tag, or branch to use.

## Find Package

The *find package* step will bring a package from the Chassy Index into the context of a workflow's execution. If you want to deploy a binary to a fleet, this binary will need to be found with *find package* before it can be deployed.

<figure><img src="/files/aZaROEZNRblQhRnpdFlX" alt="The Find Package step type contains of a name, timeout, and configurations of package name, version, package ID, and selection order."><figcaption></figcaption></figure>

#### Details

*Type* - To bring in an artifact, create a new workflow step and select “Find and Import” under Type.&#x20;

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

#### Configuration

*Package Name -* The package name is a unique identifier for an artifact within a workspace. It is used to reference the artifact in workflows and other contexts. When creating an artifact, you must specify a package name. The package name must be unique within the workspace and should accurately reflect the contents of the artifact. It is recommended to use a naming convention that is consistent with your organization's standards.

For example, if you are creating an artifact that contains the binaries for a web application, you might use the package name "web-app-binaries".

Chassy will take care of versioning so this should just be the “base name”. We follow the guidelines set in [Semantic Versioning](https://semver.org/).

*Version* - version of the package (packages are optionally versioned).

*Package ID* - ID of your preferred package (optional).

*Selection order* - the order in which collisions are handled when multiple packages are found with the provided configurations.

## Deploy

The *deploy* step distributes releases to a number of machines within a fleet. The key requirement of the deploy step is having an available release. See [#release](#release "mention") step for how to get a release.

<figure><img src="/files/ltEkelBQbVpcelB1fxVt" alt="The Deploy step type contains of a name, timeout, and configurations of fleet name, release name, type, machine selection, and optional properties."><figcaption></figcaption></figure>

#### Details

*Type -* To deploy a release, create a new workflow step and select “Deploy” under Type.&#x20;

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

The "Depends On" field is a powerful tool that can help you ensure that your workflows are executed correctly and efficiently.

#### **Configuration**

*Fleet - S*elect and list from the dropdown menu the fleet to target.

*Release -* Select the release to target. Please refer to Release above for more information.

*Type -* Currently supported types are Testbed and Production, more types coming soon.

*Count -* Select the number of Machines in the fleet to release to.

*Machine Select* - If your machine count is set to 1, select which machine you intend to deploy to.

*Environment* - In the advanced settings, define user environment variables to be set in the deployment environment. In addition to these values, Chassy sets some default environment variables with each deployment.

*Attributes*

* OS Name - the OS the package is to be deployed to.
* OS Version - the OS version the package is to be deployed to.
* IP Address - the target machine’s IP address. Only one of hostname or IP address is required.
* Host Name - the Machines hostname. Only one of hostname or IP address is required.

*Properties*

* Key Value - enter an unique key value pair.

#### Runtime Configuration

When an application is executed as part of a deployment, Chassy automatically sets the following environment variables. These variables provide context about the deployment and can be accessed by your application at runtime.

| Variable                 | Description                                                                                                                  |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| `CHASSY_MACHINE_ID`      | The unique identifier of the machine on which the application is running.                                                    |
| `CHASSY_FLEET_ID`        | The unique identifier of the fleet to which the machine belongs.                                                             |
| `CHASSY_RELEASE_ID`      | The unique identifier of the software release bundle being deployed.                                                         |
| `CHASSY_DEPLOYMENT_ID`   | The unique identifier of the deployment operation that distributed the release.                                              |
| `CHASSY_APPLICATION_DIR` | The application's home directory on the target machine. This is the root directory where your application files are located. |

These environment variables are automatically injected into your application's runtime environment and can be used for logging, monitoring, configuration management, or any application logic that needs deployment context.

#### Example Usage

```bash
#!/bin/bash
echo "Running on machine: ${CHASSY_MACHINE_ID}"
echo "Fleet: ${CHASSY_FLEET_ID}"
echo "Application directory: ${CHASSY_APPLICATION_DIR}"

# Start your application
cd "${CHASSY_APPLICATION_DIR}"
./start-app
```

## Release

The *release* step allows you to create a versioned selection of packages for use in a deployment.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXc162fCFOriXU_7b8xf7KdHkx2_D8bfJeXA0JsBR1qR6FufDHapuqmfvipNKH-GpohiuqeKO1Dtqv8-v63ElO0vlDZGt4LjDTpwEUqylkXB9aYPzY4VLPDcRFcBABsOs4yopqb-vEfi1mNSMmp14STcjcr8?key=CrjAmK76ZdHhNlRMtvcEMw" alt="The Release step type contains of a name, timeout, and configurations of artifact name, source, type, package name, and versioning options."><figcaption></figcaption></figure>

#### Details

*Type -* To release your artifact(s), create a new workflow step and select “Release” under Type.&#x20;

*Name  -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. This step is short-lived, so a timeout of 2 minutes is appropriate.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met.

When creating a release package, all the deploy packages that it depends on are automatically included in the release package. This simplifies the release process and ensures that all necessary components are included in the deployment.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Release Name* -The Artifact Name field specifies the name of the artifact to be deployed. This is the unique name within the workspace and Chassy will identify and retrieve the package.

*Target Chip* **-** This drop down lists all available chips for you to select the one that the release will target.

*Manifest -* The manifest is a file that is present in every release and contains information on what the release contains. Each file in the release should contain it’s own manifest entry. The configurable fields include the following:

* Package Name - The name of the release package.
* Package Version - Select whether to append two default tags (Latest and Current) or Manually input a custom string.
* Add another Package - Option to add another Manifest entry for another package.&#x20;

## Find Release

Find an existing release and bring it into the context of the workflow. This is ideal for release promotions across fleets or simply reusing a previously created release for a new deployment.

<figure><img src="/files/sjrHff8PRhfcnxxVsQc6" alt="The Find Release step type contains of a name, timeout, and configurations of find from, release name, version, release ID, and selection order."><figcaption></figcaption></figure>

#### Details

*Type* - To bring an existing release into a workflow's context, create a new workflow step and select "Find Release" under type.

*Name* - Logical name of step. E.g. Get Release

*Timeout* - Maximum lifetime for the step. If exceeded, the step will fail. The default timeout is one hour.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met.

When creating a release package, all the deploy packages that it depends on are automatically included in the release package. This simplifies the release process and ensures that all necessary components are included in the deployment.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Find from* - States the source from which a release is to be found. It can be found either in the Chassy Index or from an existing fleet deployment.

*Release Name* - The name of the release you intend to find.

*Version* - The version of the release you intend to find.

*Release ID - (*&#x4F;ptionally) specify a particular version of a release. With the ID specified, you won't get as much flexibility in automatic version checks.

*Fleet ID* - If using a fleet import, specify the ID of the fleet you intend to reference.

*Machine ID* - If using a fleet import, you can specify a particular machine ID to reference.

*Selection Order* - The order in which to select based on version. You can select oldest or latest.

## Wait

The step pauses the workflow for a specified duration before proceeding to the next step.

#### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

For Wait, ensure that the timeout is longer than the wait duration.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Duration -* The duration to wait, in milliseconds.

## Run CI Job

Run a CI Job in some external service such as GitHub as part of your Chassy Workflow.

<figure><img src="/files/V7KmB0qyvkSJio1FgRYk" alt="The Run CI Job step type contains of a name, timeout, and configurations of type, GitHub Workflow, Repository name and owner, Git Ref, and Job Input options."><figcaption><p>Run CI Job configuration options</p></figcaption></figure>

#### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met. This configuration option is only available for steps that do not come first in the Workflow.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Type\** - The type of CI Job you would like to run. The other configurations are all dependent on this one. At the moment, we only support the ability to run GitHub Actions workflows.

*Job Input* - Arbitrary input to provide to the job. The structure of this data will depend on the needs of the CI Job.

#### Run GitHub Actions Workflow Configurations

*GitHub Workflow\** - The name of the file containing the workflow or the ID of the workflow obtained using the GitHub API.

*Repository Name\** - The name of the repository you wish to run a workflow in.

*Repository Owner\** - The name of the owner of the repository. This can be a GitHub username or an organization name.

*Git Ref\** - Indicates the Git ref against which to run the workflow. This is useful for specifying a branch or tag. These do not need to be qualified by `heads/` or `tags/`.

{% hint style="info" %}
While you can run your workflow against any arbitrary branch, the workflow does need to *exist* in your default branch for GitHub to recognize it.
{% endhint %}

*Job Input* - JSON data to be provided to the workflow

{% hint style="danger" %}
If your inputs are unexpected (i.e. not declared in the workflow definition), you will encounter an error at execution time.
{% endhint %}

## Simulate

The *Simulation* step provides a streamlined interface for launching containerized simulations in the cloud as part of your CI/CD pipeline or software-in-the-loop (SIL) workflow. This step type integrates your custom simulation scenarios with either Chassy's pre-built simulation containers or your own, and automatically handles the complexity of cloud deployment, resource allocation, and result collection.

<figure><img src="/files/lTBJpjKasjYAw6BvUkA0" alt="The Simulate step type contains of a name, timeout, and configurations of image, repository owner and name, git revision, git reference, and git clone depth."><figcaption></figcaption></figure>

#### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Select a maximum runtime for your simulation before giving up on the task. This will prevent runaway processes from consuming resources indefinitely. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task. We suggest a few minutes for simple unit tests, to hours for comprehensive mission simulations or long-duration stability tests.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met. This configuration option is only available for steps that do not come first in the Workflow.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Simulation Image* - pre-built simulation container to use for your tests. You can upload your own simulation containers or select from any of the available Chassy example simulation containers that serve as a reference: PX4-Gazebo for drone simulations, ROS2-Gazebo for general robotics, or Isaac Sim for high-fidelity physics - depending on your project requirements. The latest tag ensures you're always using the most recent stable version, though you can specify specific versions for reproducibility.

*Git Repository Owner* - The name of the owner of the repository. This can be a GitHub username or an organization name.

*Git Repository Name* - The name of the project repository.

*Git Revision* - Indicates the Git revision against which to retrieve your custom simulation scenarios, test scripts, and configuration files.

*Git Ref* - Indicates the Git ref against which to retrieve your custom simulation scenarios, test scripts, and configuration files.

{% hint style="info" %}
This tight integration ensures that every simulation run is traceable back to a specific code commit, essential for debugging and validation workflows..
{% endhint %}

*Git Clone Depth* - Indicates how much repository history to fetch. Setting this to `1` performs a shallow clone, retrieving only the latest commit and significantly reducing setup time for large repositories. This is particularly useful for repositories with extensive history or large binary assets that aren't needed for the simulation run.

## Provision Setup

The *Provision Setup* step allows you to select an enrolled remote proxy device and use it to provision connected boards.

<figure><img src="/files/mwQFFeESOtaAa4cAbTfU" alt=""><figcaption></figcaption></figure>

#### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met. This configuration option is only available for steps that do not come first in the Workflow.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Configuration* - Choose the board type you're planning on connecting.

*Remote Proxy -* Select available remote proxy machine(s) to provision boards.

*Root File System Image* - The root filesystem to be flashed onto the connected device. This expects a URL or the ID of an image previously uploaded onto Chassy Index. The root filesystem is to include everything needed for launch at first boot, including pre-created users, credentials and network configs. You can further customize the image by injecting custom startup scripts, provisioning users, injecting SSH-keys and other customizations with a [#bake](#bake "mention") step.

*L4T distribution file* *for Nvidia devices* - Nvidia's official Linux distribution for Jetson devices, containing all the components needed to flash and boot a Jetson system. This distribution is to contain all files (including configs, kernel files, DTBs, Pinmux) required to flash your carrier board. This could be a publicly accessible URL to an L4T distribution to be downloaded, or an ID of an existing L4T package already fetched.

{% hint style="info" %}
Chassy automatically detects if a URL has already been fetched before and reuses any artifacts downloaded.
{% endhint %}

*(optional) Board Config Path for Nvidia devices* - Defines hardware-specific settings for each Jetson board variant. These include device tree files (DTBs), boot configurations, board ID's and SKU's, as well as module and carrier board combinations.

&#x20;This field expects a relative path to a file should be found within the L4T e.g. `"tools/kernel_flash/flash_l4t_t234_nvme_rootfs_ab.xml"` .

## Bake

Create a fully prepared, self-contained software bundle that’s ready to deploy to your machine using the *bake* step, or further customize existing images to add or remove capabilities.

<figure><img src="/files/E1TZG2jx69g5XiUTVeWT" alt="A screenshot of the Bake step and the details required."><figcaption></figcaption></figure>

#### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met. This configuration option is only available for steps that do not come first in the Workflow.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

#### Configuration

*Engine* - Choose an engine to bake the image. We currently support Chassy's native engine, Yocto coming soon.

*Base Image ID -* The ID of an image previously uploaded onto Chassy Index.

*Customized Image Name* - The name of the baked, deployable artifact.

*Apt Package* - Any additional system-level dependencies to include in the baked robot image, in the form of the ID of the package previously uploaded onto Chassy Index.

*Goss Test URL -* A URL containing goss tests that verify the baked image before it’s deployed.

*Chassy Enabled* - If this checkbox is selected, the image will have Chassy agent already preconfigured, so any machines can be automatically deployed to and managed by Chassy.

## Run Workflow

Use the *Run Workflow* step to link workflows together and build more complex processes.

<figure><img src="/files/OWXPPLoN791BzEYVToqa" alt="A screenshot of the Bake step and the details required."><figcaption></figcaption></figure>

### Details

*Name -* Under the name field, create a name that accurately describes your Workflow Step. This is what will be used to uniquely identify this step in your Chassy Workflow.

*Timeout -* Under the Timeout field, select an appropriate duration before giving up on the task. This will prevent the workflow from running indefinitely if there is an issue. A good rule of thumb is to set the timeout to be slightly longer than the expected runtime of the task.

*Depends On -* In Chassy, the "Depends On" field allows you to specify other tasks that must complete before the current task can execute. This is useful for ensuring that tasks are executed in the correct order and that dependencies are met. This configuration option is only available for steps that do not come first in the Workflow.

To specify a dependency, simply enter the name of the task in the "Depends On" field. You can specify multiple dependencies by separating them with commas.

### Configuration

*Target Workflow* - Choose which workflow you want to run. You cannot call the current workflow, or any other workflows that may cause an infinite loop.

*Block -* Select this checkbox if you want to wait for the called workflow to finish before proceeding with other steps.


# Hardware Hierarchy

## **Fleet**

A fleet is a group of machines that are managed and operated as a single unit often used for testing and development purposes; they allow for the simultaneous testing of multiple configurations of hardware and software. Fleets can also be used for production purposes, such as running a robot delivery service or performing Hardware in the Loop testing in the cloud.

### Examples:

1. A group of testbeds for an autonomous vehicle
2. A group of drones comprised of multiple generations of hardware in the same region

{% hint style="info" %}
Currently, the maximum number of fleets supported by Chassy is six for a single workspace.
{% endhint %}

## **Machine**

A machine is a single hardware unit with a specific hardware and software configuration. Machines can be robots, testbeds, virtual machine testbeds, or even embedded devices. Each machine within a fleet has its own unique IP address and hostname.

Each machine has a set of supported runtimes recognized by Chassy. For example, if Chassy detects that a machine is capable of running docker containers, then this will be indicated in the Chassy Console. This is useful for ensuring compatibility between artifacts and the machines intended to run them.

At the moment, the designations specify the following:

* the machine can execute binaries
* the machine can run docker containers

### Examples:

1. A mobile sidewalk delivery robot containing an ARM SoC auxiliary compute (chip) and Intel x86 based main compute (another chip)
2. A drone powered by an Nvidia Jetson Nano (chip)

## **Chip**

A chip is a semiconductor device that defines a machine's hardware and firmware configuration. Chips contain one or more processing units, such as CPUs, GPUs, memory, and other components. Each machine in a fleet can be based on one or more chips. This enables Chassy to reason about binary and image compatibility for packages uploaded to the Chassy index intended to run on specific Machines.

### Examples:

1. Nvidia Jetson Orin AGX
2. Intel 12900K with Nvidia RTX 4000
3. Raspberry Pi3&#x20;

## **Relationships between Fleets, Chips, and Machines**

* A fleet is a collection of machines.
* A machine is a single hardware unit with a specific hardware and software configuration.
* A chip defines a machine's hardware and software configuration.
* Each machine in a fleet can be based on one chip.


# Integrations

Chassy provides a handful of useful integrations with external services. This list currently includes *GitHub*, *DockerHub*, *Slack*, and *AWS*. This list is expanding to support many platforms and services.

## Build Integrations

Build integrations allow you to integrate Chassy builds with external platforms. These external platforms can range from container registry platforms to version control system remotes.

* [GitHub](/reference/integrations/github)
* [Docker Hub](/reference/integrations/docker-hub)

## Notification Integrations

Notification integrations allow you to receive communications from Chassy within specified channels. It is especially useful for receiving notifications from workflow runs.

* [Slack](/reference/integrations/slack)

## Cloud Integrations

Cloud integrations allow you to interact with cloud resources using Chassy. This can be useful for things like the persistence of logs or the import of packages within workflows.

* [AWS](/reference/integrations/aws)


# AWS

This reference will get you up and running with the Chassy AWS integration

This reference assumes you've already created a Chassy workspace. If you have yet to do this, it is recommended you [Create a Workspace](/getting-started/create-a-workspace) first.

The AWS integration is one of a number of Cloud Services Chassy natively supports. By enabling the integration, Chassy is able to import artifacts from specific S3 buckets and publish logs ingested from your machines to S3, Cloudwatch on your behalf automatically.

{% embed url="<https://www.youtube.com/watch?v=b6jht03e8pU>" %}
AWS Integration video tutorial
{% endembed %}

{% hint style="info" %}
Only an Admin or Manager is allowed to manage integrations
{% endhint %}

## How to setup AWS integration

On the Chassy console, navigate to the *Integrations* panel. Here, you will see a list of Chassy's available integrations among which will be the AWS integration.

<figure><img src="/files/LM9Xx2Jhv3rs1vSgBLEw" alt="The Integrations panel shows cards of all the available integrations."><figcaption></figcaption></figure>

On clicking *Connect*, you will be presented with a dialog asking for a client role ARN and providing you with an external ID and account ID.

<figure><img src="/files/yYR79yVWVjpNFUoHXhw6" alt=""><figcaption><p>Conect AWS Integration Dialog</p></figcaption></figure>

To continue, you will need to create a new IAM role on AWS. The required permissions are specified below in either JSON or Terraform and explained in the following table:

| Service    | Permissions | Reason                                                                                       |
| ---------- | ----------- | -------------------------------------------------------------------------------------------- |
| S3         | Read        | Allows you to import artifacts from S3 into the Chassy Index                                 |
| ECR        | Read        | Allows you to import container images from ECR into the Chassy Index                         |
| Cloudwatch | Read, Write | Allows you to push telemetry data into Cloudwatch and analyze telemetry data from Cloudwatch |

{% hint style="info" %}
The `Resource` values listed need to be replaced with values that fit your needs.
{% endhint %}

{% tabs %}
{% tab title="JSON" %}

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ReadPermissions",
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:Describe*",
        "s3:List*"
      ],
      "Resource": "arn:aws:s3:::<BUCKET_NAME>"
    },
    {
      "Sid": "ECRReadPermissions",
      "Effect": "Allow",
      "Action": [
        "ecr:BatchGet*",
        "ecr:List*",
        "ecr:Describe*",
        "ecr:Get*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudwatchLogsReadPermissions",
      "Effect": "Allow",
      "Action": [
        "logs:Get*",
        "logs:Describe*",
        "logs:List*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudwatchLogsWritePermissions",
      "Effect": "Allow",
      "Action": [
        "logs:Put*",
        "logs:Create*"
      ],
      "Resource": "*"
    }
  ]
}
```

{% endtab %}

{% tab title="Terraform" %}
You will need to create a policy.

```hcl
resource "aws_iam_policy" "policy"  
  name        = "policy_name"
  path        = "/"
  description = "My Chassy permission policy"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ReadPermissions",
      "Effect": "Allow",
      "Action": [
        "s3:Get*",
        "s3:Describe*",
        "s3:List*"
      ],
      "Resource": "arn:aws:s3:::<BUCKET_NAME>"
    },
    {
      "Sid": "ECRReadPermissions",
      "Effect": "Allow",
      "Action": [
        "ecr:BatchGet*",
        "ecr:List*",
        "ecr:Describe*",
        "ecr:Get*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudwatchLogsReadPermissions",
      "Effect": "Allow",
      "Action": [
        "logs:Get*",
        "logs:Describe*",
        "logs:List*"
      ],
      "Resource": "*"
    },
    {
      "Sid": "CloudwatchLogsWritePermissions",
      "Effect": "Allow",
      "Action": [
        "logs:Put*",
        "logs:Create*"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}
```

{% endtab %}
{% endtabs %}

After creating your role, copy the ARN of the role and paste it into the input on the Chassy console. After clicking *connect*, you should see a success message and the AWS integration should say "connected" in the *Integrations* panel.

<figure><img src="/files/m6poPdhAOupg8wVpvr1S" alt=""><figcaption></figcaption></figure>

## How to remove AWS integration

The AWS integration can be removed by navigating to the *Integrations* panel and clicking the *X* button next to the AWS integration.&#x20;

<figure><img src="/files/Vez0Gi3ul9nuXryJkZZq" alt=""><figcaption></figcaption></figure>

You will then be asked to confirm this choice in a dialog box as it is a destructive action.

<figure><img src="/files/pg6dXf7AHd9kzXeR1R9U" alt=""><figcaption></figcaption></figure>

After clicking *Disconnect*, a success message will appear confirming that you have successfully disconnected this integration.


# GitHub

The GitHub integration allows a Chassy user access to the *Workflows* panel. You can learn more about workflows by consulting the [Workflow User Guide](/user-guides/workflow-user-guide).

With our GitHub Actions, you can also automate the running of workflows within new or existing CI pipelines.

{% embed url="<https://youtu.be/8KC-SFyOkLc>" %}
Chassy GitHub Integration Tutorial
{% endembed %}

{% hint style="info" %}
Only an Admin or Manager is allowed to manage integrations
{% endhint %}

## How to enable GitHub integration

First, navigate to to the *Integrations* panel.&#x20;

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdYQMsERjjswvN0IIiNBzDHk4jwemnc-Yt0OuUwlO0m5AKOLz71a8_rnlVgEzBWLbt2OpcoOXvYJKTfLz0Awle2WmD5M0nraNQoiC6lMg-2vwmIUwKRklDa_U_eFinwA0R_0CJLTosJGTdimLzRq9LYt5wk?key=CrjAmK76ZdHhNlRMtvcEMw" alt="GitHub card on the Integrations panel." width="375"><figcaption></figcaption></figure></div>

You will be presented with Chassy's various integrations. To continue, click the *Connect* button on the GitHub integration.

After clicking *Connect*, you will be prompted to install the Chassy application on GitHub. You will be asked which organization you wish to install the Chassy bot for. You can select your personal account or any of the organizations you are a member of. Depending on your permissions, you may need an administrator of your organization to accept your request to add the Chassy application.

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeI66LIEffsuzjg19PQTHoQRzZZjcFY7vOOg_OIPNyg7UXaKs1fT09tBqq33FWZgoIHmgm1905blJH5iMdeaxlfji_35IkUolItreBJYhTgPTt2kR7kiGd-nYepSbxWl0RfuwAdkPe3tIXliZtL7Oyy3Zu3?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Select the organization you want to install the Chassy bot on." width="375"><figcaption></figcaption></figure></div>

After clicking *Configure* on your intended organization or user, you will be asked which repositories you wish to give Chassy access to. You can make a selection or select all.

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcYV8Zzo_8L_7DcWjns0m08fE21uSDgJZ4t2W9w6HMIr72-EUQ6J8iB9asRx1OcrJiTfhKZiz1yAGZlrwEl4MLbp7os1zoDOaPtImejMihTS-nRWC6rEodrFVsElSfNw31cM-zLTzm835qjZsBdBhQmN0JP?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Select repositories that Chassy can access." width="375"><figcaption></figcaption></figure></div>

After you've made your configurations, you can update Chassy's access by clicking *Update access*. After you or your organization administrator confirm these changes, Chassy will now have access to your selected repositories and you will have access to Chassy's workflow automation features.

## How to disable GitHub integration

Before you disable your GitHub integration, be mindful that you will no longer have access to workflows.

To disable the GitHub integration, first navigate to the *Integrations* panel. There, you will see the GitHub integration. Click the *X* button to disconnect this integration. You will be asked to confirm this action as it is destructive.

## Further Reading

* [Creating a Workflow](/user-guides/workflow-user-guide/creating-a-workflow)
* [Integrations](/reference/integrations)


# Docker Hub

Enabling the Docker Hub integration allows you to work with docker containers within Chassy workflows. To learn more about Workflows, consult the [Workflow User Guide](/user-guides/workflow-user-guide).

## How to enable Docker Hub integration

There are two steps required to enable the Docker Hub integration.

### Create an access token:&#x20;

Follow the instructions [here](https://docs.docker.com/security/for-developers/access-tokens/) to create an access token for Docker Hub.

Ensure that the access permissions are ‘Read, Write, Delete’.

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeC1BynBgvY2zkgzpaaXUvGaHRcewldwi025CIR4Us7Xcfyqddwvpsp2sdpwi0J7Z8HBN2jufP-qHnZpvEh93CFOkzWmsHkDpTZSzjlRqyYFRKmW_Tb1OGgnJMT3TgyZpxFV6O-dwKkvlWNbjk8-su9Bk6k?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Select &#x22;Read, Write, Delete&#x22; for the Access permissions dropdown." width="375"><figcaption></figcaption></figure></div>

### Connect to Docker Hub on Chassy Console

First, navigate to the *Integrations* panel on the Chassy console. Next, you will need to click *Connect* on the Docker Hub integration.

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcsTzT7RB4aU7c61fV-z_AAhRKJLVFlIDSNGBEUe4TFbMjDwHPZYN0LlCepmjNIbkNXz-yy8Kl6itD6iJWyV8b8VBzqhGoxuN-BvWyXDb6XZcweATpytJRhyVSkr7zFmJ7RMd9Teg3Oi3ihu-TfAx2R29cc?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Docker card on the Integrations panel." width="375"><figcaption></figcaption></figure></div>

After clicking *Connect*, a dialog box will appear asking for a username and the access token you created during the first step.

<div align="left"><figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeyEZ2Sk_XsO_Uw2bp7QdeL7ZnogC-IKWLedSv57_u8D4mLhgZeWMpj_p8ZuGYwIuOqlku3z5NBgXTpNFe442iYdj2RV7mxf6S7kMedpqs0g-FzBMFRK99KVEJIkENxSPkvVQzfdE7wwFQskp-ikpGsNZNk?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Enter the User Name and Access Token." width="375"><figcaption></figcaption></figure></div>

After filling the required fields, you can click *Connect*. Now, Docker Hub will be an enabled integration.

## How to disable Docker Hub integration

Disabling the Docker Hub integration may cause failures in workflows requiring access to particular container registries on Docker Hub. If you understand this, continue.

To disable the Docker Hub integration, first navigate to the *Integrations* pane. Clicking the *X* button on the Docker Hub integration will prompt you to confirm your action as it is destructive. Doing so will disconnect your Docker Hub integration.

You can also now revoke your access token on Docker Hub.


# Slack

The Slack integration allows you to receive Chassy notifications within specified Slack channels.&#x20;

## How to enable Slack integration

You can enable the Slack integration in three steps.

### Setup slack application&#x20;

1. Visit the Slack [app management page](https://api.slack.com/apps)

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcV5BhScDoDDq48hvnDfW-I0EtkzpW1HoTooTkXMGWnCtEagdqujGY53jKe93tYQAc2mWRk7f3tNLrez26IjQx0SiY0UW2_o3tt4XHAr0XEY53z8EoeYcvPLvvParmS2OhzK8Clt3Dk9DfhkEd3M2pcIGaF?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Slack app management page homescreen"><figcaption></figcaption></figure>

2. Create New Application&#x20;

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXesv603A2sNs6YDoN8jWQvS1Gg9ihCoys1jVYFRDrxLRHIBxMb8aU478AtjNcGb7TzI08FVvyZYVHVHxl9aTO0CFobffo7Dmk4S2IEG2UeafnRzoDB0rLFJVUalWKAUn_dmWce2nrr_vWGOW0AlkgpNHcNA?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Select &#x22;From scratch&#x22; on the dialog after clicking Create New App."><figcaption></figcaption></figure>

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeYPAC8lyE5Vr-DvJ0IHoLe4ya8551AfuR3Qcz3JJ-4XSZ-FidypepXlpVJwQBvXeCGss_JL3aIEBYtAMEuiRf_7kAsTHUT510c7ZHTq8-A18L3i5R3P1HCthByQSl8rR4FASu7kxVLaIXlPvA04YSWAaY?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Enter the App Name and pick a workspace to develop the Chassy app in."><figcaption></figcaption></figure>

3. Go to OAuth & Permissions&#x20;

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdO29Gs52Djs20ycVVLJekPivXagwGYQ6nQLMZ5YBvRrJsXeL_Knx1vFbEVlpOUhEmQ5b9_NoZprm4qvLX-b90oE-DU1qlhozMvKnsChjMhSQSQF_g1zWDgUvpRXV-Pa4WBpjxMLyvtoVrwV2aKt1IH3pKN?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Select OAuth &#x26; Permissions under Features on the side navigation."><figcaption></figcaption></figure>

4. Add chat:write permission in the Scopes section of the OAuth & Permissions page

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcaE1DBaL-H8NGh2tWywcDiX1o-Y1D_v4uw3M_TsPThNAGTTPuwgnxUOETIMGtDNqctAJ_JsTt8ydxhUI-v030cdV6OuyPZ5FIHcaEBq-1uSaIQR4jR_Hay6pCof3VMonNjJUwjzxfibMHDvKund8Xv6BFC?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Under the Bot Token Scopes section, add &#x22;chat:write&#x22;."><figcaption></figcaption></figure>

5. Install the application. In up to 10 minutes this application will be available.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXf2bM-MCTaq4lz2eFq0xi4CrEOYRbocftRRLaz--fRMo_OxtlNq-JUon3XqTubQfV0k90nS1-FNR8KKMxg4eCIYvOzj90IiY0XiOHC2cmAQLl3jeDdUS_oTlZC7RozZD7wT02z8jaFYEDtChZPNau9xNA4B?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Click on the Install button in the OAuth Tokens section."><figcaption></figcaption></figure>

6. Copy Bot User OAuth Token.&#x20;

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeEngcGnfCtiMLUkZYCnepnb5S2r0PrJX9ZHe7X0mjYL3A1xkN54l4Tvy2mOfDI0W0PPH_UghAPjrxnDM6sY6Gcd1QOad8j6OEHU7zOFoABVRreSPVihew4waUYnnc6wLcjykCkTfJ2uVbasMJA0MBo5Rw?key=CrjAmK76ZdHhNlRMtvcEMw" alt="A Bot User OAuth Token should appear after installation."><figcaption></figcaption></figure>

### Enable slack integration in the Chassy platform &#x20;

1. Go to Integrations page
2. Select the Slack integration&#x20;
3. Put the Bot User OAuth Token into the token input
4. Save the token&#x20;

### Set up a notification channel

1. Go to your Slack workspace where you added your Slack application from the [Setup Slack application](https://docs.google.com/document/d/1oQ8IHmck2kC9oeRoZ1D2sE0IQYAHPu8ELJZ3B8qM9O8/edit?pli=1#heading=h.c3jr3bn1lrzq) step
2. Create a channel&#x20;
3. Add the notification application you’ve created to the channel. One of the ways to do it is to tag the application with “@” symbol, Slack will ask you about adding the application
4. Copy the channel name
5. Go to a workflow creation page or edit page
6. Put the channel name into Slack input under the “Notifications” section

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXegGPNUtwrJLtvP9dJhLFPNy1xVPSpXolm-e8EVY0R4issCnQyn5pssw2jm_MFpzhUQOZGSmOXmdCIhwZaIGwujGg2-Xi_5g5WNY4bLv2AYVzbwofo_L0mzmnP0yi0LXOP6BCd4RHud8rLeQdVrir81t5gS?key=CrjAmK76ZdHhNlRMtvcEMw" alt="When creating a workflow, put the Slack channel name under the Notifications section."><figcaption></figcaption></figure>

#### Test&#x20;

1. Run a workflow with Slack notifications channel set
2. Wait till the workflow is finished&#x20;
3. Check the slack channel that is set in the workflow notifications configuration.&#x20;

If everything is set up correctly you should be able to see a notification in your Slack channel.

## How to disable Slack integration

Disabling the Slack integration will disallow workflow notifications to be sent to your Slack channels. If this is desired, you can do so.

First, navigate to the *Integrations* panel. Clicking the *X* on the Slack integration will prompt you to confirm your action as it is destructive. Afterwards, your Slack integration will be disabled.

If you have no desire to re-enable your Slack integration, you can also delete your Slack application.


# Wasabi

This reference will get you up and running with the Chassy Wasabi integration

This reference assumes you've already created a Chassy workspace. If you have yet to do this, it is recommended you [Create a Workspace](/getting-started/create-a-workspace) first.

The Wasabi integration is one of a number of cloud services Chassy natively supports. By enabling the integration, Chassy is able to import artifacts from specified buckets within workflows.

{% embed url="<https://youtu.be/8V3CTFvcp1U>" %}
Video tutorial showing how to enable the Wasabi integration in the Chassy Console
{% endembed %}

{% hint style="info" %}
Only an Admin or Manager is allowed to manage integrations
{% endhint %}

## How to enable the Wasabi Integration

### Create Wasabi User

First, you'll want to log into your Wasabi console and navigate to the *Users* tab.<br>

<figure><img src="/files/OwovqWZ2JL36gKLYjbfL" alt="Click on the Users tab on the side navigation on Wasabi web console."><figcaption><p>Cursor hovering over <em>Users</em> tab in the Wasabi web console</p></figcaption></figure>

Next, you will need to create a new user.

<figure><img src="/files/sqNkYAPyypCo9s6Ui8bF" alt="Create User button can be found on the top right corner on the Users panel."><figcaption><p>Cursor hovering over <em>Create User</em> button in the <em>Users</em> tab</p></figcaption></figure>

You will be prompted with a dialog containing a multi-step form, and it will ask for your configurations for this new user.&#x20;

<figure><img src="/files/9AGSZVZZmce75u5hsNdg" alt="Select &#x22;Programmatic (create API keys)&#x22; for Type of Access."><figcaption><p>The first page in the <em>create user</em> dialog form</p></figcaption></figure>

The only configuration of importance on this first page is the *Programmatic* checkbox under *Types of Access*. This checkbox must be checked. This is what will allow Chassy to interact with Wasabi.

Pressing *Next* will bring you to the next page prompting you to add this user to a group. It is a Wasabi best practice to assign users to groups.&#x20;

<figure><img src="/files/Ytm9Q2wjClEr8dSXIIPM" alt="Search for existing groups to add the user to."><figcaption><p>The second page in the <em>create user</em> dialog form</p></figcaption></figure>

After making your configurations relating to groups, pressing *Next* will bring you to the next page prompting you to configure which policies should be attached to this user.

<figure><img src="/files/QPNs9UTxGrO76vFCwFQT" alt="Policies need to be added to the user."><figcaption><p>The third page in the <em>create user</em> dialog form</p></figcaption></figure>

You will need to attach the *AmazonS3ReadOnlyAccess* policy to allow Chassy to pull files from within your S3 buckets.

<figure><img src="/files/FAtHa4DrCxPcLXDmg9wQ" alt="In the &#x22;Attach Policy To User&#x22; dropdown, select AmazonS3ReadOnlyAccess."><figcaption><p>Cursor showing policy options, the second of which happens to be the one we want, <em>AmazonS3ReadOnlyAccess</em></p></figcaption></figure>

After confirming this selection and clicking *Next*, you will be be given a summary of your configurations and asked to confirm them. Upon clicking *Create User*, you will be given a new access key and a hidden secret key. You can click *show* to show the secret key. You will need the access key and the secret key to add the integration to Chassy.

### Adding Integration in Chassy

First, navigate to the *Integrations* tab on Chassy. On this page, all of Chassy's supported integrations will be shown. Click *Connect* on the Wasabi integration.

<figure><img src="/files/yu6y5Hki4H7jhFIJVJD3" alt="Click &#x22;Connect&#x22; on the Wasabi card on the Integrations panel."><figcaption><p>Integrations tab in Chassy with cursor over Wasabi integration <em>Connect</em> button</p></figcaption></figure>

You will be prompted with a dialog asking for your access token and secret token from Wasabi.

<figure><img src="/files/9Hvup6fXRrDhz18KTFOI" alt="Enter the Access Token and Secret Token provided by Wasabi."><figcaption><p>Dialog on Chassy asking for Wasabi access token and secret token</p></figcaption></figure>

After filling these inputs with the access token and secret token provided by Wasabi, you can click *Connect* to confirm the integration.

Upon success, the *Wasabi* integration will now say *Connected*.&#x20;


# Create and Delete Users

#### Workspace Invites

An invite is a unique invitation to a prospective user to a workspace.

### Creating Invites

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdOIeG7s_oqHbKts8wTGrAAGmqaiqZm_suj4kjek9k7DDBDmIsoHVEL0wNbgcLXxDQ6ugC2PBZO9Rfny34F-6G1KQBoFp9W-7I8QMGiAdhVhyS37Ywj_U_EQ2Q2Eo_uvrn5vKmtWOykc5Ivx3QtQhWLrAaf?key=CrjAmK76ZdHhNlRMtvcEMw" alt="The Teammates tab on the Setting panel shows an overview of all members of the workspace, and a button to invite teammates."><figcaption></figcaption></figure>

From the Teammates tab in the Settings panel, the yellow button in the top right corner will prompt the user with a dialog upon being clicked.

\
In the dialog that appears, the user can specify what email addresses should receive an invite to the user’s workspace. The invite button will become active once there are some email addresses in the text box.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXegaA9vzmbVySDtJdmPB0ste3a-aO_JyeFL9YocrLWyYzyyZmayVxeT42KTIywNuTVqoqucUDAv-4JzU2QgkbtQBm6Hg42u4j4G0BtZ0y698zKMME5NZAByr60uyuZNcLzuc8ovtjVkcMmJLbJBWSTv_EFd?key=CrjAmK76ZdHhNlRMtvcEMw" alt="Enter your new teammates&#x27; email address in the dialog that appears."><figcaption></figcaption></figure>

Upon successful invitation, you will see the pending invite in the list of teammates, and the invited user will receive an email informing them of that.

## Deleting Invites

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdOIeG7s_oqHbKts8wTGrAAGmqaiqZm_suj4kjek9k7DDBDmIsoHVEL0wNbgcLXxDQ6ugC2PBZO9Rfny34F-6G1KQBoFp9W-7I8QMGiAdhVhyS37Ywj_U_EQ2Q2Eo_uvrn5vKmtWOykc5Ivx3QtQhWLrAaf?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

A pending invitation can be deleted by clicking the trash can icon in that row. Upon clicking that icon, the user is prompted with a dialog confirming their desire to delete the invitation.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeq_MqCKRqiSuGab9hzXVyDL2QAH7KbxcQXxfLz16yNcKNb7r9xliRaQ5fIqloiIGMiJU_QS88DkXmZlzBCqRdh5U4OJOZfUOphvzuyvhWsnBjTpTTsogn4LAwk0ZUijOd7Iv1KYsa149EAPG18M8vBWCg?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

After clicking delete, the pending invitation will no longer appear in the teammates table.

## Deleting User

This feature is restricted to users with admin privileges.\
If you need to remove a user from your workspace, follow these steps:

1. Navigate to *Settings* -> *Teammates*.
2. Find the user you wish to remove.
3. Click the *Delete* icon in the action section of the user’s record.

&#x20;Once confirmed, this action will immediately:

* Disable the user's access to the workspace.
* Permanently delete their account.

<figure><img src="/files/SiV9C0diFkuBlYBGPXHG" alt=""><figcaption></figcaption></figure>


# Simulation Containers Reference

## Overview

Chassy provides pre-built sample simulation containers that enable you to run robotics simulations in the cloud without managing complex dependencies. Each container includes a complete simulation environment, testing framework, and standardized interface for executing your simulations and retrieving results. You can use these as the basis for building your simulation containers, or make your own from scratch.&#x20;

## Common Features

### Standardized Command Interface

Every Chassy simulation container includes the simulate command-line tool that provides a consistent interface regardless of which simulator you're using. Chassy will automatically run all tests by executing simulate when the [Steps](/reference/workflow-components/steps#simulate) step of a workflow is run.

### Automatic GPU Detection

Well designed containers should automatically detect and utilize available GPU resources for accelerated rendering. When running on GPU-enabled instances, simulations will use hardware acceleration for improved performance and generating different report outputs into Chassy SLAM, such as images or gifs. On CPU-only instances, containers seamlessly fall back to software rendering, ensuring your simulations always run successfully. This dual-mode capability means you can develop on any hardware and deploy with confidence, knowing the container will optimize for available resources.

### Headless Simulation Support

All containers are to be configured for headless operation, running simulations without requiring a display. This enables cloud deployment without X11 forwarding, parallel simulation execution, automated testing in CI/CD pipelines, and sensor data capture in headless environments. The virtual display system can use virtual display servers like Xvfb to create a consistent rendering environment regardless of the host system configuration.

### Test Results and Reporting

Test results are automatically generated in JUnit XML format and saved to `/opt/chassy/reports`. This standardized output format integrates seamlessly with CI/CD platforms like Jenkins, GitLab CI, and GitHub Actions, as well as test aggregation tools and custom reporting dashboards.&#x20;

## Available Example Simulation Environments

### PX4-Gazebo for Autonomous Flight

The PX4-Gazebo container provides a complete headless Software-In-The-Loop (SIL) environment for autonomous flight testing, specifically designed for drone and UAV simulation with PX4 Autopilot. The container includes the latest PX4 flight stack compiled and ready to run, Gazebo Harmonic for modern physics simulation with accurate sensor models, and comprehensive MAVLink support through both mavsdk and pymavlink for drone communication protocols.

The container offers several pre-configured test suites to validate different aspects of your autonomous flight systems. The setup suite validates the PX4 and Gazebo environment, while the SIL suite tests basic SIL functionality. For more comprehensive testing, the gazebo suite runs integration tests between PX4 and Gazebo, and the flight suite tests actual flight operations including takeoff, landing, and mission execution.&#x20;

### ROS2-Gazebo for Robotics Applications

The ROS2-Gazebo container offers a full ROS2 Jazzy environment integrated with Gazebo Harmonic, making it ideal for general robotics simulation within the ROS2 ecosystem. This container provides everything needed for ROS2 development with a complete ROS2 Jazzy installation including essential packages like `robot_state_publisher`, `joint_state_publisher`, and `xacro`. The integration supports multi-robot simulation with complex robot models using URDF and Xacro formats, with pre-configured sensor message types and tf2 transforms for accurate robot state representation.

The container uses CycloneDDS for optimized container networking performance and includes the complete ROS2-Gazebo bridge suite for seamless sensor and actuator data exchange. Network isolation is maintained through configurable ROS domain IDs, allowing multiple containers to run simultaneously without interference. The environment comes pre-configured with `ROS_DISTRO` set to `jazzy`, `ROS_DOMAIN_ID` defaulting to `0` (adjustable for network isolation), and `RMW_IMPLEMENTATION` set to `rmw_cyclonedds_cpp` for optimal performance.

### Isaac Sim for Advanced Physics and AI

The Isaac Sim container leverages NVIDIA's Omniverse platform for advanced simulation capabilities, particularly suited for high-fidelity simulation with synthetic data generation needs. This container provides RTX rendering for photorealistic visualization with ray tracing, PhysX 5 for advanced physics simulation of complex interactions, and powerful synthetic data generation capabilities for computer vision and AI training. It's particularly well-suited for creating accurate digital twins of real environments.

To use the Isaac Sim container, you'll need an NGC account and API key for container access. Authentication is handled through Docker login in a bash command:

```bash
docker login nvcr.io
Username: $oauthtoken
Password: <your-ngc-api-key>
```

The container includes optional shader cache warming for consistent performance in production deployments where first-run latency is critical. This feature can be enabled when building custom versions of the container for specific use cases.

## Hardware Requirements

### GPU-Accelerated Simulation

For optimal performance with GPU-accelerated simulation, use instances equipped with NVIDIA GPUs with CUDA support. Ensure the NVIDIA Container Toolkit is installed on your host system, along with appropriate NVIDIA drivers: version 470 or higher for Gazebo containers, and version 525 or higher for Isaac Sim is recommended. GPU acceleration significantly improves rendering performance and enables real-time simulation of complex scenarios.

### CPU-Only Simulation

All containers support CPU-only execution, making them accessible for development and testing on standard hardware. Software rendering is handled via Mesa OpenGL, providing reliable rendering without GPU hardware.

## Integration with Chassy Platform

### Source Code Management

Chassy’s simulation step will automatically clone your git repository and have it available in `src` in your docker environment.

### Retrieving Results

Simulation results and test reports are automatically saved within the container at `/opt/chassy/reports`.&#x20;

When running through the Chassy workflow simulation step, the contents in `/opt/chassy/reports` will automatically be ingested and viewable in the Simulation Step's details section.

More information on results can be found on [Simulation Reports and Artifacts](/reference/simulation-reports-and-artifacts).

\ <br>


# Simulation Reports and Artifacts

## Overview

Simulation outputs go beyond simple pass/fail metrics, offering visual documentation, detailed test results, and even complete simulation replay capabilities depending on your chosen simulator. All reports are organized in a standardized directory structure at `/opt/chassy/reports`, making them easy to collect, process, and integrate into your existing workflows. Chassy’s example simulation containers generate comprehensive reports and artifacts that provide deep insights into your simulation runs.&#x20;

## Test Results and Metrics

Every simulation container generates JUnit XML reports that provide detailed test execution metrics compatible with standard CI/CD platforms. These reports capture test suite organization, individual test outcomes, execution times, and failure messages when tests don't pass. The hierarchical naming convention reflects your test organization—from unit tests that validate basic functionality through integration tests that verify complex multi-component interactions. Each XML file contains granular timing data, allowing you to identify performance bottlenecks and track test execution trends over time. Examples are provided on how to generate JUnit XML reports in each unit test in Chassy’s example code repository.

The standardized JUnit format ensures these results integrate seamlessly with test aggregation platforms and dashboard tools. The consistent naming patterns across different simulators make it straightforward to build unified reporting dashboards that aggregate results from multiple simulation types.

```sh
  /opt/chassy/reports/
  ├── junit_setup_validation.xml       
  ├── test-results-minimal.xml         
  ├── test-results-gazebo.xml          
  ├── test-results-flight.xml          
  └── test-results-integration.xml      # Combined test results
```

## Visual Documentation and Debugging

It is possible to display visual data in case of test failure, or just for logging of status. For simulations involving visual components, for example, Chassy’s Gazebo container automatically captures screenshots throughout test execution, providing visual documentation of simulation states. These captures are particularly valuable for debugging physics interactions, validating sensor placements, and verifying that visual elements render correctly in headless environments. The system generates both individual frame captures and animated GIFs that show simulation progression over time, making it easy to identify when and how issues occur during complex test scenarios.

The visual artifacts are organized by test name and component. This visual documentation proves invaluable when debugging intermittent failures or validating that simulated scenarios match expected behavior. The frame-by-frame captures allow you to precisely identify the moment when unexpected behavior occurs, while the animated GIFs provide quick visual summaries perfect for including in bug reports or design reviews.

```sh
 /opt/chassy/reports/
  ├── gazebo-test-results-integration.xml    # Test Suite 03-04 JUnit results
  ├── gazebo-test-results-manipulation.xml   # Test Suite 05 JUnit results
  ├── gazebo-test-results-simulation.xml     # Test Suite 02 JUnit results
  ├── gazebo-test-results-unit.xml          # Test Suite 01 JUnit results
  ├── screenshots/
  │   └──manipulation/                     # Test Suite 05 visual docs
  │       ├── observer_camera::link::scene_camera_0.png   # Frame 0
  │       ├── observer_camera::link::scene_camera_1.png   # Frame 1
  │       ├── ...                           # Frames 2-21 (22 total)
  │       ├── observer_camera::link::scene_camera_21.png  # Frame 21
  │       ├── unknown_test_animation.gif    # 303KB animated GIF  
```

## Advanced Replay and Analysis

It is also possible to record simulations and replay them later. This is particularly useful for investigating failures caused by non-deterministic simulations.

Chassy’s example Isaac Sim container takes simulation artifacts to the next level by generating complete USD (Universal Scene Description) files and accompanying JSON state files for each significant simulation event. These files capture the entire simulation state, including object positions, physics parameters, and sensor configurations, enabling you to replay non-deterministic simulations exactly as they occurred. This capability transforms debugging from guesswork into precise analysis, as you can load any saved state into Isaac Sim or your preferred Nvidia Omniverse Visual Debugger and inspect every aspect of the simulation at that moment. In the future, Chassy will also be able to render these scenes in your web browser.&#x20;

The OVD (Omniverse Validation Data) directory structure organizes these replay files by test scenario and timestamp, with each test generating multiple state captures at critical points during execution. The `summary.json` files provide metadata about the test run, including configuration parameters and high-level outcomes, while the numbered state files allow you to step through the simulation chronologically. This comprehensive capture approach is particularly valuable for scenarios involving complex physics interactions, multi-robot coordination, or AI behavior validation where understanding the exact sequence of events is crucial.

```sh
/opt/chassy
└── reports
    ├── junit_isaac_environment.xml
    ├── OVD
    │   ├── articulated_robot_20250907_171459_856
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   └── summary.json
    │   ├── collision_detection_20250907_171333_867
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   ├── state_005.json
    │   │   ├── state_005.usd
    │   │   ├── state_006.json
    │   │   ├── state_006.usd
    │   │   └── summary.json
    │   ├── rigid_body_physics_20250907_171315_612
    │   │   ├── state_001.json
    │   │   ├── state_001.usd
    │   │   ├── state_002.json
    │   │   ├── state_002.usd
    │   │   ├── state_003.json
    │   │   ├── state_003.usd
    │   │   ├── state_004.json
    │   │   ├── state_004.usd
    │   │   ├── state_005.json
    │   │   ├── state_005.usd
    │   │   └── summary.json
    │   └── robot_loading_20250907_171440_848
    │       ├── state_001.json
    │       ├── state_001.usd
    │       ├── state_002.json
    │       ├── state_002.usd
    │       └── summary.json
    ├── test-results-isaac-core.xml
    ├── test-results-isaac-init.xml
    ├── test-results-isaac-physics.xml
    └── test-results-isaac-robot.xml

```


# Chassy Component for ESP32

## Overview

The Chassy Component is a library for ESP32 devices that enables seamless integration with the Chassy services. It provides functionality for device registration, authentication, and over-the-air (OTA) firmware updates. This component simplifies the process of connecting ESP32 devices to the Chassy cloud, allowing for remote management and monitoring of your fleet.

### Key Features

* Automatic device registration and enrolment
* Secure authentication and communication using modern TLS protocols
* OTA firmware updates
* Status reporting to the Chassy endpoint

### Requirements

1. **ESP-IDF v5.5 or later**: This component is built and tested with ESP-IDF version 5.5. Earlier versions may not be fully compatible.
2. **OTA Partition Configuration**: Your device must have at least 2 OTA partitions of 1 MB each to support the OTA update functionality.
3. **NVS Storage**: A minimum of 4 KB of NVS (Non-Volatile Storage) must be reserved for Chassy component use. This storage is used for maintaining device credentials, deployment information, and update status.
4. **Network Connectivity**: The device must have Wi-Fi or Ethernet connectivity to communicate with Chassy services.

### Prerequisites

1. **ESP-IDF**: This component requires the Espressif IoT Development Framework (ESP-IDF). Follow the [official installation guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html) to set up ESP-IDF on your development machine.
2. **Bootstrap Token**: A bootstrap token from your Chassy account is required for initial device enrolment.

### Configuration

The component requires the following configuration in your device's Non-Volatile Storage (NVS):

* `hostname`: A unique name for your device
* `bootstrap_token`: The token obtained from your Chassy account
* `endpoint`: Set to either "development" or "production" depending on your environment

### Integration Guide

To include the Chassy component in your ESP32 project:

1. Add the Chassy component as a library to your project
2. In your initialization function, call:

   ```cpp
   chassy::ChassyDeviceManager::run_on_init(device_ip_address);
   ```
3. In your main loop, periodically call:

   ```cpp
   chassy::ChassyDeviceManager::update_chassy_endpoint(device_ip_address);
   ```
4. To check for and perform updates when available:

   ```cpp
   auto status = chassy::ChassyDeviceManager::update_chassy_endpoint(device_ip_address);
   if (status == chassy::ChassyDeviceManager::CheckUpdateStatus::kUpdateAvailable) {
       chassy::ChassyDeviceManager::perform_update(device_ip_address);
   }
   ```

### Enrollment

For a guide on how to enroll a new ESP32 device, please follow [this guide](/user-guides/fleet-user-guide/enrolling-machines/enrolling-esp32-devices).


# Get Started

#### Create a Workspace

&#x20;A workspace is the top-level location for all workflows for your organization.

<figure><img src="/files/hqFhaLGbOQq2jBYoPDXx" alt=""><figcaption></figcaption></figure>

Choose a workplace name and then select next.

#### Invite Teammates

<figure><img src="/files/g800lJoJbDtSSid5FKBG" alt=""><figcaption></figcaption></figure>

Invite teammates from your organization into your workspace. They will each create their own account. The platform provides administrators with flexible workspace permissions. You can tailor access levels for each user, ensuring they only interact with the workspaces relevant to their role and responsibilities.

#### Set up Github Integrations

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd6PngZFg-uU3MRQ-I03iXlDSG_R4TCBOAicddroaCqc9ZmJv1OqAllQlpFQ-cm5g1LlIMsCaf5lK8Uy8Uqj7cYCivxE7OYAQsehiJRBiIrPE24e9auiNx4QeRAnBEWCq8crMMadzL0hSj5F7KRQpDvGbw?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

Click on the Integrations Page button to set up GitHub integrations, and once you've added and integrated Chassy with your CI systems, return here and continue on to create your first workflow.

### Create your first Workflow

For more information on what workflows are, see the [Workflows, Steps and Tasks section](/reference/workflow-components) of the user guide.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd-gmJrJpjI_Jav8XOIPuCvbQyNmN2gbXmgMebszBOqVdBas9P8FVkLRco8oKfHlJe4nbIap8U_iQEehDEiQwQTSvpy15dbIrXgJcHgdkLQpvBjDTL9KZvhV-VSctaKtu3yXzgV73MM2nWGua0a2cXHFhUp?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

To create your first workflow, click on the Create Workflow button in the center of the dashboard.<br>

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfV0mtWUWKORNfyDVJd-dJmd0IDelH0JhFoJOjiCP1fXxDM83i877QBVkLyakPrK5jef_WdOVVCegjwIAICvI5NlPA0UMDe082DISiRAzbjHS1L7BVnMs3UPOTJshmCXkDCiihsc6khKzLNXMrcWYP6MrQY?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

Under Workflow Name, enter a name that describes the workflow you're trying to create. A helpful description can be entered in the description field.\
Fill out the notification sectioni al s if you'd like to be notified upon workflow completions. For configuring Slack notifications, refer to the [Slack configuration guide](/reference/integrations/slack).<br>

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeixgRxsX9sMUFAkRdPZXXk_WrQNj9IGjiBiYuSbP422hyLMI9ykUu76wfCA8896oEcDGvanv2rt-jyxjR9XWQdtn8tYaNyC2MPKSP1dq_lCXFXpU3sT7HFyCPVOBMG2-Z4PagPzEHK19tqCb5AvOCjR_si?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

This is the crucial stage of the workflow process where you can add or modify steps to your workflow. The top-middle section presents a graphical representation of your workflow, showcasing all the steps involved. The current step is prominently highlighted in yellow, making it easily identifiable.<br>

The "Details" tab, located on the middle-bottom of the screen, displays the configuration options and settings for the current step. This tab allows you to customize and configure the step's behavior and functionality. Once you have defined the current step to your desired specifications, you have two options to proceed:

* **Add Another Step**
  1. Click the "+" icon located on the workflow graph.
  2. A new step will be created and placed adjacent to the current step.
  3. You can then configure the newly added step in the "Details" tab.
* **Create Workflow**
  1. If you are satisfied with the workflow you have designed, click the yellow "Create Workflow" button located at the top-right corner of the screen.
  2. This action will finalize and create your workflow.
  3. The workflow will be saved and accessible for future use.

It's essential to carefully plan and configure each step of the workflow to ensure that the overall process works as intended. **Take your time reviewing and refining your workflow before finalizing it** as changes may be more challenging once the workflow is created.

If you want to go back and modify your workflow configuration, click the "Configure" button on the top-right corner. This will allow you to make changes to the steps, tasks, and settings of your workflow. Once you have made your changes, click the "Update Workflow" button to save them.

### View Workflows

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXe2jl1uLrdM5iYS2hII641ijfTXAzZJriiIh0qKRjlkRBpTsS2rjVuYkakXGECCP_mYoPEdF7nOsq5eK84WWnKvAnnO998LeJ7b_NYtXjh4AevNFgQi0X_TRp66QpwUJvNg5xMn89Yhl308AUAVXNL8aqkG?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

Once you've created your workflow, you can monitor its status or run it from the Workflows page. The status of each step is indicated by a color:&#x20;

* Grey for not started
* Green for completed
* Yellow for an issue
* Red for a critical issue

### Configure your Fleet

#### Create a Fleet

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXcQfmLXSsklOe5nxL2e72W6LwMaxrt9SeLLlinIWxo4n5XyVaEA3CV2b85G8ohlQJrcOeMtaPfvsu3mslL1v79ReuTlFbUcupa0dSy3GALUV5KrEtfew9-2fJMaP6CGB73NMEv9Wrr2gwOi0Cw5CN5xVcgC?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

The Fleets tab, located on the left column, allows you to manage your fleets. From here, you can create new fleets, configure existing ones, and view detailed information about each fleet. You can also add chips to your fleets to extend their capabilities and customize their behavior.

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXfRHwe3p5eDfsjeTtuI3ts3gug_yifDtnmlbhw1-H6p8XMJHYW6sHW0M7wPauTXxPZz2Yo-FO-SsIboIDBUHlShc06LN8TK07vJOUuDvbdTqWh3qEuJUzFfToz5YbJ9EiN8Wnls6EabAB8gcOtKlO-WUF93?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

To configure a fleet in Chassy, begin by assigning a descriptive name to the fleet and selecting the region where it will be located.

#### No chips present - add a new chip

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXd5ySwdRCviLw-POZmU5BVPHAWgtmEvl8CKzZcSKP8B1A2sscB01dgpb7n1zPn0SMIBTJwWb3GC7vTYXHN25PBt2EIk7sgi0vNK8OT0TsZTk4KV9AKUSaZ1lMDbjhclIlQDU5Igy6v61oiWDzDkeBGFxCIL?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

If no chips are configured, you will be prompted to set up a new one. To do so:

1. Assign a descriptive name to the chip and select the region where it will be located.
2. Provide a human-readable description to explain its purpose.&#x20;
   * Platform refers to the software or firmware platform that is running on the chip. (An example could be a Nvidia Jetpack release or an Ubuntu LTS version)
   * Additionally, you can specify various properties as key-value pairs to assign attributes or group your chips as needed.&#x20;
   * These properties can be used to categorize and manage your chips effectively.

#### Select a chip

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXdd3TIw7cMQu0sJ_q1HCewt2_hyAIu-K02pcex0v779H0lW6_pHZTOaVVID9QS9KP_GncPCYKLHFzB9PlJX1sqfrM4GM352OKSoGGhKrSu0ja4-1TGEFAM3pPOCpTYCOQXFRpLH9a92-abkojsWslvhyDPV?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

Select the chip to use and click continue.

### Enroll a Machine

<figure><img src="https://lh7-rt.googleusercontent.com/docsz/AD_4nXeU2ECbW26ZJWI9wCRUhtPA1jQZduN9deO-34_q05ETJ8eRpobYLh2wb58L3dg9EK6Pa3KcMbAiqUYWBIOlDdC3tnYK9KorFFDfZf_Ejgc2Q5VI7SD7CaBvrpSgqrUjqaGwvj-cxxNR5z2k05_KMsoNejs?key=CrjAmK76ZdHhNlRMtvcEMw" alt=""><figcaption></figcaption></figure>

To set up Chassy on a local machine, follow these steps:

1. Perform general housekeeping on the local machine, such as ensuring the operating system is up to date, verifying sufficient disk space and memory, disabling any firewall rules that may interfere with Chassy's communication, and ensuring a stable internet connection.
2. Generate an authentication token for Chassy to communicate with the machine by clicking on "Generate New Token" and following the instructions to generate a token. Chassy will store this token for you and send it to the machine in Step 4.
3. Select whether Chassy should manage a Docker image or an executable. More options are coming soon.
4. Copy and execute a curl command locally on the machine by opening a terminal window, copying the curl command provided by Chassy, pasting the command into the terminal window and executing it to install the Chassy agent on the machine.
5. Wait for the machine to connect to Chassy, which may take a few minutes, and monitor the terminal window for a confirmation message indicating that the machine is connected.

Congratulations! You've set up your first Chassy Workflow Pipeline. Next, you can learn more about the different [Workflow Components](/reference/workflow-components), how to [add more Users to your Chassy Workspace](/reference/create-and-delete-users), or adding [Integrations to Github Actions](/reference/integrations).


# User Guides

User guides contain information useful you may want to know as a Chassy user. These guides are best read in order as each guide presupposes knowledge from the previous guide.

For most users, it is recommended to begin with the [Broken mention](broken://pages/Ij3etpjJHo2vqUyDlnJ0) guide as it lays the foundation for following guides.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Getting Started</strong></td><td>This guide will get you up and running with a new workspace!</td><td><a href="/pages/Ij3etpjJHo2vqUyDlnJ0">/pages/Ij3etpjJHo2vqUyDlnJ0</a></td></tr><tr><td><strong>Platform User Guide</strong></td><td>This guide will take you through the process of creating platforms!</td><td><a href="/pages/cH086EAS5JTc2OGYnEw1">/pages/cH086EAS5JTc2OGYnEw1</a></td></tr><tr><td><strong>Fleet User Guide</strong></td><td>This guide will tell you all there is to know about creating and managing fleets!</td><td><a href="/pages/fXWnjwQX42iyL907U8XR">/pages/fXWnjwQX42iyL907U8XR</a></td></tr><tr><td><strong>Workflow User Guide</strong></td><td>This guide will teach you how to take advantage of Chassy's automation workflows!</td><td><a href="/pages/f4IhTnMogl9mL5qXoENF">/pages/f4IhTnMogl9mL5qXoENF</a></td></tr></tbody></table>


# Operator Guides


# Tutorials


# Quickstart

<figure><img src="https://gitbookio.github.io/onboarding-template-images/quickstart-hero.png" alt=""><figcaption></figcaption></figure>

Beautiful documentation starts with the content you create — and GitBook makes it easy to get started with any pre-existing content.

{% hint style="info" %}
Want to learn about writing content from scratch? Head to the [Basics](https://github.com/GitbookIO/onboarding-template/blob/main/getting-started/broken-reference/README.md) section to learn more.
{% endhint %}

### Import

GitBook supports importing content from many popular writing tools and formats. If your content already exists, you can upload a file or group of files to be imported.

<div data-full-width="false"><figure><img src="https://gitbookio.github.io/onboarding-template-images/quickstart-import.png" alt=""><figcaption></figcaption></figure></div>

### Sync a repository

GitBook also allows you to set up a bi-directional sync with an existing repository on GitHub or GitLab. Setting up Git Sync allows you and your team to write content in GitBook or in code, and never have to worry about your content becoming out of sync.


# Publish your docs

Once you’ve finished writing, editing, or importing your content, you can publish your work to the web as a docs site. Once published, your site will be accessible online only to your selected audience.

You can publish your site and find related settings from your docs site's homepage.

<figure><img src="https://gitbookio.github.io/onboarding-template-images/publish-hero.png" alt=""><figcaption></figcaption></figure>


# Welcome

Welcome to the GitBook Starter Template! Here you'll get an overview of all the amazing features GitBook offers to help you build beautiful, interactive documentation.

You'll see some of the best parts of GitBook in action — and find help on how you can turn this template into your own.

### Jump right in

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Getting Started</strong></td><td>Create your first site</td><td><a href="/files/UHF7zjwcq36zmrwja3ub">/files/UHF7zjwcq36zmrwja3ub</a></td><td></td><td><a href="/pages/CyH2xJQs9yWJ1S8BYNav">/pages/CyH2xJQs9yWJ1S8BYNav</a></td></tr><tr><td><strong>Basics</strong></td><td>Learn the basics of GitBook</td><td><a href="/files/vxs1ER5I8VkIA0IaOqfo">/files/vxs1ER5I8VkIA0IaOqfo</a></td><td></td><td><a href="/pages/7aUFmnCMx9m4smGncsXL">/pages/7aUFmnCMx9m4smGncsXL</a></td></tr><tr><td><strong>Publish your docs</strong></td><td>Share your docs online</td><td><a href="/files/WqTZslyWgLz3XWQj63oY">/files/WqTZslyWgLz3XWQj63oY</a></td><td></td><td><a href="/pages/JjjojIyKxaiBPzzLwvtg">/pages/JjjojIyKxaiBPzzLwvtg</a></td></tr></tbody></table>


# Editor

GitBook has a powerful block-based editor that allows you to seamlessly create, update, and enhance your content.

<figure><img src="https://gitbookio.github.io/onboarding-template-images/editor-hero.png" alt=""><figcaption></figcaption></figure>

{% embed url="<https://youtu.be/U4Wsn7O3aMk?feature=shared>" %}

### Writing content

GitBook offers a range of block types for you to add to your content inline — from simple text and tables, to code blocks and more. These elements will make your pages more useful to readers, and offer extra information and context.

Either start typing below, or press `/` to see a list of the blocks you can insert into your page.


# Markdown

GitBook supports many different types of content, and is backed by Markdown — meaning you can copy and paste any existing Markdown files directly into the editor!

<figure><img src="https://gitbookio.github.io/onboarding-template-images/markdown-hero.png" alt=""><figcaption></figcaption></figure>

Feel free to test it out and copy the Markdown below by hovering over the code block in the upper right, and pasting into a new line underneath.

```markdown
# Heading

This is some paragraph text, with a [link](https://docs.gitbook.com) to our docs. 

## Heading 2
- Point 1
- Point 2
- Point 3
```

{% hint style="info" %}
If you have multiple files, GitBook makes it easy to import full repositories too — allowing you to keep your GitBook content in sync.
{% endhint %}


# Images & media

GitBook allows you to add images and media easily to your docs. Simply drag a file into the editor, or use the file manager in the upper right corner to upload multiple images at once.

<figure><img src="https://gitbookio.github.io/onboarding-template-images/images-hero.png" alt=""><figcaption><p>Add alt text and captions to your images</p></figcaption></figure>

{% hint style="info" %}
You can also add images simply by copying and pasting them directly into the editor — and GitBook will automatically add it to your file manager.
{% endhint %}


# Interactive blocks

In addition to the default Markdown you can write, GitBook has a number of out-of-the-box interactive blocks you can use. You can find interactive blocks by pressing `/` from within the editor.

<figure><img src="https://gitbookio.github.io/onboarding-template-images/interactive-hero.png" alt=""><figcaption></figcaption></figure>

### Tabs

{% tabs %}
{% tab title="First tab" %}
Each tab is like a mini page — it can contain multiple other blocks, of any type. So you can add code blocks, images, integration blocks and more to individual tabs in the same tab block.
{% endtab %}

{% tab title="Second tab" %}
Add images, embedded content, code blocks, and more.

```javascript
const handleFetchEvent = async (request, context) => {
    return new Response({message: "Hello World"});
};
```

{% endtab %}
{% endtabs %}

### Expandable sections

<details>

<summary>Click me to expand</summary>

Expandable blocks are helpful in condensing what could otherwise be a lengthy paragraph. They are also great in step-by-step guides and FAQs.

</details>

### Drawings

<img alt="" class="gitbook-drawing">

### Embedded content

{% embed url="<https://www.youtube.com/watch?v=YILlrDYzAm4>" %}

{% hint style="info" %}
GitBook supports thousands of embedded websites out-of-the-box, simply by pasting their links. Feel free to check out which ones[ are supported natively](https://iframely.com).
{% endhint %}


# OpenAPI

You can sync GitBook pages with an OpenAPI or Swagger file or a URL to include auto-generated API methods in your documentation.

### OpenAPI block

GitBook's OpenAPI block is powered by [Scalar](https://scalar.com/), so you can test your APIs directly from your docs.

{% openapi src="<https://petstore3.swagger.io/api/v3/openapi.json>" path="/pet" method="post" %}
<https://petstore3.swagger.io/api/v3/openapi.json>
{% endopenapi %}


# Integrations

GitBook integrations allow you to connect your GitBook spaces to some of your favorite platforms and services. You can install integrations into your GitBook page from the *Integrations* menu in the top left.

<figure><img src="https://gitbookio.github.io/onboarding-template-images/integrations-hero.png" alt=""><figcaption></figcaption></figure>

### Types of integrations

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden></th></tr></thead><tbody><tr><td><strong>Analytics</strong></td><td>Track analytics from your docs</td><td><a href="https://www.gitbook.com/integrations#analytics">https://www.gitbook.com/integrations#analytics</a></td><td><a href="/files/vxs1ER5I8VkIA0IaOqfo">/files/vxs1ER5I8VkIA0IaOqfo</a></td><td></td></tr><tr><td><strong>Support</strong></td><td>Add support widgets to your docs</td><td><a href="https://www.gitbook.com/integrations#support">https://www.gitbook.com/integrations#support</a></td><td><a href="/files/WqTZslyWgLz3XWQj63oY">/files/WqTZslyWgLz3XWQj63oY</a></td><td></td></tr><tr><td><strong>Interactive</strong></td><td>Add extra functionality to your docs</td><td><a href="https://www.gitbook.com/integrations#interactive">https://www.gitbook.com/integrations#interactive</a></td><td><a href="/files/SdPaDKIKifbvNn0jWHM0">/files/SdPaDKIKifbvNn0jWHM0</a></td><td></td></tr><tr><td><strong>Visitor Authentication</strong></td><td>Protect your docs and require sign-in</td><td><a href="https://www.gitbook.com/integrations#visitor-authentication">https://www.gitbook.com/integrations#visitor-authentication</a></td><td><a href="/files/UHF7zjwcq36zmrwja3ub">/files/UHF7zjwcq36zmrwja3ub</a></td><td></td></tr></tbody></table>


