Bidirectionally convert and sync Custom Slash Commands and Skills between Claude Code, Gemini CLI, Codex CLI, OpenCode, GitHub Copilot, and Cursor with intuitive visual feedback. Features a Chimera virtual agent as a lossless conversion hub.
npm install -g agent-command-sync# Direct conversion between agents
acs sync -s claude -d gemini
acs sync -s gemini -d claude
# Import into Chimera hub (lossless)
acs import claude
acs import gemini
# Apply from Chimera hub to an agent
acs apply gemini
acs apply claude
# Preview changes (dry run)
acs drift claude # Preview import
acs plan gemini # Preview apply
# Convert Skills or Commands only
acs sync -s claude -d gemini -t skills
acs sync -s claude -d gemini -t commands
# Preview direct conversion
acs sync -n -s claude -d gemini- Colorful Output - Clear visual feedback with color-coded status indicators
- Fast Conversion - Efficiently sync commands between Claude Code, Gemini CLI, Codex CLI, OpenCode, GitHub Copilot, and Cursor
- Bidirectional - Convert in any direction (Claude ↔ Gemini ↔ Codex ↔ OpenCode ↔ Copilot ↔ Cursor)
- Safe by Default - Preview changes with dry-run mode before applying
- Chimera Hub - Lossless conversion via virtual agent that preserves all agent-specific settings (details)
- Subcommands -
import,apply,drift,planfor Chimera hub workflow;syncfor direct conversion - Short Command - Use
acsinstead ofagent-command-sync - Selective Sync - Convert specific files or all commands at once
Upgrading from v2? See the Migration Guide.
acs sync -s <source> -d <dest> [options]acs import claude # Import all from Claude
acs import gemini -t commands # Import commands onlyacs drift claude # Preview import changesacs apply gemini # Apply to Gemini
acs apply claude --remove-unsupported # Remove unsupported fieldsacs plan gemini # Preview apply changes| Option | Description |
|---|---|
-s, --src <product> |
Required. Source product: claude, gemini, codex, opencode, copilot, cursor, or chimera |
-d, --dest <product> |
Required. Destination product: claude, gemini, codex, opencode, copilot, cursor, or chimera |
-t, --type <type> |
Content type: commands, skills, or both (default: both) |
-f, --file <filename> |
Convert specific file only (supports .md, .toml extensions) |
-n, --noop |
Preview changes without applying them |
-v, --verbose |
Show detailed debug information |
--claude-dir <path> |
Claude base directory (default: ~/.claude) |
--gemini-dir <path> |
Gemini base directory (default: ~/.gemini) |
--codex-dir <path> |
Codex base directory (default: ~/.codex) |
--opencode-dir <path> |
OpenCode base directory (default: ~/.config/opencode) |
--copilot-dir <path> |
Copilot base directory (default: ~/.copilot) |
--cursor-dir <path> |
Cursor base directory (default: ~/.cursor) |
--chimera-dir <path> |
Chimera base directory (default: ~/.config/acsync) |
--no-overwrite |
Skip existing files in target directory |
--sync-delete |
Delete orphaned files in target directory |
--remove-unsupported |
Remove fields not supported by target format |
# Direct conversion with preview
acs sync -n -s claude -d gemini
# Convert specific file
acs sync -s gemini -d claude -f analyze-code
# Chimera hub workflow
acs import claude # Import Claude → Chimera
acs import gemini # Import Gemini → Chimera (merges)
acs apply claude # Apply Chimera → Claude (with Claude extras)
acs apply gemini # Apply Chimera → Gemini (with Gemini extras)
# Full sync with cleanup
acs sync -s claude -d gemini --sync-delete --remove-unsupported
# Use custom directories
acs sync -s claude -d gemini --claude-dir ~/my-claude --gemini-dir ~/my-gemini
# Show verbose output for debugging
acs sync -s claude -d gemini -v- Claude Code:
~/.claude/commands/*.md - Gemini CLI:
~/.gemini/commands/*.toml - Codex CLI:
~/.codex/prompts/*.md - OpenCode:
~/.config/opencode/commands/*.md - GitHub Copilot:
~/.copilot/prompts/*.prompt.md - Cursor:
~/.cursor/commands/*.md - Chimera:
~/.config/acsync/commands/*.md
- Claude Code:
~/.claude/skills/<skill-name>/SKILL.md - Gemini CLI:
~/.gemini/skills/<skill-name>/SKILL.md - Codex CLI:
~/.codex/skills/<skill-name>/SKILL.md - OpenCode:
~/.config/opencode/skills/<skill-name>/SKILL.md - GitHub Copilot:
~/.copilot/skills/<skill-name>/SKILL.md - Cursor:
~/.cursor/skills/<skill-name>/SKILL.md - Chimera:
~/.config/acsync/skills/<skill-name>/SKILL.md
| Aspect | Commands | Skills |
|---|---|---|
| Structure | Single file (.md, .toml) |
Directory (SKILL.md + support files) |
| Location | ~/.{tool}/commands/ |
~/.{tool}/skills/<name>/ |
| Use Case | Simple prompts | Complex tasks with multiple files |
| Feature | Claude Code | Gemini CLI | Codex CLI | OpenCode | Copilot | Cursor | Conversion Notes |
|---|---|---|---|---|---|---|---|
| File format | Markdown | TOML | Markdown | Markdown | Markdown (.prompt.md) |
Markdown | Automatically converted |
| Content field | Body content | prompt |
Body content | Body content | Body content | Body content | Main command content |
| Description metadata | description |
description |
description |
description |
description |
- | Lost when converting to Cursor (no frontmatter) |
model |
Supported | - | - | Supported | Supported | - | Preserved for Claude/OpenCode/Copilot |
tools (YAML array) |
- | - | - | - | Supported | - | Copilot-specific (passthrough via extras) |
allowed-tools, argument-hint |
Supported | - | - | - | - | - | Claude-specific (use --remove-unsupported) |
| Feature | Claude Code | Gemini CLI | Codex CLI | OpenCode | Copilot | Cursor | Conversion Behavior |
|---|---|---|---|---|---|---|---|
| All arguments | $ARGUMENTS |
{{args}} |
$ARGUMENTS |
$ARGUMENTS |
- | - | Converted between formats |
| Individual arguments | $1 ... $9 |
- | $1 ... $9 |
$1 ... $9 |
- | - | Preserved (not supported in Gemini/Copilot/Cursor) |
| Shell command | !`command` |
!{command} |
- | !`command` |
- | - | Converted between formats |
| File reference | @path/to/file |
@{path/to/file} |
- | @path/to/file |
- | - | Converted between formats |
The placeholders $1 through $9 allow referencing individual command arguments. For example, $1 refers to the first argument, $2 to the second, and so on. This feature is supported in Claude Code, Codex CLI, and OpenCode, but not in Gemini CLI. During conversion, these placeholders are preserved as-is.
File references allow embedding file contents inline within the command. The syntax differs between tools:
- Claude Code / OpenCode uses
@path/to/file.txt - Gemini CLI uses
@{path/to/file.txt} - Codex CLI does not support this feature
During conversion, the syntax is automatically converted between formats. When converting to/from Codex, the file reference syntax is preserved unchanged.
Skills follow the Agent Skills open standard adopted by Claude Code, Gemini CLI, Codex CLI, OpenCode, and Cursor.
Each skill is a directory containing SKILL.md and optional support files:
~/.claude/skills/
└── my-skill/
├── SKILL.md # Main skill definition (required)
├── helper.sh # Support file (optional)
└── config.json # Support file (optional)
All tools use the same SKILL.md format with YAML frontmatter:
---
name: my-skill
description: A helpful skill description
---
Skill instructions go here.
Use $ARGUMENTS for user input.| Field | Claude Code | Gemini CLI | Codex CLI | OpenCode | Copilot | Cursor | Conversion Notes |
|---|---|---|---|---|---|---|---|
name |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Required |
description |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Preserved |
argument-hint |
✓ | - | - | - | ✓ | - | Claude/Copilot |
allowed-tools |
✓ | - | - | - | - | ✓ | Claude/Cursor (agentskills.io) |
model |
✓ | - | - | - | - | - | Claude-specific |
context |
✓ | - | - | - | - | - | Claude-specific (e.g., "fork") |
agent |
✓ | - | - | - | - | - | Claude-specific |
hooks |
✓ | - | - | - | - | - | Claude-specific (before/after/on_error) |
disable-model-invocation |
✓ | - | ✓* | ✓** | ✓ | ✓ | Converted (see below) |
user-invocable / user-invokable |
✓ | - | - | - | ✓*** | ✓ | Converted with spelling normalization |
* Codex uses policy.allow_implicit_invocation in agents/openai.yaml (inverted logic)
** OpenCode uses disable-model-invocation directly in SKILL.md frontmatter
*** Copilot uses user-invokable (with 'k') instead of Claude's user-invocable (with 'c'); automatically normalized during conversion
Codex CLI supports an optional agents/openai.yaml configuration file:
~/.codex/skills/
└── my-skill/
├── SKILL.md
└── agents/
└── openai.yaml # Codex-specific configuration
Example openai.yaml:
interface:
display_name: "My Skill"
short_description: "A skill description"
policy:
allow_implicit_invocation: trueThe policy.allow_implicit_invocation field in Codex is converted to/from Claude's disable-model-invocation with inverted logic:
| Claude Code | Codex CLI (openai.yaml) |
|---|---|
disable-model-invocation: true |
policy.allow_implicit_invocation: false |
disable-model-invocation: false |
policy.allow_implicit_invocation: true |
When converting Claude → Codex with disable-model-invocation set, an agents/openai.yaml file is automatically generated.
Other openai.yaml fields (interface.display_name, interface.short_description) are Codex-specific and not converted.
Support files (scripts, configs, images, etc.) are copied as-is during conversion:
| File Type | Examples | Handling |
|---|---|---|
| Text | .sh, .py, .json, .yaml |
Copied as-is |
| Binary | .png, .jpg, .pdf |
Copied as-is |
| Config | openai.yaml |
Codex-specific, ignored for other targets |
Same as Commands:
| Feature | Claude Code / Codex CLI / OpenCode | Gemini CLI | Copilot | Cursor |
|---|---|---|---|---|
| All arguments | $ARGUMENTS |
{{args}} |
Not supported | Not supported |
| Individual arguments | $1 ... $9 |
Not supported | Not supported | Not supported |
| Shell command | !`command` |
!{command} |
Not supported | Not supported |
| File reference | @path/to/file |
@{path/to/file} |
Not supported | Not supported |
- Slash commands - Claude Docs
- gemini-cli/docs/cli/custom-commands.md at main · google-gemini/gemini-cli
- codex/docs/prompts.md at main · openai/codex
- OpenCode
- Custom instructions for GitHub Copilot
[A]Created (Green) - New files created in target directory[M]Modified (Yellow) - Existing files updated[=]Unchanged (Blue) - File exists and converted content is identical[D]Deleted (Red) - Files removed with--sync-delete[-]Skipped (Gray) - Files skipped with--no-overwrite
- Node.js >= 18.0.0
- npm or compatible package manager
All conversions go through a hub-and-spoke Semantic IR, eliminating the need for pairwise converters between every agent combination:
Source Format → Parser → toIR() → SemanticIR → fromIR() → Target Format
Each agent has a single class implementing all interfaces (AgentConfig, BodyParser, CommandParser, CommandConverter, SkillParser, SkillConverter). Adding a new agent requires only one agent class — not N converters for N existing agents.
interface SemanticIR {
contentType: "command" | "skill";
body: BodySegment[]; // Tokenized body content
semantic: SemanticProperties; // Shared properties (description, name, etc.)
extras: Record<string, unknown>; // Agent-specific passthrough properties
meta: SemanticMeta; // Conversion context (source path, type, etc.)
}semantic— Properties with shared meaning across agents (e.g.,description). Agent classes map between agent-specific field names and semantic properties.extras— All other properties pass through unchanged. Agent-specific fields (e.g., Claude'sallowed-tools) are preserved for round-trip fidelity and can be stripped with--remove-unsupported.body— Tokenized asBodySegment[](an array of plain strings and semantic placeholders), so placeholder syntax conversion (e.g.,$ARGUMENTS↔{{args}}) happens automatically within each agent'scommandToIR()/commandFromIR().
Body content is parsed into an array of BodySegment elements — plain strings interleaved with typed ContentPlaceholder objects:
type ContentPlaceholder =
| { type: "arguments" } // $ARGUMENTS / {{args}}
| { type: "individual-argument"; index: 1-9 } // $1-$9
| { type: "shell-command"; command: string } // !`cmd` / !{cmd}
| { type: "file-reference"; path: string }; // @path / @{path}Each agent defines its own body patterns and serializers colocated within its agent class file (src/agents/claude.ts, src/agents/gemini.ts, etc.). Claude, Codex, and OpenCode share the same placeholder syntax via a common module (src/agents/_claude-syntax-body-patterns.ts), while Codex marks unsupported placeholder types (shell-command, file-reference) for best-effort output. A type-driven serializer registry (PlaceholderSerializers) ensures compile-time exhaustiveness — adding a new placeholder type causes a type error until every agent implements it.
src/
├── agents/ # Agent classes (one file per agent: parsing, conversion, body handling)
├── types/ # Type definitions (SemanticIR, BodySegment, agent formats)
├── utils/ # Shared utilities (file ops, validation, body parsing engine)
└── cli/ # CLI entry point and sync orchestration
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint and format code
npm run lint
npm run format
# Type check
npm run lint:tsc
# Development mode (watch)
npm run dev# Check package contents
npm pack --dry-run
# Update patch version (1.0.0 → 1.0.1)
npm version patch
# Update minor version (1.0.0 → 1.1.0)
npm version minor
# Update major version (1.0.0 → 2.0.0)
npm version major
# Publish a package
npm publishMIT

