> ## 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.

# Overview

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 ImmutableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property cannot be modified">
            <Badge icon="lock" color="gray" size={size}>immutable</Badge>
        </Tooltip>;
};

<Framed background="https://assets.mirurobotics.com/docs/v04/images/config-schemas/background.png" image="https://assets.mirurobotics.com/docs/v04/images/config-schemas/header:panel.png" borderWidth={"32px 56px 0 0"} innerRadius={"0 8px 0 0"} />

A **config schema** defines the structure, types, and constraints of a config instance. It serves as a contract between code and configuration, ensuring that config instances are valid before being deployed to devices.

## Properties

<ParamField path="language" type="string">
  <ImmutableBadge />

  The [schema language](/cfg-mgmt/primitives/schemas/languages/overview) used to define the schema.

  Allowed values:

  * `jsonschema`
  * `cue`
</ParamField>

<ParamField path="format" type="enum">
  <ImmutableBadge />

  The file format used to define the schema.

  Config schemas support the following file formats:

  | Language    | Schema Formats | Instance Formats |
  | ----------- | -------------- | ---------------- |
  | JSON Schema | JSON, YAML     | JSON, YAML       |
  | CUE         | CUE            | JSON, YAML       |

  Note that a *schema's* format does not need to match the format of the *config instance* it validates. For example, a YAML-formatted JSON Schema can validate a JSON-formatted config instance.

  Allowed values:

  * `cue`
  * `json`
  * `yaml`
</ParamField>

<ParamField path="content" type="string">
  <ImmutableBadge />

  The raw schema definition, written in the specified schema language.

  The exact contents of a schema file is preserved in Miru, including any comments, whitespace, and formatting.
</ParamField>

<ParamField path="digest" type="string">
  <ImmutableBadge />

  A hash of the canonicalized schema content.

  Digests are computed by converting schemas to a canonical format—a format that ignores whitespace, comments, and other non-semantic differences—and then hashing the result. This is useful for comparing schemas and detecting duplicates.

  Examples: `sha256:45YeoJJ2btBnAKQztAEXEjHsqyyQfC1z1Mw3LLM4xMUy`
</ParamField>

<ParamField path="instance file path" type="string">
  <ImmutableBadge />

  The instance file path is the absolute file system path where config instances (for this schema) are written on the device.

  Instance file paths control the type of file that config instances are deployed as. Currently, JSON (`.json`) and YAML (`.yaml`, `.yml`) are supported.

  The default instance file path is `/srv/miru/configs/{config-type-slug}.json`.

  Examples: `/srv/miru/configs/v1/mobility.json`, `/srv/miru/configs/safety.yaml`

  <Note>
    YAML support requires Miru Agent **v0.7.0** or newer
  </Note>
</ParamField>

