# How to Sync Personal Claude Code Skills to OpenCode via Symlinks

> Sync personal Claude Code skills to OpenCode via symlinks using the compound engineering plugin. Edit live without duplication or data loss.

- Repository: [Every/compound-engineering-plugin](https://github.com/everyinc/compound-engineering-plugin)
- Tags: how-to-guide
- Published: 2026-02-16

---

**The `compound-engineering-plugin` CLI creates symbolic links between `~/.claude/skills` and `~/.config/opencode/skills`, enabling live editing without file duplication or data loss.**

The `EveryInc/compound-engineering-plugin` repository provides a dedicated `sync` command that bridges your personal Claude Code configuration with OpenCode. By parsing your Claude home directory and generating safe symbolic links, the tool ensures that any modifications to your original skill files are immediately reflected in OpenCode's environment.

## How the Sync Command Works

The synchronization process runs entirely within the plugin CLI and follows a six-step pipeline defined in [`src/commands/sync.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/commands/sync.ts). Each step includes specific safety checks to prevent path traversal and data loss.

### Loading Claude Code Configuration

The process begins with `loadClaudeHome()` in [`src/parsers/claude-home.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/parsers/claude-home.ts), which scans `~/.claude/` and returns an object containing the `skills` array. Each skill entry includes a `name` and `sourceDir` pointing to the original skill location.

### Validating Skill Names

Before creating any links, the system validates skill names using `isValidSkillName()` in [`src/utils/symlink.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/utils/symlink.ts) (lines 36-43). This function blocks path-traversal attempts like `../`, empty strings, and characters that could escape the target `~/.config/opencode/skills` directory.

### Creating Safe Symlinks

The `forceSymlink(sourceDir, targetPath)` function in [`src/utils/symlink.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/utils/symlink.ts) (lines 7-23) handles the actual link creation with the following safety protocol:

- Removes existing symlinks at the target location
- Deletes regular files if they block the path
- **Refuses to delete real directories**, throwing an error instead to prevent accidental data loss

### Merging MCP Servers

If your Claude configuration contains MCP server definitions, `convertMcpForOpenCode()` in [`src/sync/opencode.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/sync/opencode.ts) (lines 26-33) transforms them into OpenCode's format and merges them into [`opencode.json`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/opencode.json) (lines 48-74).

## Step-by-Step Sync Process

### Install the Plugin

```bash
bun install @everyinc/compound-engineering-plugin

# or globally with npm

npm i -g @everyinc/compound-engineering-plugin

```

### Run the Default Sync

```bash
npx compound-engineering-plugin sync opencode

```

This command syncs all skills from the default Claude home (`~/.claude`) into `~/.config/opencode/skills` as symbolic links.

### Specify a Custom Claude Home

If your Claude configuration resides elsewhere:

```bash
npx compound-engineering-plugin sync opencode --claude-home /path/to/custom/.claude

```

## Safety Mechanisms

The plugin implements three critical safety layers to protect your data:

- **Path traversal prevention**: The `isValidSkillName()` utility blocks `../` patterns and absolute paths that could escape the skills directory
- **Directory protection**: The `forceSymlink()` function explicitly refuses to overwrite existing directories, ensuring you cannot accidentally delete project folders
- **Secret detection**: Before merging MCP configurations, the CLI scans for potential API keys or tokens and prints a warning via `hasPotentialSecrets` to prevent credential leakage

## Why Use Symlinks?

The decision to use symbolic links rather than file copies provides two primary advantages:

- **Live editing**: Modifying a skill in `~/.claude/skills/my-skill` immediately updates the OpenCode view because the target is merely a pointer to the original file
- **Zero duplication**: No additional disk space is consumed, and the source of truth remains exclusively within your Claude Code home directory

## Summary

- The `compound-engineering-plugin` sync command bridges Claude Code and OpenCode configurations using symbolic links
- The process loads skills from `~/.claude/`, validates names against path traversal, and creates safe symlinks in `~/.config/opencode/skills`
- Safety mechanisms prevent directory overwrites and detect potential secrets in MCP server configurations
- Symlinks enable live editing without file duplication, keeping the Claude home as the single source of truth

## Frequently Asked Questions

### What happens if a skill name contains invalid characters?

The `isValidSkillName()` function in [`src/utils/symlink.ts`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/src/utils/symlink.ts) rejects names containing path traversal patterns like `../`, absolute paths, or empty strings. The sync command will skip these invalid entries and continue processing valid skills, preventing any escape from the target directory.

### Can the sync command delete my existing directories?

No. The `forceSymlink()` utility explicitly refuses to delete real directories. If a directory exists at the target path where a symlink should be created, the command throws an error and halts rather than risk data loss. It will only remove existing symlinks or regular files blocking the path.

### Do I need to re-run the sync after editing my Claude Code skills?

No. Because the sync creates symbolic links rather than file copies, any changes you make to files in `~/.claude/skills/` are immediately reflected in `~/.config/opencode/skills/`. You only need to re-run the sync when you add new skills or rename existing ones in your Claude configuration.

### How does the plugin handle MCP server secrets?

Before merging MCP server definitions into [`opencode.json`](https://github.com/EveryInc/compound-engineering-plugin/blob/main/opencode.json), the CLI scans for potential secrets using `hasPotentialSecrets`. If detected, the command prints a warning to the console to alert you that credentials may be exposed in the configuration file, allowing you to review the output before committing it to version control.