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

# Upload rules

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

export const ImmutableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property cannot be modified">
            <Badge icon="lock" color="gray" size={size}>immutable</Badge>
        </Tooltip>;
};

An **upload rule** is a standing instruction to upload data from a device: whenever files matching a source pattern appear on a device, upload them to a [bucket](/data-uploads/primitives/buckets). Every rule belongs to an [upload collection](/data-uploads/primitives/upload-collections) and is shipped to devices as part of a [release](/primitives/releases).

A rule has two parts — a `source` (what to collect on the device) and a `destination`
(where it goes in your bucket) — and belongs to an upload collection that gives its data
stream a stable identity. Rules are created by defining them as rule files and
[releasing them via the CLI](/data-uploads/define-upload-rules).

## Properties

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

  A hash of the rule's resolved definition — its collection, source, and destination.
  Upload rules are deduplicated by digest within their collection: pushing a rule
  identical to an existing one returns the existing rule instead of a duplicate.

  Example: `sha256:1234567890`
</ParamField>

<ParamField path="source" type="Source">
  <ImmutableBadge />

  What files to upload from the device. See [Sources](#sources).
</ParamField>

<ParamField path="destination" type="Destination">
  <ImmutableBadge />

  Where uploaded files are uploaded to. See [Destinations](#destinations).
</ParamField>

<ParamField path="upload collection" type="Upload Collection">
  <ImmutableBadge />

  The [upload collection](/data-uploads/primitives/upload-collections#properties) to which the
  rule belongs.

  Examples: `Robot Logs`, `Crash Reports`, `Camera Footage`
</ParamField>

## File format

Each rule is defined as a single YAML file in your Git repository:

```yaml theme={null}
collection_slug: robot-logs  # collection this rule belongs to             

source:
  glob: "/var/log/robot/*.log"          
  stability_window_secs: 60             

destination:
  bucket: my-uploads-bucket             
  path: "logs/{device_id}/{upload_id}/{file_name}"  
  delete_policy: never  # never | after_upload
```

Rule files reference the rule's collection by its `collection_slug` and the bucket by
name (`destination.bucket`).

See [sources](#sources) and [destinations](#destinations) for details on each field.

## Sources

A rule's `source` declares what to collect on the device: which files to match, and
when a matching file is considered finished and eligible for upload.

<ParamField path="glob" type="string" required>
  An absolute glob pattern that selects the files to upload.

  Must satisfy the following criteria:

  * Absolute — it starts with `/`
  * At most 1024 bytes, with no control characters
  * No `..` segments, and no empty segments (`//` or a trailing `/`)

  <Warning>
    You must grant the Miru Agent read access to the files you want to upload. Visit the [file system access](/developers/agent/filesys-access#data-uploads) section for more details.
  </Warning>

  Example: `/var/log/robot/*.log`
</ParamField>

<ParamField path="stability_window_secs" type="integer" default="60">
  How long, in seconds, a matching file's size and modification time must stay
  unchanged (quiescent) before it is considered stable and eligible for upload.
  See [completion detection](/data-uploads/primitives/uploads).
</ParamField>

## Destinations

A rule's `destination` declares where which registered [bucket](/data-uploads/primitives/buckets) to write to, and the object path within it.

<ParamField path="bucket" type="string">
  Name of the registered bucket this rule uploads to.

  Example: `my-uploads-bucket`
</ParamField>

<ParamField path="path" type="string" default="{device_id}/{year}-{month}-{day}/{upload_id}/{file_name}">
  The template which defines the object path to which the uploaded file is written.

  The following variables are supported, which are filled in when each upload's
  object key is rendered:

  | Variable        | Example     | Description                               |
  | --------------- | ----------- | ----------------------------------------- |
  | `{upload_id}`   | `upl_123`   | The upload's ID.                          |
  | `{device_id}`   | `dvc_123`   | The uploading device's ID.                |
  | `{device_name}` | `my-robot`  | The device's name.                        |
  | `{file_name}`   | `robot.log` | The source file's basename.               |
  | `{year}`        | `2026`      | The upload's creation year (e.g. `2026`). |
  | `{month}`       | `01`        | The upload's creation month.              |
  | `{day}`         | `01`        | The upload's creation day.                |
  | `{hour}`        | `00`        | The upload's creation hour.               |
  | `{minute}`      | `00`        | The upload's creation minute.             |

  <Warning>
    Templates must contain the `{upload_id}` variable.
  </Warning>
</ParamField>

<ParamField path="delete_policy" type="enum" default="never">
  When the device deletes the local source file after collecting it.

  * `never` *(default)* — keep the local file in place; you manage local retention
    yourself.
  * `after_upload` — delete the local file once the upload is durably confirmed.
</ParamField>

## Immutability

Upload rules are **immutable**. A rule is created once, shipped to devices as part of
a [release](/primitives/releases), and never edited in place. To change
what is collected, you must create a new rule, release it, and deploy it to your devices.

## Git provenance

Rules are defined as YAML files in your Git repository and created by
[releasing them via the CLI](/data-uploads/define-upload-rules). Each rule records the
Git commits it was released from — the commit itself and the rule file's path relative
to the repository root — so any rule in Miru can be traced back to the exact lines of
YAML that defined it.

## Create an upload rule  <PublisherBadge />

Upload rules must be created as part of a [release](/primitives/releases). Visit the [define releases](/data-uploads/define-upload-rules) page to learn how to create upload rules and releases.

## View an upload rule

To view an upload rule in Miru, navigate to the [Releases page](https://app.mirurobotics.com/releases), and click into the release that contains the upload rule you want to view.

<Frame>
  ![Releases Page](https://assets.mirurobotics.com/docs/v04/images/releases/page.png)
</Frame>

At the bottom of the page under the **Overview** tab, you will find a list of the release's upload rules.

<Frame>
  ![Release Upload Rules List](https://assets.mirurobotics.com/docs/v04/images/releases/upload-rule-list.png)
</Frame>

To see more details about an upload rule, simply click on the dropdown arrow next to the upload rule.

<Frame>
  ![Release Upload Rule Details](https://assets.mirurobotics.com/docs/v04/images/releases/upload-rule-details.png)
</Frame>
