> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirurobotics.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Devices

export const ViewerBadge = ({size = "md"}) => {
  return <Tooltip tip="Members with the viewer role can execute this action." cta="Workspace roles" href="/admin/users/access-control">
            <Badge icon="eye" color="gray" size={size}>viewer</Badge>
        </Tooltip>;
};

export const ProvisionerBadge = ({size = "md"}) => {
  return <Tooltip tip="Members with the provisioner role can execute this action." cta="Workspace roles" href="/admin/users/access-control">
            <Badge icon="bot" color="purple" size={size}>provisioner</Badge>
        </Tooltip>;
};

export const AdminBadge = ({size = "md"}) => {
  return <Tooltip tip="Workspace owners and administrators can execute this action." cta="Workspace roles" href="/admin/users/access-control">
            <Badge icon="shield-check" color="blue" size={size}>admin</Badge>
        </Tooltip>;
};

export const PlatformApiLink = ({endpoint, newTab, children}) => {
  const href = `/references/platform-api/2026-05-06/endpoints/${endpoint}`;
  if (newTab) {
    return <a href={href} target="_blank" rel="noopener noreferrer">{children}</a>;
  }
  return <a href={href}>{children}</a>;
};

export const Framed = ({image, background, link, alt = "Framed content", borderWidth = "24px", outerRadius = "10px", innerRadius = "6px"}) => {
  const parseShorthand = value => {
    const values = String(value).trim().split(/\s+/);
    switch (values.length) {
      case 1:
        return [values[0], values[0], values[0], values[0]];
      case 2:
        return [values[0], values[1], values[0], values[1]];
      case 3:
        return [values[0], values[1], values[2], values[1]];
      default:
        return values.slice(0, 4);
    }
  };
  const isZero = v => parseFloat(v) === 0;
  const padding = parseShorthand(borderWidth);
  const outer = parseShorthand(outerRadius);
  const cornerMasks = [];
  if (isZero(padding[0]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 0%, transparent ${outer[0]}, black ${outer[0]})`);
  }
  if (isZero(padding[0]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 0%, transparent ${outer[1]}, black ${outer[1]})`);
  }
  if (isZero(padding[2]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 100%, transparent ${outer[2]}, black ${outer[2]})`);
  }
  if (isZero(padding[2]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 100%, transparent ${outer[3]}, black ${outer[3]})`);
  }
  const backgroundMask = cornerMasks.length > 0 ? cornerMasks.join(", ") : undefined;
  const innerImage = <img src={image} alt={alt} noZoom={link ? true : false} style={{
    display: "block",
    width: "100%",
    margin: 0,
    borderRadius: 0
  }} />;
  return <div style={{
    display: "inline-block",
    position: "relative",
    borderRadius: outerRadius,
    overflow: "hidden"
  }}>
            {}
            {background && <div style={{
    position: "absolute",
    inset: 0,
    backgroundImage: `url(${background})`,
    backgroundSize: "cover",
    maskImage: backgroundMask,
    WebkitMaskImage: backgroundMask,
    maskComposite: "intersect",
    WebkitMaskComposite: "source-in"
  }} />}
            {}
            <div style={{
    position: "relative",
    padding: borderWidth
  }}>
                <div style={{
    borderRadius: innerRadius,
    overflow: "hidden",
    lineHeight: 0
  }}>
                    {link ? <a href={link}>{innerImage}</a> : innerImage}
                </div>
            </div>
        </div>;
};

export const NullableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property does not need to be set">
            <Badge icon="circle" color="gray" size={size}>nullable</Badge>
        </Tooltip>;
};

export const EditableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property can be directly modified">
            <Badge icon="pencil" color="blue" size={size}>editable</Badge>
        </Tooltip>;
};

export const MutableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property is automatically updated by the system; cannot be modified directly">
            <Badge icon="feather" color="orange" size={size}>mutable</Badge>
        </Tooltip>;
};

