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

# Define file rules

File rules are an optional part of a release. They define which files on your devices Miru manages — where they are uploaded, how long they are kept, or both. This page covers defining file rules and including them when creating a release.

While a release must contain at least one config schema, it may contain any number of file rules, including none. For the full release-creation workflow — config schemas, Git metadata, and the CLI command — see the [Create a release](/cfg-mgmt/create-a-release) guide.

## Prerequisites

A rule that uploads writes files to a bucket, so a connected bucket is required for it. Connect one before creating a release with rules that upload:

* [Connect an AWS bucket](/data-uploads/connect-a-bucket/aws)
* [Connect a GCS bucket](/data-uploads/connect-a-bucket/gcs)

A retention-only rule — one with no `upload` block — does not upload anything, so it needs no bucket.

The generic prerequisites are covered in the [Create a release](/cfg-mgmt/create-a-release) guide.

## Define the file rules

File rules are defined as YAML files in your Git repository. Below is an example rule
that uploads all log files from the `/var/log/robot` directory to the
`my-uploads-bucket` bucket, and then deletes each local copy a week after its upload is
confirmed.

```yaml robot-logs.yaml theme={null}
name: Robot Logs

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

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

retention:
  ttl_secs: 604800
  require_upload: true
```

Both `upload` and `retention` are optional and independent. A rule with only `retention` uploads nothing and simply reclaims disk on the device:

```yaml scratch-cleanup.yaml theme={null}
name: Scratch Cleanup

source:
  glob: /var/tmp/robot/*.bin

retention:
  ttl_secs: 3600
```

Like schemas, file rules are identified by hashing their content, so rules with equivalent content are deduplicated even if their comments or formatting differ.

### Source

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>

### Upload

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>

## Add file rules to a release

File rules ride along with `miru release create` — the same command that creates the release and its schemas. Include them with either flag (both may be repeated):

* `--file-rule <file>` — a single file rule YAML file
* `--file-rules <dir>` — a directory of file rule YAML files

```bash theme={null}
$ miru release create \
  --version v1.0.0 \
  --schemas ./schemas/ \
  --file-rule ./file-rules/robot-logs.yaml
```

See the [CLI reference](/references/cli/release-create) for the full flag list.
