Alloy

Configuration — v0.9.0

Advanced configuration and schema inspection for Alloy Edge v0.9.0

This is an advanced reference. Start with Track Folder v0.9.0; link creates the required files and run selects them from the installation scope.

Files and locations

FilePurpose
edge-manager.yamlCloud connection, identity seed, process supervision, and restart policy
edge-sync.yamlTracked folder, upload behavior, disk cleanup, lifecycle, and processing pipeline
Transform YAMLOptional per-recording transformation or redaction rules
ScopeConfigurationState
User$XDG_CONFIG_HOME/alloy-edge or ~/.config/alloy-edge$XDG_STATE_HOME/alloy-edge or ~/.local/state/alloy-edge
Folder-local<track-folder>/.alloy<track-folder>/.alloy/state
System/etc/alloy-edge/var/lib/alloy-edge

Use --user, --system, or --local to select an installation explicitly. Without a scope, Alloy Edge discovers the nearest valid folder-local installation, then the user installation, then the system installation. A malformed installation is an error; it does not silently fall back.

edge-manager.yaml

Top-level fields

FieldDefaultPurpose
backend_urlAlloy production backendAlloy backend endpoint. ALLOY_BACKEND_URL overrides it.
state_dirScope-specific state directoryManager state, credentials, desired state, and child configuration. ALLOY_STATE_DIR overrides it.
seed_state{}Bootstrap identity and transport used until the device is approved.
local_stateLocally owned tags and processes that cloud configuration cannot overwrite.
supervisorBuilt-in defaultsAdvanced restart, backoff, stability, and shutdown tuning.

Credentials and device identity live under the installation state directory. Deleting state is not a harmless cache clear. Use alloy-edge unlink with the installation's scope when intentionally removing a linked installation.

seed_state

alloy-edge link writes and manages credentials for new installations. The seed fields remain available for legacy or manually authored installations:

FieldDefaultPurpose
api_keyEnrollment-only provisioning key used until approval. Prefer alloy-edge link; runtime commands use the persisted device key.
edge_idHostname, then generated UUIDStable device identifier reported to Alloy.
tags{}Free-form strings for grouping and filtering devices.
transport.http.poll_secs15Seconds between desired-state checks.
processes[]Bootstrap processes used before the first successful cloud sync. Prefer local_state.processes for locally owned processes.

local_state.processes

FieldDefaultPurpose
nameRequired process name used in logs and reported state.
commandRequired command to execute.
enabledtrueKeep the process declared but stopped when false.
restarton_failureRestart policy: always, on_failure, or never.
shellfalseRun through /bin/sh -c when shell expansion is required.
triggerStart on applyStart at boot, on a five-field cron schedule, or when connectivity returns.
durationStop the process after a bounded duration.
requires_authfalseHold the process until Alloy approves the device. Set this for alloy-edge sync.
files{}Inline configuration files attached to the process.

Set local_state.report: true to report a safe, read-only projection of locally pinned state to Alloy. The default is false.

A locally owned Track Folder sync process has this shape:

local_state:
  report: true
  processes:
    - name: sync
      command: alloy-edge sync -c /data/recordings/.alloy/edge-sync.yaml
      enabled: true
      restart: on_failure
      trigger: boot
      requires_auth: true

supervisor

FieldDefaultPurpose
max_restarts10Restarts allowed before a child is marked crashed.
max_backoff_secs60Maximum exponential restart backoff.
stable_secs60Runtime required before the restart count resets. Must be greater than zero.
graceful_timeout_secs10Grace after SIGTERM before SIGKILL.

edge-sync.yaml

v0.9 uses strict schema version 1. Only input_dir is required. Cleanup has no size or age limit by default, with a default maximum of 100,000 files.

version: 1
input_dir: /data/recordings
file_pattern: "*.mcap,*.json,*.jsonl"
upload_delay: 30s

cleanup:
  max_folder_size: 10GB
  max_file_age: 72h
  max_file_count: 1000

lifecycle:
  original:
    after: keep

Durations use Go-style strings such as 5s, 1m, and 72h. Sizes and bandwidth limits use values such as 500MB, 10GB, and 5MB.

Scanning and upload

FieldDefaultPurpose
versionSet to 1 for the current strict schema. An absent value enters legacy compatibility mode.
input_dirRequired folder to scan.
file_pattern*.mcap,*.json,*.jsonlComma-separated file globs. .tmp entries are reserved and removed.
cycle_time1sSafety-net scan interval.
upload_delay30sMinimum age before a footer-less recording is eligible.
upload_orderoldest_firstDispatch ready files using oldest_first or newest_first.
mcap_require_footerfalseRequire an MCAP footer instead of falling back to file age.
upload_typesigned_urlsigned_url, none, or feature-gated opendal.
bwlimitUnlimitedOutbound bandwidth limit.
max_concurrent_uploads1Number of files uploaded in parallel.
part_concurrency4Multipart upload parts sent in parallel for one file.
metadata{}Free-form metadata included in upload requests when supported.
scan_exclude[]Subdirectory basenames to skip; dot-directories are always skipped.
fs_event_enabledtrueUse filesystem events for low-latency scans while retaining periodic scans.

The upload_settings block exposes advanced protocol controls:

FieldDefaultPurpose
multiparttrueUse the unified /upload/* protocol. Set false for the legacy single-PUT broker.
multipart_endpoint/upload/initOverride the unified-protocol initialization endpoint.
multipart_include_metadatafalseInclude metadata in the multipart initialization request.
signed_url_endpointTop-level/default endpointOverride the legacy single-PUT broker endpoint.
part_concurrencyTop-level/default valueOverride concurrent part uploads within one multipart upload.

Cleanup and upload state

FieldDefaultPurpose
cleanup.max_folder_sizeUnboundedDelete oldest eligible files when the tracked folder exceeds this size.
cleanup.max_file_ageDelete eligible files older than this duration.
cleanup.max_file_count100000Delete oldest eligible files when the count exceeds this limit.
state_dirScope-specific state directoryHolds sync state and shared device credentials.
index_store.backendsqlitePer-file upload state: sqlite or jsonl. Switching backends migrates automatically.
index_store.pathDerived from state_dirOptional JSONL path and SQLite migration source.

Files currently uploading or open by another process are not removed by cleanup. Deprecated top-level cleanup fields, txlog_path, credentials_dir, keep_files, and the flat redaction block remain readable for compatibility but should not be used in new v0.9 configuration.

Lifecycle

Lifecycle controls what happens to the original and to each transformed artifact:

lifecycle:
  original:
    after: keep
    upload: false
    cleanup:
      include_in_storage_cleanup: false
  transform:
    after: move
    move_to: .alloy-redacted
    cleanup:
      include_in_storage_cleanup: false
    on_rule_error: skip_record
    on_reader_error: skip_tail
    output_compression: inherit
    audit:
      jsonl_path: .alloy/state/redaction-audit.jsonl
      embed_in_mcap: true
      max_bytes: 5MB
      max_files: 2
FieldDefaultPurpose
original.afterkeepkeep/keep_continue, keep_stop, delete, or move the source.
original.uploadfalseUpload the untransformed original if it reaches the end of the pipeline.
transform.afterkeepkeep, delete, or move the transformed artifact.
<stage>.move_toStage-specific dot-directoryDestination when after: move; relative paths resolve from input_dir.
<stage>.cleanup.include_in_storage_cleanupfalseInclude moved files in the global size, age, and count limits.
transform.on_rule_errorskip_recordskip_record, skip_file, or explicitly opt into pass_original.
transform.on_reader_errorskip_tailskip_tail, abort, or recover malformed MCAP data.
transform.output_compressioninheritinherit, none, zstd, or lz4.
transform.audit.jsonl_pathWrite an optional rotating JSONL audit sidecar.
transform.audit.embed_in_mcaptrueEmbed the audit record in the transformed MCAP.
transform.audit.max_bytes5MBRoll the sidecar before it exceeds this size; 0 disables rotation.
transform.audit.max_files2Rotated generations to retain; must be at least one.

Processing pipeline

The optional ordered pipeline can filter, transform, upload, and retain different artifacts from one recording:

pipeline_trigger: delay-after-close
pipeline:
  - transform: .alloy/redaction.yaml
    transform_suffix: redacted
    upload: true
    transform_after: delete
    original_after: delete
    file_pattern: "**/camera/*.mcap"
    filter:
      require_topics: ["/nav/**"]
      min_duration: 60s
      min_messages: 100
      min_size: 10MB
      if: "done == true"
      if_at: any
FieldDefaultPurpose
pipeline_triggerdelay-after-closeStart after the close delay, or use close to start as soon as the file closes.
transformRules file used to create a transformed artifact.
transform_suffixStep indexInfix added to the transformed filename.
uploadfalseUpload the transformed artifact. Requires transform.
original_afterlifecycle.original.afterControl source flow after this step.
transform_afterlifecycle.transform.afterKeep, delete, or move the transformed artifact.
file_patternAll filesRestrict the step to matching paths.
filter.mcap_require_footerWait and retry when an MCAP footer is absent.
filter.require_topics[]Require matching topics; glob patterns are supported.
filter.min_durationRequire a minimum recording duration.
filter.min_messagesRequire a minimum message count.
filter.min_sizeRequire a minimum file size.
filter.ifEvaluate a Jinja2 expression against JSON or MCAP record content.
filter.if_atanySelect records for if: any, first, last, an index, or a range.
filter.require_fieldsEquality-map shorthand for simple if conditions.

All configured filter conditions must match for a step to run. A content miss continues to the next step rather than failing the file.

Inspect, validate, and edit configuration

The v0.9 CLI is the canonical source for the complete schema installed on a device:

# Authored manager and every referenced sync/transform file
alloy-edge config show

# Deterministic JSON plus the complete Draft 2020-12 schemas
alloy-edge config show --json --schema

# Validate the selected installation and every referenced file
alloy-edge config check

Select manager or an exact configured process name to narrow config show. Add --no-comments for plain YAML, or use --json --comments for source-ordered comments alongside the semantic JSON projection.

Prefer the configuration CLI for small edits. It preserves unrelated comments and styles, validates a staged candidate, and atomically replaces the source:

alloy-edge config set track-folder /data/recordings
alloy-edge config set sync.input_dir /data/recordings
alloy-edge config set manager.state_dir /var/lib/alloy-edge

Process names form the first segment of an address, such as sync.input_dir. Use alloy-edge config show to see the configured process names before editing.

After changing configuration, restart alloy-edge run or its service. Validate a change without backend calls or child processes with:

alloy-edge run --user --dry-run

For transformation rules, continue to the Redaction reference.

On this page