VSync


VSync is a VS Code extension for safely pushing and pulling selected development
configuration files through AWS S3, MinIO, Cloudflare R2, or another
S3-compatible object store. It keeps files in their original format and makes
every transfer explicit and reviewable.
VSync is currently pre-1.0. Review previews carefully and keep an independent
backup of important files.
Files & Folders sync
- Push uploads selected local files to S3.
- Pull downloads selected S3 files to their mapped local paths.
- Files keep their original name, extension, directory structure, and bytes.
- Modified text files open in the VS Code Diff Editor before transfer.
- Binary differences show sizes and require confirmation.
- Pull creates a local safety backup before replacing an existing file.
- A dedicated MinIO provider uses bucket versioning for immutable remote
snapshots and exact-version pulls.
- Folder scans retain metadata rather than every file body, and hashing and
transfers use bounded concurrency.
- Multiple S3 profiles are stored in VS Code settings.
- The active profile can be switched from the Command Palette.
- Secret access keys remain in VS Code SecretStorage.
There is no automatic bidirectional sync, custom snapshot graph, blob store, or hidden content format.
Secret Sync MVP
Secret Sync is separate from the original config-file pipeline. Create a secret
profile from the Secret Sync view, import a .env, and explicitly push an
AES-256-GCM encrypted bundle to the active S3 profile. The remote layout is:
<prefix>/secrets/<secret-profile-id>/manifest.json
<prefix>/secrets/<secret-profile-id>/bundle.enc
The encryption key and provider tokens stay in VS Code SecretStorage. Profile
metadata and keyed HMAC fingerprints contain no secret values. Recovery-key
export/import enables another desktop extension host to decrypt the bundle.
VSync intentionally has two independent profile types:
- Files & Folders profiles own config-file mappings and their S3 credentials.
- Secret Sync profiles own encrypted-bundle storage, recovery keys, and provider
targets with separate credentials. They do not borrow the Files & Folders profile.
GitHub repository/environment secrets and GitLab project variables are one-way
publishing targets. VSync cannot read their stored values, never presents them as
two-way synchronization sources, and never deletes remote provider secrets. Every
preview is key-name-only and every mutation requires selection or confirmation.
S3 layout
For a profile with prefix vsync/development:
vsync/development/
├── home/
│ ├── .zshrc
│ ├── .gitconfig
│ └── .config/
│ └── nvim/
│ ├── init.lua
│ └── lua/config.lua
└── .vsync/
└── manifest.json
Every S3 object is the original file. You can download or edit it using an ordinary S3 client. For MinIO profiles, bucket versioning is required: each v2 manifest pins the exact object VersionId, and the versioned manifest itself is the snapshot commit point.
Requirements
- VS Code 1.96 or newer.
- An S3-compatible bucket and credentials with list/get/put access.
- MinIO bucket versioning when using the dedicated
minio provider.
Install
VS Code Marketplace
After the public listing is available, open Extensions in VS Code, search for
VSync, verify that the publisher is npv2k1, and select Install. The
Marketplace extension ID is npv2k1.nsync.
GitHub Release / VSIX
- Download
vsync-<version>.vsix and SHA256SUMS from the matching
GitHub Release.
- Verify the checksum, then run
Extensions: Install from VSIX....
- Select the downloaded VSIX.
Quick start
- Run
VSync: Add or Update Profile.
- Run
VSync: Set Active Profile Secret.
- Run
VSync: Test Storage Connection.
- Run
VSync: Add File or VSync: Add Folder.
- Start with
VSync: Preview Push or VSync: Preview Pull.
- Review the changes, then run
VSync: Push Local Changes or
VSync: Pull Remote Changes.
Settings
Profiles are visible and editable in User Settings JSON:
{
"vsync.activeProfile": "development",
"vsync.profiles": {
"development": {
"provider": "minio",
"endpoint": "http://localhost:9000",
"region": "us-east-1",
"bucket": "developer-config",
"prefix": "vsync/development",
"forcePathStyle": true,
"accessKeyId": "admin",
"entries": [
{
"type": "file",
"localPath": "${userHome}/.zshrc",
"remotePath": "home/.zshrc"
},
{
"type": "folder",
"localPath": "${userHome}/.config/nvim",
"remotePath": "home/.config/nvim",
"excludes": ["**/.git/**", "**/node_modules/**"]
}
]
}
}
}
Use provider: "minio" for MinIO rather than the generic
"s3-compatible" provider. VSync then:
- uses MinIO-compatible AWS SDK checksum settings;
- verifies that bucket versioning is enabled;
- records object version IDs in
.vsync/manifest.json;
- pulls the exact version pinned by the manifest;
- retains native AWS checksum defaults for
provider: "aws-s3".
The IAM policy needs s3:GetBucketVersioning in addition to the existing
list/get/put permissions. MinIO lifecycle rules can expire noncurrent object
versions, so their retention should match the desired snapshot history.
Set the secret using VSync: Set Active Profile Secret; it is intentionally absent from settings.json.
Folder ignore behavior
For every folder entry, VSync automatically reads the root .gitignore and
any nested .gitignore files it reaches. Rules use Git semantics, including
comments, anchored paths, directory rules, and ! negation. The .gitignore
file itself is synchronized unless one of the rules excludes it.
Built-in exclusions (.git, node_modules, .DS_Store, and *.log) and an
entry's explicit excludes patterns remain hard exclusions; .gitignore
negation cannot re-include them. Ignored remote objects are hidden from preview
and pull, but VSync does not delete an object that was uploaded before a new
ignore rule was added.
Push behavior
| State |
Action |
| Local and S3 are identical |
Skip |
| Local exists, S3 missing |
Offer upload |
| Both exist and differ |
Open Diff, then Push or Skip |
| S3 exists, local missing |
Leave S3 unchanged |
Push publishes .vsync/manifest.json only after every selected upload succeeds.
The v2 manifest contains SHA-256, size, mode, and MinIO object version IDs. An
existing v1 or missing manifest uses a compatible one-time legacy comparison;
the next successful push upgrades it to v2.
Pull behavior
| State |
Action |
| Local and S3 are identical |
Skip |
| S3 exists, local missing |
Offer download |
| Both exist and differ |
Open Diff, then Pull or Skip |
| Local exists, S3 missing |
Leave local unchanged |
Pull never deletes a local file. Backups are stored below the extension's global storage directory; vsync.backup.keep controls retained backup operations.
vsync.transfer.concurrency controls concurrent hashing and transfer workers
(default 8, range 1–32). Interactive Diff prompts remain sequential.
Security
Files & Folders objects are stored in their original, unencrypted format. Do
not map private keys or credential files unless bucket permissions and
provider-side encryption are appropriate. Secret Sync is a separate pipeline:
its bundles are encrypted locally with AES-256-GCM before upload. VSync warns
about common sensitive paths.
VSync does not collect analytics or send data to a VSync-operated service.
Configured files are read locally and transferred only to the S3-compatible
endpoint selected in the active profile. Access key IDs and profile settings use
VS Code settings; secret access keys use VS Code SecretStorage.
To report a vulnerability, follow SECURITY.md rather than opening
a public issue.
Known limitations
- Synchronization is manual; there is no background or automatic bidirectional sync.
- Push and Pull do not implicitly delete files from either side.
- Symbolic links inside synchronized folders are skipped.
- Files & Folders mappings are not client-side encrypted; use Secret Sync for
encrypted
.env bundles.
See the roadmap for planned compatibility and safety work.
Support and contributing
Development
npm ci
npm run typecheck
npm test
npm run package