Alloy
Mesh StorageIngest

Track Folder

Point the Alloy edge binary at a folder of recordings and upload them automatically

This feature is in beta. The setup flow described below may not work exactly as written yet — we're actively refining it. If you hit issues, reach out to the Alloy team.

If you already have MCAP files landing in a directory — from a ROS2 recorder, Foxglove, or any other tool — the Alloy edge binary can watch that folder and upload new recordings to Mesh Storage automatically.

This is the simplest way to get data into Alloy when you don't need the full Docker setup, or when you're running alongside another agent like Foxglove Agent.

Prefer the setup modal? Open Mesh Storage → Device Setup → and select Binary to run the interactive flow with pre-filled config.

☁️ Alloy ClouduploadAlloy Edge📋 edge-sync.yamlinput_dir: /recordingsfile_pattern: *.mcapmax_folder_size: 10GBwatchesdisk cleanup📁 /recordings*.mcap.mcap🤖 Recorder(ROS2 / custom)

The client needs outbound access on port 443 (HTTPS) only. No inbound ports required.

Step 1: Download and install

In the Device Setup modal, select Binary — your OS and architecture are auto-detected. Click Download to get the binary.

.deb is recommended — it includes systemd service integration.

sudo dpkg -i alloy-edge_*.deb
chmod +x alloy-edge-linux-*
sudo mv alloy-edge-linux-* /usr/local/bin/alloy-edge
chmod +x alloy-edge-darwin-*
sudo mv alloy-edge-darwin-* /usr/local/bin/alloy-edge

Move alloy-edge-windows-amd64.exe to a folder in your PATH, or run it directly from the download location.

Step 2: Scaffold the configs

Point init at the folder you want to watch and provide your provisioning key:

alloy-edge init track-folder --track-dir /recordings --api-key <provisioning-key>

A --dry-run preview mode for this flow is planned, but not available yet.

This creates:

  • /recordings/.alloy/edge-manager.yaml — entry point; supervises edge-sync and waits for approval before uploading
  • /recordings/.alloy/edge-sync.yaml — child config; watches /recordings for *.mcap, *.json, and *.jsonl
  • /recordings/.alloy/state/ — runtime state (including credentials after approval)

If you want to scaffold first and add the key later:

  • If you have not edited the generated files yet, rerun init with --force:
alloy-edge init track-folder --track-dir /recordings --api-key <provisioning-key> --force
  • If you already edited edge-manager.yaml or edge-sync.yaml, update the key in place instead of rerunning init:
seed_state:
  api_key: <provisioning-key>
chmod 600 /recordings/.alloy/state/api_key
printf %s "<provisioning-key>" > /recordings/.alloy/state/api_key

Then tune your device identity and sync settings as needed.

Set a predictable device identity in edge-manager.yaml:

seed_state:
  edge_id: "robot-01"                 # defaults to hostname if omitted
  tags:
    environment: production
    location: warehouse-3

edge_id defaults to the device's hostname if not set. Set it explicitly to give your device a predictable, human-readable name.

edge-manager.yaml should include a local edge-sync process:

local_state:
  processes:
    - name: edge-sync
      command: "alloy-edge sync -c /recordings/.alloy/edge-sync.yaml"
      restart: on_failure
      requires_auth: true

The local_state block tells the manager to run edge-sync locally using your config file. Without it, the manager would fetch its process config from Alloy Cloud — which is the right approach for the Docker setup, but not for the binary track-folder flow where you control which folder to watch.

