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
| Symbol | Meaning |
|---|---|
| ✓ | 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) |
Agent status
Section titled “Agent status”| Agent | Status (beta) | Notes |
|---|---|---|
| Claude Code | ✅ Adapter | MCP, 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 adapter — memory (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. |
Plugin import/apply: the shared invariant
Section titled “Plugin import/apply: the shared invariant”The rule is the same for every adapter, present and future:
importreads the agent’s plugin enable-state for discovery;applynever 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:
| Adapter | reads on import (PluginIngester) | writes on apply (Render) |
|---|---|---|
| Claude | settings.json#/enabledPlugins, …#/extraKnownMarketplaces | components 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 × agent
Section titled “Component × agent”Component support across agents.
| Component | Claude | OpenCode | Codex | Cursor | Gemini | Continue | Windsurf | Roo | Cline |
|---|---|---|---|---|---|---|---|---|---|
| MCP server | ✓ ~/.claude.json (user) · .mcp.json (project) | ✓ opencode.json | ✓ config.toml | ✓ .cursor/mcp.json | ✓ .gemini/settings.json | ✓ .continue/mcpServers/ | ✓ mcp_config.json (user-only) | ✓ .roo/mcp.json (project-only) | ✓ ~/.cline/mcp.json (user-only) |
| Memory | ✓ CLAUDE.md | ✓ AGENTS.md | ✓ ~/.codex/AGENTS.md | ◐ AGENTS.md | ✓ GEMINI.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.md | ◐ argument-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.json | ◐ settings.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.
Breadth tier
Section titled “Breadth tier”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.
| Agent | Memory (rules) | MCP | Skills (SKILL.md dir) |
|---|---|---|---|
| amp | AGENTS.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) |
| qwen | QWEN.md · ~/.qwen/QWEN.md | ✓ .qwen/settings.json (dual-URL split: httpUrl = streamable HTTP, url = SSE) | ✓ .qwen/skills/ (+ user) |
| warp | WARP.md | ✓ .warp/.mcp.json · ~/.warp/.mcp.json | ✓ .agents/skills/ (+ user) |
| jules | AGENTS.md | ✗ dashboard-only (cloud) | ✗ publishes skills for other agents |
| junie | AGENTS.md (project; JetBrains documents no global guidelines file) | ✓ .junie/mcp/mcp.json (+ user) | ✓ .junie/skills/ (+ user) |
| openhands | AGENTS.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 |
| zed | AGENTS.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 |
| antigravity | AGENTS.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-cli | AGENTS.md | ✓ ~/.copilot/mcp-config.json (type, stdio=“local”) | ✓ .agents/skills/ (+ user) |
| crush | AGENTS.md | ✓ crush.json mcp key (+ user) | ✓ .agents/skills/ · ~/.config/crush/skills/ |
| factory | AGENTS.md | ✓ .factory/mcp.json · ~/.factory/mcp.json (type) | ✓ .factory/skills/ (+ user) |
| pi | AGENTS.md · ~/.pi/agent/AGENTS.md | ✓ ~/.pi/agent/mcp.json | ✓ .agents/skills/ (+ user) |
| mistral | AGENTS.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).
Reading the report
Section titled “Reading the report”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.
What each ◐ loses
Section titled “What each ◐ loses”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
toolsallowlist is remapped onto OpenCode’spermissionmodel (approximate), and Claude frontmatter keys OpenCode doesn’t recognize are dropped. - Slash command — Claude’s
argument-hinthas no OpenCode field and is dropped; there’s no command-levelallowed-tools(scoping is per-agent instead).
Codex
- Subagent — Codex custom agents are TOML, not markdown: the prose body
becomes
developer_instructions, and thename(required by Codex),description, andmodelfrontmatter carry over. There is no per-agenttoolsallowlist (tool scoping is only expressible via[mcp_servers]/ skill toggles), sotools(andcolor) 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 preservedescription+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 ahooks.jsonor 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 recognizesname/description/model/readonly/is_background; Claude’stoolsallowlist andcolorhave no Cursor field and are dropped with a report. - Slash command — Cursor commands (
.cursor/commands/*.md) are plain markdown with no frontmatter, soargument-hint,description, andallowed-toolsare 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 (PreToolUse→preToolUse,UserPromptSubmit→beforeSubmitPrompt, …) and any with no Cursor equivalent (e.g.Notification,PostCompact) are dropped with a report. The required top-levelversionis asserted if missing and a user-set value is preserved. agentsync models only Cursor’scommandhooks and only thecommand/matcher/typeentry fields; onimport, a Cursor-native event agentsync can’t render (afterFileEdit,beforeShellExecution, …) — or an event containing an entry it can’t fully represent (aprompt-type hook, or fields liketimeout/failClosed) — is left uncaptured with a warning, so a laterapplynever takes ownership of an array it would lossily rewrite.
Gemini CLI
- Subagent — markdown under
.gemini/agents/. Gemini recognizesname/description/model(plus Gemini-onlykind/temperature/max_turns/… agentsync doesn’t model); Claude’stoolslist uses a different tool vocabulary (read_file/grep_search, notRead/Grep), so copying it verbatim would name tools Gemini doesn’t have — it andcolorare dropped with a report.nameis defaulted to the filename when absent (Gemini requires it). - Slash command — Gemini commands are TOML (
.gemini/commands/*.toml) withdescription+prompt. The body becomespromptanddescriptioncarries over;argument-hint/allowed-toolshave 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.jsonunderhooksin the same nested shape as Claude, so only the event name is remapped (PreToolUse→BeforeTool,PostToolUse→AfterTool,UserPromptSubmit→BeforeAgent,Stop→AfterAgent,PreCompact→PreCompress); events with no Gemini equivalent (SubagentStart/SubagentStop/PostCompact/PermissionRequest) are dropped with a report.
Continue
- Slash command — Continue prompt blocks (
.continue/prompts/*.md) carry aname+ optionaldescription+invokable; the body becomes the prompt.argument-hint/allowed-toolshave 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.mdwith the documentedtrigger: always_onactivation 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 commanddescription/argument-hint/allowed-toolsfrontmatter drops — only the body survives. - MCP remote — Windsurf does not distinguish SSE vs streamable-HTTP in the
config (just
serverUrl), so a canonicalsseserver normalizes tohttpif later captured back viaimport/reconcile.
Roo Code
- MCP scope —
.roo/mcp.jsonis 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/*.mdkeepdescriptionANDargument-hint(Roo supports both); onlyallowed-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.mdrule (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 canonicalsseserver normalizes tohttpif later captured back viaimport/reconcile.
Why OpenCode skips hooks and LSP
Section titled “Why OpenCode skips hooks and LSP”- 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
lspconfig, but agentsync defers projecting LSP servers beyond Claude to a later release; today you’ll seelsp server X skippedin the report on non-Claude agents.
How OpenCode MCP servers are projected
Section titled “How OpenCode MCP servers are projected”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 asseserver normalizes tohttpif it is later captured back viaimport/reconcile(an apply-only flow is unaffected). - command — canonical
command+argsare flattened into OpenCode’s singlecommandstring array (["npx", "-y", "pkg"]), and split back on ingest. - environment — canonical
envis written under OpenCode’senvironmentkey (notenv). - remote —
urlandheaderscarry 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
mcpServersbecome TOML[mcp_servers.X](stdio and streamable-HTTP both representable). - Cursor MCP —
.cursor/mcp.jsonuses the samemcpServersshape as Claude, down to${env:…}references. - Gemini MCP —
.gemini/settings.jsonmcpServers: stdio keeps command/args/env; a remote server uses Gemini’s transport split —urlfor SSE,httpUrlfor HTTP streaming — both round-tripping the canonicaltype. - Continue MCP — one
.continue/mcpServers/<id>.yamlblock per server: stdio keeps command/args/env; a remote server uses Continue’sstreamable-http/ssetype +url, with auth headers underrequestOptions.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.jsonmcpServers: stdio command/args/env; remoteserverUrl+headers. - Roo MCP —
.roo/mcp.jsonmcpServers: stdio command/args/env; remote explicittype: 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.jsonmcpServers: stdio command/args/env; remoteurl+headers(transport inferred, notypekey). - Codex & Gemini memory — the same markdown lands at
~/.codex/AGENTS.md/~/.gemini/GEMINI.md(repo-rootGEMINI.mdat project scope). - Skills (Codex, Cursor & 18 breadth-tier agents) — the same skill directory
per the Agent Skills spec:
SKILL.md(name + description) plus any bundledscripts//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 nextapply(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 sharedclaude.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.
Escape hatches
Section titled “Escape hatches”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.)
Known limits
Section titled “Known limits”These are documented trade-offs, not regressions. The authoritative list lives in the README; the highlights:
- Comment preservation — comments in
mcp/*.toml, inopencode.json, in Gemini’s.gemini/settings.json, in the breadth tier’s JSONC settings files (Zed/Ampsettings.json, Copilot.vscode/mcp.json), and in Codex’s~/.codex/config.tomlare 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
applyoverwrites it with no backup (agentsync considers it its own). Runagentsync reconcilefirst to capture the edit. - Insecure sources —
http://andgit://plugin/marketplace sources are rejected by default (MITM protection); override withAGENTSYNC_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.
Footnotes
Section titled “Footnotes”-
Codex plugin system: developers.openai.com/codex/plugins. Enable-state lives in
~/.codex/config.tomlunder[plugins."<name>@<source>"]tables (anenabledbool) — the samename@sourceshape as Claude’senabledPlugins, so a future CodexPluginIngesterparses those tables (plus its marketplace sources) into the sameNativeMarketplace/NativePlugindescriptorsimportalready consumes. ↩ -
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.jsonand 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 (theenabledPlugins-equivalent aPluginIngesterwould read); given Cursor keeps user rules in app-local storage, this may not be a plain config file. The Cursor adapter therefore ships without aPluginIngester(plugin discovery onimportis deferred until that location is documented); it still fans out plugin components onapplylike every other adapter. ↩