Skip to content

Agent Capability matrix

What works, what’s lossy, and what’s deferred — per agent, per component. This is the honest-expectations page for the beta. If a translation is lossy or skipped, agentsync says so at apply time in the translation report; nothing is dropped silently.

Legend

SymbolMeaning
native — full fidelity; the agent has the concept directly
projected — translated with documented, reported loss
skipped — no honest translation; logged in the apply report
not yet implemented (adapter is registered but no-op)

AgentStatus (beta)Notes
Claude Code✅ AdapterMCP, memory, skills, subagents, commands, and hooks. Canonical LSP servers are skipped because Claude Code only reads LSP servers from plugin manifests, not settings.json; installed plugins + marketplaces are captured by import (read from enabledPlugins / extraKnownMarketplaces); on apply, each plugin’s components project to Claude’s native paths and the enablement keys themselves are deliberately left untouched (PluginIngester is read-only — see the shared invariant below).
OpenCode✅ Adapter (some components projected/skipped)MCP, memory, skills, subagents, commands. Hooks and LSP are skipped with a warning. No native plugin/marketplace concept, so nothing for plugin import to capture; it still receives plugin-projected components (skills, MCP, …) on apply.
Codex CLI✅ Adapter (some components projected)MCP, memory, skills, subagents, slash commands, and hooks. MCP servers and hooks both merge into the TOML ~/.codex/config.toml (as [mcp_servers.*] / inline [hooks.*] tables — Codex’s documented equivalent to a separate hooks.json), so config.toml is the adapter’s single key-merge file and the user’s other keys (model, sandbox_mode, [plugins.*], …) are preserved; subagents project to Codex’s TOML agent format and slash commands to global-only custom prompts (both ◐). Codex has a native plugin system1 with enable-state in ~/.codex/config.toml as [plugins."<name>@<source>"] enabled = …, so the adapter implements PluginIngester: import codex:plugin captures that enable-state. The render never re-emits those tables (same invariant as Claude). Codex records no marketplace fetch source in a documented config location, so each plugin’s marketplace is resolved from agentsync’s own registered marketplaces (agentsync marketplace add <source> first), warning + skipping any it can’t — exactly how Claude’s auto-available built-in marketplace is handled.
Cursor✅ Adapter (some components projected)MCP, memory, skills, subagents, slash commands, and hooks. MCP lands in .cursor/mcp.json (the same mcpServers shape as Claude — full fidelity) and hooks in .cursor/hooks.json (Claude’s lifecycle events remapped to Cursor’s camelCase names; the required top-level version is asserted when missing, never overwriting a user-set value; events with no Cursor equivalent are dropped with a report). Memory projects to the repo-root AGENTS.md at project scope only — Cursor keeps user-level rules in app-local storage, so user-scope memory has no filesystem target (reported as a skip). Subagents project to .cursor/agents/<name>.md (Claude’s tools/color have no Cursor field and drop); slash commands to .cursor/commands/<name>.md (plain markdown — frontmatter drops). Only LSP is unsupported (Cursor has no LSP concept). Cursor has a native plugin system2, but where it records local enable-state is undocumented, so the adapter implements no PluginIngester yet (plugin discovery on import is deferred); it still receives plugin-projected components (skills, MCP, …) on apply like any agent.
Gemini CLI✅ Adapter (some components projected)MCP, memory, subagents, slash commands, and hooks. MCP and hooks both merge into .gemini/settings.json (MCP mcpServers with Gemini’s url/httpUrl transport split; hooks under hooks, the same nested shape as Claude, with events remapped to Gemini’s BeforeTool/AfterTool/… and unmapped ones dropped) — so settings.json is the adapter’s single key-merge file and the user’s other keys (theme, model, …) are preserved. Gemini reads settings.json as JSONC, so the merge is JSONC-tolerant (merge-jsonc-keys): a commented file’s foreign keys are preserved, with comments stripped on the first agentsync write (documented in Known limits). On import, a hook event agentsync can’t fully represent — a Gemini-only event (BeforeModel, …) or a handler with unmodeled fields (timeout, name, sequential) — is left uncaptured with a warning, so a later apply never owns an array it would lossily rewrite. Memory projects to GEMINI.md (~/.gemini/GEMINI.md at user scope, repo-root GEMINI.md at project scope — full fidelity). Slash commands become .gemini/commands/<name>.toml (description + prompt; argument-hint/allowed-tools drop), subagents .gemini/agents/<name>.md (Claude’s tools vocabulary differs from Gemini’s, so it and color drop). Skills (Gemini uses extensions, not Agent Skills) and LSP have no Gemini concept and are skipped. Gemini has no native plugin enable-state agentsync models, so there is no PluginIngester; it still receives plugin-projected components on apply.
Continue✅ Adapter (some components projected)MCP, memory, and slash commands — projected as Continue “blocks” (one file per item under .continue/, so the adapter owns no shared key-merge file). MCP servers each become a .continue/mcpServers/<id>.yaml block (stdio command/args/env; remote streamable-http/sse + url with auth headers under requestOptions.headers; other requestOptions subkeys a native block carries — timeout, verifySsl, … — are preserved through import/apply via Extra passthrough — full fidelity). Memory projects to .continue/rules/agentsync.md, a frontmatter-less rule Continue always applies (so it behaves as persistent memory; byte-clean round-trip). Slash commands become .continue/prompts/<name>.md prompt blocks (name + description + invokable; argument-hint/allowed-tools drop). On import, only prompts with invokable: true are captured as slash commands (a plain prompt is left alone, with a warning — re-applying it would otherwise force it invokable). Skills, hooks, and LSP have no Continue concept, and Continue’s “agents” are top-level assistants rather than per-file subagents, so all four are skipped with a report. No PluginIngester (Continue composes blocks from its Hub + local files); it still receives plugin-projected components on apply.
Windsurf✅ Adapter (scope-asymmetric MCP)MCP, memory, and slash commands. MCP is global-only (~/.codeium/windsurf/mcp_config.json, JSON mcpServers; stdio command/args/env, remote serverUrl + headers), so it renders at user scope and is skipped (reported) at project scope. Memory renders at both scopes: project → .windsurf/rules/agentsync.md carrying the documented trigger: always_on activation frontmatter (workspace rules declare their trigger in frontmatter; ingest strips it, so the canonical body round-trips byte-clean); user → the single global rules file ~/.codeium/windsurf/memories/global_rules.md (always-on, frontmatter-less, verbatim; Windsurf documents a 6,000-character limit it enforces itself). Commands render at both scopes as plain-markdown workflows invoked as /<name>: project .windsurf/workflows/, user ~/.codeium/windsurf/global_workflows/ (command frontmatter drops). Upstream now prefers `.devin/rules
Roo Code✅ Adapter (some components projected)MCP, memory, and slash commands — clean filesystem .roo/ paths (rulesync and ruler converged on these). MCP → .roo/mcp.json (project-level, mcpServers with explicit type: streamable-http/sse for remote + url/headers; merge-by-server-name preserves foreign servers). Roo’s global MCP lives in VS Code globalStorage (OS/editor-specific), which agentsync intentionally does not target — so user-scope MCP is reported as a skip. Memory → .roo/rules/agentsync.md (plain-markdown always-applied rule) and commands → .roo/commands/<name>.md (markdown + frontmatter — Roo keeps both description and argument-hint; only allowed-tools drops), both at user and project scope (~/.roo/ + <repo>/.roo/). Skills, hooks, and LSP have no Roo concept, and Roo’s “custom modes” are not per-file subagents, so all four are skipped. No PluginIngester; it still receives plugin-projected components on apply.
Cline✅ Adapter (scope-asymmetric)MCP, memory, and slash commands. MCP → ~/.cline/mcp.json at user scope — the Cline CLI’s clean config (mcpServers, transport inferred: stdio command/args/env, remote url + headers). Cline has no project MCP file, and its VS Code-extension MCP lives in OS/editor-specific globalStorage no config-sync tool writes, so project-scope MCP is reported as a skip. Memory → .clinerules/agentsync.md (plain markdown — Cline concatenates .clinerules/) and commands → .clinerules/workflows/<name>.md (plain markdown workflows invoked as /<name>.md; command frontmatter drops), both at project scope (Cline’s global rules and workflows live in ~/Documents/Cline/, a non-XDG app path agentsync deliberately does not target). Skills, subagents, hooks, and LSP have no Cline concept and are skipped. No PluginIngester; it still receives plugin-projected components on apply.
Breadth tier (22 agents)✅ Generic adapter (memory + MCP + skills)A long tail of agents supported by one data-driven generic adaptermemory (rules file) for all, MCP where the agent reads a JSON server-map agentsync can express (15 of 22), and Agent Skills where the agent natively scans a SKILL.md directory (18 of 22). Each is a verified spec, not a hand-written package; see the Breadth tier table for per-agent coverage. They flow through the normal apply/import pipeline (drift, secrets, capture), unlike a one-way rules dump.

The rule is the same for every adapter, present and future:

import reads the agent’s plugin enable-state for discovery; apply never writes it back. Apply fans out the plugin’s components, not the plugin itself.

agentsync’s Adapter interface has a Render (canonical → native components) and the optional PluginIngester extension is read-only (IngestPlugins — native plugin enable-state → canonical). There is no RenderPlugins. Each adapter handles the asymmetry the same way:

Adapterreads on import (PluginIngester)writes on apply (Render)
Claudesettings.json#/enabledPlugins, …#/extraKnownMarketplacescomponents only (skills, MCP, commands, …); enable-state keys left untouched
Codex~/.codex/config.toml [plugins."<name>@<source>"]components only (MCP, hooks, memory, skills, …); [plugins.*] left untouched
OpenCode— (no native plugin concept)components only (receives plugin-projected components like any user-authored component)
Cursor— (PluginIngester deferred; native enable-state location undocumented)components only (skills, MCP, commands, …)
Gemini— (no native plugin enable-state agentsync models; uses extensions)components only (MCP, memory, commands, subagents, hooks)
Continue— (no native plugin enable-state agentsync models; composes Hub + local blocks)components only (MCP, memory, commands)
Windsurf— (no native plugin enable-state agentsync models)components only (MCP, memory, commands)
Roo Code— (no native plugin enable-state agentsync models)components only (MCP, memory, commands)
Cline— (no native plugin enable-state agentsync models)components only (MCP, memory, commands)

Once a plugin’s components materialise at native paths (~/.claude/skills/<name>/, mcpServers in the agent’s config, ~/.codex/AGENTS.md, …), the consumer agent reads them through the same code path it uses for hand-authored components. Plugin attribution is purely agentsync’s internal bookkeeping. The write-back is omitted on purpose: it would pick a fight with the agent’s own /plugin disable UI (ping-pong on every apply), blur ownership between agentsync and the agent’s plugin manager, and double-install with the agent’s own per-plugin install dir. See architecture.md § PluginIngester (read-only).


Component support across agents.

ComponentClaudeOpenCodeCodexCursorGeminiContinueWindsurfRooCline
MCP server~/.claude.json (user) · .mcp.json (project)opencode.jsonconfig.toml.cursor/mcp.json.gemini/settings.json.continue/mcpServers/mcp_config.json (user-only).roo/mcp.json (project-only)~/.cline/mcp.json (user-only)
MemoryCLAUDE.mdAGENTS.md~/.codex/AGENTS.mdAGENTS.mdGEMINI.md.continue/rules/.windsurf/rules/ + global_rules.md.roo/rules/.clinerules/ (project-only)
Skill~/.claude/skills/X/ (dir)✓ shared .claude/skills/~/.agents/skills/.cursor/skills/✗ no skills concept✗ no skills concept✗ no skills concept✗ no skills concept✗ no skills concept
Subagent~/.claude/agents/X.md◐ frontmatter munged◐ markdown → TOML.cursor/agents/.gemini/agents/✗ top-level assistants only✗ no subagent concept✗ custom modes only✗ no subagent concept
Slash command~/.claude/commands/X.mdargument-hint dropped~/.codex/prompts/.cursor/commands/.gemini/commands/ (TOML).continue/prompts/.windsurf/workflows/ + global_workflows/.roo/commands/ (allowed-tools dropped).clinerules/workflows/ (project-only)
Hook✓ JSON in settings✗ skip (JS/TS plugins)config.toml [hooks.*].cursor/hooks.jsonsettings.json hooks✗ no hook concept✗ no hook concept✗ no hook concept✗ no hook concept
LSP server✗ skip (Claude loads LSP only from plugin manifests)✗ skip (deferred)✗ no LSP concept✗ no LSP config✗ no LSP concept✗ no LSP concept✗ no LSP concept✗ no LSP concept✗ no LSP concept

The ◐/✗ cells are features, not bugs: agentsync refuses to invent a translation that would mislead you. Every ◐ and ✗ is printed in the apply report and queryable with agentsync explain <plugin> --json.

The nine adapters above are deep, agent-specific packages. Beyond them, agentsync covers a long tail of agents through a single data-driven generic adapter (internal/adapter/generic): each agent is a verified Spec — a row in a table — rather than a hand-written package. The generic tier deliberately projects memory (the agent’s rules/instructions file), MCP where the agent reads a JSON server-map agentsync can express, and Agent Skills where the agent natively scans a SKILL.md directory; every other component is reported as a skip. Breadth agents run through the same apply/import pipeline as the deep ones, so they get drift detection, secret resolution, and capture — not a one-way rules dump.

MCP coverage (15 of 22). The MCP merge is JSONC-tolerant (hujson), so a commented settings file (Zed, Copilot’s .vscode/mcp.json, Amp) is parsed and its foreign keys and values preserved rather than clobbered. The comments themselves are NOT preserved: the file is re-emitted as plain JSON on the first agentsync write, with keys re-sorted (the original is backed up) — for Zed that file is the user’s whole editor settings.json, so expect the reformat (see Known limits). Per-agent dialect knobs cover the variance: top-level key (mcpServers / servers / mcp / context_servers / the flat namespaced amp.mcpServers), transport field (type / transport / inferred), stdio value (stdio / local), and remote URL key (url / httpUrl / serverUrl). The seven memory-only agents are the ones whose MCP is genuinely not a JSON server-map — array (Trae), YAML (Goose), TOML (OpenHands, Mistral), IDE app-storage (JetBrains, AugmentCode), or cloud-dashboard (Jules) — where the generic engine refuses to invent a shape and reports a skip.

Skills coverage (18 of 22). Agent Skills are the open agentskills.io spec — a skill is a directory (SKILL.md frontmatter + body, plus bundled scripts//references//assets/). Unlike MCP, the on-disk format is uniform across agents (there is no dialect to model); only the scanned directory varies, so the breadth tier reuses the same projection the deep adapters use (claude.SkillFileOps) — bundled files and executable bits survive byte-for-byte. Most agents read the cross-vendor .agents/skills/ convention (the same directory Codex targets, so the render pipeline dedupes the byte-identical ops rather than fighting over the path); a few scan only their own .<agent>/skills/ (Qwen, Junie, Kiro, Factory, Copilot’s .github/skills/). The four without skills are the ones that don’t natively scan a SKILL.md directory: Jules and Firebase Studio publish skills for other agents, Amazon Q consumes skills only through an MCP server (a different component), and OpenHands loads skills programmatically with no auto-scanned directory — each leaves Skills empty and reports a skip. Skills carry no secrets, so the projection is entirely off the secret-resolution path.

Every path below was cross-referenced against the agent’s upstream docs and prior-art config-sync tools (ruler, rulesync) before inclusion. A scope or component with no verified target is left out (and reported as a skip), never guessed.

AgentMemory (rules)MCPSkills (SKILL.md dir)
ampAGENTS.md · ~/.config/amp/AGENTS.md~/.config/amp/settings.json (namespaced amp.mcpServers key).agents/skills/ · ~/.config/agents/skills/
goose.goosehints✗ YAML ~/.config/goose/config.yaml.agents/skills/ (+ user)
qwenQWEN.md · ~/.qwen/QWEN.md.qwen/settings.json (dual-URL split: httpUrl = streamable HTTP, url = SSE).qwen/skills/ (+ user)
warpWARP.md.warp/.mcp.json · ~/.warp/.mcp.json.agents/skills/ (+ user)
julesAGENTS.md✗ dashboard-only (cloud)✗ publishes skills for other agents
junieAGENTS.md (project; JetBrains documents no global guidelines file).junie/mcp/mcp.json (+ user).junie/skills/ (+ user)
openhandsAGENTS.md✗ TOML [mcp] arrays✗ programmatic load (no auto-scanned dir)
amazonq.amazonq/rules/.amazonq/mcp.json · ~/.aws/amazonq/mcp.json✗ skills only via an MCP server
zedAGENTS.md · ~/.config/zed/AGENTS.md✓ settings.json context_servers.agents/skills/ (+ user)
kilocode.kilocode/rules/.kilocode/mcp.json (project).agents/skills/ · ~/.kilo/skills/
kiro.kiro/steering/ (+ user).kiro/settings/mcp.json (+ user).kiro/skills/ (+ user)
trae.trae/rules/project_rules.md✗ non-standard array shape.agents/skills/ (project only)
jetbrains.aiassistant/rules/✗ IDE app-storage.agents/skills/ (project; via configured agent)
firebase.idx/airules.md.idx/mcp.json (project)✗ publishes skills for other agents
antigravityAGENTS.md~/.gemini/config/mcp_config.json (remote key serverUrl; the shared IDE+CLI path is codelab-sourced — older installs read ~/.gemini/antigravity-cli/mcp_config.json, where this write is a no-op; re-verify when Antigravity’s docs firm up. Lives inside ~/.gemini/, the deep Gemini adapter’s directory, but a different file — no collision).agents/skills/ (project; global path disputed, omitted)
augmentcode.augment/rules/ (+ user)✗ IDE app-storage.agents/skills/ (+ user)
copilot.github/copilot-instructions.md.vscode/mcp.json (servers key, type).github/skills/ · ~/.copilot/skills/
copilot-cliAGENTS.md~/.copilot/mcp-config.json (type, stdio=“local”).agents/skills/ (+ user)
crushAGENTS.md✓ crush.json mcp key (+ user).agents/skills/ · ~/.config/crush/skills/
factoryAGENTS.md.factory/mcp.json · ~/.factory/mcp.json (type).factory/skills/ (+ user)
piAGENTS.md · ~/.pi/agent/AGENTS.md~/.pi/agent/mcp.json.agents/skills/ (+ user)
mistralAGENTS.md✗ TOML .vibe/config.toml.agents/skills/ · ~/.vibe/skills/

Deliberate exclusions: Aider (no native MCP; memory only via an .aider.conf.yml read: pointer — needs a content+config-pointer adapter, out of the generic tier) and Firebender (single-sourced JSON-manifest model) are not included pending a faithful implementation. Replit/Rovo Dev are likewise deferred (cloud / config-string memory).

Every apply and explain ends with a coverage report — per plugin, per agent — using the same three marks (verify does not print one; it only schema-lints the source and validates secrets):

plugin: atlassian@anthropic
claude ✓ full (1 mcp, 5 commands)
opencode ◐ partial (1 mcp; 5 commands → projected)
  • ✓ native — the component landed with full fidelity.
  • ◐ projected — it landed, but with the documented loss below (e.g. an OpenCode slash command drops its argument-hint).
  • ✗ skipped — no honest translation exists, so nothing was written; the skip is logged, never silent.

Every projected (◐) cell above is a deliberate, reported translation. Here’s what doesn’t carry over.

Note that MCP/LSP capture is not field-lossy: native server fields agentsync doesn’t model (e.g. timeout, disabled, cwd) are preserved verbatim through a passthrough [server.extra] table on import/reconcile and re-rendered on apply, rather than dropped. (Extra is verbatim only — ${secret:…} there is written literally, never resolved.)

OpenCode

  • Subagent — Claude’s tools allowlist is remapped onto OpenCode’s permission model (approximate), and Claude frontmatter keys OpenCode doesn’t recognize are dropped.
  • Slash command — Claude’s argument-hint has no OpenCode field and is dropped; there’s no command-level allowed-tools (scoping is per-agent instead).

Codex

  • Subagent — Codex custom agents are TOML, not markdown: the prose body becomes developer_instructions, and the name (required by Codex), description, and model frontmatter carry over. There is no per-agent tools allowlist (tool scoping is only expressible via [mcp_servers] / skill toggles), so tools (and color) are dropped with a reported skip. Codex-only agent keys agentsync has no canonical source for (model_reasoning_effort, sandbox_mode, nickname_candidates, …) are simply not emitted.
  • Slash command — maps to Codex custom prompts (~/.codex/prompts/*.md), which do preserve description + argument-hint, but they’re global-only, so a project-scope command has no target and is skipped; they also can’t be namespaced in subdirectories, and the feature is deprecated in favor of skills.
  • Hook — Codex mirrors Claude’s declarative hook schema as inline [hooks.*] tables in ~/.codex/config.toml (Codex reads hooks from either a hooks.json or inline [hooks] tables; agentsync uses the config.toml form so the adapter has a single key-merge file), but recognizes a fixed set of lifecycle events (SessionStart, SubagentStart, PreToolUse, PermissionRequest, PostToolUse, Pre/PostCompact, UserPromptSubmit, SubagentStop, Stop); Claude events outside that set (e.g. SessionEnd, Notification) have no target and drop.

Cursor

  • Memory — project memory lands as AGENTS.md, but Cursor keeps user-level rules in app-local storage (not the filesystem), so user-scope memory has no projection target (it is reported as a skip).
  • Subagent — markdown under .cursor/agents/. Cursor recognizes name/description/model/readonly/is_background; Claude’s tools allowlist and color have no Cursor field and are dropped with a report.
  • Slash command — Cursor commands (.cursor/commands/*.md) are plain markdown with no frontmatter, so argument-hint, description, and allowed-tools are all dropped — only the prompt body survives.
  • Hook — Cursor uses a declarative .cursor/hooks.json, but with its own camelCase event names and a flat entry shape, so Claude’s events are remapped (PreToolUsepreToolUse, UserPromptSubmitbeforeSubmitPrompt, …) and any with no Cursor equivalent (e.g. Notification, PostCompact) are dropped with a report. The required top-level version is asserted if missing and a user-set value is preserved. agentsync models only Cursor’s command hooks and only the command/matcher/type entry fields; on import, a Cursor-native event agentsync can’t render (afterFileEdit, beforeShellExecution, …) — or an event containing an entry it can’t fully represent (a prompt-type hook, or fields like timeout/failClosed) — is left uncaptured with a warning, so a later apply never takes ownership of an array it would lossily rewrite.

Gemini CLI

  • Subagent — markdown under .gemini/agents/. Gemini recognizes name/description/model (plus Gemini-only kind/temperature/max_turns/… agentsync doesn’t model); Claude’s tools list uses a different tool vocabulary (read_file/grep_search, not Read/Grep), so copying it verbatim would name tools Gemini doesn’t have — it and color are dropped with a report. name is defaulted to the filename when absent (Gemini requires it).
  • Slash command — Gemini commands are TOML (.gemini/commands/*.toml) with description + prompt. The body becomes prompt and description carries over; argument-hint/allowed-tools have no Gemini field and drop. Gemini’s argument placeholder is {{args}} (not Claude’s $ARGUMENTS/$1); the body is written verbatim, so placeholder syntax is not auto-translated.
  • Hook — Gemini hooks live in settings.json under hooks in the same nested shape as Claude, so only the event name is remapped (PreToolUseBeforeTool, PostToolUseAfterTool, UserPromptSubmitBeforeAgent, StopAfterAgent, PreCompactPreCompress); events with no Gemini equivalent (SubagentStart/ SubagentStop/PostCompact/PermissionRequest) are dropped with a report.

Continue

  • Slash command — Continue prompt blocks (.continue/prompts/*.md) carry a name + optional description + invokable; the body becomes the prompt. argument-hint/allowed-tools have no Continue field and drop.
  • Subagent / Hook / Skill / LSP — Continue has no per-file subagent (its “agents” are top-level assistants), no declarative hook concept, no Agent Skills (it uses Hub blocks/extensions), and no LSP config, so each is skipped with a report rather than given a misleading translation.

Windsurf

  • Scope split — Windsurf’s MCP config is global-only (~/.codeium/windsurf/mcp_config.json): MCP renders at user scope only (skipped + reported at project scope). Memory and commands render at both scopes (project .windsurf/ tree; user ~/.codeium/windsurf/).
  • Memory — at project scope, .windsurf/rules/agentsync.md with the documented trigger: always_on activation frontmatter (workspace rules declare their trigger in frontmatter — a frontmatter-less rule’s activation is undefined); ingest strips exactly that block, so the canonical body round-trips byte-clean. At user scope, the single global rules file ~/.codeium/windsurf/memories/global_rules.md — always-on and frontmatter-less, written verbatim. It is whole-file owned like Claude’s ~/.claude/CLAUDE.md (a pre-existing hand-authored copy is backed up on first apply), and Windsurf enforces its documented 6,000-character limit itself.
  • Slash command — Windsurf workflows are plain markdown invoked as /<name> (project .windsurf/workflows/*.md, user ~/.codeium/windsurf/global_workflows/*.md), so command description/ argument-hint/allowed-tools frontmatter drops — only the body survives.
  • MCP remote — Windsurf does not distinguish SSE vs streamable-HTTP in the config (just serverUrl), so a canonical sse server normalizes to http if later captured back via import/reconcile.

Roo Code

  • MCP scope.roo/mcp.json is project-level; Roo’s global MCP lives in VS Code globalStorage (OS/editor-specific), which agentsync does not target, so user-scope MCP is reported as a skip. (rulesync and ruler make the same call.)
  • Slash command.roo/commands/*.md keep description AND argument-hint (Roo supports both); only allowed-tools (and any other unmodeled key) drops.
  • Subagent / Hook / Skill / LSP — Roo’s “custom modes” are not per-file subagents, and Roo has no hook, Agent-Skills, or LSP concept, so each is skipped with a report.

Cline

  • Scope split — Cline has no project MCP file (its VS Code-extension MCP is OS/editor-specific globalStorage no tool writes), but its CLI reads a clean ~/.cline/mcp.json, so MCP renders at user scope (skipped + reported at project scope). Memory + commands render at project scope (.clinerules/); Cline’s global rules live in ~/Documents/Cline/, a non-XDG app path agentsync does not target, so user-scope memory/commands are skipped + reported.
  • Memory — a plain .clinerules/agentsync.md rule (Cline concatenates .clinerules/ markdown), byte-clean round-trip.
  • Slash command — Cline workflows (.clinerules/workflows/*.md) are plain markdown invoked as /<name>, so command frontmatter drops — only the body survives.
  • MCP remote — Cline infers transport from keys (no type), so a canonical sse server normalizes to http if later captured back via import/reconcile.
  • Hooks — OpenCode hooks are JS/TS plugins that subscribe to events, not declarative shell commands like Claude’s. There is no mechanical translation; hand-author a small plugin if you need a hook on OpenCode.
  • LSP — OpenCode does have a native lsp config, but agentsync defers projecting LSP servers beyond Claude to a later release; today you’ll see lsp server X skipped in the report on non-Claude agents.

OpenCode’s native MCP schema differs from the canonical model, so the adapter translates rather than copying fields verbatim:

  • transport — canonical type = "stdio" → OpenCode "type": "local"; "http"/"sse""type": "remote". OpenCode has no separate SSE transport, so a sse server normalizes to http if it is later captured back via import/reconcile (an apply-only flow is unaffected).
  • command — canonical command + args are flattened into OpenCode’s single command string array (["npx", "-y", "pkg"]), and split back on ingest.
  • environment — canonical env is written under OpenCode’s environment key (not env).
  • remoteurl and headers carry through unchanged.

Full-fidelity projections (✓ with a transform)

Section titled “Full-fidelity projections (✓ with a transform)”

A few ✓ cells still change shape on the way out — same content, no loss:

  • Codex MCP — Claude’s JSON mcpServers become TOML [mcp_servers.X] (stdio and streamable-HTTP both representable).
  • Cursor MCP.cursor/mcp.json uses the same mcpServers shape as Claude, down to ${env:…} references.
  • Gemini MCP.gemini/settings.json mcpServers: stdio keeps command/args/env; a remote server uses Gemini’s transport split — url for SSE, httpUrl for HTTP streaming — both round-tripping the canonical type.
  • Continue MCP — one .continue/mcpServers/<id>.yaml block per server: stdio keeps command/args/env; a remote server uses Continue’s streamable-http/sse type + url, with auth headers under requestOptions.headers.
  • Continue memory — the body lands as .continue/rules/agentsync.md, a frontmatter-less rule Continue always applies (byte-clean round-trip).
  • Windsurf MCP~/.codeium/windsurf/mcp_config.json mcpServers: stdio command/args/env; remote serverUrl + headers.
  • Roo MCP.roo/mcp.json mcpServers: stdio command/args/env; remote explicit type: streamable-http/sse + url + headers (merge-by-server-name preserves the user’s own servers).
  • Roo memory — the body lands as .roo/rules/agentsync.md, a plain rule Roo applies recursively (byte-clean round-trip), at user or project scope.
  • Cline MCP — the Cline CLI’s ~/.cline/mcp.json mcpServers: stdio command/args/env; remote url + headers (transport inferred, no type key).
  • Codex & Gemini memory — the same markdown lands at ~/.codex/AGENTS.md / ~/.gemini/GEMINI.md (repo-root GEMINI.md at project scope).
  • Skills (Codex, Cursor & 18 breadth-tier agents) — the same skill directory per the Agent Skills spec: SKILL.md (name + description) plus any bundled scripts//references//assets/ and nested files, all carried verbatim (binary included, executable bit preserved) on apply, import, and reconcile — agentsync is not lossy for anything but the directory itself. Removing a skill (or one bundled file) from the source reclaims it from each destination on the next apply (drifted files backed up first; empty dirs pruned). Codex installs them under ~/.agents/skills/ (enabled by default — no feature flag), Cursor under .cursor/skills/, and both also read the shared .claude/skills/. The breadth tier projects the identical directory (via the shared claude.SkillFileOps) to each agent’s verified skills path — most to the cross-vendor .agents/skills/, which dedupes byte-for-byte against Codex; see the Breadth tier table for the per-agent path.

You control fan-out explicitly:

  • agents = ["claude", "opencode"] on an MCP server or plugin entry → fan out only to those agents.

(A per-component [plugin.overrides.<agent>] skip was specced but is not wired in v1 — the projector does not consult it. Use the agents allowlist.)


These are documented trade-offs, not regressions. The authoritative list lives in the README; the highlights:

  • Comment preservation — comments in mcp/*.toml, in opencode.json, in Gemini’s .gemini/settings.json, in the breadth tier’s JSONC settings files (Zed/Amp settings.json, Copilot .vscode/mcp.json), and in Codex’s ~/.codex/config.toml are not preserved across a write-back/import round-trip; the JSONC files are re-emitted as plain JSON (foreign keys preserved, comments stripped, original backed up).
  • Owned-key hand-edits — if you hand-edit an agentsync-owned key in a shared file, the next apply overwrites it with no backup (agentsync considers it its own). Run agentsync reconcile first to capture the edit.
  • Insecure sourceshttp:// and git:// plugin/marketplace sources are rejected by default (MITM protection); override with AGENTSYNC_ALLOW_INSECURE_URLS=1.
  • Symlinked destinations are rejected by default; override with AGENTSYNC_ALLOW_SYMLINK_DEST=1.
  • Planned / deferred: Aider and Firebender (see Breadth tier § “Deliberate exclusions”).

See the user guide to put this into practice.

  1. Codex plugin system: developers.openai.com/codex/plugins. Enable-state lives in ~/.codex/config.toml under [plugins."<name>@<source>"] tables (an enabled bool) — the same name@source shape as Claude’s enabledPlugins, so a future Codex PluginIngester parses those tables (plus its marketplace sources) into the same NativeMarketplace / NativePlugin descriptors import already consumes.

  2. Cursor plugin system: cursor.com/docs/reference/plugins. Plugins bundle rules, skills (SKILL.md), agents, commands, hooks, and MCP servers; the manifest is .cursor-plugin/plugin.json and multi-plugin repos use .cursor-plugin/marketplace.json — nearly identical to Claude’s .claude-plugin/*, so agentsync’s projection layer largely transfers. Not yet documented: where Cursor records which plugins are installed/enabled locally (the enabledPlugins-equivalent a PluginIngester would read); given Cursor keeps user rules in app-local storage, this may not be a plain config file. The Cursor adapter therefore ships without a PluginIngester (plugin discovery on import is deferred until that location is documented); it still fans out plugin components on apply like every other adapter.