Ferry

What Ferry carries

ferry sync publishes a set of files and values from the operator machine to the snapshot, and applies them on each box. This page lists that set. For the rules that keep credentials out of it, see the Security model.

Linked paths

Both machines have a checkout of the snapshot at ~/.ferry/store. These paths are symlinks into that checkout, on the operator machine and on each box:

Item Paths
Skills Each entry in ~/.agents/skills and ~/.claude/skills, and in the skill_root of a custom harness
Instruction file ~/AGENTS.md, ~/.claude/CLAUDE.md, ~/.codex/AGENTS.md, ~/.pi/agent/AGENTS.md, and the instruction_file of a custom harness
Claude subagents ~/.claude/agents
Claude commands ~/.claude/commands
Claude hook scripts ~/.claude/hooks

On a box, each instruction file links to a generated file, ~/.ferry/box/AGENTS.md. It has a Ferry header, your instructions for that box, and your ~/AGENTS.md. See Boxes.

Settings keys

Ferry never carries a whole settings file. It carries these keys, and the box merges them into its own file:

Agent File Keys
Claude Code ~/.claude/settings.json enabledPlugins, extraKnownMarketplaces, permissions, hooks, attribution, includeCoAuthoredBy, model, alwaysThinkingEnabled
Codex ~/.codex/config.toml model, model_reasoning_effort, model_reasoning_summary, model_verbosity, features, web_search
Pi ~/.pi/agent/settings.json defaultProvider, defaultModel, defaultThinkingLevel, enabledModels, thinkingBudgets, enableSkillCommands
Cursor Agent ~/.cursor/cli-config.json model, maxMode, hasChangedDefaultModel, attribution

Hooks

Ferry carries the hooks key of Claude Code and the scripts in ~/.claude/hooks. It leaves out a hook whose command refers to a home path that the box will not have, and prints Skipped hook: <reason>: <location>. To carry such a hook, move the script into a carried directory or onto the PATH of both machines.

MCP servers

Ferry reads the MCP servers in mcpServers of ~/.claude.json, [mcp_servers] of ~/.codex/config.toml, and mcpServers of ~/.cursor/mcp.json.

Remote servers

Ferry carries the name and the HTTPS URL. Sync declares the server on the box. It replaces a box declaration with a different URL. It never removes a box server. Ferry skips a server with a plain http:// URL. Log in to a server on the box with ferry auth <tool> --mcp <server>.

Stdio servers

Ferry carries the name, the command, the arguments, and the names of the env keys. It never carries an env value.

The sync prints one line for each server that Ferry does not carry. After the sync, ferry status lists them in the Skipped MCP servers block, each with the reason and what to change.

The Security model has the full rules.

What stays on each machine

Ferry never carries these with a sync:

ferry move carries the sessions of one project when you move that project. See Moving a project.

Skills

Install skills with ferry skills add <source>. It runs npx skills add and adds -g and --copy, so the skill is a real directory in a global harness root, and the next sync links it into the store.

ferry skills add owner/repo --skill some-skill

A skill that an agent writes on a box stays on that box. ferry status lists it under Box-only skills. ferry adopt --from-box <name> <skill> copies it to the operator machine:

  1. The Ferry on the box runs the deny rules on the skill. A skill that fails a rule does not leave the box.
  2. Ferry copies the files that pass, and shows the file list of a new skill or the diff against your copy. Then it asks.
  3. Ferry writes the skill to the same skill root on the operator machine and moves the box copy to ~/.ferry/backups on the box.
  4. Run ferry sync to publish the skill to all boxes.

Agents and tools that are off

The policy "off" in [tools] or [box.<name>.tools] of ~/.ferry/config.toml turns off gh or an agent CLI. An agent that is off also turns off its harness. Sync does not read that harness on the operator machine while the agent is off on every box. On a box where it is off, sync writes nothing there and removes the links that Ferry made earlier. The shared ~/.agents/skills and ~/AGENTS.md have no off switch.

A custom harness

Add a harness that Ferry does not know in ~/.ferry/config.toml:

[[harness]]
id = "opencode"
name = "OpenCode"
skill_root = ".config/opencode/skills"
instruction_file = ".config/opencode/AGENTS.md"

History and revert

Each sync with a change is one commit in the snapshot.

Ferry stops and changes nothing when a later commit changes the same lines, or when the operator machine has changes that are not in the snapshot. Run ferry sync first.