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

# File 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 PlatformUnsupportedBadge = () => {
  return <Tooltip tip="Platform API does not support this operation">
      <span className="inline-flex items-center gap-1.5 rounded-lg px-2 py-0.5 text-sm text-[rgb(var(--gray-500))] dark:text-[rgb(var(--gray-400))]" style={{
    marginLeft: '-0.5rem',
    cursor: 'default'
  }}>
        <Icon icon="ban" size={13} color="currentColor" /> Platform API
      </span>
    </Tooltip>;
};

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

A **file rule** is a standing instruction about files on a device: whenever files matching a source pattern appear, upload them to a [bucket](/data-uploads/primitives/buckets), and govern how long the device retains them. Rules are shipped to devices as part of a [release](/primitives/releases).

## Properties

<ParamField path="name" type="string" required>
  <ImmutableBadge />

  A human-readable name for the rule.

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

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

  A hash of the rule's resolved definition. File rules are deduplicated by digest within
  a workspace: 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" required>
  <ImmutableBadge />

  Which files on the device the rule manages. See [Sources](#sources).
</ParamField>

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

  An optional field that defines where matching files are uploaded to. Absent when the
  rule only manages local retention. See [Uploads](#uploads).
</ParamField>

<ParamField path="retention" type="Retention">
  <ImmutableBadge />

  An optional field that defines how long the device retains local copies of matching
  files. Absent when the device keeps them indefinitely — Miru never deletes them. See
  [Retention](#retention).
</ParamField>

## File format

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

```yaml theme={null}
name: Robot Logs                       

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

# optional block
upload:                                
  collection_slug: robot-logs
  bucket: my-uploads-bucket
  path: "logs/{device_id}/{upload_id}/{file_name}"  

# optional block
retention:                             
  ttl_secs: 604800                     
  require_upload: true                 
```

Rule files reference the rule's upload collection by its slug
(`upload.collection_slug`) and the bucket by name (`upload.bucket`), while the API object
returns their ids (`upload.upload_collection_id`, `upload.bucket_id`).

See [sources](#sources), [uploads](#uploads), and [retention](#retention) for details on
each field, and [define file rules](/data-uploads/define-file-rules) for how to release
them.

## Sources

A rule's `source` declares what the rule matches on the device: which files it manages,
and when a matching file is considered finished.

<ParamField path="glob" type="string" required>
  An absolute glob pattern that selects the files this rule manages.

  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. Going quiescent is what makes a file
  eligible for upload and deletion.
</ParamField>

## Uploads

A rule's `upload` block declares which registered [bucket](/data-uploads/primitives/buckets) matching files are written to, and the object path within it.

The `upload` block is optional. If omitted, the rule only manages local retention.

<ParamField path="collection_slug" type="string" required>
  Slug of the [upload collection](/data-uploads/primitives/upload-collections) the resulting uploads are grouped into.

  Example: `robot-logs`
</ParamField>

<ParamField path="bucket" type="string" required>
  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>

## Retention

A rule's `retention` block governs deletion of the local copies of matching files. When
absent, the device retains matching files indefinitely (Miru never deletes them).

The retention block doesn't go into effect until a file is considered stable. That is, its size and modification time have stayed unchanged for [`source.stability_window_secs`](/data-uploads/primitives/file-rules#sources).

<ParamField path="require_upload" type="boolean">
  Whether a file must have its upload durably confirmed before it may be deleted. Must be set when the rule has an [`upload`](/data-uploads/primitives/file-rules#uploads) block.

  * `true` — files are *never* deleted before their upload is confirmed.
  * `false` — upload is best-effort; files may be deleted once they are eligible, even if their upload has not completed.
</ParamField>

<ParamField path="ttl_secs" type="integer" required>
  How long, in seconds, the file lives on the device before it is scheduled for deletion. The clock starts as soon as the file is considered stable.

  Use `0` to delete the file as soon as it becomes eligible.

  Example: `604800`
</ParamField>

<Note>
  Local deletion is performed by the Miru Agent. Deleting a file requires write access to
  its parent directory — see [file system access](/developers/agent/filesys-access#data-uploads).
</Note>

## Immutability

File 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 managed, 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-file-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 a file rule  <PublisherBadge />

<PlatformUnsupportedBadge />

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

## View a file rule

<PlatformUnsupportedBadge />

To view a file rule in Miru, navigate to the [Releases page](https://app.mirurobotics.com/releases), and click into the release that contains the file 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 file rules.

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

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

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