How Symlink-Based Sync Enables Real-Time Configuration Updates in Compound Engineering
Symlink-based sync creates symbolic links between canonical skill directories and target platform folders, ensuring that any modification to source files is instantly reflected across all synced outputs without requiring copy or rebuild operations.
The compound-engineering-plugin leverages symlink-based sync to bridge the gap between centralized skill development and multi-platform deployment. By using symbolic links rather than file copies, the plugin ensures that engineers can iterate on skills in real-time while maintaining consistent configurations across Pi, Droid, OpenCode, Cursor, and Codex targets.
How Symlink-Based Sync Works in the Compound Engineering Plugin
The Core Mechanism: Symbolic Links as Live Pointers
At the heart of the plugin's real-time capability is the creation of symbolic links (symlinks) from the canonical skill directories to platform-specific output folders. In src/utils/symlink.ts, the forceSymlink function establishes these pointers using the underlying filesystem's symlink capability.
When a developer modifies a skill's source files in the canonical location, those changes are immediately visible through every symlink that points to that directory. Unlike copy-based deployment strategies that require explicit rebuild or re-sync operations, symlink-based sync ensures the configuration that target platforms read is always current.
Safety and Idempotence with forceSymlink
The forceSymlink utility in src/utils/symlink.ts implements robust safety checks to make repeated sync calls reliable and non-destructive:
- Existing symlink removal: If the destination already exists as a symlink, it is removed and recreated, ensuring the link points to the correct source.
- Regular file cleanup: If the destination is a regular file, it is removed before creating the symlink.
- Directory collision protection: If the destination is a real directory, the operation aborts with a clear error message, preventing accidental data loss.
This idempotent design allows developers to run the sync command as often as needed—such as after every edit—without corrupting the output tree or accumulating stale files.
Security Validation via isValidSkillName
Before creating any symlink, the plugin validates skill identifiers using isValidSkillName in src/utils/symlink.ts. This validation blocks path-traversal attacks by ensuring only safe directory names are linked, preventing malicious skill names from escaping the intended directory structure.
Real-Time Configuration Updates Across Target Platforms
Platform-Specific Sync Implementations
The plugin implements target-specific sync routines that leverage the core symlink utilities:
src/sync/pi.ts: ImplementssyncToPi, creating symlinks for each skill and writing themcporter.jsonconfiguration file.src/sync/droid.ts: Mirrors the Pi logic for Android-based targets.src/sync/opencode.ts: HandlessyncToOpenCode, symlinking skills and merging MCP server definitions intoopencode.json.src/sync/cursor.tsandsrc/sync/codex.ts: Apply the same symlink-based pattern for Cursor and Codex platforms.
Each routine calls forceSymlink for every skill, ensuring the target output directory contains live pointers to the canonical skill sources.
MCP Server Configuration Merging
For platforms that consume JSON configuration files (such as Pi and OpenCode), the sync routine performs atomic configuration updates. In src/sync/opencode.ts, the process:
- Reads any existing
opencode.jsonconfiguration file. - Merges user-defined MCP server definitions with the current configuration.
- Writes the result back atomically.
Because the JSON file is written after the symlinks are established, the final output folder contains both live skill links and an up-to-date configuration file. This sequencing ensures that the platform never sees a configuration file referencing skills that haven't been linked yet.
Practical Implementation Examples
To sync a Claude home configuration to the Pi target:
import { syncToPi } from "./src/sync/pi";
import { readClaudeHome } from "./src/parsers/claude-home";
async function main() {
const config = await readClaudeHome("/path/to/.claude-plugin");
await syncToPi(config, "/tmp/pi-output");
}
main();
To sync to the OpenCode target, which includes opencode.json updates:
import { syncToOpenCode } from "./src/sync/opencode";
await syncToOpenCode(myConfig, "/tmp/opencode-output");
Both functions internally call forceSymlink for each skill, as seen in src/sync/pi.ts at line 19:
// Inside syncToPi (see line 19)
await forceSymlink(skill.sourceDir, target);
Summary
- Symlink-based sync creates live pointers from canonical skill directories to platform output folders, eliminating copy latency.
- The
forceSymlinkutility insrc/utils/symlink.tsensures safe, idempotent link creation with protection against directory collisions. - Security validation via
isValidSkillNameprevents path-traversal attacks before symlink creation. - Platform-specific routines in
src/sync/pi.ts,src/sync/opencode.ts, and sibling files combine symlinking with atomic JSON configuration merging. - Changes to skill source files are immediately reflected across all synced targets without rebuild steps.
Frequently Asked Questions
How does symlink-based sync differ from copy-based deployment?
Symlink-based sync creates symbolic links that point to the original skill directories, whereas copy-based deployment duplicates files into the target folder. With symlinks, any modification to the source files is instantly visible to the target platform because the filesystem resolves the link to the current state of the original directory. Copy-based approaches require explicit re-sync or rebuild operations to propagate changes, introducing latency and the risk of stale configurations.
What happens if I run the sync command multiple times?
The sync command is designed to be idempotent and safe for repeated execution. The forceSymlink utility in src/utils/symlink.ts checks the destination before creating each link: existing symlinks are removed and recreated, regular files are deleted, and the operation aborts with an error if it encounters a real directory. This ensures that running the sync command after every edit updates the links without accumulating stale files or corrupting the output tree.
Does symlink-based sync work across different filesystems or network drives?
Symlink-based sync requires that the source skill directories and the target output directories reside on the same filesystem or a filesystem that supports symbolic links. If the target directory is on a different filesystem or a network drive that does not support symlinks (such as certain FAT32 or exFAT volumes, or some network-attached storage configurations), the forceSymlink operation will fail. For cross-filesystem deployment scenarios, the plugin would require a copy-based fallback strategy rather than the native symlink approach.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →