How Sync Works
A look at what kst sync actually does — how skills are installed, how MCP configs are merged, what gets overwritten, and what's always left alone.
Sync Flow
1. Load config (kasetto.yaml or --config URL)
2. Load lock file (kasetto.lock)
3. Sync skills
a. For each skill source: materialize (download if remote)
b. Discover skills in source directory
c. For each skill: hash → compare to lock → copy if changed
d. Remove skills no longer in config
4. Sync MCP servers
a. For each MCP source: materialize (download if remote)
b. Discover MCP pack files in source
c. For each pack: hash → compare to lock → merge into agent settings if changed
d. Remove MCP entries no longer in config
5. Save lock file and report (unless --dry-run)
Skills: Copy and Replace
Skills are plain directories with a SKILL.md file (see writing skills). On each sync, Kasetto:
- Discovers skills by scanning the source root and
skills/subdirectory for directories that contain aSKILL.mdfile. - Hashes the source skill directory.
- Compares the hash to the lock file. If unchanged, the skill is skipped.
- Copies the entire directory to the destination, replacing any previous version.
- Removes skill directories that are no longer listed in the config.
Skills are fully replaced on update — no partial merges.
MCP Servers: Discovery and Additive Merge
Kasetto auto-discovers MCP pack files in the source:
.mcp.jsonat the source rootmcp.jsonat the source root- Any
.jsonfile inside amcp/subdirectory
Each file must contain a mcpServers JSON object. Use the path config field to skip auto-discovery and point directly at a specific file.
Server entries are merged into each agent's native settings file (e.g., .claude.json, .cursor/mcp.json). The merge follows two simple rules:
- New entries are added. If the settings file doesn't have a server with that name, it's inserted.
- Existing entries are never overwritten. If a server name already exists - whether added by Kasetto or by hand - Kasetto leaves it untouched.
In practice, this means:
- Manual edits are safe. If you add API keys, environment variables, or tweak server settings after a sync, those changes survive future syncs.
- Re-sync is idempotent. Running
synctwice with the same config produces the same result. - First write wins. If two sources define a server with the same name, only the first one is installed.
Supported Config Formats
Kasetto auto-detects the right format for each agent:
| Format | Used by | Target file example |
|---|---|---|
| McpServers JSON | Claude Code, Cursor, Gemini CLI, Roo, and others | .claude.json, .cursor/mcp.json |
| VS Code servers JSON | GitHub Copilot | .vscode/mcp.json |
| OpenCode JSON | OpenCode | .config/opencode/opencode.json |
| Codex TOML | Codex | .codex/config.toml |
All formats follow the same additive-merge rules — the underlying behavior is identical.
Change Detection
Kasetto uses SHA-256 hashes so it only does work when something actually changed:
- Skills: The entire skill directory is hashed. If the hash matches the lock file, the skill is skipped.
- MCP packs: The pack file is hashed. If the hash matches and all server names are still present in the target settings, the pack is skipped.
This keeps re-sync fast — unchanged sources require no file I/O beyond reading the lock.
Lock File
Kasetto tracks everything it installed in a YAML lock file called kasetto.lock. Where it lives depends on the scope:
| Scope | Location |
|---|---|
| Global | $XDG_DATA_HOME/kasetto/kasetto.lock (default: ~/.local/share/kasetto/kasetto.lock) |
| Project | ./kasetto.lock in the project root |
The lock file is how Kasetto knows what to remove when you drop a source from the config or run kst clean. You generally won't need to touch it by hand.
Skills are tracked by a composite key (source::skill-name) along with their destination path and hash.
MCP servers are tracked as assets with the server names they installed (e.g., destination: "git-tools,airflow"). Only these tracked names are removed during cleanup.
Important
Kasetto never touches entries it didn't install. Manually added servers, skills from other tools, or entries from a different scope are always left alone.
Removal Behavior
Removing a Source from Config
Remove a source from kasetto.yaml and re-sync:
- Skills: The skill directory is deleted from disk.
- MCPs: The specific server entries that Kasetto installed are removed from the agent's settings file. The file itself is preserved.
kst clean
Removes everything tracked in the lock file for the given scope:
- Deletes all tracked skill directories
- Removes all tracked MCP server entries from every agent's settings file
- Clears the lock file
--dry-run prints what would be removed (skill destinations and MCP pack lines) without changing disk.
Anything you added by hand outside the lock is never touched.
Edge Cases
Conflicting server names across sources. If source A and source B both define a server named "my-server", source A wins (it's processed first). If you later remove source A, "my-server" gets removed — even though source B also wanted it. Re-sync will then install source B's version.
Renamed servers in upstream. If an upstream MCP pack renames a server from "old" to "new", Kasetto treats it as: remove "old" (no longer in pack) + add "new" (not yet in settings). The old entry is cleaned up and the new one is added.
Corrupted settings file. If an agent's settings file is malformed JSON/TOML, the merge for that file fails and is reported as an error. The lock file isn't updated for that pack, so the next sync retries the merge automatically.