export const OFFLINE_TOOLTIP = {
  tip: "Device has lost connection with Miru's servers",
  cta: "Learn more",
  href: "/learn/devices/overview#status"
};

export const ONLINE_TOOLTIP = {
  tip: "Device is connected to Miru's servers",
  cta: "Learn more",
  href: "/learn/devices/overview#status"
};

<Framed background="https://assets.mirurobotics.com/docs/v04/images/devices/background.jpeg" image="https://assets.mirurobotics.com/docs/v04/images/devices/header:list.png" borderWidth={"24px 0 0 36px"} innerRadius={"8px 0 0 0"} />

A **device** is a machine to which config instances are deployed. This could be an NVIDIA Jetson, Raspberry Pi, industrial PC, or any other computer running your robot's application.

Configurations are deployed to devices via the Miru Agent, a lightweight `systemd` service that runs on your devices, handling the deployment lifecycle of configurations. Visit the [Miru Agent](/developers/agent/overview) documentation for more information.

## Properties

<ParamField path="name" type="string">
  <EditableBadge />

  A human-readable display name that can contain most characters, such as spaces, special characters, and punctuation. Must contain between 1 and 48 characters.

  Examples: `Robot 11`, `ArcticBlaze`, `Warehouse Rover`
</ParamField>

<ParamField path="status" type="enum">
  <MutableBadge />

  The [status](#status) of the device.

  Allowed values:

  * `inactive`
  * `activating`
  * `online`
  * `offline`
</ParamField>

<ParamField path="last_connected_at" type="datetime">
  <MutableBadge />

  {' '}

  <NullableBadge />

  The timestamp of when the device last connected to Miru's servers.

  Examples: `2026-05-25T12:00:00Z`
</ParamField>

<ParamField path="last_disconnected_at" type="datetime">
  <MutableBadge />

  {' '}

  <NullableBadge />

  The timestamp of when the device last disconnected from Miru's servers.

  Examples: `2026-05-25T12:00:00Z`
</ParamField>

<ParamField path="agent version" type="string">
  <MutableBadge />

  {' '}

  <NullableBadge />

  The version of the Miru Agent running on the device.

  The agent version exists only if the device has a status of `online` or `offline`. If the device is `inactive` or `activating`, the agent version is `null`.

  Examples: `v0.6.0`
</ParamField>

<ParamField path="current release" type="Release">
  <MutableBadge />

  {' '}

  <NullableBadge />

  The [release](/primitives/releases#properties) to which the device's current deployment belongs.

  If the device is `inactive` or `activating`, the current release id is `null`. If the device is `online` or `offline`, the current release may still be `null` if the device has no deployed config instances.

  Examples: `rls_123`
</ParamField>

<ParamField path="group" type="Group">
  <EditableBadge />

  {' '}

  <NullableBadge />

  The [group](/primitives/groups#properties) to which the device belongs. If the device's group is not set, the group id is `null`.

  Examples: `grp_123`
</ParamField>

## Status

Devices leverage several states to track their registration and connectivity with the Miru control plane.

| Status       | Description                                                 |
| ------------ | ----------------------------------------------------------- |
| `inactive`   | The Miru Agent has not yet been installed and authenticated |
| `activating` | The Miru Agent is registering itself with Miru's servers    |
| `online`     | Device is currently connected to Miru's servers             |
| `offline`    | Device has lost connection to Miru's servers                |

<img src="https://assets.mirurobotics.com/docs/v04/images/devices/status-lifecycle.light.svg" alt="Device status lifecycle" className="block dark:hidden" />

<img src="https://assets.mirurobotics.com/docs/v04/images/devices/status-lifecycle.dark.svg" alt="Device status lifecycle" className="hidden dark:block" />

Devices begin in the `inactive` state. During the Miru Agent install process, devices briefly enter the `activating` state before transitioning to `online`.

Once the Miru Agent has been provisioned on a device, the device remains `online` or `offline` for the remainder of its existence—devices don't transition back to `inactive` or `activating`.

The only exception to this is when a device is [reprovisioned](/cfg-mgmt/provision-devices/reprovision). During reprovisioning, devices briefly enter the `activating` state before transitioning back to `online`.

To view a device's status, hover over its name on the Devices page.

<Frame>
  ![Device Status Hover](https://assets.mirurobotics.com/docs/v04/images/devices/status-hover.png)
</Frame>

## View a device

To view a device in Miru, navigate to the [Devices page](https://app.mirurobotics.com/devices), click into the device you want to view, and switch to the **Overview** tab at the top.

**Metadata**

At the top of the page, you'll find the device's metadata, including its name, status, agent version, and more.

<Frame>
  ![Device Overview Metadata](https://assets.mirurobotics.com/docs/v04/images/devices/overview-metadata.png)
</Frame>

**Audit trail**

At the bottom of the page, you'll find a complete audit trail of deployments made to the device.

<Frame>
  ![Device Overview Audit Trail](https://assets.mirurobotics.com/docs/v04/images/devices/overview-audit-trail.png)
</Frame>

## Provision a device  <ProvisionerBadge />

To provision a device, visit the [device provisioning](/cfg-mgmt/provision-devices/overview) .

## Edit a device  <ProvisionerBadge />

**Dashboard**

Navigate to the [Devices page](https://app.mirurobotics.com/devices), click the ellipses (...) on the device you want to edit, and hit **Edit**.

<Frame>
  ![Device Ellipses Dropdown](https://assets.mirurobotics.com/docs/v04/images/devices/ellipses-dropdown.png)
</Frame>

Update the desired fields, then click **Save**.

<Frame>
  ![Edit Device Dialog](https://assets.mirurobotics.com/docs/v04/images/devices/edit-dialog.png)
</Frame>

**Platform API**

To edit a device programmatically, use the <PlatformApiLink endpoint="devices/update">update device endpoint »</PlatformApiLink>

## Ping a device  <ViewerBadge />

Pinging a device sends a real-time request to verify whether it is online. Ping requests wait up to 5 seconds for a response from the device before timing out.

<Tooltip tip={ONLINE_TOOLTIP.tip} cta={ONLINE_TOOLTIP.cta} href={ONLINE_TOOLTIP.href}>Online</Tooltip> devices should return a success message similar to the one below.

<Frame>
  ![Ping Success](https://assets.mirurobotics.com/docs/v04/images/devices/ping-success.png)
</Frame>

On the other hand, <Tooltip tip={OFFLINE_TOOLTIP.tip} cta={OFFLINE_TOOLTIP.cta} href={OFFLINE_TOOLTIP.href}>offline</Tooltip> devices should return a timeout message similar to the one below.

<Frame>
  ![Ping Timeout](https://assets.mirurobotics.com/docs/v04/images/devices/ping-timeout.png)
</Frame>

## Move a device  <AdminBadge />

To move a device to a different group, click the ellipses (...) on the device you want to move and select **Move**.

<Frame>
  ![Device Ellipses Dropdown](https://assets.mirurobotics.com/docs/v04/images/groups/device-ellipses-dropdown.png)
</Frame>

A dialog will appear—select the group you want to move the device to and hit **Move**.

<Frame>
  ![Move Device Dialog](https://assets.mirurobotics.com/docs/v04/images/groups/move-device-dialog.png)
</Frame>

## Delete a device  <ProvisionerBadge />

Deleting a device immediately invalidates its authentication session and removes all deployment and configuration history. This action is irreversible. Please proceed with caution.

**Dashboard**

To delete a device, click the ellipses (...) on the device you want to delete and hit **Delete**.

<Frame>
  ![Device Ellipses Dropdown](https://assets.mirurobotics.com/docs/v04/images/devices/ellipses-dropdown.png)
</Frame>

A confirmation dialog will appear—click **Delete** to confirm.

<Frame>
  ![Delete Device Dialog](https://assets.mirurobotics.com/docs/v04/images/devices/delete-dialog.png)
</Frame>
