Configuration
Schema for edge-manager.yaml and edge-sync.yaml
The edge client uses two YAML config files. This page is the canonical reference for every supported field.
| File | Loaded by | Purpose |
|---|---|---|
edge-manager.yaml | alloy-edge manager | Identity + cloud connection + (optionally) local process supervision |
edge-sync.yaml | alloy-edge sync | Folder watcher + upload behaviour |
In Docker setups, edge-manager.yaml is generated for you (embedded in the downloaded docker-compose.yml) and edge-sync.yaml is delivered from the cloud — local_state is absent. In binary track-folder setups, you write both files yourself.
Durations use Go-style strings (5s, 1m, 72h). Integer shorthands like 30 are not accepted — quote them as "30s".
Looking for a starter template? The Track Folder setup → walks through a minimal working edge-manager.yaml + edge-sync.yaml pair you can copy and adapt.
edge-manager.yaml
All fields are optional at parse time — the binary will load an empty config. In practice you'll always set backend_url (via the Setup page) and seed_state.api_key.
Top-level
| Field | Type | Default | Description |
|---|---|---|---|
backend_url | string (URL) | built-in default | Alloy backend endpoint. Always set this via the Setup page. Also overridable with ALLOY_BACKEND_URL. |
state_dir | string (path) | /etc/alloy/state | Where the manager persists provisioned credentials and runtime state. Docker setups remap this to /ros2_ws/config/state. Also overridable with ALLOY_STATE_DIR. |
seed_state | object | — | Initial identity + transport. Used on first boot; server-pushed state takes over afterwards. See below. |
local_state | object | — | Local-owned supervision block. When set, its processes and tags are owned by the local config — the server cannot overwrite them. Required for binary track-folder. See below. |
seed_state
| Field | Type | Default | Description |
|---|---|---|---|
api_key | string | — | Provisioning key for first-boot registration. Required to register, but can alternatively be pre-written to {state_dir}/api_key or supplied via ALLOY_API_KEY. |
edge_id | string | /etc/machine-id, then random UUID | Human-readable device identifier reported to Alloy. Also overridable with ALLOY_EDGE_ID. |
tags | map[string, string] | {} | Free-form labels applied on registration. Used for fleet filtering once tag-based features ship. |
transport.http.poll_secs | float (seconds) | 15.0 | How often the manager checks in with the backend for desired-state updates. Sub-second supported. Non-positive values clamp to the default. |
processes[] | list | [] | Fallback processes until the first successful server sync. Same shape as local_state.processes[]. Prefer local_state.processes when you want processes the server cannot override. |
local_state
| Field | Type | Default | Description |
|---|---|---|---|
tags | map[string, string] | {} | Tags the server cannot overwrite. Merged on top of seed_state.tags. |
processes[] | list | [] | Processes supervised locally. Shape below. |
Each entry in processes[]:
| Field | Type | Default | Required | Description |
|---|---|---|---|---|
name | string | — | yes | Identifier for logs and reported_state. |
command | string | — | yes | Shell command to exec. Runs as the user invoking alloy-edge manager. |
enabled | bool | true | no | Kill switch. Set false to define a process but not start it. |
restart | enum | on_failure | no | always / on_failure / never. |
shell | bool | false | no | Wrap command in /bin/sh -c for pipes, redirects, $(...) interpolation. |
trigger | enum | — | no | When to start: boot, cron(<expr>), or connectivity. Without a trigger, processes start when apply() runs. |
duration | duration | — | no | Stop the process after this duration elapses (timed window). |
files | map[string, string] | — | no | Attached config files — filename → inline UTF-8 content. |
edge-sync.yaml
Only input_dir is strictly required. Disk-management fields default to no limit — eviction is FIFO by modification time, oldest first. Files currently uploading or open by another process are never deleted.
| Field | Type | Default | Description |
|---|---|---|---|
input_dir | string (path) | — | Required. Folder watched for new files. |
file_pattern | string (glob) | *.mcap | Which filenames to upload. |
cycle_time | duration | 1s | How often the watcher scans input_dir. |
upload_delay | duration | 30s | Wait this long after a file's last modification before uploading. Prevents grabbing files still being written. |
state_dir | string (path) | /etc/alloy/state | Where the sync process persists upload bookkeeping. Also accepted under the legacy name status_dir. |
credentials_dir | string (path) | /etc/alloy/state | Where the sync process reads device credentials written by the manager. |
max_concurrent_uploads | int | 1 | Cap on parallel uploads in flight. |
keep_files | bool | false | If false, files are deleted after successful upload. Set true when another agent (e.g. Foxglove Agent) needs to read the same files. |
mcap_require_footer | bool | true | Skip MCAP files that don't yet have a written footer — i.e. files still being recorded. |
signed_url_endpoint | string | /signed-url | Backend path for signed-URL requests. The compiled-in default targets a legacy endpoint — set /lake-signed-url explicitly for Alloy's current R2 / data-lake backend. |
metadata | map[string, string] | {} | Key-value metadata sent as x-goog-meta-* headers on GCS resumable uploads. Ignored for S3/R2 presigned PUT uploads. |
txlog_path | string (path) | {state_dir}/txlog.ndjson | Path to the NDJSON transaction log that records every upload attempt. |
max_folder_size | size | — | Cap on total folder size. Format: 10GB, 500MB. |
max_file_age | duration | — | Delete files older than this. Format: 72h. |
max_file_count | int | — | Cap on the number of files retained on disk. |
bwlimit | rate | — | Outbound bandwidth cap. Format: 10M, 1G, 500K (also accepts 10MB/s-style values). |
upload_type | enum | signed_url | signed_url (default, via Alloy backend) or opendal (upload directly to your own cloud — see below). |
redaction — strip or hash fields before upload
Optional. Points edge-sync at a redaction rules file and configures the I/O knobs (failure policy, quarantine, audit). The rules themselves — channel filter, per-topic transforms, metadata mappings — live in the file referenced by rules_file:. See Redact for the why-and-when.
redaction:
enabled: true
rules_file: /etc/alloy/redaction.yaml
on_rule_error: fail
quarantine:
dir: /var/lib/alloy/edge-sync/quarantine
ttl: 24h
audit:
enabled: true
embed_in_mcap: true| Field | Type | Default | Description |
|---|---|---|---|
enabled | bool | false | Master switch at the edge-sync level. Even with redaction.yaml itself enabled, the redactor is bypassed unless this is true. |
rules_file | string (path) | — | Required when enabled: true. Path to the redaction.yaml rules file. |
on_rule_error | enum | fail | What to do when a rule blows up at runtime. fail — file moves to the quarantine dir and is not uploaded (safe default). pass_original — fail-open: the unredacted file is uploaded. Use only with explicit operator opt-in. |
dry_run | bool | inherits from redaction.yaml | Override for the rules-file dry_run flag. Filtered output goes to <input_dir>/.dry-run/<timestamp>/ (alongside the watched recordings) and uploads are skipped. CLI --dry-run wins over both. |
quarantine.dir | string (path) | {state_dir}/quarantine | Where original files land when redaction fails with on_rule_error: fail. Successful redactions write to a scratch dir under state_dir and are deleted after upload. |
quarantine.ttl | duration string | never | How long to keep files in quarantine before the cleanup task evicts them (24h, 7d, never). |
audit.enabled | bool | true | Whether to write a JSONL sidecar ({state_dir}/redaction-audit.jsonl by default) — one line per redacted file. |
audit.path | string (path) | {state_dir}/redaction-audit.jsonl | Override for the JSONL path. |
audit.embed_in_mcap | bool | true | Also embed the audit summary as an MCAP metadata record named alloy.redaction.audit inside the redacted file, so the file documents itself. Set false only when the rule layout is itself sensitive. |
Upload directly to your own cloud (OpenDAL)
Set upload_type: opendal and add an opendal: block. Requires an alloy-edge build with the opendal feature.
| Field | Used by | Description |
|---|---|---|
scheme | all | s3, gcs, azblob, or fs |
root | all | Prefix path (e.g. /fleet/robot-01/recordings) |
bucket | s3, gcs | Bucket name |
region | s3 | AWS region |
endpoint | s3 | Custom endpoint (MinIO, R2) |
container | azblob | Azure container name |
account_name | azblob | Azure storage account |
credential_path | gcs | Service-account JSON path |
Options are passed through to OpenDAL. See the OpenDAL service docs for the complete per-scheme options each scheme supports.