Self-contained AI config sync for Codex, Cursor, Gemini, and Claude Code.
Project description
ai-sync
ai-sync synchronizes shared AI tooling artifacts into a project-local setup for Codex, Cursor, Gemini, and Claude Code.
The current workflow is:
- Install
ai-synconce on the machine. - Write a project
.ai-sync.yamlor.ai-sync.local.yaml. - Run
ai-sync plan. - Run
ai-sync apply [planfile].
License: PolyForm Noncommercial 1.0.0.
Install
End users
pipx install ai-sync
Local development
poetry sync --with dev
Poetry is configured to create an in-project .venv/, which is what the just tasks use.
Optional task runner:
brew install just
just install
just test
Machine bootstrap
install is the only machine-level setup step. It writes ~/.ai-sync/config.toml for auth/bootstrap settings such as the 1Password account identifier used by the CLI.
ai-sync install --op-account-identifier example.1password.com
The --op-account-identifier value must be a 1Password sign-in address such as example.1password.com or a 1Password user ID from op account list.
You can also authenticate with OP_SERVICE_ACCOUNT_TOKEN.
Project workflow
1. Write .ai-sync.yaml or .ai-sync.local.yaml
Projects declare their config sources explicitly and select resources by fully scoped ids.
Example:
sources:
company:
source: github.com/acme/company-ai-sync
version: v1.2.0
frontend:
source: ../frontend-ai-sync
agents:
- company/senior-software-engineer
skills:
- company/code-review
- frontend/react-review
commands:
- company/session-summary
rules:
- company/commit-conventions
mcp-servers:
- company/context7
settings:
mode: normal
subagents: true
Notes:
.ai-sync.yamlis the shared project manifest..ai-sync.local.yamlis an optional local override. If it exists,ai-syncignores.ai-sync.yamlentirely and uses the local file as the only project manifest.- Remote sources must be pinned with
version. - Local path sources are allowed, but they are less portable than pinned remote sources.
- If your local SSH setup needs a different Git host than the shared manifest uses, prefer a local Git URL rewrite over checking machine-specific hosts into
.ai-sync.yaml. For example:
git config url."git@example-git-host:example-org/".insteadOf "git@github.com:example-org/"
- Every selected resource must be scoped as
<sourceAlias>/<resourceId>.
2. Run plan
plan resolves sources under the project, validates the selection, computes planned actions, and saves a plan artifact.
ai-sync plan
By default, the saved plan goes to .ai-sync/last-plan.yaml.
You can also choose an explicit output path:
ai-sync plan --out my-plan.yaml
3. Run apply
Use a reviewed plan:
ai-sync apply .ai-sync/last-plan.yaml
Or let ai-sync compute a fresh plan and execute it immediately:
ai-sync apply
The reviewed path is:
ai-sync plan- review the output / saved plan
ai-sync apply <planfile>
Source repo layout
A source repo is a catalog of reusable artifacts:
<source>/
├── prompts/
│ └── <artifact-id>/
│ ├── artifact.yaml
│ ├── prompt.md
│ └── files/... # optional reserved bundle assets
├── skills/
│ └── <artifact-id>/
│ ├── artifact.yaml
│ ├── prompt.md
│ └── files/...
├── commands/
│ └── <relative-path>/
│ ├── artifact.yaml
│ ├── prompt.md
│ └── files/... # optional reserved bundle assets
├── rules/
│ └── <artifact-id>/
│ ├── artifact.yaml
│ ├── prompt.md
│ └── files/... # optional reserved bundle assets
├── mcp-servers/
│ └── <server-id>/
│ └── artifact.yaml
├── requirements.yaml
└── env.yaml
Resource ids
- Agents come from
prompts/<name>/artifact.yamlplusprompts/<name>/prompt.mdand are referenced as<alias>/<name>. - Skills come from
skills/<name>/artifact.yamlplusskills/<name>/prompt.mdand are referenced as<alias>/<name>. - Commands come from
commands/**/<name>/artifact.yamlplus siblingprompt.mdand are referenced as<alias>/<relative-path>. - Rules come from
rules/<name>/artifact.yamlplusrules/<name>/prompt.mdand are referenced as<alias>/<name>. - MCP servers come from
mcp-servers/<server-id>/artifact.yamland are referenced as<alias>/<server-id>.
Bundle artifact format
Every artifact bundle uses the same entry-file convention:
<bundle>/
├── artifact.yaml
├── prompt.md # prompt-bearing bundles only
└── files/... # optional bundled assets
For prompts, skills, commands, and rules, artifact.yaml stores metadata only. The markdown body lives in sibling prompt.md:
<bundle>/
├── artifact.yaml
└── prompt.md
Example command bundle:
description: Session summary command
Summarize the current session.
Notes:
- For prompts and rules, default ids are derived from the bundle directory name, not from the literal filename
artifact.yaml. - Skills are authored from
artifact.yamlplusprompt.md;ai-syncgenerates the client-facingSKILL.mdduring sync. - Skill assets live under
skills/<name>/files/...in the source repo and are written to the client skill root without thefiles/prefix (for examplefiles/scripts/tool.pybecomesscripts/tool.py). - Non-skill prompt-bearing bundles may also reserve
files/in the source repo, butai-syncdoes not sync those assets to client outputs yet. - To migrate older inline
prompt:bundles, usemigration/scripts/migrate_to_split_prompt_bundles.py.
Secrets
Secrets stay as references in source repos and project config. ai-sync resolves them locally and can generate a project-local .env.ai-sync file when needed.
Example env.yaml:
CONTEXT7_API_KEY:
value: op://Example Vault/AI Tools/CONTEXT7_API_KEY
EXA_API_KEY:
value: op://Example Vault/AI Tools/EXA_API_KEY
PUBLIC_CLIENT_ID:
value: abc123
GITHUB_PAT:
scope: local
description: Personal GitHub PAT
Rules:
- plan artifacts never store plaintext secret values
- plans show secret-backed outputs in redacted form
- apply fails if required secret values cannot be resolved
Project-local outputs
ai-sync manages project-local files such as:
.codex/*.cursor/*.gemini/*.claude/*.mcp.jsonCLAUDE.md.env.ai-sync.ai-sync/rules/.ai-sync/state/.ai-sync/sources/.ai-sync/last-plan.yaml
It does not modify machine-global client config under ~/.codex, ~/.cursor, ~/.gemini, or ~/.claude.
When rules are selected, ai-sync writes rule files to .ai-sync/rules/ and maintains a small managed link block in AGENTS.md instead of replacing the whole file.
You should usually cover these paths and .ai-sync.local.yaml with .gitignore, but ai-sync no longer blocks plan or apply when they are not ignored.
Reliability rules
- Remote sources must be pinned.
- If two selected resources would write the same non-composable output, planning fails.
- Saved plans are invalidated when the project config or resolved source fingerprints change.
Commands
ai-sync install
ai-sync plan
ai-sync apply [planfile]
ai-sync doctor
ai-sync uninstall [--apply]
Architecture
Runtime orchestration is class-based and dependency-injected:
- The composition root lives in
ai_sync.di, with providers declared inAppContainer. - The only runtime entrypoint is
cli.main(), which callsbootstrap_runtime()to resolveCommandHandlersService. - Command flows (
install,plan,apply,doctor,uninstall) are implemented on service classes underai_sync.services. - Adapter boundaries (
filesystem,process runner) isolate side effects from orchestration logic.
Testing
python -m pytest tests
DI-heavy tests should prefer provider overrides over module monkeypatching:
- Build a fresh container via
create_container(). - Override collaborators with
container.override_providers(...). - Resolve the service under test from the container after overrides are applied.
Project details
Release history Release notifications | RSS feed
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 ai_sync-1.2.0.tar.gz.
File metadata
- Download URL: ai_sync-1.2.0.tar.gz
- Upload date:
- Size: 53.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86e5f69552677518f188a3df89b04411b8547cf7406b12b675437f7a8c20f318
|
|
| MD5 |
c547d2794b6f7bc35459a0a0fe8fbe6a
|
|
| BLAKE2b-256 |
cb7f921927bf2dfa79c453cd1f18a9ca40535569fc9ec78e08e0107b0afc99d1
|
Provenance
The following attestation bundles were made for ai_sync-1.2.0.tar.gz:
Publisher:
release.yml on Ephasme/ai-sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_sync-1.2.0.tar.gz -
Subject digest:
86e5f69552677518f188a3df89b04411b8547cf7406b12b675437f7a8c20f318 - Sigstore transparency entry: 1107843660
- Sigstore integration time:
-
Permalink:
Ephasme/ai-sync@4eb4ca627fab5e6f2b7358778084555ae903e11f -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/Ephasme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4eb4ca627fab5e6f2b7358778084555ae903e11f -
Trigger Event:
push
-
Statement type:
File details
Details for the file ai_sync-1.2.0-py3-none-any.whl.
File metadata
- Download URL: ai_sync-1.2.0-py3-none-any.whl
- Upload date:
- Size: 82.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16137d3e5181651ee1de98348c3cdf35622ef189020d87c2641bb15dfda80cb7
|
|
| MD5 |
b1d3e950aaa4a966971faa01099cb471
|
|
| BLAKE2b-256 |
3fda788e61a4c23bd1fa1ed1da7b36ab445cf463c020fb39df7483b008b892df
|
Provenance
The following attestation bundles were made for ai_sync-1.2.0-py3-none-any.whl:
Publisher:
release.yml on Ephasme/ai-sync
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_sync-1.2.0-py3-none-any.whl -
Subject digest:
16137d3e5181651ee1de98348c3cdf35622ef189020d87c2641bb15dfda80cb7 - Sigstore transparency entry: 1107843662
- Sigstore integration time:
-
Permalink:
Ephasme/ai-sync@4eb4ca627fab5e6f2b7358778084555ae903e11f -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/Ephasme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4eb4ca627fab5e6f2b7358778084555ae903e11f -
Trigger Event:
push
-
Statement type: