What syncs across devices

When sync is enabled, Autohand keeps the following data consistent between every machine tied to your account:

CategoryWhat gets syncedLocation
ConfigurationGlobal settings, model preferences, permission rules, theme choices~/.autohand/settings.json
API keysProvider keys (OpenAI, Anthropic, etc.) encrypted separately before upload~/.autohand/credentials.enc
Custom agentsYour AGENTS.md files and agent configurations~/.autohand/agents/
Community skillsInstalled community skill definitions and their configurations~/.autohand/skills/community/
Custom skillsSkills you wrote yourself, including prompt templates and tool definitions~/.autohand/skills/custom/
User hooksGlobal hook definitions that run across all projects~/.autohand/hooks/
Memory filesYour global CLAUDE.md and project memory summaries~/.autohand/memory/
Project knowledgeLearned patterns, codebase indexes, and project-specific context~/.autohand/knowledge/
Session historyRecent session metadata (not full transcripts) so you can resume on another machine~/.autohand/sessions/
Shared contentBookmarked prompts, saved snippets, and templates you marked for sync~/.autohand/shared/

Project-level config stays local. Files inside a project's .autohand/ directory are not synced because they belong in version control with the rest of the project. Only global settings under ~/.autohand/ participate in sync.

How sync works

Autohand sync uses Cloudflare R2 as its storage backend. Your data never touches a traditional database. Here is what happens under the hood:

  1. Local change detection - Autohand watches ~/.autohand/ for file changes using filesystem events.
  2. Encryption - Changed files are encrypted with AES-256-GCM using a key derived from your account credentials. API keys go through an additional encryption layer.
  3. Upload - Encrypted blobs are uploaded to Cloudflare R2 in your assigned region.
  4. Pull - Other devices poll for changes every 5 minutes (configurable) and decrypt new files locally.
# The sync cycle in practice
# 1. You change a setting on your laptop
autohand config set model.default "gpt-4o"

# 2. Within 5 minutes, the change uploads (encrypted) to R2
# 3. Your desktop pulls the change on its next sync interval
# 4. Both machines now use gpt-4o as the default model

Sync intervals

The default sync interval is 5 minutes. You can adjust this in your settings:

{
  "sync": {
    "enabled": true,
    "intervalMinutes": 2
  }
}

Setting the interval below 1 minute is not recommended. Frequent polling increases network usage without much practical benefit since most configuration changes are infrequent.

Conflict resolution

When the same file changes on two devices between sync intervals, Autohand uses a cloud-wins strategy by default. The version that reached the cloud first becomes the source of truth. The losing local version is saved to ~/.autohand/.sync-conflicts/ with a timestamp so you can recover it if needed.

Enabling sync

You need to be logged in before sync can work. If you have not logged in yet, run /login inside a session or use the CLI flag:

# Log in first (required)
autohand login

# Then enable sync using the slash command
/sync

There are three ways to enable sync depending on your preference:

Option 1: The /sync command

Inside an active session, type /sync. This walks you through setup interactively. You can choose which categories to sync, set the interval, and confirm encryption settings.

/sync

# Output:
# Sync setup
# Account: [email protected]
# Region: us-east-1
#
# Select what to sync:
#   [x] Configuration
#   [x] Custom agents
#   [x] Skills
#   [x] Hooks
#   [x] Memory files
#   [ ] Session history
#   [ ] Telemetry data
#
# Sync interval: 5 minutes
# Enable sync? (y/n)

Option 2: CLI flag

Pass --sync-settings when starting Autohand to enable sync immediately:

autohand --sync-settings

Option 3: Configuration file

Add the sync block to your ~/.autohand/settings.json:

{
  "sync": {
    "enabled": true,
    "intervalMinutes": 5,
    "categories": [
      "configuration",
      "agents",
      "skills",
      "hooks",
      "memory",
      "knowledge",
      "shared"
    ]
  }
}

Login is required

Sync will not start until you have authenticated with autohand login or /login. If you enable sync in the config file without being logged in, Autohand will display a reminder when it starts.

Excluding files from sync

You may have files in ~/.autohand/ that should not sync. Large local model caches, temporary debug logs, or machine-specific paths are good examples. Use glob patterns in the sync.exclude array to skip them:

{
  "sync": {
    "enabled": true,
    "exclude": [
      "cache/**",
      "models/**",
      "tmp/**",
      "*.log",
      "sessions/local-*",
      "debug/**"
    ]
  }
}

Common exclusion patterns

PatternWhat it excludesWhy
cache/**Downloaded model caches, token cachesLarge files that can be rebuilt locally
models/**Local model weights (Ollama, MLX)Multi-gigabyte files, specific to hardware
tmp/**Temporary working filesCreated and deleted during sessions
*.logDebug and error logsMachine-specific, not useful elsewhere
sessions/local-*Sessions marked as local-onlySome sessions contain sensitive project data

Exclusion patterns follow standard glob syntax. You can test them with the /sync status command, which shows what will and will not be synced.

Conflict resolution

Conflicts happen when the same file is edited on two machines before either one syncs. Autohand handles this automatically in most cases.

Default behavior: cloud wins

The first device to upload its change wins. When your other device pulls the update, the local version is replaced with the cloud version. The overwritten local file is saved to the conflicts directory:

# Conflict backup location
~/.autohand/.sync-conflicts/settings.json.2026-03-04T14-30-00Z

# List recent conflicts
ls ~/.autohand/.sync-conflicts/

# Restore a specific conflict backup
cp ~/.autohand/.sync-conflicts/settings.json.2026-03-04T14-30-00Z ~/.autohand/settings.json

When local changes take priority

If you are offline and making changes, those changes accumulate locally. When you come back online, Autohand uploads your local changes if the cloud version has not changed since your last sync. If the cloud version did change, the cloud version wins, and your local changes go to the conflicts directory.

To force your local version to become the cloud version, use:

# Force push local state to cloud
/sync push --force

# This overwrites the cloud with your current local state
# Use carefully, as it replaces data on all other devices

Manual resolution

For cases where you need to merge changes from both versions:

# Step 1: See what conflicts exist
/sync conflicts

# Step 2: Compare the cloud version with your local backup
diff ~/.autohand/settings.json ~/.autohand/.sync-conflicts/settings.json.2026-03-04T14-30-00Z

# Step 3: Edit the current file to include changes from both
# Step 4: Force push the merged result
/sync push --force

Optional sync items

Some data categories are not synced by default because they contain usage patterns that some users prefer to keep private. You can opt in to these categories individually.

Telemetry data

If you use Autohand on multiple machines and want a unified view of your usage patterns, you can sync telemetry data. This is useful for teams that aggregate usage metrics across workstations.

{
  "sync": {
    "enabled": true,
    "includeTelemetry": true
  }
}

When includeTelemetry is true, anonymous usage metrics are included in the sync payload. This does not change what telemetry collects. It only syncs the local telemetry state so it is consistent across devices.

Feedback data

Feedback you submit through /feedback can be synced so you have a record of your past reports on every machine:

{
  "sync": {
    "enabled": true,
    "includeFeedback": true
  }
}

Both of these options are strictly opt-in. They are never enabled automatically.

Security

Sync was designed with the assumption that the storage backend is untrusted. Even if someone gained access to the R2 bucket, they would not be able to read your data.

Encryption details

  • Algorithm: AES-256-GCM with unique nonces per file
  • Key derivation: PBKDF2 with 600,000 iterations from your account credentials
  • API keys: Encrypted with a separate derived key before the file-level encryption runs, creating two layers of protection
  • Transport: All uploads and downloads use TLS 1.3

What never leaves your machine

  • Your encryption key (it is derived locally and never transmitted)
  • Decrypted file contents (decryption only happens locally)
  • Personally identifiable information such as your name, email, or IP address in the sync payload
  • Project source code or git history

Revoking sync access

If a device is lost or compromised, you can revoke its sync access from any other authenticated device:

# List all synced devices
/sync devices

# Revoke a specific device
/sync revoke --device "work-macbook"

# Revoke all devices and reset sync (nuclear option)
/sync reset

Revoking a device removes its ability to pull new data. It does not delete data already on that device. If the device is physically compromised, change your account password to rotate the encryption key.

Troubleshooting sync

If sync is not working as expected, work through these common issues.

Sync is not starting

SymptomCauseFix
"Sync requires login" messageYou are not authenticatedRun autohand login and try again
No sync activity in logssync.enabled is not set to trueAdd "sync": {"enabled": true} to settings.json
Sync starts but immediately stopsNetwork connectivity issueCheck your internet connection and any proxy settings

Stale data on a device

If a device seems stuck on old settings, force a pull from the cloud:

# Force pull latest from cloud
/sync pull --force

# Check sync status and last sync time
/sync status

Resetting sync state

If sync gets into a broken state, you can reset it without losing your local files:

# Reset local sync metadata (keeps your files intact)
/sync reset --local

# Full reset: clears cloud data and re-uploads from this device
/sync reset --full

Debug logging

Enable verbose sync logs to see exactly what is happening:

# Run with sync debug output
AUTOHAND_SYNC_DEBUG=true autohand

# Logs show:
# [sync] Checking for changes... 3 files modified locally
# [sync] Encrypting settings.json (2.1 KB)
# [sync] Uploading to R2: us-east-1/user-abc/settings.json.enc
# [sync] Upload complete (234ms)
# [sync] Pulling remote changes... 0 new files