Keep your ClawDE sessions, files, and state consistent across Desktop, Mobile, and Web. Edit on your laptop, pick up on your phone — without manually copying anything.
nself-sync is the backbone of ClawDE's multi-device story. Without it, each ClawDE instance is isolated. With it, your sessions travel with you.
nself license set nself_pro_...
nself plugin install sync
nself build
nself startnself-sync maintains a server-side representation of your ClawDE state: open sessions, file snapshots, environment variables, and context pages. Any ClawDE client — desktop, mobile, web — can push its current state and pull the latest from any other client.
Sync uses last-write-wins for scalar values (open file path, cursor position, active session ID). For file contents with concurrent edits, a three-way merge is attempted. If the merge produces a conflict, both versions are kept and flagged for manual resolution in the ClawDE UI — the plugin never silently discards data.
State is versioned. Each push increments a monotonic sequence number. Clients that have been offline reconnect with their last known sequence and receive a delta of changes since then. A full snapshot is served as a fallback when a client is more than 100 versions behind.
| Variable | Required | Default | Description |
|---|---|---|---|
PLUGIN_SYNC_PUSH_INTERVAL_MS | No | 5000 | How often ClawDE clients push state (milliseconds). Lower = more real-time, more requests. |
PLUGIN_SYNC_CONFLICT_STRATEGY | No | merge | How concurrent file edits are handled: merge (3-way, flag conflicts) or lww (last-write-wins, no flag) |
PLUGIN_SYNC_MAX_FILE_SIZE_KB | No | 512 | Max size of a synced file snapshot in kilobytes |
PLUGIN_SYNC_SNAPSHOT_THRESHOLD | No | 100 | Versions behind at which a full snapshot is served instead of deltas |
PLUGIN_SYNC_RETENTION_DAYS | No | 30 | How long old state versions are kept before pruning |
| Endpoint | Method | Description |
|---|---|---|
/sync/push | POST | Push current client state. Body: { device_id, seq, state } |
/sync/pull | GET | Pull delta since ?since_seq=N. Returns full snapshot if behind threshold. |
/sync/devices | GET | List registered devices for the authenticated user |
/sync/devices/:id | DELETE | Remove a device (revokes its sync token) |
/sync/conflicts | GET | List unresolved file conflicts for the user |
/sync/conflicts/:id/resolve | POST | Resolve a conflict. Body: { resolution: "mine" | "theirs" | "merged", content? } |
/health | GET | Plugin health check |
| Table | Purpose |
|---|---|
np_sync_devices | Device: user_id, device_id, platform (desktop/mobile/web), last_seen, sync_token |
np_sync_state | Latest state snapshot per user: open sessions, active file, env vars (encrypted), sequence number |
np_sync_deltas | Versioned state deltas: device_id, seq, diff JSON, created_at |
np_sync_conflicts | Unresolved file conflicts: file_path, mine, theirs, base, created_at, resolved_at |
| Event | Payload |
|---|---|
sync.state.updated | User ID, device ID, sequence number, updated keys |
sync.conflict.created | User ID, file path, conflicting device IDs |
sync.conflict.resolved | Conflict ID, resolution type, resolver device ID |
The ClawDE desktop and mobile apps call /sync/push on a configurable interval and /sync/pull on startup and after a period of inactivity. Environment variables in the state payload are encrypted at rest using a key derived from the user's auth token — they are never stored in plaintext.
// ClawDE client push (simplified)
await fetch('/sync/push', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token },
body: JSON.stringify({
device_id: 'desktop-abc123',
seq: localSeq,
state: {
open_session_id: currentSession.id,
active_file: editor.currentFile,
// env vars are encrypted client-side before sending
env_encrypted: await encryptEnv(localEnvVars, userKey),
}
})
})| Feature | nself-sync | iCloud / Google Drive | Dropbox |
|---|---|---|---|
| Self-hosted | Yes | No | No |
| ClawDE-aware state | Yes (sessions, env, files) | Files only | Files only |
| Conflict resolution | 3-way merge + manual flag | Duplicate file | Duplicate file |
| Env var sync | Yes (encrypted) | No | No |
| Symptom | Fix |
|---|---|
| Pull returns full snapshot instead of delta | Client is more than PLUGIN_SYNC_SNAPSHOT_THRESHOLD versions behind. This is expected after being offline. The snapshot is complete — no data loss. |
| Conflict not resolving | Call POST /sync/conflicts/:id/resolve with a valid resolution. Unresolved conflicts block future pushes from the affected device until resolved. |
| Device shows as unknown | A new device_id was used. Check GET /sync/devices — the device registers on first push and will appear within one push cycle. |
Port: 3829 | Bundle: ClawDE ($0.99/mo) or ɳSelf+ ($3.99/mo) | Last Updated: May 2026 | Plugin Version 1.0.13