<ParamField path="config type" type="Config Type">
  <ImmutableBadge />

  The [config type](/cfg-mgmt/primitives/config-types#properties) to which the schema belongs.

  Examples: `Mobility`, `Safety Features`, `Perception`
</ParamField>

## Schema languages

Config schemas are defined using a schema language—a formal language for describing the structure, constraints, and data types of a configuration.

Miru supports:

* [JSON Schema](https://json-schema.org/draft/2020-12) (draft 2020-12)
* [CUE](https://cuelang.org/)

For more information on schema languages, visit the [languages](/cfg-mgmt/primitives/schemas/languages/overview) section of this guide.

## File formats

Config schemas support the following file formats:

| Language    | Schema Formats | Instance Formats |
| ----------- | -------------- | ---------------- |
| JSON Schema | JSON, YAML     | JSON, YAML       |
| CUE         | CUE            | JSON, YAML       |

Note that a *schema's* format does not need to match the format of the *config instance* it validates. For example, a YAML-formatted JSON Schema can validate a JSON-formatted config instance.

## Schema annotations

Annotations are a convenient way to store metadata with your schemas. Most annotations are optional, but some are required for Miru to process the schemas correctly.

<ParamField path="config type" required>
  The config type is a required annotation that identifies the config type to which a schema belongs. Below is the syntax for annotating a schema with a [config type slug](/cfg-mgmt/primitives/config-types#param-slug).

  <CodeGroup>
    ```yaml JSON Schema theme={null}
    x-miru-config-type: "{config-type-slug}"
    ```

    ```cue CUE theme={null}
    @miru(config_type="{config-type-slug}")
    ```
  </CodeGroup>

  If the provided config type slug does not yet exist, it is automatically created. To edit a config type after creation, visit the [config types documentation](/cfg-mgmt/primitives/config-types#edit-a-config-type).

  Examples: `mobility`, `communication`, `perception`
</ParamField>

<ParamField path="instance file path">
  The instance file path is the absolute file system path where config instances for this schema are written on the device.

  <Warning>
    The Miru Agent ships with out-of-the-box access to `/srv/miru`. To deploy configs to a custom directory, please visit the [File system access](/developers/agent/filesys-access#configs) page.
  </Warning>

  Instance file paths control the type of file that config instances are deployed as. Currently, JSON (`.json`) and YAML (`.yaml`, `.yml`) are supported.

  This annotation is optional and defaults to `/srv/miru/configs/{config-type-slug}.json`.

  <CodeGroup>
    ```yaml JSON Schema theme={null}
    x-miru-instance-filepath: "/srv/miru/configs/{config-type-slug}.json"
    ```

    ```cue CUE theme={null}
    @miru(instance_filepath="/srv/miru/configs/{config-type-slug}.json")
    ```
  </CodeGroup>

  Examples:

  * `/srv/miru/configs/mobility.json`
  * `/home/myapp/configs/communication.yaml`
  * `/var/lib/myapp/configs/safety.yaml`
</ParamField>

## Immutability

Config schemas are **immutable**. A schema is created once as part of a
release and never edited in place. To change what a config type accepts, you must create a new schema, release it, and deploy it to your devices.

## Git provenance

Schemas are defined as files in your Git repository and created by
[releasing them via the CLI](/cfg-mgmt/create-a-release). Each schema records the
Git commits it was released from — the commit itself and the schema file's paths
relative to the repository root — so any schema in Miru can be traced back to the exact
lines that defined it.

## Validating instances

The primary purpose of schemas is to validate config instances. Let's look at a simple example to see this in action.

The following is a toy schema written in JSON Schema.

```yaml JSON Schema expandable theme={null}
$schema: "https://json-schema.org/draft/2020-12/schema"
title: Mobility
type: object
properties:
    max_linear_speed_mps:
        type: number
        minimum: 0.1
        maximum: 5.0
        default: 1.2
    max_angular_speed_radps:
        type: number
        minimum: 0.1
        maximum: 3.0
        default: 1.0
    obstacle_avoidance_enabled:
        type: boolean
        default: true
    navigation_mode:
        type: string
        enum: [conservative, balanced, aggressive]
        default: balanced
    telemetry:
        type: object
        properties:
        upload_interval_sec:
            type: integer
            minimum: 10
            maximum: 300
            default: 60
        heartbeat_interval_sec:
            type: integer
            minimum: 1
            maximum: 60
            default: 10
        required:
        - upload_interval_sec
        - heartbeat_interval_sec
required:
- max_linear_speed_mps
- max_angular_speed_radps
- obstacle_avoidance_enabled
- navigation_mode
- telemetry
```

The schema defines what constitutes a valid config instance in several different ways:

* Names the available properties
* Organizes the configuration structure, placing some properties at the root while nesting other properties into logical groups
* Gives each property a type, such as `number`, `boolean`, etc.
* Constrains the values of each property—minimums, maximums, enumerations, etc.
* Supplies default values to properties where appropriate

Most of these constraints are optional, and many features of JSON Schema are omitted here, but this gives you a flavor of what schemas are capable of.

Say we are deploying the following config instance.

<Frame>
  ![Invalid Mobility Edit](https://assets.mirurobotics.com/docs/v04/images/devices/editor/invalid-mobility-edit.png)
</Frame>

Unbeknownst to us, the `max_angular_speed_radps` field exceeds the maximum allowed value of 3.0.

Luckily, before deployment to the device, the config instance is validated against the schema, throwing the following error:

<Frame>
  ![Invalid Mobility Error Message](https://assets.mirurobotics.com/docs/v04/images/devices/editor/invalid-mobility-err-msg.png)
</Frame>

Identifying the issue, we correct the `max_angular_speed_radps` field to use the maximum allowed value of 3.0 and deploy the config instance to the device.

<Frame>
  ![Valid Mobility Edit](https://assets.mirurobotics.com/docs/v04/images/devices/editor/valid-mobility-edit.png)
</Frame>

This time, the config instance successfully validates against the schema and is deployed to the device.

Although simple in concept, schemas are a powerful tool for preventing typos, misconfigurations, and other preventable errors.

## Empty schemas

While schemas provide significant value in production deployments, defining one from scratch can be a considerable undertaking.

Many teams find it best to begin with an empty schema—one that accepts any configuration—and gradually add constraints. This approach allows you to define the most highly valued constraints first and progressively transition to stricter and stricter schemas as needed.

Below are the empty schemas for JSON Schema and CUE, respectively.

<CodeGroup>
  ```yaml JSON Schema theme={null}
  $schema: "https://json-schema.org/draft/2020-12/schema"
  ```

  ```cue CUE theme={null}
  {}
  ```
</CodeGroup>
