---
title: "Settings Sync"
source: https://docs.autohand.ai/working-with-autohand-code/settings-sync
---

# Settings Sync

Keep your Autohand configuration, custom agents, skills, hooks, and memory files in sync across every machine you work on. Settings sync is encrypted end-to-end and runs in the background so your workflow stays the same wherever you open a terminal.

## What syncs across devices

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

| Category | What gets synced | Location |
|---|---|---|
| Configuration | Global settings, model preferences, permission rules, theme choices | ~/.autohand/settings.json |
| API keys | Provider keys (OpenAI, Anthropic, etc.) encrypted separately before upload | ~/.autohand/credentials.enc |
| Custom agents | Your AGENTS.md files and agent configurations | ~/.autohand/agents/ |
| Community skills | Installed community skill definitions and their configurations | ~/.autohand/skills/community/ |
| Custom skills | Skills you wrote yourself, including prompt templates and tool definitions | ~/.autohand/skills/custom/ |
| User hooks | Global hook definitions that run across all projects | ~/.autohand/hooks/ |
| Memory files | Your global CLAUDE.md and project memory summaries | ~/.autohand/memory/ |
| Project knowledge | Learned patterns, codebase indexes, and project-specific context | ~/.autohand/knowledge/ |
| Session history | Recent session metadata (not full transcripts) so you can resume on another machine | ~/.autohand/sessions/ |
| Shared content | Bookmarked 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.

``` bash
# 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:

``` json
{
  "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:

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

``` bash
/sync

# Output:
# Sync setup
# Account: you@example.com
# 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:

``` bash
autohand --sync-settings
```

### Option 3: Configuration file

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

``` 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:

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

### Common exclusion patterns

| Pattern | What it excludes | Why |
|---|---|---|
| cache/** | Downloaded model caches, token caches | Large files that can be rebuilt locally |
| models/** | Local model weights (Ollama, MLX) | Multi-gigabyte files, specific to hardware |
| tmp/** | Temporary working files | Created and deleted during sessions |
| *.log | Debug and error logs | Machine-specific, not useful elsewhere |
| sessions/local-* | Sessions marked as local-only | Some 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:

``` bash
# 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:

``` bash
# 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:

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

``` json
{
  "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:

``` json
{
  "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:

``` bash
# 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

| Symptom | Cause | Fix |
|---|---|---|
| "Sync requires login" message | You are not authenticated | Run autohand login and try again |
| No sync activity in logs | sync.enabled is not set to true | Add "sync": {"enabled": true} to settings.json |
| Sync starts but immediately stops | Network connectivity issue | Check 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:

``` bash
# 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:

``` bash
# 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:

``` bash
# 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
```