No description
  • TypeScript 100%
Find a file
winetree94 1a6721d704
Some checks are pending
CI / validate (push) Waiting to run
fix: run build before tests in release workflow
2026-03-23 03:47:11 +09:00
.github/workflows fix: run build before tests in release workflow 2026-03-23 03:47:11 +09:00
src chore: update biome schema and disable noTemplateCurlyInString rule 2026-03-23 03:40:45 +09:00
tests feat: compile TypeScript to JavaScript for npm distribution 2026-03-23 03:36:07 +09:00
.gitignore feat: initialize devtools web toolkit 2026-03-18 22:25:44 +09:00
AGENTS.md docs: clarify test placement and coverage guidance in AGENTS.md 2026-03-20 14:57:06 +09:00
biome.json chore: update biome schema and disable noTemplateCurlyInString rule 2026-03-23 03:40:45 +09:00
CLAUDE.md chore: add CLAUDE.md with project conventions 2026-03-22 12:42:16 +09:00
LICENSE docs: add MIT license 2026-03-19 02:41:11 +09:00
package-lock.json chore(release): 1.2.1 2026-03-23 03:44:39 +09:00
package.json chore(release): 1.2.1 2026-03-23 03:44:39 +09:00
README.md docs: update README to reflect files directory removal in sync layout 2026-03-22 01:31:04 +09:00
tsconfig.build.json feat: compile TypeScript to JavaScript for npm distribution 2026-03-23 03:36:07 +09:00
tsconfig.json feat: compile TypeScript to JavaScript for npm distribution 2026-03-23 03:36:07 +09:00
vitest.config.ts feat: compile TypeScript to JavaScript for npm distribution 2026-03-23 03:36:07 +09:00

devsync

devsync is a cross-platform CLI for managing the configuration files in your home directory with git and syncing them across multiple machines.

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 machine when you need it.

1. Purpose and how it differs

Most dotfiles tools start from the repository and ask you to shape your local machine around it.

devsync takes the opposite approach:

  • Your real config under HOME is the source of truth.
  • The git repository is a sync artifact, not the primary authoring location.
  • push captures your current machine state into the repository.
  • pull applies the repository back onto another machine.

That makes devsync a good fit when you want to:

  • manage existing dotfiles and app configs without reorganizing your home directory,
  • keep machine-specific config workflows intact,
  • sync plain files and encrypted secrets together,
  • use normal git remotes as the transport layer between PCs.

Core capabilities:

  • track files and directories under your home directory,
  • store synced artifacts in ~/.config/devsync/sync,
  • mark paths as normal, secret, or ignore,
  • encrypt secret artifacts with age,
  • preview both directions with status, push --dry-run, and pull --dry-run.

2. Installation

Requirements:

  • Node.js 24+
  • npm
  • git

Install globally:

npm install -g @tinyrack/devsync
devsync --help

Run without installing globally:

npx @tinyrack/devsync --help

Run from this checkout:

npm install
npm run start -- --help

The published package name is @tinyrack/devsync, and the installed command is devsync.

3. Quickstart

Initialize a local sync repository:

devsync init

Track a few configs:

devsync add ~/.gitconfig
devsync add ~/.zshrc
devsync add ~/.config/mytool --secret

Review what would be captured:

devsync status
devsync push --dry-run

Write your current local config into the sync repository:

devsync push

Open the sync repository and publish it with git:

devsync cd
git status
git add .
git commit -m "Update synced config"
git push

On another machine, clone and restore from the same repo:

devsync init https://example.com/my-sync-repo.git
devsync status
devsync pull --dry-run
devsync pull

Notes:

  • push updates the sync repository contents only; it does not create git commits or push to a remote.
  • pull updates local files only.
  • Secret paths are stored encrypted in the repository and require the configured age identity to decrypt on restore.

4. Detailed docs

How tracking works

  • You add files or directories that live under your home directory.
  • devsync mirrors 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.secret suffix.

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 content
  • secret: encrypt before storing in the repo
  • ignore: skip during push and pull

You can apply modes to tracked roots or nested paths inside tracked directories.

Profile-specific behavior inherits the tracked root mode and only changes nested paths inside tracked directories.

Examples:

devsync set secret ~/.config/mytool/token.json
devsync set ignore ~/.config/mytool/cache --recursive
devsync set normal ~/.config/mytool/public.json
devsync set secret ~/.config/mytool/token.json --profile work

Profile-specific overrides

  • Track the root once without --profile.
  • Use devsync set --profile <name> only for child paths inside tracked directories.
  • Profile-specific rules inherit the parent root mode and only override nested paths.
  • Named profile artifacts are stored under <profile>/<repoPath>.
  • default is reserved for the base layout and cannot be used as a named profile.
  • Standalone profiled roots and profiled file entries are not supported.

Example config.json:

{
  "version": 1,
  "age": {
    "identityFile": "$XDG_CONFIG_HOME/devsync/age/keys.txt",
    "recipients": ["age1example..."]
  },
  "entries": [
    {
      "kind": "directory",
      "localPath": "~/.config/mytool",
      "mode": "normal",
      "overrides": {
        "cache/": "ignore"
      },
      "profiles": {
        "work": {
          "overrides": {
            "token.json": "secret"
          }
        }
      },
      "repoPath": ".config/mytool"
    }
  ]
}

Common workflow

Check what changed:

devsync status

Capture local config into the repository:

devsync push

Restore repository state onto the machine:

devsync pull

Use dry runs when you want to review first:

devsync push --dry-run
devsync pull --dry-run

Command 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...

add

Track a file or directory under your home directory.

devsync add ~/.gitconfig
devsync add ~/.config/mytool
devsync add ~/.config/mytool --secret

add --profile is not supported for tracked roots. Track the root first, then use set --profile for child overrides.

set

Change the sync mode for a tracked root, child path, or subtree.

devsync set secret ~/.config/mytool/token.json
devsync set ignore ~/.config/mytool/cache --recursive
devsync set secret ~/.config/mytool/token.json --profile work

With --profile, the target must be a child path inside a tracked directory, and default cannot be used as the profile name. Profile-specific root mode changes are not supported.

forget

Remove a tracked path or nested override from config.

devsync forget ~/.gitconfig
devsync forget ~/.config/mytool
devsync forget .config/mytool/token.json --profile work

list

Show tracked entries, default modes, root overrides, and profile-specific child overrides.

devsync list

status

Preview planned push and pull changes.

devsync status

doctor

Validate repo state, config, tracked paths, and secret setup.

devsync doctor

push

Write local state into the sync repository.

devsync push
devsync push --dry-run

pull

Apply repository state back onto the local machine.

devsync pull
devsync pull --dry-run

cd

Open the sync repository in your shell, or print its path.

devsync cd
devsync cd --print

For flag-level details, use built-in help:

devsync --help
devsync init --help
devsync add --help
devsync set --help

Development

Run the CLI locally:

npm run start -- --help

Watch mode:

npm run dev

Validation:

npm run typecheck
biome check .
npm run test

Or run everything at once:

npm run check

Release

  • CI runs npm run check on every push and pull request.
  • npm publishing runs automatically for Git tags matching v*.*.*.
  • The release workflow expects the pushed tag to match package.json version.

Typical release flow:

npm version patch
git push --follow-tags