skillferry
Your agent workflow, portable across tools and machines.
skillferry turns one versioned, Git-friendly workspace — skills, global instructions, and non-secret MCP connection templates — into the native configurations of Codex, Claude Code, and DeepSeek Harness, on macOS, Windows, and Linux. It never copies credentials or runtime state, and it tells you honestly, per asset, how portable that asset is.
Sync capabilities, not credentials. · Write skills once. Run them across agents. · Your agent capabilities should not be locked inside one client.
Table of contents
- 30-second demo
- Before / after
- Quick start
- Compatibility matrix
- Security boundary
- Workspace layout
- Not a dotfiles / symlink / GUI tool
- Adapter development
- Migrating from codex-profile-sync
- Documentation map
- Roadmap
- License
30-second demo
$ skillferry import --from codex --output ~/workspaces/demo # 1. two skills + one MCP server
$ export GITHUB_PERSONAL_ACCESS_TOKEN=... # 2. token lives on this machine only
$ skillferry plan --workspace ~/workspaces/demo # 3. grades for all three agents
SKILL release-checklist
codex native
claude native
dsh native
MCP github
codex translated secret resolved from local env
claude translated secret resolved from local env
dsh translated inserted as dsh-mcp-client entries in the profile cordis.patch.yml
$ skillferry apply --workspace ~/workspaces/demo # 4. one workspace, three agents
$ skillferry doctor --workspace ~/workspaces/demo # 5. zero drift
$ skillferry export --shareable ~/workspaces/public # proof: no secrets, ever
Exported 15 file(s). No secret references were expanded.
The five-beat flow — import, secret references, per-target grades, apply,
secret-free export — is rehearsed in CI by the test suite (see
tests/test_plan_apply.py, tests/test_importers.py,
tests/test_export_audit.py) and was accepted natively on macOS in
docs/acceptance/macos-native.md.
Before / after
| Before | After |
|---|---|
| Re-author the same skills, rules, and MCP configs per tool, per machine | One workspace.toml + assets, git pull, skillferry apply |
| Tokens copied into configs that end up in Git | secret:env/NAME references; each machine supplies real values locally |
| "Sync succeeded" with no idea what was lost in translation | plan prints native / translated / degraded / manual / unsupported per asset with loss notes |
| Sync tools silently overwrite hand edits | Per-path hash ledger: local modifications become conflicts (exit 3), never silent overwrites |
Why this matters to real users: cross-machine skill/config loss is one of the most-requested fixes in the official trackers (claude-code #36693, #69231, codex #26691), and the MCP client-configuration split is an open standardization pain point (SEP-2633, MCP IG #2761).
Quick start
$ pipx install skillferry
$ skillferry init my-workspace && cd my-workspace
# add skills/**, edit instructions/global.md and mcp/servers.toml
$ skillferry plan # read every grade and conflict first
$ skillferry apply # backs up, writes only owned paths
$ skillferry doctor # exit 0 = in sync
plan and apply are dry-run-safe by design: plan never writes, and
apply refuses to run when any conflict exists. Exit codes: 0 in sync,
1 error, 2 safe drift, 3 conflict needs a human decision
(--resolve <id>=adopt|overwrite|keep-local).
Compatibility matrix
Grades are produced by each adapter from an evidence-backed capability table
(docs/AGENT_MATRIX.md); nothing is labeled native
without a verified loading path.
| Asset | Codex | Claude Code | DeepSeek Harness |
|---|---|---|---|
| Skills (SKILL.md dirs) | native — ~/.agents/skills/ |
native — ~/.claude/skills/ (docs) |
native — ~/.agents/skills/ |
| Global rules | native — marker blocks in ~/.codex/AGENTS.md |
translated — marker blocks in ~/.claude/CLAUDE.md |
native — marker blocks in $DSH_HOME/AGENTS.md |
| MCP (stdio) | translated — [mcp_servers.<name>] in ~/.codex/config.toml; secrets resolved from local env |
translated — user-level ~/.claude.json mcpServers (docs) |
translated — dsh-mcp-client entries in the profile cordis.patch.yml |
| MCP (http/sse) | manual (per-target instructions printed) |
manual |
manual |
| Extensions/plugins | manual — declared expected state, never auto-installed |
manual |
manual |
What the grades mean
plan grades are a promise about loading: native loads in the target's
own format with nothing lost; translated works after a transformation the
notes name; degraded works with known limits or unverified behavior;
manual prints instructions instead of writing; unsupported does not
apply. The full contract — merge order, conflicts, and exit codes — is in
docs/PORTABILITY_CONTRACT.md.
Security boundary
The security model is architecture, not documentation. See docs/THREAT_MODEL.md; machine-verifiable highlights:
- The workspace schema rejects literal secrets: MCP
envvalues must besecret:env/NAMEorsecret:file/PATHreferences (src/skillferry/workspace.py, negative tests intests/test_workspace.py). export --shareablescans every copied file and refuses to export on any credential-shaped content; it never expands a reference (src/skillferry/secrets.py,tests/test_export_audit.py).- Backups are raw (0600, local-only, for exact rollback) plus redacted
copies for human inspection (
src/skillferry/io_ops.py,test_backups_redact_secrets). - JSON reports and logs contain references, never resolved values
(
test_env_secret_lands_only_in_local_config). [protect]declares what a workspace may never manage (auth, sessions, sqlite, caches, embedded servers); mis-declarations fail at schema level.scripts/audit_public_tree.pyfails CI when the public tree contains credential patterns, machine paths, or runtime filenames.
Workspace layout
# workspace.toml — target-neutral by construction
schema_version = 1
[skills] directory = "skills"
default_targets = ["codex", "claude", "dsh"]
[instructions] common = "instructions/global.md" # marker | copy | include
[mcp] registry = "mcp/servers.toml" # env: secret refs only
[extensions] manifest = "extensions/manifest.toml"
[overlays] platform_dir / target_dir / host_dir # base < target < platform < host < local
[protect] paths = [] # never-manage declarations
A complete runnable example ships in
examples/starter-workspace (validated in CI),
together with two seed skills: setup-skillferry and release-checklist.
Merge order is base < target < platform < host < local override; lists
replace wholesale and dicts deep-merge, every value's origin is visible to
plan, and conflicts are never silent
(docs/PORTABILITY_CONTRACT.md).
Not a dotfiles / symlink / GUI tool
skillferry is deliberately a headless CLI. It is not a full-dotfiles synchronizer (it manages only declared, structured assets), it never creates symlinks or Windows junction/reparse points (the schema rejects them), it ships no GUI, it does not switch API providers, sync sessions/history, or "losslessly convert any plugin". The honest comparison with the existing landscape, including what we can and cannot claim about competitors, is in docs/COMPARISON.md.
Adapter development
Adding a target is bounded: implement adapters/base.py's interface (where
each asset lands, the capability-backed grades, and the MCP rendering) and
register it in adapters/registry.py. See
docs/AGENT_MATRIX.md for the evidence bar each grade
must meet.
Migrating from codex-profile-sync
skillferry migrate --from codex-profile-sync <bundle> --output <dir> converts
the legacy bundle's skills and MCP declarations into a draft workspace
(credential values become secret:env/... references; the bundle is never
modified). Details in docs/MIGRATION.md.
Documentation map
The docs/ tree is indexed by docs/README.md. For your role, start with:
| Role | Start with |
|---|---|
| Everyone | docs/PORTABILITY_CONTRACT.md — grades, merge order, conflicts, exit codes |
| Security review | docs/THREAT_MODEL.md + SECURITY.md |
| Contributors | CONTRIBUTING.md + docs/AGENT_MATRIX.md |
| Comparing alternatives | docs/COMPARISON.md |
| Legacy migration | docs/MIGRATION.md |
| Evidence records | docs/acceptance/macos-native.md · docs/acceptance/windows-native.md |
Chinese translations: README.zh-CN.md is the entry point, core documents live in docs/zh-CN/. Release history: CHANGELOG.md.
Roadmap
- A (this release): the portable core — skills/rules/MCP rendering, grades, ownership ledger, import/export/migrate, CI on 3 OS × Python 3.11–3.13.
- B: Gemini CLI adapter (first v1.x target),
lockfile/provenance records. - C: team layer (
scope/teamoverlays), SSH/remote targets. - D: reference implementations as the SKILL.md/mcp.json standards converge.
License
Apache-2.0. See LICENSE.
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 skillferry-0.1.0.tar.gz.
File metadata
- Download URL: skillferry-0.1.0.tar.gz
- Upload date:
- Size: 97.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9013fbb8e60577dc78ad2545de00cd72da26cedb200b8d1e95eff06adc2913f6
|
|
| MD5 |
a88808ae23512428d725d34722419efc
|
|
| BLAKE2b-256 |
4b3fb283c6746245a6cd53e871b8d3bd837616ab67f426529fd71fc6d855a542
|
Provenance
The following attestation bundles were made for skillferry-0.1.0.tar.gz:
Publisher:
release.yml on GreenLv/skillferry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skillferry-0.1.0.tar.gz -
Subject digest:
9013fbb8e60577dc78ad2545de00cd72da26cedb200b8d1e95eff06adc2913f6 - Sigstore transparency entry: 2533809138
- Sigstore integration time:
-
Permalink:
GreenLv/skillferry@a78bf54d042ce1cf7eb16a056237fd32bb56d238 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GreenLv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a78bf54d042ce1cf7eb16a056237fd32bb56d238 -
Trigger Event:
release
-
Statement type:
File details
Details for the file skillferry-0.1.0-py3-none-any.whl.
File metadata
- Download URL: skillferry-0.1.0-py3-none-any.whl
- Upload date:
- Size: 67.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c960615f7422df14c5908bf93ca4ca5d3b32f8777613953d8868f961897807b
|
|
| MD5 |
914e727632233699194dad1a3611fd45
|
|
| BLAKE2b-256 |
eb4ab5aee4acc10e4b649f1890e0cb3e8e4fb428a745ac5c4393d3c4a2b987af
|
Provenance
The following attestation bundles were made for skillferry-0.1.0-py3-none-any.whl:
Publisher:
release.yml on GreenLv/skillferry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
skillferry-0.1.0-py3-none-any.whl -
Subject digest:
3c960615f7422df14c5908bf93ca4ca5d3b32f8777613953d8868f961897807b - Sigstore transparency entry: 2533809322
- Sigstore integration time:
-
Permalink:
GreenLv/skillferry@a78bf54d042ce1cf7eb16a056237fd32bb56d238 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/GreenLv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a78bf54d042ce1cf7eb16a056237fd32bb56d238 -
Trigger Event:
release
-
Statement type: