Metadata-Version: 2.5
Name: aicsync
Version: 0.1.2
Summary: AI client config sync CLI — back up / migrate Claude Code & Cursor config (MCP, skills, plugins, rules, extensions).
Project-URL: Homepage, https://github.com/hanjinxin/aicsync
Author: hanjinxin
License-Expression: MIT
License-File: LICENSE
Keywords: backup,claude-code,cli,config,cursor,mcp,sync
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# aicsync

**AI client config sync** — back up and migrate your Claude Code and Cursor configuration (MCP servers, skills, plugins, commands, agents, rules, extensions) across machines.

Pure Python standard library. Zero dependencies, zero build step. `python3 -m aics` or the `aics` command.

## Why

You've accumulated a personal config across Claude Code and Cursor — MCP servers, skills, plugins, custom commands, Cursor rules, extensions. When you switch machines or reinstall, these are scattered across `~/.claude.json`, `~/.claude/`, `~/.cursor/` and can't be carried over in one shot. Manual copying is error-prone and risks leaking plaintext API tokens elsewhere.

Existing tools (Smithery, community `mcp-sync`) only handle *installing MCP servers from scratch*. There's nothing that *packages your whole setup and restores it on a new machine*. aicsync fills that gap.

## Install

Requires Python 3.10+ (standard library only).

From PyPI (remote) — recommended via `pipx` (Homebrew/system Python is PEP 668 externally-managed and blocks plain `pip`):

```bash
brew install pipx            # macOS, once
pipx install aicsync         # or: pipx install aicsync==0.1.2
aics --version               # installed command is `aics`
```

Without `pipx`, use a venv:

```bash
python3 -m venv ~/.venvs/aicsync && source ~/.venvs/aicsync/bin/activate
pip install aicsync
aics --version
```

From source:

```bash
git clone <your-repo> aicsync && cd aicsync
pipx install -e .            # editable: pipx install -e .
```

> The PyPI distribution name is `aicsync`; the installed command is `aics`. Upgrade later with `pipx upgrade aicsync`.

## Global options

```
-V, --version     print version
-v, --verbose     verbose logging to stderr
-q, --quiet       suppress progress logs
-h, --help        show help
```

Results go to **stdout**, logs/errors to **stderr** — safe for pipes. Exit codes: `0` success, `1` failure, `130` interrupt. Override the target home with `AICS_HOME` (for testing / sandboxes).

## Interactive mode

aicsync is a **CLI with an interactive layer** (not a full-screen TUI). In a TTY it activates automatically; under a pipe / agent it stays plain text:

- **`aics` with no args**: in a TTY opens a numbered menu (status/export/list/diff/install/convert/quit) and prompts for arguments; non-TTY prints help.
- **Color**: when stdout is a TTY, status/diff/list are colored (headers cyan, `==` green, `+bundle`/`+local` yellow, redacted red). Set `NO_COLOR` or pipe → plain text.
- **Install confirm gate**: in a TTY without `--yes`, prints a colored diff, then `Apply these changes? [y/N]`. Answering `n` aborts (no backup, no changes); `y` backs up and applies. Non-TTY / `--yes` skips the gate for automation.

## Commands

### `status` — what's on this machine

```bash
aics status                 # both clients
aics status --client claude
```

Prints a markdown inventory: install commands for every MCP server, `claude plugin install` lines for plugins, lists of skills/commands/agents, and Cursor extensions. Secrets are redacted by default.

### `export` — pack a bundle

```bash
aics export -o ./my-bundle                      # redact secrets by default
aics export -o ./my-bundle --tar                 # also produce a tar.gz
aics export -o ./my-bundle --include-secrets     # keep plaintext secrets
```

Bundle layout:

```
my-bundle/
├── INSTALL.md            # agent-readable install guide (with per-item commands)
├── manifest.json         # machine-readable index (counts / redacted / assets)
├── claude_mcp.json       # MCP servers + settings + plugins manifest
├── cursor_config.json    # MCP + settings + extensions manifest
└── assets/
    ├── claude/{skills,commands,agents}/   # plain-text assets, copied as-is
    └── cursor/rules/                     # .mdc rule files
```

### `list` — bundle contents

```bash
aics list ./my-bundle
```

### `diff` — bundle vs local

```bash
aics diff ./my-bundle
```

Item-by-item comparison of MCP/plugins/skills/extensions counts.

### `install` — apply to this machine

```bash
aics install ./my-bundle                     # file ops applied; network ops only printed
aics install ./my-bundle --client claude
aics install ./my-bundle --force              # overwrite existing items
aics install ./my-bundle --yes               # also run network installs (plugins/extensions)
```

Behavior:

- **Before applying**, the current config is backed up to `~/.aics/backup/<timestamp>/`.
- **File ops** (MCP JSON merge, skills/commands/agents/rules copy, settings merge) run directly and are idempotent (existing items skipped; `--force` overwrites).
- **Network ops** (`claude plugin install`, `cursor --install-extension`) only print commands by default; `--yes` runs them.
- **Secrets**: redacted fields stay empty and prompt you to fill them manually — values are never guessed.

### `convert` — Claude skill → Cursor rule

```bash
aics convert --skill ~/.claude/skills/foo/SKILL.md --out foo.mdc
```

Translates a SKILL.md's frontmatter into a Cursor `.mdc` rule; trigger semantics that can't be expressed get a `<!-- TODO -->`.

## Two usage paths

```mermaid
flowchart LR
    A["aics export"] --> B["bundle + INSTALL.md"]
    B --> C{who installs?}
    C -->|let the CLI do it| D["aics install bundle --yes"]
    C -->|hand to an agent| E["agent reads INSTALL.md\nruns each command"]
    B -.->|secrets| F["redacted list\nfill manually"]
```

## Agent usage

Non-TTY → no color, no confirm gate, no menu. stdout carries parseable results; stderr carries progress logs. Exit codes: `0` / `1` / `130`.

Minimum three steps:

```bash
aics export -o b        # pack (secrets redacted by default; produces b/INSTALL.md + manifest.json)
aics install b --yes    # apply (non-interactive; --yes also runs network installs; idempotent)
aics diff b             # verify (all == means fully restored)
```

Notes:

- `aics status` stdout is markdown; each `claude mcp add ...` / `claude plugin install ...` line is directly executable.
- Secrets are `null` in the bundle — **the agent never guesses values**; surface `manifest.json`'s `redacted` list for the user to fill.
- Sandbox test: `AICS_HOME=/tmp/sb aics install b --yes` — doesn't touch your real home.
- `install` is idempotent; re-running skips existing items.

## Design: why plugins are "reinstalled", not "copied"

The plugin cache in `~/.claude/plugins/cache/` holds platform-specific compiled artifacts (darwin-x64 binaries), git working-tree state, and absolute paths — and all of it is reproducible from `installed_plugins.json`'s `name@marketplace` + git SHA. So aicsync only exports the install manifest and runs `claude plugin install <name>@<marketplace>` on `install`, rebuilding by SHA. We migrate the *intent to install*, not the *cache corpse*.

skills/commands/agents/rules are plain text — copied directly, no reinstall needed.

## Security model

- **Redact by default**: any JSON value whose key matches `token|key|secret|password|auth|credential` is nulled on export/status and recorded in `manifest.redacted`.
- `--include-secrets` is an explicit opt-in to keep plaintext.
- `install` never guesses secret values — it prompts you to fill them.
- `install` always backs up the existing config first.

## Client adapters

Currently supports Claude Code + Cursor. Adding a client means writing one scan function and one apply function.

## Module layout

```
aics/
├── __main__.py    # python3 -m aics entry
├── cli.py         # arg parsing + command dispatch + version/help + exit codes
├── config.py       # path constants + env (AICS_HOME)
├── log.py          # leveled logging -> stderr (verbose/quiet)
├── errors.py       # AicsError + exit codes
├── scan.py         # Claude/Cursor config scanners
├── sanitize.py     # secret redaction
├── render.py       # markdown rendering (status + install guide)
├── bundle.py       # export / list / diff / tar
├── installer.py    # install / backup / merge
└── convert.py      # skill -> cursor rule
```

## License

MIT