requires_auth: true keeps alloy-edge sync stopped until the backend approves the device — the process needs the device API key to authenticate uploads, and trying to run pre-approval would just generate auth errors. Other processes (diagnostics, local recorders, anything that doesn't talk to the data plane with the device key) can leave requires_auth off and start immediately.

Step 3 (optional): Tune the watch config

Edit edge-sync.yaml to tune watch and retention behavior:

input_dir: "/recordings"                 # the folder to watch
file_pattern: "*.mcap,*.json,*.jsonl"    # comma-separated globs; default if omitted
upload_delay: "60s"                      # wait after last write before uploading

# Disk management — oldest files deleted first (FIFO by mtime)
max_folder_size: 10GB                    # delete oldest files when total exceeds this
max_file_age: 72h                        # delete files older than this
# max_file_count: 1000                   # optional — cap on number of files

# Lifecycle — what to do with each file after a successful upload.
# Default is `keep` (fail-safe); pair with the cleanup limits above to bound disk.
lifecycle:
  original:
    after: keep                          # keep | delete | move

Files currently being uploaded are never deleted. Files open by other processes (e.g. an active recorder or another upload agent) are also skipped.

Sidecar metadata. Drop a metadata.json, metadata.yml, or metadata.yaml next to your .mcap in the same folder and its key/value pairs are attached to every row of every topic table as queryable _meta_* columns.

For the full schema — including lifecycle.transform (v0.7: lifecycle.redacted), mcap_require_footer, cycle_time, max_concurrent_uploads, and uploading directly to your own cloud via OpenDAL — see the configuration reference.

Step 4: Run

alloy-edge manager -c /recordings/.alloy/edge-manager.yaml
alloy-edge whoami -c /recordings/.alloy/edge-manager.yaml

The client contacts Alloy using the provisioning key and registers the device. It then waits for approval. Your device will appear in Mesh Storage under the devices/ folder as Pending.

For production, run it as a background service so it starts on boot:

The .deb package includes a systemd unit file:

sudo systemctl enable --now alloy-edge

Create a launch agent at ~/Library/LaunchAgents/ai.usealloy.edge.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>ai.usealloy.edge</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/local/bin/alloy-edge</string>
    <string>manager</string>
    <string>-c</string>
    <string>/recordings/.alloy/edge-manager.yaml</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/ai.usealloy.edge.plist

Use NSSM or Task Scheduler to run alloy-edge.exe manager -c C:\recordings\.alloy\edge-manager.yaml at startup:

# Task Scheduler (runs at logon)
schtasks /create /tn "AlloyEdge" /tr "C:\path\to\alloy-edge.exe manager -c C:\recordings\.alloy\edge-manager.yaml" /sc onlogon /rl highest

Step 5: Approve the device

  1. Open the devices/ folder in Mesh Storage
  2. Find the new device and click Approve
  3. Alloy issues the device a permanent API key
  4. The client picks up the new key on its next sync — no manual key distribution needed

What happens next

After approval, the edge client starts uploading files from your watched directory. Within a few minutes you should see:

  • Last seen updating as the client syncs
  • Files appearing in the device's folder in Mesh Storage

You can then replay, inspect, or query any uploaded MCAP file directly from Mesh Storage.

Running alongside Foxglove Agent

The Alloy edge binary coexists with Foxglove Agent on the same machine — no conflicts. Both can watch the same recording directory simultaneously.

☁️ Alloy Cloud☁️ Foxglove ClouduploaduploadAlloy Edge📋 edge-sync.yamlinput_dir: /recordingsfile_pattern: *.mcapmax_folder_size: 10GBFoxglove Agent📋 foxglove-agent.yamlrecordingsDir: /recordingsretainRecordingsSeconds: 0watcheswatchesdisk cleanup📁 /recordings*.mcap.mcap🤖 Recorder(ROS2 / custom)

Recommended setup:

  1. Your recorder writes MCAP files to a shared directory (e.g. /recordings)
  2. Foxglove Agent watches the directory and uploads recordings to Foxglove
  3. Alloy Edge watches the same directory and uploads recordings to Alloy
  4. Alloy Edge handles disk cleanup — set max_folder_size high enough that both agents have time to upload before old files are evicted

Neither agent deletes files on upload — they both read and upload independently. Alloy Edge's disk cleanup is safe:

  • Files are deleted oldest-first (FIFO by modification time)
  • Files currently being uploaded by Alloy Edge are skipped
  • Files open by other processes (including Foxglove Agent) are never deleted

Disable Foxglove Agent's retainRecordingsSeconds (set to 0, which is the default) so that Alloy Edge is the single owner of disk cleanup. This avoids race conditions where one agent deletes a file before the other has finished uploading.

On this page