@tinyrack/devsync
v1.13.3
Published
A personal CLI tool for git-backed configuration sync.
Maintainers
Readme
devsync
devsync is a cross-platform CLI for managing the configuration files in your home directory with git and syncing them across multiple devices.
Instead of treating the repository as the source of truth, devsync treats your actual local config as the truth. You choose files and directories under HOME, devsync mirrors them into a git-backed sync repository, and later restores that repository onto another device when you need it.
1. Purpose and how it differs
Most dotfiles tools start from the repository and ask you to shape your local system around it.
devsync takes the opposite approach:
- Your real config under
HOMEis the source of truth. - The git repository is a sync artifact, not the primary authoring location.
pushcaptures your current local state into the repository.pullapplies the repository back onto another device.
That makes devsync a good fit when you want to:
- manage existing dotfiles and app configs without reorganizing your home directory,
- keep profile-specific config workflows intact,
- sync plain files and encrypted secrets together,
- use normal git remotes as the transport layer between PCs,
- handle platform-specific paths across Windows, macOS, and Linux.
Core capabilities:
- track files and directories under your home directory,
- store synced artifacts in
~/.config/devsync/sync, - mark paths as
normal,secret, orignore, - encrypt secret artifacts with
age, - assign entries to profiles so different machines sync different subsets,
- support platform-specific local paths per entry,
- preview both directions with
status,push --dry-run, andpull --dry-run.
2. Installation
Requirements:
- Node.js 25.5+
- npm
- git
Install globally:
npm install -g @tinyrack/devsync
devsync --helpRun without installing globally:
npx @tinyrack/devsync --helpRun from this checkout:
npm install
npm run start -- --helpThe published package name is @tinyrack/devsync, and the installed command is devsync.
Single executable builds with Node SEA
This repository also supports a local-platform single executable build through Node SEA.
Requirements for SEA builds:
- Node.js 25.5+
- the build must run on the same platform you want to execute initially
Build the executable:
npm run sea:build
./dist/sea/devsync --versionRun the dedicated smoke test:
npm run sea:smokeNotes:
- The SEA output is written to
dist/sea/devsyncon Unix-like systems anddist/sea/devsync.exeon Windows. npm run sea:bundlecreates only the single-file bundled entry that feeds SEA generation.- The initial SEA workflow is local-platform only. Cross-platform release generation and code signing are separate concerns.
3. Quickstart
Initialize a local sync repository:
devsync initProvide an existing age private key during setup:
devsync init --key AGE-SECRET-KEY-...Track a few configs:
devsync track ~/.gitconfig
devsync track ~/.zshrc
devsync track ~/.config/mytool --mode secretReview what would be captured:
devsync status
devsync push --dry-runWrite your current local config into the sync repository:
devsync pushOpen the sync repository and publish it with git:
devsync cd
# inside the spawned shell
git add .
git commit -m "Update synced config"
git push
exitOn another device, clone and restore from the same repo:
devsync init https://example.com/my-sync-repo.git
devsync status
devsync pull --dry-run
devsync pullNotes:
pushupdates the sync repository contents only; it does not create git commits or push to a remote.pullupdates local files only.- Secret paths are stored encrypted in the repository and require the configured
ageidentity to decrypt on restore. initprompts for an age private key when--keyis omitted. Submit an empty response to generate a new identity automatically.- Long-running commands such as
init,status,push,pull, and multi-targettracknow stream progress tostderrwhile keeping the final summary onstdout. - Use
--verboseto show more detailed per-entry and per-file progress output.
Shell autocomplete
Load autocomplete into the current shell session with eval:
eval "$(devsync autocomplete bash)"eval "$(devsync autocomplete zsh)"To enable autocomplete automatically for future shells, add the matching eval line to your shell startup file such as ~/.bashrc or ~/.zshrc.
4. Detailed docs
How tracking works
- You track files or directories that live under your home directory.
devsyncmirrors them into~/.config/devsync/sync/default/<repoPath>for the default profile, or~/.config/devsync/sync/<profile>/<repoPath>for a named profile.- Plain artifacts are stored as-is.
- Secret artifacts are stored with the
.devsync.secretsuffix.
Storage layout:
- Sync repo:
~/.config/devsync/sync - Default profile artifacts:
~/.config/devsync/sync/default/<repoPath> - Named profile artifacts:
~/.config/devsync/sync/<profile>/<repoPath> - Default age identity:
$XDG_CONFIG_HOME/devsync/age/keys.txt
Sync modes
Each tracked path can use one of three modes:
normal: store and restore plain contentsecret: encrypt before storing in the repoignore: skip during push and pull
Set modes when tracking, or update them later:
devsync track ~/.config/mytool --mode secret
devsync track ~/.config/mytool/cache --mode ignore
devsync track ~/.config/mytool/public.json --mode normalChild entries inside a tracked directory inherit the parent mode unless explicitly overridden.
Profiles
Profiles let you sync different subsets of entries on different machines. Each entry can be assigned to one or more profiles. When a profile is active, only entries assigned to that profile (plus entries with no profile restriction) are synced.
devsync track ~/.ssh/config --mode secret --profile work
devsync track ~/.gitconfig --profile work --profile personal
devsync track ~/.zshrc
devsync profile use work
devsync profile listKey behaviors:
- Entries without
--profileare synced on all profiles (including when no profile is active). - Entries with
--profileare only synced when one of the listed profiles is active. - Pass
--profile ''to clear profile restrictions from an entry. - The
defaultprofile namespace is reserved for entries with no profile restriction. - Commands like
push,pull, andstatusaccept--profileto override the active profile for a single operation.
Platform-specific paths
Entries can specify different local paths per platform, so the same sync config works across Windows, macOS, Linux, and WSL:
Example manifest.json:
{
"version": 7,
"age": {
"identityFile": "$XDG_CONFIG_HOME/devsync/age/keys.txt",
"recipients": ["age1example..."]
},
"entries": [
{
"kind": "file",
"localPath": {
"default": "~/.gitconfig",
"win": "%USERPROFILE%/.gitconfig"
},
"mode": {
"default": "normal"
}
},
{
"kind": "directory",
"localPath": {
"default": "~/.config/mytool",
"win": "%APPDATA%/mytool"
},
"mode": {
"default": "normal",
"win": "ignore"
},
"profiles": ["work"]
},
{
"kind": "file",
"localPath": {
"default": "~/.config/mytool/token.json"
},
"mode": {
"default": "secret"
},
"profiles": ["work"]
}
]
}The localPath object supports default, win, mac, linux, and wsl keys. The default key is required. On WSL, wsl is used first, then linux, then default.
The mode object uses the same shape. mode.default is required, OS-specific keys are optional, and on WSL the fallback order is wsl -> linux -> default. An explicit child mode replaces the parent's full mode policy instead of merging platform overrides.
Common workflow
Check what changed:
devsync statusCapture local config into the repository:
devsync pushRestore repository state locally:
devsync pullUse dry runs when you want to review first:
devsync push --dry-run
devsync pull --dry-runOverride the active profile for a single operation:
devsync push --profile work
devsync pull --profile personal
devsync status --profile workCommand reference
init
Create or connect the local sync repository.
devsync init
devsync init https://example.com/my-sync-repo.git
devsync init --identity "$XDG_CONFIG_HOME/devsync/age/keys.txt" --recipient age1...track
Track a file or directory under your home directory.
devsync track ~/.gitconfig
devsync track ~/.gitconfig ~/.zshrc ~/.config/nvim
devsync track ~/.ssh/config --mode secret
devsync track ~/.ssh/config --mode secret --profile work
devsync track ~/.config/mytool/cache --mode ignoreIf the target is already tracked, its mode is updated. Targets may also be repository paths inside a tracked directory to create child entries with a specific mode.
untrack
Remove a tracked entry from the sync config.
devsync untrack ~/.gitconfig
devsync untrack ~/.config/mytool
devsync untrack .config/mytool/token.jsonThis only updates the sync config; actual file changes happen on the next push or pull.
status
Preview planned push and pull changes.
devsync status
devsync status --profile workdoctor
Validate repo state, config, tracked paths, and secret setup.
devsync doctorpush
Write local state into the sync repository.
devsync push
devsync push --dry-run
devsync push --profile workpull
Apply repository state back onto local paths.
devsync pull
devsync pull --dry-run
devsync pull --profile workprofile list
Show configured profiles and which one is active.
devsync profile listprofile use
Set or clear the active sync profile.
devsync profile use work
devsync profile useOmit the profile name to clear the active profile.
cd
Launch a shell in the sync repository directory.
devsync cddevsync cd opens a child shell rooted at the sync repository directory. Exit that shell to return to your original session.
For flag-level details, use built-in help:
devsync --help
devsync init --help
devsync track --helpDevelopment
Run the CLI locally:
npm run start -- --helpWatch mode:
npm run devValidation:
npm run typecheck
biome check .
npm run testOr run everything at once:
npm run checkRelease
- CI runs
npm run checkon every push and pull request. - npm publishing runs automatically for Git tags matching
v*.*.*. - The release workflow expects the pushed tag to match
package.jsonversion.
Typical release flow:
npm version patch
git push --follow-tags