Cross-platform CLI to sync scattered local dev configs & secrets to a private Git repo, with qoder<->codex AI config translation.
Project description
asura-sync
Cross-platform CLI to sync scattered local dev configs & secrets to a private Git repo, with qoder↔codex AI config translation.
跨平台配置与密钥同步工具——将散落在本机各处的 SSH 密钥、AI skill/MCP、Docker、npm、gitconfig 等用户级配置统一同步到私有 Git 仓库,支持 三方对账(本地/仓库/基线)和 AI 配置平级翻译(qoder↔codex)。
Features
- 6 个同步模块:SSH、Docker、npm/yarn、gitconfig、AI skills、AI MCP
- 三方对账引擎:引入"上次同步基线"作为第三参照点,内容 sha256 比较,绝不依赖 mtime
- AI 配置翻译:canonical 中立格式为仓库唯一权威源,qoder/codex 平级双向翻译,确定性规则 + 四道工程兜底
- 增量同步:仅处理有变化的项,支持
--dry-run预览 - 冲突安全:冲突项自动备份 + 上报,支持
--prefer local|cloud决策 - SSH 权限保持:私钥回写本机后自动恢复 600 权限(Windows 跳过)
- Docker 凭据剔除:
--exclude-secrets选项可剔除 config.json 的 auths 字段
Installation
pip install config-sync
Or install from source:
git clone <this-repo>
cd config-sync
pip install -e .
Quick Start
1. Initialize
config-sync init --repo git@github.com:your/config-sync-repo.git
2. Push local configs to repo
config-sync push # push all modules
config-sync push --only ssh,skills # push specific modules
config-sync push --only skills --dry-run # preview only
3. Pull configs from repo
config-sync pull # pull all modules
config-sync pull --only ssh # pull SSH only
4. Two-way sync (default)
config-sync sync # auto-detect push/pull per item
config-sync sync --prefer local # resolve conflicts in favor of local
config-sync sync --prefer cloud # resolve conflicts in favor of cloud
5. Check status
config-sync status # show reconciliation results
config-sync status --only ssh,skills # filter by module
CLI Reference
| Command | Description |
|---|---|
init --repo <url> |
Initialize local working copy (clone or init + remote) |
sync |
Two-way sync with three-way reconciliation |
push |
One-way: local → repo → git push |
pull |
One-way: git pull → repo → local |
status |
Show per-item reconciliation status |
Common Options
| Option | Description |
|---|---|
--only <modules> |
Comma-separated module list: ssh,docker,npm,git,skills,mcp |
--dry-run |
Preview actions without executing |
-v, --verbose |
Verbose output |
--prefer local|cloud |
Conflict resolution direction (sync/push only) |
--exclude-secrets |
Strip Docker auths and similar credentials (push only) |
--from <tool> |
Specify authoritative AI tool when collecting (qoder or codex) |
Modules
| Module | Source | Repo Path | Notes |
|---|---|---|---|
ssh |
~/.ssh/ |
ssh/ |
Keys, config, known_hosts; chmod 600 on private keys |
docker |
~/.docker/ |
docker/ |
daemon.json + config.json; --exclude-secrets strips auths |
npm |
~/.npmrc etc. |
npm/ |
.npmrc / .yarnrc / .yarnrc.yml |
git |
~/.gitconfig |
gitconfig/ |
Global git config + ignore file |
skills |
~/.qoder/skills/ etc. |
ai/skills/ |
SKILL.md standard, fan-out to all detected tools |
mcp |
Tool MCP files | ai/mcp/ |
Canonical JSON, translated to codex TOML / qoder JSON |
Three-Way Reconciliation
Problem: configs are scattered across ~/.ssh, ~/.qoder/skills, ~/.codex, etc. Git can't see these external source files, so git version alone can't tell which side is newer.
Solution: Introduce a sync baseline (base) as the third reference point. Compare three content hashes per item:
| Condition | Decision |
|---|---|
| local==base && repo==base | No change → skip |
| local!=base && repo==base | Local only → push |
| local==base && repo!=base | Cloud only → pull |
| Both changed, local==repo | Converged → update base |
| Both changed, local!=repo | Conflict → backup + report |
Never relies on mtime — always uses content sha256 as the authority.
AI Config Translation
- Canonical as authority: Git repo stores one neutral canonical format; qoder and codex are equal peers
- Skills: Same SKILL.md standard, fan-out by copying to each tool's skills root directory
- MCP: Canonical
servers.json→ codex TOML[mcp_servers.*]/ qoder JSONmcpServers - Four safeguards: unknown field passthrough, round-trip idempotency check, versioned field map, graceful degradation
Architecture
config-sync/
├── pyproject.toml
├── config_sync/
│ ├── cli.py # argparse subcommands
│ ├── syncer.py # Three-way reconciliation engine
│ ├── manifest.py # Module registry
│ ├── state.py # Sync baseline (sha256 per item)
│ ├── gitrepo.py # Git subprocess wrapper
│ ├── logger.py # Console + file logging
│ ├── toolpaths.py # TOOL_TARGETS path table
│ ├── modules/
│ │ ├── base.py # SyncModule + FileSyncModule
│ │ ├── ssh.py # SSH module
│ │ ├── docker.py # Docker module
│ │ ├── npm.py # npm/yarn module
│ │ ├── gitcfg.py # gitconfig module
│ │ └── ai.py # AiSkillsModule + AiMcpModule
│ └── adapters/
│ ├── canonical.py # Neutral canonical format
│ ├── collectors.py # Tool → canonical
│ ├── translators.py # Canonical → tool format
│ └── _toml.py # TOML read/write compat
└── tests/
└── test_core.py # 22 unit tests
Development
# Install in dev mode
pip install -e ".[dev]"
# Run tests
python -m pytest
Requirements
- Python 3.9+
- Git installed and available in PATH
- Dependencies: PyYAML, tomli (Python < 3.11), tomli-w
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file asura_sync-0.1.2.tar.gz.
File metadata
- Download URL: asura_sync-0.1.2.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b19e5577bb03ed3475ceea1302cc9dcf72c2d0bd8eba483d34787ef19cfa93c4
|
|
| MD5 |
b8d00c7b579cb64d18e18f3290012542
|
|
| BLAKE2b-256 |
8265454e1b86052dc2835b0907cfef001f6180157ea21e581b007cb341e49a81
|
File details
Details for the file asura_sync-0.1.2-py3-none-any.whl.
File metadata
- Download URL: asura_sync-0.1.2-py3-none-any.whl
- Upload date:
- Size: 30.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9529e1b06b6d6054e4fbf3afb985f9aeb8beb78ce5fc03d650ac562d8892be6
|
|
| MD5 |
07744d4dad125a323a87290d1dad4239
|
|
| BLAKE2b-256 |
0b0e89d0404393bda3b681a91de5c12d76ab8a7b52ac16fe20bac28db5f2c30d
|