feat: portable settings sync across machines via GitHub#40
Open
dipendave wants to merge 1 commit intoAlexPeppas:masterfrom
Open
feat: portable settings sync across machines via GitHub#40dipendave wants to merge 1 commit intoAlexPeppas:masterfrom
dipendave wants to merge 1 commit intoAlexPeppas:masterfrom
Conversation
Add a complete settings sync system that keeps AgentPlex preferences and
Claude CLI configuration in sync across machines using a private GitHub
repo as the backend.
## Settings System
- Expand `settings-manager.ts` from a single `defaultShell` field to a
full extensible `AppPreferences` with `getAllSettings()`,
`updateSettings()`, and `invalidateCache()`
- All user-configurable values now live in `~/.agentplex/settings.json`
- Settings are edited via a Monaco JSON editor in the Settings panel
- Font size, font family, theme (dark/light), and all other preferences
are reactive — changes apply immediately to the terminal and UI
## Sync Engine (`sync-engine.ts`)
- Git-based sync using a private GitHub repo (`agentplex-sync`)
- One-click setup: detects GitHub auth via `gh` CLI, auto-creates the
repo if it doesn't exist, works with GitHub.com and GHE
- GitHub login flow built into the UI with device code display
- **Auto-sync**: `fs.watch` on `~/.claude/` dirs triggers debounced
push (30s); lightweight GitHub API poll with ETags every 5 min for
remote changes (304 Not Modified = zero cost)
- Conflict resolution via Monaco diff editor (`SyncConflictDialog.tsx`)
- Profile support in the backend (folders in sync repo: `default/`,
`work/`, etc.) with create/switch/rename/delete — UI hidden for now
- Automatic migration from flat repo layout to profile-based folders
- `syncClaudeIncludes` setting controls what gets synced from
`~/.claude/` (allowlist: CLAUDE.md, settings.json, agents, commands,
plugins by default)
- Sync config fields preserved during pull (machine-specific fields
like `syncRepoUrl` are never overwritten by synced settings)
## UI
- Settings panel opens as a floating overlay (no layout shift)
- Sync status icon at bottom of ActivityBar with colored dot indicator:
green (synced), spinning (syncing), yellow (conflict), red (error)
- Sync controls: "Sync Now" button + "Disconnect"
- Tooltip on Settings Sync header explaining what gets synced
- Terminal font size/family reactive to preferences — Ctrl+/- also
persists to settings.json for sync
- Theme toggle now persists to settings.json for cross-machine sync
## Testing
- Set up vitest with `pnpm test` / `pnpm test:watch`
- 56 tests across 2 test files:
- `settings-manager.test.ts` (11): load, save, merge, cache,
invalidate, extensibility, backward compat, sync config fields
- `sync-engine.test.ts` (45): file walking with allowlist, 1MB
guard, copy to/from repo, setup (empty/existing), push, pull,
disconnect, status, auto-sync, GitHub user parsing (GH + GHE),
profiles (list/create/switch/rename/delete/protection), custom
syncClaudeIncludes, flat-to-profile migration, sync config
preservation
- Tests use real git repos in temp directories (no git mocking)
- CLAUDE.md updated with TDD guidelines and settings conventions
## New Files
- `src/main/sync-engine.ts` — sync engine
- `src/main/settings-manager.test.ts` — settings tests
- `src/main/sync-engine.test.ts` — sync tests
- `src/renderer/components/SettingsPanel.tsx` — JSON editor + sync UI
- `src/renderer/components/SyncConflictDialog.tsx` — conflict resolver
- `vitest.config.mts` — test configuration
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a complete settings sync system that keeps AgentPlex preferences and Claude CLI configuration in sync across machines using a private GitHub repo as the backend. Includes a test framework (vitest) with 56 tests, an expanded settings system, and a new Settings panel with a Monaco JSON editor.
Key features:
agentplex-syncrepo viaghCLI, with built-in GitHub login flow (supports GitHub.com and GHE)~/.agentplex/settings.json, editable via a Monaco JSON editor in the Settings panelsyncClaudeIncludesallowlist controls which~/.claude/files/dirs are synced (default: CLAUDE.md, settings.json, agents, commands, plugins)What changed
New files
src/main/sync-engine.tssrc/main/settings-manager.test.tssrc/main/sync-engine.test.tssrc/renderer/components/SettingsPanel.tsxsrc/renderer/components/SyncConflictDialog.tsxvitest.config.mtsModified files
settings-manager.tsAppPreferencesinterface (extensible[key: string]: unknown),getAllSettings(),updateSettings(),invalidateCache()ipc-channels.tsSyncConflictFile,SyncConflictResolution; 17 new IPC channelsipc-handlers.tspreload.tstypes.tsAgentPlexAPIinterface additionsstore.tssyncStatus,preferencesstate;PanelIdincludes'settings'ActivityBar.tsxSidePanel.tsxApp.tsxmain.tsuseTerminal.tspackage.jsontest/test:watchscripts, vitest dependencyCLAUDE.mdArchitecture
Sync flow
Sync repo structure
Settings preserved during sync
Sync-config fields (
syncRepoUrl,syncLastSyncedAt,syncAutoSync,syncActiveProfile) are machine-specific and never overwritten by pulled settings.Auto-sync safeguards
suppressWatcherflag prevents feedback loops during sync operations (2s cooldown)localEditRefin the JSON editor prevents editor → save → broadcast → editor loopssyncingmutex prevents concurrent sync operations~/.claude/dirs are watchedTest plan
pnpm test)npx tsc --noEmit)syncClaudeIncludes~/.claude/commands/, wait 30s, verify push to GitHub🤖 Generated with Claude Code