sync/ reads MCP server definitions and platform configs, injects secrets from env/secrets.json, then renders them into each platform's native format.
# 1. 复制 secrets 模板(唯一需要创建的文件)
cp env/secrets.json.example env/secrets.json
# 2. 编辑填写你的 API Keys
$EDITOR env/secrets.json
# 3. 一键同步到所有平台
bash sync.shenv/
├── secrets.json ← 你唯一需要配置的文件(gitignored)
├── secrets.json.example ← 模板(已提交,列出所有需要的 Key)
│
├── mcp/ ← MCP 服务器定义(已提交,开箱即用)
│ ├── github.json ← token 用 ${github.token} 占位
│ ├── apifox.json
│ └── ...
│
├── platforms/ ← 平台配置(已提交,开箱即用)
│ ├── codex.json ← url/key 用 ${codex.url}/${codex.key} 占位
│ ├── claude.json
│ └── ...
│
└── templates/ ← 模板(供新增 MCP/平台时参考)
├── mcp.template.json
└── platform.template.json
所有配置文件的敏感值使用 ${platform.field} 占位,同步时从 env/secrets.json 注入:
// env/mcp/github.json(已提交)
{ "headers": { "Authorization": "Bearer ${github.token}" } }
// env/platforms/codex.json(已提交)
{ "model_providers": { "dataeyes": {
"base_url": "${codex.url}",
"env_key": "DATAEYES_API_KEY"
}},
"env": { "DATAEYES_API_KEY": "${codex.key}" }
}
// env/secrets.json(不提交,用户填写 — 每个平台一个对象)
{
"github": { "token": "ghp_xxx" },
"codex": { "url": "https://api.example.com/v1", "key": "sk-xxx" },
...
}
// 运行时解析为:
{ "headers": { "Authorization": "Bearer ghp_xxx" } }
{ "base_url": "https://api.example.com/v1", ... }Each env/mcp/<name>.json:
{
"name": "my-server",
"type": "stdio",
"command": "npx",
"args": ["-y", "my-mcp-package"],
"env": {},
"platforms": ["claude", "codex", "codebuddy"]
}type:"stdio"(requirescommand/args) or"sse"(requiresurl/headers)platforms: optional filter — omit to sync to all platforms, or list specific platformsenv: environment variables passed to the MCP server process- Secrets: use
${platform.field}syntax, resolved from nestedenv/secrets.jsonat sync time
Each env/platforms/<name>.json mostly follows that platform's native configuration shape,
with a small number of sync-engine metadata fields such as api.enabled.
| Platform | File | Follows |
|---|---|---|
| Codex | codex.json |
Codex config.toml schema |
| Claude | claude.json |
Claude Code env API sync + preamble/agents metadata |
| CodeBuddy | codebuddy.json |
CodeBuddy models.json schema |
| Gemini | gemini.json |
Gemini CLI env vars |
| Continue | continue.json |
Continue config.yaml models |
| Cursor | cursor.json |
(no platform config needed) |
| Cline | cline.json |
Merge globalState + secrets into ~/.cline/data/ |
| Qwen Code | qwen.json |
Merge env into ~/.qwen/settings.json, sync skills |
Engine metadata is consumed by the sync layer and is not written into the target tool config.
For Claude, api.enabled defaults to true; setting it to false skips API env sync and
removes sync-managed API fields, while MCP servers and preamble/agents still sync.
For CodeBuddy, api.enabled also defaults to true; setting it to false skips model
definition sync and clears the managed availableModels list in ~/.codebuddy/models.json
(set to [], not removed) so synced models drop out of the picker without losing provider
definitions. MCP servers, skills, and the preamble still sync.
For Gemini, api.enabled also defaults to true; setting it to false skips syncing the
model field into ~/.gemini/settings.json (pruned via the managed-keys sidecar) and
removes the managed env block (GEMINI_API_KEY, GOOGLE_GEMINI_BASE_URL, GEMINI_MODEL)
from ~/.zshrc. MCP servers, general settings, and the preamble still sync.
Use the Claude cleanup as the reference contract before adding another platform's API toggle: Platform Sync Contract.
For Cline, Codex, Claude, CodeBuddy, Gemini, Continue, and Qwen Code, sync first checks
the tool's home directory (~/.cline, ~/.codex, ~/.claude,
~/.codebuddy, ~/.gemini, ~/.continue, ~/.qwen). If that root does not
exist, the target is skipped so sync does not create config for tools the user
has not installed.
Xcode CodingAssistant targets are checked separately. If
~/Library/Developer/Xcode/CodingAssistant does not exist, native CLI targets
still sync, but the Xcode-specific Codex / Claude / Gemini outputs are skipped.
All platform paths are centralized in sync/core/paths.py. By default
each tool resolves under its well-known home location (~/.codex, ~/.claude,
~/.gemini, …). To support tools installed in non-default locations, override
any platform's install root via the paths object in env/config.json:
{ "paths": { "codex": "/opt/codex", "claude": "/custom/.claude" } }When a key is set, every derived path for that platform (config, settings,
skills, MCP files) resolves under the override. Empty string "" or a missing
key falls back to the default. For Codex, the standard CODEX_HOME /
CODEX_CONFIG env vars still take precedence over this override. See
env/README.md for the full key list.
Cursor project rule sync can also read additional project roots from
paths.cursor_project_roots in env/config.json; CURSOR_PROJECT_ROOTS
remains available as a one-shot environment override.
| Target | Output |
|---|---|
| Cursor | Replace mcpServers in ~/.cursor/mcp.json |
| CodeBuddy | Replace mcpServers in ~/.codebuddy/mcp.json, sync models.json, skills |
| Codex CLI | Managed MCP + shared blocks in ~/.codex/config.toml |
| Xcode Codex | ~/Library/.../CodingAssistant/codex/ |
| Claude Code | Replace mcpServers in ~/.claude.json + Xcode Claude |
| Claude settings | If api.enabled=true, merge API env into ~/.claude/settings.json and set ~/.claude/config.json primaryApiKey to self; if false, clean sync-managed API fields |
| Cline | Replace mcpServers in VSCode extension settings + skills sync + merge globalState/secrets into ~/.cline/data/ |
| Gemini CLI | Replace mcpServers in ~/.gemini/settings.json + ~/.zshrc env |
| Continue | Update mcpServers + models in ~/.continue/config.yaml, creating it when ~/.continue exists |
| Qwen Code | Merge env into ~/.qwen/settings.json, sync skills to ~/.qwen/skills/ |
End-to-end recall: the historical-recall trigger is wired to Cline (
~/.cline/rules/ai-coding-kit-recall.md) and Qwen Code (~/.qwen/QWEN.md) as recall-only preambles, and to CodeBuddy (~/.codebuddy/CODEBUDDY.md) as a full preamble (which embeds historical-recall) — all three viaskills-engineering/scripts/sync-agent-preamble.sh. Continue gets it via therulesfield in~/.continue/config.yaml(injected bysync/platforms/continue.py). Run bothsync.sh(covers Continue) andsync-agent-preamble.sh(covers Cline / CodeBuddy / Qwen) so every platform receives its preamble.
- Copy template:
cp env/templates/platform.template.json env/platforms/my-platform.json - Fill in config following the platform's official spec
- Read Platform Sync Contract and decide field ownership, cleanup, and
api.enabledsemantics before writing the renderer. - If the platform only needs
mcpServersin a JSON file, add"mcp_target": "~/.my-platform/mcp.json"to the config - If custom rendering is needed, create
sync/platforms/my_platform.pywith async(mcp_servers, cfg)function. The sync engine discovers it fromenv/platforms/my-platform.json; nosync_config.pyregistration is needed. - Put shared path helpers in
sync/core/paths.pyonly when the platform has a well-known default install root. Otherwise prefer the JSONinstall_root/mcp_targetfields.
cp env/templates/mcp.template.json env/mcp/my-new-server.json
$EDITOR env/mcp/my-new-server.json
bash sync.shbash sync.sh # sync all
python3 sync/cli/main.py sync --target all # sync all (Python direct)
python3 sync/cli/main.py sync --target codex # single platform开箱即用的服务器在 env/mcp/。非默认、社区/高级服务器放在 env/optional_mcps/,用 sync/scripts/optional_mcps.sh 按需启用:
bash sync/scripts/optional_mcps.sh list # 查看可选服务器与启用状态
bash sync/scripts/optional_mcps.sh enable puppeteer # 启用 -> 下次 sync.sh 生效
bash sync/scripts/optional_mcps.sh disable puppeteer # 停用disable 带护栏:只移除由本工具启用的服务器,绝不删除仓库默认的 env/mcp/*.json。详见 env/optional_mcps/README.md。
- One file to configure: user only edits
env/secrets.json— each platform has its own{url, key/token}object - MCP separation: one file per server — no monolithic config
- Platform spec compliance: config keys match the platform's native naming exactly
- Zero field-name mapping: renderers convert format (JSON→TOML, JSON→YAML), not field names
- Auto-discovery: platforms are discovered from
env/platforms/directory - Secrets injection:
${platform.field}references are resolved from nestedenv/secrets.jsonat sync time
env/secrets.jsonis gitignored — never committedenv/mcp/*.jsonandenv/platforms/*.jsonare committed — use${VAR}placeholders, no real secretsenv/secrets.json.exampleis committed — shows required keys with placeholder valuesenv/templates/is committed — templates for adding new servers/platforms