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

# Rule definition

File rules are 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`).

## 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 matching files and their containing
    directories. Files in directories the agent can't read are silently skipped. See
    [file system access](/developers/agent/filesys-access#data-uploads) for details.
  </Warning>

  Example: `/var/log/robot/*.log`

  See [glob patterns](/data-uploads/primitives/file-rules/rule-definition#glob-patterns) for
  supported syntax, examples, and matching behavior.
</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>

File rules use `source.glob` to select the files that Miru manages on a device. The
Miru Agent evaluates the pattern on every scan, so files that appear after a rule is
deployed can still match it.

### Glob patterns

File rule glob patterns select the files that Miru manages on a device.

Every pattern must:

* Be absolute, starting with `/`
* Be at most 1024 bytes and contain no control characters
* Contain no `..` segments or empty segments (`//` or a trailing `/`)

Each rule accepts one pattern. To match files that no single pattern covers, define a
rule for each pattern.

**Supported syntax**

| Syntax             | Matches                                                                                                                                                    |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `*`                | any characters within one path segment; never crosses a `/`                                                                                                |
| `**`               | zero or more directories at any depth; must be a whole path segment on its own (`/var/log/**/*.log` is valid but `**.log`, `run**`, and `***` are invalid) |
| `?`                | one character                                                                                                                                              |
| `[abc]`, `[a-z]`   | one character from the set or range                                                                                                                        |
| `[!abc]`, `[!a-z]` | one character not in the set or range                                                                                                                      |

Brace expansion (`{a,b}`), backslash escapes (`\*`), and extended patterns such as
`!(x)` are not supported. Braces and backslashes match literally. To match a literal
`*`, `?`, or `[`, wrap it in brackets: `[*]`, `[?]`, or `[[]`.

**Examples**

| Pattern                        | Matches                                                        |
| ------------------------------ | -------------------------------------------------------------- |
| `/var/log/robot/*.log`         | `.log` files directly inside `/var/log/robot`                  |
| `/var/log/robot/*/*.log`       | `.log` files exactly one directory below `/var/log/robot`      |
| `/var/log/robot/**/*.log`      | `.log` files in `/var/log/robot` and all of its subdirectories |
| `/var/log/robot/**/*`          | Every file in `/var/log/robot` and all of its subdirectories   |
| `/var/log/robot/run-[0-9].log` | `run-0.log` through `run-9.log` in `/var/log/robot`            |

**Matching behavior**

* a trailing `**` matches only directories, so `/var/log/robot/**` matches no files — use `/var/log/robot/**/*` instead
* only regular files match; a directory never matches even if its name does
* symbolic links to files and directories are followed
* matching is case-sensitive (`*.log` does not match `APP.LOG`)
* `*` and `**` match hidden files and directories whose names start with `.`
* keep the part of the pattern before the first wildcard as specific as possible; a broad pattern such as `/**/*.log` walks large parts of the file system on every scan

<Warning>
  You must grant the Miru Agent read access to matching files and their containing
  directories. Files in directories the agent can't read are silently skipped. See
  [file system access](/developers/agent/filesys-access#data-uploads) for details.
</Warning>

## 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/rule-definition#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/rule-definition#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>
